全部產品
Search
文件中心

Application Real-Time Monitoring Service:使用OpenTelemetry過濾指定的Span

更新時間:Jul 06, 2024

本文介紹對於Java和Node.js應用如何使用OpenTelemetry過濾指定的Span。

Java

OpenTelemetry Samplers可用來過濾Span。如果不希望修改業務代碼,或者已經使用了OpenTelemetry Java Agent自動上報應用資料,那麼可以參考方法一對OpenTelemetry Java Agent的功能進行擴充,編寫自訂的OpenTelemetry Sampler,通過在Sampler中定義過濾規則,實現無侵入的Span過濾。如果您已經使用了OpenTelemetry Java SDK手動上報應用資料,可以參考方法二在業務代碼中編寫自訂Sampler。

方法一:使用OpenTelemetry Java Agent Extension(自動埋點 / 無侵入式)

前提條件

已經使用OpenTelemetry Java Agent為應用程式自動埋點。具體操作,請參見通過OpenTelemetry上報Java應用資料

  1. 建立專案。

    建立一個空白的Maven專案,用於建立和構建Agent Extension,對Agent的功能進行擴充。

  2. 在pom.xml中添加依賴。

    重要

    為保證依賴互相相容,請將各項opentelemetry依賴設定為同一版本,且與您使用的OpenTelemetry Java Agent版本保持一致。

     <dependency>
     <groupId>com.google.auto.service</groupId>
     <artifactId>auto-service</artifactId>
     <version>1.1.1</version>
     </dependency>
     
     <dependency>
     <groupId>io.opentelemetry.javaagent</groupId>
     <artifactId>opentelemetry-javaagent</artifactId>
     <version>1.28.0</version>
     <!--這裡要設定為compile的-->
     <scope>compile</scope>
     </dependency>
     
     <dependency>
     <groupId>io.opentelemetry</groupId>
     <artifactId>opentelemetry-sdk-trace</artifactId>
     <version>1.28.0</version>
     </dependency>
     
     <dependency>
     <groupId>io.opentelemetry</groupId>
     <artifactId>opentelemetry-sdk-extension-autoconfigure</artifactId>
     <version>1.28.0</version>
     </dependency>
     
     <dependency>
     <groupId>io.opentelemetry</groupId>
     <artifactId>opentelemetry-semconv</artifactId>
     <version>1.28.0-alpha</version>
     </dependency>

  3. 建立SpanFilterSampler類(類名可自訂)。

    需要實現io.opentelemetry.sdk.trace.samplers.Sampler介面,並實現shouldSample方法和getDescription方法。

    • shouldSample方法

      可以在方法中自訂過濾條件。對於要過濾的Span,返回SamplingResult.create(SamplingDecision.DROP),需要保留並繼續上報的Span則返回 SamplingResult.create(SamplingDecision.RECORD_AND_SAMPLE)

    • getDescription方法

      返回自訂Sampler的名稱。

    例如,下面範例程式碼中,SpanFilterSampler會過濾名稱為spanName1spanName2的Span,以及attributes.http.target為/api/checkHealth/health/checks的所有Span。

     package org.example;
     
     import io.opentelemetry.api.common.Attributes;
     import io.opentelemetry.api.trace.SpanKind;
     import io.opentelemetry.context.Context;
     import io.opentelemetry.sdk.trace.data.LinkData;
     import io.opentelemetry.sdk.trace.samplers.Sampler;
     import io.opentelemetry.sdk.trace.samplers.SamplingDecision;
     import io.opentelemetry.sdk.trace.samplers.SamplingResult;
     import io.opentelemetry.semconv.trace.attributes.SemanticAttributes;
     
     import java.util.*;
     
     public class SpanFilterSampler implements Sampler {
     /*
     * 過濾Span名稱在EXCLUDED_SPAN_NAMES中的所有Span
     */
     private static List<String> EXCLUDED_SPAN_NAMES = Collections.unmodifiableList(
     Arrays.asList("spanName1", "spanName2")
     );
     
     /*
     * 過濾attributes.http.target在EXCLUDED_HTTP_REQUEST_TARGETS中的所有Span
     */
     private static List<String> EXCLUDED_HTTP_REQUEST_TARGETS = Collections.unmodifiableList(
     Arrays.asList("/api/checkHealth", "/health/checks")
     );
     
     @Override
     public SamplingResult shouldSample(Context parentContext, String traceId, String name, SpanKind spanKind, Attributes attributes, List<LinkData> parentLinks) {
     String httpTarget = attributes.get(SemanticAttributes.HTTP_TARGET) != null ? attributes.get(SemanticAttributes.HTTP_TARGET) : "";
     
     if (EXCLUDED_SPAN_NAMES.contains(name) || EXCLUDED_HTTP_REQUEST_TARGETS.contains(httpTarget)) { // 根據條件進行過濾
     return SamplingResult.create(SamplingDecision.DROP);
     } else {
     return SamplingResult.create(SamplingDecision.RECORD_AND_SAMPLE);
     }
     }
     
     @Override
     public String getDescription() {
     return "SpanFilterSampler"; // SpanFilterSampler可以替換為自訂的名稱
     }
     }

  4. 建立SpanFilterSamplerProvider類(類名可自訂)。

    需要實現io.opentelemetry.sdk.autoconfigure.spi.traces.ConfigurableSamplerProvider介面,實現createSampler方法和getName方法。

    • createSampler方法

      建立並返回您自訂的Sampler執行個體。

    • getName方法

      擷取自訂的Sampler名稱,OpenTelemetry Java Agent通過該名稱找到這個Sampler。

     package org.example;
     
     import com.google.auto.service.AutoService;
     import io.opentelemetry.sdk.autoconfigure.spi.ConfigProperties;
     import io.opentelemetry.sdk.autoconfigure.spi.traces.ConfigurableSamplerProvider;
     import io.opentelemetry.sdk.trace.samplers.Sampler;
     
     @AutoService(ConfigurableSamplerProvider.class)
     public class SpanFilterSamplerProvider implements ConfigurableSamplerProvider {
     @Override
     public Sampler createSampler(ConfigProperties configProperties) {
     return new SpanFilterSampler();
     }
     
     @Override
     public String getName() {
     return "SpanFilterSampler"; // SpanFilterSampler可以替換為自訂的名稱
     }
     }

  5. 構建.

    將程式打包成JAR包,構建後儲存在target目錄下。

    mvn clean package

  6. 啟動應用時載入OpenTelemetry Java Agent擴充。

    • 方法一:在原有VM參數上添加otel.traces.sampler參數

       -Dotel.traces.sampler=<your-sampler-name> // 將<your-sampler-name>替換為您自訂的Sampler名稱,也就是getName方法的傳回值

      展開查看完整啟動命令樣本

       java -javaagent:path/to/opentelemetry-javaagent.jar \
       -Dotel.javaagent.extensions=path/to/opentelemetry-java-agent-extension.jar \
       -Dotel.traces.sampler=<your-sampler-name> \ 
       -Dotel.exporter.otlp.headers=Authentication=<token> \
       -Dotel.exporter.otlp.endpoint=<endpoint> \
       -Dotel.metrics.exporter=none 
       -jar yourapp.jar

    • 方法二:設定OTEL_TRACES_SAMPLER環境變數。

       export OTEL_TRACES_SAMPLER="<your-sampler-name>" // 將<your-sampler-name>替換為您自訂的Sampler名稱,也就是getName方法的傳回值

      展開查看完整啟動命令樣本

       export OTEL_JAVAAGENT_EXTENSIONS="path/to/opentelemetry-java-agent-extension.jar"
       export OTEL_TRACES_SAMPLER="<your-sampler-name>"
       export OTEL_EXPORTER_OTLP_HEADERS="Authentication=<token>"
       export OTEL_EXPORTER_OTLP_ENDPOINT="<endpoint>"
       export OTEL_METRICS_EXPORTER="none"
       
       java -javaagent:path/to/opentelemetry-javaagent.jar \
       -jar yourapp.jar

方法二:使用OpenTelemetry Java SDK(手動埋點)

前提條件

已經使用OpenTelemetry Java SDK為應用程式手動埋點。具體操作,請參見通過OpenTelemetry上報Java應用資料

  1. 在您的業務代碼中建立自訂Sampler類。

    需要實現io.opentelemetry.sdk.trace.samplers.Sampler介面,並實現shouldSample方法和getDescription方法。

    • shouldSample方法

      可以在方法中自訂過濾條件。對於要過濾的Span,返回SamplingResult.create(SamplingDecision.DROP),需要保留並繼續上報的Span則返回SamplingResult.create(SamplingDecision.RECORD_AND_SAMPLE)

    • getDescription方法

      返回自訂Sampler的名稱。

    例如,下面範例程式碼中,SpanFilterSampler會過濾名稱為spanName1spanName2的Span,以及attributes.http.target為/api/checkHealth/health/check的所有Span。

     package org.example;
     
     import io.opentelemetry.api.common.Attributes;
     import io.opentelemetry.api.trace.SpanKind;
     import io.opentelemetry.context.Context;
     import io.opentelemetry.sdk.trace.data.LinkData;
     import io.opentelemetry.sdk.trace.samplers.Sampler;
     import io.opentelemetry.sdk.trace.samplers.SamplingDecision;
     import io.opentelemetry.sdk.trace.samplers.SamplingResult;
     import io.opentelemetry.semconv.trace.attributes.SemanticAttributes;
     
     import java.util.*;
     
     public class SpanFilterSampler implements Sampler {
     /*
     * 過濾Span名稱在EXCLUDED_SPAN_NAMES中的所有Span
     */
     private static List<String> EXCLUDED_SPAN_NAMES = Collections.unmodifiableList(
     Arrays.asList("spanName1", "spanName2")
     );
     
     /*
     * 過濾attributes.http.target在EXCLUDED_HTTP_REQUEST_TARGETS中的所有Span
     */
     private static List<String> EXCLUDED_HTTP_REQUEST_TARGETS = Collections.unmodifiableList(
     Arrays.asList("/api/checkHealth", "/health/checks")
     );
     
     @Override
     public SamplingResult shouldSample(Context parentContext, String traceId, String name, SpanKind spanKind, Attributes attributes, List<LinkData> parentLinks) {
     String httpTarget = attributes.get(SemanticAttributes.HTTP_TARGET) != null ? attributes.get(SemanticAttributes.HTTP_TARGET) : "";
     
     if (EXCLUDED_SPAN_NAMES.contains(name) || EXCLUDED_HTTP_REQUEST_TARGETS.contains(httpTarget)) { // 根據條件進行過濾
     return SamplingResult.create(SamplingDecision.DROP);
     } else {
     return SamplingResult.create(SamplingDecision.RECORD_AND_SAMPLE);
     }
     }
     
     @Override
     public String getDescription() {
     return "SpanFilterSampler"; // SpanFilterSampler可以替換為自訂的名稱
     }
     }

  2. 在建立SdkTracerProvider執行個體時設定自訂Sampler。

    在建立SdkTracerProvider執行個體時,調用setSampler(new SpanFilterSampler()),即可完成配置。

     ...
     
     
     SdkTracerProvider sdkTracerProvider = SdkTracerProvider.builder()
     .setSampler(new MySampler()) // 添加這一行
     .addSpanProcessor(BatchSpanProcessor.builder(OtlpGrpcSpanExporter.builder()
     .setEndpoint("<endpoint>")
     .addHeader("Authentication", "<token>")
     .build()).build())
     .setResource(resource)
     .build();
     
     
     ...

  3. 啟動應用。

Node.js

樣本Demo:opentelemetry-nodejs-demo

前提條件

已經使用OpenTelemetry JavaScript API為應用程式埋點。具體操作,請參見通過OpenTelemetry上報Node.js應用資料

方法一:在Span建立階段過濾

  1. 建立HttpInstrumentation時設定ignoreIncomingRequestHook。

    建立HttpInstrumentation時可以設定HttpInstrumentationConfig參數,參數包括ignoreIncomingRequestHook,該參數允許使用者傳入一個自訂方法,在請求被處理前判斷是否需要建立埋點。需要注意,此方法的作用只是不建立Span,而不會影響該請求的執行。

    例如,下面代碼中展示了如何過濾request.url=/api/checkHealth的請求:

     ...
     
     // 要被替換的內容
     // registerInstrumentations({
     // tracerProvider: provider,
     // instrumentations: [new HttpInstrumentation(), ExpressInstrumentation],
     // });
     
     const httpInstrumentation = new HttpInstrumentation({
     
     // 添加一個自訂的ignoreIncomingRequestHook
     ignoreIncomingRequestHook: (request) => {
     //忽略request.url為/api/checkHealth的請求
     if (request.url === '/api/checkHealth') {
     return true;
     }
     return false;
     },
     
     });
     
     registerInstrumentations({
     tracerProvider: provider,
     instrumentations: [httpInstrumentation, ExpressInstrumentation],
     });
     
     ...

  2. 啟動應用。

方法二:在Span上報階段過濾

  1. 建立自訂Sampler類。

    建立一個實現了Sampler介面的自訂Sampler類。該介面定義了是否採樣的規則。例如:

     const opentelemetry = require('@opentelemetry/api');
     
     class SpanFilterSampler {
     shouldSample(spanContext, parentContext) {
     // 在此處實現您的自訂採樣邏輯
     }
     }

  2. 建立NodeTracerProvider執行個體時設定自訂Sampler。

     ...
     const provider = new NodeTracerProvider({
     sampler: new SpanFilterSampler(), // 添加這一行代碼,設定自訂Sampler
     resource: new Resource({
     [SemanticResourceAttributes.HOST_NAME]: require("os").hostname(), // your host name
     [SemanticResourceAttributes.SERVICE_NAME]: "<your-service-name>",
     }),
     });
     ...