DEV Community

Otávio Larrosa
Otávio Larrosa

Posted on

3

Trabalhando com correlationId em .Net + Serilog

Em aplicações distribuídas, uma das coisas mais importantes que devemos ter, é rastreabilidade, principalmente de erros, e uma prática muito comum e eficiente, é trabalharmos com correlation id’s, para diferentes requisições ou workers.

Para implementarmos esse conceito, iremos utilizar como padrão, um exemplo de API, que pode ser encontrada em: otaviolarrosa/DotnetApi (github.com).

Primeiro, iremos utilizar os seguintes pacotes:

  1. Serilog
  2. Serilog.AspNetCore
  3. Serilog.Enrichers.CorrelationId

Conforme exemplificado no arquivo .csproj da aplicação

  <Project Sdk="Microsoft.NET.Sdk.Web">

    <PropertyGroup>
        <TargetFramework>net6.0</TargetFramework>
        <Nullable>enable</Nullable>
        <ImplicitUsings>enable</ImplicitUsings>
    </PropertyGroup>

    <ItemGroup>
        <PackageReference Include="Microsoft.AspNet.WebApi.Core" Version="5.2.9" />
        <PackageReference Include="Serilog" Version="2.11.0" />
        <PackageReference Include="Serilog.AspNetCore" Version="6.0.1" />
        <PackageReference Include="Serilog.Enrichers.CorrelationId" Version="3.0.1" />
        <PackageReference Include="Serilog.Enrichers.Memory" Version="1.0.4" />
        <PackageReference Include="Serilog.Sinks.Console" Version="4.0.1" />
        <PackageReference Include="Swashbuckle.AspNetCore" Version="6.4.0" />
        <PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="6.0.8">
            <PrivateAssets>all</PrivateAssets>
            <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
        </PackageReference>
    </ItemGroup>

    <ItemGroup>
        <ProjectReference Include="..\..\StreamNet\StreamNet\StreamNet.csproj" />
        <ProjectReference Include="..\Application\Application.csproj" />
        <ProjectReference Include="..\Consumers\Consumers.csproj" />
        <ProjectReference Include="..\Infrastructure\Infrastructure.csproj" />
        <ProjectReference Include="..\Producers\Producers.csproj" />
    </ItemGroup>

</Project>
Enter fullscreen mode Exit fullscreen mode

Após isso, também é necessário configurar no startup do projeto, alguns pontos para utilizarmos o Serilog, tais como:

  • Utilização do Serilog com o Enricher do CorrelationId
  • Utilização do Serilog, para utilizar o CorrelationId que vem do chamador da requisição, caso queira uma rastreabilidade integrada
  • Formatação de um template para facilitar a leitura dos logs
using Application.Extensions;
using Consumers;
using Infrastructure.Extensions;
using Producers;
using Serilog;
using StreamNet;

var builder = WebApplication.CreateBuilder(args);


Log.Logger = new LoggerConfiguration()
    .MinimumLevel.Debug()
    .Enrich.WithCorrelationId() //Aqui, pedimos para o Serilog utilizar a feature de correlation Id.
    .Enrich.WithCorrelationIdHeader() //Aqui, pedimos para utilizar o correlation Id, de quem solicitou a chamada na requisição HTTP, para que o trace fique ainda mais rico, com os logs do frontend.
    .WriteTo.Console(outputTemplate: "[{CorrelationId} - {Timestamp:HH:mm:ss} {Level:u3}] {Message:lj}{NewLine}{Exception}") //Aqui, formatamos um template para formatação dos logs padronizados, à fim de facilitar a leitura.
    .CreateLogger();

builder.Host.UseSerilog(); //Adicionamos o Serilog dentro do Host do nosso serviço
builder.Services.AddHttpContextAccessor();
builder.Services.AddSingleton(builder.Logging);

builder.Services.AddControllers();
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();

builder.Services.RegisterApplicationDependencies(builder.Configuration);
builder.Services.RegisterInfrastructureDependencies(builder.Configuration);
builder.Services.AddProducers();
builder.Services.AddConsumers();
builder.Services.AddTopicManagement();

var app = builder.Build();
app.RunMigrations();

// Configure the HTTP request pipeline.
if (app.Environment.IsDevelopment())
{
    app.UseSwagger();
    app.UseSwaggerUI();
}

app.UseAuthorization();

app.MapControllers();

app.Run();
Enter fullscreen mode Exit fullscreen mode

Após isso, temos apenas que utilizar a interface ILogger da abstração Microsoft.Extensions.Logging, como na controller abaixo:

using Application.UseCases.User.CreateUser.Input;
using Application.UseCases.User.RequestCreateUser;
using Microsoft.AspNetCore.Mvc;
using System.Net;

namespace Api.Controllers
{
    [Route("api/[controller]")]
    [ApiController]
    public class UserController : ControllerBase
    {
        private readonly IRequestCreateUserUseCase _requestCreateUserUseCase;
        private readonly ILogger<UserController> _logger;

        public UserController(IRequestCreateUserUseCase requestCreateUserUseCase, ILogger<UserController> logger)
        {
            _requestCreateUserUseCase = requestCreateUserUseCase;
            _logger = logger;
        }

        [HttpPost]
        [Route("/user")]
        public async Task<IActionResult> CreateUser([FromBody]RequestCreateUserInput userInput)
        {
            try
            {
                _logger.LogInformation("Starting request {method} with params {@input}", nameof(CreateUser), userInput);
                await _requestCreateUserUseCase.ExecuteAsync(userInput);
                _logger.LogInformation("Ended request {method} with params {@input}", nameof(CreateUser), userInput);
                return Ok();
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "A unexpected error occurred in {method} with params {@input}", nameof(CreateUser), userInput);
                return StatusCode((int)HttpStatusCode.InternalServerError, "A unexpected error occurred in CreateUser.");
            }
        }
    }
}
Enter fullscreen mode Exit fullscreen mode

E assim, temos como resultado, um template bem simples de ler, e com o correlationId :)

correlationIdTemplate

Sentry image

See why 4M developers consider Sentry, “not bad.”

Fixing code doesn’t have to be the worst part of your day. Learn how Sentry can help.

Learn more

Top comments (0)

A Workflow Copilot. Tailored to You.

Pieces.app image

Our desktop app, with its intelligent copilot, streamlines coding by generating snippets, extracting code from screenshots, and accelerating problem-solving.

Read the docs