From 705cbe9379cb323f1b46575ad2723f4c6e7b0f4e Mon Sep 17 00:00:00 2001 From: svrnm Date: Wed, 2 Aug 2023 20:51:36 +0200 Subject: [PATCH 01/17] Rework java manual instrumentation Signed-off-by: svrnm --- .../en/docs/instrumentation/java/exporters.md | 131 +++++++ .../en/docs/instrumentation/java/manual.md | 358 ++++++++++++++---- .../en/docs/instrumentation/java/resources.md | 53 +++ 3 files changed, 466 insertions(+), 76 deletions(-) create mode 100644 content/en/docs/instrumentation/java/exporters.md create mode 100644 content/en/docs/instrumentation/java/resources.md diff --git a/content/en/docs/instrumentation/java/exporters.md b/content/en/docs/instrumentation/java/exporters.md new file mode 100644 index 000000000000..e00833baab1f --- /dev/null +++ b/content/en/docs/instrumentation/java/exporters.md @@ -0,0 +1,131 @@ +--- +title: Exporters +weight: 50 +--- + +In order to visualize and analyze your traces, you will need to export them to a +backend such as [Jaeger](https://www.jaegertracing.io/) or +[Zipkin](https://zipkin.io/). OpenTelemetry Java provides exporters for some +common open source backends. + +If you use the Javaagent for +[automatic instrumentation](/docs/instrumentation/java/automatic) you can learn +how to setup exporters following the [Agent Configuration +Guide]/docs/instrumentation/java/automatic/agent-config) + +For [manual instrumentation](/docs/instrumentation/java/manual), you will find +some introductions below on how to set up backends and the matching exporters. + +## OTLP endpoint + +To send trace data to a OTLP endpoint (like the [collector](/docs/collector) or +Jaeger) you'll want to use `opentelemetry-exporter-otlp`: + + + +{{< tabpane >}} +{{< tab Gradle >}} +dependencies { + implementation 'io.opentelemetry:opentelemetry-exporter-otlp:{{% param javaVersion %}}' +} +{{< /tab >}} +{{< tab Maven >}} + + + + io.opentelemetry + opentelemetry-exporter-otlp + + + +{{< /tab >}} +{{< /tabpane>}} + +Next, configure the exporter to point at an OTLP endpoint. For example you can +update the [example app](/docs/instrumentation/java/manual#example-app) like the +following: + + + +```java +package otel; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.Banner; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +import io.opentelemetry.api.OpenTelemetry; +import io.opentelemetry.api.common.Attributes; +import io.opentelemetry.api.trace.propagation.W3CTraceContextPropagator; +import io.opentelemetry.context.propagation.ContextPropagators; +import io.opentelemetry.exporter.otlp.metrics.OtlpGrpcMetricExporter; +import io.opentelemetry.exporter.otlp.trace.OtlpGrpcSpanExporter; +import io.opentelemetry.exporter.otlp.logs.OtlpGrpcLogRecordExporter; +import io.opentelemetry.sdk.OpenTelemetrySdk; +import io.opentelemetry.sdk.metrics.SdkMeterProvider; +import io.opentelemetry.sdk.metrics.export.PeriodicMetricReader; +import io.opentelemetry.sdk.resources.Resource; +import io.opentelemetry.sdk.trace.SdkTracerProvider; +import io.opentelemetry.sdk.trace.export.BatchSpanProcessor; +import io.opentelemetry.sdk.logs.SdkLoggerProvider; +import io.opentelemetry.sdk.logs.export.BatchLogRecordProcessor; +import io.opentelemetry.sdk.logs.export.LogRecordExporter; +import io.opentelemetry.semconv.resource.attributes.ResourceAttributes; + +@SpringBootApplication +public class DiceApplication { + public static void main(String[] args) { + + Resource resource = Resource.getDefault() + .merge(Resource.create(Attributes.of(ResourceAttributes.SERVICE_NAME, "dice-server", + ResourceAttributes.SERVICE_VERSION, "0.1.0"))); + + SdkTracerProvider sdkTracerProvider = SdkTracerProvider.builder() + .addSpanProcessor(BatchSpanProcessor.builder(OtlpGrpcSpanExporter.builder().build()).build()) + .setResource(resource) + .build(); + + SdkMeterProvider sdkMeterProvider = SdkMeterProvider.builder() + .registerMetricReader(PeriodicMetricReader.builder(OtlpGrpcMetricExporter.builder().build()).build()) + .setResource(resource) + .build(); + + SdkLoggerProvider sdkLoggerProvider = SdkLoggerProvider.builder() + .addLogRecordProcessor( + BatchLogRecordProcessor.builder(OtlpGrpcLogRecordExporter.builder().build()).build()) + .setResource(resource) + .build(); + + OpenTelemetry openTelemetry = OpenTelemetrySdk.builder() + .setTracerProvider(sdkTracerProvider) + .setMeterProvider(sdkMeterProvider) + .setLoggerProvider(sdkLoggerProvider) + .setPropagators(ContextPropagators.create(W3CTraceContextPropagator.getInstance())) + .buildAndRegisterGlobal(); + + SpringApplication app = new SpringApplication(DiceApplication.class); + app.setBannerMode(Banner.Mode.OFF); + app.run(args); + } +} +``` + +To try out the exporters quickly, you can run Jaeger with OTLP enabled in a +docker container: + +```shell +docker run -d --name jaeger \ + -e COLLECTOR_ZIPKIN_HOST_PORT=:9411 \ + -e COLLECTOR_OTLP_ENABLED=true \ + -p 6831:6831/udp \ + -p 6832:6832/udp \ + -p 5778:5778 \ + -p 16686:16686 \ + -p 4317:4317 \ + -p 4318:4318 \ + -p 14250:14250 \ + -p 14268:14268 \ + -p 14269:14269 \ + -p 9411:9411 \ + jaegertracing/all-in-one:latest +``` diff --git a/content/en/docs/instrumentation/java/manual.md b/content/en/docs/instrumentation/java/manual.md index f780dee6c231..d92a4e105e99 100644 --- a/content/en/docs/instrumentation/java/manual.md +++ b/content/en/docs/instrumentation/java/manual.md @@ -14,26 +14,43 @@ cSpell:ignore: autoconfigure classpath customizer logback loggable multivalued {{% docs/instrumentation/manual-intro %}} -## Setup +{{% alert title="Note" color="info" %}} -The first step is to get a handle to an instance of the `OpenTelemetry` -interface. +On this page you will learn how you can add traces, metrics and logs to your +code _manually_. But, you are not limited to only use one kind of +instrumentation: use +[automatic instrumentation](/docs/instrumentation/java/automatic/) to get started +and then enrich your code with manual instrumentation as needed. -If you are an application developer, you need to configure an instance of the -`OpenTelemetrySdk` as early as possible in your application. This can be done -using the `OpenTelemetrySdk.builder()` method. The returned -`OpenTelemetrySdkBuilder` instance gets the providers related to the signals, -tracing and metrics, in order to build the `OpenTelemetry` instance. +Also, for libraries your code depends on, you don't have to write +instrumentation code yourself, since they might come with OpenTelemetry built-in +_natively_ or you can make use of +[instrumentation libraries](/docs/instrumentation/java/libraries/). -You can build the providers by using the `SdkTracerProvider.builder()` and -`SdkMeterProvider.builder()` methods. It is also strongly recommended to define -a `Resource` instance as a representation of the entity producing the telemetry; -in particular the `service.name` attribute is the most important piece of -telemetry source-identifying info. +{{% /alert %}} -### Maven +## Example app preparation {#example-app} -```xml +This page uses the example app from +[Getting Started](/docs/instrumentation/java/getting-started/) to help you +learn about manual instrumentation. + +You don't have to use the example app: if you want to instrument your own app or +library, follow the instructions here to adapt the process to your own code. + +## Manual instrumentation setup + +The first step is to install the dependencies for the OpenTelemetry API. + + + +{{< tabpane >}} +{{< tab Gradle >}} +dependencies { + implementation 'io.opentelemetry:opentelemetry-api:{{% param javaVersion %}}' +} +{{< /tab >}} +{{< tab Maven >}} @@ -46,7 +63,49 @@ telemetry source-identifying info. + + + io.opentelemetry + opentelemetry-api + + + +{{< /tab >}} +{{< /tabpane>}} + + + +### Initialize the SDK + +{{% alert title="Note" color="info" %}} If you’re instrumenting a library, +**skip this step**. {{% /alert %}} + +If you instrument a Java app, install the dependencies for the OpenTelemetry SDK. + + +{{< tabpane >}} +{{< tab Gradle >}} +dependencies { + implementation 'io.opentelemetry:opentelemetry-api:{{% param javaVersion %}}' + implementation 'io.opentelemetry:opentelemetry-sdk:{{% param javaVersion %}}' + implementation 'io.opentelemetry:opentelemetry-exporter-logging:{{% param javaVersion %}}' + implementation 'io.opentelemetry:opentelemetry-semconv:{{% param javaVersion %}}-alpha' +} +{{< /tab >}} +{{< tab Maven >}} + + + + + io.opentelemetry + opentelemetry-bom + {{% param javaVersion %}} + pom + import + + + io.opentelemetry @@ -58,7 +117,7 @@ telemetry source-identifying info. io.opentelemetry - opentelemetry-exporter-otlp + opentelemetry-exporter-logging io.opentelemetry @@ -67,81 +126,138 @@ telemetry source-identifying info. -``` +{{< /tab >}} +{{< /tabpane>}} -See [releases][releases] for a full list of artifact coordinates. + -### Gradle - -```kotlin -dependencies { - implementation 'io.opentelemetry:opentelemetry-api:{{% param javaVersion %}}' - implementation 'io.opentelemetry:opentelemetry-sdk:{{% param javaVersion %}}' - implementation 'io.opentelemetry:opentelemetry-exporter-otlp:{{% param javaVersion %}}' - implementation 'io.opentelemetry:opentelemetry-semconv:{{% param javaVersion %}}-alpha' -} -``` +If you are an application developer, you need to configure an instance of the +`OpenTelemetrySdk` as early as possible in your application. This can be done +using the `OpenTelemetrySdk.builder()` method. The returned +`OpenTelemetrySdkBuilder` instance gets the providers related to the signals, +tracing and metrics, in order to build the `OpenTelemetry` instance. -See [releases][releases] for a full list of artifact coordinates. +You can build the providers by using the `SdkTracerProvider.builder()` and +`SdkMeterProvider.builder()` methods. -### Imports +In the case of the [Getting Started](/docs/instrumentation/java/getting-started) example app +the `main` method of the `DiceApplication` gets updated as follows: ```java +package otel; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.Banner; +import org.springframework.boot.autoconfigure.SpringBootApplication; + import io.opentelemetry.api.OpenTelemetry; import io.opentelemetry.api.common.Attributes; import io.opentelemetry.api.trace.propagation.W3CTraceContextPropagator; import io.opentelemetry.context.propagation.ContextPropagators; -import io.opentelemetry.exporter.otlp.metrics.OtlpGrpcMetricExporter; -import io.opentelemetry.exporter.otlp.trace.OtlpGrpcSpanExporter; -import io.opentelemetry.exporter.otlp.logs.OtlpGrpcLogRecordExporter; +import io.opentelemetry.exporter.logging.LoggingMetricExporter; +import io.opentelemetry.exporter.logging.LoggingSpanExporter; +import io.opentelemetry.exporter.logging.SystemOutLogRecordExporter; import io.opentelemetry.sdk.OpenTelemetrySdk; import io.opentelemetry.sdk.metrics.SdkMeterProvider; import io.opentelemetry.sdk.metrics.export.PeriodicMetricReader; import io.opentelemetry.sdk.resources.Resource; import io.opentelemetry.sdk.trace.SdkTracerProvider; -import io.opentelemetry.sdk.trace.export.BatchSpanProcessor; +import io.opentelemetry.sdk.trace.export.SimpleSpanProcessor; import io.opentelemetry.sdk.logs.SdkLoggerProvider; import io.opentelemetry.sdk.logs.export.BatchLogRecordProcessor; +import io.opentelemetry.sdk.logs.export.LogRecordExporter; import io.opentelemetry.semconv.resource.attributes.ResourceAttributes; + +@SpringBootApplication +public class DiceApplication { + public static void main(String[] args) { + + Resource resource = Resource.getDefault() + .merge(Resource.create(Attributes.of(ResourceAttributes.SERVICE_NAME, "dice-server", ResourceAttributes.SERVICE_VERSION, "0.1.0"))); + + SdkTracerProvider sdkTracerProvider = SdkTracerProvider.builder() + .addSpanProcessor(SimpleSpanProcessor.create(LoggingSpanExporter.create())) + .setResource(resource) + .build(); + + SdkMeterProvider sdkMeterProvider = SdkMeterProvider.builder() + .registerMetricReader(PeriodicMetricReader.builder(LoggingMetricExporter.create()).build()) + .setResource(resource) + .build(); + + SdkLoggerProvider sdkLoggerProvider = SdkLoggerProvider.builder() + .addLogRecordProcessor(BatchLogRecordProcessor.builder(SystemOutLogRecordExporter.create()).build()) + .setResource(resource) + .build(); + + OpenTelemetry openTelemetry = OpenTelemetrySdk.builder() + .setTracerProvider(sdkTracerProvider) + .setMeterProvider(sdkMeterProvider) + .setLoggerProvider(sdkLoggerProvider) + .setPropagators(ContextPropagators.create(W3CTraceContextPropagator.getInstance())) + .buildAndRegisterGlobal(); + + SpringApplication app = new SpringApplication(DiceApplication.class); + app.setBannerMode(Banner.Mode.OFF); + app.run(args); + } +} ``` -### Example +For debugging and local development purposes, the example exports +telemetry to the console. After you have finished setting up manual +instrumentation, you need to configure an appropriate exporter to +[export the app's telemetry data](/docs/instrumentation/java/exporters/) to one or +more telemetry backends. -```java -Resource resource = Resource.getDefault() - .merge(Resource.create(Attributes.of(ResourceAttributes.SERVICE_NAME, "logical-service-name"))); +The example also sets up the mandatory SDK default attribute `service.name`, +which holds the logical name of the service, and the optional (but highly +encouraged!) attribute `service.version`, which holds the version of the service +API or implementation. -SdkTracerProvider sdkTracerProvider = SdkTracerProvider.builder() - .addSpanProcessor(BatchSpanProcessor.builder(OtlpGrpcSpanExporter.builder().build()).build()) - .setResource(resource) - .build(); +Alternative methods exist for setting up resource attributes. For more +information, see [Resources](/docs/instrumentation/java/resources/). -SdkMeterProvider sdkMeterProvider = SdkMeterProvider.builder() - .registerMetricReader(PeriodicMetricReader.builder(OtlpGrpcMetricExporter.builder().build()).build()) - .setResource(resource) - .build(); +To verify your code, run the app: + +```sh +java -jar ./build/libs/java-simple.jar +``` + +This basic setup has no effect on your app yet. You need to add code for +[traces](#traces), [metrics](#metrics), and/or [logs](#logs). + +You can register instrumentation libraries with the OpenTelemetry SDK for +Node.js in order to generate telemetry data for your dependencies. For more +information, see [Libraries](/docs/instrumentation/java/libraries/). + +## Traces + +### Initialize Tracing + +{{% alert title="Note" color="info" %}} If you’re instrumenting a library, +**skip this step**. {{% /alert %}} + +To enable [tracing](/docs/concepts/signals/traces/) in your app, you'll need to +have an initialized +[`TracerProvider`](/docs/concepts/signals/traces/#tracer-provider) that will let +you create a [`Tracer`](/docs/concepts/signals/traces/#tracer): + +```java +import io.opentelemetry.sdk.trace.SdkTracerProvider; -SdkLoggerProvider sdkLoggerProvider = SdkLoggerProvider.builder() - .addLogRecordProcessor(BatchLogRecordProcessor.builder(OtlpGrpcLogRecordExporter.builder().build()).build()) +SdkTracerProvider sdkTracerProvider = SdkTracerProvider.builder() + .addSpanProcessor(spanProcessor) .setResource(resource) .build(); - -OpenTelemetry openTelemetry = OpenTelemetrySdk.builder() - .setTracerProvider(sdkTracerProvider) - .setMeterProvider(sdkMeterProvider) - .setLoggerProvider(sdkLoggerProvider) - .setPropagators(ContextPropagators.create(W3CTraceContextPropagator.getInstance())) - .buildAndRegisterGlobal(); ``` -As an aside, if you are writing library instrumentation, it is strongly -recommended that you provide your users the ability to inject an instance of -`OpenTelemetry` into your instrumentation code. If this is not possible for some -reason, you can fall back to using an instance from the `GlobalOpenTelemetry` -class. Note that you can't force end users to configure the global, so this is -the most brittle option for library instrumentation. +If a `TracerProvider` is not created, the OpenTelemetry APIs for tracing will +use a no-op implementation and fail to generate data. -## Traces +If you followed the instructions to [initialize the SDK](#initialize-the-sdk) +above, you have a `TracerProvider` setup for you already. You can continue with +[acquiring a tracer](#acquiring-a-tracer). ### Acquiring a Tracer @@ -157,38 +273,128 @@ instrumenting][instrumentation library] the [instrumented library] or application to be monitored. More information is available in the specification chapter [Obtaining a Tracer]. -```java -import io.opentelemetry.api; +Anywhere in your application where you write manual tracing code should call +`getTracer` to acquire a tracer. For example: -//... +```java +import io.opentelemetry.api.trace.Tracer; -Tracer tracer = - openTelemetry.getTracer("instrumentation-library-name", "1.0.0"); +Tracer tracer = openTelemetry.getTracer("roll-controller", "0.1.0"); ``` -Important: the "name" and optional version of the tracer are purely -informational. All `Tracer`s that are created by a single `OpenTelemetry` +The values of `instrumentation-scope-name` and `instrumentation-scope-version` +should uniquely identify the +[instrumentation scope](/docs/specs/otel/glossary/#instrumentation-scope), such +as the package, module or class name. While the name is required, the version is +still recommended despite being optional. Note, that all `Tracer`s that are created by a single `OpenTelemetry` instance will interoperate, regardless of name. +It's generally recommended to call `getTracer` in your app when you need it +rather than exporting the `tracer` instance to the rest of your app. This helps +avoid trickier application load issues when other required dependencies are +involved. + +In the case of the [example app](#example-app) a `Tracer` can be acquired in the +`index` method of the `RollController` as follows: + +```java +package otel; + +import java.util.Optional; +import java.util.concurrent.ThreadLocalRandom; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.RestController; + +import io.opentelemetry.api.GlobalOpenTelemetry; +import io.opentelemetry.api.trace.Tracer; + +@RestController +public class RollController { + private static final Logger logger = LoggerFactory.getLogger(RollController.class); + + @GetMapping("/rolldice") + public String index(@RequestParam("player") Optional player) { + + Tracer tracer = GlobalOpenTelemetry.getTracer("roll-controller", "0.1.0"); + + int result = this.getRandomNumber(1, 6); + if (player.isPresent()) { + logger.info("{} is rolling the dice: {}", player.get(), result); + } else { + logger.info("Anonymous player is rolling the dice: {}", result); + } + return Integer.toString(result); + } + + public int getRandomNumber(int min, int max) { + return ThreadLocalRandom.current().nextInt(min, max + 1); + } +} +``` + +As an aside, if you are writing library instrumentation, it is strongly +recommended that you provide your users the ability to inject an instance of +`OpenTelemetry` into your instrumentation code. If this is not possible for some +reason, you can fall back to using an instance from the `GlobalOpenTelemetry` +class. Note that you can't force end users to configure the global, so this is +the most brittle option for library instrumentation. + ### Create Spans +Now that you have [tracers](/docs/concepts/signals/traces/#tracer) initialized, +you can create [spans](/docs/concepts/signals/traces/#spans). + To create [Spans](/docs/concepts/signals/traces/#spans), you only need to specify the name of the span. The start and end time of the span is automatically set by the OpenTelemetry SDK. +The code below illustrates how to create a span: + ```java -Span span = tracer.spanBuilder("my span").startSpan(); +import io.opentelemetry.api.trace.Span; +import io.opentelemetry.context.Scope; -// Make the span the current span -try (Scope ss = span.makeCurrent()) { - // In this scope, the span is the current/active span -} finally { - span.end(); -} +... + + Span span = tracer.spanBuilder("rollTheDice").startSpan(); + + // Make the span the current span + try (Scope ss = span.makeCurrent()) { + int result = this.getRandomNumber(1, 6); + if (player.isPresent()) { + logger.info("{} is rolling the dice: {}", player.get(), result); + } else { + logger.info("Anonymous player is rolling the dice: {}", result); + } + return Integer.toString(result); + } finally { + span.end(); + } ``` It's required to call `end()` to end the span when you want it to end. +If you followed the instructions using the [example app](#example-app) up to +this point, you can copy the code above into the `index` method of the `RollController`. +You should now be able to see spans emitted from your app. + +Start your app as follows, and then send it requests by visiting + with your browser or `curl`: + +```shell +java -jar ./build/libs/java-simple.jar +``` + +After a while, you should see the spans printed in the console by the +`LoggingSpanExporter`, something like this: + +```log +2023-08-02T17:22:22.658+02:00 INFO 2313 --- [nio-8080-exec-1] i.o.e.logging.LoggingSpanExporter : 'rollTheDice' : 565232b11b9933fa6be8d6c4a1307fe2 6e1e011e2e8c020b INTERNAL [tracer: roll-controller:0.1.0] {} +``` + ### Create nested Spans Most of the time, we want to correlate diff --git a/content/en/docs/instrumentation/java/resources.md b/content/en/docs/instrumentation/java/resources.md new file mode 100644 index 000000000000..a3a8884a5e22 --- /dev/null +++ b/content/en/docs/instrumentation/java/resources.md @@ -0,0 +1,53 @@ +--- +title: Resources +weight: 70 +cSpell:ignore: myhost SIGINT uuidgen WORKDIR getenv +--- + +A [resource](/docs/specs/otel/resource/sdk/) represents the entity producing telemetry as resource attributes. +For example, a process producing telemetry that is running in a container on +Kubernetes has a Pod name, a namespace, and possibly a deployment name. All +three of these attributes can be included in the resource. + +In your observability backend, you can use resource information to better +investigate interesting behavior. For example, if your trace or metrics data +indicate latency in your system, you can narrow it down to a specific container, +pod, or Kubernetes deployment. + +If you use the Javaagent for [automatic instrumentation](/docs/instrumentation/java/automatic) you +can learn how to setup resource detection following the [Agent Configuration Guide]/docs/instrumentation/java/automatic/agent-config) + +For manual instrumentation, you will find some introductions on how to set up resource detection below. + +## Adding resources in code + +Custom resources can be configured in your code like the following: + +```java + Resource resource = Resource.getDefault() + .merge(Resource.create(Attributes.builder() + .put(ResourceAttributes.SERVICE_NAME, "dice-service") + .put(ResourceAttributes.SERVICE_VERSION, "0.1.0") + .put(ResourceAttributes.SERVICE_INSTANCE_ID, "dice-service-1") + .put(ResourceAttributes.HOST_NAME, System.getenv("HOSTNAME")) + .put(ResourceAttributes.PROCESS_PID, ProcessHandle.current().pid()) + .build())); + + Resource resource = Resource.getDefault() + .merge(Resource.create(attributes)); + + SdkTracerProvider sdkTracerProvider = SdkTracerProvider.builder() + .setResource(resource) + ... + .build(); + + SdkMeterProvider sdkMeterProvider = SdkMeterProvider.builder() + .setResource(resource) + ... + .build(); + + SdkLoggerProvider sdkLoggerProvider = SdkLoggerProvider.builder() + .setResource(resource) + ... + .build(); +``` From 09140a62045ce9eb7f907a553bdd8f1019d4260e Mon Sep 17 00:00:00 2001 From: svrnm Date: Fri, 4 Aug 2023 16:17:24 +0200 Subject: [PATCH 02/17] updates Signed-off-by: svrnm --- .../en/docs/instrumentation/java/manual.md | 34 ++++++++++++++++++- 1 file changed, 33 insertions(+), 1 deletion(-) diff --git a/content/en/docs/instrumentation/java/manual.md b/content/en/docs/instrumentation/java/manual.md index d92a4e105e99..db169bb6fda2 100644 --- a/content/en/docs/instrumentation/java/manual.md +++ b/content/en/docs/instrumentation/java/manual.md @@ -31,13 +31,45 @@ _natively_ or you can make use of ## Example app preparation {#example-app} -This page uses the example app from +This page uses a modified version of the example app from [Getting Started](/docs/instrumentation/java/getting-started/) to help you learn about manual instrumentation. You don't have to use the example app: if you want to instrument your own app or library, follow the instructions here to adapt the process to your own code. +### Dependencies {#example-app-dependencies} + +To begin, set up an environment in a new directory called `java-simple`. Within +that directory, create a file called `build.gradle.kts` with the following +content: + +```kotlin +plugins { + id("java") + id("org.springframework.boot") version "3.0.6" + id("io.spring.dependency-management") version "1.1.0" +} + +sourceSets { + main { + java.setSrcDirs(setOf(".")) + } +} + +repositories { + mavenCentral() +} + +dependencies { + implementation("org.springframework.boot:spring-boot-starter-web") +} +``` + +### Create and launch an HTTP Server + + + ## Manual instrumentation setup The first step is to install the dependencies for the OpenTelemetry API. From 2cc0984e7d2a533e77478b626dac84c92b4d57ce Mon Sep 17 00:00:00 2001 From: svrnm Date: Tue, 8 Aug 2023 15:58:34 +0200 Subject: [PATCH 03/17] finalize first draft Signed-off-by: svrnm --- .../en/docs/instrumentation/java/exporters.md | 66 +-- .../en/docs/instrumentation/java/libraries.md | 7 + .../en/docs/instrumentation/java/manual.md | 505 ++++++++++++++---- .../en/docs/instrumentation/java/resources.md | 20 +- 4 files changed, 452 insertions(+), 146 deletions(-) create mode 100644 content/en/docs/instrumentation/java/libraries.md diff --git a/content/en/docs/instrumentation/java/exporters.md b/content/en/docs/instrumentation/java/exporters.md index e00833baab1f..10db443da048 100644 --- a/content/en/docs/instrumentation/java/exporters.md +++ b/content/en/docs/instrumentation/java/exporters.md @@ -10,8 +10,8 @@ common open source backends. If you use the Javaagent for [automatic instrumentation](/docs/instrumentation/java/automatic) you can learn -how to setup exporters following the [Agent Configuration -Guide]/docs/instrumentation/java/automatic/agent-config) +how to setup exporters following the +[Agent Configuration Guide](/docs/instrumentation/java/automatic/agent-config) For [manual instrumentation](/docs/instrumentation/java/manual), you will find some introductions below on how to set up backends and the matching exporters. @@ -23,13 +23,16 @@ Jaeger) you'll want to use `opentelemetry-exporter-otlp`: -{{< tabpane >}} -{{< tab Gradle >}} +{{< tabpane text=true >}} +{{% tab Gradle %}} +```kotlin dependencies { implementation 'io.opentelemetry:opentelemetry-exporter-otlp:{{% param javaVersion %}}' } -{{< /tab >}} -{{< tab Maven >}} +``` +{{% /tab %}} +{{% tab Maven %}} +```xml @@ -38,47 +41,31 @@ dependencies { +``` {{< /tab >}} {{< /tabpane>}} -Next, configure the exporter to point at an OTLP endpoint. For example you can -update the [example app](/docs/instrumentation/java/manual#example-app) like the +Next, configure the exporter to point at an OTLP endpoint. + +If you use [SDK auto-configuration](/docs/instrumentation/java/manual/#automatic-configuration) +all you need to do is update your environment variables: + +```shell +env OTEL_TRACES_EXPORTER=otlp OTEL_METRICS_EXPORTER=otlp OTEL_LOGS_EXPORTER=otlp java -jar ./build/libs/java-simple.jar +``` + +In the case of [manual configuration] you can update the [example app](/docs/instrumentation/java/manual#example-app) like the following: ```java -package otel; - -import org.springframework.boot.SpringApplication; -import org.springframework.boot.Banner; -import org.springframework.boot.autoconfigure.SpringBootApplication; - -import io.opentelemetry.api.OpenTelemetry; -import io.opentelemetry.api.common.Attributes; -import io.opentelemetry.api.trace.propagation.W3CTraceContextPropagator; -import io.opentelemetry.context.propagation.ContextPropagators; import io.opentelemetry.exporter.otlp.metrics.OtlpGrpcMetricExporter; import io.opentelemetry.exporter.otlp.trace.OtlpGrpcSpanExporter; import io.opentelemetry.exporter.otlp.logs.OtlpGrpcLogRecordExporter; -import io.opentelemetry.sdk.OpenTelemetrySdk; -import io.opentelemetry.sdk.metrics.SdkMeterProvider; import io.opentelemetry.sdk.metrics.export.PeriodicMetricReader; -import io.opentelemetry.sdk.resources.Resource; -import io.opentelemetry.sdk.trace.SdkTracerProvider; import io.opentelemetry.sdk.trace.export.BatchSpanProcessor; -import io.opentelemetry.sdk.logs.SdkLoggerProvider; import io.opentelemetry.sdk.logs.export.BatchLogRecordProcessor; -import io.opentelemetry.sdk.logs.export.LogRecordExporter; -import io.opentelemetry.semconv.resource.attributes.ResourceAttributes; - -@SpringBootApplication -public class DiceApplication { - public static void main(String[] args) { - - Resource resource = Resource.getDefault() - .merge(Resource.create(Attributes.of(ResourceAttributes.SERVICE_NAME, "dice-server", - ResourceAttributes.SERVICE_VERSION, "0.1.0"))); SdkTracerProvider sdkTracerProvider = SdkTracerProvider.builder() .addSpanProcessor(BatchSpanProcessor.builder(OtlpGrpcSpanExporter.builder().build()).build()) @@ -95,19 +82,6 @@ public class DiceApplication { BatchLogRecordProcessor.builder(OtlpGrpcLogRecordExporter.builder().build()).build()) .setResource(resource) .build(); - - OpenTelemetry openTelemetry = OpenTelemetrySdk.builder() - .setTracerProvider(sdkTracerProvider) - .setMeterProvider(sdkMeterProvider) - .setLoggerProvider(sdkLoggerProvider) - .setPropagators(ContextPropagators.create(W3CTraceContextPropagator.getInstance())) - .buildAndRegisterGlobal(); - - SpringApplication app = new SpringApplication(DiceApplication.class); - app.setBannerMode(Banner.Mode.OFF); - app.run(args); - } -} ``` To try out the exporters quickly, you can run Jaeger with OTLP enabled in a diff --git a/content/en/docs/instrumentation/java/libraries.md b/content/en/docs/instrumentation/java/libraries.md new file mode 100644 index 000000000000..6c7d77b50373 --- /dev/null +++ b/content/en/docs/instrumentation/java/libraries.md @@ -0,0 +1,7 @@ +--- +title: Using instrumentation libraries +linkTitle: Libraries +weight: 40 +--- + +_to be done_ \ No newline at end of file diff --git a/content/en/docs/instrumentation/java/manual.md b/content/en/docs/instrumentation/java/manual.md index db169bb6fda2..9caaca7137d1 100644 --- a/content/en/docs/instrumentation/java/manual.md +++ b/content/en/docs/instrumentation/java/manual.md @@ -19,8 +19,8 @@ cSpell:ignore: autoconfigure classpath customizer logback loggable multivalued On this page you will learn how you can add traces, metrics and logs to your code _manually_. But, you are not limited to only use one kind of instrumentation: use -[automatic instrumentation](/docs/instrumentation/java/automatic/) to get started -and then enrich your code with manual instrumentation as needed. +[automatic instrumentation](/docs/instrumentation/java/automatic/) to get +started and then enrich your code with manual instrumentation as needed. Also, for libraries your code depends on, you don't have to write instrumentation code yourself, since they might come with OpenTelemetry built-in @@ -32,8 +32,8 @@ _natively_ or you can make use of ## Example app preparation {#example-app} This page uses a modified version of the example app from -[Getting Started](/docs/instrumentation/java/getting-started/) to help you -learn about manual instrumentation. +[Getting Started](/docs/instrumentation/java/getting-started/) to help you learn +about manual instrumentation. You don't have to use the example app: if you want to instrument your own app or library, follow the instructions here to adapt the process to your own code. @@ -68,21 +68,138 @@ dependencies { ### Create and launch an HTTP Server +To highlight the difference between instrumenting a _library_ and a standalone +_app_, split out the dice rolling into a _library_ class, which then will be +imported as a dependency by the app. +Create the _library file_ name `Dice.java` and add the following code to it: + +```Java +package otel; + +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.ThreadLocalRandom; + +public class Dice { + + private int min; + private int max; + + public Dice(int min, int max) { + this.min = min; + this.max = max; + } + + public List rollTheDice(int rolls) { + List results = new ArrayList(); + for (int i = 0; i < rolls; i++) { + results.add(this.rollOnce()); + } + return results; + } + + private int rollOnce() { + return ThreadLocalRandom.current().nextInt(this.min, this.max + 1); + } +} +``` + +Create the app files `DiceApplication.java` and `RollController.java` and add +the following code to them: + +```java +// DiceApplication.java +package otel; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.Banner; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +@SpringBootApplication +public class DiceApplication { + public static void main(String[] args) { + + SpringApplication app = new SpringApplication(DiceApplication.class); + app.setBannerMode(Banner.Mode.OFF); + app.run(args); + } +} +``` + +```java +// RollController.java +package otel; + +import java.util.List; +import java.util.Optional; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.http.HttpStatus; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.RestController; +import org.springframework.web.server.ResponseStatusException; + +import otel.Dice; + +@RestController +public class RollController { + private static final Logger logger = LoggerFactory.getLogger(RollController.class); + + @GetMapping("/rolldice") + public List index(@RequestParam("player") Optional player, + @RequestParam("rolls") Optional rolls) { + + if (!rolls.isPresent()) { + throw new ResponseStatusException(HttpStatus.BAD_REQUEST, "Missing rolls parameter", null); + } + + List result = new Dice(1, 6).rollTheDice(rolls.get()); + + if (player.isPresent()) { + logger.info("{} is rolling the dice: {}", player.get(), result); + } else { + logger.info("Anonymous player is rolling the dice: {}", result); + } + return result; + } +} +``` + +To ensure that it is working, run the application with the following command and +open in your web browser: + +```shell +java -jar ./build/libs/java-simple.jar +``` + +You should get a list of 12 numbers in your browser window, for example: + +```text +[5,6,5,3,6,1,2,5,4,4,2,4] +``` ## Manual instrumentation setup -The first step is to install the dependencies for the OpenTelemetry API. +For both library and app instrumentation, the first step is to install the +dependencies for the OpenTelemetry API. -{{< tabpane >}} -{{< tab Gradle >}} +{{< tabpane text=true >}} +{{% tab Gradle %}} + +```kotlin dependencies { implementation 'io.opentelemetry:opentelemetry-api:{{% param javaVersion %}}' } -{{< /tab >}} -{{< tab Maven >}} +``` + +{{% /tab %}} +{{% tab Maven %}} + +```xml @@ -102,8 +219,10 @@ dependencies { -{{< /tab >}} -{{< /tabpane>}} +``` + +{{% /tab %}} +{{% /tabpane %}} @@ -112,20 +231,25 @@ dependencies { {{% alert title="Note" color="info" %}} If you’re instrumenting a library, **skip this step**. {{% /alert %}} -If you instrument a Java app, install the dependencies for the OpenTelemetry SDK. +If you instrument a Java app, install the dependencies for the OpenTelemetry +SDK. - +{{< tabpane text=true >}} {{% tab Gradle %}} -{{< tabpane >}} -{{< tab Gradle >}} +```kotlin dependencies { implementation 'io.opentelemetry:opentelemetry-api:{{% param javaVersion %}}' implementation 'io.opentelemetry:opentelemetry-sdk:{{% param javaVersion %}}' + implementation 'io.opentelemetry:opentelemetry-sdk-metrics:{{% param javaVersion %}}' implementation 'io.opentelemetry:opentelemetry-exporter-logging:{{% param javaVersion %}}' implementation 'io.opentelemetry:opentelemetry-semconv:{{% param javaVersion %}}-alpha' + implementation 'opentelemetry-sdk-extension-autoconfigure:{{% param javaVersion %}}' } -{{< /tab >}} -{{< tab Maven >}} +``` + +{{% /tab %}} {{% tab Maven %}} + +```xml @@ -146,6 +270,10 @@ dependencies { io.opentelemetry opentelemetry-sdk + + + io.opentelemetry + opentelemetry-sdk-metrics io.opentelemetry @@ -156,24 +284,145 @@ dependencies { opentelemetry-semconv {{% param javaVersion %}}-alpha + + io.opentelemetry + opentelemetry-sdk-extension-autoconfigure + -{{< /tab >}} -{{< /tabpane>}} +``` + +{{% /tab %}} {{< /tabpane>}} If you are an application developer, you need to configure an instance of the -`OpenTelemetrySdk` as early as possible in your application. This can be done -using the `OpenTelemetrySdk.builder()` method. The returned -`OpenTelemetrySdkBuilder` instance gets the providers related to the signals, -tracing and metrics, in order to build the `OpenTelemetry` instance. +`OpenTelemetrySdk` as early as possible in your application. This can either be +done manually by using the `OpenTelemetrySdk.builder()` or by using the SDK +auto-configuration extension through the +`opentelemetry-sdk-extension-autoconfigure` module. It is recommended to use +auto-configuration, as it is easier to use and comes with various additional +capabilities. + +#### Automatic Configuration + +To use auto-configuration add the following dependency to your application: + +{{< tabpane text=true >}} {{% tab Gradle %}} + +```kotlin +dependencies { + implementation 'opentelemetry-sdk-extension-autoconfigure:{{% param javaVersion %}}' + implementation 'opentelemetry-sdk-extension-autoconfigure-spi:{{% param javaVersion %}}' +} +``` + +{{% /tab %}} {{% tab Maven %}} + +```xml + + + + io.opentelemetry + opentelemetry-sdk-extension-autoconfigure + + + io.opentelemetry + opentelemetry-sdk-extension-autoconfigure-spi + + + +``` + +{{% /tab %}} {{< /tabpane>}} + +It allows you to auto-configure the OpenTelemetry SDK based on a standard set of +supported environment variables and system properties. Each environment variable +has a corresponding system property named the same way but as lower case and +using the `.` (dot) character instead of the `_` (underscore) as separator. + +The logical service name can be specified via the `OTEL_SERVICE_NAME` +environment variable (or `otel.service.name` system property). + +The traces, metrics or logs exporters can be set via the `OTEL_TRACES_EXPORTER`, +`OTEL_METRICS_EXPORTER` and `OTEL_LOGS_EXPORTER` environment variables. For +example `OTEL_TRACES_EXPORTER=logging` configures your application to use an +exporter that writes all traces to the console. The corresponding exporter +library has to be provided in the classpath of the application as well. + +For debugging and local development purposes, use the `logging` exporter. After +you have finished setting up manual instrumentation, provide an appropriate +exporter library in the classpath of the application to +[export the app's telemetry data](/docs/instrumentation/java/exporters/) to one +or more telemetry backends. + +The SDK auto-configuration has to be initialized from your code in order to +allow the module to go through the provided environment variables (or system +properties) and set up the `OpenTelemetry` instance by using the builders +internally. + +```java +import io.opentelemetry.sdk.autoconfigure.AutoConfiguredOpenTelemetrySdk; + +OpenTelemetrySdk sdk = AutoConfiguredOpenTelemetrySdk.initialize() + .getOpenTelemetrySdk(); +``` + +In the case of the [example app](#example-app) the the `DiceApplication` class +gets updated as follows: + +```java +package otel; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.Banner; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.context.annotation.Bean; + +import io.opentelemetry.api.OpenTelemetry; +import io.opentelemetry.sdk.autoconfigure.AutoConfiguredOpenTelemetrySdk; + +@SpringBootApplication +public class DiceApplication { + public static void main(String[] args) { + SpringApplication app = new SpringApplication(DiceApplication.class); + app.setBannerMode(Banner.Mode.OFF); + app.run(args); + } + + @Bean + public OpenTelemetry openTelemetry() { + return AutoConfiguredOpenTelemetrySdk.initialize().getOpenTelemetrySdk(); + } +} +``` + +To verify your code, build and run the app: + +```sh +gradle assemble +env \ +OTEL_SERVICE_NAME=dice-server \ +OTEL_TRACES_EXPORTER=logging \ +OTEL_METRICS_EXPORTER=logging \ +OTEL_LOGS_EXPORTER=logging \ +java -jar ./build/libs/java-simple.jar +``` + +This basic setup has no effect on your app yet. You need to add code for +[traces](#traces), [metrics](#metrics), and/or [logs](#logs). + +#### Manual Configuration + +`OpenTelemetrySdk.builder()` returns an instance of `OpenTelemetrySdkBuilder`, +which gets the providers related to the signals, tracing and metrics, in order +to build the `OpenTelemetry` instance. You can build the providers by using the `SdkTracerProvider.builder()` and `SdkMeterProvider.builder()` methods. -In the case of the [Getting Started](/docs/instrumentation/java/getting-started) example app -the `main` method of the `DiceApplication` gets updated as follows: +In the case of the [example app](#example-app) the the `DiceApplication` class +gets updated as follows: ```java package otel; @@ -181,6 +430,7 @@ package otel; import org.springframework.boot.SpringApplication; import org.springframework.boot.Banner; import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.context.annotation.Bean; import io.opentelemetry.api.OpenTelemetry; import io.opentelemetry.api.common.Attributes; @@ -203,7 +453,13 @@ import io.opentelemetry.semconv.resource.attributes.ResourceAttributes; @SpringBootApplication public class DiceApplication { public static void main(String[] args) { + SpringApplication app = new SpringApplication(DiceApplication.class); + app.setBannerMode(Banner.Mode.OFF); + app.run(args); + } + @Bean + public OpenTelemetry openTelemetry() { Resource resource = Resource.getDefault() .merge(Resource.create(Attributes.of(ResourceAttributes.SERVICE_NAME, "dice-server", ResourceAttributes.SERVICE_VERSION, "0.1.0"))); @@ -229,18 +485,16 @@ public class DiceApplication { .setPropagators(ContextPropagators.create(W3CTraceContextPropagator.getInstance())) .buildAndRegisterGlobal(); - SpringApplication app = new SpringApplication(DiceApplication.class); - app.setBannerMode(Banner.Mode.OFF); - app.run(args); + return openTelemetry; } } ``` -For debugging and local development purposes, the example exports -telemetry to the console. After you have finished setting up manual -instrumentation, you need to configure an appropriate exporter to -[export the app's telemetry data](/docs/instrumentation/java/exporters/) to one or -more telemetry backends. +For debugging and local development purposes, the example exports telemetry to +the console. After you have finished setting up manual instrumentation, you need +to configure an appropriate exporter to +[export the app's telemetry data](/docs/instrumentation/java/exporters/) to one +or more telemetry backends. The example also sets up the mandatory SDK default attribute `service.name`, which holds the logical name of the service, and the optional (but highly @@ -250,19 +504,16 @@ API or implementation. Alternative methods exist for setting up resource attributes. For more information, see [Resources](/docs/instrumentation/java/resources/). -To verify your code, run the app: +To verify your code, buld and run the app: ```sh +gradle assemble java -jar ./build/libs/java-simple.jar ``` This basic setup has no effect on your app yet. You need to add code for [traces](#traces), [metrics](#metrics), and/or [logs](#logs). -You can register instrumentation libraries with the OpenTelemetry SDK for -Node.js in order to generate telemetry data for your dependencies. For more -information, see [Libraries](/docs/instrumentation/java/libraries/). - ## Traces ### Initialize Tracing @@ -311,59 +562,75 @@ Anywhere in your application where you write manual tracing code should call ```java import io.opentelemetry.api.trace.Tracer; -Tracer tracer = openTelemetry.getTracer("roll-controller", "0.1.0"); +Tracer tracer = openTelemetry.getTracer("instrumentation-scope-name", "instrumentation-scope-version"); ``` The values of `instrumentation-scope-name` and `instrumentation-scope-version` should uniquely identify the [instrumentation scope](/docs/specs/otel/glossary/#instrumentation-scope), such as the package, module or class name. While the name is required, the version is -still recommended despite being optional. Note, that all `Tracer`s that are created by a single `OpenTelemetry` -instance will interoperate, regardless of name. +still recommended despite being optional. Note, that all `Tracer`s that are +created by a single `OpenTelemetry` instance will interoperate, regardless of +name. It's generally recommended to call `getTracer` in your app when you need it rather than exporting the `tracer` instance to the rest of your app. This helps avoid trickier application load issues when other required dependencies are involved. -In the case of the [example app](#example-app) a `Tracer` can be acquired in the -`index` method of the `RollController` as follows: +In the case of the [example app](#example-app), there are two places where a +tracer may be acquired with an appropriate instrumentation scope: + +First, in the `index` method of the `RollController` as follows: ```java package otel; -import java.util.Optional; -import java.util.concurrent.ThreadLocalRandom; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.RequestParam; -import org.springframework.web.bind.annotation.RestController; - -import io.opentelemetry.api.GlobalOpenTelemetry; +// ... +import org.springframework.beans.factory.annotation.Autowired; +import io.opentelemetry.api.OpenTelemetry; import io.opentelemetry.api.trace.Tracer; @RestController public class RollController { private static final Logger logger = LoggerFactory.getLogger(RollController.class); + private final Tracer tracer; - @GetMapping("/rolldice") - public String index(@RequestParam("player") Optional player) { + @Autowired + RollController(OpenTelemetry openTelemetry) { + tracer = openTelemetry.getTracer(RollController.class.getName(), "0.1.0"); + } + // ... +} +``` - Tracer tracer = GlobalOpenTelemetry.getTracer("roll-controller", "0.1.0"); +And second, in the _library file_ `Dice.java`: - int result = this.getRandomNumber(1, 6); - if (player.isPresent()) { - logger.info("{} is rolling the dice: {}", player.get(), result); - } else { - logger.info("Anonymous player is rolling the dice: {}", result); - } - return Integer.toString(result); +```java +// ... +import io.opentelemetry.api.GlobalOpenTelemetry; +import io.opentelemetry.api.OpenTelemetry; +import io.opentelemetry.api.trace.Tracer; + +public class Dice { + + private int min; + private int max; + private Tracer tracer; + + public Dice(int min, int max, OpenTelemetry openTelemetry) { + this.min = min; + this.max = max; + this.tracer = openTelemetry.getTracer(Dice.class.getName(), "0.1.0"); } - public int getRandomNumber(int min, int max) { - return ThreadLocalRandom.current().nextInt(min, max + 1); + public Dice(int min, int max) { + this.min = min; + this.max = max; + this.tracer = OpenTelemetry.noop().getTracer(Dice.class.getName(), "0.1.0"); } + + // ... } ``` @@ -371,8 +638,16 @@ As an aside, if you are writing library instrumentation, it is strongly recommended that you provide your users the ability to inject an instance of `OpenTelemetry` into your instrumentation code. If this is not possible for some reason, you can fall back to using an instance from the `GlobalOpenTelemetry` -class. Note that you can't force end users to configure the global, so this is -the most brittle option for library instrumentation. +class: + +```java +import io.opentelemetry.api.GlobalOpenTelemetry; + +Tracer tracer = GlobalOpenTelemetry.getTracer("instrumentation-scope-name", "instrumentation-scope-version"); +``` + +Note that you can't force end users to configure the global, so this is the most +brittle option for library instrumentation. ### Create Spans @@ -394,7 +669,7 @@ import io.opentelemetry.context.Scope; Span span = tracer.spanBuilder("rollTheDice").startSpan(); // Make the span the current span - try (Scope ss = span.makeCurrent()) { + try (Scope scope = span.makeCurrent()) { int result = this.getRandomNumber(1, 6); if (player.isPresent()) { logger.info("{} is rolling the dice: {}", player.get(), result); @@ -410,13 +685,19 @@ import io.opentelemetry.context.Scope; It's required to call `end()` to end the span when you want it to end. If you followed the instructions using the [example app](#example-app) up to -this point, you can copy the code above into the `index` method of the `RollController`. -You should now be able to see spans emitted from your app. +this point, you can copy the code above into the `index` method of the +`RollController`. You should now be able to see spans emitted from your app. Start your app as follows, and then send it requests by visiting with your browser or `curl`: ```shell +gradle assemble +env \ +OTEL_SERVICE_NAME=dice-server \ +OTEL_TRACES_EXPORTER=logging \ +OTEL_METRICS_EXPORTER=logging \ +OTEL_LOGS_EXPORTER=logging \ java -jar ./build/libs/java-simple.jar ``` @@ -424,7 +705,7 @@ After a while, you should see the spans printed in the console by the `LoggingSpanExporter`, something like this: ```log -2023-08-02T17:22:22.658+02:00 INFO 2313 --- [nio-8080-exec-1] i.o.e.logging.LoggingSpanExporter : 'rollTheDice' : 565232b11b9933fa6be8d6c4a1307fe2 6e1e011e2e8c020b INTERNAL [tracer: roll-controller:0.1.0] {} +2023-08-02T17:22:22.658+02:00 INFO 2313 --- [nio-8080-exec-1] i.o.e.logging.LoggingSpanExporter : 'rollTheDice' : 565232b11b9933fa6be8d6c4a1307fe2 6e1e011e2e8c020b INTERNAL [tracer: otel.RollController:0.1.0] {} ``` ### Create nested Spans @@ -440,7 +721,7 @@ following way: ```java void parentOne() { - Span parentSpan = tracer.spanBuilder("parent").startSpan(); + try { childOne(parentSpan); } finally { @@ -460,27 +741,65 @@ void childOne(Span parentSpan) { } ``` +```java +import io.opentelemetry.api.trace.Span; +import io.opentelemetry.context.Context; + + public List rollTheDice(int rolls) { + Span parentSpan = tracer.spanBuilder("parent").startSpan(); + List results = new ArrayList(); + try { + for (int i = 0; i < rolls; i++) { + results.add(this.rollOnce(parentSpan)); + } + return results; + } finally { + parentSpan.end(); + } + } + + private int rollOnce(Span parentSpan) { + Span childSpan = tracer.spanBuilder("child") + .setParent(Context.current().with(parentSpan)) + .startSpan(); + try { + return ThreadLocalRandom.current().nextInt(this.min, this.max + 1); + } finally { + childSpan.end(); + } + } +``` + The OpenTelemetry API offers also an automated way to propagate the parent span on the current thread: ```java -void parentTwo() { - Span parentSpan = tracer.spanBuilder("parent").startSpan(); - try(Scope scope = parentSpan.makeCurrent()) { - childTwo(); - } finally { - parentSpan.end(); +import io.opentelemetry.api.trace.Span; +import io.opentelemetry.context.Scope; + + public List rollTheDice(int rolls) { + Span parentSpan = tracer.spanBuilder("parent").startSpan(); + try(Scope scope = parentSpan.makeCurrent()) { + List results = new ArrayList(); + for (int i = 0; i < rolls; i++) { + results.add(this.rollOnce()); + } + return results; + } finally { + parentSpan.end(); + } } -} -void childTwo() { - Span childSpan = tracer.spanBuilder("child") + + private int rollOnce() { + Span childSpan = tracer.spanBuilder("child") // NOTE: setParent(...) is not required; // `Span.current()` is automatically added as the parent .startSpan(); - try(Scope scope = childSpan.makeCurrent()) { - // do stuff - } finally { - childSpan.end(); + try(Scope scope = childSpan.makeCurrent()) { + return ThreadLocalRandom.current().nextInt(this.min, this.max + 1); + } finally { + childSpan.end(); + } } } ``` @@ -532,7 +851,15 @@ defined in the specification at First add the semantic conventions as a dependency to your application: -#### Maven +{{< tabpane text=true >}} {{% tab Gradle %}} + +```kotlin +dependencies { + implementation("io.opentelemetry:opentelemetry-semconv") +} +``` + +{{% /tab %}} {{% tab Maven %}} ```xml @@ -541,13 +868,7 @@ First add the semantic conventions as a dependency to your application: ``` -#### Gradle - -```kotlin -dependencies { - implementation("io.opentelemetry:opentelemetry-semconv") -} -``` +{{% /tab %}} {{< /tabpane>}} Finally, you can update your file to include semantic attributes: diff --git a/content/en/docs/instrumentation/java/resources.md b/content/en/docs/instrumentation/java/resources.md index a3a8884a5e22..850af42d81d1 100644 --- a/content/en/docs/instrumentation/java/resources.md +++ b/content/en/docs/instrumentation/java/resources.md @@ -1,23 +1,27 @@ --- title: Resources weight: 70 -cSpell:ignore: myhost SIGINT uuidgen WORKDIR getenv +cSpell:ignore: getenv myhost SIGINT uuidgen WORKDIR --- -A [resource](/docs/specs/otel/resource/sdk/) represents the entity producing telemetry as resource attributes. -For example, a process producing telemetry that is running in a container on -Kubernetes has a Pod name, a namespace, and possibly a deployment name. All -three of these attributes can be included in the resource. +A [resource](/docs/specs/otel/resource/sdk/) represents the entity producing +telemetry as resource attributes. For example, a process producing telemetry +that is running in a container on Kubernetes has a Pod name, a namespace, and +possibly a deployment name. All three of these attributes can be included in the +resource. In your observability backend, you can use resource information to better investigate interesting behavior. For example, if your trace or metrics data indicate latency in your system, you can narrow it down to a specific container, pod, or Kubernetes deployment. -If you use the Javaagent for [automatic instrumentation](/docs/instrumentation/java/automatic) you -can learn how to setup resource detection following the [Agent Configuration Guide]/docs/instrumentation/java/automatic/agent-config) +If you use the Javaagent for +[automatic instrumentation](/docs/instrumentation/java/automatic) you can learn +how to setup resource detection following the [Agent Configuration +Guide]/docs/instrumentation/java/automatic/agent-config) -For manual instrumentation, you will find some introductions on how to set up resource detection below. +For manual instrumentation, you will find some introductions on how to set up +resource detection below. ## Adding resources in code From 6b325e14e512ffb22e5c2f45428573eb22841ef8 Mon Sep 17 00:00:00 2001 From: svrnm Date: Tue, 8 Aug 2023 16:04:44 +0200 Subject: [PATCH 04/17] fixes Signed-off-by: svrnm --- content/en/docs/instrumentation/java/libraries.md | 2 +- content/en/docs/instrumentation/java/manual.md | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/content/en/docs/instrumentation/java/libraries.md b/content/en/docs/instrumentation/java/libraries.md index 6c7d77b50373..a89cfbba7c1a 100644 --- a/content/en/docs/instrumentation/java/libraries.md +++ b/content/en/docs/instrumentation/java/libraries.md @@ -4,4 +4,4 @@ linkTitle: Libraries weight: 40 --- -_to be done_ \ No newline at end of file +_to be done_ diff --git a/content/en/docs/instrumentation/java/manual.md b/content/en/docs/instrumentation/java/manual.md index 9caaca7137d1..1ea875c52c65 100644 --- a/content/en/docs/instrumentation/java/manual.md +++ b/content/en/docs/instrumentation/java/manual.md @@ -7,7 +7,8 @@ aliases: - /docs/instrumentation/java/manual_instrumentation weight: 30 description: Manual instrumentation for OpenTelemetry Java -cSpell:ignore: autoconfigure classpath customizer logback loggable multivalued +# prettier-ignore +cSpell:ignore: autoconfigure Autowired classpath customizer logback loggable multivalued rolldice springframework --- @@ -504,7 +505,7 @@ API or implementation. Alternative methods exist for setting up resource attributes. For more information, see [Resources](/docs/instrumentation/java/resources/). -To verify your code, buld and run the app: +To verify your code, build and run the app: ```sh gradle assemble @@ -1661,6 +1662,5 @@ io.opentelemetry.sdk.trace.export.BatchSpanProcessor = io.opentelemetry.extensio [opentelemetry registry]: /ecosystem/registry/?component=exporter&language=java [parentbased]: https://github.com/open-telemetry/opentelemetry-java/blob/main/sdk/trace/src/main/java/io/opentelemetry/sdk/trace/samplers/ParentBasedSampler.java -[releases]: https://github.com/open-telemetry/opentelemetry-java#releases [traceidratiobased]: https://github.com/open-telemetry/opentelemetry-java/blob/main/sdk/trace/src/main/java/io/opentelemetry/sdk/trace/samplers/TraceIdRatioBasedSampler.java From bca9d34340400204fb1252e16b13c58ffb322388 Mon Sep 17 00:00:00 2001 From: svrnm Date: Tue, 8 Aug 2023 16:07:16 +0200 Subject: [PATCH 05/17] markdown issue fixes Signed-off-by: svrnm --- content/en/docs/instrumentation/java/exporters.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/content/en/docs/instrumentation/java/exporters.md b/content/en/docs/instrumentation/java/exporters.md index 10db443da048..4216f9645079 100644 --- a/content/en/docs/instrumentation/java/exporters.md +++ b/content/en/docs/instrumentation/java/exporters.md @@ -25,13 +25,16 @@ Jaeger) you'll want to use `opentelemetry-exporter-otlp`: {{< tabpane text=true >}} {{% tab Gradle %}} + ```kotlin dependencies { implementation 'io.opentelemetry:opentelemetry-exporter-otlp:{{% param javaVersion %}}' } ``` + {{% /tab %}} {{% tab Maven %}} + ```xml @@ -42,6 +45,7 @@ dependencies { ``` + {{< /tab >}} {{< /tabpane>}} From 54b09d4eea15856733f7f15adc1831437532e000 Mon Sep 17 00:00:00 2001 From: svrnm Date: Wed, 9 Aug 2023 16:50:52 +0200 Subject: [PATCH 06/17] Updates following feedback Signed-off-by: svrnm --- .../en/docs/instrumentation/java/exporters.md | 89 +++++++++---- .../en/docs/instrumentation/java/manual.md | 122 ++++++++---------- .../en/docs/instrumentation/java/resources.md | 4 +- 3 files changed, 116 insertions(+), 99 deletions(-) diff --git a/content/en/docs/instrumentation/java/exporters.md b/content/en/docs/instrumentation/java/exporters.md index 4216f9645079..9ce73ee84c67 100644 --- a/content/en/docs/instrumentation/java/exporters.md +++ b/content/en/docs/instrumentation/java/exporters.md @@ -1,6 +1,7 @@ --- title: Exporters weight: 50 +cSpell:ignore: autoconfigure springframework --- In order to visualize and analyze your traces, you will need to export them to a @@ -55,37 +56,81 @@ If you use [SDK auto-configuration](/docs/instrumentation/java/manual/#automatic all you need to do is update your environment variables: ```shell -env OTEL_TRACES_EXPORTER=otlp OTEL_METRICS_EXPORTER=otlp OTEL_LOGS_EXPORTER=otlp java -jar ./build/libs/java-simple.jar +env OTEL_EXPORTER_OTLP_ENDPOINT=http://example:4317 java -jar ./build/libs/java-simple.jar ``` +Note, that in the case of exporting via OTLP you do not need to set `OTEL_TRACES_EXPORTER`, `OTEL_METRICS_EXPORTER` and `OTEL_LOGS_EXPORTER` +since `otlp` is their default value + In the case of [manual configuration] you can update the [example app](/docs/instrumentation/java/manual#example-app) like the following: -```java +```java { hl_lines=["12-14",21,"39-53"] } +package otel; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.Banner; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.context.annotation.Bean; + +import io.opentelemetry.api.OpenTelemetry; +import io.opentelemetry.api.common.Attributes; +import io.opentelemetry.api.trace.propagation.W3CTraceContextPropagator; +import io.opentelemetry.context.propagation.ContextPropagators; import io.opentelemetry.exporter.otlp.metrics.OtlpGrpcMetricExporter; import io.opentelemetry.exporter.otlp.trace.OtlpGrpcSpanExporter; import io.opentelemetry.exporter.otlp.logs.OtlpGrpcLogRecordExporter; +import io.opentelemetry.sdk.OpenTelemetrySdk; +import io.opentelemetry.sdk.metrics.SdkMeterProvider; import io.opentelemetry.sdk.metrics.export.PeriodicMetricReader; +import io.opentelemetry.sdk.resources.Resource; +import io.opentelemetry.sdk.trace.SdkTracerProvider; import io.opentelemetry.sdk.trace.export.BatchSpanProcessor; import io.opentelemetry.sdk.logs.export.BatchLogRecordProcessor; - - SdkTracerProvider sdkTracerProvider = SdkTracerProvider.builder() - .addSpanProcessor(BatchSpanProcessor.builder(OtlpGrpcSpanExporter.builder().build()).build()) - .setResource(resource) - .build(); - - SdkMeterProvider sdkMeterProvider = SdkMeterProvider.builder() - .registerMetricReader(PeriodicMetricReader.builder(OtlpGrpcMetricExporter.builder().build()).build()) - .setResource(resource) - .build(); - - SdkLoggerProvider sdkLoggerProvider = SdkLoggerProvider.builder() - .addLogRecordProcessor( - BatchLogRecordProcessor.builder(OtlpGrpcLogRecordExporter.builder().build()).build()) - .setResource(resource) - .build(); +import io.opentelemetry.sdk.logs.SdkLoggerProvider; +import io.opentelemetry.sdk.logs.export.LogRecordExporter; +import io.opentelemetry.semconv.resource.attributes.ResourceAttributes; + +@SpringBootApplication +public class DiceApplication { + public static void main(String[] args) { + SpringApplication app = new SpringApplication(DiceApplication.class); + app.setBannerMode(Banner.Mode.OFF); + app.run(args); + } + + @Bean + public OpenTelemetry openTelemetry() { + Resource resource = Resource.getDefault().toBuilder().put(SERVICE_NAME, "dice-server").put(SERVICE_VERSION, "0.1.0").build() + + SdkTracerProvider sdkTracerProvider = SdkTracerProvider.builder() + .addSpanProcessor(BatchSpanProcessor.builder(OtlpGrpcSpanExporter.builder().build()).build()) + .setResource(resource) + .build(); + + SdkMeterProvider sdkMeterProvider = SdkMeterProvider.builder() + .registerMetricReader(PeriodicMetricReader.builder(OtlpGrpcMetricExporter.builder().build()).build()) + .setResource(resource) + .build(); + + SdkLoggerProvider sdkLoggerProvider = SdkLoggerProvider.builder() + .addLogRecordProcessor( + BatchLogRecordProcessor.builder(OtlpGrpcLogRecordExporter.builder().build()).build()) + .setResource(resource) + .build(); + + OpenTelemetry openTelemetry = OpenTelemetrySdk.builder() + .setTracerProvider(sdkTracerProvider) + .setMeterProvider(sdkMeterProvider) + .setLoggerProvider(sdkLoggerProvider) + .setPropagators(ContextPropagators.create(W3CTraceContextPropagator.getInstance())) + .buildAndRegisterGlobal(); + + return openTelemetry; + } +} ``` To try out the exporters quickly, you can run Jaeger with OTLP enabled in a @@ -93,17 +138,9 @@ docker container: ```shell docker run -d --name jaeger \ - -e COLLECTOR_ZIPKIN_HOST_PORT=:9411 \ -e COLLECTOR_OTLP_ENABLED=true \ - -p 6831:6831/udp \ - -p 6832:6832/udp \ - -p 5778:5778 \ -p 16686:16686 \ -p 4317:4317 \ -p 4318:4318 \ - -p 14250:14250 \ - -p 14268:14268 \ - -p 14269:14269 \ - -p 9411:9411 \ jaegertracing/all-in-one:latest ``` diff --git a/content/en/docs/instrumentation/java/manual.md b/content/en/docs/instrumentation/java/manual.md index 1ea875c52c65..1a9f2a2f00b7 100644 --- a/content/en/docs/instrumentation/java/manual.md +++ b/content/en/docs/instrumentation/java/manual.md @@ -23,6 +23,9 @@ instrumentation: use [automatic instrumentation](/docs/instrumentation/java/automatic/) to get started and then enrich your code with manual instrumentation as needed. +Note, that especially if you cannot modify the source code of your app, you can +skip manual instrumentation and only use automatic instrumentation. + Also, for libraries your code depends on, you don't have to write instrumentation code yourself, since they might come with OpenTelemetry built-in _natively_ or you can make use of @@ -186,19 +189,16 @@ You should get a list of 12 numbers in your browser window, for example: For both library and app instrumentation, the first step is to install the dependencies for the OpenTelemetry API. - - -{{< tabpane text=true >}} -{{% tab Gradle %}} +{{< tabpane text=true >}} {{% tab Gradle %}} -```kotlin +```kotlin { hl_lines=3 } dependencies { - implementation 'io.opentelemetry:opentelemetry-api:{{% param javaVersion %}}' + implementation("org.springframework.boot:spring-boot-starter-web"); + implementation("io.opentelemetry:opentelemetry-api:{{% param javaVersion %}}"); } ``` -{{% /tab %}} -{{% tab Maven %}} +{{% /tab %}} {{% tab Maven %}} ```xml @@ -222,10 +222,7 @@ dependencies { ``` -{{% /tab %}} -{{% /tabpane %}} - - +{{% /tab %}} {{% /tabpane %}} ### Initialize the SDK @@ -237,14 +234,15 @@ SDK. {{< tabpane text=true >}} {{% tab Gradle %}} -```kotlin +```kotlin { hl_lines="4-8" } dependencies { - implementation 'io.opentelemetry:opentelemetry-api:{{% param javaVersion %}}' - implementation 'io.opentelemetry:opentelemetry-sdk:{{% param javaVersion %}}' - implementation 'io.opentelemetry:opentelemetry-sdk-metrics:{{% param javaVersion %}}' - implementation 'io.opentelemetry:opentelemetry-exporter-logging:{{% param javaVersion %}}' - implementation 'io.opentelemetry:opentelemetry-semconv:{{% param javaVersion %}}-alpha' - implementation 'opentelemetry-sdk-extension-autoconfigure:{{% param javaVersion %}}' + implementation("org.springframework.boot:spring-boot-starter-web"); + implementation("io.opentelemetry:opentelemetry-api:{{% param javaVersion %}}"); + implementation("io.opentelemetry:opentelemetry-sdk:{{% param javaVersion %}}"); + implementation("io.opentelemetry:opentelemetry-sdk-metrics:{{% param javaVersion %}}"); + implementation("io.opentelemetry:opentelemetry-exporter-logging:{{% param javaVersion %}}"); + implementation("io.opentelemetry:opentelemetry-semconv:{{% param javaVersion %}}-alpha"); + implementation("opentelemetry-sdk-extension-autoconfigure:{{% param javaVersion %}}"); } ``` @@ -295,8 +293,6 @@ dependencies { {{% /tab %}} {{< /tabpane>}} - - If you are an application developer, you need to configure an instance of the `OpenTelemetrySdk` as early as possible in your application. This can either be done manually by using the `OpenTelemetrySdk.builder()` or by using the SDK @@ -311,10 +307,17 @@ To use auto-configuration add the following dependency to your application: {{< tabpane text=true >}} {{% tab Gradle %}} -```kotlin +```kotlin { hl_lines="9-10" } dependencies { - implementation 'opentelemetry-sdk-extension-autoconfigure:{{% param javaVersion %}}' - implementation 'opentelemetry-sdk-extension-autoconfigure-spi:{{% param javaVersion %}}' + implementation("org.springframework.boot:spring-boot-starter-web"); + implementation("io.opentelemetry:opentelemetry-api:{{% param javaVersion %}}"); + implementation("io.opentelemetry:opentelemetry-sdk:{{% param javaVersion %}}"); + implementation("io.opentelemetry:opentelemetry-sdk-metrics:{{% param javaVersion %}}"); + implementation("io.opentelemetry:opentelemetry-exporter-logging:{{% param javaVersion %}}"); + implementation("io.opentelemetry:opentelemetry-semconv:{{% param javaVersion %}}-alpha"); + implementation("opentelemetry-sdk-extension-autoconfigure:{{% param javaVersion %}}"); + implementation("opentelemetry-sdk-extension-autoconfigure:{{% param javaVersion %}}"); + implementation("opentelemetry-sdk-extension-autoconfigure-spi:{{% param javaVersion %}}"); } ``` @@ -357,10 +360,10 @@ exporter library in the classpath of the application to [export the app's telemetry data](/docs/instrumentation/java/exporters/) to one or more telemetry backends. -The SDK auto-configuration has to be initialized from your code in order to -allow the module to go through the provided environment variables (or system -properties) and set up the `OpenTelemetry` instance by using the builders -internally. +The SDK auto-configuration has to be initialized as early as possible in the +application lifecycle in order to allow the module to go through the provided +environment variables (or system properties) and set up the `OpenTelemetry` +instance by using the builders internally. ```java import io.opentelemetry.sdk.autoconfigure.AutoConfiguredOpenTelemetrySdk; @@ -369,10 +372,10 @@ OpenTelemetrySdk sdk = AutoConfiguredOpenTelemetrySdk.initialize() .getOpenTelemetrySdk(); ``` -In the case of the [example app](#example-app) the the `DiceApplication` class -gets updated as follows: +In the case of the [example app](#example-app) the `DiceApplication` class gets +updated as follows: -```java +```java { hl_lines=["6-9","19-22"] } package otel; import org.springframework.boot.SpringApplication; @@ -425,7 +428,7 @@ You can build the providers by using the `SdkTracerProvider.builder()` and In the case of the [example app](#example-app) the the `DiceApplication` class gets updated as follows: -```java +```java { hl_lines=["6-24","34-62"] } package otel; import org.springframework.boot.SpringApplication; @@ -461,8 +464,7 @@ public class DiceApplication { @Bean public OpenTelemetry openTelemetry() { - Resource resource = Resource.getDefault() - .merge(Resource.create(Attributes.of(ResourceAttributes.SERVICE_NAME, "dice-server", ResourceAttributes.SERVICE_VERSION, "0.1.0"))); + Resource resource = Resource.getDefault().toBuilder().put(SERVICE_NAME, "dice-server").put(SERVICE_VERSION, "0.1.0").build() SdkTracerProvider sdkTracerProvider = SdkTracerProvider.builder() .addSpanProcessor(SimpleSpanProcessor.create(LoggingSpanExporter.create())) @@ -584,7 +586,7 @@ tracer may be acquired with an appropriate instrumentation scope: First, in the `index` method of the `RollController` as follows: -```java +```java { hl_lines=["4-6",11,"13-16"] } package otel; // ... @@ -607,9 +609,8 @@ public class RollController { And second, in the _library file_ `Dice.java`: -```java +```java { hl_lines=["2-3","9-19"]} // ... -import io.opentelemetry.api.GlobalOpenTelemetry; import io.opentelemetry.api.OpenTelemetry; import io.opentelemetry.api.trace.Tracer; @@ -626,9 +627,7 @@ public class Dice { } public Dice(int min, int max) { - this.min = min; - this.max = max; - this.tracer = OpenTelemetry.noop().getTracer(Dice.class.getName(), "0.1.0"); + this(min, max, OpenTelemetry.noop()) } // ... @@ -661,12 +660,14 @@ automatically set by the OpenTelemetry SDK. The code below illustrates how to create a span: -```java +```java { hl_lines=["1-2","8-11","19-21"] } import io.opentelemetry.api.trace.Span; import io.opentelemetry.context.Scope; -... - +// ... + @GetMapping("/rolldice") + public List index(@RequestParam("player") Optional player, + @RequestParam("rolls") Optional rolls) { Span span = tracer.spanBuilder("rollTheDice").startSpan(); // Make the span the current span @@ -681,6 +682,7 @@ import io.opentelemetry.context.Scope; } finally { span.end(); } + } ``` It's required to call `end()` to end the span when you want it to end. @@ -717,35 +719,13 @@ OpenTelemetry supports tracing within processes and across remote processes. For more details how to share context between remote processes, see [Context Propagation](#context-propagation). -For a method `a` calling a method `b`, the spans could be manually linked in the -following way: +For example in the `Dice` class method `rollTheDice` calling method `rollOnce`, +the spans could be manually linked in the following way: -```java -void parentOne() { - - try { - childOne(parentSpan); - } finally { - parentSpan.end(); - } -} - -void childOne(Span parentSpan) { - Span childSpan = tracer.spanBuilder("child") - .setParent(Context.current().with(parentSpan)) - .startSpan(); - try { - // do stuff - } finally { - childSpan.end(); - } -} -``` - -```java +```java { hl_lines=["1-2","5","7","9","12-14","17-21","23-25"]} import io.opentelemetry.api.trace.Span; import io.opentelemetry.context.Context; - +// ... public List rollTheDice(int rolls) { Span parentSpan = tracer.spanBuilder("parent").startSpan(); List results = new ArrayList(); @@ -774,10 +754,10 @@ import io.opentelemetry.context.Context; The OpenTelemetry API offers also an automated way to propagate the parent span on the current thread: -```java +```java { hl_lines=["1-2","5-6","12-14","18-22","24-26"]} import io.opentelemetry.api.trace.Span; import io.opentelemetry.context.Scope; - +// ... public List rollTheDice(int rolls) { Span parentSpan = tracer.spanBuilder("parent").startSpan(); try(Scope scope = parentSpan.makeCurrent()) { diff --git a/content/en/docs/instrumentation/java/resources.md b/content/en/docs/instrumentation/java/resources.md index 850af42d81d1..f52dec400f04 100644 --- a/content/en/docs/instrumentation/java/resources.md +++ b/content/en/docs/instrumentation/java/resources.md @@ -17,8 +17,8 @@ pod, or Kubernetes deployment. If you use the Javaagent for [automatic instrumentation](/docs/instrumentation/java/automatic) you can learn -how to setup resource detection following the [Agent Configuration -Guide]/docs/instrumentation/java/automatic/agent-config) +how to setup resource detection following the +[Agent Configuration Guide](/docs/instrumentation/java/automatic/agent-config). For manual instrumentation, you will find some introductions on how to set up resource detection below. From 0a6dd88428d5b61c779b2318aee746c2c8574e12 Mon Sep 17 00:00:00 2001 From: Severin Neumann Date: Wed, 6 Sep 2023 12:18:17 +0200 Subject: [PATCH 07/17] Update content/en/docs/instrumentation/java/manual.md Co-authored-by: Mateusz Rzeszutek --- content/en/docs/instrumentation/java/manual.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/content/en/docs/instrumentation/java/manual.md b/content/en/docs/instrumentation/java/manual.md index 1a9f2a2f00b7..88865e6d785d 100644 --- a/content/en/docs/instrumentation/java/manual.md +++ b/content/en/docs/instrumentation/java/manual.md @@ -242,7 +242,7 @@ dependencies { implementation("io.opentelemetry:opentelemetry-sdk-metrics:{{% param javaVersion %}}"); implementation("io.opentelemetry:opentelemetry-exporter-logging:{{% param javaVersion %}}"); implementation("io.opentelemetry:opentelemetry-semconv:{{% param javaVersion %}}-alpha"); - implementation("opentelemetry-sdk-extension-autoconfigure:{{% param javaVersion %}}"); + implementation("io.opentelemetry:opentelemetry-sdk-extension-autoconfigure:{{% param javaVersion %}}"); } ``` From ff9383afd54cc1a161ee6ba551b3f0b987253437 Mon Sep 17 00:00:00 2001 From: Severin Neumann Date: Wed, 6 Sep 2023 14:55:05 +0200 Subject: [PATCH 08/17] Update content/en/docs/instrumentation/java/manual.md Co-authored-by: Mateusz Rzeszutek --- content/en/docs/instrumentation/java/manual.md | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/content/en/docs/instrumentation/java/manual.md b/content/en/docs/instrumentation/java/manual.md index 88865e6d785d..ce67515b7fca 100644 --- a/content/en/docs/instrumentation/java/manual.md +++ b/content/en/docs/instrumentation/java/manual.md @@ -760,12 +760,12 @@ import io.opentelemetry.context.Scope; // ... public List rollTheDice(int rolls) { Span parentSpan = tracer.spanBuilder("parent").startSpan(); - try(Scope scope = parentSpan.makeCurrent()) { - List results = new ArrayList(); - for (int i = 0; i < rolls; i++) { - results.add(this.rollOnce()); - } - return results; + try (Scope scope = parentSpan.makeCurrent()) { + List results = new ArrayList(); + for (int i = 0; i < rolls; i++) { + results.add(this.rollOnce()); + } + return results; } finally { parentSpan.end(); } From 647cb7e27ac1cf27017bd0a5cea09a66cc570092 Mon Sep 17 00:00:00 2001 From: Severin Neumann Date: Wed, 6 Sep 2023 14:55:20 +0200 Subject: [PATCH 09/17] Update content/en/docs/instrumentation/java/exporters.md Co-authored-by: Mateusz Rzeszutek --- content/en/docs/instrumentation/java/exporters.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/content/en/docs/instrumentation/java/exporters.md b/content/en/docs/instrumentation/java/exporters.md index 9ce73ee84c67..b4b5ec76d826 100644 --- a/content/en/docs/instrumentation/java/exporters.md +++ b/content/en/docs/instrumentation/java/exporters.md @@ -103,7 +103,7 @@ public class DiceApplication { @Bean public OpenTelemetry openTelemetry() { - Resource resource = Resource.getDefault().toBuilder().put(SERVICE_NAME, "dice-server").put(SERVICE_VERSION, "0.1.0").build() + Resource resource = Resource.getDefault().toBuilder().put(SERVICE_NAME, "dice-server").put(SERVICE_VERSION, "0.1.0").build(); SdkTracerProvider sdkTracerProvider = SdkTracerProvider.builder() .addSpanProcessor(BatchSpanProcessor.builder(OtlpGrpcSpanExporter.builder().build()).build()) From bf481958d893ac960f6b3fd2541cd96b4774e019 Mon Sep 17 00:00:00 2001 From: svrnm Date: Fri, 8 Sep 2023 16:13:34 +0200 Subject: [PATCH 10/17] resolving suggestions Signed-off-by: svrnm --- .../en/docs/instrumentation/java/exporters.md | 27 ++++----- .../en/docs/instrumentation/java/manual.md | 33 +++++----- .../en/docs/instrumentation/java/resources.md | 60 ++++++++++++++++++- 3 files changed, 87 insertions(+), 33 deletions(-) diff --git a/content/en/docs/instrumentation/java/exporters.md b/content/en/docs/instrumentation/java/exporters.md index b4b5ec76d826..eb18ed299935 100644 --- a/content/en/docs/instrumentation/java/exporters.md +++ b/content/en/docs/instrumentation/java/exporters.md @@ -9,7 +9,7 @@ backend such as [Jaeger](https://www.jaegertracing.io/) or [Zipkin](https://zipkin.io/). OpenTelemetry Java provides exporters for some common open source backends. -If you use the Javaagent for +If you use the Java agent for [automatic instrumentation](/docs/instrumentation/java/automatic) you can learn how to setup exporters following the [Agent Configuration Guide](/docs/instrumentation/java/automatic/agent-config) @@ -22,10 +22,7 @@ some introductions below on how to set up backends and the matching exporters. To send trace data to a OTLP endpoint (like the [collector](/docs/collector) or Jaeger) you'll want to use `opentelemetry-exporter-otlp`: - - -{{< tabpane text=true >}} -{{% tab Gradle %}} +{{< tabpane text=true >}} {{% tab Gradle %}} ```kotlin dependencies { @@ -33,8 +30,7 @@ dependencies { } ``` -{{% /tab %}} -{{% tab Maven %}} +{{% /tab %}} {{% tab Maven %}} ```xml @@ -47,25 +43,24 @@ dependencies { ``` -{{< /tab >}} -{{< /tabpane>}} +{{< /tab >}} {{< /tabpane>}} Next, configure the exporter to point at an OTLP endpoint. -If you use [SDK auto-configuration](/docs/instrumentation/java/manual/#automatic-configuration) +If you use +[SDK auto-configuration](/docs/instrumentation/java/manual/#automatic-configuration) all you need to do is update your environment variables: ```shell env OTEL_EXPORTER_OTLP_ENDPOINT=http://example:4317 java -jar ./build/libs/java-simple.jar ``` -Note, that in the case of exporting via OTLP you do not need to set `OTEL_TRACES_EXPORTER`, `OTEL_METRICS_EXPORTER` and `OTEL_LOGS_EXPORTER` -since `otlp` is their default value - -In the case of [manual configuration] you can update the [example app](/docs/instrumentation/java/manual#example-app) like the -following: +Note, that in the case of exporting via OTLP you do not need to set +`OTEL_TRACES_EXPORTER`, `OTEL_METRICS_EXPORTER` and `OTEL_LOGS_EXPORTER` since +`otlp` is their default value - +In the case of [manual configuration] you can update the +[example app](/docs/instrumentation/java/manual#example-app) like the following: ```java { hl_lines=["12-14",21,"39-53"] } package otel; diff --git a/content/en/docs/instrumentation/java/manual.md b/content/en/docs/instrumentation/java/manual.md index ce67515b7fca..eba78ee4fa12 100644 --- a/content/en/docs/instrumentation/java/manual.md +++ b/content/en/docs/instrumentation/java/manual.md @@ -175,6 +175,7 @@ To ensure that it is working, run the application with the following command and open in your web browser: ```shell +gradle assemble java -jar ./build/libs/java-simple.jar ``` @@ -242,7 +243,6 @@ dependencies { implementation("io.opentelemetry:opentelemetry-sdk-metrics:{{% param javaVersion %}}"); implementation("io.opentelemetry:opentelemetry-exporter-logging:{{% param javaVersion %}}"); implementation("io.opentelemetry:opentelemetry-semconv:{{% param javaVersion %}}-alpha"); - implementation("io.opentelemetry:opentelemetry-sdk-extension-autoconfigure:{{% param javaVersion %}}"); } ``` @@ -283,10 +283,6 @@ dependencies { opentelemetry-semconv {{% param javaVersion %}}-alpha - - io.opentelemetry - opentelemetry-sdk-extension-autoconfigure - ``` @@ -316,7 +312,6 @@ dependencies { implementation("io.opentelemetry:opentelemetry-exporter-logging:{{% param javaVersion %}}"); implementation("io.opentelemetry:opentelemetry-semconv:{{% param javaVersion %}}-alpha"); implementation("opentelemetry-sdk-extension-autoconfigure:{{% param javaVersion %}}"); - implementation("opentelemetry-sdk-extension-autoconfigure:{{% param javaVersion %}}"); implementation("opentelemetry-sdk-extension-autoconfigure-spi:{{% param javaVersion %}}"); } ``` @@ -464,7 +459,7 @@ public class DiceApplication { @Bean public OpenTelemetry openTelemetry() { - Resource resource = Resource.getDefault().toBuilder().put(SERVICE_NAME, "dice-server").put(SERVICE_VERSION, "0.1.0").build() + Resource resource = Resource.getDefault().toBuilder().put(ResourceAttributes.SERVICE_NAME, "dice-server").put(ResourceAttributes.SERVICE_VERSION, "0.1.0").build(); SdkTracerProvider sdkTracerProvider = SdkTracerProvider.builder() .addSpanProcessor(SimpleSpanProcessor.create(LoggingSpanExporter.create())) @@ -486,6 +481,7 @@ public class DiceApplication { .setMeterProvider(sdkMeterProvider) .setLoggerProvider(sdkLoggerProvider) .setPropagators(ContextPropagators.create(W3CTraceContextPropagator.getInstance())) + .setPropagators(ContextPropagators.create(W3CBaggagePropagator.getInstance())) .buildAndRegisterGlobal(); return openTelemetry; @@ -571,10 +567,10 @@ Tracer tracer = openTelemetry.getTracer("instrumentation-scope-name", "instrumen The values of `instrumentation-scope-name` and `instrumentation-scope-version` should uniquely identify the [instrumentation scope](/docs/specs/otel/glossary/#instrumentation-scope), such -as the package, module or class name. While the name is required, the version is -still recommended despite being optional. Note, that all `Tracer`s that are -created by a single `OpenTelemetry` instance will interoperate, regardless of -name. +as the package, module or class name. This will help later help determining what +the source of telemetry is. While the name is required, the version is still +recommended despite being optional. Note, that all `Tracer`s that are created by +a single `OpenTelemetry` instance will interoperate, regardless of name. It's generally recommended to call `getTracer` in your app when you need it rather than exporting the `tracer` instance to the rest of your app. This helps @@ -672,15 +668,24 @@ import io.opentelemetry.context.Scope; // Make the span the current span try (Scope scope = span.makeCurrent()) { - int result = this.getRandomNumber(1, 6); + + if (!rolls.isPresent()) { + throw new ResponseStatusException(HttpStatus.BAD_REQUEST, "Missing rolls parameter", null); + } + + List result = new Dice(1, 6).rollTheDice(rolls.get()); + if (player.isPresent()) { logger.info("{} is rolling the dice: {}", player.get(), result); } else { logger.info("Anonymous player is rolling the dice: {}", result); } - return Integer.toString(result); + return result; + } catch(Throwable t) { + span.recordException(t); + throw t; } finally { - span.end(); + span.end(); } } ``` diff --git a/content/en/docs/instrumentation/java/resources.md b/content/en/docs/instrumentation/java/resources.md index f52dec400f04..bc54e797833c 100644 --- a/content/en/docs/instrumentation/java/resources.md +++ b/content/en/docs/instrumentation/java/resources.md @@ -23,6 +23,63 @@ how to setup resource detection following the For manual instrumentation, you will find some introductions on how to set up resource detection below. +## Detecting resources from common environments + +You can use `ResourceProvider`s for filling in attributes related to common +environments, like docs/specs/otel/resource/semantic_conventions/container/, +[Host](/docs/specs/otel/resource/semantic_conventions/host/) or +[Operating System](/docs/specs/otel/resource/semantic_conventions/os/). These +can be used with or without +[auto-configuration](/docs/instrumentation/java/manual/#automatic-configuration). + +To use those providers, add the following dependency: + +{{< tabpane text=true >}} {{% tab Gradle %}} + +```kotlin +dependencies { + implementation("io.opentelemetry.instrumentation:opentelemetry-resources:{{% param javaVersion %}}-alpha"); +} +``` + +{{% /tab %}} {{% tab Maven %}} + +```xml + + + + io.opentelemetry.instrumentation + opentelemetry-resources + + + +``` + +{{< /tab >}} {{< /tabpane>}} + +Next you can use them like the following in your code: + +```java +import io.opentelemetry.instrumentation.resources.ContainerResource; +import io.opentelemetry.instrumentation.resources.HostResource; +import io.opentelemetry.instrumentation.resources.OsResource; +import io.opentelemetry.instrumentation.resources.ProcessResource; +import io.opentelemetry.instrumentation.resources.ProcessRuntimeResource; + +... + Resource resource = Resource.getDefault() + .merge(ContainerResource.get()) + .merge(HostResource.get()) + .merge(OsResource.get()) + .merge(ProcessResource.get()) + .merge(ProcessRuntimeResource.get()) + .merge(Resource.create(Attributes.builder() + .put(ResourceAttributes.SERVICE_NAME, "dice-service") + ... + .build())); +... +``` + ## Adding resources in code Custom resources can be configured in your code like the following: @@ -37,9 +94,6 @@ Custom resources can be configured in your code like the following: .put(ResourceAttributes.PROCESS_PID, ProcessHandle.current().pid()) .build())); - Resource resource = Resource.getDefault() - .merge(Resource.create(attributes)); - SdkTracerProvider sdkTracerProvider = SdkTracerProvider.builder() .setResource(resource) ... From e19548a58f52c4b063fd6901808a081cdf3beb05 Mon Sep 17 00:00:00 2001 From: Severin Neumann Date: Mon, 11 Sep 2023 11:54:03 +0200 Subject: [PATCH 11/17] Apply suggestions from code review Co-authored-by: Mateusz Rzeszutek --- content/en/docs/instrumentation/java/resources.md | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/content/en/docs/instrumentation/java/resources.md b/content/en/docs/instrumentation/java/resources.md index bc54e797833c..d46c8f2e377b 100644 --- a/content/en/docs/instrumentation/java/resources.md +++ b/content/en/docs/instrumentation/java/resources.md @@ -26,7 +26,7 @@ resource detection below. ## Detecting resources from common environments You can use `ResourceProvider`s for filling in attributes related to common -environments, like docs/specs/otel/resource/semantic_conventions/container/, +environments, like [Container](/docs/specs/otel/resource/semantic_conventions/container/), [Host](/docs/specs/otel/resource/semantic_conventions/host/) or [Operating System](/docs/specs/otel/resource/semantic_conventions/os/). These can be used with or without @@ -68,12 +68,12 @@ import io.opentelemetry.instrumentation.resources.ProcessRuntimeResource; ... Resource resource = Resource.getDefault() - .merge(ContainerResource.get()) - .merge(HostResource.get()) - .merge(OsResource.get()) - .merge(ProcessResource.get()) - .merge(ProcessRuntimeResource.get()) - .merge(Resource.create(Attributes.builder() + .merge(ContainerResource.get()) + .merge(HostResource.get()) + .merge(OsResource.get()) + .merge(ProcessResource.get()) + .merge(ProcessRuntimeResource.get()) + .merge(Resource.create(Attributes.builder() .put(ResourceAttributes.SERVICE_NAME, "dice-service") ... .build())); From ea8a2a9a924cf4aa8b382a25e84b2d03fc88ffbc Mon Sep 17 00:00:00 2001 From: Severin Neumann Date: Mon, 11 Sep 2023 14:29:07 +0200 Subject: [PATCH 12/17] Update content/en/docs/instrumentation/java/manual.md --- content/en/docs/instrumentation/java/manual.md | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/content/en/docs/instrumentation/java/manual.md b/content/en/docs/instrumentation/java/manual.md index 77610e535f82..ba93932e82de 100644 --- a/content/en/docs/instrumentation/java/manual.md +++ b/content/en/docs/instrumentation/java/manual.md @@ -480,8 +480,7 @@ public class DiceApplication { .setTracerProvider(sdkTracerProvider) .setMeterProvider(sdkMeterProvider) .setLoggerProvider(sdkLoggerProvider) - .setPropagators(ContextPropagators.create(W3CTraceContextPropagator.getInstance())) - .setPropagators(ContextPropagators.create(W3CBaggagePropagator.getInstance())) + .setPropagators(ContextPropagators.create(TextMapPropagator.composite(W3CTraceContextPropagator.getInstance(), W3CBaggagePropagator.getInstance()))) .buildAndRegisterGlobal(); return openTelemetry; From 70d9ac99cbc96739386f5b794ab68c91bfa9e3ba Mon Sep 17 00:00:00 2001 From: Severin Neumann Date: Mon, 11 Sep 2023 14:29:43 +0200 Subject: [PATCH 13/17] Update content/en/docs/instrumentation/java/manual.md --- content/en/docs/instrumentation/java/manual.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/content/en/docs/instrumentation/java/manual.md b/content/en/docs/instrumentation/java/manual.md index ba93932e82de..6171d6531c73 100644 --- a/content/en/docs/instrumentation/java/manual.md +++ b/content/en/docs/instrumentation/java/manual.md @@ -480,7 +480,7 @@ public class DiceApplication { .setTracerProvider(sdkTracerProvider) .setMeterProvider(sdkMeterProvider) .setLoggerProvider(sdkLoggerProvider) - .setPropagators(ContextPropagators.create(TextMapPropagator.composite(W3CTraceContextPropagator.getInstance(), W3CBaggagePropagator.getInstance()))) + .setPropagators(ContextPropagators.create(TextMapPropagator.composite(W3CTraceContextPropagator.getInstance(), W3CBaggagePropagator.getInstance()))) .buildAndRegisterGlobal(); return openTelemetry; From 839ab5e3172202f6525347cdcbbf211cf7cae0cb Mon Sep 17 00:00:00 2001 From: svrnm Date: Wed, 13 Sep 2023 14:10:32 +0200 Subject: [PATCH 14/17] fixes Signed-off-by: svrnm --- content/en/docs/instrumentation/java/exporters.md | 2 +- content/en/docs/instrumentation/java/manual.md | 6 ++++-- content/en/docs/instrumentation/java/resources.md | 3 ++- 3 files changed, 7 insertions(+), 4 deletions(-) diff --git a/content/en/docs/instrumentation/java/exporters.md b/content/en/docs/instrumentation/java/exporters.md index eb18ed299935..7cc6f2e75094 100644 --- a/content/en/docs/instrumentation/java/exporters.md +++ b/content/en/docs/instrumentation/java/exporters.md @@ -128,7 +128,7 @@ public class DiceApplication { } ``` -To try out the exporters quickly, you can run Jaeger with OTLP enabled in a +To see the traces exported quickly, you can run Jaeger with OTLP enabled in a docker container: ```shell diff --git a/content/en/docs/instrumentation/java/manual.md b/content/en/docs/instrumentation/java/manual.md index b5028002d213..c3511d76cc61 100644 --- a/content/en/docs/instrumentation/java/manual.md +++ b/content/en/docs/instrumentation/java/manual.md @@ -199,8 +199,9 @@ dependencies { } ``` -Throughout this documentation you will add additional dependencies. For a full list of artificat coordinates see [releases][releases] and for semantic convention releases -see [semantic-conventions-java][semantic-conventions-java]. +Throughout this documentation you will add additional dependencies. For a full +list of artificat coordinates see [releases][releases] and for semantic +convention releases see [semantic-conventions-java][semantic-conventions-java]. {{% /tab %}} {{% tab Maven %}} @@ -225,6 +226,7 @@ see [semantic-conventions-java][semantic-conventions-java]. ``` + {{% /tab %}} {{% /tabpane %}} ### Initialize the SDK diff --git a/content/en/docs/instrumentation/java/resources.md b/content/en/docs/instrumentation/java/resources.md index d46c8f2e377b..1dd6958f8cff 100644 --- a/content/en/docs/instrumentation/java/resources.md +++ b/content/en/docs/instrumentation/java/resources.md @@ -26,7 +26,8 @@ resource detection below. ## Detecting resources from common environments You can use `ResourceProvider`s for filling in attributes related to common -environments, like [Container](/docs/specs/otel/resource/semantic_conventions/container/), +environments, like +[Container](/docs/specs/otel/resource/semantic_conventions/container/), [Host](/docs/specs/otel/resource/semantic_conventions/host/) or [Operating System](/docs/specs/otel/resource/semantic_conventions/os/). These can be used with or without From 624bb55c249e7dc7fdf8ba1b5b0e268a2d502681 Mon Sep 17 00:00:00 2001 From: svrnm Date: Wed, 13 Sep 2023 14:12:47 +0200 Subject: [PATCH 15/17] fix typo Signed-off-by: svrnm --- content/en/docs/instrumentation/java/manual.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/content/en/docs/instrumentation/java/manual.md b/content/en/docs/instrumentation/java/manual.md index c3511d76cc61..15208284f233 100644 --- a/content/en/docs/instrumentation/java/manual.md +++ b/content/en/docs/instrumentation/java/manual.md @@ -200,7 +200,7 @@ dependencies { ``` Throughout this documentation you will add additional dependencies. For a full -list of artificat coordinates see [releases][releases] and for semantic +list of artifact coordinates see [releases][releases] and for semantic convention releases see [semantic-conventions-java][semantic-conventions-java]. {{% /tab %}} {{% tab Maven %}} From 5de87c7f83e98c76ae102ed5b736c4efc0c2d583 Mon Sep 17 00:00:00 2001 From: svrnm Date: Wed, 13 Sep 2023 14:16:51 +0200 Subject: [PATCH 16/17] fix markdown issue Signed-off-by: svrnm --- .../en/docs/instrumentation/java/resources.md | 42 +++++++++---------- 1 file changed, 21 insertions(+), 21 deletions(-) diff --git a/content/en/docs/instrumentation/java/resources.md b/content/en/docs/instrumentation/java/resources.md index 1dd6958f8cff..baa15aee2329 100644 --- a/content/en/docs/instrumentation/java/resources.md +++ b/content/en/docs/instrumentation/java/resources.md @@ -86,27 +86,27 @@ import io.opentelemetry.instrumentation.resources.ProcessRuntimeResource; Custom resources can be configured in your code like the following: ```java - Resource resource = Resource.getDefault() - .merge(Resource.create(Attributes.builder() - .put(ResourceAttributes.SERVICE_NAME, "dice-service") - .put(ResourceAttributes.SERVICE_VERSION, "0.1.0") - .put(ResourceAttributes.SERVICE_INSTANCE_ID, "dice-service-1") - .put(ResourceAttributes.HOST_NAME, System.getenv("HOSTNAME")) - .put(ResourceAttributes.PROCESS_PID, ProcessHandle.current().pid()) - .build())); - - SdkTracerProvider sdkTracerProvider = SdkTracerProvider.builder() - .setResource(resource) - ... - .build(); +Resource resource = Resource.getDefault() + .merge(Resource.create(Attributes.builder() + .put(ResourceAttributes.SERVICE_NAME, "dice-service") + .put(ResourceAttributes.SERVICE_VERSION, "0.1.0") + .put(ResourceAttributes.SERVICE_INSTANCE_ID, "dice-service-1") + .put(ResourceAttributes.HOST_NAME, System.getenv("HOSTNAME")) + .put(ResourceAttributes.PROCESS_PID, ProcessHandle.current().pid()) + .build())); - SdkMeterProvider sdkMeterProvider = SdkMeterProvider.builder() - .setResource(resource) - ... - .build(); +SdkTracerProvider sdkTracerProvider = SdkTracerProvider.builder() + .setResource(resource) + ... + .build(); - SdkLoggerProvider sdkLoggerProvider = SdkLoggerProvider.builder() - .setResource(resource) - ... - .build(); +SdkMeterProvider sdkMeterProvider = SdkMeterProvider.builder() + .setResource(resource) + ... + .build(); + +SdkLoggerProvider sdkLoggerProvider = SdkLoggerProvider.builder() + .setResource(resource) + ... + .build(); ``` From 8ee2a729c28f3b77f30ed9d69035da607ce1c01b Mon Sep 17 00:00:00 2001 From: Severin Neumann Date: Wed, 13 Sep 2023 15:26:08 +0200 Subject: [PATCH 17/17] Update content/en/docs/instrumentation/java/manual.md Co-authored-by: Mateusz Rzeszutek --- content/en/docs/instrumentation/java/manual.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/content/en/docs/instrumentation/java/manual.md b/content/en/docs/instrumentation/java/manual.md index 15208284f233..5c8ba8fabf77 100644 --- a/content/en/docs/instrumentation/java/manual.md +++ b/content/en/docs/instrumentation/java/manual.md @@ -315,7 +315,7 @@ dependencies { implementation("io.opentelemetry:opentelemetry-sdk:{{% param javaVersion %}}"); implementation("io.opentelemetry:opentelemetry-sdk-metrics:{{% param javaVersion %}}"); implementation("io.opentelemetry:opentelemetry-exporter-logging:{{% param javaVersion %}}"); - implementation 'io.opentelemetry.semconv:opentelemetry-semconv:{{% param semconvJavaVersion %}}-alpha' + implementation("io.opentelemetry.semconv:opentelemetry-semconv:{{% param semconvJavaVersion %}}-alpha") implementation("opentelemetry-sdk-extension-autoconfigure:{{% param javaVersion %}}"); implementation("opentelemetry-sdk-extension-autoconfigure-spi:{{% param javaVersion %}}"); }