Saudações, queridos amigos!
Quero compartilhar meus pensamentos sobre o tópico do log e o que eles levaram.
Talvez devido a alguma falta de pesquisa teórica, o registro sempre tenha sido uma zona de turbulência no mundo Java. Com o tempo, isso causou o surgimento de várias bibliotecas para log, como:
- Log4j
- Java Util Logging
- Registro do Commons
- Logback
- Log4j2
Tentando restringir o resto, infelizmente cada um deles introduziu suas próprias falhas.
E se, do ponto de vista da padronização de código, a situação melhorasse após o aparecimento do Slf4j - como uma camada de abstração para registro, problemas ainda não resolvidos ainda estão presentes nas implementações existentes.
Como uma comunidade de código aberto, estamos tomando a iniciativa de criar uma abordagem nova e revolucionária - e criar um criador de logs leve (mas ao mesmo tempo funcionalmente rico), usando os desenvolvimentos mais recentes, como scripts.
Os problemas
- As implementações existentes fornecem apenas suporte parcial para scripts nas configurações
Isso leva à programação declarativa nos arquivos de configuração do criador de logs (XML, JSON, YAML), embora seja muito mais simples interpretar dinamicamente os valores de configuração em tempo de execução usando scripts imperativos.
Vamos dar um exemplo de uma configuração de filtro no Logback, para registrar apenas mensagens com o nível de registro INFO:
<filter class="ch.qos.logback.classic.filter.LevelFilter"> <level>INFO</level> <onMatch>ACCEPT</onMatch> <onMismatch>DENY</onMismatch> </filter>
Este é um exemplo típico de programação XML declarativa.
(sim, o Logback suporta um filtro usando o Groovy, mas se aplica apenas a anexadores específicos, não ao criador de logs)
Mas o suporte de script para formatar a string está completamente ausente.
- Configuração complicada e longa
Veja Logback e Log4j2:
Não há como configurar o nível de log para um aplicativo específico.
Apêndices são configurados separadamente dos registradores e os registradores se referem aos anexos usando o atributo “AppenderRef” - enquanto apenas os registradores suportam a definição do nível de registro e nomes de classe.
Suponha que precisamos excluir mensagens de Depuração de uma classe Foo de um arquivo de log específico sem afetar outros arquivos e classes de log.
No Logback, isso é possível usando o filtro Groovy Script no appender - mas se tivermos muitos anexadores, o tamanho da configuração aumentará exponencialmente.
- Para cada nível de registro - um arquivo separado!
Não foi possível encontrar a possibilidade de uma configuração em que as mensagens sejam agrupadas em arquivos por nível de mensagem (depuração, informações etc.)
Os recursos existentes requerem duplicação de anexadores em cada nível de log.
- Definindo a filtragem pelo nome da classe no próprio registrador raiz
O criador de logs raiz suporta a configuração apenas do nível de criação de log, mas não há possibilidade de controle centralizado de quais classes devem ser registradas.
- Há uma desconexão conceitual entre como os dados do log são gerados no aplicativo e como esses dados são consumidos pelo criador de logs
A prática histórica é tal que os criadores de logs (e suas configurações) são mais centrados em classes do que se fossem centrados em arquivos.
Isso contradiz a percepção humana, que percebe mais logicamente as expectativas em torno do conteúdo final dos arquivos de log, em vez de se preocupar em configurar cada classe individual.
Na prática, esse paradoxo é a razão das limitações funcionais das implementações existentes:
- Configuração complicada do nome do arquivo
- Configuração irracional do logger, por exemplo:
O Logback suporta no máximo 1 "discriminador" no "SiftingAppender".
O SiftingAppender possui limitações nas configurações de política para arquivamento
RoutingAppender redesenhado no Log4j2
Solução
- Suporte completo a scripts na configuração
A bobina usa a configuração como um localizador para scripts Groovy que determinam o comportamento do criador de logs no tempo de execução do aplicativo.
É assim que o exemplo de "filtro" se parece:
{ "levels": "['info'].contains(level)" }
Cada aspecto do criador de logs suporta a customização usando scripts:
- Níveis de log
- Nomes de classe
- Formato da mensagem
- Nomes de arquivos
- Configuração simples e concisa
A bobina não requer codificadores, padrões, filtros, discriminadores e muitas outras coisas desnecessárias.
É configurado com apenas alguns parâmetros básicos:
- Níveis
- Aulas
- Arquivos
- Formato de linha
Arquivos separados para cada nível de log: basta colocar "$ {level}" na máscara de nome de arquivo em Bobbin.json (arquivo de configuração).
Arquivo de configuração de exemplo:
{ "levels": "['debug', 'info', 'warn', 'error'].contains(level)", "destinations": [ { "name": "io.infinite.bobbin.destinations.FileDestination", "properties": { "fileName": "\"./LOGS/PLUGINS/INPUT/${className}/${level}/${className}_${level}.log\"" }, "classes": "className.contains('conf.plugins.input')" }, { "name": "io.infinite.bobbin.destinations.FileDestination", "properties": { "fileName": "\"./LOGS/PLUGINS/OUTPUT/${className}/${level}/${threadName}_${level}_${date}.log\"" }, "classes": "className.contains('conf.plugins.output')" }, { "name": "io.infinite.bobbin.destinations.FileDestination", "properties": { "fileName": "\"./LOGS/THREADS/${threadGroupName}/${threadName}/${level}/${threadName}_${level}_${date}.log\"" }, "classes": "className.contains('io.infinite.')" }, { "name": "io.infinite.bobbin.destinations.FileDestination", "properties": { "fileName": "\"./LOGS/ALL/WARNINGS_AND_ERRORS_${date}.log\"" }, "levels": "['warn', 'error'].contains(level)" }, { "name": "io.infinite.bobbin.destinations.ConsoleDestination", "levels": "['warn', 'error'].contains(level)" } ] }
Experimente o Bobbin agora:
Gradle: compile "io.infinite:bobbin:2.0.0"
* Bobbin é um projeto de código aberto licenciado sob Apache.