Как сделать так, чтобы вывод журнала java отображался в одной строке?

124

На данный момент запись по умолчанию выглядит примерно так:

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

Как мне это сделать?

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

Пояснение Я использую java.util.logging

Обедия Стейн
источник

Ответы:

81

Начиная с Java 7, java.util.logging.SimpleFormatter поддерживает получение своего формата из системного свойства, поэтому добавление чего-то вроде этого в командную строку 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'
Тревор Робинсон
источник
4
Верно с Java7. В документации Java6 об этом не упоминается.
jbruni
1
Также в IDEA работает с двойными кавычками. @jbruni Это не работает в Java6.
Джошуа Дэвис
1
У меня работает с одинарными кавычками в Eclipse.
rich
1
Вместо% 1 $ tY-% 1 $ tm-% 1 $ td% 1 $ tH:% 1 $ tM:% 1 $ tS вы можете написать% 1 $ tF% 1 $ tT. Делает его немного короче. Не знаю, быстрее ли это.
Бруно Эберхард
1
... или в logging.properties, с адаптацией, основанной на предложении @BrunoEberhard и сокращенном имени регистратора: java.util.logging.SimpleFormatter.format=%1$tF %1$tT %4$.1s %2$s %5$s%6$s%n
Kariem
73

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

Java 7 поддерживает свойство с java.util.Formatterсинтаксисом строки формата.

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

Смотрите здесь .

Мой любимый:

-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) ручной работы

У меня есть библиотека с несколькими java.util.loggingродственными классами . Среди них это SingleLineFormatter. Скачать jar здесь .

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/…
user93353
если он превращает XML вместо ожидаемого формата - это означает, что параметр в вашем файле свойств не нашел ваш класс форматирования, вы можете сделать 2 вещи: 1. Убедитесь, что ваш класс находится в пакете, и установите свойство форматирования для этого класса и пакет 2. убедитесь, что ваш класс имеет уникальное имя, например "MyFormatter", последнее: убедитесь, что все обработчики имеют нужный вам форматер (java.util.logging.ConsoleHandler.formatter = my.package.MyFormatter, а также: java.util .logging.FileHandler.formatter = my.package.MyFormatter)
Shaybc
Спасибо, что поделился. Я поделился Formatter, который написал в ответ на другой вопрос . Это хорошо для меня выполнено. Мне нравится видеть уловки, которые придумывают другие разработчики, чтобы сделать код меньше и быстрее.
Ryan
1
@ ondra-Žižka. Как бы то ни было, я только что отправил вам патч для вашего репозитория кода Google.
Ryan
62

Подобно Tervor, но мне нравится изменять свойство во время выполнения.

Обратите внимание, что это необходимо установить до создания первого SimpleFormatter - как было написано в комментариях.

    System.setProperty("java.util.logging.SimpleFormatter.format", 
            "%1$tF %1$tT %4$s %2$s %5$s%6$s%n");
Гай Л
источник
6
Обратите внимание, что это необходимо установить до создания первого SimpleFormatter - например, до получения обработчиков глобального регистратора.
Sheepy 06
5
Это самый быстрый способ заставить ваши журналы записываться в одну строку без добавления каких-либо других параметров запуска в JVM. Но убедитесь, что вы установили это свойство перед вызовом new SimpleFormatter () в своем коде.
Сальвадор Валенсия,
36

Как сказал Обедия Стейн, необходимо создать свой собственный formatметод. Но я бы изменил несколько вещей:

  • Создайте подкласс, производный непосредственно от Formatter, а не от SimpleFormatter. Больше SimpleFormatterнечего добавить.

  • Будьте осторожны при создании нового Dateобъекта! Убедитесь, что вы указали дату LogRecord. При создании нового Dateс конструктором по умолчанию он будет представлять дату и время Formatterобработки LogRecord, а не дату LogRecordсоздания.

Следующий класс может использоваться как средство форматирования в Handler, который, в свою очередь, может быть добавлен в 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/…
user93353
если он превращает XML вместо ожидаемого формата - это означает, что параметр в вашем файле свойств не нашел ваш класс форматирования, вы можете сделать 2 вещи: 1. Убедитесь, что ваш класс находится в пакете, и установите свойство форматирования для этого класса и пакет 2. убедитесь, что ваш класс имеет уникальное имя, например "MyFormatter", последнее: убедитесь, что все обработчики имеют нужный вам форматер (java.util.logging.ConsoleHandler.formatter = my.package.MyFormatter, а также: java.util .logging.FileHandler.formatter = my.package.MyFormatter)
Shaybc,
10

Это то, что я использую.

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
1
@fegemo Я думаю, вы можете распечатать след звездочки вот так. ofNullable(record.getThrown()).ifPresent(v -> v.printStackTrace());непосредственно перед возвратом отформатированного сообщения.
Джин Квон
7

Конфигурация Eclipse

На снимке экрана в Eclipse выберите «Запуск от имени», затем «Запуск конфигураций ...» и добавьте ответ Тревора Робинсона в двойные кавычки вместо кавычек. Если вы пропустите двойные кавычки, вы получите ошибку «не удалось найти или загрузить основной класс».

rupweb
источник
2
Согласно предыдущему ответу, это работает в Java 7. В Java 6 этой функции нет.
Джошуа Дэвис
5

Я выяснил, как это работает. Вы можете создать подкласс SimpleFormatter и переопределить метод форматирования

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

Немного удивленный этим API, я бы подумал, что больше функциональности / гибкости будет предоставлено из коробки.

Обедия Стейн
источник
Любой должен использовать formatMessage(record)вместо record.getMessage(). Владельцы места не меняются.
Джин Квон
-2

Это ведение журнала относится к вашему приложению, а не к общей функции Java. Какие приложения вы используете?

Возможно, это происходит из конкретной библиотеки журналов, которую вы используете в своем собственном коде. Если да, опубликуйте информацию о том, какой из них вы используете.

Ли Колдуэлл
источник
3
Это не какое-то приложение для случайного ведения журнала. Это собственная Javajava.util.logging.Logger
Андре К. Андерсен
-2

Если вы входите в веб-приложение с помощью tomcat, добавьте:

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

Об аргументах ВМ

Мохаммад Ирфан
источник
-3

если вы используете java.util.logging, то есть файл конфигурации, который делает это для регистрации содержимого (если вы не используете программную конфигурацию). Итак, ваши варианты:
1) запустить постпроцессор, который удаляет разрывы строк
2) изменить конфигурацию журнала И удалить из него разрывы строк. Перезагрузите приложение (сервер), и все будет хорошо.

anjanb
источник