You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何为Unix下Java应用的SystemOut及未捕获异常日志添加时间戳?

给Java应用的System.out及未捕获异常添加时间戳的解决方案

一、Shell脚本管道方案(无需修改Java代码)

这是最快速的调整方式,直接通过Unix工具给输出每行加上时间戳:

1. 使用ts命令(推荐,需安装moreutils)

先安装依赖包:

  • Debian/Ubuntu:apt install moreutils
  • RHEL/CentOS:yum install moreutils(需先启用EPEL源)

修改启动命令:

nohup java -jar app.jar 2>&1 | ts '[%Y-%m-%d %H:%M:%S]' > nohup.out &

ts会给每一行输出(包括System.out和未捕获异常的错误输出)加上指定格式的时间戳,再写入nohup文件。

2. 用awk替代(无需额外安装)

如果系统没有ts,可以用awk内置的时间函数实现:

nohup java -jar app.jar 2>&1 | awk '{print strftime("[%Y-%m-%d %H:%M:%S]"), $0}' > nohup.out &

awk的strftime函数生成时间戳,和原输出内容拼接后输出。

二、JVM层面修改(从根源控制输出)

1. 自定义启动类替换System.out

写一个简单的Java类,替换默认的System.out和System.err,让所有输出自动带时间戳:

import java.io.PrintStream;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.lang.reflect.Method;

public class TimestampedLauncher {
    private static final SimpleDateFormat TIME_FORMAT = new SimpleDateFormat("[yyyy-MM-dd HH:mm:ss]");

    public static void main(String[] args) throws Exception {
        // 替换System.out和System.err
        PrintStream timestampOut = new PrintStream(System.out) {
            @Override
            public void println(String x) {
                super.println(TIME_FORMAT.format(new Date()) + " " + x);
            }

            @Override
            public void print(String x) {
                super.print(TIME_FORMAT.format(new Date()) + " " + x);
            }
        };
        System.setOut(timestampOut);
        System.setErr(timestampOut);

        // 启动原应用主类
        Class<?> mainClass = Class.forName(args[0]);
        Method mainMethod = mainClass.getMethod("main", String[].class);
        String[] appArgs = new String[args.length - 1];
        System.arraycopy(args, 1, appArgs, 0, appArgs.length);
        mainMethod.invoke(null, (Object) appArgs);
    }
}

编译这个类后,修改启动命令:

nohup java -cp .:app.jar TimestampedLauncher com.yourcompany.YourMainApp > nohup.out 2>&1 &

替换com.yourcompany.YourMainApp为你实际的主类全路径,这样所有System.out/err输出、未捕获异常都会带时间戳。

2. 利用Log4j重定向系统输出(适合已用Log4j的场景)

如果你的应用已经用Log4j做日志管理,可以直接把System.out/err重定向到Log4j的appender,复用已有的时间戳格式:
在Log4j配置文件(log4j.xml或log4j.properties)中添加:

<appender name="SYSTEM_OUT" class="org.apache.log4j.ConsoleAppender">
    <layout class="org.apache.log4j.PatternLayout">
        <param name="ConversionPattern" value="%d{yyyy-MM-dd HH:mm:ss} %-5p %c - %m%n"/>
    </layout>
</appender>
<logger name="sysout" additivity="false">
    <level value="INFO"/>
    <appender-ref ref="SYSTEM_OUT"/>
</logger>
<logger name="syserr" additivity="false">
    <level value="ERROR"/>
    <appender-ref ref="SYSTEM_OUT"/>
</logger>

然后在应用初始化代码中添加:

import org.apache.log4j.Logger;
import org.apache.log4j.Level;
import java.io.PrintStream;
import java.io.OutputStream;

public class Log4jStream extends OutputStream {
    private final Logger logger;
    private final Level level;
    private final StringBuilder buffer = new StringBuilder();

    public Log4jStream(Logger logger, Level level) {
        this.logger = logger;
        this.level = level;
    }

    @Override
    public void write(int b) {
        if (b == '\n') {
            logger.log(level, buffer.toString());
            buffer.setLength(0);
        } else {
            buffer.append((char) b);
        }
    }
}

// 在应用启动时执行
System.setOut(new PrintStream(new Log4jStream(Logger.getLogger("sysout"), Level.INFO), true));
System.setErr(new PrintStream(new Log4jStream(Logger.getLogger("syserr"), Level.ERROR), true));

这样系统输出会自动进入Log4j的日志流程,带上统一的时间戳。

三、整合系统日志方案

如果想把应用输出和系统日志统一管理,可以用logger命令:

nohup java -jar app.jar 2>&1 | logger -t my-java-app -p user.info &

-t指定应用标签方便区分,-p指定日志级别,输出会写入系统日志文件(如/var/log/messages),自带系统时间戳,还能通过系统日志工具(如journalctl)检索。

内容的提问来源于stack exchange,提问作者Achilles

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.15 18:45:41