Usar um agente para adicionar mensagens de log personalizadas

Concluído

O .NET fornece APIs que você pode usar para registrar dados de telemetria personalizados. O OpenTelemetry pode exportar esses dados.

Nesta unidade, você aprenderá a escrever um código eficiente que envia eventos para logs estruturados.

Objetos ILogger

As ferramentas do .NET Aspire configuram a API do OpenTelemetry automaticamente ao se criar um projeto com base nos modelos ou adicionar um projeto existente à orquestração do .NET Aspire. Se você deseja gravar a telemetria, não é necessário criar seus próprios objetos de registro em log, métricas ou rastreamento. Em vez disso, você pode recuperá-los usando a injeção de dependência em seus microsserviços.

Por exemplo, na classe BasketService a seguir, um objeto ILogger é incluído na declaração de classe. Você pode usar esse agente em qualquer lugar da classe para gravar eventos:

public class BasketService(
    IBasketRepository repository,
    ILogger<BasketService> logger) : Basket.BasketBase
{
    [AllowAnonymous]
    public override async Task<CustomerBasketResponse> GetBasket(
	    GetBasketRequest request, ServerCallContext context)
    {
        var userId = context.GetUserIdentity();

        // Use the logger to write events
        if (logger.IsEnabled(LogLevel.Debug))
        {
            logger.LogDebug("Begin GetBasketById call from method {Method} for basket id {userId}", context.Method, userId);
        }

        var data = await repository.GetBasketAsync(userId);

        return new();
    }
}

Registro em log eficiente

O registro em log ajuda a tornar seu microsserviço observável. Quando o aplicativo é testado, preparado e implantado em produção, um código de log minucioso pode habilitar um rápido diagnóstico de falhas ou gargalos. Portanto, é tentador registrar tudo em log. No entanto, embora o registro em log seja rápido, ele não é feito sem custo e você deve ter cuidado para fazer isso com eficiência.

Os fornecedores geralmente cobram sistemas de APM (Gerenciamento de Desempenho de Aplicativos) com base no volume de dados que eles ingerem. A seleção do nível de log apropriado para suas mensagens e os níveis de coleção padrão podem ter um grande efeito na fatura mensal. Os níveis de coleta de logs podem ser definidos por provedor, que normalmente é o nome do tipo usado em ILogger<T>.

Use as seguintes técnicas sempre que registrar em log:

  • Verifique se o nível de registro em log que você deseja usar está habilitado. Os níveis disponíveis incluem: informação, aviso, erro e crítico. Os administradores podem habilitar níveis diferentes ao testar, preparar e implantar em produção. A saída de log é controlada por meio de IConfiguration, normalmente usando appsettings.json ou variáveis de ambiente.
  • Evite a interpolação de cadeia de caracteres em sua mensagem registrada. Cadeias de caracteres interpoladas são definidas com o símbolo $ e são avaliadas mesmo que o nível de log escolhido não esteja habilitado. Em vez disso, use um método de log como LogInformation() ou LogDebug() e passe parâmetros na lista de argumentos.
  • Use a geração de fonte de dados de tempo de compilação para otimizar ainda mais o desempenho do registro em log e criar um identificador exclusivo para cada mensagem de log, o que é útil ao consultar mensagens de log em um APM.

Geração de fonte de dados de tempo de compilação

A geração de fonte de dados de tempo de compilação com objetos ILogger reduz o custo do registro em log fazendo a análise de cadeia de caracteres uma vez, em vez de a cada solicitação de registro. Ela também inclui uma ID para cada tipo de mensagem de log. Para usar essa técnica, defina métodos de registro em log parciais com os parâmetros adequados e aplique o LoggerMessageAttribute a eles. O .NET gera automaticamente o método de registro em log completo quando o código é compilado.

Lembre-se de que, no .NET Aspire, você não precisa criar um ILogger, mas pode obtê-lo com a injeção de dependência:

public partial class BasketService(
    IBasketRepository repository,
    ILogger<BasketService> logger) : Basket.BasketBase
{
    [LoggerMessage(
        EventId = 0,
        Level = LogLevel.Information,
        Message = "Obtaining a basket from method {Method} for basket {basketId}")]
    public partial void LogGetBasket(string Method, int basketId);
}

Saiba mais