पिछले लेख में, मैंने DiagnosticSource तंत्र के बारे में बात की थी और एक सरल उदाहरण के साथ दिखाया था कि कैसे SqlConnection
और SqlCommand
कक्षाओं के माध्यम से डेटाबेस के अनुरोधों को रोकना और उनके निष्पादन समय को मापना है।
वर्तमान में, DiagnosticSource पहले से ही AspNetCore, EntityFrameworkCore, HttpClient और SqlClient में उपयोग किया जाता है - उनमें से प्रत्येक अपने स्वयं के ईवेंट भेजता है, जिसे इंटरसेप्ट किया जा सकता है और संसाधित किया जा सकता है।
इस लेख में, मैं कुछ उदाहरणों पर विचार करना चाहता हूं कि आप ASP.NET कोर अनुप्रयोगों में DiagnosticSource का उपयोग कैसे कर सकते हैं।
- सहसंबंध और सेवाओं के बीच अग्रसारण प्रमुख
- मैट्रिक्स और निशान का संग्रह
- लॉगिंग
इसके अलावा, इस लेख में मैंने उन घटनाओं की एक सूची एकत्र करने का निर्णय लिया है जो प्रसंस्करण के लिए उपलब्ध हैं और आपके अनुप्रयोगों में उपयोग की जा सकती हैं, साथ ही कुछ ऐसे नुकसानों के बारे में बात करते हैं जिन्हें आप अपने प्रोजेक्ट में DiagnosticSource तंत्र का उपयोग करने का निर्णय ले सकते हैं।
मौजूदा घटनाएँ
उदाहरणों की जांच करने के लिए आगे बढ़ने से पहले, हमें यह समझने की आवश्यकता है कि डायग्नोस्टिक स्रोत के माध्यम से कौन से घटक घटनाओं को भेजते हैं, और इन घटनाओं को क्या कहा जाता है। दुर्भाग्य से, घटनाओं की पूरी सूची प्रलेखन में कहीं भी वर्णित नहीं है, और आप इसे केवल GitHub पर स्रोत कोड में पा सकते हैं।
इसलिए, यह समझने का सबसे आसान तरीका है कि कौन सी ईवेंट मौजूद हैं, एक ऐसा वर्ग बनाना है जो IObserver<DiagnosticListener>
और IObserver<KeyValuePair<string, object>>
interfaces को कार्यान्वित करता है, IObserver<DiagnosticListener>
किसी भी DiagnosticListener
उदाहरणों की सदस्यता लें और देखें कि एप्लिकेशन में क्या ईवेंट पकड़े जाएंगे। उसी तरह, आप प्रत्येक घटना के साथ संचरित मापदंडों को निर्धारित कर सकते हैं।
आपके कार्य को सरल बनाने के लिए, मैंने पहले से ही चार घटकों के लिए कुछ सबसे उपयोगी घटनाओं (यह पूरी सूची नहीं है) एकत्र की है:
Microsoft.AspNetCore
घटक की ईवेंट आपको ASP.NET कोर में HTTP अनुरोध प्रसंस्करण के जीवन की घटनाओं को बाधित करने की अनुमति देती है।
- Microsoft.AspNetCore.Hosting.HttpRequestIn.Start
- Microsoft.AspNetCore.Hosting.HttpRequestIn.Stop
ये घटनाएँ http अनुरोध के प्रसंस्करण के आरंभ और अंत में होती हैं।
- Microsoft.AspNetCore.Diagnostics.UnhandledException
बिना अपवाद वाले अपवाद। यह एकमात्र स्थान है जहां आप इस घटक के अपवादों को संभाल सकते हैं।
- Microsoft.AspNetCore.Mvc.BeforeAction
- Microsoft.AspNetCore.Mvc.AfterAction
UseMvc
में http रिक्वेस्ट को प्रोसेस करने से पहले और बाद में उपयोग करें, जो UseMvc
का उपयोग करते समय जोड़े जाते हैं। वस्तुतः दोनों के बीच निम्न घटनाएँ होती हैं।
- Microsoft.AspNetCore.Mvc.BeforeOnAuthorization
- Microsoft.AspNetCore.Mvc.AfterOnAuthorization
प्राधिकरण के पहले और बाद में।
- Microsoft.AspNetCore.Mvc.BeforeActionMethod
- Microsoft.AspNetCore.Mvc.AfterActionMethod
नियंत्रक विधि के क्रियान्वयन से पहले और बाद में।
- Microsoft.AspNetCore.Mvc.BeforeActionResult
- Microsoft.AspNetCore.Mvc.AfterActionResult
ExecuteResultAsync
को ExecuteResultAsync
उदाहरण पर कॉल करने से पहले और बाद में होता है, जो नियंत्रक विधि से वापस किया गया था। यह, उदाहरण के लिए, परिणाम को जस में शामिल कर सकता है।
- Microsoft.AspNetCore.Mvc.BeforeHandlerMethod
- Microsoft.AspNetCore.Mvc.AfterHandlerMethod
ASP.NET पेज में उपयोग किया जाता है। पृष्ठ मॉडल विधि के निष्पादन से पहले और बाद में होना।
- Microsoft.AspNetCore.Mvc.BeforeView
- Microsoft.AspNetCore.Mvc.AfterView
दृश्य प्रस्तुत करने से पहले और बाद में भी।
Microsoft.EntityFrameworkCore
घटक की ईवेंट्स आपको EntityFrameworkCore के माध्यम से डेटाबेस एक्सेस इवेंट्स को इंटरसेप्ट करने की अनुमति देती हैं।
- Microsoft.EntityFrameworkCore.Infrastructure.ContextInitialized
- Microsoft.EntityFrameworkCore.Infrastructure.ContextDisposed
DbContext
इंस्टेंस का उपयोग करने से पहले और बाद में भी
- Microsoft.EntityFrameworkCore.Database.Connection.ConnectionOpening
- Microsoft.EntityFrameworkCore.Database.Connection.ConnectionOpened
- Microsoft.EntityFrameworkCore.Database.Connection.ConnectionError
डेटाबेस कनेक्शन खोलने से पहले और बाद में भी। यदि कनेक्शन सफलतापूर्वक खोला गया था, तो ConnectionOpened
घटना होती है। यदि कनेक्शन खोलते समय कोई त्रुटि होती है, तो ConnectionError
घटना को उठाया जाता है।
- Microsoft.EntityFrameworkCore.Database.Connection.ConnectionClosing
- Microsoft.EntityFrameworkCore.Database.Connection.ConnectionClosed
- Microsoft.EntityFrameworkCore.Database.Connection.ConnectionError
इसी तरह डेटाबेस कनेक्शन को बंद करने से पहले और बाद में होता है।
- Microsoft.EntityFrameworkCore.Database.Command.CommandExecuting
- Microsoft.EntityFrameworkCore.Database.Command.CommandExecuted
- Microsoft.EntityFrameworkCore.Database.Command.CommandError
इसी तरह डेटाबेस से क्वेरी के पहले और बाद में होते हैं।
- Microsoft.EntityFrameworkCore.Database.Command.DataReaderDisposing
DbDataReader
उदाहरण से पढ़ने के बाद होता है।
SqlClientDiagnosticListener
घटक की घटनाएँ आपको संबंधित ADO.NET प्रदाता के माध्यम से SQL सर्वर डेटाबेस तक पहुँचने की घटनाओं को रोकने के लिए अनुमति देती हैं।
- System.Data.SqlClient.WriteConnectionOpenBefore
- System.Data.SqlClient.WriteConnectionOpenAfter
- System.Data.SqlClient.WriteConnectionOpenError
डेटाबेस कनेक्शन खोलने से पहले और बाद में भी। यदि कनेक्शन सफलतापूर्वक खोला गया था, तो WriteConnectionOpenAfter
घटना WriteConnectionOpenAfter
। यदि कनेक्शन खोलते समय कोई त्रुटि होती है, तो WriteConnectionOpenError
घटना WriteConnectionOpenError
।
- System.Data.SqlClient.WriteConnectionCloseBefore
- System.Data.SqlClient.WriteConnectionCloseAfter
- System.Data.SqlClient.WriteConnectionCloseError
इसी तरह डेटाबेस कनेक्शन को बंद करने से पहले और बाद में होता है।
- System.Data.SqlClient.WriteCommandBefore
- System.Data.SqlClient.WriteCommandAfter
- System.Data.SqlClient.WriteCommandError
इसी तरह डेटाबेस से क्वेरी के पहले और बाद में होते हैं।
HttpHandlerDiagnosticListener
घटक HttpHandlerDiagnosticListener
घटनाएँ आपको उदाहरण के लिए, HttpClient
वर्ग का उपयोग करते समय निवर्तमान http अनुरोधों को रोकने की HttpHandlerDiagnosticListener
हैं।
- System.Net.Http.HttpRequestOut.Start
- System.Net.Http.HttpRequestOut.Stop
एक आउटगोइंग http अनुरोध के पहले और बाद में।
- System.Net.Http.Exception
जावक http अनुरोध के दौरान कोई त्रुटि हुई है, तो होता है।
वैसे, यहां तक कि एक DiagnosticSource उपयोगकर्ता मार्गदर्शिका भी है , जो DiagnosticSource के लिए नामकरण की सिफारिशों और सम्मेलनों का वर्णन करती है।
जैसा कि आप आसानी से अनुमान लगा सकते हैं, Microsoft इन अनुशंसाओं का पालन नहीं करता है और विपरीत =) करता है (ठीक है, मैं अतिशयोक्ति कर रहा हूँ। निदानकर्ता उपयोगकर्ता के गाइड दिखाई देने से पहले बस डायग्नोस्टिक स्रोत .NET कोर घटकों में उपयोग किया जाने लगा)
आम कोड
यह माना जाता है कि मैं नीचे जिन सभी उदाहरणों पर विचार करूंगा, उनका उपयोग ASP.NET Core एप्लिकेशन में किया जाएगा (हालाँकि यह आवश्यक नहीं है), और बेस क्लास DiagnosticObserverBase
का उपयोग DiagnosticObserverBase
घटनाओं की सदस्यता लेने और उन्हें संसाधित करने के लिए करेगा।
यह वर्ग मेरे पिछले लेख से ExampleDiagnosticObserver
वर्ग पर आधारित है, जहाँ आप इसके संचालन का विवरण पा सकते हैं। ईवेंट की सदस्यता लेने और संसाधित करने के लिए, यह वर्ग Microsoft के NuGet पैकेज से SubscribeWithAdapter
विधि का उपयोग करेगा।
public abstract class DiagnosticObserverBase : IObserver<DiagnosticListener> { private readonly List<IDisposable> _subscriptions = new List<IDisposable>(); protected abstract bool IsMatch(string name); void IObserver<DiagnosticListener>.OnNext(DiagnosticListener diagnosticListener) { if (IsMatch(diagnosticListener.Name)) { var subscription = diagnosticListener.SubscribeWithAdapter(this); _subscriptions.Add(subscription); } } void IObserver<DiagnosticListener>.OnError(Exception error) { } void IObserver<DiagnosticListener>.OnCompleted() { _subscriptions.ForEach(x => x.Dispose()); _subscriptions.Clear(); } }
विशिष्ट घटकों से घटनाओं की सदस्यता लेने के लिए, आपको एक नया वर्ग बनाने की आवश्यकता है, इसे DiagnosticObserverBase
से इनहेरिट करें, IsMatch
विधि को फिर से परिभाषित करें IsMatch
यह उन घटकों के लिए true
हो जाए जिन्हें हम सदस्यता लेना चाहते हैं, घटनाओं से निपटने के लिए तरीके जोड़ते हैं और उन्हें DiagnosticNameAttribute
विशेषताओं के साथ चिह्नित करते हैं, जहाँ आप नाम निर्दिष्ट करते हैं ईवेंट संसाधित किया जा रहा है। उदाहरण के लिए:
public sealed class SomeDiagnosticObserver : DiagnosticObserverBase { protected override bool IsMatch(string name) { return name == "SomeComponent"; } [DiagnosticName("SomeEvent")] public void OnSomeEvent(/* EventParameters */) { // ... } }
DI कंटेनर में DiagnosticObserverBase
वर्ग के आधार पर हैंडलर को पंजीकृत करने के लिए, हम AddDiagnosticObserver
एक्सटेंशन AddDiagnosticObserver
उपयोग करेंगे, जिसका उपयोग Startup.cs फ़ाइल में ConfigureServices
विधि में किया जाएगा:
public static class DiagnosticServiceCollectionExtensions { public static void AddDiagnosticObserver<TDiagnosticObserver>( this IServiceCollection services) where TDiagnosticObserver : DiagnosticObserverBase { services.TryAddEnumerable(ServiceDescriptor .Transient<DiagnosticObserverBase, TDiagnosticObserver>()); } }
और DiagnosticSource से घटनाओं की सदस्यता लेने के लिए, Configure
विधि में निम्नलिखित पंक्तियाँ जोड़ें:
public void Configure(IApplicationBuilder app, IHostingEnvironment env) { var diagnosticObservers = app .ApplicationServices.GetServices<DiagnosticObserverBase>(); foreach (var diagnosticObserver in diagnosticObservers) { DiagnosticListener.AllListeners.Subscribe(diagnosticObserver); } // ... app.UseMvc(); }
शायद यह रजिस्टर करने का सबसे अच्छा तरीका नहीं है, और व्यवहार में हम आमतौर पर ऐसे उद्देश्यों के लिए IHostedService
इंटरफ़ेस का उपयोग करते हैं, लेकिन हमारे उदाहरण पर्याप्त होंगे।
कुछ नुकसान
यदि आप अपनी परियोजनाओं में DiagnosticSource का उपयोग करने का निर्णय लेते हैं, तो आप कुछ गैर-स्पष्ट बिंदुओं पर आ सकते हैं, जिन पर मैं ध्यान देना चाहूंगा।
कभी-कभी गैर-मौजूद घटनाओं के लिए डमी हैंडलर की आवश्यकता हो सकती है
आमतौर पर, अगर कुछ घटक अपने काम के बारे में घटनाओं को भेजता है, तो घटना भेजने के लिए कोड निम्नानुसार है:
if (_diagnosticSource.IsEnabled("SomeEvent")) _diagnosticSource.Write("SomeEvent", new { /* parameters */ });
यह पैरामीटर के साथ एक ऑब्जेक्ट बनाने की अनुमति नहीं देता है अगर कोई भी घटना को संसाधित करने के लिए नहीं जा रहा है, और कचरा संग्रह पर थोड़ा बचा है।
हालाँकि, कुछ मामलों में प्रत्ययों के साथ युग्मित घटनाएँ होती हैं .Stop
और .Stop
, दोनों को या तो काम करना चाहिए या नहीं। ऐसी घटनाओं को भेजने के लिए कोड कुछ इस तरह दिख सकता है:
// , . var someEventIsEnabled = _diagnosticSource.IsEnabled("SomeEvent"); if (someEventIsEnabled && _diagnosticSource.IsEnabled("SomeEvent.Start")) _diagnosticSource.Write("SomeEvent.Start", new { /* parameters */ }); // ... if (someEventIsEnabled && _diagnosticSource.IsEnabled("SomeEvent.Stop")) _diagnosticSource.Write("SomeEvent.Stop", new { /* parameters */ });
इसलिए, SomeEvent.Start
और SomeEvent.Stop
घटनाओं की सदस्यता लेने के लिए, SomeEvent.Stop
इवेंट के लिए एक डमी हैंडलर भी जोड़ना होगा, जिसे कभी भी कॉल नहीं किया जाएगा, लेकिन इसकी उपस्थिति की जाँच की जाएगी।
कुछ घटनाओं को जोड़ा जाता है और कुछ को ट्रिपल
कुछ ईवेंट जोड़े जाते हैं, जैसे कि System.Net.Http.HttpRequestOut.Start
और System.Net.Http.HttpRequestOut.Stop
। इसका मतलब यह है कि प्रत्यय के साथ घटना। कुछ ऑपरेशन के शुरू होने से पहले स्टार्ट को बुलाया जाएगा, और प्रत्यय के साथ घटना। सबसे अंत में कॉल किया जाएगा। इस मामले में, अंतिम घटना को ट्रिगर करने की गारंटी दी जाएगी (यदि उपयुक्त हैंडलर हैं), भले ही ऑपरेशन एक त्रुटि के साथ समाप्त हो गया हो या नहीं।
हालाँकि, कुछ ईवेंट ट्रिपल हैं, उदाहरण के लिए, System.Data.SqlClient.WriteCommandBefore
, System.Data.SqlClient.WriteCommandAfter
और System.Data.SqlClient.WriteCommandError
, जहां अंतिम घटना ऑपरेशन के परिणाम पर निर्भर करती है। इस स्थिति में, यदि ऑपरेशन सफलतापूर्वक पूरा हो गया था, केवल System.Data.SqlClient.WriteCommandAfter
घटना को System.Data.SqlClient.WriteCommandAfter
जाएगा, और यदि ऑपरेशन के दौरान कोई त्रुटि होती है, तो केवल System.Data.SqlClient.WriteCommandError
घटना को System.Data.SqlClient.WriteCommandError
जाएगा।
यह ध्यान में रखा जाना चाहिए यदि, उदाहरण के लिए, आप संचालन के समय को मापने के लिए घटनाओं का उपयोग करते हैं। उदाहरण के लिए, यदि आप ऑपरेशन की शुरुआत में स्टॉपवॉच शुरू करते हैं, तो आपको इसे दो स्थानों पर रोकने की आवश्यकता है ताकि डेटा खोना न हो।
डायग्नोस्टिक स्रोत
अब सब कुछ हमारे लिए तैयार है कि कैसे DiagnosticSource तंत्र को वास्तविक अनुप्रयोगों में व्यवहार में लाया जा सके।
सहसंबंध और सेवाओं के बीच अग्रसारण प्रमुख
माइक्रोसर्विस की दुनिया में, सहसंबंध शब्द अक्सर पाया जा सकता है। यह कुछ पहचानकर्ता है जो हर बार जब आप किसी भी सेवा का उपयोग करते हैं और http हेडर के माध्यम से सेवा से सेवा में प्रेषित किया जाता है। यह पहचानकर्ता आमतौर पर लॉग में लिखा जाता है, जिससे आप एकल लेनदेन के हिस्से के रूप में प्राप्त कई सेवाओं के संदेशों को लिंक कर सकते हैं।
ASP.NET Core के लिए, एक CorrelationId NuGet पैकेज है, हालांकि, डेवलपर्स को सभी आउटगोइंग अनुरोधों के लिए उपयुक्त हेडर को मैन्युअल रूप से जोड़ना होगा, इसलिए इसका उपयोग करना बहुत सुविधाजनक नहीं है।
हम DiagnosticSource के माध्यम से CorrelationId को लागू करते हैं। शुरू करने के लिए, हमारे पहचानकर्ता को संग्रहीत करने के लिए जिम्मेदार CorrelationId
वर्ग जोड़ें:
public static class CorrelationId { private static readonly AsyncLocal<Guid?> _current = new AsyncLocal<Guid?>(); public static Guid Current { get { var value = _current.Value; if (value == null) throw new InvalidOperationException("CorrelationId isn't assigned."); return value.Value; } set { _current.Value = value; } } }
यह वर्ग वर्तमान CorrelationId मान को संग्रहीत करने के लिए AsyncLocal <T> प्रकार की एक आवृत्ति का उपयोग करता है, जो प्रत्येक अनुरोध के लिए अद्वितीय होगा, लेकिन एसिंक्रोनस कोड के साथ काम करते समय थ्रेडपूल से एक धागे से दूसरे में सही ढंग से स्थानांतरित किया जाएगा।
अगले चरण में DiagnosticSource से एक इवेंट हैंडलर जोड़ना है, जो इनकमिंग और आउटगोइंग http अनुरोधों को रोक देगा। आने वाले अनुरोधों में, हम X-Correlation-ID
हैडर की उपस्थिति की जाँच करेंगे और यदि ऐसा नहीं है, तो हम Guid.NewGuid()
माध्यम से एक नया पहचानकर्ता उत्पन्न करेंगे। आउटगोइंग अनुरोधों में, हम केवल CorrelationId.Current
का उपयोग करके एक हेडर जोड़ेंगे।
public sealed class CorrelationIdHandler : DiagnosticObserverBase { protected override bool IsMatch(string name) { return name == "Microsoft.AspNetCore" || name == "HttpHandlerDiagnosticListener"; } // http [DiagnosticName("Microsoft.AspNetCore.Hosting.HttpRequestIn")] public void OnHttpRequestIn() { } [DiagnosticName("Microsoft.AspNetCore.Hosting.HttpRequestIn.Start")] public void OnHttpRequestInStart(HttpContext httpContext) { // CorrelationId http . var headers = httpContext.Request.Headers; if (headers.TryGetValue("X-Correlation-ID", out var header)) { if (Guid.TryParse(header, out var correlationId)) { CorrelationId.Current = correlationId; return; } } // CorrelationId. CorrelationId.Current = Guid.NewGuid(); } // http [DiagnosticName("System.Net.Http.HttpRequestOut")] public void OnHttpRequestOut() { } [DiagnosticName("System.Net.Http.HttpRequestOut.Start")] public void OnHttpRequestOutStart(HttpRequestMessage request) { // http CorrelationId var correlationId = CorrelationId.Current.ToString(); request.Headers.Add("X-Correlation-ID", correlationId); } }
इस वर्ग में, IsMatch
विधि में IsMatch
हम रिपोर्ट करते हैं कि हम Microsoft.AspNetCore
से IsMatch
घटकों (आने वाले http अनुरोधों के लिए जिम्मेदार) और HttpHandlerDiagnosticListener
(निवर्तमान http अनुरोधों के लिए जिम्मेदार) से घटनाओं को संसाधित करना चाहते हैं। हेडर्स की डायरेक्ट प्रोसेसिंग OnHttpRequestInStart
और OnHttpRequestOutStart
में होती है।
इसके अलावा, हमें दो डमी तरीके OnHttpRequestIn
और OnHttpRequestOut
जोड़ना पड़ा। उन्हें प्रसंस्करण के दौरान नहीं बुलाया जाएगा, लेकिन यह निर्धारित करने के लिए उपयोग किया जाता है कि Start
और Stop
हैंडलर की एक जोड़ी को कॉल करना है या नहीं। उनके बिना, इन घटनाओं को ट्रिगर नहीं किया जाएगा।
यह केवल Startup.cs फ़ाइल में हमारे हैंडलर को पंजीकृत करने के लिए बनी हुई है:
services.AddDiagnosticObserver<CorrelationIdHandler>();
व्यवहार में, यह किसी एक को आगे करने के लिए भी उपयोगी हो सकता है, लेकिन एक निश्चित उपसर्ग के साथ कई हेडर (उदाहरण के लिए, "X-Api-"), जिससे तथाकथित प्रसंग प्रचार का एहसास होता है। यह तंत्र आपको एक विशिष्ट सेवा के साथ एक मूल्य निर्धारित करने और दूसरे में पढ़ने की अनुमति देता है, इस मूल्य को अनुरोध निकाय के माध्यम से स्पष्ट रूप से पारित किए बिना। ऊपर वर्णित CorrelationIdHandler
वर्ग के आधार पर एक समान तंत्र को आसानी से लागू किया जा सकता है।
मैट्रिक्स और निशान का संग्रह
मैट्रिक्स और निशान किसी भी एप्लिकेशन का एक महत्वपूर्ण हिस्सा हैं। मेट्रिक्स आपको अनुप्रयोगों और निशान के लिए निगरानी और डैशबोर्ड को कॉन्फ़िगर करने की अनुमति देता है - उनमें अड़चन खोजने के लिए।
हम OZON.ru पर मैट्रिक्स इकट्ठा करने के लिए प्रोमेथियस का उपयोग करते हैं और ASP.NET कोर सेवाओं के लिए, NuGet पैकेज Prometheus.Client.AspNetCore ।
निशान इकट्ठा करने के लिए, हम OpenTracing और Jaeger का उपयोग करते हैं। (यदि आप चाहें, तो आप मेरी बात "डॉट नेट में ओपनट्रेस्टिंग का उपयोग कर" डॉटकॉम एमएसीटी # 30 के साथ देख सकते हैं)
हालांकि, कई डेवलपर्स मैट्रिक्स और निशान के साथ अपने अनुप्रयोगों को कवर करने के लिए बहुत उत्सुक नहीं हैं, क्योंकि अक्सर इसके लिए अतिरिक्त वर्दी कोड लिखने की आवश्यकता होती है और "व्यावसायिक कार्यों" के साथ बहुत संगत नहीं है।
सौभाग्य से, अधिकांश घटक जो DiagnosticSource के माध्यम से घटनाओं को भेजते हैं, युग्मित घटनाओं को भेजते हैं, जिनमें से पहला एक निश्चित ऑपरेशन की शुरुआत को इंगित करता है, और दूसरा - इसका पूरा होना। यह, उदाहरण के लिए, स्टॉपवॉच को पहले शुरू करने की अनुमति देता है, और फिर इसे रोकना और एक निश्चित मीट्रिक देना।
उदाहरण के लिए, यदि हम सभी नियंत्रक क्रियाओं के निष्पादन समय के लिए एक मीट्रिक एकत्र करने के लिए जाते हैं, तो हम निम्न वर्ग का उपयोग कर सकते हैं:
public sealed class AspNetCoreMetricsHandler : DiagnosticObserverBase { private readonly Histogram requestDurationSeconds; public MetricsHandler(MetricFactory metricFactory) { // , NuGet Prometheus.Client. // . requestDurationSeconds = metricFactory.CreateHistogram( "request_duration_seconds", "", labelNames: new[] {"action_name"}); } protected override bool IsMatch(string name) { return name == "Microsoft.AspNetCore"; } [DiagnosticName("Microsoft.AspNetCore.Hosting.HttpRequestIn")] public void OnHttpRequestIn() { } [DiagnosticName("Microsoft.AspNetCore.Hosting.HttpRequestIn.Start")] public void OnHttpRequestInStart(HttpContext httpContext) { // http . httpContext.Items["Stopwatch"] = Stopwatch.StartNew(); } [DiagnosticName("Microsoft.AspNetCore.Mvc.BeforeAction")] public void OnBeforeAction(HttpContext httpContext, ActionDescriptor actionDescriptor) { // , // . httpContext.Items["ActionName"] = actionDescriptor.DisplayName; } [DiagnosticName("Microsoft.AspNetCore.Hosting.HttpRequestIn.Stop")] public void OnHttpRequestInStop(HttpContext httpContext) { // http // . if (!httpContext.Items.TryGetValue("Stopwatch", out object stopwatch)) return; if (!httpContext.Items.TryGetValue("ActionName", out object actionName)) actionName = "Unknown"; var duration = ((Stopwatch) stopwatch).Elapsed.TotalSeconds; requestDurationSeconds .WithLabels(actionName.ToString()) .Observe(duration); } }
यहां कंस्ट्रक्टर में हम प्रोमेथियस के नूगेट पैकेज से हिस्टोग्राम मीट्रिक घोषित करते हैं। इस मीट्रिक के लिए हम "एक्शन_नाम" लेबल जोड़ते हैं, जो हमें नियंत्रकों के विभिन्न कार्यों में एकत्र किए गए मीट्रिक के बीच अंतर करने की अनुमति देता है।
ईवेंट प्रोसेसिंग ( OnHttpRequestInStart
विधि) की शुरुआत में, हम क्वेरी निष्पादन समय को मापने के लिए स्टॉपवॉच शुरू करते हैं। हमें संसाधित किए जा रहे कार्य का नाम भी याद है ( OnBeforeAction
विधि)। और अंत में, अनुरोध को संसाधित करने के बाद ( OnHttpRequestInStop
विधि), हम फिर से httpContext.Items
संग्रह से सभी डेटा प्राप्त करते हैं और इसे मीट्रिक पर लिखते हैं।
यह केवल हमारे हैंडलर और MetricFactory
आवृत्ति को MetricFactory
फ़ाइल में पंजीकृत करने के लिए बना हुआ है:
services.AddSingleton(Prometheus.Client.Metrics.DefaultFactory); services.AddDiagnosticObserver<AspNetCoreMetricsHandler>();
एक समान तकनीक का उपयोग NuGet OpenTracing पैकेज का उपयोग करके निशान एकत्र करने के लिए किया जा सकता है।
लॉगिंग
DiagnosticSource का एक और बहुत उपयोगी अनुप्रयोग अपवाद लॉगिंग है। लेकिन सवाल उठ सकता है: "इसकी आवश्यकता क्यों है?"। आखिरकार, आप बस अपने कोड को ट्राइ-कैच ब्लॉक में लपेट सकते हैं या यहां तक कि सभी अखंडित अपवादों के लिए एक वैश्विक हैंडलर कॉन्फ़िगर कर सकते हैं।
तथ्य यह है कि DiagnosticSource घटनाओं के माध्यम से अपवाद हैंडलिंग बहुत प्रारंभिक चरण में होती है, जब विभिन्न ऑब्जेक्ट अभी भी उपलब्ध हैं जो हमें अपवाद के कारण को समझने में मदद कर सकते हैं। (यह ध्यान देने योग्य है कि DiagnosticSource केवल आपको अपवाद को संभालने की अनुमति देता है, लेकिन इसके आगे प्रसार को नहीं रोक सकेगा)
मान लीजिए कि हम लॉग को क्वेरी टेक्स्ट और उसके मापदंडों को रिकॉर्ड करते समय, डेटाबेस तक पहुंचते समय सभी अपवादों को केंद्रीय रूप से संभालना चाहते हैं। DiagnosticSource का उपयोग हम इस प्रकार कर सकते हैं:
public sealed class SqlClientLoggingHandler : DiagnosticObserverBase { private readonly ILogger<SqlClientLoggingHandler> _logger; public SqlClientLoggingHandler(ILogger<SqlClientLoggingHandler> logger) { _logger = logger; } protected override bool IsMatch(string name) { return name == "SqlClientDiagnosticListener"; } [DiagnosticName("System.Data.SqlClient.WriteCommandError")] public void OnCommandError(DbCommand command, Exception exception) { var sb = new StringBuilder(); sb.AppendLine("Command: " + command.CommandText); if (command.Parameters.Count > 0) { sb.AppendLine("Parameters: "); foreach (DbParameter parameter in command.Parameters) { sb.AppendLine($"\t{parameter.ParameterName}: {parameter.Value}"); } } _logger.LogError(exception, sb.ToString()); } }
IsMatch
, SqlClientDiagnosticListener
, OnCommandError
.
Startup.cs :
services.AddDiagnosticObserver<SqlClientLoggingHandler>();
निष्कर्ष
DiagnosticSource. , , , DiagnosticSource, ASP.NET Core.
OZON.ru . , NuGet , , .