ARMS用戶體驗監控支持以用戶會話作為切入點,追蹤用戶與應用交互過程中的錯誤、緩慢、異常問題,通過與ARMS應用監控聯動,實現端到端分析,幫助您打通問題分析鏈路。本文介紹移動端監控如何實現端到端Trace打通。
前提條件
支持的Trace協議類型
Skywalking:v3版本(Skywalking 8.*)
OpenTelemetry(w3c)
接入操作
添加自身服務域名并開啟Trace透傳
- 登錄ARMS控制臺。
在左側導航欄選擇
,并在頂部菜單欄選擇目標地域。單擊目標應用名稱,然后單擊應用設置。
在請求管理區域配置自身服務域名。
重要請勿將第三方服務域名添加為自身服務,否則Trace打通可能不會生效。
添加自身服務域名,打開鏈路打通開關,并選擇后端服務對應的透傳協議。
說明后端應用需要先接入ARMS鏈路追蹤,具體操作,請參見接入指南。
透傳格式名稱
格式
sw8: {sample}-{trace-id}-{segment-id}-{0}-{service}-{instance}-{endpoint}-{peer}
traceparent : {version}-{trace-id}-{parent-id}-{trace-flags}
tracestate: rum={version}&{appType}&{pid}&{sessionId}
單擊確認,系統將會自動推送Trace打通配置到移動端。
重要端側配置的生效,可能會有分鐘級延遲,具體取決于用戶側行為,SDK默認在App冷啟動時會拉取一次配置,切至后臺超過30s后再次打開時,也會重新拉取。
需要注意,雖然移動端不存在Web的CORS策略限制,但各協議透傳的Request Header需要服務端網關支持透傳,否則后端服務無法接受Header,也就無法實現RUM與Trace打通。
驗證是否配置成功
此處以SkyWalking V3版本透傳協議為例驗證Trace是否配置成功。
Android
可通過Android Studio內置的App Inspection工具查看網絡請求的Request Headers中是否攜帶了sw8協議信息判斷是否接入成功。
iOS
可通過Xcode Profile工具(在Xcode工具欄選擇
)查看網絡請求的Request Headers中是否攜帶了sw8協議信息判斷是否接入成功。配置后端應用Trace串聯
為了打通完整Trace鏈路,還需要對后端應用進行配置,目前支持的后端應用類型以及接入方式如下:
Java應用
使用ARMS應用監控探針接入
ARMS應用監控探針默認集成了對OpenTelemetry協議的支持,因此無需額外配置,即可實現與RUM Trace關聯,但需要確保以下兩點:
支持的ARMS應用監控探針版本:2.x、3.x、4.x,為了獲得更好的使用體驗,推薦升級到4.x版本。
支持的Web容器和框架:支持Tomcat、Jetty、WebLogic、Undertow等主流Web容器,以及SpringBoot、SpringMVC等框架。支持的完整組件和框架請參見ARMS應用監控支持的Java組件和框架。
ARMS應用監控探針接入操作請參見開始監控Java應用。
使用OpenTelemetry接入
通過OpenTelemetry接入ARMS(可觀測鏈路 OpenTelemetry 版),目前分為兩種方式:自動埋點和手動埋點。
自動埋點場景下,由于OpenTelemetry已經支持了絕大多數主流框架,因此,無需額外配置,即可實現與RUM Trace的串聯。
說明OpenTelemetry支持的Java框架,請參見通過OpenTelemetry上報Java應用數據。
手動埋點場景下,需要通過OpenTelemetry SDK提供的擴展機制,實現與RUM Trace的串聯,即從前端請求頭(traceparent、tracesate)中,解析出Trace上下文,以下是Springboot場景代碼示例:
引入OpenTelemetry的依賴項。
<dependency> <groupId>io.opentelemetry</groupId> <artifactId>opentelemetry-api</artifactId> </dependency> <dependency> <groupId>io.opentelemetry</groupId> <artifactId>opentelemetry-sdk-trace</artifactId> </dependency> <dependency> <groupId>io.opentelemetry</groupId> <artifactId>opentelemetry-extension-annotations</artifactId> <version>1.18.0</version> </dependency> <dependency> <groupId>io.opentelemetry</groupId> <artifactId>opentelemetry-exporter-otlp</artifactId> </dependency> <dependency> <groupId>io.opentelemetry</groupId> <artifactId>opentelemetry-sdk</artifactId> </dependency> <dependency> <groupId>io.opentelemetry</groupId> <artifactId>opentelemetry-semconv</artifactId> <version>1.30.1-alpha</version> </dependency> <dependency> <groupId>io.opentelemetry</groupId> <artifactId>opentelemetry-sdk-extension-autoconfigure</artifactId> <version>1.34.1</version> </dependency> <dependency> <groupId>io.opentelemetry</groupId> <artifactId>opentelemetry-extension-incubator</artifactId> <version>1.35.0-alpha</version> </dependency>
在OpenTelemetry初始化時,添加W3C Propagator。
Resource resource = Resource.getDefault() .merge(Resource.create(Attributes.of( ResourceAttributes.SERVICE_NAME, "otel-demo", ResourceAttributes.HOST_NAME, "xxxx" ))); SdkTracerProvider sdkTracerProvider = SdkTracerProvider.builder() .addSpanProcessor(BatchSpanProcessor.builder(OtlpHttpSpanExporter.builder() .setEndpoint("Your Endpoint") .addHeader("Authentication", "Your Token") .build()).build()) .setResource(resource) .build(); openTelemetry = OpenTelemetrySdk.builder() .setTracerProvider(sdkTracerProvider) // 這里添加W3C Propagator .setPropagators(ContextPropagators.create( TextMapPropagator.composite(W3CTraceContextPropagator.getInstance(), W3CBaggagePropagator.getInstance())) ).buildAndRegisterGlobal(); // 這里需要使用擴展的Tracer tracer = ExtendedTracer.create(openTelemetry.getTracer("com.example.tracer", "1.0.0"));
在業務接口中,添加headers參數,并從請求頭中解析Trace上下文,設置parent。
// Controller中添加請求header參數,用于解析Trace上下文 @RequestMapping("/test") public String test(@RequestHeader Map<String, String> headers) { Span span = OpenTelemetrySupport.getTracer() .spanBuilder("/test") // 從headers中解析parent span .setParentFrom(OpenTelemetrySupport.getContextPropagators(), headers) .setSpanKind(SpanKind.SERVER) .startSpan(); try (Scope scope = span.makeCurrent()) { // do something } catch (Throwable t) { span.setStatus(StatusCode.ERROR, "handle parent span error"); } finally { span.end(); } return "success"; }
使用SkyWalking接入
完整接入方式請參見Java Agent插件。
SkyWalking目前僅提供了Java Agent接入方式,您只需要按照上述文檔接入,即可實現RUM與后端Trace串聯。
和RUM側配置的協議匹配要求:sw8(v3版本)對應SkyWalking 8.x版本探針。
Go應用
通過OpenTelemetry接入
完整接入方式請參見通過OpenTelemetry上報Go應用數據。
按照文檔接入,然后在HTTP請求Handler中,通過request context生成Span,即可實現與RUM Trace串聯。
// 初始化tracer
tracer := otel.Tracer(common.TraceInstrumentationName)
// 通過request context生成span
handler := http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
ctx := req.Context()
span := trace.SpanFromContext(ctx)
// do something
w.Write([]byte("Hello World"))
})
使用SkyWalking接入
完整接入方式請參見通過SkyWalking上報Go應用數據。
按照文檔接入,推薦采用skywalking-go接入方式,該方式支持了主流的Web服務框架,如gin、go-restful、http、go-kratos v2、go-micro、go-resty等,無需修改代碼即可實現與RUM Trace串聯。
如果您希望手動從HTTP請求頭中解析出Trace上下文,也可參考以下代碼實現:
//Extract context from HTTP request header `sw8`
span, ctx, err := tracer.CreateEntrySpan(r.Context(), "/api/test", func(key string) (string, error) {
return r.Header.Get(key), nil
})
Python應用
通過OpenTelemetry接入
完整接入方式請參見通過OpenTelemetry上報Python應用數據。
按照文檔接入,然后從HTTP請求頭中解析Span上下文,實現與RUM Trace串聯,代碼示例如下:
// 初始化tracer
trace.set_tracer_provider(TracerProvider())
trace.get_tracer_provider().add_span_processor(BatchSpanProcessor(ConsoleSpanExporter()))
tracer = trace.get_tracer(__name__)
@app.route('/test')
def test():
headers = dict(request.headers)
// 從headers中解析trace context
carrier ={'traceparent': headers['Traceparent'], 'tracestate': headers['Tracestate']}
ctx = TraceContextTextMapPropagator().extract(carrier=carrier)
with tracer.start_span("test", context=ctx):
// do something
return "success"
使用SkyWalking接入
完整接入方式請參見通過SkyWalking上報Python應用數據。
按照文檔接入,然后從HTTP請求頭中解析Span上下文,實現與RUM Trace串聯,代碼示例如下:
from skywalking import config, agent
from skywalking.trace.context import SpanContext, get_context
from skywalking.trace.carrier import CarrierItem
# 配置 SkyWalking,根據需要調整相關參數
config.init(agent_collector_backend_services='<endpoint>',
agent_authentication='<auth-token>')
agent.start()
# 示例 HTTP 請求處理函數,需要傳入 HTTP 請求的 headers
def handle_request(headers):
# 從請求頭 headers 中提取追蹤信息
carrier_items = []
for item in SpanContext.make_carrier():
carrier_header = headers.get(item.key.lower())
if carrier_header:
carrier_items.append(CarrierItem(item.key, carrier_header))
carrier = SpanContext.make_carrier(carrier_items)
# 從 Carrier 中提取追蹤上下文
context = get_context().extract(carrier)
# 創建一個新 Span 來處理請求
with get_context().new_entry_span(op='operation_name') as span:
# 在這里處理請求,并在結束時自動提交 Span
...
# 模擬接收到的 HTTP 請求 header 包含 sw8
incoming_headers = {
'sw8': '1-My40LjU=-MTY1MTcwNDI5OTk5OA==-xxxx-xx-x-x==', # 示例值,實際根據請求填寫
# 其他 header...
}
# 調用函數處理請求
handle_request(incoming_headers)
查看端到端完整Trace數據
完成前后端Trace打通后,您可以在ARMS用戶體驗控制臺查看前端請求對應的調用鏈。
單擊查看調用鏈,可以看到請求的完整調用鏈路,以及應用拓撲。此時,可以結合RUM側的請求明細數據,與后端Trace數據,分析錯慢請求問題。
最上面的Span即代表RUM入口Span,根據端側接入類型,分為以下幾種:
Web & H5場景:應用名:rum-browser,Span名稱前綴:
"browser.request:"
。小程序場景:應用名:rum-miniapp,Span名稱前綴:
"miniapp.request: "
。移動端Android場景:應用名:rum-android,Span名稱前綴:
"android.request: "
。移動端iOS場景:應用名:rum-ios,Span名稱前綴:
"ios.request: "
。
同時,也可以通過拓撲圖,直觀地看到整個請求的上下游服務拓撲。