前言
紀錄 Elastic APM、opentelemetry-collector 環境建置、.Net Core 串接 OTLP 拋送資訊至 Elastic APM 來監控服務
機器環境&服務
環境
Linux Server: Ubuntu 18.04.6 LTS
服務: Kibana、ElasticSeatch、Elastic APM
Linux Server 端安裝服務
安裝Docker
參考 w4560000 - Linux 安裝 Docker、Docker-Compose
docker-compose 建立 kibana 、elasticsearch、apm、opentelemetry-collector 服務
官方文件請參考
OpenTelemetry Docs/Collector/Configuration
Elastic-7.8 open-telemetry-elastic-get-started
流程圖
需要注意的是 目前測試是用 APM 7.8版本,Elastic 有自行擴充 Elastic Exporter 在 otel/opentelemetry-collector-contrib-dev:40d055d5a23eb00e3732c23be56442c9cb1e1684
2023/04/15 測試時,發現最新版 otel/opentelemetry-collector-contrib-dev 的 otel-collector-config 格式 沒有支援 elastic
所以先延用舊版本 otel/opentelemetry-collector-contrib-dev:40d055d5a23eb00e3732c23be56442c9cb1e1684
todo 正式版的 otel/opentelemetry-collector-contrib 會在測試看看 是否支援 Elastic
vi apm.yaml
version: '3'
services:
kibana:
container_name: kibana
image: kibana:7.8.0
depends_on:
- elasticsearch
ports:
- 5601:5601
environment:
SERVER_NAME: kibana-server
ELASTICSEARCH_HOSTS: http://elasticsearch:9200
elasticsearch:
container_name: elasticsearch
image: elasticsearch:7.8.0
environment:
- discovery.type=single-node
- bootstrap.memory_lock=true
- "ES_JAVA_OPTS=-Xms512m -Xmx512m"
ulimits:
memlock:
soft: -1
hard: -1
ports:
- 9200:9200
volumes:
- /data01:/usr/share/elasticsearch/data
apm:
container_name: apm
image: docker.elastic.co/apm/apm-server:7.8.0
ports:
- 8200:8200
depends_on:
- elasticsearch
- kibana
opentelemetry-collector:
container_name: opentelemetry
image: otel/opentelemetry-collector-contrib-dev:40d055d5a23eb00e3732c23be56442c9cb1e1684
command: ["--config=/etc/otel-collector-config.yaml", ""]
volumes:
- /data02/otel-collector-config.yaml:/etc/otel-collector-config.yaml
depends_on:
- apm
ports:
- 4317:4317
建立 otel-collector-config.yaml
vi otel-collector-config.yaml
receivers:
otlp:
protocols:
grpc:
http:
processors:
batch:
exporters:
elastic:
apm_server_url: "http://apm:8200"
service:
pipelines:
traces:
receivers: [otlp]
processors: [batch]
exporters: [elastic]
將服務跑起來
docker-compose -f apm.yaml up -d
.Net Core 專案建置
範例專案可參考
Github-w4560000 DemoOpentelemetry
DemoOpentelemetry.UI = 入口站台
DemoOpentelemetry.API = API1
DemoOpentelemetry.API2 = API2
入口站台會呼叫 API1 的 WeatherForecast API
API1 的 WeatherForecast API 則會呼叫 DB、Redis、API2 的 WeatherForecast API
API2 的 WeatherForecast API 則非同步同時呼叫 一個政府公開資料的API
藉此模擬後端服務之間 Server to Server API 之間的串接,來觀察串接狀況
查看 APM
可清楚看到 API 串接呼叫流程,後面的非同步呼叫也可以看到同時間呼叫三次API
紀錄 API Request、Response
安裝 Nuget 套件 OpenTelemetry.Instrumentation.Http 1.0.0-rc9
程式碼參考 https://github.com/w4560000/DemoOpentelemetry/blob/master/API/Program.cs
.AddHttpClientInstrumentation(options =>
{
options.Enrich = (activity, eventName, rawObject) =>
{
if (eventName.Equals("OnStartActivity"))
{
if (rawObject is HttpRequestMessage httpRequest)
{
var request = "empty";
if (httpRequest.Content != null)
request = httpRequest.Content.ReadAsStringAsync().Result;
activity.SetTag("http.request_content", request);
}
}
if (eventName.Equals("OnStopActivity"))
{
if (rawObject is HttpResponseMessage httpResponse)
{
var response = "empty";
if (httpResponse.Content != null)
response = httpResponse.Content.ReadAsStringAsync().Result;
activity.SetTag("http.response_content", response);
}
}
};
})
紀錄呼叫 Sql Server QueryString、StoredProcedure、傳入參數
安裝 Nuget 套件 OpenTelemetry.Instrumentation.SqlClient 1.0.0-rc9
.AddSqlClientInstrumentation(options =>
{
options.EnableConnectionLevelAttributes = true;
options.SetDbStatementForStoredProcedure = true;
options.SetDbStatementForText = true;
options.RecordException = true;
options.Enrich = (activity, connection, command) =>
{
if(command is DbCommand dbCommand)
{
var parameters = dbCommand.Parameters;
foreach (SqlParameter parameter in parameters)
activity.SetTag($"sql.parameter.{parameter.ParameterName}", parameter.Value?.ToString());
}
};
})
攔截 DB Query字串、參數
攔截 DB SP字串、參數
原本想嘗試抓 DB 回傳資料,但後來查原始碼發現 Enrich 是在呼叫 DB 之前執行的,所以無法攔截到 DB 回傳資料
DB回傳資料後的動作,該套件沒有提供自定義方法來供呼叫,所以抓不到 DB 回傳資料
https://github.com/open-telemetry/opentelemetry-dotnet/blob/main/src/OpenTelemetry.Instrumentation.SqlClient/Implementation/SqlClientDiagnosticListener.cs#L153
紀錄呼叫 Redis
安裝 Nuget 套件 OpenTelemetry.Instrumentation.StackExchangeRedis 1.0.0-rc9.7
.AddRedisInstrumentation(connectionMultiplexer, o => o.SetVerboseDatabaseStatements = true)
結論
可以跨服務實現鏈路追蹤後,會讓開發或維運人員更清楚的了解當服務發生異常時,是哪一支 API 造成,或是延遲發生在哪一段流程
不然以往查看 Log,都要開發人員開專案起來比對 Log 邏輯,才能找出問題原因,甚至若 Log 沒印到的話,還需要重埋 Log 等下次才能重現
OpenTelemetry 目前已經有提供各語言的 SDK 供開發人員使用,且以 .Net Core 來說使用上是不用修改到專案程式碼
只需要在 Program.cs 註冊後即可使用
以往使用 Nuget 開源套件,假設有 Http 呼叫的動作,我們沒辦法得知當下他呼叫了多久,以及傳入回傳值,因為沒有 Log 可以追蹤
但有了鏈路追蹤之後,因為不用改到程式碼,所以這些套件的動作也都可以監控到了,這樣對專案服務的監控和掌控度就可以更多一些,也更能追蹤到異常點
參考連結
Opentelemetry Documentation
m@rcus 學習筆記 [APM] 提升應用程式效能的利器 Elastic APM : dotnet x Elastic
Nitesh Singhal OpenTelemetry with Jaeger in .NET Core
轉載請註明來源,若有任何錯誤或表達不清楚的地方,歡迎在下方評論區留言,也可以來信至 leozheng0621@gmail.com
如果文章對您有幫助,歡迎斗內(donate),請我喝杯咖啡