Blog
Domine a plataforma e otimize seus gastos!
Criando logs com o Serilog - parte 1
O Serilog é uma biblioteca de registro (logging) para o .NET que oferece flexibilidade, desempenho e facilidade de uso. Ele é projetado para fornecer uma maneira estruturada de registrar informações em aplicativos .NET. A grande vantagem do Serilog é sua capacidade de lidar com dados estruturados de forma eficiente, o que permite uma análise mais profunda e fácil dos registros. Com sua sintaxe simples e poderosa, torna a configuração e o uso do registro em aplicativos .NET uma tarefa simples e eficaz.
Nesse post, vamos fazer uma introdução ao Serilog, e aos seus sinks! Para isso, vamos precisar que você tenha o .NET instalado em sua máquina.
Inicialmente iremos criar um diretório raiz para nossa solução.
mkdir LoggingSerilogSeq
Após isso, vamos criar um gitignore, uma solution e um projeto do tipo web api.
dotnet git ignore
dotnet new sln
dotnet new webapi -n App
dotnet sln add App/App.csproj
Precisamos instalar o pacote NuGet Serilog.AspNetCore.
dotnet add package Serilog.AspNetCore
Criaremos um extension method para configurar o Serilog em nosso projeto. Observe que estamos configurando apenas o logger para ser feito no console.
using Serilog;
using Serilog.Sinks.SystemConsole.Themes;
namespace App.Logging;
public static class LoggerExtensions
{
public static WebApplicationBuilder AddCustomLogging(this WebApplicationBuilder builder)
{
// Create the logger configuration
var loggerConfig = new LoggerConfiguration();
// Add console provider
loggerConfig.WriteTo.Console(theme: SystemConsoleTheme.Colored);
// Create logger
var logger = loggerConfig.CreateLogger();
// Clear providers
builder.Logging.ClearProviders();
// Add Serilog
builder.Logging.AddSerilog(logger);
return builder;
}
}
Com essa classe estática pronta, vamos refatorar o Program.cs.
using App.Logging;
using Microsoft.AspNetCore.Http.HttpResults;
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();
// Logging
builder.AddCustomLogging();
var app = builder.Build();
app.UseSwagger();
app.UseSwaggerUI();
app.UseHttpsRedirection();
app.MapGet("/logging", (ILogger<Program> logger) =>
{
logger.LogTrace("This is a trace log");
logger.LogDebug("This is a debug log");
logger.LogInformation("This is an information log");
logger.LogWarning("This is a warning log");
logger.LogError("This is an error log");
logger.LogCritical("This is a critical log");
return Results.Ok();
})
.WithName("LoggingEndpoint")
.WithOpenApi();
app.Run();
No endpoint /logging, estamos fazendo vários logs com diferentes níveis de gravidade!
Vamos executar o endpoint e ver o resultado em nosso console:


Observe que foram gerados vários logs por nossa web api, e entre eles, os que foram configurados anteriormente.

Porém, apenas logs com níveis de gravidades maiores do que Information foram gerados. Isso se deve ao minimum level que pode ser configurado!
Vamos alterar esse valor para verbose e repetir o processo:
// MinimumLevel
loggerConfig.MinimumLevel.Verbose();

Todos os logs foram gerados com sucesso!
Vamos agora remover todos os logs que não foram escritos por nós, como os mostrados abaixo:

Para isso, precisamos definir que para logs gerados pelos pacotes iniciados por "Microsoft", o level mínimo é Error.
// Microsoft minimum log level
loggerConfig.MinimumLevel.Override("Microsoft", LogEventLevel.Error);
Podemos repetir o teste e verificar o resultado:

Para o log de exceptions, podemos implementar o seguinte código:
try
{
throw new Exception("*** Error ***");
}
catch (Exception e)
{
logger.LogCritical(e, "This is an exception!");
}
É necessário adicionar pacote NuGet Serilog.Exceptions e fazer uma configuração extra ao nosso projeto.
dotnet add package Serilog.Exceptions
// Set application name
loggerConfig.Enrich.WithExceptionDetails();
Com isso, temos o resultado:

Os "sinks" no contexto do Serilog referem-se aos destinos para onde os logs são direcionados após serem gerados pelo aplicativo. Eles são componentes cruciais para o fluxo de registro, permitindo que os registros sejam armazenados, exibidos ou processados de várias maneiras.
Para exemplificar, podemos enviar nossos logs para a ferramenta Seq. Para isso, vamos adicionar o seguinte pacote:
dotnet add package Serilog.Sinks.Seq
Para rodar o Seq localmente, vamos criar um docker compose com o seguinte conteúdo
version: '3'
services:
seq:
image: datalust/seq:latest
ports:
- '8090:80'
- '5341:5341'
environment:
- ACCEPT_EULA=Y
Podemos executá-lo.
docker compose up -d
Já na nossa web api, precisamos fazer uma nova configuração para que os logs sejam enviados a essa ferramenta corretamente.
loggerConfig.WriteTo.Seq("http://localhost:5341");
Com a web api rodando, podemos acessar a UI do Seq e verificar que os logs foram gerados corretamente!
http://localhost:8090


Podemos ainda adicionar propriedades adicionais na configuração do Serilog. Por exemplo, o nome da nossa aplicação:
loggerConfig.Enrich.WithProperty("Application", "my-web-api");

Outro exemplo de sink muito utilizado, é Serilog.Sinks.File. Para utilizá-lo, iremos precisar instalar o seguinte pacote NuGet e adicionar outra configuração ao projeto:
dotnet add package Serilog.Sinks.File
// Add File
loggerConfig.WriteTo.File("log.txt", rollingInterval: RollingInterval.Day);
Após a execução do endpoint, podemos ver que o log foi gerado em arquivos .txt!

Essa é só a primeiro parte de uma série de posts relacionados ao Serilog e seus sinks!
Não esquece de me seguir no LinkedIn!
Até a próxima, abraços!