Configuração programática com Log4j 2

Configuração programática com Log4j 2

1. Introdução

Neste tutorial, daremos uma olhada em diferentes maneiras de configurar o Apache Log4j 2 de maneira programática.

2. Configuração inicial

Para começar a usar Log4j 2, precisamos apenas incluir as dependênciaslog4j-coreelog4j-slf4j-impl em nossopom.xml:


    org.apache.logging.log4j
    log4j-core
    2.11.0


    org.apache.logging.log4j
    log4j-slf4j-impl
    2.11.0

3. ConfigurationBuilder

Depois de configurar o Maven, precisamos criar umConfigurationBuilder, que é a classe que nos permite configurarappenders, filters, layouts,eloggers.

Log4j 2 fornece várias maneiras de obter umConfigurationBuilder.

Vamos começar da maneira mais direta:

ConfigurationBuilder builder
 = ConfigurationBuilderFactory.newConfigurationBuilder();

E para começar a configurar os componentes,ConfigurationBuilder está equipado com um métodonew correspondente, comonewAppender ornewLayout, para cada componente.

Alguns componentes têm subtipos diferentes, comoFileAppender ouConsoleAppender, e são referidos na API comoplugins.

3.1. Configurando Appenders

Vamos dizer aobuilder para onde enviar cada linha de registro configurando umappender:

AppenderComponentBuilder console
  = builder.newAppender("stdout", "Console");

builder.add(console);

AppenderComponentBuilder file
  = builder.newAppender("log", "File");
file.addAttribute("fileName", "target/logging.log");

builder.add(file);

Enquanto a maioria dos métodosnew não suportam isso,newAppender(name, plugin) nos permite dar um nome ao appender, o que se tornará importante mais tarde. Esses anexadores, nós chamamosstdout elog, embora pudéssemos ter nomeado qualquer coisa.

Também dissemos aobuilder qual anexadorplugin  (ou, mais simplesmente, que tipo de anexador) usar. Console eFile referem-se aos anexos do Log4j 2 para gravação na saída padrão e no sistema de arquivos, respectivamente.

EmboraLog4j 2 supports several appenders,configuring them using Java can be a bit tricky since AppenderComponentBuilder is a generic class for all appender types.

Isso faz com que tenha métodos comoaddAttributeeaddComponent ao invés desetFileNameeaddTriggeringPolicy:

AppenderComponentBuilder rollingFile
  = builder.newAppender("rolling", "RollingFile");
rollingFile.addAttribute("fileName", "rolling.log");
rollingFile.addAttribute("filePattern", "rolling-%d{MM-dd-yy}.log.gz");
rollingFile.addComponent(triggeringPolicies);

builder.add(rollingFile);

E, finalmente,don’t forget to call builder.add to append it to the main configuration!

3.2. Configurando Filtros

Podemos adicionar filtros a cada um de nossos anexadores, que decidem em cada linha de log se deve ou não ser anexado.

Vamos usar o plug-inMarkerFilter em nosso anexador de console:

FilterComponentBuilder flow = builder.newFilter(
  "MarkerFilter",
  Filter.Result.ACCEPT,
  Filter.Result.DENY);
flow.addAttribute("marker", "FLOW");

console.add(flow);

Observe que este métodonew não nos permite nomear o filtro, mas nos pede para indicar o que fazer se o filtro passar ou falhar.

Neste caso, mantivemos as coisas simples, afirmando que seMarkerFilter passa, entãoACCEPT a linha de log. Caso contrário,DENY enta.

Observe, neste caso, que não anexamos isso aobuilder, mas sim aos anexadores que queremos usar este filtro.

3.3. Configurando Layouts

A seguir, vamos definir o layout para cada linha de registro. Nesse caso, usaremos o plug-inPatternLayout:

LayoutComponentBuilder standard
  = builder.newLayout("PatternLayout");
standard.addAttribute("pattern", "%d [%t] %-5level: %msg%n%throwable");

console.add(standard);
file.add(standard);
rolling.add(standard);

Novamente, nós os adicionamos diretamente aos appenders apropriados, em vez de aosbuilder diretamente.

3.4. Configurando o Root Logger

Agora que sabemos para onde os logs serão enviados, queremos configurar quais logs irão para cada destino.

O logger root é o logger mais alto, comoObject em Java. Esse criador de logs é o que será usado por padrão, a menos que seja substituído.

Então, vamos usar um logger root para definir o nível de registro padrão paraERRORe o appender padrão para nosso appenderstdout acima:

RootLoggerComponentBuilder rootLogger
  = builder.newRootLogger(Level.ERROR);
rootLogger.add(builder.newAppenderRef("stdout"));

builder.add(rootLogger);

Para apontar nosso logger para um appender específico, não damos a ele uma instância do construtor. Em vez disso,we refer to it by the name that we gave it earlier.

3.5. Configurando registradores adicionais

Registradores filhos podem ser usados ​​para direcionar pacotes específicos ou nomes de registradores.

Vamos adicionar um logger para o pacotecom em nosso aplicativo, definindo o nível de log paraDEBUGe fazendo com que vá para nosso sappenderlog :

LoggerComponentBuilder logger = builder.newLogger("com", Level.DEBUG);
logger.add(builder.newAppenderRef("log"));
logger.addAttribute("additivity", false);

builder.add(logger);

Observe que podemos definiradditivity com nossos registradores, o que indica se este registrador deve herdar propriedades como nível de registro e tipos de apêndice de seus ancestrais.

3.6. Configurando Outros Componentes

Nem todos os componentes têm um métodonew dedicado emConfigurationBuilder.

Então, nesse caso, chamamosnewComponent.

Por exemplo, porque não há umTriggeringPolicyComponentBuilder, precisamos usarnewComponent  para algo como especificar nossa política de acionamento para anexadores de arquivo contínuo:

ComponentBuilder triggeringPolicies = builder.newComponent("Policies")
  .addComponent(builder.newComponent("CronTriggeringPolicy")
    .addAttribute("schedule", "0 0 0 * * ?"))
  .addComponent(builder.newComponent("SizeBasedTriggeringPolicy")
    .addAttribute("size", "100M"));

rolling.addComponent(triggeringPolicies);

3.7. O equivalente em XML

ConfigurationBuilder comes equipados com um método prático para imprimir o XML equivalente:

builder.writeXMLConfiguration(System.out);

A execução da linha acima é impressa:



   
      
         
         
      
      
         
         
            
            
         
      
      
         
      
   
   
      
         
      
      
         
      
   

Isso é útil quando queremos verificar novamente nossa configuração ou se queremos persistir, digamos, no sistema de arquivos.

3.8. Juntando tudo

Agora que estamos totalmente configurados, vamos dizer ao Log4j 2 para usar nossa configuração:

Configurator.initialize(builder.build());

Depois de invocado,future calls to Log4j 2 will use our configuration.

Observe que isso significa que precisamos invocarConfigurator.initialize antes de fazermos qualquer chamada paraLogManager.getLogger.

4. ConfigurationFactory

Agora que vimos uma maneira de obter e aplicarConfigurationBuilder, vamos dar uma olhada em mais uma:

public class CustomConfigFactory
  extends ConfigurationFactory {

    public Configuration createConfiguration(
      LoggerContext context,
      ConfigurationSource src) {

        ConfigurationBuilder builder = super
          .newConfigurationBuilder();

        // ... configure appenders, filters, etc.

        return builder.build();
    }

    public String[] getSupportedTypes() {
        return new String[] { "*" };
    }
}

Nesse caso, em vez de usarConfigurationBuilderFactory, criamos uma subclasse deConfigurationFactory, uma classe abstrata destinada à criação de instâncias deConfiguration.

Então, em vez de chamarConfigurator.initialize como fizemos da primeira vez, simplesmente precisamos informar ao Log4j 2 sobre nossa nova fábrica de configuração.

Existem três formas de fazer isso:

  • Inicialização estática

  • Uma propriedade de tempo de execução, ou

  • A anotação@Plugin 

4.1. Usar inicialização estática

Log4j 2 suporta a chamada desetConfigurationFactory  durante a inicialização estática:

static {
    ConfigurationFactory custom = new CustomConfigFactory();
    ConfigurationFactory.setConfigurationFactory(custom);
}

Esta abordagem tem a mesma limitação da última abordagem que vimos, que é que precisaremos invocá-labefore any calls to LogManager.getLogger.

4.2. Use uma propriedade de tempo de execução

Se tivermos acesso ao comando de inicialização do Java, o Log4j 2 também suporta a especificação deConfigurationFactory to use por meio de um parâmetro-D:

-Dlog4j2.configurationFactory=com.example.log4j2.CustomConfigFactory

O principal benefício desta abordagem é que não precisamos nos preocupar com a ordem de inicialização, como fazemos com as duas primeiras abordagens.

4.3. Use a anotação@Plugin 

E, finalmente, nas circunstâncias em que não queremos mexer no comando de inicialização do Java adicionando-D, podemos simplesmente anotar nossoCustomConfigurationFactory com a anotação Log4j 2@Plugin :

@Plugin(
  name = "CustomConfigurationFactory",
  category = ConfigurationFactory.CATEGORY)
@Order(50)
public class CustomConfigFactory
  extends ConfigurationFactory {

  // ... rest of implementation
}

Log4j 2 varrerá o caminho de classe em busca de classes com a anotação@Plugin annotation e, encontrando esta classe na categoriaConfigurationFactory , irá usá-la.

4.4. Combinando com configuração estática

Outro benefício de usar uma extensãoConfigurationFactory é que podemos facilmente combinar nossa configuração personalizada com outras fontes de configuração como XML:

public Configuration createConfiguration(
  LoggerContext context,
  ConfigurationSource src) {
    return new WithXmlConfiguration(context, src);
}

O parâmetrosource representa o arquivo de configuração XML ou JSON estático que o Log4j 2 encontra, se houver.

Podemos pegar esse arquivo de configuração e enviá-lo para nossa implementação personalizada deXmlConfiguration, onde podemos colocar qualquer configuração de substituição necessária:

public class WithXmlConfiguration extends XmlConfiguration {

    @Override
    protected void doConfigure() {
        super.doConfigure(); // parse xml document

        // ... add our custom configuration
    }
}

5. Conclusão

Neste artigo, vimos como usar a nova APIConfigurationBuilder disponível no Log4j 2.

Também analisamos a personalização da combinação deConfigurationFactory in comConfigurationBuilder para casos de uso mais avançados.

Não se esqueça de verificar meus exemplos completosover on GitHub.