将System.out.println记录到单个应用程序的日志文件
我们在Tomcat上有多个应用程序,它们使用System.out.println语句记录到Catalina.out。 只有一个应用程序会创建大量日志语句,因此我想将这些应用程序输出记录到单独的日志文件中。
我已经创建了一个log4j.xml设置,它只将警告级别记录到Catalina.out。 但是RollingFileAppender尚不能用于System.out语句,我不确定要更改什么。我不想接触其他应用程序。有没有可能呢?
<Configuration status="INFO">
<Appenders>
<Console name="stdout" target="SYSTEM_OUT">
<PatternLayout pattern="%d{yyyy-MM-dd HH:mm:ss} [%t] %-5level %logger{36}: %msg%n" />
</Console>
<RollingFile
name="logFile"
fileName="../logs/app/log.log"
filePattern="../logs/app/log.%d{yyyy-MM-dd}.log.gz"
ignoreExceptions="false">
<PatternLayout>
<Pattern>%d{yyyy-MM-dd HH:mm:ss} %-5p %m%n</Pattern>
</PatternLayout>
<Policies>
<TimeBasedTriggeringPolicy interval="1"/>
</Policies>
<DefaultRolloverStrategy max="31" />
</RollingFile>
<Async name="logFile_async">
<AppenderRef ref="logFile"/>
</Async>
</Appenders>
<Loggers>
<Root level="WARN">
<AppenderRef ref="stdout" />
</Root>
<Logger name="my.company.logger" level="DEBUG">
<AppenderRef ref="logFile_async"/>
</Logger>
</Loggers>
</Configuration>
解决方案
如备注中所述,打印到System.out
不是正确的日志记录方式,并且很难将发送到此处的数据重定向到正确的日志记录框架。
您有两个选择:
System.out到Juli重定向
您可以将上下文的swallowOutput
属性设置为true(参见documentation),将应用程序的标准输出和错误重定向到JULI logging system。
log4j2-appserver.jar
有一个juli实现,它将所有日志发送到Log4j2(请参阅documentation)。
将System.out定向到Log4j重定向
您可以这样定义PrintStream
到Logger
适配器:
public class LogPrintStream extends PrintStream {
private static class LogOnFlush extends ByteArrayOutputStream {
// WeakHashMap so that we don't keep a reference to the classloaders.
protected final Map<ClassLoader, Logger> classLoaderLoggers = new WeakHashMap<>();
public LogOnFlush() {
// NOP
}
@Override
public void flush() {
final String message = toString();
if (message != null && message.length() > 0) {
Logger logger = getLogger();
logger.debug(message);
}
reset();
}
public Logger getLogger() {
final ClassLoader cl = Thread.currentThread().getContextClassLoader();
Logger logger = classLoaderLoggers.get(cl);
if (logger == null) {
final String name;
if (cl instanceof WebappClassLoaderBase) {
final WebappClassLoaderBase webCl = (WebappClassLoaderBase) cl;
name = String.format("%s.[%s].[%s]", LogPrintStream.class.getName(), webCl.getHostName(), webCl.getContextName());
} else {
name = String.format("%s.[%08x]", LogPrintStream.class.getName(), cl.hashCode());
}
logger = LogManager.getLogger(name);
classLoaderLoggers.put(cl, logger);
}
return logger;
}
}
public LogPrintStream() {
super(new LogOnFlush(), true);
}
}
,并在服务器启动的非常早期阶段使用它替换System.out
到System#setOut
。例如,您可以像这样使用LifecycleListener
:
public class SystemOutReplaceListener implements LifecycleListener {
@Override
public void lifecycleEvent(LifecycleEvent event) {
if (Lifecycle.AFTER_INIT_EVENT.equals(event.getType())) {
System.setOut(new LogPrintStream());
}
}
}
警告:在此示例中,System.out
的输出发送到Log4j2。必须小心,以免Log4j2将其日志转发给System.out
。
相关文章