全部產品
Search
文件中心

Application Real-Time Monitoring Service:通過OpenTelemetry Java SDK實現跨進程上下文傳遞

更新時間:Dec 21, 2024

接入ARMS應用監控以後,ARMS探針對常見的Java架構進行了自動埋點,因此不需要修改任何代碼,就可以實現調用鏈資訊的採集。但如果您需要跨進程傳遞上下文,可以引入OpenTelemetry Java SDK實現。

ARMS探針支援的組件和架構,請參見ARMS應用監控支援的Java組件和架構

使用情境

使用私人協議跨進程網路通訊時,通常用戶端和服務端無法在鏈路中串聯,這種情境需要使用者自行在用戶端擷取Trace上下文(traceId、spanId、sampleFlag、baggage等資訊)並自行傳遞到服務端後在服務端還原。

前提條件

引入依賴

請先參考如下Maven代碼引入OpenTelemetry Java SDK。更多資訊,請參見OpenTelemetry官方文檔

<dependencies>
    <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-sdk</artifactId>
    </dependency>
</dependencies>

<dependencyManagement>
  <dependencies>
    <dependency>
      <groupId>io.opentelemetry</groupId>
      <artifactId>opentelemetry-bom</artifactId>
      <version>1.23.0</version>
      <type>pom</type>
      <scope>import</scope>
    </dependency>
  </dependencies>
</dependencyManagement>

跨進程傳遞上下文

下方代碼中,CustomRpcCallMessage代表了使用者私人協議中跨進程通訊的資料承載實體。主要利用其中的headerMap傳遞上下文資訊,如果實際的跨進程調用資料承載實體沒有該欄位,則需要手動修改代碼支援該欄位。

class CustomRpcCallMessage {

    private Map<String, String> headerMap;
    //省略其他業務欄位

    public String getHeader(String key) {
        return headerMap.get(key);
    }

    public void setHeader(String key, String value) {
        this.headerMap.put(key, value);
    }

    public Map<String, String> getHeaderMap() {
        return headerMap;
    }
}

public class CrossProcessPropagateDemo {
    public static void clientSide(String[] args) {
        CustomRpcCallMessage rpcCall = new CustomRpcCallMessage();
        TextMapSetter<CustomRpcCallMessage> setter = new TextMapSetter<CustomRpcCallMessage>() {
            @Override
            public void set(CustomRpcCallMessage carrier, String key, String value) {
                carrier.setHeader(key, value);
            }
        };
        W3CTraceContextPropagator.getInstance().inject(Context.current(), rpcCall, setter);
        W3CBaggagePropagator.getInstance().inject(Context.current(), rpcCall, setter);
    }

    private static void serverSide() {
        //服務端擷取請求
        CustomRpcCallMessage rpcCall ;
        TextMapGetter<CustomRpcCallMessage> getter = new TextMapGetter<CustomRpcCallMessage>() {
            @Override
            public Iterable<String> keys(CustomRpcCallMessage carrier) {
                return carrier.getHeaderMap().keySet();
            }

            @Override
            public String get(CustomRpcCallMessage carrier, String key) {
                return carrier.getHeader(key);
            }
        };
        Context context = W3CTraceContextPropagator.getInstance().extract(Context.current(), rpcCall, getter);
        context = W3CBaggagePropagator.getInstance().extract(context, rpcCall, getter);
        try (Scope scope = context.makeCurrent()) {
            //省略 服務端處理邏輯 
        }
    }
}

在實際的業務情境中,您只需要改造上面程式碼片段中的setter變數和getter變數的實作類別,使得其對應的Set、Get方法可以保證能實現對應的語義,其餘部分代碼為模板代碼可以直接使用。

相關文檔

您可以在應用的業務日誌中關聯調用鏈的TraceId資訊,從而在應用出現問題時,能夠通過調用鏈的TraceId快速關聯到業務日誌,及時定位、分析解決問題。更多資訊,請參見Java應用業務日誌關聯調用鏈TraceId