.NET使用?OpenTelemetry?Traces?追蹤應(yīng)用程序的方法
上一次我們講了 OpenTelemetry Logs
。今天繼續(xù)來說說 OpenTelemetry Traces
。
在今天的微服務(wù)和云原生環(huán)境中,理解和監(jiān)控系統(tǒng)的行為變得越來越重要。在當(dāng)下我們實現(xiàn)一個功能可能需要調(diào)用了 N 個方法,涉及到 N 個服務(wù)。方法之間的調(diào)用如蜘蛛網(wǎng)一樣。分布式追蹤這個時候就至關(guān)重要。它可以把我們程序的調(diào)用鏈可視化。這對于運維人員監(jiān)控程序狀態(tài),開發(fā)人員 trouble shooting 都非常用幫助。
什么是 OpenTelemetry Traces
OpenTelemetry Traces
是 OpenTelemetry
提供的一種遙測數(shù)據(jù)類型,用于記錄和描述在分布式系統(tǒng)中的單個操作或工作單元的生命周期。
在 OpenTelemetry
中,一個 Trace
可以被視為由一系列相關(guān)的事件組成的時間線,這些事件被稱為 Spans
。每個 Span
可以包含多個屬性、注釋和事件,用于描述在該 Span 的生命周期中發(fā)生的特定操作或事件。
例如,一個 HTTP 請求可以被表示為一個 Span
,其中包含了請求的開始時間、結(jié)束時間、HTTP 方法、URL、狀態(tài)碼等信息。如果這個請求還調(diào)用了其他的服務(wù)或數(shù)據(jù)庫,那么這些調(diào)用也可以被表示為與原始請求 Span
相關(guān)聯(lián)的子 Span
。
注意:Span
是 OpenTelemetry
定義的概念,在 .NET 中使用 Activity
表示一個 Span
。
以上的話呢比較官方,是我用 chatGPT 生成的。還是直接用代碼來演示一下效果大家好理解。
示例:追蹤 Http 與 Database
在日常的開發(fā)活動中,http
與 database
操作基本就是涵蓋了 99%
的場景。很多時候我們希望監(jiān)控應(yīng)用程序?qū)γ總€請求的響應(yīng)速度,以及其中數(shù)據(jù)庫操作的耗時。這是一個非常非常常見的需求。以下使用一個用戶登錄接口來演示。
安裝依賴
<PackageReference Include="Npgsql" Version="8.0.3" /> <PackageReference Include="Npgsql.OpenTelemetry" Version="8.0.3" /> <PackageReference Include="OpenTelemetry.Exporter.OpenTelemetryProtocol" Version="1.8.1" /> <PackageReference Include="OpenTelemetry.Extensions.Hosting" Version="1.8.1" /> <PackageReference Include="OpenTelemetry.Instrumentation.AspNetCore" Version="1.8.1" />
使用 nuget 安裝以上包。
注入服務(wù)
var otel = builder.Services.AddOpenTelemetry(); // Configure OpenTelemetry Resources with the application name otel.ConfigureResource(resource => resource .AddService(builder.Environment.ApplicationName)); otel.WithTracing(tracing => { tracing .AddAspNetCoreInstrumentation() .AddNpgsql() .AddOtlpExporter(otlpOptions => { otlpOptions.Protocol = OtlpExportProtocol.HttpProtobuf; otlpOptions.Endpoint = new Uri("http://192.168.0.1:5341/ingest/otlp/v1/traces"); }); });
跟 Logs 類似,我們使用 WithTracing 擴展方法來對 Traces 進行配置。
- 調(diào)用
AddAspNetCoreInstrumentation
方法來添加對AspNetCore
框架的跟蹤支持。這將自動跟蹤應(yīng)用程序中的HTTP請求和響應(yīng),并生成相應(yīng)的跟蹤數(shù)據(jù)。 - 調(diào)用
AddNpgsql
方法來添加對Npgsql
庫的跟蹤支持。這將自動跟蹤應(yīng)用程序中使用Npgsql
庫進行的數(shù)據(jù)庫操作,并生成相應(yīng)的跟蹤數(shù)據(jù)。 - 我們調(diào)用
AddOtlpExporter
方法來添加一個OTLP
(OpenTelemetry Protocol)導(dǎo)出器。這個導(dǎo)出器將把跟蹤數(shù)據(jù)發(fā)送到指定的OTLP
接收端。在這里,我們將跟蹤數(shù)據(jù)發(fā)送到"http://192.168.0.201:5341/ingest/otlp/v1/traces"這個地址。
登錄代碼
public class UserRepository { private readonly string _connectionString = "Host=127.0.0.1;Username=postgres;Password=123456"; public async Task<User> GetUserAsync(string username, string password) { using var conn = new NpgsqlConnection(_connectionString); conn.Open(); using var cmd = new NpgsqlCommand("SELECT * FROM t_users WHERE username = @username AND password = @password", conn); cmd.Parameters.AddWithValue("username", username); cmd.Parameters.AddWithValue("password", password); using var reader = await cmd.ExecuteReaderAsync(); if (reader.Read()) { return new User { Id = reader.GetString(0), Username = reader.GetString(1), Password = reader.GetString(2), // 其他字段... }; } return null; } } public class User { public string Id { get; set; } public string Username { get; set; } public string Password { get; set; } // 其他字段... }
[HttpPost] public async Task<string> Login([FromBody] LoginModel model) { var user = await new UserRepository().GetUserAsync(model.Username, model.Password); if (user != null) { return "ok"; } return "error"; }
平平無奇的代碼,簡單演示一下用用戶名密碼進行登錄。在這里我想指出的一個點是:
其中并沒有任何
Trace
的代碼會侵入到我們的業(yè)務(wù)中。
在 Seq 中查看 Trace
以上就是所有的關(guān)鍵代碼。讓我們運行程序使用 postman 調(diào)用登錄接口。打開 Seq
界面進行查看。
Trace 的信息已經(jīng)到了 Seq 里??梢钥吹秸麄€ POST Account 接口耗時 326ms,其中 postgres 耗時 42 ms。點擊每一行都有更詳細(xì)的屬性。比如 postgres 里包含了 connection string,sql statement 等非常有用的信息。
示例:自定義 Trace 內(nèi)容
以上示例能是使用現(xiàn)成的庫進行 Trace
。雖然絕大多數(shù)情況下已經(jīng)夠用了。但是有的時候我們想更加詳細(xì)的對我們的程序進行追蹤,那么就需要自己來定義 Span
(Activity)來實現(xiàn)了。以下就讓我們通過一個獲取天氣的接口來演示如何自定義 Activity
。
添加 Trace 的 source
otel.WithTracing(tracing => { tracing .AddSource("MyTraceSample") .... });
編寫接口
[ApiController] [Route("[controller]")] public class WeatherForecastController : ControllerBase { private readonly ILogger<WeatherForecastController> _logger; private readonly ActivitySource _source; public WeatherForecastController(ILogger<WeatherForecastController> logger) { _logger = logger; _source = new ActivitySource("MyTraceSample", "1.0.0"); } [HttpGet] public async Task<string> Get([FromQuery]string city) { _logger.LogInformation("Hello WeatherForecast"); using (var activity = _source.StartActivity("CallWeatherForecast")) { activity?.AddTag("city", city); await Task.Delay(100); await GetWeatherInfoFromWebservice(); await FormatWeatherInfo(); } return "24°c"; } async Task GetWeatherInfoFromWebservice() { using (var activity = _source.StartActivity("GetWeatherInfoFromWebservice")) { await Task.Delay(200); } } async Task FormatWeatherInfo() { using (var activity = _source.StartActivity("FormatWeatherInfo")) { await Task.Delay(300); } } }
在 Controller
的 Get
方法可以接受一個 city
的參數(shù),然后調(diào)用 GetWeatherInfoFromWebservice
模擬從其他服務(wù)獲取數(shù)據(jù),再調(diào)用 FormatWeatherInfo
方法來模擬對獲取的天氣數(shù)據(jù)進行格式化。每個方法中都加入了 Task.Delay
來模擬耗時。
首先我們會實例化一個 ActivitySource
。然后在每個需要追蹤的方法最頂上調(diào)用 _source.StartActivity
得到一個 Activity
實例。這時候 Activity
就開始計時了。但是為啥沒有 Stop
呢?
顯然是 using
幫我們調(diào)用了。 以上代碼可能對業(yè)務(wù)代碼侵入的比較嚴(yán)重,那么可以使用 AOP
技術(shù)進行解耦。這里就不展開了。
在 Seq 中查看自定義的 Trace
運行程序,使用 postman 進行調(diào)用。然后打開 Seq
界面查看 Trace
。
通過以上圖片可以清晰看到:GET WeatherForecast
接口調(diào)用了 CallWeatherForecast
, CallWeatherForecast
又調(diào)用了 GetWeatherInfoFromWebservice
與 FormatWeatherInfo
。以及這些方法與整個 http
請求的耗時??梢哉f是非常非常直觀。
點擊 CallWeatherForecast
這一行,還可以看到我們設(shè)置的 tag
的內(nèi)容。
總結(jié)
以上我們可以看到如果你想對 http
接口以及 database
操作進行追蹤,只需要簡單的幾行代碼就可以完成而且全程無侵入。如果你想對程序進行更細(xì)致的追蹤還可以使用自定義的 Activity
進行擴展,整個過程也毫無難度。希望這篇內(nèi)容對想要學(xué)習(xí) .NET
程序可觀測的同學(xué)有所幫助。
到此這篇關(guān)于.NET 中使用 OpenTelemetry Traces 追蹤應(yīng)用程序的文章就介紹到這了,更多相關(guān).NET OpenTelemetry Traces 追蹤應(yīng)用程序內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Asp.net+jquery+.ashx文件實現(xiàn)分頁思路
分頁思路: .ashx程序中,編寫好取得不同頁碼的程序。在頁面布局好的前提下,留下數(shù)據(jù)區(qū)域 div。然后在頁面請求 .ashx程序生成下一頁的html代碼。覆蓋div.innerHTMl2013-03-03ASP.NET Web API教程 創(chuàng)建Admin控制器實例分享
在本文中我們要添加一個對產(chǎn)品支持CRUD(創(chuàng)建、讀取、更新和刪除)操作的Web API控制器,需要的朋友可以參考下2012-11-11asp.net(c#)下各種進制間的輕松轉(zhuǎn)換(2進制、8進制、10進制、16進制)
在.NET Framework中,System.Convert類中提供了較為全面的各種類型、數(shù)值之間的轉(zhuǎn)換功能。2010-10-10asp.net Request.ServerVariables[] 讀解
asp.net Request.ServerVariables[] 讀解,學(xué)習(xí).net的朋友可以參考下,方便獲取服務(wù)器的一些信息。2011-08-08asp.net uploadify實現(xiàn)多附件上傳功能
這篇文章主要為大家詳細(xì)介紹了asp.net uploadify實現(xiàn)多附件上傳功能,具有一定的參考價值,感興趣的小伙伴們可以參考一下2016-11-11ASP.NET MVC重寫RazorViewEngine實現(xiàn)多主題切換
這篇文章主要為大家詳細(xì)介紹了ASP.NET MVC重寫RazorViewEngine實現(xiàn)多主題切換,具有一定的參考價值,感興趣的小伙伴們可以參考一下2017-06-06