Novidades do .NET 6: Compile-time logging source generation em ASP.NET Core
No final do último mês (Maio) aconteceu a edição 2021 do Microsoft Build, a conferência anual da Microsoft para Desenvolvedores. Foram inúmeros anúncios envolvendo a plataforma .NET, com as postagens a seguir detalhando algumas dessas novidades:
Já publiquei inclusive aqui neste blog 8 artigos cobrindo novos recursos que vieram com esta edição do Build, com o lançamento do Preview 4 do .NET 6:
Novidades do .NET 6: suporte a Hot Reload no Visual Studio 2019
Novidades do .NET 6: Minimal APIs em ASP.NET Core
Novidades do .NET 6: HTTP Logging no ASP.NET Core
Novidades do .NET 6: melhorias em LINQ - ExceptBy e DistinctBy
Novidades do .NET 6: melhorias em LINQ - FirstOrDefault, LastOrDefault e SingleOrDefault
Novidades do .NET 6: DateOnly e TimeOnly structs
Novidades do .NET 6: melhorias em LINQ - UnionBy e IntersectBy
Novidades do .NET 6: melhorias em LINQ - MaxBy e MinBy
Aproveito esse espaço para um convite…
Dia 30/06 (segunda) às 21:00 — horário de Brasília — teremos mais um evento online e gratuito no canal Canal .NET.
Ao longo desta live abordarei dicas, truques e alternativas úteis para o desenvolvimento Back-End e de APIs REST com .NET 5, ASP.NET Core, Azure Functions. Ao longo da apresentação será coberto o uso de diferentes frameworks, serviços na nuvem, mensageria, bancos de dados e boas práticas de forma a facilitar e tornar mais dinâmica a implementação de soluções baseadas na plataforma .NET no seu dia a dia.
Teremos também algumas novidades do .NET 6 demonstradas na prática!
Para participar faça sua inscrição no link a seguir, a transmissão acontecerá via YouTube:
E neste novo post abordo uma novidade do .NET 6 Preview 4 envolvendo a produção de logs: Compile-time logging source generation, utilizando para isto um exemplo em ASP.NET Core.
O conceito de source generators foi introduzido ainda com o C# 9, oferecendo a possibilidade de geração de código em tempo de compilação e empregando técnicas de metaprogramação. Este assunto foi inclusive tema de uma live recente no Canal .NET e que está disponível no YouTube:
Para ativar essa funcionalidade neste momento será necessário adicionar a versão Preview do package Microsoft.Extensions.Logging, como indicado no arquivo .csproj de uma API REST que criei para testes (linha 8):
Supondo uma implementação como a da classe CalculoFinanceiroController e indicada na listagem a seguir, em que foram utilizados os métodos LogInformation (linhas 26 e 45) e LogError (linha 60):
Podemos refatorar este tipo e simplificar a produção de logs, utilizando para isso extensões de ILogger que empreguem compile-time logging source generation.
Na próxima listagem temos o código para o tipo FinancasLogging:
- Esta classe foi marcada como partial e static. Os diferentes métodos que constituem a mesma também (LogNovaRequisicaoCalculo, LogValorComJuros e LogParametroInvalido), além de terem sido definidos como void;
- As chamadas aos métodos LogNovaRequisicaoCalculo e LogValorComJuros substituem o acionamento de LogInformation, ao passo que invocar LogParametroInvalido tem o mesmo efeito com LogError;
- Em todos os métodos foi associado o atributo LoggerMessage, com o preenchimento das propriedades EventId, Level (em que se especifica o LogLevel, como Information ou Error) e Message. Por serem extensões de ILogger tais métodos recebem como primeiro parâmetro uma instância baseada nesta interface, a qual foi marcada com this;
- No caso específico de Message é possível observar que os parâmetros de cada método (excetuando a instância de ILogger) foram mapeados para placeholders, de forma que a string correspondente à mensagem de log tenha seu valor gerado com base em tais parâmetros.
Mas e quanto às implementações destes 3 métodos (LogNovaRequisicaoCalculo, LogValorComJuros e LogParametroInvalido) e à própria classe FinancasLogging, que foram todos especificados como partial? É aqui que conhecemos o potencial de optar pelo uso de compile-time logging source generation.
As implementações correspondentes serão geradas ao se identificar a presença do atributo LoggerMessage. Trata-se certamente de uma abordagem mais performática, dispensando uma série de manipulações que poderiam ocorrer em tempo de execução (e comumente presentes em soluções de logging).
Mas um alerta importante deve ser feito…
Erros de compilação serão gerados se não houver correspondência entre os parâmetros de um método marcado com LoggerMessage e os placeholders na propriedade Message. É o que demonstra a imagem a seguir:
Ao corrigir os erros apontados teremos então sucesso no build via Terminal do Visual Studio Code:
As diferentes possibilidades de implementações utilizando compile-time logging source generation podem ser encontradas na documentação deste recurso:
Compile-time logging source generation | Microsoft Docs
Na próxima listagem temos a versão refatorada de CalculoFinanceiroController, com as chamadas aos métodos LogNovaRequisicaoCalculo, LogValorComJuros e LogParametroInvalido:
Ao efetuar o debugging do método LogNovaRequisicaoCalculo será possível notar o código de implementação gerado automaticamente, bem como a produção da mensagem com base nos parâmetros informados ao invocar esta operação (a extensão Thunder Client foi utilizada aqui para testes de envio de requisições):
O mesmo comportamento será observado com o método LogValorComJuros:
E também com o método LogParametroInvalido:
Este projeto também foi disponibilizado no GitHub, já com implementações para os Previews 4 e 5:
https://github.com/renatogroffe/ASPNETCore6-Preview4-REST_API-LoggingSourceGeneration_JurosCompostos
https://github.com/renatogroffe/ASPNETCore6-Preview5-REST_API-LoggingSourceGeneration_JurosCompostos
Referências
.NET 6 - Guia de Referência: artigos, vídeos e exemplos de utilização
ASP.NET Core updates in .NET 6 Preview 4 | ASP.NET Blog
Announcing .NET 6 Preview 4 | .NET Blog
Compile-time logging source generation | Microsoft Docs
Dicas de Visual Studio Code: testes de APIs REST e integração com Azure DevOps | parte 4