Not
Bu sayfaya erişim yetkilendirme gerektiriyor. Oturum açmayı veya dizinleri değiştirmeyi deneyebilirsiniz.
Bu sayfaya erişim yetkilendirme gerektiriyor. Dizinleri değiştirmeyi deneyebilirsiniz.
Olaylar size şu erişime izin verir:
- Bir işlemin ömrü boyunca doğru zaman damgaları. Örneğin, sunucuya bağlanmanın ne kadar sürdüğü ve bir HTTP isteğinin yanıt üst bilgilerini alması ne kadar sürdüğü.
- Başka yollarla alınamayan hata ayıklama/izleme bilgileri. Örneğin, bağlantı havuzunun ne tür kararlar aldığı ve neden olduğu.
İzleme EventSource'a dayalıdır ve bu bilgileri işlemin içinden ve dışından toplamanıza olanak sağlar.
Olay sağlayıcıları
Ağ bilgileri aşağıdaki olay sağlayıcıları arasında bölünür:
-
System.Net.Http(HttpClientveSocketsHttpHandler) -
System.Net.NameResolution(Dns) -
System.Net.Security(SslStream) System.Net.SocketsMicrosoft.AspNetCore.HostingMicrosoft-AspNetCore-Server-Kestrel
Telemetrinin etkinleştirildiğinde bazı performans yükleri vardır, bu nedenle yalnızca gerçekten ilgilendiğiniz olay sağlayıcılarına abone olduğunuzdan emin olun.
İşlemdeki olayları kullanma
Daha kolay olay bağıntısı ve analizi için mümkün olduğunda işlem içi koleksiyonu tercih edin.
Olay Dinleyicisi
EventListener, EventSource olaylarını üreten aynı işlemden dinlemenizi sağlayan bir API'dir.
using System.Diagnostics.Tracing;
using var listener = new MyListener();
using var client = new HttpClient();
await client.GetStringAsync("https://httpbin.org/get");
public sealed class MyListener : EventListener
{
protected override void OnEventSourceCreated(EventSource eventSource)
{
if (eventSource.Name == "System.Net.Http")
{
EnableEvents(eventSource, EventLevel.Informational);
}
}
protected override void OnEventWritten(EventWrittenEventArgs eventData)
{
Console.WriteLine($"{DateTime.UtcNow:ss:fff} {eventData.EventName}: " +
string.Join(' ', eventData.PayloadNames!.Zip(eventData.Payload!).Select(pair => $"{pair.First}={pair.Second}")));
}
}
Yukarıdaki kod çıktıyı aşağıdakine benzer şekilde yazdırır:
00:598 RequestStart: scheme=https host=httpbin.org port=443 pathAndQuery=/get versionMajor=1 versionMinor=1 versionPolicy=0
01:470 ConnectionEstablished: versionMajor=1 versionMinor=1
01:474 RequestLeftQueue: timeOnQueueMilliseconds=470,6214 versionMajor=1 versionMinor=1
01:476 RequestHeadersStart:
01:477 RequestHeadersStop:
01:592 ResponseHeadersStart:
01:593 ResponseHeadersStop:
01:633 ResponseContentStart:
01:635 ResponseContentStop:
01:635 RequestStop:
01:637 ConnectionClosed: versionMajor=1 versionMinor=1
Yarp.Telemetri.Tüketim
EventListener Yukarıda özetlenen yaklaşım hızlı deneme ve hata ayıklama için yararlı olsa da, API'ler kesin olarak yazılmaz ve sizi izleme kitaplığının uygulama ayrıntılarına bağımlı olmanıza zorlar.
Bunu ele almak için .NET, işlemdeki ağ olaylarının kullanılmasını kolaylaştıran bir kitaplık oluşturmuştur: Yarp.Telemetry.Consumption.
Paket şu anda YARP projesinin bir parçası olarak korunsa da, herhangi bir .NET uygulamasında kullanılabilir.
Bunu kullanmak için ilgilendiğiniz arabirimleri ve yöntemleri (olayları) uygulayın:
public sealed class MyTelemetryConsumer : IHttpTelemetryConsumer, INetSecurityTelemetryConsumer
{
public void OnRequestStart(DateTime timestamp, string scheme, string host, int port, string pathAndQuery, int versionMajor, int versionMinor, HttpVersionPolicy versionPolicy)
{
Console.WriteLine($"Request to {host} started at {timestamp}");
}
public void OnHandshakeStart(DateTime timestamp, bool isServer, string targetHost)
{
Console.WriteLine($"Starting TLS handshake with {targetHost}");
}
}
Ve uygulamaları DI kapsayıcınıza kaydedin:
services.AddTelemetryConsumer<MyTelemetryConsumer>();
Kitaplık aşağıdaki kesin olarak belirlenmiş arabirimleri sağlar:
IHttpTelemetryConsumerINameResolutionTelemetryConsumerINetSecurityTelemetryConsumerISocketsTelemetryConsumerIKestrelTelemetryConsumer
Bu geri çağırmalar, izlemeli işlemin bir parçası olarak çağrılır, bu nedenle genel günlük kılavuzu uygulanır. Geri çağırmanın bir parçası olarak pahalı hesaplamaları engellemekten veya gerçekleştirmekten kaçınmanız gerekir. Temel alınan işlemeye gecikme süresi eklenmesini önlemek için işlem sonrası işleri farklı iş parçacıklarına boşaltın.
İşlem dışından olayları kullanma
dotnet-trace
dotnet-trace , yerel profil oluşturucu olmadan çalışan bir işlemin .NET Core izlemelerinin toplanmasını sağlayan platformlar arası bir araçtır.
dotnet tool install --global dotnet-trace
dotnet-trace collect --providers System.Net.Http,System.Net.Security,System.Threading.Tasks.TplEventSource:0x80:4 --process-id 1234
Tüm kullanılabilir komutlar ve parametreler için dotnet-trace belgelerine bakın.
Yakalanan .nettrace dosyayı Visual Studio veya PerfView'da analiz edebilirsiniz.
Daha fazla bilgi için dotnet-trace analiz belgelerine bakın.
PerfView
PerfView ücretsiz, gelişmiş bir performans analizi aracıdır. Windows üzerinde çalışır ancak Linux'ta yakalanan izlemeleri de analiz edebilir.
Yakalanacak olayların listesini yapılandırmak için altında belirtin Advanced Options / Additional Providers:
*System.Net.Sockets,*System.Net.NameResolution,*System.Net.Http,*System.Net.Security
TraceEvent
TraceEvent , farklı işlemlerden gelen olayları gerçek zamanlı olarak kullanmanıza olanak tanıyan bir kitaplıktır.
dotnet-trace ve PerfView her ikisi de buna güveniyor.
Olayları program aracılığıyla ve gerçek zamanlı olarak işlemek istiyorsanız belgelere TraceEvent bakın.
Olayları başlatma ve durdurma
Daha büyük işlemler genellikle bir Start olayla başlar ve bir Stop olayla biter.
Örneğin, veya öğesinden RequestStart/RequestStopSystem.Net.Httpgelen olayları ConnectStartgörürsünüz./ConnectStopSystem.Net.Sockets
Bunlar gibi büyük işlemler genellikle bir Stop olayın her zaman mevcut olacağını garanti etse de, her zaman böyle değildir. Örneğin, öğesinin RequestHeadersStart olayını System.Net.Http görmek, bunun da günlüğe kaydedileceğini garanti RequestHeadersStop etmez.
Olay bağıntısı
Bu olayları gözlemlemeyi öğrendiğinize göre, genellikle bunları genellikle kaynak HTTP isteğiyle ilişkilendirmeniz gerekir.
Daha kolay olay bağıntısı ve analizi için mümkün olduğunda işlem içi koleksiyonu tercih edin.
İşlem içi bağıntı
Ağ zaman uyumsuz G/Ç kullandığından, belirli bir isteği tamamlayan iş parçacığının da onu başlatan iş parçacığı olduğunu varsayamazsınız.
Başka bir deyişle, olayları ilişkilendirmek için statikleri kullanamazsınız [ThreadLocal] , ancak bir AsyncLocalkullanabilirsiniz.
AsyncLocal Bu tür, çalışmayı farklı iş parçacıkları arasında ilişkilendirmek için önemli olduğundan bilgi edinin.
AsyncLocal bir işlemin zaman uyumsuz akışında aynı duruma daha derin erişmenizi sağlar.
AsyncLocal değerler yalnızca aşağı doğru akar (zaman uyumsuz çağrı yığınının daha derinine doğru) ve değişiklikleri çağırana yaymayın.
Aşağıdaki örneği inceleyin:
AsyncLocal<int> asyncLocal = new();
asyncLocal.Value = 1;
await WorkAsync();
Console.WriteLine($"Value after WorkAsync: {asyncLocal.Value}");
async Task WorkAsync()
{
Console.WriteLine($"Value in WorkAsync: {asyncLocal.Value}");
asyncLocal.Value = 2;
Console.WriteLine($"Value in WorkAsync: {asyncLocal.Value}");
}
Bu kod şu çıkışı oluşturur:
Value in WorkAsync: 1
Value in WorkAsync: 2
Value after WorkAsync: 1
Değer 1 çağırandan içine WorkAsyncakıp akmıştı, ancak (WorkAsync) içindeki 2 değişiklik çağırana geri akmadı.
Telemetri olayları (ve bunlara karşılık gelen geri çağırmalar) temel alınan işlemin bir parçası olarak gerçekleştiğinden, bunlar isteği başlatan çağıranla aynı zaman uyumsuz kapsam içinde gerçekleşir.
Bu, geri çağırmanın içinden gözlemleyebileceğiniz asyncLocal.Value anlamına gelir, ancak geri çağırmada değeri ayarlarsanız, hiçbir şey bunu yığında daha fazla gözlemleyemez.
Aşağıdaki adımlarda genel desen gösterilmektedir.
Olay geri çağırmalarının içinden güncelleştirilebilen değiştirilebilir bir sınıf oluşturun.
public sealed class RequestInfo { public DateTime StartTime, HeadersSent; }AsyncLocal.ValueDurumun işleme akması için ana işlemden önce değerini ayarlayın.private static readonly AsyncLocal<RequestInfo> _requestInfo = new(); public async Task SendRequestAsync(string url) { var info = new RequestInfo(); _requestInfo.Value = info; info.StartTime = DateTime.UtcNow; await _client.GetStringAsync(url);Olay geri çağırmaları içinde, paylaşılan durumun kullanılabilir olup olmadığını denetleyin ve güncelleştirin.
AsyncLocal.Value, isteğin ilk etapta ayarlınullolmayan bir bileşen tarafından gönderilmesi durumunda olurAsyncLocal.Value.public void OnRequestHeadersStop(DateTime timestamp) { if (_requestInfo.Value is { } info) info.HeadersSent = timestamp; }İşlemi tamamladıktan sonra toplanan bilgileri işleyin.
await _client.GetStringAsync(url); Log($"Time until headers were sent {url} was {info.HeadersSent - info.StartTime}");
Bunu yapmanın diğer yolları için örnekler bölümüne bakın.
İşlem dışındaki bağıntı
Her olay, öğesine adlı ActivityIDbir veri parçası eklenmiştir. Bu kimlik, olayın oluşturulduğu sırada zaman uyumsuz hiyerarşiyi kodlar.
PerfView'da bir izleme dosyasına bakarsanız aşağıdaki gibi olayları görürsünüz:
System.Net.Http/Request/Start ActivityID="/#14396/1/1/"
System.Net.Http/RequestHeaders/Start ActivityID="/#14396/1/1/2/"
System.Net.Http/RequestHeaders/Stop ActivityID="/#14396/1/1/2/"
System.Net.Http/ResponseHeaders/Start ActivityID="/#14396/1/1/3/"
System.Net.Http/ResponseHeaders/Stop ActivityID="/#14396/1/1/3/"
System.Net.Http/Request/Stop ActivityID="/#14396/1/1/"
Ön eki paylaştığından /#14396/1/1/ bu olayların aynı isteğe ait olduğunu bilirsiniz.
El ile araştırma yaparken, ilgilendiğiniz bir isteğin System.Net.Http/Request/Start olayını aramak ve ardından bunu metin kutusuna ActivityID yapıştırmak Text Filter yararlı bir püf noktasıdır. Şimdi tüm kullanılabilir sağlayıcıları seçerseniz, bu isteğin bir parçası olarak oluşturulan tüm olayların listesini görürsünüz.
PerfView otomatik olarak öğesini toplar ActivityID, ancak gibi dotnet-tracearaçlar kullanıyorsanız sağlayıcıyı System.Threading.Tasks.TplEventSource:0x80:4 açıkça etkinleştirmeniz gerekir (yukarıdaki örneğe bakın dotnet-trace ).
HttpClient isteği ile bağlantı ömrü karşılaştırması
.NET 6'dan bu yana, bir HTTP isteği artık belirli bir bağlantıya bağlı değildir. Bunun yerine, herhangi bir bağlantı kullanılabilir olduğunda isteğe hizmet verilecektir.
Bu, aşağıdaki olay sırasını görebileceğiniz anlamına gelir:
- İstek başlangıcı
- Dns başlangıç
- İstek durdurma
- Dns durdurma
Bu, isteğin bir DNS çözümlemesi tetiklediğini, ancak DNS çağrısı tamamlanmadan önce farklı bir bağlantı tarafından işlendiğini gösterir. Aynı durum yuva bağlantıları veya TLS el sıkışmaları için de geçerli olur. Kaynak istek tamamlanmadan önce tamamlanabilir.
Bu tür olayları ayrı ayrı düşünmelisiniz. DNS çözümlemelerini veya TLS el sıkışmalarını belirli bir isteğin zaman çizelgesine bağlamadan izleyin.
İç tanılama
.NET'teki bazı bileşenler, dahili olarak olup bitenlerle ilgili daha fazla içgörü sağlayan ek hata ayıklama düzeyinde olaylarla izlenir. Bu olaylar yüksek performans ek yüküyle birlikte gelir ve şekilleri sürekli değişir. Adından da anlaşılacağı gibi, bunlar genel API'nin bir parçası değildir ve bu nedenle davranışlarına veya varlığına güvenmemelisiniz. Ayrıca, bunlar redakte edilmez ve kişisel olarak tanımlanabilir bilgi içerebilir.
Ne olursa olsun, diğer tüm olaylar başarısız olduğunda bu olaylar birçok içgörü sunabilir.
Yığın, System.Net bu tür olayları ad alanından Private.InternalDiagnostics.System.Net.* yayar.
Yukarıdaki örnekteki EventListener koşulu olarak eventSource.Name.Contains("System.Net")değiştirirseniz, yığında farklı katmanlardan 100'den fazla olay görürsünüz.
Daha fazla bilgi için bkz . tam örnek.
Bunları işlemin dışında kullanmak için kullanın dotnet-trace, örneğin:
dotnet-trace collect --providers Private.InternalDiagnostics.System.Net.Http:0xf --process-id 1234
Örnekler
- Belirli bir uç nokta için DNS çözümlemelerini ölçme
- HttpClient kullanırken üst bilgi zamanı ölçme
- Kestrel çalıştıran ASP.NET Core'da bir isteği işleme süresi
- .NET ters ara sunucusunun gecikme süresini ölçme
Belirli bir uç nokta için DNS çözümlemelerini ölçme
services.AddTelemetryConsumer(new DnsMonitor("httpbin.org"));
public sealed class DnsMonitor : INameResolutionTelemetryConsumer
{
private static readonly AsyncLocal<DateTime?> _startTimestamp = new();
private readonly string _hostname;
public DnsMonitor(string hostname) => _hostname = hostname;
public void OnResolutionStart(DateTime timestamp, string hostNameOrAddress)
{
if (hostNameOrAddress.Equals(_hostname, StringComparison.OrdinalIgnoreCase))
{
_startTimestamp.Value = timestamp;
}
}
public void OnResolutionStop(DateTime timestamp)
{
if (_startTimestamp.Value is { } start)
{
Console.WriteLine($"DNS resolution for {_hostname} took {(timestamp - start).TotalMilliseconds} ms");
}
}
}
HttpClient kullanırken üst bilgi zamanı ölçme
var info = RequestState.Current; // Initialize the AsyncLocal's value ahead of time
var response = await client.GetStringAsync("http://httpbin.org/get");
var requestTime = (info.RequestStop - info.RequestStart).TotalMilliseconds;
var serverLatency = (info.HeadersReceived - info.HeadersSent).TotalMilliseconds;
Console.WriteLine($"Request took {requestTime:N2} ms, server request latency was {serverLatency:N2} ms");
public sealed class RequestState
{
private static readonly AsyncLocal<RequestState> _asyncLocal = new();
public static RequestState Current => _asyncLocal.Value ??= new();
public DateTime RequestStart;
public DateTime HeadersSent;
public DateTime HeadersReceived;
public DateTime RequestStop;
}
public sealed class TelemetryConsumer : IHttpTelemetryConsumer
{
public void OnRequestStart(DateTime timestamp, string scheme, string host, int port, string pathAndQuery, int versionMajor, int versionMinor, HttpVersionPolicy versionPolicy) =>
RequestState.Current.RequestStart = timestamp;
public void OnRequestStop(DateTime timestamp) =>
RequestState.Current.RequestStop = timestamp;
public void OnRequestHeadersStop(DateTime timestamp) =>
RequestState.Current.HeadersSent = timestamp;
public void OnResponseHeadersStop(DateTime timestamp) =>
RequestState.Current.HeadersReceived = timestamp;
}
Kestrel çalıştıran ASP.NET Core'da bir isteği işleme süresi
Bu, şu anda belirli bir isteğin süresini ölçmenin en doğru yoludur.
public sealed class KestrelTelemetryConsumer : IKestrelTelemetryConsumer
{
private static readonly AsyncLocal<DateTime?> _startTimestamp = new();
private readonly ILogger<KestrelTelemetryConsumer> _logger;
public KestrelTelemetryConsumer(ILogger<KestrelTelemetryConsumer> logger) => _logger = logger;
public void OnRequestStart(DateTime timestamp, string connectionId, string requestId, string httpVersion, string path, string method)
{
_startTimestamp.Value = timestamp;
}
public void OnRequestStop(DateTime timestamp, string connectionId, string requestId, string httpVersion, string path, string method)
{
if (_startTimestamp.Value is { } startTime)
{
var elapsed = timestamp - startTime;
_logger.LogInformation("Request {requestId} to {path} took {elapsedMs} ms", requestId, path, elapsed.TotalMilliseconds);
}
}
}
.NET ters ara sunucusunun gecikme süresini ölçme
Bu örnek, Kestrel aracılığıyla gelen istekleri alan ve HttpClient (örneğin, YARP) üzerinden giden istekler yapan bir ters ara sunucunuz varsa geçerlidir.
Bu örnek, istek üst bilgilerini alma süresini arka uç sunucusuna gönderilene kadar ölçer.
public sealed class InternalLatencyMonitor : IKestrelTelemetryConsumer, IHttpTelemetryConsumer
{
private record RequestInfo(DateTime StartTimestamp, string RequestId, string Path);
private static readonly AsyncLocal<RequestInfo> _requestInfo = new();
private readonly ILogger<InternalLatencyMonitor> _logger;
public InternalLatencyMonitor(ILogger<InternalLatencyMonitor> logger) => _logger = logger;
public void OnRequestStart(DateTime timestamp, string connectionId, string requestId, string httpVersion, string path, string method)
{
_requestInfo.Value = new RequestInfo(timestamp, requestId, path);
}
public void OnRequestHeadersStop(DateTime timestamp)
{
if (_requestInfo.Value is { } requestInfo)
{
var elapsed = (timestamp - requestInfo.StartTimestamp).TotalMilliseconds;
_logger.LogInformation("Internal latency for {requestId} to {path} was {duration} ms", requestInfo.RequestId, requestInfo.Path, elapsed);
}
}
}
Daha fazla telemetriye mi ihtiyacınız var?
Olaylar veya ölçümler aracılığıyla kullanıma sunulacak diğer yararlı bilgiler için önerileriniz varsa bir dotnet/runtime sorunu oluşturun.
Kitaplığı kullanıyorsanız Yarp.Telemetry.Consumption ve herhangi bir öneriniz varsa bir microsoft/reverse-proxy sorunu oluşturun.