Introdução ao Log4j2 - Anexos, layouts e filtros

Introdução ao Log4j2 - Anexos, layouts e filtros

1. Visão geral

Registrar eventos é um aspecto crítico do desenvolvimento de software. Embora existam muitas estruturas disponíveis no ecossistema Java, o Log4J é o mais popular há décadas, devido à flexibilidade e simplicidade que ele fornece.

Log4j 2 é uma versão nova e aprimorada do framework Log4j clássico.

Neste artigo, apresentaremos os appenders, layouts e filtros mais comuns por meio de exemplos práticos.

No Log4J2, um appender é simplesmente um destino para eventos de log; pode ser tão simples quanto um console e pode ser complexo como qualquer RDBMS. Os layouts determinam como os logs serão apresentados e os filtros filtram os dados de acordo com os vários critérios.

2. Configuração

Para entender vários componentes de registro e sua configuração, vamos definir diferentes casos de uso de teste, cada um consistindo em um arquivo de configuraçãolog4J2.xml e uma classe de testeJUnit 4.

Duas dependências independentes são comuns a todos os exemplos:


    org.apache.logging.log4j
    log4j-core
    2.7


    org.apache.logging.log4j
    log4j-core
    2.7
    test-jar
    test

Além do pacotelog4j-core principal, precisamos incluir o ‘test jar 'pertencente ao pacote para obter acesso a uma regra de contexto necessária para testar arquivos de configuração com nomes incomuns.

3. Configuração padrão

ConsoleAppender é a configuração padrão do pacote principalLog4J 2. Ele registra as mensagens no console do sistema em um padrão simples:



    
        
            
        
    
    
        
            
        
    

Vamos analisar as tags nesta configuração XML simples:

  • Configuration: O elemento raiz de um arquivo de configuraçãoLog4J 2 e atributostatus é o nível dos eventos Log4J internos, que queremos registrar

  • Appenders: Este elemento está segurando um ou mais appenders. Aqui, vamos configurar um appender que envia para o console do sistema na saída padrão

  • Loggers: Este elemento pode consistir em vários elementosLogger configurados. Com a tag especialRoot, você pode configurar um logger padrão sem nome que receberá todas as mensagens de log do aplicativo. Cada criador de logs pode ser definido com um nível mínimo de registro

  • AppenderRef: Este elemento define uma referência a um elemento da seçãoAppenders. Portanto, o atributo 'ref' está vinculado a um atributo 'name' de anexos

O teste unitário correspondente será igualmente simples. Obteremos uma referênciaLogger e imprimiremos duas mensagens:

@Test
public void givenLoggerWithDefaultConfig_whenLogToConsole_thanOK()
  throws Exception {
    Logger logger = LogManager.getLogger(getClass());
    Exception e = new RuntimeException("This is only a test!");

    logger.info("This is a simple message at INFO level. " +
      "It will be hidden.");
    logger.error("This is a simple message at ERROR level. " +
    "This is the minimum visible level.", e);
}

4. ConsoleAppender comPatternLayout

Vamos definir um novo appender de console com um padrão de cor personalizado em um arquivo XML separado e incluí-lo em nossa configuração principal:



    

Este arquivo está usando algumas variáveis ​​padrão que são substituídas porLog4J 2 no tempo de execução:

  • %style\{…}{colorname}: Isso imprimirá o texto no primeiro par de colchetes () em uma determinada cor (colorname).

  • %highlight\{…}\{FATAL=colorname, …}: Isso é semelhante à variável de 'estilo'. Mas uma cor diferente pode ser dada para cada nível de log.

  • %date{format}: É substituído pela data atual noformat especificado. Aqui, estamos usando o formato DateTime ‘DEFAULT’,yyyy_-MM-dd HH: mm: ss, SSS'_.

  • %-5level: Imprime o nível da mensagem de log alinhado à direita.

  • %message: Representa a mensagem de log bruta

Mas existem muito mais variáveis ​​e formatação emPatternLayout.. Você pode consultá-los na documentação oficial deLog4J 2.

Agora vamos incluir o anexador de console definido em nossa configuração principal:



    
        
    
    
        
            
        
    

O teste de unidade:

@Test
public void givenLoggerWithConsoleConfig_whenLogToConsoleInColors_thanOK()
  throws Exception {
    Logger logger = LogManager.getLogger("CONSOLE_PATTERN_APPENDER_MARKER");
    logger.trace("This is a colored message at TRACE level.");
    ...
}

5. Anexador de arquivo assíncrono comJSONLayout eBurstFilter

Às vezes, é útil escrever mensagens de registro de maneira assíncrona. Por exemplo, se o desempenho do aplicativo tiver prioridade sobre a disponibilidade dos logs.

Em tais casos de uso, podemos usar umAsyncAppender.

Para o nosso exemplo, estamos configurando um arquivo de logJSON assíncrono. Além disso, incluiremos um filtro de burst que limita a saída de log a uma taxa especificada:



    
        ...
        
            
            
        
        
            
        
    
    
        ...
        
            
        
        
            
        
    

Notar que:

  • OJSONLayout é configurado de forma que grava um evento de log por linha

  • OBurstFilter descartará todos os eventos com o nível 'INFO' e acima se houver mais de dois deles, mas no máximo 10 eventos descartados

  • OAsyncAppender é definido como um buffer de 80 mensagens de log; depois disso, o buffer é liberado para o arquivo de log

Vamos dar uma olhada no teste de unidade correspondente. Estamos enchendo o buffer anexado em um loop, deixe-o gravar no disco e inspecione a contagem de linhas do arquivo de log:

@Test
public void givenLoggerWithAsyncConfig_whenLogToJsonFile_thanOK()
  throws Exception {
    Logger logger = LogManager.getLogger("ASYNC_JSON_FILE_APPENDER");

    final int count = 88;
    for (int i = 0; i < count; i++) {
        logger.info("This is async JSON message #{} at INFO level.", count);
    }

    long logEventsCount
      = Files.lines(Paths.get("target/logfile.json")).count();
    assertTrue(logEventsCount > 0 && logEventsCount <= count);
}

6. RollingFile Appender eXMLLayout

A seguir, criaremos um arquivo de registro contínuo. Após um tamanho de arquivo configurado, o arquivo de log é compactado e girado.

Desta vez, estamos usando um layoutXML:



    
        
            
            
                
            
        
    
    
        
            
        
        
            
        
    

Notar que:

  • O appenderRollingFile tem um atributo ‘filePattern ', que é usado para nomear arquivos de log girados e pode ser configurado com variáveis ​​de espaço reservado. No nosso exemplo, ele deve conter uma data e um contador antes do sufixo do arquivo.

  • A configuração padrão deXMLLayout gravará objetos de eventos de log únicos sem o elemento raiz.

  • Estamos usando uma política baseada em tamanho para girar nossos arquivos de registro.

Nossa classe de teste de unidade será semelhante à da seção anterior:

@Test
public void givenLoggerWithRollingFileConfig_whenLogToXMLFile_thanOK()
  throws Exception {
    Logger logger = LogManager.getLogger("XML_ROLLING_FILE_APPENDER");
    final int count = 88;
    for (int i = 0; i < count; i++) {
        logger.info(
          "This is rolling file XML message #{} at INFO level.", i);
    }
}

7. Syslog Appender

Digamos que precisamos enviar eventos registrados para uma máquina remota na rede. A maneira mais simples de fazer isso usando Log4J2 seria usandoSyslog Appender:



    
        ...
        
        
    
    
        ...
        
            
        
        
            
        
    

Os atributos na tagSyslog:

  • name: define o nome do anexador e deve ser exclusivo. Como podemos ter vários anexadores Syslog para o mesmo aplicativo e configuração

  • format: pode ser definido como BSD ou RFC5424, e os registros Syslog seriam formatados de acordo

  • host & port: o nome do host e a porta da máquina do servidor Syslog remoto

  • protocol: se usar TCP ou UPD

  • facility: para qual facilidade Syslog o evento será gravado

  • connectTimeoutMillis: período de tempo de espera por uma conexão estabelecida, o padrão é zero

  • reconnectionDelayMillis: tempo de espera antes de tentar novamente a conexão

8. FailoverAppender

Agora, pode haver casos em que um appender falha ao processar os eventos de log e não queremos perder os dados. Nesses casos, oFailoverAppender é útil.

Por exemplo, se o anexadorSyslog falhar ao enviar eventos para a máquina remota, em vez de perder esses dados, podemos voltar paraFileAppender temporariamente.

OFailoverAppender leva um anexador primário e um número de anexadores secundários. No caso de falha do primário, ele tenta processar o evento de registro com os secundários em ordem até que um seja bem-sucedido ou não haja nenhum secundário para tentar:


    
        
    

Vamos testar:

@Test
public void givenLoggerWithFailoverConfig_whenLog_thanOK()
  throws Exception {
    Logger logger = LogManager.getLogger("FAIL_OVER_SYSLOG_APPENDER");
    Exception e = new RuntimeException("This is only a test!");

    logger.trace("This is a syslog message at TRACE level.");
    logger.debug("This is a syslog message at DEBUG level.");
    logger.info("This is a syslog message at INFO level.
      This is the minimum visible level.");
    logger.warn("This is a syslog message at WARN level.");
    logger.error("This is a syslog message at ERROR level.", e);
    logger.fatal("This is a syslog message at FATAL level.");
}

9. JDBC Appender

O aplicativo JDBC envia eventos de log para um RDBMS, usando JDBC padrão. A conexão pode ser obtida usando qualquer fonte de dados JNDI ou qualquer connection factory.

A configuração básica consiste emDataSource ouConnectionFactory, ColumnConfigs etableName:


    
    
    
    
    
    

Agora vamos experimentar:

@Test
public void givenLoggerWithJdbcConfig_whenLogToDataSource_thanOK()
  throws Exception {
    Logger logger = LogManager.getLogger("JDBC_APPENDER");
    final int count = 88;
    for (int i = 0; i < count; i++) {
        logger.info("This is JDBC message #{} at INFO level.", count);
    }

    Connection connection = ConnectionFactory.getConnection();
    ResultSet resultSet = connection.createStatement()
      .executeQuery("SELECT COUNT(*) AS ROW_COUNT FROM logs");
    int logCount = 0;
    if (resultSet.next()) {
        logCount = resultSet.getInt("ROW_COUNT");
    }
    assertTrue(logCount == count);
}

10. Conclusão

Este artigo mostra exemplos muito simples de como você pode usar diferentes anexos de log, filtro e layouts com o Log4J2 e maneiras de configurá-los.

Os exemplos que acompanham o artigo estão disponíveisover on GitHub.