OpenTelemetry を使用してアプリケーションをインストルメントし、トレースデータを Managed Service for OpenTelemetry にレポートすると、Managed Service for OpenTelemetry はアプリケーションの監視を開始します。 アプリケーショントポロジー、トレース、異常トランザクション、低速トランザクション、SQL分析など、アプリケーションのモニタリングデータを表示できます。 このトピックでは、エージェントまたは OpenTelemetry SDK for Java を使用して Java アプリケーションを自動または手動でインストルメントし、Java アプリケーションのトレースデータをレポートする方法について説明します。
背景情報
OpenTelemetry Java エージェント が自動的にインストルメントできる Java フレームワークを次の表に示します。 詳細については、「サポートされているライブラリ、フレームワーク、アプリケーションサーバー、および JVM」をご参照ください。
サンプルコード
java-opentelemetry-demo からサンプルコードをダウンロードします。
方法 1: OpenTelemetry Java エージェントを使用してアプリケーションを自動的にインストルメントする
OpenTelemetry Java エージェントを使用すると、非侵入型で OpenTelemetry を Managed Service for OpenTelemetry に接続できます。 OpenTelemetry Java エージェントを使用すると、数百の Java フレームワークのトレースデータを自動的にアップロードできます。 サポートされている Java フレームワークの詳細については、「サポートされているライブラリ、フレームワーク、アプリケーションサーバー、および JVM」をご参照ください。
OpenTelemetry Java エージェントをダウンロードします。
トレースデータをレポートするために、Java 起動構成で JVM パラメーターを変更します。
HTTP 経由: トレースエンドポイントとメトリックエンドポイントを設定します。
gRPC 経由: トレースエンドポイントと認証トークンを設定します。
HTTP
java -javaagent:/path/to/opentelemetry-javaagent.jar\ // ファイルのダウンロードパスを指定します。 -Dotel.resource.attributes=service.name=,service.version=,deployment.environment= \ -Dotel.exporter.otlp.protocol=http/protobuf \ -Dotel.exporter.otlp.traces.endpoint=<traces.endpoint> \ // 「前提条件」セクションで取得したトレースエンドポイントを指定します。 -Dotel.exporter.otlp.metrics.endpoint=<metrics.endpoint> \ // 「前提条件」セクションで取得したメトリックエンドポイントを指定します。 -Dotel.logs.exporter=none \ -jar /path/to/your/app.jar // JAR パッケージを保存するパスを指定します。例:
java -javaagent:/path/to/opentelemetry-javaagent.jar \ -Dotel.resource.attributes=service.name=,service.version=,deployment.environment= \ -Dotel.exporter.otlp.protocol=http/protobuf \ -Dotel.exporter.otlp.traces.endpoint=http://tracing-analysis-dc-hz-internal.aliyuncs.com/adapt_ggxw4l****@7323a5caae3****_ggxw4l****@53df7ad2afe****/api/otlp/traces \ -Dotel.exporter.otlp.metrics.endpoint=http://tracing-analysis-dc-hz-internal.aliyuncs.com/adapt_ggxw4l****@7323a5caae3****_ggxw4l****@53df7ad2afe****/api/otlp/metrics \ -Dotel.logs.exporter=none \ -jar /path/to/your/app.jargRPC
java -javaagent:/path/to/opentelemetry-javaagent.jar \ // ファイルのダウンロードパスを指定します。 -Dotel.resource.attributes=service.name=,service.version=,deployment.environment= \ -Dotel.exporter.otlp.protocol=grpc \ -Dotel.exporter.otlp.headers=Authentication=<token> \ // 「前提条件」セクションで取得した認証トークンを指定します。 -Dotel.exporter.otlp.endpoint=<endpoint> \ // 「前提条件」セクションで取得したエンドポイントを指定します。 -Dotel.logs.exporter=none \ -jar /path/to/your/app.jar // JAR パッケージを保存するパスを指定します。例:
java -javaagent:/path/to/opentelemetry-javaagent.jar \ -Dotel.resource.attributes=service.name=,service.version=,deployment.environment= \ -Dotel.exporter.otlp.protocol=grpc \ -Dotel.exporter.otlp.headers=Authentication=ggxw4l****@7323a5caae3****_ggxw4l****@53df7ad2afe**** \ -Dotel.exporter.otlp.endpoint=http://tracing-analysis-dc-hz-internal.aliyuncs.com:8090 \ -Dotel.logs.exporter=none \ -jar /path/to/your/app.jar説明OpenTelemetry Collector を使用してトレースデータを転送する場合は、
-Dotel.exporter.otlp.headers=Authentication=<token>を削除し、<endpoint>をオンプレミス マシンにデプロイされている サービス の URL に置き換えます。
方法 2: OpenTelemetry SDK for Java を使用してアプリケーションを手動でインストルメント化する
OpenTelemetry Java エージェントは、OpenTelemetry SDK for Java に基づいて実装されています。SDK はさまざまなカスタム機能を提供します。 OpenTelemetry Java エージェントを使用して追加されたインストルメンテーションがビジネス要件を満たさなくなった場合、またはビジネス要件に基づいてカスタムインストルメンテーションを追加する場合は、次の手順を実行します。
Maven プロジェクトの pom.xml ファイルに次の依存関係を追加します。
<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-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.0-alpha</version> </dependency> </dependencies> <dependencyManagement> <dependencies> <dependency> <groupId>io.opentelemetry</groupId> <artifactId>opentelemetry-bom</artifactId> <version>1.30.0</version> <type>pom</type> <scope>import</scope> </dependency> </dependencies> </dependencyManagement>OpenTelemetry トレーサーを取得します。
HTTP
import io.opentelemetry.api.OpenTelemetry; import io.opentelemetry.api.common.Attributes; import io.opentelemetry.api.trace.Tracer; import io.opentelemetry.api.trace.propagation.W3CTraceContextPropagator; import io.opentelemetry.context.propagation.ContextPropagators; import io.opentelemetry.exporter.otlp.http.trace.OtlpHttpSpanExporter; import io.opentelemetry.sdk.OpenTelemetrySdk; import io.opentelemetry.sdk.resources.Resource; import io.opentelemetry.sdk.trace.SdkTracerProvider; import io.opentelemetry.sdk.trace.export.BatchSpanProcessor; import io.opentelemetry.semconv.resource.attributes.ResourceAttributes; public class OpenTelemetrySupport { static { // OpenTelemetry トレーサーを取得します。 Resource resource = Resource.getDefault() .merge(Resource.create(Attributes.of( ResourceAttributes.SERVICE_NAME, "", // アプリケーション名。 ResourceAttributes.SERVICE_VERSION, "", // バージョン番号。 ResourceAttributes.DEPLOYMENT_ENVIRONMENT, "", // 環境。 ResourceAttributes.HOST_NAME, "${host-name}" // ${host-name} をサーバー名に変更します。 ))); SdkTracerProvider sdkTracerProvider = SdkTracerProvider.builder() .addSpanProcessor(BatchSpanProcessor.builder(OtlpHttpSpanExporter.builder() .setEndpoint("<endpoint>") // <endpoint> を「前提条件」セクションで取得したエンドポイントに変更します。 .build()).build()) .setResource(resource) .build(); OpenTelemetry openTelemetry = OpenTelemetrySdk.builder() .setTracerProvider(sdkTracerProvider) .setPropagators(ContextPropagators.create(W3CTraceContextPropagator.getInstance())) .buildAndRegisterGlobal(); tracer = openTelemetry.getTracer("OpenTelemetry Tracer", "1.0.0"); } private static Tracer tracer; public static Tracer getTracer() { return tracer; } }gRPC
import io.opentelemetry.api.OpenTelemetry; import io.opentelemetry.api.common.Attributes; import io.opentelemetry.api.trace.Tracer; import io.opentelemetry.api.trace.propagation.W3CTraceContextPropagator; import io.opentelemetry.context.propagation.ContextPropagators; import io.opentelemetry.exporter.otlp.trace.OtlpGrpcSpanExporter; import io.opentelemetry.sdk.OpenTelemetrySdk; import io.opentelemetry.sdk.resources.Resource; import io.opentelemetry.sdk.trace.SdkTracerProvider; import io.opentelemetry.sdk.trace.export.BatchSpanProcessor; import io.opentelemetry.semconv.resource.attributes.ResourceAttributes; public class OpenTelemetrySupport { static { // OpenTelemetry トレーサーを取得します。 Resource resource = Resource.getDefault() .merge(Resource.create(Attributes.of( ResourceAttributes.SERVICE_NAME, "", // アプリケーション名。 ResourceAttributes.SERVICE_VERSION, "", // バージョン番号。 ResourceAttributes.DEPLOYMENT_ENVIRONMENT, "", // 環境。 ResourceAttributes.HOST_NAME, "${host-name}" // ${host-name} をサーバー名に変更します。 ))); SdkTracerProvider sdkTracerProvider = SdkTracerProvider.builder() .addSpanProcessor(BatchSpanProcessor.builder(OtlpGrpcSpanExporter.builder() .setEndpoint("<endpoint>") // <endpoint> を「前提条件」セクションで取得したエンドポイントに変更します。 .addHeader("Authentication", "<token>") // <token> を「前提条件」セクションで取得した認証トークンに変更します。 .build()).build()) .setResource(resource) .build(); OpenTelemetry openTelemetry = OpenTelemetrySdk.builder() .setTracerProvider(sdkTracerProvider) .setPropagators(ContextPropagators.create(W3CTraceContextPropagator.getInstance())) .buildAndRegisterGlobal(); tracer = openTelemetry.getTracer("OpenTelemetry Tracer", "1.0.0"); } private static Tracer tracer; public static Tracer getTracer() { return tracer; } }スパンを作成します。
import io.opentelemetry.api.trace.Span; import io.opentelemetry.api.trace.StatusCode; import io.opentelemetry.context.Scope; public class Main { public static void parentMethod() { Span span = OpenTelemetrySupport.getTracer().spanBuilder("parent span").startSpan(); try (Scope scope = span.makeCurrent()) { span.setAttribute("good", "job"); childMethod(); } catch (Throwable t) { span.setStatus(StatusCode.ERROR, "handle parent span error"); // 親スパンエラーを処理します } finally { span.end(); } } public static void childMethod() { Span span = OpenTelemetrySupport.getTracer().spanBuilder("child span").startSpan(); try (Scope scope = span.makeCurrent()) { span.setAttribute("hello", "world"); } catch (Throwable t) { span.setStatus(StatusCode.ERROR, "handle child span error"); // 子スパンエラーを処理します } finally { span.end(); } } public static void main(String[] args) { parentMethod(); } }アプリケーションを起動します。
の [アプリケーション] ページで、アプリケーション名をクリックします。 表示されたページで、トレースデータを表示します。Managed Service for OpenTelemetry コンソール の [アプリケーション] ページで、アプリケーション名をクリックします。 表示されたページで、トレースデータを表示します。
方法 3: OpenTelemetry Java エージェントと OpenTelemetry SDK for Java を使用してアプリケーションをインストゥルメントする
OpenTelemetry Java エージェントを使用して自動インストゥルメントを実行し、OpenTelemetry SDK for Java を使用してビジネス要件に基づいてカスタムインストゥルメントを追加できます。
OpenTelemetry Java エージェント をダウンロードします。
方法 2 の依存関係に加えて、Maven プロジェクトの pom.xml ファイルに次の依存関係を追加します。
<dependency> <groupId>io.opentelemetry</groupId> <artifactId>opentelemetry-extension-annotations</artifactId> </dependency> <dependency> <groupId>io.opentelemetry</groupId> <artifactId>opentelemetry-sdk-extension-autoconfigure</artifactId> <version>1.23.0-alpha</version> </dependency>説明上記のコードでは、
opentelemetry-sdk-extension-autoconfigure依存関係を使用して、OpenTelemetry SDK for Java を自動的に構成し、OpenTelemetry Java エージェントの設定を SDK に転送します。OpenTelemetry Tracer を取得します。
OpenTelemetry Java エージェントと OpenTelemetry SDK for Java を使用してアプリケーションをインストゥルメントする場合、方法 2 で使用されている OpenTelemetrySupport クラスを使用して OpenTelemetry トレーサーを取得する必要はありません。
OpenTelemetry openTelemetry = GlobalOpenTelemetry.get(); Tracer tracer = openTelemetry.getTracer("instrumentation-library-name", "1.0.0");コントローラーコードとサービスコードを変更します。
次のサンプルコントローラーコードでは、方法 1 と方法 2 を使用することをお勧めします。
package com.alibaba.arms.brightroar.console.controller; import com.alibaba.arms.brightroar.console.service.UserService; import io.opentelemetry.api.GlobalOpenTelemetry; import io.opentelemetry.api.OpenTelemetry; import io.opentelemetry.api.trace.Span; import io.opentelemetry.api.trace.StatusCode; import io.opentelemetry.api.trace.Tracer; import io.opentelemetry.context.Context; import io.opentelemetry.context.Scope; import io.opentelemetry.extension.annotations.SpanAttribute; import io.opentelemetry.extension.annotations.WithSpan; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; /** * 参考文献: * 1. https://opentelemetry.io/docs/java/manual_instrumentation/ */ @RestController @RequestMapping("/user") public class UserController { @Autowired private UserService userService; private ExecutorService es = Executors.newFixedThreadPool(5); // 方法 1: アプリケーションで自動インストゥルメントを実行します。API 操作を呼び出して情報を追加します。 @RequestMapping("/async") public String async() { System.out.println("UserController.async -- " + Thread.currentThread().getId()); Span span = Span.current(); span.setAttribute("user.id", "123456"); userService.async(); child("vip"); return "async"; } // 方法 2: タグに基づいてアプリケーションをインストゥルメントします。 @WithSpan private void child(@SpanAttribute("user.type") String userType) { System.out.println(userType); biz(); } // 方法 3: トレーサーを使用してアプリケーションを手動でインストゥルメントします。 private void biz() { Tracer tracer = GlobalOpenTelemetry.get().getTracer("tracer"); Span span = tracer.spanBuilder("biz (manual)") .setParent(Context.current().with(Span.current())) // オプション。システムは設定を自動的に構成します。 .startSpan(); try (Scope scope = span.makeCurrent()) { span.setAttribute("biz-id", "111"); es.submit(new Runnable() { @Override public void run() { Span asyncSpan = tracer.spanBuilder("async") .setParent(Context.current().with(span)) .startSpan(); try { Thread.sleep(1000L); // 一部の非同期ジョブ } catch (Throwable e) { } asyncSpan.end(); } }); Thread.sleep(1000); // フェイクビジネスロジック System.out.println("biz done"); OpenTelemetry openTelemetry = GlobalOpenTelemetry.get(); openTelemetry.getPropagators(); } catch (Throwable t) { span.setStatus(StatusCode.ERROR, "handle biz error"); // ビジネスエラーを処理する } finally { span.end(); } } }サンプルサービスコード:
package com.alibaba.arms.brightroar.console.service; import org.springframework.scheduling.annotation.Async; import org.springframework.stereotype.Service; @Service public class UserService { @Async public void async() { System.out.println("UserService.async -- " + Thread.currentThread().getId()); System.out.println("my name is async"); // 私の名前は非同期です System.out.println("UserService.async -- "); } }
トレースデータをレポートするために、Java 起動構成で JVM パラメーターを変更します。
-javaagent:/path/to/opentelemetry-javaagent.jar // パスを OpenTelemetry Java エージェントのダウンロードに使用する URL に置き換えます。 -Dotel.resource.attributes=service.name=<appName> // <appName> を実際のアプリケーション名に置き換えます。 -Dotel.exporter.otlp.headers=Authentication=<token> -Dotel.exporter.otlp.endpoint=<endpoint>トレースデータを直接レポートする場合は、
<token>を前提条件で取得したトークンに置き換え、<endpoint>をトレースデータをレポートするリージョンのエンドポイントに置き換えます。例:
-javaagent:/Users/carpela/Downloads/opentelemetry-javaagent.jar -Dotel.resource.attributes=service.name=ot-java-agent-sample -Dotel.exporter.otlp.headers=Authentication=b590xxxxuqs@3a75d95xxxxx9b_b59xxxxguqs@53dxxxx2afe8301 -Dotel.exporter.otlp.endpoint=http://tracing-analysis-dc-bj:8090OpenTelemetry Collector を使用してトレースデータを転送する場合は、
-Dotel.exporter.otlp.headers=Authentication=<token>を削除し、<endpoint>をオンプレミス マシンにデプロイされているサービスの URL に置き換えます。
アプリケーションを起動します。
[アプリケーション] ページ、または Managed Service for OpenTelemetry コンソール の [アプリケーション] ページで、アプリケーションの名前をクリックします。表示されるページで、トレースデータを表示します。