如何为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
相关产品推荐
相关产品推荐

