【问题标题】:How do I get java logging output to appear on a single line?如何让 java 日志输出显示在一行上?
【发布时间】:2010-09-16 17:21:49
【问题描述】:

目前默认条目如下所示:

Oct 12, 2008 9:45:18 AM myClassInfoHere
INFO: MyLogMessageHere

我如何让它做到这一点?

Oct 12, 2008 9:45:18 AM myClassInfoHere - INFO: MyLogMessageHere

澄清我正在使用 java.util.logging

【问题讨论】:

    标签: java logging


    【解决方案1】:

    从 Java 7 开始,java.util.logging.SimpleFormatter 支持从系统属性中获取其 format,因此在 JVM 命令行中添加类似这样的内容会导致它在一行上打印:

    -Djava.util.logging.SimpleFormatter.format='%1$tY-%1$tm-%1$td %1$tH:%1$tM:%1$tS %4$s %2$s %5$s%6$s%n'
    

    或者,您也可以将其添加到您的logger.properties

    java.util.logging.SimpleFormatter.format='%1$tY-%1$tm-%1$td %1$tH:%1$tM:%1$tS %4$s %2$s %5$s%6$s%n'
    

    【讨论】:

    • 从 Java7 开始为真。 Java6 文档中没有提到这一点。
    • 也在 IDEA 中,使用双引号。 @jbruni 这在 Java6 中不起作用。
    • 对我来说在 Eclipse 中使用单引号。
    • 你可以写成 %1$tF %1$tT 而不是 %1$tY-%1$tm-%1$td %1$tH:%1$tM:%1$tS 。使它更短一点。不知道是不是更快。
    • ... 或logging.properties,根据@BrunoEberhard 的建议和缩短的记录器名称进行改编:java.util.logging.SimpleFormatter.format=%1$tF %1$tT %4$.1s %2$s %5$s%6$s%n
    【解决方案2】:

    1) -Djava.util.logging.SimpleFormatter.format

    Java 7 支持具有java.util.Formatter 格式字符串语法的属性。

    -Djava.util.logging.SimpleFormatter.format=... 
    

    here

    我最喜欢的是:

    -Djava.util.logging.SimpleFormatter.format=%1$tY-%1$tm-%1$td %1$tH:%1$tM:%1$tS %4$-6s %2$s %5$s%6$s%n
    

    这使得输出如下:

    2014-09-02 16:44:57 SEVERE org.jboss.windup.util.ZipUtil unzip: Failed to load: foo.zip
    

    2) 放到 IDE 中

    IDE 通常允许您为项目设置系统属性。 例如。在 NetBeans 中,不要在某处添加 -D...=...,而是在操作对话框中以 java.util.logging.SimpleFormatter.format=%1$tY-%1$tm-... 的形式添加属性 - 不带任何引号。 IDE 应该会弄清楚。

    3) 把它交给 Maven - Surefire

    为方便起见,以下是如何将其放入 Surefire:

    <!-- Surefire -->
    <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-surefire-plugin</artifactId>
        <version>2.17</version>
        <configuration>
            <systemPropertyVariables>
                <!-- Set JUL Formatting -->
                <java.util.logging.SimpleFormatter.format>%1$tY-%1$tm-%1$td %1$tH:%1$tM:%1$tS %4$-6s %2$s %5$s%6$s%n</java.util.logging.SimpleFormatter.format>
            </systemPropertyVariables>
        </configuration>
    </plugin>
    

    4) 手工制作

    我有一个带有few java.util.logging related classes 的库。其中,SingleLineFormatter。 可下载jarhere.

    public class SingleLineFormatter extends Formatter {
    
      Date dat = new Date();
      private final static String format = "{0,date} {0,time}";
      private MessageFormat formatter;
      private Object args[] = new Object[1];
    
      // Line separator string.  This is the value of the line.separator
      // property at the moment that the SimpleFormatter was created.
      //private String lineSeparator = (String) java.security.AccessController.doPrivileged(
      //        new sun.security.action.GetPropertyAction("line.separator"));
      private String lineSeparator = "\n";
    
      /**
       * Format the given LogRecord.
       * @param record the log record to be formatted.
       * @return a formatted log record
       */
      public synchronized String format(LogRecord record) {
    
        StringBuilder sb = new StringBuilder();
    
        // Minimize memory allocations here.
        dat.setTime(record.getMillis());    
        args[0] = dat;
    
    
        // Date and time 
        StringBuffer text = new StringBuffer();
        if (formatter == null) {
          formatter = new MessageFormat(format);
        }
        formatter.format(args, text, null);
        sb.append(text);
        sb.append(" ");
    
    
        // Class name 
        if (record.getSourceClassName() != null) {
          sb.append(record.getSourceClassName());
        } else {
          sb.append(record.getLoggerName());
        }
    
        // Method name 
        if (record.getSourceMethodName() != null) {
          sb.append(" ");
          sb.append(record.getSourceMethodName());
        }
        sb.append(" - "); // lineSeparator
    
    
    
        String message = formatMessage(record);
    
        // Level
        sb.append(record.getLevel().getLocalizedName());
        sb.append(": ");
    
        // Indent - the more serious, the more indented.
        //sb.append( String.format("% ""s") );
        int iOffset = (1000 - record.getLevel().intValue()) / 100;
        for( int i = 0; i < iOffset;  i++ ){
          sb.append(" ");
        }
    
    
        sb.append(message);
        sb.append(lineSeparator);
        if (record.getThrown() != null) {
          try {
            StringWriter sw = new StringWriter();
            PrintWriter pw = new PrintWriter(sw);
            record.getThrown().printStackTrace(pw);
            pw.close();
            sb.append(sw.toString());
          } catch (Exception ex) {
          }
        }
        return sb.toString();
      }
    }
    

    【讨论】:

    • 比其他解决方案更好的内存消耗。
    • 我试过这个 - 但它给了我 XML 的日志 - 我做错了什么 - stackoverflow.com/questions/16030578/…
    • 如果它转换为 XML 而不是您期望的格式 - 这意味着您的属性文件中的设置没有找到您的格式化程序类,您可以做 2 件事:1. 确保您的类在一个包中并将 formatter 属性设置为该类和包 2. 确保您的类具有唯一名称,例如“MyFormatter”,最后:确保所有处理程序都具有您想要的格式化程序(java.util.logging.ConsoleHandler.formatter=my.package .MyFormatter 以及:java.util.logging.FileHandler.formatter=my.package.MyFormatter)
    • 感谢分享。我分享了我在response to another question 中写的格式化程序。它对我来说表现得很好。我喜欢看到其他开发人员想出的让代码更小更快的技巧。
    • @ondra-Žižka 为了它的价值,我刚刚在你的谷歌代码仓库上给你发了一个补丁。
    【解决方案3】:

    类似于 Tervor,但我喜欢在运行时更改属性。

    请注意,这需要在创建第一个 SimpleFormatter 之前设置 - 正如在 cmets 中所写的那样。

        System.setProperty("java.util.logging.SimpleFormatter.format", 
                "%1$tF %1$tT %4$s %2$s %5$s%6$s%n");
    

    【讨论】:

    • 请注意,这需要在创建第一个 SimpleFormatter 之前设置 - 例如在获取全局记录器的处理程序之前。
    • 这是在不向 JVM 添加任何其他启动参数的情况下强制将日志写入单行的最快方法。但请确保在代码中调用“new SimpleFormatter()”之前设置此属性。
    【解决方案4】:

    就像 Obediah Stane 所说,有必要创建自己的 format 方法。但我会改变一些事情:

    • 创建一个直接从Formatter 派生的子类,而不是从SimpleFormatterSimpleFormatter 没有什么可添加的了。

    • 小心创建新的Date 对象!您应该确保代表LogRecord 的日期。使用默认构造函数创建新的Date 时,它将表示Formatter 处理LogRecord 的日期和时间,而不是LogRecord 的创建日期。

    以下类可以是Handler 中的used as formatter,而added 又可以是Logger。请注意,它会忽略LogRecord 中可用的所有类和方法信息。

    import java.io.PrintWriter;
    import java.io.StringWriter;
    import java.util.Date;
    import java.util.logging.Formatter;
    import java.util.logging.LogRecord;
    
    public final class LogFormatter extends Formatter {
    
        private static final String LINE_SEPARATOR = System.getProperty("line.separator");
    
        @Override
        public String format(LogRecord record) {
            StringBuilder sb = new StringBuilder();
    
            sb.append(new Date(record.getMillis()))
                .append(" ")
                .append(record.getLevel().getLocalizedName())
                .append(": ")
                .append(formatMessage(record))
                .append(LINE_SEPARATOR);
    
            if (record.getThrown() != null) {
                try {
                    StringWriter sw = new StringWriter();
                    PrintWriter pw = new PrintWriter(sw);
                    record.getThrown().printStackTrace(pw);
                    pw.close();
                    sb.append(sw.toString());
                } catch (Exception ex) {
                    // ignore
                }
            }
    
            return sb.toString();
        }
    }
    

    【讨论】:

    • 我试过这个 - 但它给了我 XML 的日志 - 我做错了什么 - stackoverflow.com/questions/16030578/…
    • 如果它转换为 XML 而不是您期望的格式 - 这意味着您的属性文件中的设置没有找到您的格式化程序类,您可以做 2 件事:1. 确保您的类在一个包中并将 formatter 属性设置为该类和包 2. 确保您的类具有唯一名称,例如“MyFormatter”,最后:确保所有处理程序都具有您想要的格式化程序(java.util.logging.ConsoleHandler.formatter=my.package .MyFormatter 还有:java.util.logging.FileHandler.formatter=my.package.MyFormatter)
    【解决方案5】:

    这是我正在使用的。

    public class VerySimpleFormatter extends Formatter {
    
        private static final String PATTERN = "yyyy-MM-dd'T'HH:mm:ss.SSSXXX";
    
        @Override
        public String format(final LogRecord record) {
            return String.format(
                    "%1$s %2$-7s %3$s\n",
                    new SimpleDateFormat(PATTERN).format(
                            new Date(record.getMillis())),
                    record.getLevel().getName(), formatMessage(record));
        }
    }
    

    你会得到类似...

    2016-08-19T17:43:14.295+09:00 INFO    Hey~
    2016-08-19T17:43:16.068+09:00 SEVERE  Seriously?
    2016-08-19T17:43:16.068+09:00 WARNING I'm warning you!!!
    

    【讨论】:

    • 我们如何让这个格式化程序输出异常信息,比如它的堆栈跟踪?
    • @fegemo 我认为您可以像这样打印starcktrace。 ofNullable(record.getThrown()).ifPresent(v -&gt; v.printStackTrace()); 就在返回格式化消息之前。
    【解决方案6】:

    根据屏幕截图,在 Eclipse 中选择“run as”,然后选择“Run Configurations...”,然后使用双引号而不是引号添加 Trevor Robinson 的答案。如果你错过了双引号,你会得到“找不到或加载主类”的错误。

    【讨论】:

    • 根据前面的答案,这在 Java 7 中有效。Java 6 没有此功能。
    【解决方案7】:

    我想出了一个可行的方法。您可以继承 SimpleFormatter 并覆盖格式方法

        public String format(LogRecord record) {
            return new java.util.Date() + " " + record.getLevel() + " " + record.getMessage() + "\r\n";
        }
    

    对这个 API 有点惊讶,我原以为会开箱即用地提供更多功能/灵活性

    【讨论】:

    • 任何人都应该使用formatMessage(record) 而不是record.getMessage()。占位符不会改变。
    【解决方案8】:

    如果您使用 tomcat 登录 Web 应用程序,请添加:

    -Djava.util.logging.ConsoleHandler.formatter = org.apache.juli.OneLineFormatter
    

    关于虚拟机参数

    【讨论】:

      【解决方案9】:

      此日志记录特定于您的应用程序,而不是一般的 Java 功能。您正在运行什么应用程序?

      这可能来自您在自己的代码中使用的特定日志库。如果是这样,请发布您正在使用的详细信息。

      【讨论】:

      • 这不是一些随机记录器应用程序。是java自己的java.util.logging.Logger
      【解决方案10】:

      如果您使用的是 java.util.logging,那么有一个配置文件正在执行此操作以记录内容(除非您使用的是编程配置)。所以,你的选择是
      1) 运行删除换行符的后处理器
      2)更改日志配置并从中删除换行符。重新启动您的应用程序(服务器),您应该会很好。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2019-04-25
        • 1970-01-01
        • 2016-06-06
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多