Como faço para que a saída do log java apareça em uma única linha?

124

No momento, uma entrada padrão se parece com isso:

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

Como faço para fazer isso?

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

Esclarecimento Estou usando java.util.logging

Obediah Stane
fonte

Respostas:

81

No Java 7, java.util.logging.SimpleFormatter suporta a obtenção de seu formato a partir de uma propriedade do sistema, portanto, adicionar algo assim à linha de comando da JVM fará com que ela seja impressa em uma linha:

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

Como alternativa, você também pode adicionar isso ao seu 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
fonte
4
Verdadeiro a partir do Java7. Não há menção a isso nos documentos Java6.
jbruni
1
Também na IDEA, trabalha com aspas duplas. @jbruni Isso não funciona no Java6.
27713 Joshua Davis
1
Funciona com aspas simples no Eclipse para mim.
rico
1
Em vez de% 1 $ tY-% 1 $ tm-% 1 $ td% 1 $ tH:% 1 $ tM:% 1 $ tS, você pode escrever% 1 $ tF% 1 $ tT. Torna um pouco mais curto. Não sei se é ainda mais rápido.
Bruno Eberhard
1
... ou in logging.properties, com adaptação baseada na sugestão de @BrunoEberhard e um nome abreviado de logger: java.util.logging.SimpleFormatter.format=%1$tF %1$tT %4$.1s %2$s %5$s%6$s%n
Kariem 20/04/2015
73

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

O Java 7 suporta uma propriedade com a java.util.Formattersintaxe da cadeia de formato.

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

Veja aqui .

Meu favorito é:

-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

o que torna a saída como:

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

2) Colocando nos IDEs

Os IDEs normalmente permitem definir propriedades do sistema para um projeto. Por exemplo, no NetBeans, em vez de adicionar -D ... = ... em algum lugar, adicione a propriedade na caixa de diálogo de ação, na forma de java.util.logging.SimpleFormatter.format=%1$tY-%1$tm-...- sem aspas. O IDE deve descobrir.

3) Colocando isso no Maven - Surefire

Para sua comodidade, veja como colocá-lo no 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) Feito à mão

Eu tenho uma biblioteca com poucas java.util.loggingclasses relacionadas . Entre eles, é SingleLineFormatter. Jar para download aqui .

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
fonte
melhor consumo de memória do que a outra solução.
Tim Williscroft
Tentei fazer isso - mas dá-me o log em XML - o que estou fazendo de errado - stackoverflow.com/questions/16030578/...
user93353
se ele transformar XML em vez do formato que você esperava - isso significa que a configuração no seu arquivo de propriedades não encontrou sua classe de formatador, você pode fazer duas coisas: 1. verifique se sua classe está em um pacote e defina a propriedade de formatador para essa classe e pacote 2. verifique se a sua classe possui um nome exclusivo como "MyFormatter"; por último: verifique se todos os manipuladores têm o formatador desejado (java.util.logging.ConsoleHandler.formatter = my.package.MyFormatter e também: java.util .logging.FileHandler.formatter = my.package.MyFormatter)
Shaybc
Obrigado por compartilhar. Compartilhei um formatador que escrevi em resposta a outra pergunta . Está tudo bem para mim. Eu gosto de ver os truques que outros desenvolvedores inventam para tornar o código menor e mais rápido.
Ryan
1
@ ondra-Žižka Pelo que vale a pena, enviei um patch no seu repositório de códigos do google.
21713 Ryan
61

Semelhante ao Tervor, mas eu gosto de alterar a propriedade no tempo de execução.

Observe que isso precisa ser definido antes da criação do primeiro SimpleFormatter - como foi escrito nos comentários.

    System.setProperty("java.util.logging.SimpleFormatter.format", 
            "%1$tF %1$tT %4$s %2$s %5$s%6$s%n");
Guy L
fonte
6
Observe que isso precisa ser definido antes da criação do primeiro SimpleFormatter - por exemplo, antes de obter os manipuladores do criador de logs global.
Sheepy
5
Essa é a maneira mais rápida de forçar seus logs a gravar em uma única linha sem adicionar outros parâmetros de inicialização à JVM. Mas certifique-se de definir esta propriedade antes de fazer sua chamada para 'new SimpleFormatter ()' no seu código.
Salvador Valencia
36

Como Obediah Stane disse, é necessário criar seu próprio formatmétodo. Mas eu mudaria algumas coisas:

  • Crie uma subclasse diretamente derivada de Formatter, não de SimpleFormatter. O SimpleFormatternão tem mais nada a acrescentar.

  • Cuidado ao criar um novo Dateobjeto! Você deve certificar-se de representar a data do LogRecord. Ao criar um novo Datecom o construtor padrão, ele representará a data e a hora dos Formatterprocessos LogRecord, e não a data em que LogRecordfoi criado.

A classe a seguir pode ser usada como formatador em a Handler, que por sua vez pode ser adicionado ao Logger. Observe que ele ignora todas as informações de classe e método disponíveis no 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
fonte
Tentei fazer isso - mas dá-me o log em XML - o que estou fazendo de errado - stackoverflow.com/questions/16030578/...
user93353
se ele transformar XML em vez do formato que você esperava - isso significa que a configuração no seu arquivo de propriedades não encontrou sua classe de formatador, você pode fazer duas coisas: 1. verifique se sua classe está em um pacote e defina a propriedade de formatador para essa classe e pacote 2. verifique se a sua classe possui um nome exclusivo como "MyFormatter"; por último: verifique se todos os manipuladores têm o formatador desejado (java.util.logging.ConsoleHandler.formatter = my.package.MyFormatter e também: java.util .logging.FileHandler.formatter = my.package.MyFormatter)
Shaybc
10

É isso que estou 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));
    }
}

Você terá 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
fonte
Como podemos fazer com que esse formatador produza informações de exceção, como seu rastreamento de pilha?
fegemo 24/04
1
@egemo Eu acho que você pode imprimir o starcktrace assim. ofNullable(record.getThrown()).ifPresent(v -> v.printStackTrace());pouco antes de retornar a mensagem formatada.
Jin Kwon
7

Configuração do Eclipse

Por captura de tela, no Eclipse, selecione "executar como" e "Executar configurações ..." e adicione a resposta de Trevor Robinson entre aspas duplas, em vez de aspas. Se você perder as aspas duplas, obterá erros "não foi possível encontrar ou carregar a classe principal".

rupweb
fonte
2
Conforme a resposta anterior, isso funciona no Java 7. O Java 6 não possui esse recurso.
27713 Joshua Davis
5

Eu descobri uma maneira que funciona. Você pode subclassificar SimpleFormatter e substituir o método de formato

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

Um pouco surpreso com esta API, eu teria pensado que mais funcionalidade / flexibilidade seriam fornecidas imediatamente

Obediah Stane
fonte
Qualquer pessoa deve usar formatMessage(record)e não record.getMessage(). Os suportes do local não serão alterados.
Jin Kwon
-2

Esse log é específico para seu aplicativo e não um recurso Java geral. Quais aplicativos você está executando?

Pode ser que isso seja proveniente de uma biblioteca de log específica que você esteja usando no seu próprio código. Em caso afirmativo, publique os detalhes de qual você está usando.

Leigh Caldwell
fonte
3
Não é um aplicativo de log aleatório. É o próprio Javajava.util.logging.Logger
André C. Andersen
-2

Se você efetuar login em um aplicativo Web usando o tomcat, adicione:

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

Nos argumentos da VM

Mohammad Irfan
fonte
-3

se você estiver usando java.util.logging, existe um arquivo de configuração que está fazendo isso para registrar o conteúdo (a menos que você esteja usando a configuração programática). Portanto, suas opções são
1) executar o pós-processador que remove as quebras de linha
2) alterar a configuração do log E remover as quebras de linha. Reinicie seu aplicativo (servidor) e você deve ser bom.

anjanb
fonte