Kestrel 中的诊断
注意
此版本不是本文的最新版本。 有关当前版本,请参阅本文的 .NET 9 版本。
警告
此版本的 ASP.NET Core 不再受支持。 有关详细信息,请参阅 .NET 和 .NET Core 支持策略。 对于当前版本,请参阅此文的 .NET 8 版本。
本文提供从 Kestrel 收集诊断以帮助解决问题的指南。 涵盖的主题包括:
- 日志记录:写入 .NET Core 日志记录的结构化日志。 应用框架使用 ILogger 来编写日志,用户使用它在应用中进行用户自己的日志记录。
- 指标:一段时间间隔内数据度量值的表示形式,例如每秒请求数。 指标是使用
EventCounter
发出的,可以使用 dotnet-counters 命令行工具或 Application Insights 进行观察。 - DiagnosticSource:
DiagnosticSource
是一种用于记录生产时间的机制,具有丰富的数据有效负载可供进程使用。 与日志记录不同,后者假设数据将离开进程并且需要可序列化的数据,DiagnosticSource
可以很好地处理复杂数据。
Logging
与 ASP.NET Core 中的大多数组件一样,Kestrel 使用 Microsoft.Extensions.Logging
发出日志信息。 Kestrel 使用多个类别,你可以选择要侦听的日志。
日志记录类别名称 | 日志记录事件 |
---|---|
Microsoft.AspNetCore.Server.Kestrel |
ApplicationError 、、ConnectionHeadResponseBodyWrite 、RequestBodyStart ApplicationNeverCompleted 、RequestBodyDone 、RequestBodyNotEntirelyRead 、RequestBodyDrainTimedOut 、ResponseMinimumDataRateNotSatisfied 、、 InvalidResponseHeaderRemoved HeartbeatSlow |
Microsoft.AspNetCore.Server.Kestrel.BadRequests |
ConnectionBadRequest 、 RequestProcessingError 、、 RequestBodyMinimumDataRateNotSatisfied |
Microsoft.AspNetCore.Server.Kestrel.Connections |
ConnectionAccepted 、、ConnectionStart 、ConnectionPause ConnectionStop 、ConnectionResume 、ConnectionKeepAlive 、ConnectionRejected ConnectionDisconnect 、、NotAllConnectionsClosedGracefully 、、 NotAllConnectionsAborted ApplicationAbortedConnection |
Microsoft.AspNetCore.Server.Kestrel.Http2 |
Http2ConnectionError 、、Http2ConnectionClosing 、Http2StreamError Http2ConnectionClosed 、Http2StreamResetAbort 、HPackDecodingError 、HPackEncodingError 、Http2FrameReceived 、、 Http2FrameSending Http2MaxConcurrentStreamsReached |
Microsoft.AspNetCore.Server.Kestrel.Http3 |
Http3ConnectionError 、、Http3ConnectionClosing Http3ConnectionClosed 、Http3StreamAbort 、Http3FrameReceived 、Http3FrameSending |
连接日志记录
Kestrel 还支持为字节级别的通信发出 Debug
级别日志,并可根据每个终结点启用该功能。 若要启用连接日志记录,请参阅为 Kestrel 配置终结点
指标
指标是一段时间间隔内数据度量值的表示形式,例如每秒请求数。 使用指标数据可以在高级别观察应用的状态。 Kestrel 指标是使用 EventCounter
发出的。
注意
connections-per-second
和 tls-handshakes-per-second
计数器命名不正确。 计数器:
- 并不总是包含新建连接数或每秒 TLS 握手数
- 显示上次更新间隔内新建连接数或 TLS 握手数,正如事件使用者通过
filterPayload
到KestrelEventSource
中的EventCounterIntervalSec
参数请求的那样。
建议这些计数器的使用者按照 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 进程时,不会强制实施某些超时和速率限制。 有关详细信息,请参阅附加了调试器的行为。