
Compartilhar:
Steve é um ex-membro da equipe da Vonage. Ele atuou como Developer Advocate .NET na Vonage, engenheiro de software full-stack poliglota, especializado em IA/ML
Registro adaptável de bibliotecas com o Microsoft.Extensions.Logging
Como Aprendi a Deixar de Me Preocupar e a Adorar Registrar Minhas Atividades
Ao longo da minha carreira, trabalhei em alguns projetos .NET de média a grande escala. Em cada projeto, encontrei um tipo diferente de registrador de logs e, normalmente, todos eles utilizavam mais de um registrador!
Normalmente, a história é mais ou menos assim: “No início, não conseguíamos decidir qual logger usar, então criamos o nosso próprio. Depois, percebemos que a forma como havíamos implementado o registro de logs não era a mais eficiente, então mudamos para o logger X à medida que o aplicativo crescia. Não queríamos voltar atrás e remover o logger antigo, pois isso implicaria mexer em todos os arquivos da nossa solução; por isso, simplesmente o removemos dos locais onde ele estava causando problemas e, a partir de agora, vamos usar apenas o logger X para tudo.”
Como eu disse, esse é um problema surpreendentemente comum — e que podemos contornar ao separar o registrador do processo de registro.
Registro na biblioteca Nexmo .NET
Recentemente, tenho dado uma olhada no .NET Server SDK e vim organizando algumas coisas. Ao fazer isso, percebi que nossa estrutura de registro de logs LibLog foi descontinuada.
Essa ferramenta foi ótima, pois separou o logger da operação de registro de logs. Ela permitiu que qualquer pessoa que desenvolvesse com nosso SDK pudesse usar seu próprio logger. Desde que seu logger fosse compatível, era possível fazer com que o logger do SDK funcionasse em conjunto com o logger de sua escolha, sem qualquer intervenção (o que, na prática, poderia ser uma vantagem ou uma desvantagem, dependendo do ponto de vista).
Devido ao fato de o LibLog ter sido descontinuado, fui obrigado a procurar em outro lugar uma ferramenta de registro de logs que atendesse às nossas necessidades. Felizmente, não precisei procurar muito longe.
Avançando com o Microsoft.Extensions.Logging
O (relativamente) novo Microsoft.Extensions.Logging acertou em cheio em termos de funcionalidade. Com o pacote de extensão, basta instalar o pacote NuGet, juntamente com qualquer estrutura de registro de logs que você tenha escolhido usar, configurar uma fábrica e criar o registrador.
Isso se encaixa no nosso caso de uso, já que não queremos necessariamente que nossos logs sejam automaticamente anexados e intercalados aos logs dos nossos usuários — e, ao mesmo tempo, não queremos ditar aos nossos usuários exatamente onde, como e com qual estrutura os logs serão capturados.
Portanto, com o lançamento da nossa próxima versão principal, a 5.0.0, você poderá ativar dinamicamente qualquer nível ou categoria que desejar dentro do SDK, bastando para isso substituir a Logger Factory no SDK.
Criação de registradores de log com o Microsoft.Extensions.Logging
Criar o provedor de logs
Dois componentes constituem a base do Microsoft.Extensions.Logging: ILoggerFactory e ILogger. A fábrica gera os loggers e o logger realiza o registro.
Esses dois componentes são utilizados na classe LogProvider para nos permitir criar um registrador de logs totalmente dinâmico e extensível para a biblioteca, permitindo que o desenvolvedor utilize seu próprio registrador de logs.
public static class LogProvider
{
private static IDictionary<string, ILogger> _loggers = new Dictionary<string, ILogger>();
private static ILoggerFactory _loggerFactory = new LoggerFactory();
public static void SetLogFactory(ILoggerFactory factory)
{
_loggerFactory?.Dispose();
_loggerFactory = factory;
_loggers.Clear();
}
public static ILogger GetLogger(string category)
{
if (!_loggers.ContainsKey(category))
{
_loggers[category] = _loggerFactory?.CreateLogger(category)?? NullLogger.Instance;
}
return _loggers[category];
}
}Em nosso modelo, criamos uma classe estática chamada LogProvider com dois campos: _loggers, um dicionário que contém o logger para cada categoria, e _loggerFactory, que cria os loggers.
Existem também dois métodos: SetLogFactory, que descarta a LogFactory antiga e define a fábrica de logs como a nova fábrica de logs passada como parâmetro, e GetLogger, que verifica os _loggers para ver se o logger dessa categoria já foi criado e, caso contrário, cria um.
Como usar o Log Provider
Agora, ao iniciar qualquer método do qual desejamos gerar registros, basta chamar o `GetLogger` com a categoria apropriada:
var logger = Api.Logger.LogProvider.GetLogger(LOGGER_CATEGORY); Exploração madeireira
A partir daqui, basta usar o logger como qualquer outro logger que já vimos antes. Por exemplo:
logger.LogInformation("Available authentication: {0}", string.Join(",", authCapabilities));Isso registrará, como informação, os recursos de autenticação disponíveis no formato que você tiver definido para o seu registrador de logs.
Configurando registradores adaptativos
Agora que já abordamos a criação e o uso dos registradores de log, vamos ver como configurá-los para que façam o que queremos.
Selecione seu provedor de registros
Uma das vantagens do Microsoft.Extensions.Logging é que ele é independente do provedor de log que você usa. Desde que o provedor de log implemente a ILogProvider interface, ele pode ser qualquer um que você quiser. E, do ponto de vista do desenvolvedor que deseja utilizá-lo, é ainda mais simples. A maioria dos principais provedores de log de terceiros que você provavelmente usará (por exemplo, Log4Net, Serilog, NLog etc.) possui pacotes de extensão que facilitam a adição do logger desejado.
Registro em console com o Serilog
Para demonstrar como podemos criar esses registradores, vamos usar o exemplo de registro de log no Console com o Serilog. Para isso, você precisará dos seguintes pacotes do NuGet:
Microsoft.Extensions.Logging
Serilog.Extensions.Logging
Serilog.Sinks.Console
Em seguida, você fará o seguinte:
Crie um novo LoggerFactory, que será o que usaremos para criar
Crie uma nova LoggerConfiguration que definirá a configuração do Serilog
Chame a função AddSerilog na fábrica
Criar um registrador da categoria 'teste'
Fechar sessão
Quando encadeados, fica assim:
var log = new LoggerConfiguration()
.MinimumLevel.Debug()
.WriteTo.Console(outputTemplate: "{Timestamp:HH:mm} [{Level}] ({Name:l}) {Message}\n")
.CreateLogger();
var factory = new LoggerFactory();
factory.AddSerilog(log);
ILogger logger = factory.CreateLogger("test");
logger.LogInformation("Hello world");Muito limpo e simples.
Agora, para interagir com o SDK da Nexmo, em vez de criar um registrador após configurar a fábrica, basta definir o LogFactory no Log Provider como a fábrica de registros que você criou e à qual adicionou o Serilog, e você verá os registros serem enviados pelo SDK.
var log = new LoggerConfiguration()
.MinimumLevel.Debug()
.WriteTo.Console(outputTemplate: "{Timestamp:HH:mm} [{Level}] ({Name:l}) {Message}\n")
.CreateLogger();
var factory = new LoggerFactory();
factory.AddSerilog(log);
LogProvider.SetLogFactory(factory);Et voilà — nosso próprio registrador de log de biblioteca, altamente configurável.
Benefícios
O Microsoft.Extensions.Logging nos permite evitar o cenário apavorante de iniciar um projeto usando um registrador de logs e, por qualquer motivo, precisar mudar para outro.
Se você quiser usar seu logger, pode fazê-lo à vontade, mesmo ao utilizar as Extensões de Logging. Basta implementar a interface ILogProvider com o logger de sua preferência e adicioná-la à fábrica.