Diagnóstico no Kestrel

Por Sourabh Shirhatti

Este artigo fornece diretrizes para coletar diagnóstico do Kestrel a fim de ajudar a solucionar problemas. Os tópicos abordados incluem:

  • Registro em log: logs estruturados gravados no Registro em log do .NET Core. ILogger é usado por estruturas de aplicativos para gravar logs e por usuários para seus próprios logs em um aplicativo.
  • Métricas: representação de medidas de dados em intervalos de tempo como, por exemplo, solicitações por segundo. As métricas são emitidas usando o EventCounter e podem ser observadas usando a ferramenta de linha de comando dotnet-counters ou o Application Insights.
  • DiagnosticSource: DiagnosticSource é um mecanismo para registro em log em tempo de produção com conteúdos de dados avançados para consumo dentro do processo. Ao contrário do registro em log, que pressupõe que os dados deixarão o processo e espera dados serializáveis, o DiagnosticSource funciona bem com dados complexos.

Log

Como a maioria dos componentes no ASP.NET Core, o Kestrel usa Microsoft.Extensions.Logging para emitir informações de log. O Kestrel emprega o uso de várias categorias, o que permite que você seja seletivo em quais logs você escuta.

Nome da categoria de registro em log Registro em log de eventos
Microsoft.AspNetCore.Server.Kestrel ApplicationError, ConnectionHeadResponseBodyWrite, ApplicationNeverCompleted, RequestBodyStart, RequestBodyDone, RequestBodyNotEntirelyRead, RequestBodyDrainTimedOut, ResponseMinimumDataRateNotSatisfied, InvalidResponseHeaderRemoved, HeartbeatSlow
Microsoft.AspNetCore.Server.Kestrel.BadRequests ConnectionBadRequest, RequestProcessingError, RequestBodyMinimumDataRateNotSatisfied
Microsoft.AspNetCore.Server.Kestrel.Connections ConnectionAccepted, ConnectionStart, ConnectionStop, ConnectionPause, ConnectionResume, ConnectionKeepAlive, ConnectionRejected, ConnectionDisconnect, NotAllConnectionsClosedGracefully, NotAllConnectionsAborted, ApplicationAbortedConnection
Microsoft.AspNetCore.Server.Kestrel.Http2 Http2ConnectionError, Http2ConnectionClosing, Http2ConnectionClosed, Http2StreamError, Http2StreamResetAbort, HPackDecodingError, HPackEncodingError, Http2FrameReceived, Http2FrameSending, Http2MaxConcurrentStreamsReached
Microsoft.AspNetCore.Server.Kestrel.Http3 Http3ConnectionError, Http3ConnectionClosing, Http3ConnectionClosed, Http3StreamAbort, Http3FrameReceived, Http3FrameSending

Registro em log de conexão

O Kestrel também dá suporte à capacidade de emitir logs de nível Debug para comunicação no nível do byte e pode ser habilitado por ponto de extremidade. Para habilitar o registro em log de conexão, confira Configurar pontos de extremidade para Kestrel

Métricas

As métricas são uma representação de medidas de dados em intervalos de tempo, por exemplo, solicitações por segundo. Os dados de métricas permitem a observação do estado de um aplicativo em um alto nível. As métricas Kestrel são emitidas usando EventCounter.

Observação

Os contadores connections-per-second e tls-handshakes-per-second são nomeados incorretamente. Os contadores:

  • Nem sempre contêm o número de novas conexões ou handshakes TLS por segundo
  • Exiba o número de novas conexões ou handshakes TLS no último intervalo de atualização, conforme solicitado como o consumidor de Eventos por meio do argumento EventCounterIntervalSec no filterPayload para KestrelEventSource.

Recomendamos que os consumidores desses contadores dimensionem o valor da métrica com base no DisplayRateTimeScale de um segundo.

Nome Nome de exibição Descrição
connections-per-second Taxa de conexão O número de novas conexões de entrada por intervalo de atualização
total-connections Total de conexões O número total de conexões
tls-handshakes-per-second Taxa de handshake do TLS O número de novos handshakes TLS por intervalo de atualização
total-tls-handshakes Total de handshakes do TLS O número total de handshakes TLS
current-tls-handshakes Handshakes do TLS atuais O número atual de handshakes do TLS em processo
failed-tls-handshakes Handshakes do TLS com falha O número total de handshakes TLS com falha
current-connections Conexões atuais O número total de conexões, incluindo conexões ociosas
connection-queue-length Comprimento da fila de conexão O número total de conexões enfileiradas no pool de threads. Em um sistema íntegro em estado estável, esse número deve estar sempre próximo de zero
request-queue-length Comprimento da fila de conexão O número total de solicitações enfileiradas no pool de threads. Em um sistema íntegro em estado estável, esse número deve estar sempre próximo de zero. Essa métrica é diferente da fila de solicitações do IIS/Http.Sys e não pode ser comparada
current-upgraded-requests Solicitações atualizadas atuais (WebSockets) O número de solicitações WebSocket ativas

DiagnosticSource

O Kestrel emite um evento DiagnosticSource para solicitações HTTP rejeitadas na camada de servidor, como solicitações malformadas e violações de protocolos. Dessa forma, essas solicitações nunca entram na camada de hospedagem do ASP.NET Core.

O Kestrel emite esses eventos com o nome do evento Microsoft.AspNetCore.Server.Kestrel.BadRequest e um IFeatureCollection como o conteúdo do objeto. A exceção subjacente pode ser recuperada acessando o IBadRequestExceptionFeature na coleção de recursos.

Resolver esses eventos é um processo de duas etapas. Um observador para DiagnosticListener deve ser criado:

class BadRequestEventListener : IObserver<KeyValuePair<string, object>>, IDisposable
{
    private readonly IDisposable _subscription;
    private readonly Action<IBadRequestExceptionFeature> _callback;

    public BadRequestEventListener(DiagnosticListener diagnosticListener, Action<IBadRequestExceptionFeature> callback)
    {
        _subscription = diagnosticListener.Subscribe(this!, IsEnabled);
        _callback = callback;
    }
    private static readonly Predicate<string> IsEnabled = (provider) => provider switch
    {
        "Microsoft.AspNetCore.Server.Kestrel.BadRequest" => true,
        _ => false
    };
    public void OnNext(KeyValuePair<string, object> pair)
    {
        if (pair.Value is IFeatureCollection featureCollection)
        {
            var badRequestFeature = featureCollection.Get<IBadRequestExceptionFeature>();

            if (badRequestFeature is not null)
            {
                _callback(badRequestFeature);
            }
        }
    }
    public void OnError(Exception error) { }
    public void OnCompleted() { }
    public virtual void Dispose() => _subscription.Dispose();
}

Assine o ASP.NET Core DiagnosticListener com o observador. Neste exemplo, criamos um retorno de chamada que registra a exceção subjacente.

var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();
var diagnosticSource = app.Services.GetRequiredService<DiagnosticListener>();
using var badRequestListener = new BadRequestEventListener(diagnosticSource, (badRequestExceptionFeature) =>
{
    app.Logger.LogError(badRequestExceptionFeature.Error, "Bad request received");
});
app.MapGet("/", () => "Hello world");
app.Run();

Comportamento com depurador anexado

Determinados tempos limite e limites de taxa não são impostos quando um depurador é anexado a um processo Kestrel. Para obter mais informações, confira Comportamento com o depurador anexado.