微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

将 System.out.println 记录到单个应用程序的日志文件 System.out 到 JULI 重定向直接 System.out 到 Log4j 重定向

如何解决将 System.out.println 记录到单个应用程序的日志文件 System.out 到 JULI 重定向直接 System.out 到 Log4j 重定向

我们在 tomcat 上有多个应用程序,它们使用 System.out.println 语句记录到 catalina.out。 有一个应用程序会创建很多日志语句,因此我想将这些应用程序输出记录到单独的日志文件中。

我创建了一个 log4j.xml 设置,它只将 WARN 级别记录到 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 重定向

您可以像这样定义 PrintStreamLogger 适配器:

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]",cl.hashCode());
            }
            logger = LogManager.getLogger(name);
            classLoaderLoggers.put(cl,logger);
         }
         return logger;
      }
   }

   public LogPrintStream() {
      super(new LogOnFlush(),true);
   }
}

并在服务器启动的早期阶段使用它来替换 System.outSystem#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

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其他元素将获得点击?
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。)
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbcDriver发生异常。为什么?
这是用Java进行XML解析的最佳库。
Java的PriorityQueue的内置迭代器不会以任何特定顺序遍历数据结构。为什么?
如何在Java中聆听按键时移动图像。
Java“Program to an interface”。这是什么意思?