Biblioteca vs aplicação: requisitos de logging fundamentalmente diferentes
- Logging de aplicação: configuração e gerenciamento explícitos em um ambiente controlado diretamente pelo desenvolvedor
- Logging de biblioteca: incluído em projetos de terceiros, exigindo respeito ao ambiente e ao poder de escolha do usuário
- Limites das abordagens existentes: ao aplicar loggers centrados em aplicações (winston, Pino) a bibliotecas, surge o problema da imposição
- O dilema de quem cria bibliotecas: fornecer informações de depuração vs não impor ônus ao usuário
Problemas atuais do logging em bibliotecas
- Ecossistema de logging fragmentado: Express usa
DEBUG=express:*, Mongoose usa mongoose.set('debug', true) etc., cada um com uma abordagem diferente
- Dilema das dependências: ao usar bibliotecas centradas em aplicações como winston e Pino, impõem-se ao usuário dependências e configurações indesejadas
- Silêncio vs imposição: a escolha fica entre abrir mão do logging por completo ou forçar um método de logging ao usuário
- Complexidade da injeção de dependência: é uma abordagem mais sofisticada, mas aumenta a complexidade da API e o peso para o usuário
A filosofia "biblioteca em primeiro lugar" do LogTape
- Ativação condicional: se o logging não estiver configurado, não faz absolutamente nada; quando configurado, é gerenciado de forma integrada
- Garantia de escolha para o usuário: a biblioteca não impõe um método de logging e só é ativado quando o usuário quiser
- Zero dependências: tamanho de 5.3KB, eliminando riscos de segurança na cadeia de suprimentos e evitando conflitos de versão
- Suporte completo a ESM/CJS: resolve problemas na cadeia de compatibilidade e otimiza bundles com tree shaking
Vantagens práticas
- Otimização de desempenho: overhead quase zero quando desativado, e excelente desempenho de saída no console quando ativado
- Separação por namespace: categorias hierárquicas no formato
["my-lib", "feature"] evitam conflitos
- Projeto com foco em TypeScript: oferece segurança total de tipos sem pacotes de tipos adicionais
- Integração com sistemas existentes: suporte à adoção gradual por meio de adaptadores para winston e Pino
Considerações realistas
- O significado dos adaptadores: reconhece que ainda não existe um padrão de ecossistema e propõe um compromisso prático
- Inspiração no ecossistema Python: referência ao caso de sucesso do Python, unificado pela biblioteca padrão
logging
- Abordagem orientada ao futuro: apresentada como uma opção para a melhoria gradual do ecossistema de bibliotecas
7 comentários
Não entendo muito bem como isso seria “inoperante” quando não há configuração.
Ao chamar
getLogger, o logger já é criado e, se você emitir umdebug, ele funciona.Pelo que vi no código, isso só faz parecer que não está funcionando,
e também não adia as operações com
string,então, sinceramente, não entendo em que esse “inoperante” é diferente de outras bibliotecas que simplesmente não exibem nada quando você define o nível de log.
Ué, os logs estão sendo emitidos mesmo sem chamar
configure()/configureSync()? Onde eles estão sendo emitidos? Estão sendo exibidos no console?Ah, o que eu quis dizer aqui com funcionar não é que o log seja salvo no console ou em um arquivo, mas sim se a função é executada e se isso de fato gera overhead.
Acho que isso pode ter causado um mal-entendido
Claro, considerando que o principal overhead do logger é a
system call, dá para dizer que não é sem overhead,mas dá para dizer que isso é um diferencial em relação a outros loggers? Nesse ponto, não, porque os outros loggers também funcionam da mesma forma.
Ah, entendi o que você quis dizer. Primeiro, quando rodei um benchmark usando null output como referência, pareceu que praticamente não há overhead. Mas, mais do que o overhead de desempenho, achei que o mais importante era se o comportamento padrão é no-op ou não. Do ponto de vista de quem desenvolve a biblioteca, mesmo que ela gere logs internamente, seria problemático se, ao executar a aplicação que usa essa biblioteca, os logs fossem parar arbitrariamente no console ou em um arquivo.
Ah, era SHOW GN.
Acho que parte do motivo de eu não ter me identificado é que, hoje em dia, o ecossistema costuma escolher muito uma forma em que o logger é injetado de fora.
Se não estiver configurado, naturalmente não funciona.
Mesmo assim, como também é uma interface de logger que não existia nesse ecossistema até agora, e tem bastante liberdade, acho que acaba sendo melhor.
No caso do benchmark que você passou, como ele produz
null outputexcluindo o system call,acho que essa parte realmente pode variar bastante dependendo do formato do logger interno.
Nesse ponto, ele chega a ter uma diferença de até 3x em relação ao Pino. Caramba.
FYI: além disso, a forma de logger injetado de fora que eu mencionei pode ser vista facilmente só olhando o Openai Node sdk, já que ele recebe o logger externamente e faz a saída dessa forma.
https://github.com/dahlia/logtape/…