¿Cómo consigo que la salida del registro de Java aparezca en una sola línea?

124

Por el momento, una entrada predeterminada se ve así:

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

¿Cómo consigo que haga esto?

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

Aclaración Estoy usando java.util.logging

Obediah Stane
fuente

Respuestas:

81

A partir de Java 7, java.util.logging.SimpleFormatter admite obtener su formato de una propiedad del sistema, por lo que agregar algo como esto a la línea de comando de JVM hará que se imprima en una línea:

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

Alternativamente, también puede agregar esto a su 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
fuente
44
Verdadero a partir de Java7. No se menciona esto en los documentos de Java6.
jbruni
1
También en IDEA, funciona con comillas dobles. @jbruni Esto no funciona en Java6.
Joshua Davis
1
Funciona con comillas simples en Eclipse para mí.
rico
1
En lugar de% 1 $ tY-% 1 $ tm-% 1 $ td% 1 $ tH:% 1 $ tM:% 1 $ tS puede escribir% 1 $ tF% 1 $ tT. Lo hace un poco más corto. No sé si es aún más rápido.
Bruno Eberhard
1
... o en logging.properties, con una adaptación basada en la sugerencia de @BrunoEberhard y un nombre de registrador abreviado: 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 admite una propiedad con la java.util.Formattersintaxis de cadena de formato.

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

Ver aquí .

Mi favorito es:

-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

lo que hace que la salida como:

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

2) Poniéndolo en IDEs

Los IDE generalmente le permiten establecer las propiedades del sistema para un proyecto. Por ejemplo, en NetBeans, en lugar de agregar -D ... = ... en alguna parte, agregue la propiedad en el cuadro de diálogo de acción, en forma de java.util.logging.SimpleFormatter.format=%1$tY-%1$tm-...- sin comillas. El IDE debería resolverlo.

3) Poniéndole eso a Maven - Surefire

Para su comodidad, aquí le mostramos cómo ponerlo en 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) hecho a mano

Tengo una biblioteca con pocas java.util.loggingclases relacionadas . Entre ellos, es SingleLineFormatter. Tarro descargable aquí .

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
fuente
Mejor consumo de memoria que la otra solución.
Tim Williscroft
He intentado esto - pero me da el registro en XML - ¿qué estoy haciendo mal - stackoverflow.com/questions/16030578/...
user93353
si convierte XML en lugar del formato que esperaba, eso significa que la configuración en su archivo de propiedades no encontró su clase de formateador, puede hacer 2 cosas: 1. asegúrese de que su clase esté en un paquete y establezca la propiedad del formateador en esa clase y el paquete 2. asegúrese de que su clase tenga un nombre único como "MyFormatter", por último: asegúrese de que todos los controladores tengan el formateador que desea (java.util.logging.ConsoleHandler.formatter = my.package.MyFormatter y también: java.util .logging.FileHandler.formatter = my.package.MyFormatter)
Shaybc
Gracias por compartir. Compartí un formateador que escribí en respuesta a otra pregunta . Se realizó bien para mí. Me gusta ver los trucos que otros desarrolladores inventan para hacer el código más pequeño y más rápido.
Ryan
1
@ ondra-Žižka Por lo que vale, acabo de enviarte un parche en tu repositorio de código de Google.
Ryan
61

Similar a Tervor, pero me gusta cambiar la propiedad en tiempo de ejecución.

Tenga en cuenta que esto debe establecerse antes de crear el primer SimpleFormatter, como se escribió en los comentarios.

    System.setProperty("java.util.logging.SimpleFormatter.format", 
            "%1$tF %1$tT %4$s %2$s %5$s%6$s%n");
Guy L
fuente
66
Tenga en cuenta que esto debe establecerse antes de crear el primer SimpleFormatter, por ejemplo, antes de obtener los controladores del registrador global.
Sheepy
55
Esta es la forma más rápida de obligar a sus registros a escribir en una sola línea sin agregar ningún otro parámetro de inicio a la JVM. Pero asegúrese de configurar esta propiedad antes de hacer su llamada a 'new SimpleFormatter ()' en su código.
Salvador Valencia
36

Como dijo Obediah Stane, es necesario crear su propio formatmétodo. Pero cambiaría algunas cosas:

  • Cree una subclase directamente derivada de Formatter, no de SimpleFormatter. losSimpleFormatter ya no tiene nada que agregar.

  • ¡Tenga cuidado al crear un nuevo Dateobjeto! Debe asegurarse de representar la fecha de la LogRecord. Al crear un nuevo Datecon el constructor predeterminado, representará la fecha y hora en que los Formatterprocesos LogRecord, no la fecha en que LogRecordse creó.

La siguiente clase se puede usar como formateador en a Handler, que a su vez se puede agregar a Logger. Tenga en cuenta que ignora toda la información de clase y método disponible en 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
fuente
He intentado esto - pero me da el registro en XML - ¿qué estoy haciendo mal - stackoverflow.com/questions/16030578/...
user93353
si convierte XML en lugar del formato que esperaba, eso significa que la configuración en su archivo de propiedades no encontró su clase de formateador, puede hacer 2 cosas: 1. asegúrese de que su clase esté en un paquete y establezca la propiedad del formateador en esa clase y el paquete 2. asegúrese de que su clase tenga un nombre único como "MyFormatter", por último: asegúrese de que todos los controladores tengan el formateador que desea (java.util.logging.ConsoleHandler.formatter = my.package.MyFormatter y también: java.util .logging.FileHandler.formatter = my.package.MyFormatter)
Shaybc
10

Esto es lo que estoy usando.

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

Obtendrás algo como ...

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
fuente
¿Cómo podríamos tener esta información de excepción de salida del formateador, como su stacktrace?
fegemo
1
@fegemo Creo que puedes imprimir el rastro de estrellas como este. ofNullable(record.getThrown()).ifPresent(v -> v.printStackTrace());justo antes de devolver el mensaje formateado.
Jin Kwon
7

Config Eclipse

Por captura de pantalla, en Eclipse, seleccione "ejecutar como" y luego "Ejecutar configuraciones ..." y agregue la respuesta de Trevor Robinson con comillas dobles en lugar de comillas. Si pierde las comillas dobles, obtendrá errores de "no se pudo encontrar o cargar la clase principal".

rupweb
fuente
2
Según la respuesta anterior, esto funciona en Java 7. Java 6 no tiene esta característica.
Joshua Davis
5

He descubierto una forma que funciona. Puede subclasificar SimpleFormatter y anular el método de formato

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

Un poco sorprendido por esta API, hubiera pensado que se hubiera proporcionado más funcionalidad / flexibilidad de fábrica

Obediah Stane
fuente
Cualquiera debería usar en formatMessage(record)lugar de record.getMessage(). Los marcadores de posición no cambiarán.
Jin Kwon
-2

Este registro es específico de su aplicación y no es una característica general de Java. ¿Qué aplicaciones estás ejecutando?

Es posible que esto provenga de una biblioteca de registro específica que está utilizando dentro de su propio código. Si es así, publique los detalles de cuál está utilizando.

Leigh Caldwell
fuente
3
No es una aplicación de registro aleatorio. Es propio de Javajava.util.logging.Logger
André C. Andersen
-2

Si inicia sesión en una aplicación web con Tomcat, agregue:

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

Sobre argumentos de VM

Mohammad Irfan
fuente
-3

si está usando java.util.logging, entonces hay un archivo de configuración que está haciendo esto para registrar el contenido (a menos que esté usando la configuración programática). Por lo tanto, sus opciones son
1) ejecutar el postprocesador que elimina los saltos de línea
2) cambie la configuración del registro Y elimine los saltos de línea. Reinicie su aplicación (servidor) y debería ser bueno.

anjanb
fuente