Kestrel 中的診斷

作者:Sourabh Shirhatti

本文提供從 Kestrel 收集診斷資料的指引,以協助針對問題進行疑難排解。 涵蓋的主題包括:

  • 記錄:寫入至 .NET Core 記錄的結構化記錄。 應用程式架構會使用 ILogger 來寫入記錄,而使用者則會用來在應用程式中自行記錄。
  • 計量:時間間隔內資料量值的表示法,例如每秒的要求數。 計量是透過 EventCounter 發出,可以使用 dotnet-counters 命令列工具或 Application Insights 來觀察。
  • DiagnosticSourceDiagnosticSource 是一種生產時間記錄機制,具有豐富的資料承載,以供流程內取用。 不同於記錄是假設資料將離開流程,並預期可序列化的資料,DiagnosticSource 則特別適合處理複雜的資料。

記錄

就像 ASP.NET Core 中的大部分元件一樣,Kestrel 會使用 Microsoft.Extensions.Logging 來發出記錄資訊。 Kestrel 採用多重類別,可讓您選擇聆聽哪些記錄。

記錄類別名稱 記錄事件
Microsoft.AspNetCore.Server.Kestrel ApplicationError, ConnectionHeadResponseBodyWrite, ApplicationNeverCompleted, RequestBodyStart, RequestBodyDone, RequestBodyNotEntirelyRead, RequestBodyDrainTimedOut, ResponseMinimumDataRateNotSatisfied, InvalidResponseHeaderRemoved, HeartbeatSlow
Microsoft.AspNetCore.Server.Kestrel.BadRequests ConnectionBadRequestRequestProcessingErrorRequestBodyMinimumDataRateNotSatisfied
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

連線記錄

Kestrel 也支援針對位元組層級通訊發出 Debug 層級記錄的功能,而且可以針對每個端點來啟用。 若要啟用連線記錄,請參閱設定 Kestrel 的端點

度量

計量是時間間隔內資料量值的表示法,例如每秒的要求數。 計量資料可以讓您從高層次觀察應用程式的狀態。 Kestrel 計量是透過 EventCounter 所發出。

注意

connections-per-secondtls-handshakes-per-second 計數器的命名不正確。 計數器:

  • 不一定總是包含每秒鐘的新連線數或 TLS 交握數
  • 會根據事件取用者的要求,透過 filterPayloadKestrelEventSource 中的 EventCounterIntervalSec 引數,顯示上一個更新間隔中的新連線數或 TLS 交握數。

我們建議這些計數器的取用者根據一秒鐘的 DisplayRateTimeScale 來調整計量值。

名稱 顯示名稱 描述
connections-per-second 連線速率 每個更新間隔的新傳入連線數
total-connections 連線數總計 連線的總數
tls-handshakes-per-second TLS 交握率 每個更新間隔的新 TLS 交握數
total-tls-handshakes TLS 交握數總計 TLS 交握的總數
current-tls-handshakes 目前的 TLS 交握數 處理中的 TLS 交握數
failed-tls-handshakes 失敗的 TLS 交握數 失敗的 TLS 交握總數
current-connections 目前的連線數 連線總數,包括閒置連線
connection-queue-length 連線佇列長度 排入執行緒集區的連線總數。 在處於穩定狀態的狀況良好系統中,此數字應始終趨近零
request-queue-length 要求佇列長度 排入執行緒集區的要求總數。 在處於穩定狀態的狀況良好系統中,此數字應始終趨近零。 此計量與 IIS/Http.Sys 要求佇列不同,無法進行比較
current-upgraded-requests 目前的升級要求數 (WebSocket 數) 作用中 WebSocket 要求的數目

DiagnosticSource

Kestrel 會針對伺服器層拒絕的 HTTP 要求 (例如格式錯誤的要求和通訊協定違規) 發出 DiagnosticSource 事件。 因此,這些要求永遠不會進入 ASP.NET Core 的裝載層。

Kestrel 使用 Microsoft.AspNetCore.Server.Kestrel.BadRequest 事件名稱和 IFeatureCollection 作為物件承載來發出這些事件。 藉由存取功能集合上的 IBadRequestExceptionFeature,即可擷取基礎例外狀況。

解決這些事件的過程分為兩個步驟。 必須建立 DiagnosticListener 的觀察者:

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();
}

使用觀察者訂閱 ASP.NET Core DiagnosticListener。 在此範例中,我們會建立回撥來記錄基礎例外狀況。

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();

附加偵錯工具時的行為

附加偵錯工具至 Kestrel 流程時,並不會強制執行某些逾時和速率限制。 如需詳細資訊,請參閱附加偵錯工具時的行為