Як змусити вихід журналу 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.
багатий

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) Поклавши це на Мейвен - 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. Завантажується баночка тут .

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

Дякую, що поділились. Я поділився форматором, який я написав у відповідь на інше запитання . Це було добре для мене. Мені подобається бачити хитрощі інших розробників, щоб зробити код меншим та швидшим.
Райан

1
@ ondra-Žižka Щодо того, що варто, я щойно надіслав вам патч на ваш репо-код Google google.
Райан

61

Подібно до Тервора, але мені подобається змінювати властивість під час виконання.

Зауважте, що це потрібно встановити до створення першого SimpleFormatter - як було написано в коментарях.

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

6
Зауважте, що це потрібно встановити до створення першого SimpleFormatter - наприклад, перед тим, як отримати обробники глобальних реєстраторів.
Sheepy

5
Це найшвидший спосіб змусити ваші журнали виписати в один рядок, не додаючи до JVM жодних інших параметрів запуску. Але переконайтеся, що ви встановили цю властивість, перш ніж здійснити дзвінок на "новий SimpleFormatter ()" у своєму коді.
Сальвадор Валенсія

36

Як сказав Obediah Stane, потрібно створити свій власний 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 виберіть "запустити як", потім "Запустити конфігурації ..." та додайте відповідь від Тревора Робінсона подвійними лапками замість лапок. Якщо ви пропустите подвійні лапки, ви отримаєте помилки "не змогли знайти або завантажити основний клас".


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) змінити конфігурацію журналу І видалити з нього перерви рядка. Перезавантажте свою програму (сервер), і ви повинні бути хорошими.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.