Wie kann ich die Java-Protokollierungsausgabe in einer einzelnen Zeile anzeigen lassen?

124

Im Moment sieht ein Standardeintrag ungefähr so ​​aus:

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

Wie bekomme ich das dazu?

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

Klarstellung Ich verwende java.util.logging

Obediah Stane
quelle

Antworten:

81

Ab Java 7 unterstützt java.util.logging.SimpleFormatter das Abrufen des Formats von einer Systemeigenschaft. Wenn Sie also der JVM-Befehlszeile etwas Ähnliches hinzufügen, wird es in einer Zeile gedruckt:

-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'

Alternativ können Sie dies auch zu Ihrem hinzufügen 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'
Trevor Robinson
quelle
4
Richtig ab Java7. Dies wird in den Java6-Dokumenten nicht erwähnt.
Jbruni
1
Funktioniert auch in IDEA mit doppelten Anführungszeichen. @jbruni Dies funktioniert nicht in Java6.
Joshua Davis
1
Arbeitet mit einfachen Anführungszeichen in Eclipse für mich.
reich
1
Anstelle von% 1 $ tY-% 1 $ tm-% 1 $ td% 1 $ tH:% 1 $ tM:% 1 $ tS können Sie% 1 $ tF% 1 $ tT schreiben. Macht es etwas kürzer. Ich weiß nicht, ob es noch schneller ist.
Bruno Eberhard
1
... oder in logging.properties, mit Anpassung basierend auf dem Vorschlag von @BrunoEberhard und einem verkürzten Loggernamen: 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 unterstützt eine Eigenschaft mit der java.util.FormatterFormat-String-Syntax.

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

Siehe hier .

Mein Liebling ist:

-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

was macht Ausgabe wie:

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

2) Zu IDEs bringen

Mit IDEs können Sie normalerweise Systemeigenschaften für ein Projekt festlegen. Fügen Sie beispielsweise in NetBeans anstelle von -D ... = ... irgendwo die Eigenschaft im Aktionsdialog in Form von java.util.logging.SimpleFormatter.format=%1$tY-%1$tm-...- ohne Anführungszeichen hinzu. Die IDE sollte es herausfinden.

3) Setzen Sie das zu Maven - Surefire

Für Ihre Bequemlichkeit, hier ist, wie man es zu Surefire bringt:

        <!-- 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) Handgemacht

Ich habe eine Bibliothek mit wenigen java.util.loggingverwandten Klassen . Unter ihnen ist es SingleLineFormatter. Hier kann das Glas heruntergeladen werden .

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();
  }
}
Ondra Žižka
quelle
Schöner Speicherverbrauch als die andere Lösung.
Tim Williscroft
Ich habe es versucht - aber es gibt mir das Protokoll in XML - was mache ich falsch - stackoverflow.com/questions/16030578/…
user93353
Wenn XML anstelle des erwarteten Formats angezeigt wird - das bedeutet, dass die Einstellung in Ihrer Eigenschaftendatei Ihre Formatierungsklasse nicht gefunden hat -, können Sie zwei Dinge tun: 1. Stellen Sie sicher, dass sich Ihre Klasse in einem Paket befindet, und setzen Sie die Formatierungseigenschaft auf diese Klasse und Paket 2. Stellen Sie sicher, dass Ihre Klasse einen eindeutigen Namen wie "MyFormatter" hat. Zuletzt: Stellen Sie sicher, dass alle Handler den gewünschten Formatierer haben (java.util.logging.ConsoleHandler.formatter = my.package.MyFormatter und auch: java.util .logging.FileHandler.formatter = my.package.MyFormatter)
Shaybc
Danke für das Teilen. Ich habe einen Formatierer geteilt, den ich als Antwort auf eine andere Frage geschrieben habe . Es ist in Ordnung für mich durchgeführt. Ich mag es, die Tricks zu sehen, die andere Entwickler entwickeln, um Code kleiner und schneller zu machen.
Ryan
1
@ ondra-Žižka Für was es wert ist, habe ich dir gerade einen Patch auf deinem Google Code Repo geschickt.
Ryan
61

Ähnlich wie Tervor, aber ich möchte die Eigenschaft zur Laufzeit ändern.

Beachten Sie, dass dies festgelegt werden muss, bevor der erste SimpleFormatter erstellt wird - wie in den Kommentaren beschrieben.

    System.setProperty("java.util.logging.SimpleFormatter.format", 
            "%1$tF %1$tT %4$s %2$s %5$s%6$s%n");
Guy L.
quelle
6
Beachten Sie, dass dies festgelegt werden muss, bevor der erste SimpleFormatter erstellt wird - beispielsweise bevor die Handler des globalen Protokollierers abgerufen werden.
Sheepy
5
Dies ist der schnellste Weg, um Ihre Protokolle zu zwingen, in eine einzelne Zeile zu schreiben, ohne der JVM weitere Startparameter hinzuzufügen. Stellen Sie jedoch sicher, dass Sie diese Eigenschaft festlegen, bevor Sie in Ihrem Code 'new SimpleFormatter ()' aufrufen.
Salvador Valencia
36

Wie Obediah Stane sagte, ist es notwendig, eine eigene formatMethode zu entwickeln. Aber ich würde ein paar Dinge ändern:

  • Erstellen Sie eine Unterklasse, die direkt von Formatterund nicht von abgeleitet ist SimpleFormatter. Das SimpleFormatterhat nichts mehr hinzuzufügen.

  • Seien Sie vorsichtig beim Erstellen eines neuen DateObjekts! Sie sollten sicherstellen, dass Sie das Datum des LogRecord. Beim Erstellen eines neuen DateKonstruktors mit dem Standardkonstruktor werden Datum und Uhrzeit der FormatterProzesse LogRecordund nicht das Erstellungsdatum angegeben LogRecord.

Die folgende Klasse kann als Formatierer verwendet , in einem Handler, die wiederum wird hinzugefügt , um die Logger. Beachten Sie, dass alle im und verfügbaren Klassen- und Methodeninformationen ignoriert werden 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();
    }
}
Benno Richters
quelle
Ich habe es versucht - aber es gibt mir das Protokoll in XML - was mache ich falsch - stackoverflow.com/questions/16030578/…
user93353
Wenn XML anstelle des erwarteten Formats angezeigt wird - das bedeutet, dass die Einstellung in Ihrer Eigenschaftendatei Ihre Formatierungsklasse nicht gefunden hat -, können Sie zwei Dinge tun: 1. Stellen Sie sicher, dass sich Ihre Klasse in einem Paket befindet, und setzen Sie die Formatierungseigenschaft auf diese Klasse und Paket 2. Stellen Sie sicher, dass Ihre Klasse einen eindeutigen Namen wie "MyFormatter" hat. Zuletzt: Stellen Sie sicher, dass alle Handler den gewünschten Formatierer haben (java.util.logging.ConsoleHandler.formatter = my.package.MyFormatter und auch: java.util .logging.FileHandler.formatter = my.package.MyFormatter)
Shaybc
10

Das benutze ich.

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));
    }
}

Sie werden so etwas wie ...

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!!!
Jin Kwon
quelle
Wie kann dieser Formatierer Ausnahmeinformationen ausgeben, z. B. seine Stapelverfolgung?
Fegemo
1
@fegemo Ich denke, Sie können die Starcktrace so drucken. ofNullable(record.getThrown()).ifPresent(v -> v.printStackTrace());kurz vor der Rückgabe der formatierten Nachricht.
Jin Kwon
7

Eclipse-Konfiguration

Wählen Sie pro Screenshot in Eclipse "Ausführen als" und dann "Konfigurationen ausführen ..." und fügen Sie die Antwort von Trevor Robinson mit doppelten Anführungszeichen anstelle von Anführungszeichen hinzu. Wenn Sie die doppelten Anführungszeichen verpassen, erhalten Sie die Fehlermeldung "Hauptklasse konnte nicht gefunden oder geladen werden".

Rupweb
quelle
2
Wie in der vorherigen Antwort beschrieben, funktioniert dies in Java 7. Java 6 verfügt nicht über diese Funktion.
Joshua Davis
5

Ich habe einen Weg gefunden, der funktioniert. Sie können SimpleFormatter in Unterklassen unterteilen und die Formatierungsmethode überschreiben

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

Ein bisschen überrascht über diese API hätte ich gedacht, dass mehr Funktionalität / Flexibilität sofort bereitgestellt worden wäre

Obediah Stane
quelle
Jeder sollte formatMessage(record)eher verwenden als record.getMessage(). Platzhalter werden nicht gewechselt.
Jin Kwon
-2

Diese Protokollierung ist anwendungsspezifisch und keine allgemeine Java-Funktion. Welche Anwendung (en) führen Sie aus?

Möglicherweise stammt dies aus einer bestimmten Protokollierungsbibliothek, die Sie in Ihrem eigenen Code verwenden. Wenn ja, geben Sie bitte die Details an, die Sie verwenden.

Leigh Caldwell
quelle
3
Es ist keine zufällige Logger-Anwendung. Es ist Java's eigenejava.util.logging.Logger
André C. Andersen
-2

Wenn Sie sich mit tomcat in einer Webanwendung anmelden, fügen Sie Folgendes hinzu:

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

Bei VM-Argumenten

Mohammad Irfan
quelle
-3

Wenn Sie java.util.logging verwenden, gibt es eine Konfigurationsdatei, die dies zum Protokollieren von Inhalten ausführt (es sei denn, Sie verwenden eine programmgesteuerte Konfiguration). Sie haben also folgende Möglichkeiten:
1) Führen Sie einen Postprozessor aus, der die Zeilenumbrüche entfernt.
2) Ändern Sie die Protokollkonfiguration UND entfernen Sie die Zeilenumbrüche. Starten Sie Ihre Anwendung (Server) neu und Sie sollten gut sein.

anjanb
quelle