From c49198e1810e867ba76d7f570cd28f827fd778ae Mon Sep 17 00:00:00 2001 From: Jack Berg Date: Tue, 1 Oct 2024 12:49:24 -0500 Subject: [PATCH 01/13] Refactor java instrumentation --- content/en/docs/collector/deployment/agent.md | 2 +- .../concepts/instrumentation/libraries.md | 6 +- .../en/docs/languages/java/api-components.md | 1691 +++++++++++++++++ content/en/docs/languages/java/api.md | 4 +- .../en/docs/languages/java/configuration.md | 64 +- .../en/docs/languages/java/instrumentation.md | 1345 ++----------- content/en/docs/languages/java/sdk.md | 28 +- .../concepts/instrumentation/libraries.md | 2 +- .../concepts/instrumentation/libraries.md | 10 +- static/refcache.json | 136 ++ 10 files changed, 2073 insertions(+), 1215 deletions(-) create mode 100644 content/en/docs/languages/java/api-components.md diff --git a/content/en/docs/collector/deployment/agent.md b/content/en/docs/collector/deployment/agent.md index 2a17343c3b7b..eff8d8df82ef 100644 --- a/content/en/docs/collector/deployment/agent.md +++ b/content/en/docs/collector/deployment/agent.md @@ -129,7 +129,7 @@ Cons: [instrumentation]: /docs/languages/ [otlp]: /docs/specs/otel/protocol/ [collector]: /docs/collector/ -[instrument-java-metrics]: /docs/languages/java/instrumentation/#metrics +[instrument-java-metrics]: /docs/languages/java/api-components/#meterprovider [otlp-exporter]: /docs/specs/otel/protocol/exporter/ [java-otlp-example]: https://github.com/open-telemetry/opentelemetry-java-docs/tree/main/otlp diff --git a/content/en/docs/concepts/instrumentation/libraries.md b/content/en/docs/concepts/instrumentation/libraries.md index 9d240f97b2ad..3501730b343c 100644 --- a/content/en/docs/concepts/instrumentation/libraries.md +++ b/content/en/docs/concepts/instrumentation/libraries.md @@ -265,7 +265,7 @@ After you create a span, pass new trace context to the application code (callback or handler), by making the span active; if possible, do this explicitly. The following Java example shows how to add trace context and activate a span. See the -[Context extraction in Java](/docs/languages/java/instrumentation/#context-propagation), +[Context extraction in Java](/docs/languages/java/api-components/#contextpropagators), for more examples. ```java @@ -289,9 +289,7 @@ try (Scope unused = span.makeCurrent()) { ``` In the case of a messaging system, you might receive more than one message at -once. Received messages become -[links](/docs/languages/java/instrumentation/#create-spans-with-links) on the -span you create. Refer to +once. Received messages become links on the span you create. Refer to [messaging conventions](/docs/specs/semconv/messaging/messaging-spans/) for details. diff --git a/content/en/docs/languages/java/api-components.md b/content/en/docs/languages/java/api-components.md new file mode 100644 index 000000000000..46ff62dcd567 --- /dev/null +++ b/content/en/docs/languages/java/api-components.md @@ -0,0 +1,1691 @@ +--- +title: Record Telemetry with API +linkTitle: Record Telemetry with API +weight: 11 +logBridgeWarning: > + While the `LoggerProvider` / `Logger` APIs are structurally similar to the + equivalent trace and metric APIs, they serve a different use case. As of now, + `LoggerProvider` / `Logger` and associated classes represent the [Log Bridge + API](/docs/specs/otel/logs/bridge-api/), which exists to write log appenders + to bridge logs recorded through other log APIs / frameworks into + OpenTelemetry. They are not intended for end user use as a replacement for + Log4j / SLF4J / Logback / etc. +cSpell:ignore: Dotel kotlint Logback updowncounter +--- + + + + +The API is a set of classes and interfaces for recording telemetry across key +observability signals. The [SDK](../sdk/) is the built-in reference +implementation of the API, [configured](../configuration/) to process and export +telemetry . This page is a conceptual overview of the API, including +descriptions, links to relevant Javadocs, artifact coordinates, sample API +usage. + +The API consists of the following top level components: + +- [Context](#context-api): A standalone API for propagating context throughout + an application and across application boundaries, including trace context and + baggage. +- [TracerProvider](#tracerprovider): The API entry point for traces. +- [MeterProvider](#meterprovider): The API entry point for metrics. +- [LoggerProvider](#loggerprovider): The API entry point for logs. +- [OpenTelemetry](#opentelemetry): A holder for top level API components (i.e. + `TracerProvider`, `MeterProvider`, `LoggerProvider`, `ContextPropagators`) + which is convenient to pass to instrumentation. + +The API is designed to support multiple implementations. Two implementations are +provided by OpenTelemetry: + +- [SDK](../sdk/) reference implementation. This is the right choice for most + users. +- [Noop](#noop-implementation) implementation. A minimalist, zero dependency + implementation for instrumentations to use by default when the user doesn't + install an instance. + +The API is designed to be taken as a direct dependency by libraries, frameworks, +and application owners. It comes with +[strong backwards compatibility guarantees](https://github.com/open-telemetry/opentelemetry-java/blob/main/VERSIONING.md#compatibility-requirements), +zero transitive dependencies, and +[supports Java 8+](https://github.com/open-telemetry/opentelemetry-java/blob/main/VERSIONING.md#language-version-compatibility). +Libraries and frameworks should depend only on the API and only call methods +from the API, and instruct applications / end users to add a dependency on the +SDK and install a configured instance. + +## API Components + +The following sections describe the OpenTelemetry API. Each component section +includes: + +- A brief description, including a link to the Javadoc type reference. +- Links to relevant resources to understand the API methods and arguments. +- A simple exploration of API usage. + +## Context API + +The `io.opentelemetry:opentelemetry-api-context:{{% param vers.otel %}}` +artifact contains standalone APIs (i.e. packaged separately from +[OpenTelemetry API](#opentelemetry-api)) for propagating context throughout an +application and across application boundaries. + +It consists of: + +- [Context](#context): An immutable bundle of key value pairs which is + implicitly or explicitly propagated through an application. +- [ContextStorage](#contextstorage): A mechanism for storing and retrieving the + current context, defaulting to thread local. +- [ContextPropagators](#context): A container of registered propagators for + propagating `Context` across application boundaries. + +The `io.opentelemetry:opentelemetry-extension-kotlint:{{% param vers.otel %}}` +is an extension with tool for propagating context into coroutines. + +### Context + +[Context](https://www.javadoc.io/doc/io.opentelemetry/opentelemetry-context/latest/io/opentelemetry/context/Context.html) +is an immutable bundle of key value pairs, with utilities for implicitly +propagating through an application and across threads. Implicit propagation +means that the context can be accessed without explicitly passing it as an +argument. Context is a recurring concept in the OpenTelemetry API: + +- The current active [Span](#span) is stored in context, and by default a span's + parent is assigned to whatever span is currently in context. +- The measurements recorded to [metric instruments](#meter) accept a context + argument, used to link measurements to spans via + [exemplars](/docs/specs/otel/metrics/data-model/#exemplars) and defaulting to + whatever span is currently in context. +- [LogRecords](#logrecordbuilder) accept a context argument, used to link log + records spans and defaulting to whatever span is currently in context. + +The following code snippet explores `Context` API usage: + + + +```java +package otel; + +import io.opentelemetry.context.Context; +import io.opentelemetry.context.ContextKey; +import io.opentelemetry.context.Scope; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.TimeUnit; + +public class ContextUsage { + public static void contextUsage() throws Exception { + // Define an example context key + ContextKey exampleContextKey = ContextKey.named("example-context-key"); + + // Context doesn't contain the key until we add it + // Context.current() accesses the current context + // output => current context value: null + System.out.println("current context value: " + Context.current().get(exampleContextKey)); + + // Add entry to context + Context context = Context.current().with(exampleContextKey, "value"); + + // The local context var contains the added value + // output => context value: value + System.out.println("context value: " + context.get(exampleContextKey)); + // The current context still doesn't contain the value + // output => current context value: null + System.out.println("current context value: " + Context.current().get(exampleContextKey)); + + // Calling context.makeCurrent() sets Context.current() to the context until the scope is + // closed, upon which Context.current() is restored to the state prior to when + // context.makeCurrent() was called. The resulting Scope implements AutoCloseable and is + // normally used in a try-with-resources block. Failure to call Scope.close() is an error and + // may cause memory leaks or other issues. + try (Scope scope = context.makeCurrent()) { + // The current context now contains the added value + // output => context value: value + System.out.println("context value: " + context.get(exampleContextKey)); + } + + // The local context var still contains the added value + // output => context value: value + System.out.println("context value: " + context.get(exampleContextKey)); + // The current context no longer contains the value + // output => current context value: null + System.out.println("current context value: " + Context.current().get(exampleContextKey)); + + ExecutorService executorService = Executors.newSingleThreadExecutor(); + ScheduledExecutorService scheduledExecutorService = Executors.newScheduledThreadPool(1); + + // Context instances can be explicitly passed around application code, but its more convenient + // to use implicit context, calling Context.makeCurrent() and accessing via Context.current(). + // Context provides a number of utilities for implicit context propagation. These utilities wrap + // utility classes like Scheduler, and ExecutorService, ScheduledExecutorService, Runnable, + // Callable, Consumer, Supplier, Function, etc and modify their behavior to call + // Context.makeCurrent() before running. + context.wrap(ContextUsage::callable).call(); + context.wrap(ContextUsage::runnable).run(); + context.wrap(executorService).submit(ContextUsage::runnable); + context.wrap(scheduledExecutorService).schedule(ContextUsage::runnable, 1, TimeUnit.SECONDS); + context.wrapConsumer(ContextUsage::consumer).accept(new Object()); + context.wrapConsumer(ContextUsage::biConsumer).accept(new Object(), new Object()); + context.wrapFunction(ContextUsage::function).apply(new Object()); + context.wrapSupplier(ContextUsage::supplier).get(); + } + + /** Example {@link java.util.concurrent.Callable}. */ + private static Object callable() { + return new Object(); + } + + /** Example {@link Runnable}. */ + private static void runnable() {} + + /** Example {@link java.util.function.Consumer}. */ + private static void consumer(Object object) {} + + /** Example {@link java.util.function.BiConsumer}. */ + private static void biConsumer(Object object1, Object object2) {} + + /** Example {@link java.util.function.Function}. */ + private static Object function(Object object) { + return object; + } + + /** Example {@link java.util.function.Supplier}. */ + private static Object supplier() { + return new Object(); + } +} +``` + + +### ContextStorage + +[ContextStorage](https://www.javadoc.io/doc/io.opentelemetry/opentelemetry-context/latest/io/opentelemetry/context/ContextStorage.html) +is a mechanism for storing and retrieving the current `Context`. + +The default `ContextStorage` implementation stores `Context` in thread local. + +### ContextPropagators + +[ContextPropagators](https://www.javadoc.io/doc/io.opentelemetry/opentelemetry-context/latest/io/opentelemetry/context/propagation/ContextPropagators.html) +is a container of registered propagators for propagating `Context` across +application boundaries. Context is injected into a carrier when leaving an +application (i.e. an outbound HTTP request), and extracted from a carrier when +entering an application (i.e. serving an HTTP request). + +See [SDK TextMapPropagators](../sdk/#textmappropagator) for propagator +implementations. + +The following code snippet explores `ContextPropagators` API for injection: + + + +```java +package otel; + +import io.opentelemetry.api.baggage.propagation.W3CBaggagePropagator; +import io.opentelemetry.api.trace.propagation.W3CTraceContextPropagator; +import io.opentelemetry.context.Context; +import io.opentelemetry.context.propagation.ContextPropagators; +import io.opentelemetry.context.propagation.TextMapPropagator; +import io.opentelemetry.context.propagation.TextMapSetter; +import java.net.URI; +import java.net.http.HttpClient; +import java.net.http.HttpRequest; +import java.net.http.HttpResponse; + +public class InjectContextUsage { + private static final TextMapSetter TEXT_MAP_SETTER = new HttpRequestSetter(); + + public static void injectContextUsage() throws Exception { + // Create a ContextPropagators instance which propagates w3c trace context and w3c baggage + ContextPropagators propagators = + ContextPropagators.create( + TextMapPropagator.composite( + W3CTraceContextPropagator.getInstance(), W3CBaggagePropagator.getInstance())); + + // Create an HttpRequest builder + HttpClient httpClient = HttpClient.newBuilder().build(); + HttpRequest.Builder requestBuilder = + HttpRequest.newBuilder().uri(new URI("http://127.0.0.1:8080/resource")).GET(); + + // Given a ContextPropagators instance, inject the current context into the HTTP request carrier + propagators.getTextMapPropagator().inject(Context.current(), requestBuilder, TEXT_MAP_SETTER); + + // Send the request with the injected context + httpClient.send(requestBuilder.build(), HttpResponse.BodyHandlers.discarding()); + } + + /** {@link TextMapSetter} with a {@link HttpRequest.Builder} carrier. */ + private static class HttpRequestSetter implements TextMapSetter { + @Override + public void set(HttpRequest.Builder carrier, String key, String value) { + if (carrier == null) { + return; + } + carrier.setHeader(key, value); + } + } +} +``` + + +The following code snippet explores `ContextPropagators` API for extraction: + + + +```java +package otel; + +import com.sun.net.httpserver.HttpExchange; +import com.sun.net.httpserver.HttpHandler; +import com.sun.net.httpserver.HttpServer; +import io.opentelemetry.api.baggage.propagation.W3CBaggagePropagator; +import io.opentelemetry.api.trace.propagation.W3CTraceContextPropagator; +import io.opentelemetry.context.Context; +import io.opentelemetry.context.Scope; +import io.opentelemetry.context.propagation.ContextPropagators; +import io.opentelemetry.context.propagation.TextMapGetter; +import io.opentelemetry.context.propagation.TextMapPropagator; +import io.opentelemetry.context.propagation.TextMapSetter; +import java.io.IOException; +import java.io.OutputStream; +import java.net.InetSocketAddress; +import java.nio.charset.StandardCharsets; +import java.util.List; + +public class ExtractContextUsage { + private static final TextMapGetter TEXT_MAP_GETTER = new HttpRequestGetter(); + + public static void extractContextUsage() throws Exception { + // Create a ContextPropagators instance which propagates w3c trace context and w3c baggage + ContextPropagators propagators = + ContextPropagators.create( + TextMapPropagator.composite( + W3CTraceContextPropagator.getInstance(), W3CBaggagePropagator.getInstance())); + + // Create a server, which uses the propagators to extract context from requests + HttpServer server = HttpServer.create(new InetSocketAddress(8080), 0); + server.createContext("/path", new Handler(propagators)); + server.setExecutor(null); + server.start(); + } + + private static class Handler implements HttpHandler { + private final ContextPropagators contextPropagators; + + private Handler(ContextPropagators contextPropagators) { + this.contextPropagators = contextPropagators; + } + + @Override + public void handle(HttpExchange exchange) throws IOException { + // Extract the context from the request and make the context current + Context extractedContext = + contextPropagators + .getTextMapPropagator() + .extract(Context.current(), exchange, TEXT_MAP_GETTER); + try (Scope scope = extractedContext.makeCurrent()) { + // Do work with the extracted context + } finally { + String response = "success"; + exchange.sendResponseHeaders(200, response.length()); + OutputStream os = exchange.getResponseBody(); + os.write(response.getBytes(StandardCharsets.UTF_8)); + os.close(); + } + } + } + + /** {@link TextMapSetter} with a {@link HttpExchange} carrier. */ + private static class HttpRequestGetter implements TextMapGetter { + @Override + public Iterable keys(HttpExchange carrier) { + return carrier.getRequestHeaders().keySet(); + } + + @Override + public String get(HttpExchange carrier, String key) { + if (carrier == null) { + return null; + } + List headers = carrier.getRequestHeaders().get(key); + if (headers == null || headers.isEmpty()) { + return null; + } + return headers.get(0); + } + } +} +``` + + +## OpenTelemetry API + +The `io.opentelemetry:opentelemetry-api:{{% param vers.otel %}}` artifact +contains the OpenTelemetry API, including traces, metrics, logs, noop +implementation, baggage, key `TextMapPropagator` implementations, and a +dependency on the [context API](#context-api). + +### Providers and Scopes + +Providers and scopes are recurring concepts in the OpenTelemetry API. A scope is +a logical unit within the application which telemetry is associated with. A +provider provides components for recording telemetry relative to a particular +scope: + +- [TracerProvider](#tracerprovider) provides scoped [Tracers](#tracer) for + recording spans. +- [MeterProvider](#meterprovider) provides scoped [Meters](#meter) for recording + metrics. +- [LoggerProvider](#loggerprovider) provides scoped [Loggers](#logger) for + recording logs. + +{{% alert %}} {{% param logBridgeWarning %}} {{% /alert %}} + +A scope is identified by the triplet (name, version, schemaUrl). Care must be +taken to ensure to the scope identity is unique. A typical approach is to set +the scope name to the package name or fully qualified class name, and to set the +scope version to the library version. If emitting telemetry for multiple signals +(i.e. metrics and traces), the same scope should be used. See +[instrumentation scope](/docs/concepts/instrumentation-scope/) for details. + +The following code snippet explores provider and scope API usage: + + + +```java +package otel; + +import io.opentelemetry.api.OpenTelemetry; +import io.opentelemetry.api.logs.Logger; +import io.opentelemetry.api.logs.LoggerProvider; +import io.opentelemetry.api.metrics.Meter; +import io.opentelemetry.api.metrics.MeterProvider; +import io.opentelemetry.api.trace.Tracer; +import io.opentelemetry.api.trace.TracerProvider; + +public class ProvidersAndScopes { + + private static final String SCOPE_NAME = "fully.qualified.name"; + private static final String SCOPE_VERSION = "1.0.0"; + private static final String SCOPE_SCHEMA_URL = "https://example"; + + public static void providersUsage(OpenTelemetry openTelemetry) { + // Access providers from an OpenTelemetry instance + TracerProvider tracerProvider = openTelemetry.getTracerProvider(); + MeterProvider meterProvider = openTelemetry.getMeterProvider(); + // NOTE: LoggerProvider is a special case and should only be used to bridge logs from other + // logging APIs / frameworks into OpenTelemetry. + LoggerProvider loggerProvider = openTelemetry.getLogsBridge(); + + // Access tracer, meter, logger from providers to record telemetry for a particular scope + Tracer tracer = + tracerProvider + .tracerBuilder(SCOPE_NAME) + .setInstrumentationVersion(SCOPE_VERSION) + .setSchemaUrl(SCOPE_SCHEMA_URL) + .build(); + Meter meter = + meterProvider + .meterBuilder(SCOPE_NAME) + .setInstrumentationVersion(SCOPE_VERSION) + .setSchemaUrl(SCOPE_SCHEMA_URL) + .build(); + Logger logger = + loggerProvider + .loggerBuilder(SCOPE_NAME) + .setInstrumentationVersion(SCOPE_VERSION) + .setSchemaUrl(SCOPE_SCHEMA_URL) + .build(); + + // ...optionally, shorthand versions are available if scope version and schemaUrl aren't + // available + tracer = tracerProvider.get(SCOPE_NAME); + meter = meterProvider.get(SCOPE_NAME); + logger = loggerProvider.get(SCOPE_NAME); + } +} +``` + + +### Attributes + +[Attributes](https://www.javadoc.io/doc/io.opentelemetry/opentelemetry-api/latest/io/opentelemetry/api/common/Attributes.html) +is a bundle of key value pairs representing the +[standard attribute definition](/docs/specs/otel/common/#standard-attribute). +`Attributes` are a recurring concept in the OpenTelemetry API: + +- [Spans](#span), span events, and span links have attributes +- The measurements recorded to [metric instruments](#meter) have attributes +- [LogRecords](#logrecordbuilder) have attributes +- and more + +See [semantic attributes](#semantic-attributes) for attribute constants +generated from the semantic conventions. + +See [attribute naming](/docs/specs/semconv/general/attribute-naming/) for +guidance on attribute naming. + +The following code snippet explores `Attributes` API usage: + + + +```java +package otel; + +import io.opentelemetry.api.common.AttributeKey; +import io.opentelemetry.api.common.Attributes; +import io.opentelemetry.api.common.AttributesBuilder; +import java.util.Map; + +public class AttributesUsage { + // Establish static constant for attribute keys and reuse to avoid allocations + private static final AttributeKey SHOP_ID = AttributeKey.stringKey("com.acme.shop.id"); + private static final AttributeKey SHOP_NAME = + AttributeKey.stringKey("com.acme.shop.name"); + private static final AttributeKey CUSTOMER_ID = + AttributeKey.longKey("com.acme.customer.id"); + private static final AttributeKey CUSTOMER_NAME = + AttributeKey.stringKey("com.acme.customer.name"); + + public static void attributesUsage() { + // Use a varargs initializer and pre-allocated attribute keys. This is the most efficient way to + // create attributes. + Attributes attributes = + Attributes.of( + SHOP_ID, + "abc123", + SHOP_NAME, + "opentelemetry-demo", + CUSTOMER_ID, + 123L, + CUSTOMER_NAME, + "Jack"); + + // ...or use a builder. + attributes = + Attributes.builder() + .put(SHOP_ID, "abc123") + .put(SHOP_NAME, "opentelemetry-demo") + .put(CUSTOMER_ID, 123) + .put(CUSTOMER_NAME, "Jack") + // optionally initialize attribute keys on the fly + .put(AttributeKey.stringKey("com.acme.string-key"), "value") + .put(AttributeKey.booleanKey("com.acme.bool-key"), true) + .put(AttributeKey.longKey("com.acme.long-key"), 1L) + .put(AttributeKey.doubleKey("com.acme.double-key"), 1.1) + .put(AttributeKey.stringArrayKey("com.acme.string-array-key"), "value1", "value2") + .put(AttributeKey.booleanArrayKey("come.acme.bool-array-key"), true, false) + .put(AttributeKey.longArrayKey("come.acme.long-array-key"), 1L, 2L) + .put(AttributeKey.doubleArrayKey("come.acme.double-array-key"), 1.1, 2.2) + // optionally omit initializing AttributeKey + .put("com.acme.string-key", "value") + .put("com.acme.bool-key", true) + .put("come.acme.long-key", 1L) + .put("come.acme.double-key", 1.1) + .put("come.acme.string-array-key", "value1", "value2") + .put("come.acme.bool-array-key", true, false) + .put("come.acme.long-array-key", 1L, 2L) + .put("come.acme.double-array-key", 1.1, 2.2) + .build(); + + // Attributes has a variety of methods for manipulating and reading data. + // Read an attribute key: + String shopIdValue = attributes.get(SHOP_ID); + // Inspect size: + int size = attributes.size(); + boolean isEmpty = attributes.isEmpty(); + // Convert to a map representation: + Map, Object> map = attributes.asMap(); + // Iterate through entries, printing each to the template: (): \n + attributes.forEach( + (attributeKey, value) -> + System.out.printf( + "%s (%s): %s%n", attributeKey.getKey(), attributeKey.getType(), value)); + // Convert to a builder, remove the com.acme.customer.id and any entry whose key starts with + // com.acme.shop, and build a new instance: + AttributesBuilder builder = attributes.toBuilder(); + builder.remove(CUSTOMER_ID); + builder.removeIf(attributeKey -> attributeKey.getKey().startsWith("com.acme.shop")); + Attributes trimmedAttributes = builder.build(); + } +} +``` + + +### OpenTelemetry + +[OpenTelemetry](https://www.javadoc.io/doc/io.opentelemetry/opentelemetry-api/latest/io/opentelemetry/api/OpenTelemetry.html) +is a holder for top-level API components which is convenient to pass to +instrumentation. + +`OpenTelemetry` consists of: + +- [TracerProvider](#tracerprovider): The API entry point for traces. +- [MeterProvider](#meterprovider): The API entry point for metrics. +- [LoggerProvider](#loggerprovider): The API entry point for logs. +- [ContextPropagators](#contextpropagators): The API entry point for context + propagation. + +The following code snippet explores `OpenTelemetry` API usage: + + + +```java +package otel; + +import io.opentelemetry.api.OpenTelemetry; +import io.opentelemetry.api.common.Attributes; +import io.opentelemetry.api.logs.LoggerProvider; +import io.opentelemetry.api.metrics.MeterProvider; +import io.opentelemetry.api.trace.TracerProvider; +import io.opentelemetry.context.propagation.ContextPropagators; + +public class OpenTelemetryUsage { + private static final Attributes WIDGET_RED_CIRCLE = Util.WIDGET_RED_CIRCLE; + + public static void openTelemetryUsage(OpenTelemetry openTelemetry) { + // Access TracerProvider, MeterProvider, LoggerProvider, ContextPropagators + TracerProvider tracerProvider = openTelemetry.getTracerProvider(); + MeterProvider meterProvider = openTelemetry.getMeterProvider(); + LoggerProvider loggerProvider = openTelemetry.getLogsBridge(); + ContextPropagators propagators = openTelemetry.getPropagators(); + } +} +``` + + +### GlobalOpenTelemetry + +[GlobalOpenTelemetry](https://www.javadoc.io/doc/io.opentelemetry/opentelemetry-api/latest/io/opentelemetry/api/GlobalOpenTelemetry.html) +holds a global singleton [OpenTelemetry](#opentelemetry) instance. + +Instrumentation should avoid using `GlobalOpenTelemetry`. Instead, accept +`OpenTelemetry` as an initialization argument and default to the +[Noop implementation](#noop-implementation) if not set. There is an exception to +this rule: the `OpenTelemetry` instance installed by the +[Java agent](/docs/zero-code/java/agent/) is available via +`GlobalOpenTelemetry`. Users with additional manual instrumentation are +encouraged to access it via `GlobalOpenTelemetry.get()`. + +`GlobalOpenTelemetry.get()` is guaranteed to always return the same result. If +`GlobalOpenTelemetry.get()` is called before `GlobalOpenTelemetry.set(..)`, +`GlobalOpenTelemetry` is set to the noop implementation and future calls to +`GlobalOpenTelemetry.set(..)` throw an exception. Therefore, it's critical to +call `GlobalOpenTelemetry.set(..)` as early in the application lifecycle as +possible, and before `GlobalOpenTelemetry.get()` is called by any +instrumentation. This guarantee surfaces initialization ordering issues: calling +`GlobalOpenTelemetry.set()` too late (i.e. after instrumentation has called +`GlobalOpenTelemetry.get()`) triggers an exception rather than silently failing. + +If [autoconfigure](../configuration/#zero-code-sdk-autoconfigure) is present, +`GlobalOpenTelemetry` can be automatically initialized by setting +`-Dotel.java.global-autoconfigure.enabled=true` (or via env var +`export OTEL_JAVA_GLOBAL_AUTOCONFIGURE_ENABLED=true`). When enabled, the first +call to `GlobalOpenTelemetry.get()` triggers autoconfiguration and calls +`GlobalOpenTelemetry.set(..)` with the resulting `OpenTelemetry` instance. + +The following code snippet explores `GlobalOpenTelemetry` API context +propagation: + + + +```java +package otel; + +import io.opentelemetry.api.GlobalOpenTelemetry; +import io.opentelemetry.api.OpenTelemetry; + +public class GlobalOpenTelemetryUsage { + + public static void openTelemetryUsage(OpenTelemetry openTelemetry) { + // Set the GlobalOpenTelemetry instance as early in the application lifecycle as possible + // Set must only be called once. Calling multiple times raises an exception. + GlobalOpenTelemetry.set(openTelemetry); + + // Get the GlobalOpenTelemetry instance. + openTelemetry = GlobalOpenTelemetry.get(); + } +} +``` + + +### TracerProvider + +[TracerProvider](https://www.javadoc.io/doc/io.opentelemetry/opentelemetry-api/latest/io/opentelemetry/api/trace/TracerProvider.html) +is the API entry point for traces, and provides [Tracers](#tracer). See +[providers and scopes](#providers-and-scopes) for information on providers and +scopes. + +#### Tracer + +[Tracer](https://www.javadoc.io/doc/io.opentelemetry/opentelemetry-api/latest/io/opentelemetry/api/trace/Tracer.html) +is used to [record spans](#span) for an instrumentation scope. See +[providers and scopes](#providers-and-scopes) for information on providers and +scopes. + +#### Span + +[SpanBuilder](https://www.javadoc.io/doc/io.opentelemetry/opentelemetry-api/latest/io/opentelemetry/api/trace/SpanBuilder.html) +and +[Span](https://www.javadoc.io/doc/io.opentelemetry/opentelemetry-api/latest/io/opentelemetry/api/trace/Span.html) +are used to construct and record data to spans. + +`SpanBuilder` is used to add data to a span before starting it by calling +`Span startSpan()`. Data can be added / updated after starting by calling +various `Span` update methods. The data provided to `SpanBuilder` before +starting is provided as an input to [Samplers](../sdk/#sampler). + +The following code snippet explores `SpanBuilder` / `Span` API usage: + + + +```java +package otel; + +import static io.opentelemetry.context.Context.current; + +import io.opentelemetry.api.common.AttributeKey; +import io.opentelemetry.api.common.Attributes; +import io.opentelemetry.api.trace.Span; +import io.opentelemetry.api.trace.SpanContext; +import io.opentelemetry.api.trace.SpanKind; +import io.opentelemetry.api.trace.StatusCode; +import io.opentelemetry.api.trace.Tracer; +import java.util.Arrays; + +public class SpanUsage { + private static final Attributes WIDGET_RED_CIRCLE = Util.WIDGET_RED_CIRCLE; + + public static void spanUsage(Tracer tracer) { + // Get a span builder by providing the span name + Span span = + tracer + .spanBuilder("span name") + // Set span kind + .setSpanKind(SpanKind.INTERNAL) + // Set attributes + .setAttribute(AttributeKey.stringKey("com.acme.string-key"), "value") + .setAttribute(AttributeKey.booleanKey("com.acme.bool-key"), true) + .setAttribute(AttributeKey.longKey("com.acme.long-key"), 1L) + .setAttribute(AttributeKey.doubleKey("com.acme.double-key"), 1.1) + .setAttribute( + AttributeKey.stringArrayKey("com.acme.string-array-key"), + Arrays.asList("value1", "value2")) + .setAttribute( + AttributeKey.booleanArrayKey("come.acme.bool-array-key"), + Arrays.asList(true, false)) + .setAttribute( + AttributeKey.longArrayKey("come.acme.long-array-key"), Arrays.asList(1L, 2L)) + .setAttribute( + AttributeKey.doubleArrayKey("come.acme.double-array-key"), Arrays.asList(1.1, 2.2)) + // optionally omit initializing AttributeKey + .setAttribute("com.acme.string-key", "value") + .setAttribute("com.acme.bool-key", true) + .setAttribute("come.acme.long-key", 1L) + .setAttribute("come.acme.double-key", 1.1) + .setAllAttributes(WIDGET_RED_CIRCLE) + // Optionally explicitly set the parent span context. If omitted, the span's parent will + // be set using Context.current() + // .setParent(parentContext) + // Optionally add links + // .addLink(linkContext, linkAttributes) + // Start the span + .startSpan(); + + // Check if span is recording before computing additional data + if (span.isRecording()) { + // Update the span name with information not avilable when starting + span.updateName("new span name"); + + // Add additional attributes not available when starting + span.setAttribute("com.acme.string-key2", "value"); + + // Add additional span links not available when starting + span.addLink(exampleLinkContext()); + // optionally include attributes on the link + span.addLink(exampleLinkContext(), WIDGET_RED_CIRCLE); + + // Add span events + span.addEvent("my-event"); + // optionally include attributes on the event + span.addEvent("my-event", WIDGET_RED_CIRCLE); + + // Record exception, syntactic sugar for a span event with a specific shape + span.recordException(new RuntimeException("error")); + + // Set the span status + span.setStatus(StatusCode.OK, "status description"); + } + + // Finally, end the span + span.end(); + } + + /** Return a dummy link context. */ + private static SpanContext exampleLinkContext() { + return Span.fromContext(current()).getSpanContext(); + } +} +``` + + +Span parenting is an important aspect of tracing. Each span has an optional +parent. By collecting all the spans in a trace and following each span's parent, +we can construct a hierarchy. The span APIs are build on top of +[context](#context), which allows span context to be implicitly passed around an +application and across threads. When a span is created, its parent is set to the +whatever span is present in `Context.current()` unless there is no span or the +context is explicitly overridden. + +Most of the context API usage guidance applies to span. Span context is +propagated across application boundaries with the +[W3CTraceContextPropagator](https://www.javadoc.io/doc/io.opentelemetry/opentelemetry-api/latest/io/opentelemetry/api/trace/propagation/W3CTraceContextPropagator.html) +and other [TextMapPropagators](/docs/languages/java/sdk/#textmappropagator). + +The following code snippet explores `Span` API context propagation: + + + +```java +package otel; + +import io.opentelemetry.api.trace.Span; +import io.opentelemetry.api.trace.Tracer; +import io.opentelemetry.context.Context; +import io.opentelemetry.context.Scope; + +public class SpanAndContextUsage { + private final Tracer tracer; + + SpanAndContextUsage(Tracer tracer) { + this.tracer = tracer; + } + + public void nestedSpanUsage() { + // Start a span. Since we don't call makeCurrent(), we must explicitly call setParent on + // children. Wrap code in try / finally to ensure we end the span. + Span span = tracer.spanBuilder("span").startSpan(); + try { + // Start a child span, explicitly setting the parent. + Span childSpan = + tracer + .spanBuilder("span child") + // Explicitly set parent. + .setParent(span.storeInContext(Context.current())) + .startSpan(); + // Call makeCurrent(), adding childSpan to Context.current(). Spans created inside the scope + // will have their parent set to childSpan. + try (Scope childSpanScope = childSpan.makeCurrent()) { + // Call another method which creates a span. The span's parent will be childSpan since it is + // started in the childSpan scope. + doWork(); + } finally { + childSpan.end(); + } + } finally { + span.end(); + } + } + + private int doWork() { + Span doWorkSpan = tracer.spanBuilder("doWork").startSpan(); + try (Scope scope = doWorkSpan.makeCurrent()) { + int result = 0; + for (int i = 0; i < 10; i++) { + result += i; + } + return result; + } finally { + doWorkSpan.end(); + } + } +} +``` + + +### MeterProvider + +[MeterProvider](https://www.javadoc.io/doc/io.opentelemetry/opentelemetry-api/latest/io/opentelemetry/api/metrics/MeterProvider.html) +is the API entry point for metrics, and provides [Meters](#meter). See +[providers and scopes](#providers-and-scopes) for information on providers and +scopes. + +#### Meter + +[Meter](https://www.javadoc.io/doc/io.opentelemetry/opentelemetry-api/latest/io/opentelemetry/api/metrics/Meter.html) +is used to obtain instruments for a particular +[instrumentation scope](#providers-and-scopes). See +[providers and scopes](#providers-and-scopes) for information on providers and +scopes. There are a variety of instruments, each with different semantics and +default behavior in the SDK. Its important to choose the right instrument for +each particular use case: + +| Instrument | Sync or Async | Description | Example | Default SDK Aggregation | +| ------------------------------------------- | ------------- | ---------------------------------------------------------------------------------- | ------------------------------------------------------- | ---------------------------------------------------------------------------------------------- | +| [Counter](#counter) | sync | Record monotonic (positive) values. | Record user logins | [sum (monotonic=true)](/docs/specs/otel/metrics/sdk/#sum-aggregation) | +| [Async Counter](#async-counter) | async | Observe monotonic sums. | Observe number of classes loaded in the JVM | [sum (monotonic=true)](/docs/specs/otel/metrics/sdk/#sum-aggregation) | +| [UpDownCounter](#updowncounter) | sync | Record non-monotonic (positive and negative) values. | Record when items are added to and removed from a queue | [sum (monotonic=false)](/docs/specs/otel/metrics/sdk/#sum-aggregation) | +| [Async UpDownCounter](#async-updowncounter) | async | Observe non-monotonic (positive and negative) sums. | Observe JVM memory pool usage | [sum (monotonic=false)](/docs/specs/otel/metrics/sdk/#sum-aggregation) | +| [Histogram](#histogram) | sync | Record monotonic (positive) values where the distribution is important. | Record duration of HTTP requests processed by server | [ExplicitBucketHistogram](/docs/specs/otel/metrics/sdk/#explicit-bucket-histogram-aggregation) | +| [Gauge](#gauge) | sync | Record the latest value where spatial re-aggregation does not make sense **[1]**. | Record temperature | [LastValue](/docs/specs/otel/metrics/sdk/#last-value-aggregation) | +| [Async Gauge](#async-gauge) | async | Observe the latest value where spatial re-aggregation does not make sense **[1]**. | Observe CPU utilization | [LastValue](/docs/specs/otel/metrics/sdk/#last-value-aggregation) | + +**[1]**: Spatial re-aggregation is the process of merging attribute streams by +dropping attributes which are not needed. For example, given series with +attributes `{"color": "red", "shape": "square"}`, +`{"color": "blue", "shape": "square"}`, you can perform spatial re-aggregation +by dropping the `color` attribute, and merging the series where the attributes +are equal after dropping `color`. Most aggregations have a useful spatial +aggregation merge function (i.e. sums are summed together), but gauges +aggregated by the `LastValue` aggregation are the exception. For example, +suppose the series mentioned previously are tracking the temperature of widgets. +How do you merge the series when you drop the `color` attribute? There is no +good answer besides flipping a coin and selecting a random value. + +The instrument APIs have share a variety of features: + +- Created using the builder pattern. +- Required instrument name. +- Optional unit and description. +- Record values which are `long` or `double`, which is configured via the + builder. + +See +[metric guidelines](http://localhost:1313/docs/specs/semconv/general/metrics/#general-guidelines) +for details on metric naming and units. + +See +[guidelines for instrumentation library authors](/docs/specs/otel/metrics/supplementary-guidelines/#guidelines-for-instrumentation-library-authors) +for additional guidance on instrument selection. + +#### Counter + +[LongCounter](https://www.javadoc.io/doc/io.opentelemetry/opentelemetry-api/latest/io/opentelemetry/api/metrics/LongCounter.html) +and +[DoubleCounter](https://www.javadoc.io/doc/io.opentelemetry/opentelemetry-api/latest/io/opentelemetry/api/metrics/DoubleCounter.html) +are used to record monotonic (positive) values. + +The following code snippet explores counter API usage: + + + +```java +package otel; + +import static otel.Util.WIDGET_COLOR; +import static otel.Util.WIDGET_SHAPE; +import static otel.Util.computeWidgetColor; +import static otel.Util.computeWidgetShape; +import static otel.Util.customContext; + +import io.opentelemetry.api.common.Attributes; +import io.opentelemetry.api.metrics.LongCounter; +import io.opentelemetry.api.metrics.Meter; + +public class CounterUsage { + private static final Attributes WIDGET_RED_CIRCLE = Util.WIDGET_RED_CIRCLE; + + public static void counterUsage(Meter meter) { + // Construct a counter to record measurements that are always positive (monotonically + // increasing). + LongCounter counter = + meter + .counterBuilder("fully.qualified.counter") + .setDescription("A count of produced widgets") + .setUnit("{widget}") + // optionally change the type to double + // .ofDoubles() + .build(); + + // Record a measurement with no attributes or context. + // Attributes defaults to Attributes.empty(), context to Context.current(). + counter.add(1L); + + // Record a measurement with attributes, using pre-allocated attributes whenever possible. + counter.add(1L, WIDGET_RED_CIRCLE); + // Sometimes, attributes must be computed using application context. + counter.add( + 1L, Attributes.of(WIDGET_SHAPE, computeWidgetShape(), WIDGET_COLOR, computeWidgetColor())); + + // Record a measurement with attributes, and context. + // Most users will opt to omit the context argument, preferring the default Context.current(). + counter.add(1L, WIDGET_RED_CIRCLE, customContext()); + } +} +``` + + +#### Async Counter + +[ObservableLongCounter](https://www.javadoc.io/doc/io.opentelemetry/opentelemetry-api/latest/io/opentelemetry/api/metrics/ObservableLongCounter.htmll) +and +[ObservableDoubleCounter](https://www.javadoc.io/doc/io.opentelemetry/opentelemetry-api/latest/io/opentelemetry/api/metrics/ObservableDoubleCounter.html) +are used to observe monotonic (positive) sums. + +The following code snippet explores async counter API usage: + + + +```java +package otel; + +import static otel.Util.WIDGET_COLOR; +import static otel.Util.WIDGET_SHAPE; +import static otel.Util.computeWidgetColor; +import static otel.Util.computeWidgetShape; + +import io.opentelemetry.api.common.Attributes; +import io.opentelemetry.api.metrics.Meter; +import io.opentelemetry.api.metrics.ObservableLongCounter; +import java.util.concurrent.atomic.AtomicLong; + +public class AsyncCounterUsage { + // Pre-allocate attributes whenever possible + private static final Attributes WIDGET_RED_CIRCLE = Util.WIDGET_RED_CIRCLE; + + public static void asyncCounterUsage(Meter meter) { + AtomicLong widgetCount = new AtomicLong(); + + // Construct an async counter to observe an existing counter in a callback + ObservableLongCounter asyncCounter = + meter + .counterBuilder("fully.qualified.counter") + .setDescription("A count of produced widgets") + .setUnit("{widget}") + // optionally change the type to double + // .ofDoubles() + // the callback is invoked a MetricReader reads metrics + .buildWithCallback( + observableMeasurement -> { + long currentWidgetCount = widgetCount.get(); + + // Record a measurement with no attributes. + // Attributes defaults to Attributes.empty(). + observableMeasurement.record(currentWidgetCount); + + // Record a measurement with attributes, using pre-allocated attributes whenever + // possible. + observableMeasurement.record(currentWidgetCount, WIDGET_RED_CIRCLE); + // Sometimes, attributes must be computed using application context. + observableMeasurement.record( + currentWidgetCount, + Attributes.of( + WIDGET_SHAPE, computeWidgetShape(), WIDGET_COLOR, computeWidgetColor())); + }); + + // Optionally close the counter to unregister the callback when required + asyncCounter.close(); + } +} +``` + + +#### UpDownCounter + +[LongUpDownCounter](https://www.javadoc.io/doc/io.opentelemetry/opentelemetry-api/latest/io/opentelemetry/api/metrics/LongUpDownCounter.html) +and +[DoubleUpDownCounter](https://www.javadoc.io/doc/io.opentelemetry/opentelemetry-api/latest/io/opentelemetry/api/metrics/DoubleUpDownCounter.html) +are used to record non-monotonic (positive and negative) values. + +The following code snippet explores updowncounter API usage: + + + +```java +package otel; + +import static otel.Util.WIDGET_COLOR; +import static otel.Util.WIDGET_SHAPE; +import static otel.Util.computeWidgetColor; +import static otel.Util.computeWidgetShape; +import static otel.Util.customContext; + +import io.opentelemetry.api.common.Attributes; +import io.opentelemetry.api.metrics.LongUpDownCounter; +import io.opentelemetry.api.metrics.Meter; + +public class UpDownCounterUsage { + + private static final Attributes WIDGET_RED_CIRCLE = Util.WIDGET_RED_CIRCLE; + + public static void usage(Meter meter) { + // Construct an updowncounter to record measurements that go up and down. + LongUpDownCounter upDownCounter = + meter + .upDownCounterBuilder("fully.qualified.updowncounter") + .setDescription("Current length of widget processing queue") + .setUnit("{widget}") + // optionally change the type to double + // .ofDoubles() + .build(); + + // Record a measurement with no attributes or context. + // Attributes defaults to Attributes.empty(), context to Context.current(). + upDownCounter.add(1L); + + // Record a measurement with attributes, using pre-allocated attributes whenever possible. + upDownCounter.add(-1L, WIDGET_RED_CIRCLE); + // Sometimes, attributes must be computed using application context. + upDownCounter.add( + -1L, Attributes.of(WIDGET_SHAPE, computeWidgetShape(), WIDGET_COLOR, computeWidgetColor())); + + // Record a measurement with attributes, and context. + // Most users will opt to omit the context argument, preferring the default Context.current(). + upDownCounter.add(1L, WIDGET_RED_CIRCLE, customContext()); + } +} +``` + + +#### Async UpDownCounter + +[ObservableLongUpDownCounter](https://www.javadoc.io/doc/io.opentelemetry/opentelemetry-api/latest/io/opentelemetry/api/metrics/ObservableLongUpDownCounter.html) +and +[ObservableDoubleUpDownCounter](https://www.javadoc.io/doc/io.opentelemetry/opentelemetry-api/latest/io/opentelemetry/api/metrics/ObservableDoubleUpDownCounter.html) +are used to observe non-monotonic (positive and negative) sums. + +The following code snippet explores async updowncounter API usage: + + + +```java +package otel; + +import static otel.Util.WIDGET_COLOR; +import static otel.Util.WIDGET_SHAPE; +import static otel.Util.computeWidgetColor; +import static otel.Util.computeWidgetShape; + +import io.opentelemetry.api.common.Attributes; +import io.opentelemetry.api.metrics.Meter; +import io.opentelemetry.api.metrics.ObservableLongUpDownCounter; +import java.util.concurrent.atomic.AtomicLong; + +public class AsyncUpDownCounterUsage { + private static final Attributes WIDGET_RED_CIRCLE = Util.WIDGET_RED_CIRCLE; + + public static void asyncUpDownCounterUsage(Meter meter) { + AtomicLong queueLength = new AtomicLong(); + + // Construct an async updowncounter to observe an existing up down counter in a callback + ObservableLongUpDownCounter asyncUpDownCounter = + meter + .upDownCounterBuilder("fully.qualified.updowncounter") + .setDescription("Current length of widget processing queue") + .setUnit("{widget}") + // optionally change the type to double + // .ofDoubles() + // the callback is invoked a MetricReader reads metrics + .buildWithCallback( + observableMeasurement -> { + long currentWidgetCount = queueLength.get(); + + // Record a measurement with no attributes. + // Attributes defaults to Attributes.empty(). + observableMeasurement.record(currentWidgetCount); + + // Record a measurement with attributes, using pre-allocated attributes whenever + // possible. + observableMeasurement.record(currentWidgetCount, WIDGET_RED_CIRCLE); + // Sometimes, attributes must be computed using application context. + observableMeasurement.record( + currentWidgetCount, + Attributes.of( + WIDGET_SHAPE, computeWidgetShape(), WIDGET_COLOR, computeWidgetColor())); + }); + + // Optionally close the counter to unregister the callback when required + asyncUpDownCounter.close(); + } +} +``` + + +#### Histogram + +[DoubleHistogram](https://www.javadoc.io/doc/io.opentelemetry/opentelemetry-api/latest/io/opentelemetry/api/metrics/DoubleHistogram.html) +and +[LongHistogram](https://www.javadoc.io/doc/io.opentelemetry/opentelemetry-api/latest/io/opentelemetry/api/metrics/LongHistogram.html) +are used to record monotonic (positive) values where the distribution is +important. + +The following code snippet explores histogram API usage: + + + +```java +package otel; + +import static otel.Util.WIDGET_COLOR; +import static otel.Util.WIDGET_SHAPE; +import static otel.Util.computeWidgetColor; +import static otel.Util.computeWidgetShape; +import static otel.Util.customContext; + +import io.opentelemetry.api.common.Attributes; +import io.opentelemetry.api.metrics.DoubleHistogram; +import io.opentelemetry.api.metrics.Meter; + +public class HistogramUsage { + private static final Attributes WIDGET_RED_CIRCLE = Util.WIDGET_RED_CIRCLE; + + public static void histogramUsage(Meter meter) { + // Construct a histogram to record measurements where the distribution is important. + DoubleHistogram histogram = + meter + .histogramBuilder("fully.qualified.histogram") + .setDescription("Length of time to process a widget") + .setUnit("s") + // optionally provide advice on useful default explicit bucket boundaries + // .setExplicitBucketBoundariesAdvice(Arrays.asList(1.0, 2.0, 3.0)) + // optionally change the type to long + // .ofLongs() + .build(); + + // Record a measurement with no attributes or context. + // Attributes defaults to Attributes.empty(), context to Context.current(). + histogram.record(1.1); + + // Record a measurement with attributes, using pre-allocated attributes whenever possible. + histogram.record(2.2, WIDGET_RED_CIRCLE); + // Sometimes, attributes must be computed using application context. + histogram.record( + 3.2, Attributes.of(WIDGET_SHAPE, computeWidgetShape(), WIDGET_COLOR, computeWidgetColor())); + + // Record a measurement with attributes, and context. + // Most users will opt to omit the context argument, preferring the default Context.current(). + histogram.record(4.4, WIDGET_RED_CIRCLE, customContext()); + } +} +``` + + +#### Gauge + +[DoubleGauge](https://www.javadoc.io/doc/io.opentelemetry/opentelemetry-api/latest/io/opentelemetry/api/metrics/DoubleGauge.html) +and +[LongGauge](https://www.javadoc.io/doc/io.opentelemetry/opentelemetry-api/latest/io/opentelemetry/api/metrics/LongGauge.html) +are used to record the latest value where spatial re-aggregation does not make +sense. + +The following code snippet explores gauge API usage: + + + +```java +package otel; + +import static otel.Util.WIDGET_COLOR; +import static otel.Util.WIDGET_SHAPE; +import static otel.Util.computeWidgetColor; +import static otel.Util.computeWidgetShape; +import static otel.Util.customContext; + +import io.opentelemetry.api.common.Attributes; +import io.opentelemetry.api.metrics.DoubleGauge; +import io.opentelemetry.api.metrics.Meter; + +public class GaugeUsage { + private static final Attributes WIDGET_RED_CIRCLE = Util.WIDGET_RED_CIRCLE; + + public static void gaugeUsage(Meter meter) { + // Construct a gauge to record measurements as they occur when cannot be spatially + // re-aggregated. + DoubleGauge gauge = + meter + .gaugeBuilder("fully.qualified.gauge") + .setDescription("The current temperature of the widget processing line") + .setUnit("K") + // optionally change the type to long + // .ofLongs() + .build(); + + // Record a measurement with no attributes or context. + // Attributes defaults to Attributes.empty(), context to Context.current(). + gauge.set(273.0); + + // Record a measurement with attributes, using pre-allocated attributes whenever possible. + gauge.set(273.0, WIDGET_RED_CIRCLE); + // Sometimes, attributes must be computed using application context. + gauge.set( + 273.0, + Attributes.of(WIDGET_SHAPE, computeWidgetShape(), WIDGET_COLOR, computeWidgetColor())); + + // Record a measurement with attributes, and context. + // Most users will opt to omit the context argument, preferring the default Context.current(). + gauge.set(1L, WIDGET_RED_CIRCLE, customContext()); + } +} +``` + + +#### Async Gauge + +[ObservableDoubleGauge](https://www.javadoc.io/doc/io.opentelemetry/opentelemetry-api/latest/io/opentelemetry/api/metrics/ObservableDoubleGauge.html) +and +[ObservableLongGauge](https://www.javadoc.io/doc/io.opentelemetry/opentelemetry-api/latest/io/opentelemetry/api/metrics/ObservableLongGauge.html) +are used to observe the latest value where spatial re-aggregation does not make +sense. + +The following code snippet explores async gauge API usage: + + + +```java +package otel; + +import static otel.Util.WIDGET_COLOR; +import static otel.Util.WIDGET_SHAPE; +import static otel.Util.computeWidgetColor; +import static otel.Util.computeWidgetShape; + +import io.opentelemetry.api.common.Attributes; +import io.opentelemetry.api.metrics.Meter; +import io.opentelemetry.api.metrics.ObservableDoubleGauge; +import java.util.concurrent.atomic.AtomicReference; + +public class AsyncGaugeUsage { + private static final Attributes WIDGET_RED_CIRCLE = Util.WIDGET_RED_CIRCLE; + + public static void asyncGaugeUsage(Meter meter) { + AtomicReference processingLineTemp = new AtomicReference<>(273.0); + + // Construct an async counter to observe an existing counter in a callback + ObservableDoubleGauge asyncGauge = + meter + .gaugeBuilder("fully.qualified.gauge") + .setDescription("The current temperature of the widget processing line") + .setUnit("K") + // optionally change the type to long + // .ofLongs() + // the callback is invoked a MetricReader reads metrics + .buildWithCallback( + observableMeasurement -> { + double currentWidgetCount = processingLineTemp.get(); + + // Record a measurement with no attributes. + // Attributes defaults to Attributes.empty(). + observableMeasurement.record(currentWidgetCount); + + // Record a measurement with attributes, using pre-allocated attributes whenever + // possible. + observableMeasurement.record(currentWidgetCount, WIDGET_RED_CIRCLE); + // Sometimes, attributes must be computed using application context. + observableMeasurement.record( + currentWidgetCount, + Attributes.of( + WIDGET_SHAPE, computeWidgetShape(), WIDGET_COLOR, computeWidgetColor())); + }); + + // Optionally close the gauge to unregister the callback when required + asyncGauge.close(); + } +} +``` + + +### LoggerProvider + +[LoggerProvider](https://www.javadoc.io/doc/io.opentelemetry/opentelemetry-api/latest/io/opentelemetry/api/logs/LoggerProvider.html) +is the API entry point for logs, and provides [Loggers](#logger). See +[providers and scopes](#providers-and-scopes) for information on providers and +scopes. + +{{% alert %}} {{% param logBridgeWarning %}} {{% /alert %}} + +#### Logger + +[Logger](https://www.javadoc.io/doc/io.opentelemetry/opentelemetry-api/latest/io/opentelemetry/api/logs/Logger.html) +is used to [emit log records](#logrecordbuilder) for an +[instrumentation scope](#providers-and-scopes). See +[providers and scopes](#providers-and-scopes) for information on providers and +scopes. + +#### LogRecordBuilder + +[LogRecordBuilder](https://www.javadoc.io/doc/io.opentelemetry/opentelemetry-api/latest/io/opentelemetry/api/logs/LogRecordBuilder.html) +is used to construct and emit log records. + +The following code snippet explores `LogRecordBuilder` API usage: + + + +```java +package otel; + +import io.opentelemetry.api.common.AttributeKey; +import io.opentelemetry.api.common.Attributes; +import io.opentelemetry.api.common.Value; +import io.opentelemetry.api.logs.Logger; +import io.opentelemetry.api.logs.Severity; +import java.util.Arrays; +import java.util.Map; +import java.util.concurrent.TimeUnit; + +public class LogRecordUsage { + private static final Attributes WIDGET_RED_CIRCLE = Util.WIDGET_RED_CIRCLE; + + public static void logRecordUsage(Logger logger) { + logger + .logRecordBuilder() + // Set body. Note, setBody(..) is called multiple times for demonstration purposes but only + // the last call is used. + // Set the body to a string, syntactic sugar for setBody(Value.of("log message")) + .setBody("log message") + // Optionally set the body to a Value to record arbitrarily complex structured data + .setBody(Value.of("log message")) + .setBody(Value.of(1L)) + .setBody(Value.of(1.1)) + .setBody(Value.of(true)) + .setBody(Value.of(new byte[] {'a', 'b', 'c'})) + .setBody(Value.of(Value.of("entry1"), Value.of("entry2"))) + .setBody( + Value.of( + Map.of( + "stringKey", + Value.of("entry1"), + "mapKey", + Value.of(Map.of("stringKey", Value.of("entry2")))))) + // Set severity + .setSeverity(Severity.DEBUG) + .setSeverityText("debug") + // Set timestamp + .setTimestamp(System.currentTimeMillis(), TimeUnit.MILLISECONDS) + // Optionally set the timestamp when the log was observed + .setObservedTimestamp(System.currentTimeMillis(), TimeUnit.MILLISECONDS) + // Set attributes + .setAttribute(AttributeKey.stringKey("com.acme.string-key"), "value") + .setAttribute(AttributeKey.booleanKey("com.acme.bool-key"), true) + .setAttribute(AttributeKey.longKey("com.acme.long-key"), 1L) + .setAttribute(AttributeKey.doubleKey("com.acme.double-key"), 1.1) + .setAttribute( + AttributeKey.stringArrayKey("com.acme.string-array-key"), + Arrays.asList("value1", "value2")) + .setAttribute( + AttributeKey.booleanArrayKey("come.acme.bool-array-key"), Arrays.asList(true, false)) + .setAttribute(AttributeKey.longArrayKey("come.acme.long-array-key"), Arrays.asList(1L, 2L)) + .setAttribute( + AttributeKey.doubleArrayKey("come.acme.double-array-key"), Arrays.asList(1.1, 2.2)) + .setAllAttributes(WIDGET_RED_CIRCLE) + // Optionally explicitly set the context used to correlate with spans. If omitted, + // Context.current() is used. + // .setContext(context) + // Emit the log record + .emit(); + } +} +``` + + +### Noop implementation + +The `OpenTelemetry#noop()` method provides access to a noop implementation of +[OpenTelemetry](#opentelemetry) and all API components it provides access to. As +the name suggests, the noop implementation does nothing and is designed to have +no impact on performance. Instrumentation may see impact on performance even +when the noop is used if it is computing / allocating attribute values and other +data required to record the telemetry. The noop is a useful default instance of +`OpenTelemetry` when a user has not configured and installed a concrete +implementation such as the [SDK](/docs/languages/java/sdk/). + +The following code snippet explores `OpenTelemetry#noop()` API usage: + + + +```java +package otel; + +import static otel.Util.WIDGET_COLOR; +import static otel.Util.WIDGET_RED_CIRCLE; +import static otel.Util.WIDGET_SHAPE; + +import io.opentelemetry.api.OpenTelemetry; +import io.opentelemetry.api.common.Attributes; +import io.opentelemetry.api.logs.Logger; +import io.opentelemetry.api.logs.Severity; +import io.opentelemetry.api.metrics.DoubleGauge; +import io.opentelemetry.api.metrics.DoubleHistogram; +import io.opentelemetry.api.metrics.LongCounter; +import io.opentelemetry.api.metrics.LongUpDownCounter; +import io.opentelemetry.api.metrics.Meter; +import io.opentelemetry.api.trace.StatusCode; +import io.opentelemetry.api.trace.Tracer; + +public class NoopUsage { + private static final String SCOPE_NAME = "fully.qualified.name"; + + public static void noopUsage() { + // Access the noop OpenTelemetry instance + OpenTelemetry noopOpenTelemetry = OpenTelemetry.noop(); + + // Noop tracing + Tracer noopTracer = OpenTelemetry.noop().getTracer(SCOPE_NAME); + noopTracer + .spanBuilder("span name") + .startSpan() + .setAttribute(WIDGET_SHAPE, "square") + .setStatus(StatusCode.OK) + .addEvent("event-name", Attributes.builder().put(WIDGET_COLOR, "red").build()) + .end(); + + // Noop metrics + Attributes attributes = WIDGET_RED_CIRCLE; + Meter noopMeter = OpenTelemetry.noop().getMeter(SCOPE_NAME); + DoubleHistogram histogram = noopMeter.histogramBuilder("fully.qualified.histogram").build(); + histogram.record(1.0, attributes); + // counter + LongCounter counter = noopMeter.counterBuilder("fully.qualified.counter").build(); + counter.add(1, attributes); + // async counter + noopMeter + .counterBuilder("fully.qualified.counter") + .buildWithCallback(observable -> observable.record(10, attributes)); + // updowncounter + LongUpDownCounter upDownCounter = + noopMeter.upDownCounterBuilder("fully.qualified.updowncounter").build(); + // async updowncounter + noopMeter + .upDownCounterBuilder("fully.qualified.updowncounter") + .buildWithCallback(observable -> observable.record(10, attributes)); + upDownCounter.add(-1, attributes); + // gauge + DoubleGauge gauge = noopMeter.gaugeBuilder("fully.qualified.gauge").build(); + gauge.set(1.1, attributes); + // async gauge + noopMeter + .gaugeBuilder("fully.qualified.gauge") + .buildWithCallback(observable -> observable.record(10, attributes)); + + // Noop logs + Logger noopLogger = OpenTelemetry.noop().getLogsBridge().get(SCOPE_NAME); + noopLogger + .logRecordBuilder() + .setBody("log message") + .setAttribute(WIDGET_SHAPE, "square") + .setSeverity(Severity.INFO) + .emit(); + } +} +``` + + +### Semantic attributes + +The [semantic conventions](/docs/specs/semconv/) describe how to collect +telemetry in a standardized way for common operations. This includes an +[attribute registry](/docs/specs/semconv/attributes-registry/), which enumerates +definitions for all attributes referenced in the conventions, organized by +domain. The +[semantic-conventions-java](https://github.com/open-telemetry/semantic-conventions-java) +project generates constants from the semantic conventions, which can be used to +help instrumentation conform: + +| Description | Artifact | +| -------------------------------------------------- | -------------------------------------------------------------------------------------------- | +| Generated code for stable semantic conventions | `io.opentelemetry.semconv:opentelemetry-semconv:{{% param vers.semconv %}}-alpha` | +| Generated code for incubating semantic conventions | `io.opentelemetry.semconv:opentelemetry-semconv-incubating:{{% param vers.semconv %}}-alpha` | + +{{% alert %}} While both `opentelemetry-semconv` and +`opentelemetry-semconv-incubating` include the `-alpha` suffix and are subject +to breaking changes, the intent is to stabilize `opentelemetry-semconv` and +leave the `-alpha` suffix on `opentelemetry-semconv-incubating` permanently. +Libraries can use `opentelemetry-semconv-incubating` for testing, but should not +include it as a dependency: since attributes may come and go from version to +version, including as a dependency may expose end users to runtime errors when +transitive version conflicts occur. {{% /alert %}} + +The attribute constants generated from semantic conventions are instances of +`AttributeKey`, and can be used anywhere the OpenTelemetry API accepts +attributes. + +The following code snippet explores semantic convention attribute API usage: + + + +```java +package otel; + +import io.opentelemetry.api.common.Attributes; +import io.opentelemetry.semconv.HttpAttributes; +import io.opentelemetry.semconv.ServerAttributes; +import io.opentelemetry.semconv.incubating.HttpIncubatingAttributes; + +public class SemanticAttributesUsage { + public static void semanticAttributesUsage() { + // Semantic attributes are organized by top level domain and whether they are stable or + // incubating. + // For example: + // - stable attributes starting with http.* are in the HttpAttributes class. + // - stable attributes starting with server.* are in the ServerAttributes class. + // - incubating attributes starting with http.* are in the HttpIncubatingAttributes class. + // Attribute keys which define an enumeration of values are accessible in an inner + // {AttributeKey}Values class. + // For example, the enumeration of http.request.method values is available in the + // HttpAttributes.HttpRequestMethodValues class. + Attributes attributes = + Attributes.builder() + .put(HttpAttributes.HTTP_REQUEST_METHOD, HttpAttributes.HttpRequestMethodValues.GET) + .put(HttpAttributes.HTTP_ROUTE, "/users/:id") + .put(ServerAttributes.SERVER_ADDRESS, "example") + .put(ServerAttributes.SERVER_PORT, 8080L) + .put(HttpIncubatingAttributes.HTTP_RESPONSE_BODY_SIZE, 1024) + .build(); + } +} +``` + + +### Baggage + +[Baggage](https://www.javadoc.io/doc/io.opentelemetry/opentelemetry-api/latest/io/opentelemetry/api/baggage/Baggage.html) +is a bundle of application defined key-value pairs associated with a distributed +request or workflow execution. Baggage keys and values are strings, and values +have optional string metadata. Telemetry can be enriched with data from baggage +by configuring the [SDK](/docs/languages/java/sdk/) to add entries as attributes +to spans, metrics, and log records. The baggage API is built on top of +[context](#context), which allows span context to be implicitly passed around an +application and across threads. Most of the context API usage guidance applies +to baggage. + +Baggage is propagated across application boundaries with the +[W3CBaggagePropagator](https://www.javadoc.io/doc/io.opentelemetry/opentelemetry-api/latest/io/opentelemetry/api/baggage/propagation/W3CBaggagePropagator.html) +(see [TextMapPropagator](/docs/languages/java/sdk/#textmappropagator) for +details). + +The following code snippet explores `Baggage` API usage: + + + +```java +package otel; + +import static io.opentelemetry.context.Context.current; + +import io.opentelemetry.api.baggage.Baggage; +import io.opentelemetry.api.baggage.BaggageEntry; +import io.opentelemetry.api.baggage.BaggageEntryMetadata; +import io.opentelemetry.api.common.Attributes; +import io.opentelemetry.context.Scope; +import java.util.Map; +import java.util.stream.Collectors; + +public class BaggageUsage { + private static final Attributes WIDGET_RED_CIRCLE = Util.WIDGET_RED_CIRCLE; + + public static void baggageUsage() { + // Access current baggage with Baggage.current() + // output => context baggage: {} + Baggage currentBaggage = Baggage.current(); + System.out.println("current baggage: " + asString(currentBaggage)); + // ...or from a Context + currentBaggage = Baggage.fromContext(current()); + + // Baggage has a variety of methods for manipulating and reading data. + // Convert to builder and add entries: + Baggage newBaggage = + Baggage.current().toBuilder() + .put("shopId", "abc123") + .put("shopName", "opentelemetry-demo", BaggageEntryMetadata.create("metadata")) + .build(); + // ...or start from empty + // newBaggage = Baggage.empty().toBuilder().put("shopId", "abc123").build(); + // output => new baggage: {shopId=abc123(), shopName=opentelemetry-demo(metadata)} + System.out.println("new baggage: " + asString(newBaggage)); + // Read an entry: + String shopIdValue = newBaggage.getEntryValue("shopId"); + // Inspect size: + int size = newBaggage.size(); + boolean isEmpty = newBaggage.isEmpty(); + // Convert to map representation: + Map map = newBaggage.asMap(); + // Iterate through entries: + newBaggage.forEach((s, baggageEntry) -> {}); + + // The current baggage still doesn't contain the new entries + // output => context baggage: {} + System.out.println("current baggage: " + asString(Baggage.current())); + + // Calling Baggage.makeCurrent() sets Baggage.current() to the baggage until the scope is + // closed, upon which Baggage.current() is restored to the state prior to when + // Baggage.makeCurrent() was called. + try (Scope scope = newBaggage.makeCurrent()) { + // The current baggage now contains the added value + // output => context baggage: {shopId=abc123(), shopName=opentelemetry-demo(metadata)} + System.out.println("current baggage: " + asString(Baggage.current())); + } + + // The current baggage no longer contains the new entries: + // output => context baggage: {} + System.out.println("current baggage: " + asString(Baggage.current())); + } + + private static String asString(Baggage baggage) { + return baggage.asMap().entrySet().stream() + .map( + entry -> + String.format( + "%s=%s(%s)", + entry.getKey(), + entry.getValue().getValue(), + entry.getValue().getMetadata().getValue())) + .collect(Collectors.joining(", ", "{", "}")); + } +} +``` + + +## Incubating API + +The `io.opentelemetry:opentelemetry-api-incubator:{{% param vers.otel %}}-alpha` +artifact contains experimental trace, metric, log, and context APIs which. +Incubating APIs may have breaking API changes in minor releases. Often, these +represent experimental specification features or API designs we want to vet with +user feedback before committing to. We encourage users to try these APIs and +open issues with any feedback (positive or negative). Libraries should not +depend on the incubating APIs, since users may be exposed to runtime errors when +transitive version conflicts occur. + +See +[incubator README](https://github.com/open-telemetry/opentelemetry-java/tree/main/api/incubator) +for available APIs and sample usage. diff --git a/content/en/docs/languages/java/api.md b/content/en/docs/languages/java/api.md index 5a77f07f940e..8c8e8f079851 100644 --- a/content/en/docs/languages/java/api.md +++ b/content/en/docs/languages/java/api.md @@ -1,6 +1,6 @@ --- -title: API reference -linkTitle: API +title: Javadoc API reference +linkTitle: Javadoc redirect: https://javadoc.io/doc/io.opentelemetry manualLinkTarget: _blank _build: { render: link } diff --git a/content/en/docs/languages/java/configuration.md b/content/en/docs/languages/java/configuration.md index f73a996a8786..ba6bb9ee8890 100644 --- a/content/en/docs/languages/java/configuration.md +++ b/content/en/docs/languages/java/configuration.md @@ -1,7 +1,7 @@ --- title: Configure the SDK linkTitle: Configure the SDK -weight: 12 +weight: 13 aliases: [config] # prettier-ignore cSpell:ignore: authservice autoconfigured blrp Customizer Dotel ignore LOWMEMORY myservice ottrace PKCS retryable tracepropagators @@ -11,7 +11,7 @@ cSpell:ignore: authservice autoconfigured blrp Customizer Dotel ignore LOWMEMORY The [SDK](../sdk/) is the built-in reference implementation of the -[API](../instrumentation/), processing and exporting telemetry produced by +[API](../api-components/), processing and exporting telemetry produced by instrumentation API calls. Configuring the SDK to process and export appropriately is an essential step to integrating OpenTelemetry into an application. @@ -361,36 +361,36 @@ import java.util.Collections; public class CustomizedAutoConfiguredSdk { public static OpenTelemetrySdk autoconfiguredSdk() { return AutoConfiguredOpenTelemetrySdk.builder() - // Optionally customize TextMapPropagator. - .addPropagatorCustomizer((textMapPropagator, configProperties) -> textMapPropagator) - // Optionally customize Resource. - .addResourceCustomizer((resource, configProperties) -> resource) - // Optionally customize Sampler. - .addSamplerCustomizer((sampler, configProperties) -> sampler) - // Optionally customize SpanExporter. - .addSpanExporterCustomizer((spanExporter, configProperties) -> spanExporter) - // Optionally customize SpanProcessor. - .addSpanProcessorCustomizer((spanProcessor, configProperties) -> spanProcessor) - // Optionally supply additional properties. - .addPropertiesSupplier(Collections::emptyMap) - // Optionally customize ConfigProperties. - .addPropertiesCustomizer(configProperties -> Collections.emptyMap()) - // Optionally customize SdkTracerProviderBuilder. - .addTracerProviderCustomizer((builder, configProperties) -> builder) - // Optionally customize SdkMeterProviderBuilder. - .addMeterProviderCustomizer((builder, configProperties) -> builder) - // Optionally customize MetricExporter. - .addMetricExporterCustomizer((metricExporter, configProperties) -> metricExporter) - // Optionally customize MetricReader. - .addMetricReaderCustomizer((metricReader, configProperties) -> metricReader) - // Optionally customize SdkLoggerProviderBuilder. - .addLoggerProviderCustomizer((builder, configProperties) -> builder) - // Optionally customize LogRecordExporter. - .addLogRecordExporterCustomizer((logRecordExporter, configProperties) -> logRecordExporter) - // Optionally customize LogRecordProcessor. - .addLogRecordProcessorCustomizer((processor, configProperties) -> processor) - .build() - .getOpenTelemetrySdk(); + // Optionally customize TextMapPropagator. + .addPropagatorCustomizer((textMapPropagator, configProperties) -> textMapPropagator) + // Optionally customize Resource. + .addResourceCustomizer((resource, configProperties) -> resource) + // Optionally customize Sampler. + .addSamplerCustomizer((sampler, configProperties) -> sampler) + // Optionally customize SpanExporter. + .addSpanExporterCustomizer((spanExporter, configProperties) -> spanExporter) + // Optionally customize SpanProcessor. + .addSpanProcessorCustomizer((spanProcessor, configProperties) -> spanProcessor) + // Optionally supply additional properties. + .addPropertiesSupplier(Collections::emptyMap) + // Optionally customize ConfigProperties. + .addPropertiesCustomizer(configProperties -> Collections.emptyMap()) + // Optionally customize SdkTracerProviderBuilder. + .addTracerProviderCustomizer((builder, configProperties) -> builder) + // Optionally customize SdkMeterProviderBuilder. + .addMeterProviderCustomizer((builder, configProperties) -> builder) + // Optionally customize MetricExporter. + .addMetricExporterCustomizer((metricExporter, configProperties) -> metricExporter) + // Optionally customize MetricReader. + .addMetricReaderCustomizer((metricReader, configProperties) -> metricReader) + // Optionally customize SdkLoggerProviderBuilder. + .addLoggerProviderCustomizer((builder, configProperties) -> builder) + // Optionally customize LogRecordExporter. + .addLogRecordExporterCustomizer((logRecordExporter, configProperties) -> logRecordExporter) + // Optionally customize LogRecordProcessor. + .addLogRecordProcessorCustomizer((processor, configProperties) -> processor) + .build() + .getOpenTelemetrySdk(); } } ``` diff --git a/content/en/docs/languages/java/instrumentation.md b/content/en/docs/languages/java/instrumentation.md index f106bfc12bcc..f4a0b88b24b9 100644 --- a/content/en/docs/languages/java/instrumentation.md +++ b/content/en/docs/languages/java/instrumentation.md @@ -1,1102 +1,190 @@ --- -title: Instrumentation +title: Instrumentation ecosystem aliases: - /docs/java/getting_started - /docs/java/manual_instrumentation - manual - manual_instrumentation -weight: 20 -description: Manual instrumentation for OpenTelemetry Java -# prettier-ignore -cSpell:ignore: Autowired customizer logback loggable multivalued rolldice springframework +weight: 10 +description: Instrumentation ecosystem in OpenTelemetry Java +cSpell:ignore: Logback logback --- -{{% docs/languages/instrumentation-intro %}} +Instrumentation records telemetry using the [API](../api-components/). The +[SDK](../sdk/) is the built-in reference implementation of the API, and is +[configured](../configuration/) to process and export the telemetry produced by +instrumentation API calls. This page discusses the OpenTelemetry ecosystem in +OpenTelemetry Java, including resources for end users and cross-cutting +instrumentation topics: + +- [Instrumentation categories](#instrumentation-categories): There are a variety + of categories of instrumentation addressing different use cases and + installation patterns. +- [Context propagation](#context-propagation): Context propagation provides + correlation between traces, metrics, and logs, allowing the signals to + complement each other. +- [Semantic conventions](#semantic-conventions): The semantic conventions define + how to produce telemetry for standard operations. +- [Log instrumentation](#log-instrumentation): The semantic conventions define + how to produce telemetry for standard operations. -{{% alert title="Note" color="info" %}} See [Manage Telemetry with SDK](../sdk/) -for a conceptual overview of OpenTelemetry Java SDK concepts. See -**[Configure the SDK](../configuration/)** for details on SDK configuration, -including -[zero-code SDK autoconfigure](../configuration/#zero-code-sdk-autoconfigure). -{{% /alert %}} +## Instrumentation categories -{{% alert title="Note" color="info" %}} +There are several categories of instrumentation: -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 [zero-code instrumentation](/docs/zero-code/java/agent/) to -get started and then enrich your code with manual instrumentation as needed. +- [Zero-code: Java agent](#zero-code-java-agent) is a form of zero-code + instrumentation **[1]** that dynamically manipulates application bytecode. +- [Zero-code: Spring Boot starter](#zero-code-spring-boot-starter) is a form of + zero-code instrumentation **[1]** that leverages spring autoconfigure to + install [library instrumentation](#library-instrumentation). +- [Library instrumentation](#library-instrumentation) wraps or uses extension + points to instrument a library, requiring users to install and/or adapt + library usage. +- [Native instrumentation](#native-instrumentation) is built directly into + libraries and frameworks. +- [Manual instrumentation](#manual-instrumentation) is written by application + authors, and typically specific to the application domain. + +**[1]**: Zero-code instrumentation is installed automatically based on detected +libraries / frameworks. + +The +[opentelemetry-java-instrumentation](https://github.com/open-telemetry/opentelemetry-java-instrumentation) +project contains the source code for Java agent, Spring Boot starter, and +Library instrumentation. + +### Zero-code: Java agent + +The Java agent is a form of zero-code instrumentation that dynamically +manipulations application bytecode. + +For a list of libraries instrumented by the Java agent, see the +"Auto-instrumented versions" column on +[supported libraries](https://github.com/open-telemetry/opentelemetry-java-instrumentation/blob/main/docs/supported-libraries.md). + +See [Java agent](/docs/zero-code/java/agent/) for more details. + +### Zero-code: Spring Boot starter + +The Spring Boot starter is a form of zero-code instrumentation that leverages +spring autoconfigure to install +[library instrumentation](#library-instrumentation). + +See [Spring Boot starter](/docs/zero-code/java/spring-boot-starter/) for +details. + +### Library instrumentation + +Library instrumentation wraps or uses extension points to instrument a library, +requiring users to install and/or adapt library usage. + +For a list of instrumentation libraries, see the "Standalone Library +Instrumentation" column on +[supported libraries](https://github.com/open-telemetry/opentelemetry-java-instrumentation/blob/main/docs/supported-libraries.md). + +### Native instrumentation + +Native instrumentation is built directly into libraries or frameworks. +OpenTelemetry encourages library authors to add native instrumentation using the +[API](../api-components/). In the long term, we hope the native instrumentation +becomes the norm, and view the instrumentation maintained by OpenTelemetry in +[opentelemetry-java-instrumentation](https://github.com/open-telemetry/opentelemetry-java-instrumentation) +as a temporary means of filling the gap. + +For a list of libraries with native instrumentation, look for entries with the +"native" badge in the [registry](/ecosystem/registry/?language=java). + +### Manual instrumentation + +Manual instrumentation is written by application authors, and typically specific +to the application domain. + +### Shims + +A shim is instrumentation that bridges data from one observability library to +another, typically _from_ some library into OpenTelemetry. + +Shims maintained in the OpenTelemetry Java ecosystem: + +| Description | Documentation | Signal(s) | Artifact | +| ------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------- | ------------------------------------------------------------------------------------------------------------------------------- | +| Bridge [OpenTracing](https://opentracing.io/) into OpenTelemetry | [README](https://github.com/open-telemetry/opentelemetry-java/tree/main/opentracing-shim) | Traces | `io.opentelemetry:opentelemetry-opentracing-shim:{{% param vers.otel %}}` | +| Bridge [Opencensus](https://opencensus.io/) into OpenTelemetry | [README](https://github.com/open-telemetry/opentelemetry-java/tree/main/opencensus-shim) | Traces, Metrics | `io.opentelemetry:opentelemetry-opencensus-shim:{{% param vers.otel %}}-alpha` | +| Bridge [Micrometer](https://micrometer.io/) into OpenTelemetry | [README](https://github.com/open-telemetry/opentelemetry-java-instrumentation/tree/main/instrumentation/micrometer/micrometer-1.5/library) | Metrics | `io.opentelemetry.instrumentation:opentelemetry-micrometer-1.5:{{% param vers.instrumentation %}}-alpha` | +| Bridge [JMX](https://docs.oracle.com/javase/7/docs/technotes/guides/management/agent.html) into OpenTelemetry | [README](https://github.com/open-telemetry/opentelemetry-java-instrumentation/blob/main/instrumentation/jmx-metrics/javaagent/README.md) | Metrics | `io.opentelemetry.instrumentation:opentelemetry-jmx-metrics:{{% param vers.instrumentation %}}-alpha` | +| Bridge OpenTelemetry into [Prometheus Java client](https://github.com/prometheus/client_java) | [README](https://github.com/open-telemetry/opentelemetry-java-contrib/tree/main/prometheus-client-bridge) | Metrics | `io.opentelemetry.contrib:opentelemetry-prometheus-client-bridge:{{% param vers.contrib %}}-alpha` | +| Bridge OpenTelemetry into [Micrometer](https://micrometer.io/) | [README](https://github.com/open-telemetry/opentelemetry-java-contrib/tree/main/micrometer-meter-provider) | Metrics | `io.opentelemetry.contrib:opentelemetry-micrometer-meter-provider:{{% param vers.contrib %}}-alpha` | +| Bridge [Log4j](https://logging.apache.org/log4j/2.x/index.html) into OpenTelemetry | [README](https://github.com/open-telemetry/opentelemetry-java-instrumentation/tree/main/instrumentation/log4j/log4j-appender-2.17/library) | Logs | `io.opentelemetry.instrumentation:opentelemetry-log4j-appender-2.17:{{% param vers.instrumentation %}}-alpha` | +| Bridge [Logback](https://logback.qos.ch/) into OpenTelemetry | [README](https://github.com/open-telemetry/opentelemetry-java-instrumentation/tree/main/instrumentation/logback/logback-appender-1.0/library) | Logs | `io.opentelemetry.instrumentation:opentelemetry-logback-appender-1.0:{{% param vers.instrumentation %}}-alpha` | +| Bridge OpenTelemetry context into [Log4j](https://logging.apache.org/log4j/2.x/index.html) | [README](https://github.com/open-telemetry/opentelemetry-java-instrumentation/tree/main/instrumentation/log4j/log4j-context-data/log4j-context-data-2.17/library-autoconfigure) | Context | `io.opentelemetry.instrumentation:opentelemetry-log4j-context-data-2.17-autoconfigure:{{% param vers.instrumentation %}}-alpha` | +| Bridge OpenTelemetry context into [Logback](https://logback.qos.ch/) | [README](https://github.com/open-telemetry/opentelemetry-java-instrumentation/tree/main/instrumentation/logback/logback-mdc-1.0/library) | Context | `io.opentelemetry.instrumentation:opentelemetry-logback-mdc-1.0:{{% param vers.instrumentation %}}-alpha` | + +## Context propagation + +The OpenTelemetry APIs are designed to be complementary, with the whole greater +than the sum of the parts. Each signal has its own strengths, and collectively +stitch together a compelling observability story. + +Importantly, the data from the various signals are linked together through trace +context: -Note, that especially if you cannot modify the source code of your app, you can -skip manual instrumentation and only use automatic instrumentation. +- Spans are related to other spans through span parent and links, which each + record trace context of related spans. +- Metrics are related to spans through + [exemplars](/docs/specs/otel/metrics/data-model/#exemplars), which record + trace context of a particular measurement. +- Logs are related to spans by recording trace context on log records. + +For this correlation to work, trace context must be propagated throughout an +application (across function calls and threads), and across application +boundaries. The [context API](../api-components/#context-api) facilitates this. +Instrumentation needs to be written in a manner which is context aware: -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](../libraries/). +- Libraries that represent the entry point to an application (i.e. HTTP servers, + message consumers, etc.) should + [extract context](../api-components/#contextpropagators) from incoming + messages. +- Libraries that represent an exit point from an application (i.e. HTTP clients, + message producers, etc.) should + [inject context](../api-components/#contextpropagators) into outgoing + messages. +- Libraries should implicitly or explicitly pass + [Context](../api-components/#context) through the callstack and across any + threads. -{{% /alert %}} +## Semantic conventions -## Example app preparation {#example-app} +The [semantic conventions](/docs/specs/semconv/) define how to produce telemetry +for standard operations. Among other things, the semantic conventions specify +span names, span kinds, metric instruments, metric units, metric types, and +attribute key, value, and requirement levels. -This page uses a modified version of the example app from -[Getting Started](../getting-started/) to help you learn about manual -instrumentation. +When writing instrumentation, consult the semantic conventions and conform to +any which are applicable to the domain. -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. +OpenTelemetry Java [publishes artifacts](../api-components/#semantic-attributes) +to assist in conforming to the semantic conventions, including generated +constants for attribute keys and values. -### Prerequisites - -For running the example app, ensure that you have the following installed -locally: - -- Java JDK 17+, due to the use of Spring Boot 3. OpenTelemetry Java itself only - [requires Java 8+][java-vers]. -- [Gradle](https://gradle.org/). - -### 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 - -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 -gradle assemble -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 - -For both library and app instrumentation, the first step is to install the -dependencies for the OpenTelemetry API. - -Throughout this documentation you will add dependencies. For a full list of -artifact coordinates, see [releases]. For semantic convention releases, see -[semantic-conventions-java]. - -[releases]: https://github.com/open-telemetry/opentelemetry-java#releases -[semantic-conventions-java]: - https://github.com/open-telemetry/semantic-conventions-java/releases - -### Dependency management - -A Bill of Material -([BOM](https://maven.apache.org/guides/introduction/introduction-to-dependency-mechanism.html#bill-of-materials-bom-poms)) -ensures that versions of dependencies (including transitive ones) are aligned. -Importing the `opentelemetry-bom` BOM is important to ensure version alignment -across all OpenTelemetry dependencies. - -{{< tabpane text=true >}} {{% tab Gradle %}} - -```kotlin { hl_lines=["1-5",9] } -dependencyManagement { - imports { - mavenBom("io.opentelemetry:opentelemetry-bom:{{% param vers.otel %}}") - } -} - -dependencies { - implementation("org.springframework.boot:spring-boot-starter-web"); - implementation("io.opentelemetry:opentelemetry-api"); -} -``` - -If you are not using Spring and its `io.spring.dependency-management` dependency -management plugin, install the OpenTelemetry BOM and API using Gradle -dependencies only. - -```kotlin -dependencies { - implementation(platform("io.opentelemetry:opentelemetry-bom:{{% param vers.otel %}}")); - implementation("io.opentelemetry:opentelemetry-api"); -} -``` - -{{% /tab %}} {{% tab Maven %}} - -```xml - - - - - io.opentelemetry - opentelemetry-bom - {{% param vers.otel %}} - pom - import - - - - - - io.opentelemetry - opentelemetry-api - - - -``` - -{{% /tab %}} {{% /tabpane %}} - -## Traces - -The following sections describe the OpenTelemetry Java tracing API. See -[SdkTracerProvider](../sdk/#sdktracerprovider) for an overview of trace SDK -concepts and configuration. - -### Acquiring a tracer - -To do [Tracing](/docs/concepts/signals/traces/) you'll need to acquire a -[`Tracer`](/docs/concepts/signals/traces/#tracer). - -**Note:** Methods of the OpenTelemetry SDK should never be called. - -First, a `Tracer` must be acquired, which is responsible for creating spans and -interacting with the [Context](#context-propagation). A tracer is acquired by -using the OpenTelemetry API specifying the name and version of the [library -instrumenting][instrumentation library] the [instrumented library] or application -to be monitored. More information is available in the specification chapter [Obtaining -a -Tracer]. - -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-scope-name", "instrumentation-scope-version"); -``` - -The values of `instrumentation-scope-name` and `instrumentation-scope-version` -should uniquely identify the -[Instrumentation Scope](/docs/concepts/instrumentation-scope/), such 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 -avoid trickier application load issues when other required dependencies are -involved. - -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 { hl_lines=["4-6",11,"13-16"] } -package otel; - -// ... -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; - - @Autowired - RollController(OpenTelemetry openTelemetry) { - tracer = openTelemetry.getTracer(RollController.class.getName(), "0.1.0"); - } - // ... -} -``` - -And second, in the _library file_ `Dice.java`: - -```java { hl_lines=["2-3","9-19"]} -// ... -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 Dice(int min, int max) { - this(min, max, OpenTelemetry.noop()); - } - - // ... -} -``` - -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: - -```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. - -### Acquiring a tracer in Java agent - -If you are using the [Java agent], you can acquire a `Tracer` from the global OpenTelemetry -instance: - -```java -import io.opentelemetry.api.GlobalOpenTelemetry; - -Tracer tracer = GlobalOpenTelemetry.getTracer("application"); -``` - -If you are using Spring Boot, you can add the following bean to your -`@SpringBootApplication` class - to acquire a `Tracer` as in the -[Spring Boot starter](#acquiring-a-tracer-in-spring-boot-starter) section below: - -```java -import io.opentelemetry.api.OpenTelemetry; -import io.opentelemetry.api.GlobalOpenTelemetry; - -@Configuration -public class OpenTelemetryConfig { - @Bean - public OpenTelemetry openTelemetry() { - return GlobalOpenTelemetry.get(); - } -} -``` - -### Acquiring a tracer in Spring Boot starter - -If you are using the [Spring Boot starter], you can acquire a `Tracer` from the -autowired OpenTelemetry instance: - -```java -import io.opentelemetry.api.OpenTelemetry; -import io.opentelemetry.api.trace.Tracer; - -@Controller -public class MyController { - private final Tracer tracer; - - public MyController(OpenTelemetry openTelemetry) { - this.tracer = openTelemetry.getTracer("application"); - } -} -``` - -### 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 { hl_lines=["1-2","8-11","25-30"] } -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 - try (Scope scope = span.makeCurrent()) { - - 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; - } catch(Throwable t) { - span.recordException(t); - throw t; - } 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 -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 -``` - -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: otel.RollController:0.1.0] {} -``` - -### Create nested Spans - -Most of the time, we want to correlate -[spans](/docs/concepts/signals/traces/#spans) for nested operations. -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 example in the `Dice` class method `rollTheDice` calling method `rollOnce`, -the spans could be manually linked in the following way: - -```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(); - 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 { 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()) { - List results = new ArrayList(); - for (int i = 0; i < rolls; i++) { - results.add(this.rollOnce()); - } - return results; - } finally { - parentSpan.end(); - } - } - - 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()) { - return ThreadLocalRandom.current().nextInt(this.min, this.max + 1); - } finally { - childSpan.end(); - } - } -} -``` - -To link spans from remote processes, it is sufficient to set the -[Remote Context](#context-propagation) as parent. - -```java -Span childRemoteParent = tracer.spanBuilder("Child").setParent(remoteContext).startSpan(); -``` - -### Get the current span - -Sometimes it's helpful to do something with the current/active -[span](/docs/concepts/signals/traces/#spans) at a particular point in program -execution. - -```java -Span span = Span.current() -``` - -And if you want the current span for a particular `Context` object: - -```java -Span span = Span.fromContext(context) -``` - -### Span Attributes - -In OpenTelemetry [spans](/docs/concepts/signals/traces/#spans) can be created -freely and it's up to the implementor to annotate them with attributes specific -to the represented operation. -[Attributes](/docs/concepts/signals/traces/#attributes) provide additional -context on a span about the specific operation it tracks, such as results or -operation properties. - -```java -Span span = tracer.spanBuilder("/resource/path").setSpanKind(SpanKind.CLIENT).startSpan(); -span.setAttribute("http.method", "GET"); -span.setAttribute("http.url", url.toString()); -``` - -### Semantic Attributes - -There are semantic conventions for spans representing operations in well-known -protocols like HTTP or database calls. Semantic conventions for these spans are -defined in the specification at -[Trace Semantic Conventions](/docs/specs/semconv/general/trace/). - -First add the semantic conventions as a dependency to your application: - -{{< tabpane text=true >}} {{% tab Gradle %}} - -```kotlin -dependencies { - implementation("io.opentelemetry.semconv:opentelemetry-semconv:{{% param vers.semconv %}}-alpha") -} -``` - -{{% /tab %}} {{% tab Maven %}} - -```xml - - io.opentelemetry.semconv - opentelemetry-semconv - {{% param vers.semconv %}}-alpha - -``` - -{{% /tab %}} {{< /tabpane>}} - -Finally, you can update your file to include semantic attributes: - -```java -Span span = tracer.spanBuilder("/resource/path").setSpanKind(SpanKind.CLIENT).startSpan(); -span.setAttribute(SemanticAttributes.HTTP_METHOD, "GET"); -span.setAttribute(SemanticAttributes.HTTP_URL, url.toString()); -``` - -### Create Spans with events - -[Spans](/docs/concepts/signals/traces/#spans) can be annotated with named events -(called [Span Events](/docs/concepts/signals/traces/#span-events)) that can -carry zero or more [Span Attributes](#span-attributes), each of which itself is -a key:value map paired automatically with a timestamp. - -```java -span.addEvent("Init"); -... -span.addEvent("End"); -``` - -```java -Attributes eventAttributes = Attributes.of( - AttributeKey.stringKey("key"), "value", - AttributeKey.longKey("result"), 0L); - -span.addEvent("End Computation", eventAttributes); -``` - -### Create Spans with links - -A [Span](/docs/concepts/signals/traces/#spans) may be linked to zero or more -other Spans that are causally related via a -[Span Link](/docs/concepts/signals/traces/#span-links). Links can be used to -represent batched operations where a Span was initiated by multiple initiating -Spans, each representing a single incoming item being processed in the batch. - -```java -Span child = tracer.spanBuilder("childWithLink") - .addLink(parentSpan1.getSpanContext()) - .addLink(parentSpan2.getSpanContext()) - .addLink(parentSpan3.getSpanContext()) - .addLink(remoteSpanContext) - .startSpan(); -``` - -For more details how to read context from remote processes, see -[Context Propagation](#context-propagation). - -### Set span status - -A [status](/docs/concepts/signals/traces/#span-status) can be set on a -[span](/docs/concepts/signals/traces/#spans), typically used to specify that a -span has not completed successfully - `SpanStatus.Error`. In rare scenarios, you -could override the `Error` status with `OK`, but don't set `OK` on -successfully-completed spans. - -The status can be set at any time before the span is finished: - -```java -Span span = tracer.spanBuilder("my span").startSpan(); -// put the span into the current Context -try (Scope scope = span.makeCurrent()) { - // do something -} catch (Throwable t) { - span.setStatus(StatusCode.ERROR, "Something bad happened!"); - throw t; -} finally { - span.end(); // Cannot set a span after this call -} -``` - -### Record exceptions in spans - -It can be a good idea to record exceptions when they happen. It's recommended to -do this in conjunction with setting [span status](#set-span-status). - -```java -Span span = tracer.spanBuilder("my span").startSpan(); -// put the span into the current Context -try (Scope scope = span.makeCurrent()) { - // do something -} catch (Throwable throwable) { - span.setStatus(StatusCode.ERROR, "Something bad happened!"); - span.recordException(throwable); -} finally { - span.end(); // Cannot set a span after this call -} -``` - -This will capture things like the current stack trace in the span. - -### Context Propagation - -OpenTelemetry provides a text-based approach to propagate context to remote -services using the [W3C Trace Context](https://www.w3.org/TR/trace-context/) -HTTP headers. - -### Context propagation between threads - -The following example demonstrates how to propagate the context between threads: - -```java -io.opentelemetry.context.Context context = io.opentelemetry.context.Context.current(); -Thread thread = new Thread(context.wrap(new Runnable() { - @Override - public void run() { - // Code for which you want to propagate the context - } -})); -thread.start(); -``` - -### Context propagation between HTTP requests - -The following presents an example of an outgoing HTTP request using -`HttpURLConnection`. - -```java -// Tell OpenTelemetry to inject the context in the HTTP headers -TextMapSetter setter = - new TextMapSetter() { - @Override - public void set(HttpURLConnection carrier, String key, String value) { - // Insert the context as Header - carrier.setRequestProperty(key, value); - } -}; - -URL url = new URL("http://127.0.0.1:8080/resource"); -Span outGoing = tracer.spanBuilder("/resource").setSpanKind(SpanKind.CLIENT).startSpan(); -try (Scope scope = outGoing.makeCurrent()) { - // Use the Semantic Conventions. - // (Note that to set these, Span does not *need* to be the current instance in Context or Scope.) - outGoing.setAttribute(SemanticAttributes.HTTP_METHOD, "GET"); - outGoing.setAttribute(SemanticAttributes.HTTP_URL, url.toString()); - HttpURLConnection transportLayer = (HttpURLConnection) url.openConnection(); - // Inject the request with the *current* Context, which contains our current Span. - openTelemetry.getPropagators().getTextMapPropagator().inject(Context.current(), transportLayer, setter); - // Make outgoing call -} finally { - outGoing.end(); -} -... -``` - -Similarly, the text-based approach can be used to read the W3C Trace Context -from incoming requests. The following presents an example of processing an -incoming HTTP request using [HttpExchange][]. - -```java -TextMapGetter getter = - new TextMapGetter<>() { - @Override - public String get(HttpExchange carrier, String key) { - if (carrier.getRequestHeaders().containsKey(key)) { - return carrier.getRequestHeaders().get(key).get(0); - } - return null; - } - - @Override - public Iterable keys(HttpExchange carrier) { - return carrier.getRequestHeaders().keySet(); - } -}; -... -public void handle(HttpExchange httpExchange) { - // Extract the SpanContext and other elements from the request. - Context extractedContext = openTelemetry.getPropagators().getTextMapPropagator() - .extract(Context.current(), httpExchange, getter); - try (Scope scope = extractedContext.makeCurrent()) { - // Automatically use the extracted SpanContext as parent. - Span serverSpan = tracer.spanBuilder("GET /resource") - .setSpanKind(SpanKind.SERVER) - .startSpan(); - try { - // Add the attributes defined in the Semantic Conventions - serverSpan.setAttribute(SemanticAttributes.HTTP_METHOD, "GET"); - serverSpan.setAttribute(SemanticAttributes.HTTP_SCHEME, "http"); - serverSpan.setAttribute(SemanticAttributes.HTTP_HOST, "localhost:8080"); - serverSpan.setAttribute(SemanticAttributes.HTTP_TARGET, "/resource"); - // Serve the request - ... - } finally { - serverSpan.end(); - } - } -} -``` - -The following code presents an example to read the W3C Trace Context from -incoming request, add spans, and further propagate the context. The example -utilizes -[HttpHeaders](https://docs.oracle.com/en/java/javase/11/docs/api/java.net.http/java/net/http/HttpHeaders.html) -to fetch the traceparent header for context propagation. - -```java -TextMapGetter getter = - new TextMapGetter() { - @Override - public String get(HttpHeaders headers, String s) { - assert headers != null; - return headers.getHeaderString(s); - } - - @Override - public Iterable keys(HttpHeaders headers) { - List keys = new ArrayList<>(); - MultivaluedMap requestHeaders = headers.getRequestHeaders(); - requestHeaders.forEach((k, v) ->{ - keys.add(k); - }); - } -}; - -TextMapSetter setter = - new TextMapSetter() { - @Override - public void set(HttpURLConnection carrier, String key, String value) { - // Insert the context as Header - carrier.setRequestProperty(key, value); - } -}; - -//... -public void handle( HttpHeaders headers){ - Context extractedContext = opentelemetry.getPropagators().getTextMapPropagator() - .extract(Context.current(), headers, getter); - try (Scope scope = extractedContext.makeCurrent()) { - // Automatically use the extracted SpanContext as parent. - Span serverSpan = tracer.spanBuilder("GET /resource") - .setSpanKind(SpanKind.SERVER) - .startSpan(); - - try(Scope ignored = serverSpan.makeCurrent()) { - // Add the attributes defined in the Semantic Conventions - serverSpan.setAttribute(SemanticAttributes.HTTP_METHOD, "GET"); - serverSpan.setAttribute(SemanticAttributes.HTTP_SCHEME, "http"); - serverSpan.setAttribute(SemanticAttributes.HTTP_HOST, "localhost:8080"); - serverSpan.setAttribute(SemanticAttributes.HTTP_TARGET, "/resource"); - - HttpURLConnection transportLayer = (HttpURLConnection) url.openConnection(); - // Inject the request with the *current* Context, which contains our current Span. - openTelemetry.getPropagators().getTextMapPropagator().inject(Context.current(), transportLayer, setter); - // Make outgoing call - }finally { - serverSpan.end(); - } - } -} -``` - -## Metrics - -[Spans](/docs/concepts/signals/traces/#spans) provide detailed information about -your application, but produce data that is proportional to the load on the -system. In contrast, [metrics](/docs/concepts/signals/metrics) combine -individual measurements into aggregations, and produce data which is constant as -a function of system load. The aggregations lack details required to diagnose -low level issues, but complement spans by helping to identify trends and -providing application runtime telemetry. - -The metrics API defines a variety of instruments. Instruments record -measurements, which are aggregated by the metrics SDK and eventually exported -out of process. Instruments come in synchronous and asynchronous varieties. -Synchronous instruments record measurements as they happen. Asynchronous -instruments register a callback, which is invoked once per collection, and which -records measurements at that point in time. - -The following sections describe the OpenTelemetry Java metrics API. See -[SdkMeterProvider](../sdk/#sdkmeterprovider) for an overview of metrics SDK -concepts and configuration. - -### Acquiring a meter - -Anywhere in your application where you have manually instrumented code you can -call `opentelemetry.meterBuilder(instrumentationScopeName)` to get or create a -new meter instance using the builder pattern, or -`opentelemetry.getMeter(instrumentationScopeName)` to get or create a meter -based on just the instrument scope name. - -```java -// Get or create a named meter instance with instrumentation version using builder -Meter meter = openTelemetry.meterBuilder("dice-server") - .setInstrumentationVersion("0.1.0") - .build(); - -// Get or create a named meter instance by name only -Meter meter = openTelemetry.getMeter("dice-server"); -``` - -Now that you have [meters](/docs/concepts/signals/metrics/#meter) initialized. -you can create -[metric instruments](/docs/concepts/signals/metrics/#metric-instruments). - -### Acquiring a meter in Java agent - -If you are using the [Java agent], you can acquire a `Meter` from the global OpenTelemetry -instance: - -```java -import io.opentelemetry.api.GlobalOpenTelemetry; - -Meter meter = GlobalOpenTelemetry.getMeter("application"); -``` - -If you are using Spring Boot, you can add the following bean to your -`@SpringBootApplication` class - to acquire a `Meter` as in the -[Spring Boot starter](#acquiring-a-meter-in-spring-boot-starter) section below: - -```java -import io.opentelemetry.api.OpenTelemetry; -import io.opentelemetry.api.GlobalOpenTelemetry; - -@Configuration -public class OpenTelemetryConfig { - @Bean - public OpenTelemetry openTelemetry() { - return GlobalOpenTelemetry.get(); - } -} -``` - -### Acquiring a meter in Spring Boot starter - -If you are using the [Spring Boot starter], you can acquire a `Meter` from the -autowired OpenTelemetry instance: - -```java -import io.opentelemetry.api.OpenTelemetry; -import io.opentelemetry.api.metrics.Meter; - -@Controller -public class MyController { - private final Meter meter; - - public MyController(OpenTelemetry openTelemetry) { - this.meter = openTelemetry.getMeter("application"); - } -} -``` - -### Using Counters - -Counters can be used to measure non-negative, increasing values. - -```java -LongCounter counter = meter.counterBuilder("dice-lib.rolls.counter") - .setDescription("How many times the dice have been rolled.") - .setUnit("rolls") - .build(); - -counter.add(1, attributes); -``` - -### Using Observable (Async) Counters - -Observable counters can be used to measure an additive, non-negative, -monotonically increasing value. These counters specifically focus on the total -accumulated amount, which is gathered from external sources. Unlike synchronous -counters where each increment is recorded as it happens, observable counters -allow you to asynchronously monitor the overall sum of multiple increments. - -```java -ObservableLongCounter counter = meter.counterBuilder("dice-lib.uptime") - .buildWithCallback(measurement -> measurement.record(getUpTime())); -``` - -### Using UpDown Counters - -UpDown counters can increment and decrement, allowing you to observe a value -that goes up or down. - -```java -LongUpDownCounter counter = meter.upDownCounterBuilder("dice-lib.score") - .setDescription("Score from dice rolls.") - .setUnit("points") - .build(); - -//... - -counter.add(10, attributes); - -//... - -counter.add(-20, attributes); -``` - -### Using Observable (Async) UpDown Counters - -Observable UpDown counters can increment and decrement, allowing you to measure -an additive, non-negative, non-monotonically increasing cumulative value. These -UpDown counters specifically focus on the total accumulated amount, which is -gathered from external sources. Unlike synchronous UpDown counters where each -increment is recorded as it happens, observable counters allow you to -asynchronously monitor the overall sum of multiple increments. - -```java -ObservableDoubleUpDownCounter upDownCounter = meter.upDownCounterBuilder("dice-lib.score") - .buildWithCallback(measurement -> measurement.record(calculateScore())); -``` - -### Using Histograms - -Histograms are used to measure a distribution of values over time. - -```java -LongHistogram histogram = meter.histogramBuilder("dice-lib.rolls") - .ofLongs() // Required to get a LongHistogram, default is DoubleHistogram - .setDescription("A distribution of the value of the rolls.") - .setExplicitBucketBoundariesAdvice(Arrays.asList(1L, 2L, 3L, 4L, 5L, 6L, 7L)) - .setUnit("points") - .build(); - -histogram.record(7, attributes); -``` - -### Using Observable (Async) Gauges - -Observable Gauges should be used to measure non-additive values. - -```java -ObservableDoubleGauge gauge = meter.gaugeBuilder("jvm.memory.used") - .buildWithCallback(measurement -> measurement.record(getMemoryUsed())); -``` - -### Adding Attributes - -When you generate metrics, adding attributes creates unique metric series based -on each distinct set of attributes that receive measurements. This leads to the -concept of 'cardinality', which is the total number of unique series. -Cardinality directly affects the size of the metric payloads that are exported. -Therefore, it's important to carefully select the dimensions included in these -attributes to prevent a surge in cardinality, often referred to as 'cardinality -explosion'. - -```java -Attributes attrs = Attributes.of( - stringKey("hostname"), "i-98c3d4938", - stringKey("region"), "us-east-1"); - -histogram.record(7, attrs); -``` - -## Logs - -Logs are distinct from metrics and traces in that **there is no user-facing -OpenTelemetry logs API**. Instead, there is tooling to bridge logs from existing -popular log frameworks (e.g. SLF4j, JUL, Logback, Log4j) into the OpenTelemetry -ecosystem. For rationale behind this design decision, see -[Logging specification](/docs/specs/otel/logs/). - -The two typical workflows discussed below each cater to different application -requirements. +TODO: discuss instrumentation API and how it helps conform to semantic +conventions + +## Log instrumentation + +While the [LoggerProvider](../api-components/#loggerprovider) / +[Logger](../api-components/#logger) APIs are structurally similar to the +equivalent [trace](../api-components/#tracerprovider) and +[metric](../api-components/#meterprovider) APIs, they serve a different use +case. As of now, `LoggerProvider` / `Logger` and associated classes represent +the [Log Bridge API](/docs/specs/otel/logs/bridge-api/), which exists to write +log appenders to bridge logs recorded through other log APIs / frameworks into +OpenTelemetry. They are not intended for end user use as a replacement for Log4j +/ SLF4J / Logback / etc. + +There are two typical workflows for consuming log instrumentation in +OpenTelemetry catering to different application requirements: ### Direct to collector @@ -1104,47 +192,23 @@ In the direct to collector workflow, logs are emitted directly from an application to a collector using a network protocol (e.g. OTLP). This workflow is simple to set up as it doesn't require any additional log forwarding components, and allows an application to easily emit structured logs that -conform to the [log data model][log data model]. However, the overhead required -for applications to queue and export logs to a network location may not be -suitable for all applications. +conform to the [log data model](/docs/specs/otel/logs/data-model/). However, the +overhead required for applications to queue and export logs to a network +location may not be suitable for all applications. To use this workflow: -- Install appropriate [Log Appender](#log-appenders). +- Install appropriate log appender. **[1]** - Configure the OpenTelemetry [Log SDK](../sdk/#sdkloggerprovider) to export log records to desired target destination (the - [collector][opentelemetry collector] or other). + [collector](https://github.com/open-telemetry/opentelemetry-collector) or + other). -#### Log appenders - -A log appender bridges logs from a log framework into the OpenTelemetry -[Log SDK](../sdk/#sdkloggerprovider) using the [Logs Bridge -API][logs bridge API]. Log appenders are available for various popular Java log -frameworks: - -- [Log4j2 Appender][log4j2 appender] -- [Logback Appender][logback appender] - -The links above contain full usage and installation documentation, but -installation is generally as follows: - -- Add required dependency via gradle or maven. -- Extend the application's log configuration (i.e. `logback.xml`, `log4j.xml`, - etc) to include a reference to the OpenTelemetry log appender. - - Optionally configure the log framework to determine which logs (i.e. filter - by severity or logger name) are passed to the appender. - - Optionally configure the appender to indicate how logs are mapped to - OpenTelemetry Log Records (i.e. capture thread information, context data, - markers, etc). - -Log appenders automatically include the trace context in log records, enabling -log correlation with traces. - -The [Log Appender example][log appender example] demonstrates setup for a -variety of scenarios. - -See [SdkLoggerProvider](../sdk/#sdkloggerprovider) for an overview of log SDK -concepts and configuration. +**[1]**: Log appenders are a type of [shim](#shims) which bridges logs from a +log framework into the OpenTelemetry log SDK. See "Bridge Log4j into +OpenTelemetry", "Bridge Logback into OpenTelemetry" entries. See +[Log Appender example](https://github.com/open-telemetry/opentelemetry-java-docs/tree/main/log-appender) +for demonstration of a variety of scenarios. ### Via file or stdout @@ -1155,48 +219,11 @@ as the collector. This workflow may be preferable in situations where application requirements do not permit additional overhead from [direct to collector](#direct-to-collector). However, it requires that all log fields required down stream are encoded into the logs, and that the component -reading the logs parse the data into the [log data model][log data model]. The -installation and configuration of log forwarding components is outside the scope -of this document. - -Log correlation with traces is available by installing -[log context instrumentation](#log-context-instrumentation). - -#### Log context instrumentation - -OpenTelemetry provides components which enrich log context with trace context -for various popular Java log frameworks: - -- [Log4j context data instrumentation][log4j context instrumentation] -- [Logback MDC instrumentation][logback context instrumentation] - -This links above contain full usage and installation documentation, but -installation is generally as follows: - -- Add required dependency via gradle or maven. -- Extend the application's log configuration (i.e. `logback.xml` or `log4j.xml`, - etc) to reference the trace context fields in the log pattern. - -[httpexchange]: - https://docs.oracle.com/javase/8/docs/jre/api/net/httpserver/spec/com/sun/net/httpserver/HttpExchange.html -[java-vers]: - https://github.com/open-telemetry/opentelemetry-java/blob/main/VERSIONING.md#language-version-compatibility -[instrumentation library]: /docs/specs/otel/glossary/#instrumentation-library -[instrumented library]: /docs/specs/otel/glossary/#instrumented-library -[logs bridge API]: /docs/specs/otel/logs/bridge-api -[log data model]: /docs/specs/otel/logs/data-model -[log4j2 appender]: - https://github.com/open-telemetry/opentelemetry-java-instrumentation/tree/main/instrumentation/log4j/log4j-appender-2.17/library -[logback appender]: - https://github.com/open-telemetry/opentelemetry-java-instrumentation/tree/main/instrumentation/logback/logback-appender-1.0/library -[log appender example]: - https://github.com/open-telemetry/opentelemetry-java-docs/tree/main/log-appender -[log4j context instrumentation]: - https://github.com/open-telemetry/opentelemetry-java-instrumentation/tree/main/instrumentation/log4j/log4j-context-data/log4j-context-data-2.17/library-autoconfigure -[logback context instrumentation]: - https://github.com/open-telemetry/opentelemetry-java-instrumentation/tree/main/instrumentation/logback/logback-mdc-1.0/library -[obtaining a tracer]: /docs/specs/otel/trace/api/#get-a-tracer -[opentelemetry collector]: - https://github.com/open-telemetry/opentelemetry-collector -[Java agent]: /docs/zero-code/java/agent/ -[Spring Boot starter]: /docs/zero-code/java/spring-boot-starter/ +reading the logs parse the data into the +[log data model](/docs/specs/otel/logs/data-model). The installation and +configuration of log forwarding components is outside the scope of this +document. + +Log correlation with traces is available by installing a [shim](#shims) to +bridge OpenTelemetry context into the log framework. See "Bridge OpenTelemetry +context into Log4j", "Bridge OpenTelemetry context into Logback" entries. diff --git a/content/en/docs/languages/java/sdk.md b/content/en/docs/languages/java/sdk.md index 11aa6f478ab5..7975559ad186 100644 --- a/content/en/docs/languages/java/sdk.md +++ b/content/en/docs/languages/java/sdk.md @@ -1,6 +1,8 @@ --- title: Manage Telemetry with SDK -weight: 11 +linkTitle: Manage Telemetry with SDK +weight: 12 +aliases: [sdk-concepts] cSpell:ignore: autoconfigured FQCNs Interceptable Logback okhttp --- @@ -8,7 +10,7 @@ cSpell:ignore: autoconfigured FQCNs Interceptable Logback okhttp The SDK is the built-in reference implementation of the -[API](../instrumentation/), processing and exporting telemetry produced by +[API](../api-components/), processing and exporting telemetry produced by instrumentation API calls. This page is a conceptual overview of the SDK, including descriptions, links to relevant Javadocs, artifact coordinates, sample programmatic configurations and more. See @@ -55,6 +57,9 @@ implementing various plugin extension interfaces: ## SDK components +The `io.opentelemetry:opentelemetry-sdk:{{% param vers.otel %}}` artifact +contains the OpenTelemetry SDK. + The following sections describe the core user-facing components of the SDK. Each component section includes: @@ -72,8 +77,8 @@ component section includes: [OpenTelemetrySdk](https://www.javadoc.io/doc/io.opentelemetry/opentelemetry-sdk/latest/io/opentelemetry/sdk/OpenTelemetrySdk.html) is the SDK implementation of -[OpenTelemetry](https://www.javadoc.io/doc/io.opentelemetry/opentelemetry-api/latest/io/opentelemetry/api/OpenTelemetry.html). -It is a holder for top-level SDK components which makes it convenient to pass +[OpenTelemetry](/docs/languages/java/api-components/#opentelemetry). It is a +holder for top-level SDK components which makes it convenient to pass fully-configured SDK components to instrumentation. `OpenTelemetrySdk` is configured by the application owner, and consists of: @@ -150,8 +155,8 @@ public class ResourceConfig { [SdkTracerProvider](https://www.javadoc.io/doc/io.opentelemetry/opentelemetry-sdk-trace/latest/io/opentelemetry/sdk/trace/SdkTracerProvider.html) is the SDK implementation of -[TracerProvider](https://www.javadoc.io/doc/io.opentelemetry/opentelemetry-api/latest/io/opentelemetry/api/trace/TracerProvider.html), -and is responsible for handling trace telemetry produced by the API. +[TracerProvider](/docs/languages/java/api-components/#tracerprovider), and is +responsible for handling trace telemetry produced by the API. `SdkTracerProvider` is configured by the application owner, and consists of: @@ -558,8 +563,8 @@ public class SpanLimitsConfig { [SdkMeterProvider](https://www.javadoc.io/doc/io.opentelemetry/opentelemetry-sdk-metrics/latest/io/opentelemetry/sdk/metrics/SdkMeterProvider.html) is the SDK implementation of -[MeterProvider](https://www.javadoc.io/doc/io.opentelemetry/opentelemetry-api/latest/io/opentelemetry/api/metrics/MeterProvider.html), -and is responsible for handling metric telemetry produced by the API. +[MeterProvider](/docs/languages/java/api-components/#meterprovider), and is +responsible for handling metric telemetry produced by the API. `SdkMeterProvider` is configured by the application owner, and consists of: @@ -927,8 +932,8 @@ public class ViewConfig { [SdkLoggerProvider](https://www.javadoc.io/doc/io.opentelemetry/opentelemetry-sdk-logs/latest/io/opentelemetry/sdk/logs/SdkLoggerProvider.html) is the SDK implementation of -[LoggerProvider](https://www.javadoc.io/doc/io.opentelemetry/opentelemetry-api/latest/io/opentelemetry/api/logs/LoggerProvider.html), -and is responsible for handling log telemetry produced by the log bridge API. +[LoggerProvider](/docs/languages/java/api-components/#loggerprovider), and is +responsible for handling log telemetry produced by the log bridge API. `SdkLoggerProvider` is configured by the application owner, and consists of: @@ -1198,6 +1203,9 @@ public class LogLimitsConfig { is a [plugin extension interface](#sdk-plugin-extension-interfaces) responsible for propagating context across process boundaries in a text format. +TextMapPropagators built-in to the SDK and maintained by the community in +`opentelemetry-java-contrib`: + | Class | Artifact | Description | | --------------------------- | --------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------- | | `W3CTraceContextPropagator` | `io.opentelemetry:opentelemetry-api:{{% param vers.otel %}}` | Propagate trace context using W3C trace context propagation protocol. | diff --git a/content/ja/docs/concepts/instrumentation/libraries.md b/content/ja/docs/concepts/instrumentation/libraries.md index e7c89111f324..7c6122ae2916 100644 --- a/content/ja/docs/concepts/instrumentation/libraries.md +++ b/content/ja/docs/concepts/instrumentation/libraries.md @@ -231,7 +231,7 @@ try (Scope unused = span.makeCurrent()) { ここに[Java でのコンテキスト抽出の例](/docs/languages/java/instrumentation/#context-propagation) の完全なものがあります。 メッセージングシステムの場合、一度に複数のメッセージを受け取ることがあります。 -受信したメッセージは、作成したスパンの[_リンク_](/docs/languages/java/instrumentation/#create-spans-with-links)になります。 +受信したメッセージは、作成したスパンの*リンク*になります。 詳しくは[メッセージング規約](/docs/specs/semconv/messaging/messaging-spans/)を参照してください(警告:メッセージング規約は[策定中](https://github.com/open-telemetry/oteps/pull/173) 🚧 です)。 ### コンテキストを注入する {#injecting-context} diff --git a/content/pt/docs/concepts/instrumentation/libraries.md b/content/pt/docs/concepts/instrumentation/libraries.md index 3410ddd032f4..a2a9aa1c328e 100644 --- a/content/pt/docs/concepts/instrumentation/libraries.md +++ b/content/pt/docs/concepts/instrumentation/libraries.md @@ -309,12 +309,10 @@ Aqui estão os [exemplos completos de extração de contexto em Java](/docs/languages/java/instrumentation/#context-propagation), consulte a documentação do OpenTelemetry no seu idioma. -No caso de um sistema de mensagens, você pode receber mais de uma mensagem de -uma vez. As mensagens recebidas se tornam -[_links_](/docs/languages/java/instrumentation/#create-spans-with-links) no -trecho que você cria. Consulte as -[convenções de mensagens](/docs/specs/semconv/messaging/messaging-spans/) para -mais detalhes (AVISO: as convenções de mensagens estão +No caso de um sistema de mensagens, você pode receber mais de uma mensagem de a +vez. As mensagens recebidas se tornam _links_ no trecho que você cria. Consulte +as [convenções de mensagens](/docs/specs/semconv/messaging/messaging-spans/) +para mais detalhes (AVISO: as convenções de mensagens estão [em construção](https://github.com/open-telemetry/oteps/pull/173) 🚧). ### Injetando contexto diff --git a/static/refcache.json b/static/refcache.json index 9fc02794914b..d7639447eba3 100644 --- a/static/refcache.json +++ b/static/refcache.json @@ -3047,6 +3047,10 @@ "StatusCode": 200, "LastSeen": "2024-08-09T10:45:54.649845-04:00" }, + "https://docs.oracle.com/javase/7/docs/technotes/guides/management/agent.html": { + "StatusCode": 200, + "LastSeen": "2024-09-30T10:42:17.488566-05:00" + }, "https://docs.oracle.com/javase/8/docs/api/java/lang/Runtime.html#availableProcessors--": { "StatusCode": 200, "LastSeen": "2024-01-30T16:04:00.071297-05:00" @@ -7519,6 +7523,10 @@ "StatusCode": 200, "LastSeen": "2024-01-30T06:06:25.505322-05:00" }, + "https://github.com/prometheus/client_java": { + "StatusCode": 200, + "LastSeen": "2024-09-30T10:42:19.363961-05:00" + }, "https://github.com/prometheus/prometheus/commit/d9d51c565c622cdc7d626d3e7569652bc28abe15#diff-bdaf80ebc5fa26365f45db53435b960ce623ea6f86747fb8870ad1abc355f64fR76-R83": { "StatusCode": 200, "LastSeen": "2024-01-18T19:37:11.409183-05:00" @@ -9019,6 +9027,14 @@ "StatusCode": 200, "LastSeen": "2024-08-09T10:43:55.405438-04:00" }, + "https://logback.qos.ch/": { + "StatusCode": 206, + "LastSeen": "2024-09-30T10:42:23.585047-05:00" + }, + "https://logging.apache.org/log4j/2.x/index.html": { + "StatusCode": 206, + "LastSeen": "2024-09-30T10:42:20.642504-05:00" + }, "https://lookerstudio.google.com/s/tSTKxK1ECeU": { "StatusCode": 200, "LastSeen": "2024-03-06T14:56:05.033361-05:00" @@ -10063,6 +10079,10 @@ "StatusCode": 206, "LastSeen": "2024-01-18T19:07:33.813401-05:00" }, + "https://opentracing.io/": { + "StatusCode": 206, + "LastSeen": "2024-09-30T10:42:13.94789-05:00" + }, "https://operatorhub.io/operator/opentelemetry-operator": { "StatusCode": 206, "LastSeen": "2024-01-18T19:10:45.627677-05:00" @@ -12923,22 +12943,134 @@ "StatusCode": 200, "LastSeen": "2024-01-18T19:55:46.525923-05:00" }, + "https://www.javadoc.io/doc/io.opentelemetry/opentelemetry-api/latest/io/opentelemetry/api/GlobalOpenTelemetry.html": { + "StatusCode": 200, + "LastSeen": "2024-09-30T10:42:23.12239-05:00" + }, "https://www.javadoc.io/doc/io.opentelemetry/opentelemetry-api/latest/io/opentelemetry/api/OpenTelemetry.html": { "StatusCode": 200, "LastSeen": "2024-08-05T15:19:48.24217-05:00" }, + "https://www.javadoc.io/doc/io.opentelemetry/opentelemetry-api/latest/io/opentelemetry/api/baggage/Baggage.html": { + "StatusCode": 200, + "LastSeen": "2024-09-30T10:43:07.738549-05:00" + }, + "https://www.javadoc.io/doc/io.opentelemetry/opentelemetry-api/latest/io/opentelemetry/api/baggage/propagation/W3CBaggagePropagator.html": { + "StatusCode": 200, + "LastSeen": "2024-09-30T10:43:07.651421-05:00" + }, + "https://www.javadoc.io/doc/io.opentelemetry/opentelemetry-api/latest/io/opentelemetry/api/common/Attributes.html": { + "StatusCode": 200, + "LastSeen": "2024-09-30T10:42:20.917364-05:00" + }, + "https://www.javadoc.io/doc/io.opentelemetry/opentelemetry-api/latest/io/opentelemetry/api/logs/LogRecordBuilder.html": { + "StatusCode": 200, + "LastSeen": "2024-09-30T10:43:04.945711-05:00" + }, + "https://www.javadoc.io/doc/io.opentelemetry/opentelemetry-api/latest/io/opentelemetry/api/logs/Logger.html": { + "StatusCode": 200, + "LastSeen": "2024-09-30T10:43:01.318503-05:00" + }, "https://www.javadoc.io/doc/io.opentelemetry/opentelemetry-api/latest/io/opentelemetry/api/logs/LoggerProvider.html": { "StatusCode": 200, "LastSeen": "2024-08-05T15:59:36.584528-05:00" }, + "https://www.javadoc.io/doc/io.opentelemetry/opentelemetry-api/latest/io/opentelemetry/api/metrics/DoubleCounter.html": { + "StatusCode": 200, + "LastSeen": "2024-09-30T11:26:12.546964-05:00" + }, + "https://www.javadoc.io/doc/io.opentelemetry/opentelemetry-api/latest/io/opentelemetry/api/metrics/DoubleGauge.html": { + "StatusCode": 200, + "LastSeen": "2024-09-30T10:42:56.762156-05:00" + }, + "https://www.javadoc.io/doc/io.opentelemetry/opentelemetry-api/latest/io/opentelemetry/api/metrics/DoubleHistogram.html": { + "StatusCode": 200, + "LastSeen": "2024-09-30T10:42:51.433911-05:00" + }, + "https://www.javadoc.io/doc/io.opentelemetry/opentelemetry-api/latest/io/opentelemetry/api/metrics/DoubleUpDownCounter.html": { + "StatusCode": 200, + "LastSeen": "2024-09-30T10:42:39.724087-05:00" + }, + "https://www.javadoc.io/doc/io.opentelemetry/opentelemetry-api/latest/io/opentelemetry/api/metrics/LongCounter.html": { + "StatusCode": 200, + "LastSeen": "2024-09-30T11:26:11.401131-05:00" + }, + "https://www.javadoc.io/doc/io.opentelemetry/opentelemetry-api/latest/io/opentelemetry/api/metrics/LongGauge.html": { + "StatusCode": 200, + "LastSeen": "2024-09-30T10:42:57.12662-05:00" + }, + "https://www.javadoc.io/doc/io.opentelemetry/opentelemetry-api/latest/io/opentelemetry/api/metrics/LongHistogram.html": { + "StatusCode": 200, + "LastSeen": "2024-09-30T10:42:52.311487-05:00" + }, + "https://www.javadoc.io/doc/io.opentelemetry/opentelemetry-api/latest/io/opentelemetry/api/metrics/LongUpDownCounter.html": { + "StatusCode": 200, + "LastSeen": "2024-09-30T10:42:37.428847-05:00" + }, + "https://www.javadoc.io/doc/io.opentelemetry/opentelemetry-api/latest/io/opentelemetry/api/metrics/Meter.html": { + "StatusCode": 200, + "LastSeen": "2024-09-30T10:42:27.180222-05:00" + }, "https://www.javadoc.io/doc/io.opentelemetry/opentelemetry-api/latest/io/opentelemetry/api/metrics/MeterProvider.html": { "StatusCode": 200, "LastSeen": "2024-08-05T15:59:35.353354-05:00" }, + "https://www.javadoc.io/doc/io.opentelemetry/opentelemetry-api/latest/io/opentelemetry/api/metrics/ObservableDoubleCounter.html": { + "StatusCode": 200, + "LastSeen": "2024-09-30T10:42:35.879775-05:00" + }, + "https://www.javadoc.io/doc/io.opentelemetry/opentelemetry-api/latest/io/opentelemetry/api/metrics/ObservableDoubleGauge.html": { + "StatusCode": 200, + "LastSeen": "2024-09-30T10:42:57.769016-05:00" + }, + "https://www.javadoc.io/doc/io.opentelemetry/opentelemetry-api/latest/io/opentelemetry/api/metrics/ObservableDoubleUpDownCounter.html": { + "StatusCode": 200, + "LastSeen": "2024-09-30T10:42:49.469015-05:00" + }, + "https://www.javadoc.io/doc/io.opentelemetry/opentelemetry-api/latest/io/opentelemetry/api/metrics/ObservableLongCounter.htmll": { + "StatusCode": 200, + "LastSeen": "2024-09-30T10:42:34.290165-05:00" + }, + "https://www.javadoc.io/doc/io.opentelemetry/opentelemetry-api/latest/io/opentelemetry/api/metrics/ObservableLongGauge.html": { + "StatusCode": 200, + "LastSeen": "2024-09-30T10:43:02.724791-05:00" + }, + "https://www.javadoc.io/doc/io.opentelemetry/opentelemetry-api/latest/io/opentelemetry/api/metrics/ObservableLongUpDownCounter.html": { + "StatusCode": 200, + "LastSeen": "2024-09-30T10:42:45.458127-05:00" + }, + "https://www.javadoc.io/doc/io.opentelemetry/opentelemetry-api/latest/io/opentelemetry/api/trace/Span.html": { + "StatusCode": 200, + "LastSeen": "2024-09-30T10:42:25.46897-05:00" + }, + "https://www.javadoc.io/doc/io.opentelemetry/opentelemetry-api/latest/io/opentelemetry/api/trace/SpanBuilder.html": { + "StatusCode": 200, + "LastSeen": "2024-09-30T10:42:25.000171-05:00" + }, + "https://www.javadoc.io/doc/io.opentelemetry/opentelemetry-api/latest/io/opentelemetry/api/trace/Tracer.html": { + "StatusCode": 200, + "LastSeen": "2024-09-30T10:42:23.509988-05:00" + }, "https://www.javadoc.io/doc/io.opentelemetry/opentelemetry-api/latest/io/opentelemetry/api/trace/TracerProvider.html": { "StatusCode": 200, "LastSeen": "2024-08-05T15:19:51.603241-05:00" }, + "https://www.javadoc.io/doc/io.opentelemetry/opentelemetry-api/latest/io/opentelemetry/api/trace/propagation/W3CTraceContextPropagator.html": { + "StatusCode": 200, + "LastSeen": "2024-09-30T10:42:26.645518-05:00" + }, + "https://www.javadoc.io/doc/io.opentelemetry/opentelemetry-context/latest/io/opentelemetry/context/Context.html": { + "StatusCode": 200, + "LastSeen": "2024-09-30T10:42:14.126006-05:00" + }, + "https://www.javadoc.io/doc/io.opentelemetry/opentelemetry-context/latest/io/opentelemetry/context/ContextStorage.html": { + "StatusCode": 200, + "LastSeen": "2024-09-30T11:26:04.981525-05:00" + }, + "https://www.javadoc.io/doc/io.opentelemetry/opentelemetry-context/latest/io/opentelemetry/context/propagation/ContextPropagators.html": { + "StatusCode": 200, + "LastSeen": "2024-09-30T10:42:19.966187-05:00" + }, "https://www.javadoc.io/doc/io.opentelemetry/opentelemetry-context/latest/io/opentelemetry/context/propagation/TextMapPropagator.html": { "StatusCode": 200, "LastSeen": "2024-08-05T15:20:15.97313-05:00" @@ -13031,6 +13163,10 @@ "StatusCode": 200, "LastSeen": "2024-08-05T15:19:47.672179-05:00" }, + "https://www.javadoc.io/static/io.opentelemetry/opentelemetry-context/1.41.0/io/opentelemetry/context/ContextStorage.html": { + "StatusCode": 200, + "LastSeen": "2024-09-30T10:42:16.987832-05:00" + }, "https://www.jenkins.io": { "StatusCode": 206, "LastSeen": "2024-01-30T05:18:35.317496-05:00" From 1eb524e6d12e7a77280900c7fadc0b830c0f9c00 Mon Sep 17 00:00:00 2001 From: Jack Berg Date: Wed, 2 Oct 2024 09:07:27 -0500 Subject: [PATCH 02/13] PR feedback --- .../en/docs/languages/java/api-components.md | 19 +++++++++--------- content/en/docs/languages/java/sdk.md | 20 ++++++++----------- 2 files changed, 17 insertions(+), 22 deletions(-) diff --git a/content/en/docs/languages/java/api-components.md b/content/en/docs/languages/java/api-components.md index 46ff62dcd567..f2825fee3602 100644 --- a/content/en/docs/languages/java/api-components.md +++ b/content/en/docs/languages/java/api-components.md @@ -19,11 +19,11 @@ cSpell:ignore: Dotel kotlint Logback updowncounter The API is a set of classes and interfaces for recording telemetry across key observability signals. The [SDK](../sdk/) is the built-in reference implementation of the API, [configured](../configuration/) to process and export -telemetry . This page is a conceptual overview of the API, including +telemetry. This page is a conceptual overview of the API, including descriptions, links to relevant Javadocs, artifact coordinates, sample API usage. -The API consists of the following top level components: +The API consists of the following top-level components: - [Context](#context-api): A standalone API for propagating context throughout an application and across application boundaries, including trace context and @@ -31,7 +31,7 @@ The API consists of the following top level components: - [TracerProvider](#tracerprovider): The API entry point for traces. - [MeterProvider](#meterprovider): The API entry point for metrics. - [LoggerProvider](#loggerprovider): The API entry point for logs. -- [OpenTelemetry](#opentelemetry): A holder for top level API components (i.e. +- [OpenTelemetry](#opentelemetry): A holder for top-level API components (i.e. `TracerProvider`, `MeterProvider`, `LoggerProvider`, `ContextPropagators`) which is convenient to pass to instrumentation. @@ -40,7 +40,7 @@ provided by OpenTelemetry: - [SDK](../sdk/) reference implementation. This is the right choice for most users. -- [Noop](#noop-implementation) implementation. A minimalist, zero dependency +- [Noop](#noop-implementation) implementation. A minimalist, zero-dependency implementation for instrumentations to use by default when the user doesn't install an instance. @@ -781,7 +781,7 @@ context is explicitly overridden. Most of the context API usage guidance applies to span. Span context is propagated across application boundaries with the [W3CTraceContextPropagator](https://www.javadoc.io/doc/io.opentelemetry/opentelemetry-api/latest/io/opentelemetry/api/trace/propagation/W3CTraceContextPropagator.html) -and other [TextMapPropagators](/docs/languages/java/sdk/#textmappropagator). +and other [TextMapPropagators](../sdk/#textmappropagator). The following code snippet explores `Span` API context propagation: @@ -1427,7 +1427,7 @@ no impact on performance. Instrumentation may see impact on performance even when the noop is used if it is computing / allocating attribute values and other data required to record the telemetry. The noop is a useful default instance of `OpenTelemetry` when a user has not configured and installed a concrete -implementation such as the [SDK](/docs/languages/java/sdk/). +implementation such as the [SDK](../sdk/). The following code snippet explores `OpenTelemetry#noop()` API usage: @@ -1582,16 +1582,15 @@ public class SemanticAttributesUsage { is a bundle of application defined key-value pairs associated with a distributed request or workflow execution. Baggage keys and values are strings, and values have optional string metadata. Telemetry can be enriched with data from baggage -by configuring the [SDK](/docs/languages/java/sdk/) to add entries as attributes -to spans, metrics, and log records. The baggage API is built on top of +by configuring the [SDK](../sdk/) to add entries as attributes to spans, +metrics, and log records. The baggage API is built on top of [context](#context), which allows span context to be implicitly passed around an application and across threads. Most of the context API usage guidance applies to baggage. Baggage is propagated across application boundaries with the [W3CBaggagePropagator](https://www.javadoc.io/doc/io.opentelemetry/opentelemetry-api/latest/io/opentelemetry/api/baggage/propagation/W3CBaggagePropagator.html) -(see [TextMapPropagator](/docs/languages/java/sdk/#textmappropagator) for -details). +(see [TextMapPropagator](../sdk/#textmappropagator) for details). The following code snippet explores `Baggage` API usage: diff --git a/content/en/docs/languages/java/sdk.md b/content/en/docs/languages/java/sdk.md index 7975559ad186..f2c58896dbce 100644 --- a/content/en/docs/languages/java/sdk.md +++ b/content/en/docs/languages/java/sdk.md @@ -1,8 +1,6 @@ --- title: Manage Telemetry with SDK -linkTitle: Manage Telemetry with SDK weight: 12 -aliases: [sdk-concepts] cSpell:ignore: autoconfigured FQCNs Interceptable Logback okhttp --- @@ -76,9 +74,8 @@ component section includes: ### OpenTelemetrySdk [OpenTelemetrySdk](https://www.javadoc.io/doc/io.opentelemetry/opentelemetry-sdk/latest/io/opentelemetry/sdk/OpenTelemetrySdk.html) -is the SDK implementation of -[OpenTelemetry](/docs/languages/java/api-components/#opentelemetry). It is a -holder for top-level SDK components which makes it convenient to pass +is the SDK implementation of [OpenTelemetry](../api-components/#opentelemetry). +It is a holder for top-level SDK components which makes it convenient to pass fully-configured SDK components to instrumentation. `OpenTelemetrySdk` is configured by the application owner, and consists of: @@ -155,8 +152,8 @@ public class ResourceConfig { [SdkTracerProvider](https://www.javadoc.io/doc/io.opentelemetry/opentelemetry-sdk-trace/latest/io/opentelemetry/sdk/trace/SdkTracerProvider.html) is the SDK implementation of -[TracerProvider](/docs/languages/java/api-components/#tracerprovider), and is -responsible for handling trace telemetry produced by the API. +[TracerProvider](../api-components/#tracerprovider), and is responsible for +handling trace telemetry produced by the API. `SdkTracerProvider` is configured by the application owner, and consists of: @@ -562,9 +559,8 @@ public class SpanLimitsConfig { ### SdkMeterProvider [SdkMeterProvider](https://www.javadoc.io/doc/io.opentelemetry/opentelemetry-sdk-metrics/latest/io/opentelemetry/sdk/metrics/SdkMeterProvider.html) -is the SDK implementation of -[MeterProvider](/docs/languages/java/api-components/#meterprovider), and is -responsible for handling metric telemetry produced by the API. +is the SDK implementation of [MeterProvider](../api-components/#meterprovider), +and is responsible for handling metric telemetry produced by the API. `SdkMeterProvider` is configured by the application owner, and consists of: @@ -932,8 +928,8 @@ public class ViewConfig { [SdkLoggerProvider](https://www.javadoc.io/doc/io.opentelemetry/opentelemetry-sdk-logs/latest/io/opentelemetry/sdk/logs/SdkLoggerProvider.html) is the SDK implementation of -[LoggerProvider](/docs/languages/java/api-components/#loggerprovider), and is -responsible for handling log telemetry produced by the log bridge API. +[LoggerProvider](../api-components/#loggerprovider), and is responsible for +handling log telemetry produced by the log bridge API. `SdkLoggerProvider` is configured by the application owner, and consists of: From d422675c7e19ef0c5f8ac2d99d2a02274d75f9b2 Mon Sep 17 00:00:00 2001 From: Jack Berg Date: Wed, 2 Oct 2024 09:09:26 -0500 Subject: [PATCH 03/13] Revert link updates to i18n pages --- content/ja/docs/concepts/instrumentation/libraries.md | 2 +- content/pt/docs/concepts/instrumentation/libraries.md | 10 ++++++---- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/content/ja/docs/concepts/instrumentation/libraries.md b/content/ja/docs/concepts/instrumentation/libraries.md index 7c6122ae2916..e7c89111f324 100644 --- a/content/ja/docs/concepts/instrumentation/libraries.md +++ b/content/ja/docs/concepts/instrumentation/libraries.md @@ -231,7 +231,7 @@ try (Scope unused = span.makeCurrent()) { ここに[Java でのコンテキスト抽出の例](/docs/languages/java/instrumentation/#context-propagation) の完全なものがあります。 メッセージングシステムの場合、一度に複数のメッセージを受け取ることがあります。 -受信したメッセージは、作成したスパンの*リンク*になります。 +受信したメッセージは、作成したスパンの[_リンク_](/docs/languages/java/instrumentation/#create-spans-with-links)になります。 詳しくは[メッセージング規約](/docs/specs/semconv/messaging/messaging-spans/)を参照してください(警告:メッセージング規約は[策定中](https://github.com/open-telemetry/oteps/pull/173) 🚧 です)。 ### コンテキストを注入する {#injecting-context} diff --git a/content/pt/docs/concepts/instrumentation/libraries.md b/content/pt/docs/concepts/instrumentation/libraries.md index a2a9aa1c328e..3410ddd032f4 100644 --- a/content/pt/docs/concepts/instrumentation/libraries.md +++ b/content/pt/docs/concepts/instrumentation/libraries.md @@ -309,10 +309,12 @@ Aqui estão os [exemplos completos de extração de contexto em Java](/docs/languages/java/instrumentation/#context-propagation), consulte a documentação do OpenTelemetry no seu idioma. -No caso de um sistema de mensagens, você pode receber mais de uma mensagem de a -vez. As mensagens recebidas se tornam _links_ no trecho que você cria. Consulte -as [convenções de mensagens](/docs/specs/semconv/messaging/messaging-spans/) -para mais detalhes (AVISO: as convenções de mensagens estão +No caso de um sistema de mensagens, você pode receber mais de uma mensagem de +uma vez. As mensagens recebidas se tornam +[_links_](/docs/languages/java/instrumentation/#create-spans-with-links) no +trecho que você cria. Consulte as +[convenções de mensagens](/docs/specs/semconv/messaging/messaging-spans/) para +mais detalhes (AVISO: as convenções de mensagens estão [em construção](https://github.com/open-telemetry/oteps/pull/173) 🚧). ### Injetando contexto From 292638251cc1ec0958952f9340b0cfbf1de4b0a6 Mon Sep 17 00:00:00 2001 From: Jack Berg Date: Wed, 2 Oct 2024 14:37:54 -0500 Subject: [PATCH 04/13] Update opentelemetry-java-examples and code excerpts to latest --- content-modules/opentelemetry-java-examples | 2 +- .../en/docs/languages/java/api-components.md | 42 ++++++------- .../en/docs/languages/java/configuration.md | 60 +++++++++---------- 3 files changed, 52 insertions(+), 52 deletions(-) diff --git a/content-modules/opentelemetry-java-examples b/content-modules/opentelemetry-java-examples index 8fe9a11a33af..dd12ee9dc30f 160000 --- a/content-modules/opentelemetry-java-examples +++ b/content-modules/opentelemetry-java-examples @@ -1 +1 @@ -Subproject commit 8fe9a11a33affcc4942f2df6668cd6ce787cde3f +Subproject commit dd12ee9dc30ff6370f5c238336e478d49fc3a4ba diff --git a/content/en/docs/languages/java/api-components.md b/content/en/docs/languages/java/api-components.md index f2825fee3602..2e15aaf6f6c0 100644 --- a/content/en/docs/languages/java/api-components.md +++ b/content/en/docs/languages/java/api-components.md @@ -509,7 +509,7 @@ public class AttributesUsage { .put(SHOP_NAME, "opentelemetry-demo") .put(CUSTOMER_ID, 123) .put(CUSTOMER_NAME, "Jack") - // optionally initialize attribute keys on the fly + // Optionally initialize attribute keys on the fly .put(AttributeKey.stringKey("com.acme.string-key"), "value") .put(AttributeKey.booleanKey("com.acme.bool-key"), true) .put(AttributeKey.longKey("com.acme.long-key"), 1L) @@ -518,7 +518,7 @@ public class AttributesUsage { .put(AttributeKey.booleanArrayKey("come.acme.bool-array-key"), true, false) .put(AttributeKey.longArrayKey("come.acme.long-array-key"), 1L, 2L) .put(AttributeKey.doubleArrayKey("come.acme.double-array-key"), 1.1, 2.2) - // optionally omit initializing AttributeKey + // Optionally omit initializing AttributeKey .put("com.acme.string-key", "value") .put("com.acme.bool-key", true) .put("come.acme.long-key", 1L) @@ -719,23 +719,23 @@ public class SpanUsage { AttributeKey.longArrayKey("come.acme.long-array-key"), Arrays.asList(1L, 2L)) .setAttribute( AttributeKey.doubleArrayKey("come.acme.double-array-key"), Arrays.asList(1.1, 2.2)) - // optionally omit initializing AttributeKey + // Optionally omit initializing AttributeKey .setAttribute("com.acme.string-key", "value") .setAttribute("com.acme.bool-key", true) .setAttribute("come.acme.long-key", 1L) .setAttribute("come.acme.double-key", 1.1) .setAllAttributes(WIDGET_RED_CIRCLE) - // Optionally explicitly set the parent span context. If omitted, the span's parent will - // be set using Context.current() + // Uncomment to optionally explicitly set the parent span context. If omitted, the + // span's parent will be set using Context.current(). // .setParent(parentContext) - // Optionally add links + // Uncomment to optionally add links. // .addLink(linkContext, linkAttributes) // Start the span .startSpan(); // Check if span is recording before computing additional data if (span.isRecording()) { - // Update the span name with information not avilable when starting + // Update the span name with information not available when starting span.updateName("new span name"); // Add additional attributes not available when starting @@ -993,10 +993,10 @@ public class AsyncCounterUsage { .counterBuilder("fully.qualified.counter") .setDescription("A count of produced widgets") .setUnit("{widget}") - // optionally change the type to double + // Uncomment to optionally change the type to double // .ofDoubles() - // the callback is invoked a MetricReader reads metrics .buildWithCallback( + // the callback is invoked a MetricReader reads metrics observableMeasurement -> { long currentWidgetCount = widgetCount.get(); @@ -1056,7 +1056,7 @@ public class UpDownCounterUsage { .upDownCounterBuilder("fully.qualified.updowncounter") .setDescription("Current length of widget processing queue") .setUnit("{widget}") - // optionally change the type to double + // Uncomment to optionally change the type to double // .ofDoubles() .build(); @@ -1114,10 +1114,10 @@ public class AsyncUpDownCounterUsage { .upDownCounterBuilder("fully.qualified.updowncounter") .setDescription("Current length of widget processing queue") .setUnit("{widget}") - // optionally change the type to double + // Uncomment to optionally change the type to double // .ofDoubles() - // the callback is invoked a MetricReader reads metrics .buildWithCallback( + // the callback is invoked a MetricReader reads metrics observableMeasurement -> { long currentWidgetCount = queueLength.get(); @@ -1177,9 +1177,9 @@ public class HistogramUsage { .histogramBuilder("fully.qualified.histogram") .setDescription("Length of time to process a widget") .setUnit("s") - // optionally provide advice on useful default explicit bucket boundaries + // Uncomment to optionally provide advice on useful default explicit bucket boundaries // .setExplicitBucketBoundariesAdvice(Arrays.asList(1.0, 2.0, 3.0)) - // optionally change the type to long + // Uncomment to optionally change the type to long // .ofLongs() .build(); @@ -1237,7 +1237,7 @@ public class GaugeUsage { .gaugeBuilder("fully.qualified.gauge") .setDescription("The current temperature of the widget processing line") .setUnit("K") - // optionally change the type to long + // Uncomment to optionally change the type to long // .ofLongs() .build(); @@ -1297,10 +1297,10 @@ public class AsyncGaugeUsage { .gaugeBuilder("fully.qualified.gauge") .setDescription("The current temperature of the widget processing line") .setUnit("K") - // optionally change the type to long + // Uncomment to optionally change the type to long // .ofLongs() - // the callback is invoked a MetricReader reads metrics .buildWithCallback( + // the callback is invoked a MetricReader reads metrics observableMeasurement -> { double currentWidgetCount = processingLineTemp.get(); @@ -1408,8 +1408,8 @@ public class LogRecordUsage { .setAttribute( AttributeKey.doubleArrayKey("come.acme.double-array-key"), Arrays.asList(1.1, 2.2)) .setAllAttributes(WIDGET_RED_CIRCLE) - // Optionally explicitly set the context used to correlate with spans. If omitted, - // Context.current() is used. + // Uncomment to optionally explicitly set the context used to correlate with spans. If + // omitted, Context.current() is used. // .setContext(context) // Emit the log record .emit(); @@ -1553,7 +1553,7 @@ import io.opentelemetry.semconv.incubating.HttpIncubatingAttributes; public class SemanticAttributesUsage { public static void semanticAttributesUsage() { - // Semantic attributes are organized by top level domain and whether they are stable or + // Semantic attributes are organized by top-level domain and whether they are stable or // incubating. // For example: // - stable attributes starting with http.* are in the HttpAttributes class. @@ -1627,7 +1627,7 @@ public class BaggageUsage { .put("shopId", "abc123") .put("shopName", "opentelemetry-demo", BaggageEntryMetadata.create("metadata")) .build(); - // ...or start from empty + // ...or uncomment to start from empty // newBaggage = Baggage.empty().toBuilder().put("shopId", "abc123").build(); // output => new baggage: {shopId=abc123(), shopName=opentelemetry-demo(metadata)} System.out.println("new baggage: " + asString(newBaggage)); diff --git a/content/en/docs/languages/java/configuration.md b/content/en/docs/languages/java/configuration.md index ba6bb9ee8890..5668297caa6d 100644 --- a/content/en/docs/languages/java/configuration.md +++ b/content/en/docs/languages/java/configuration.md @@ -361,36 +361,36 @@ import java.util.Collections; public class CustomizedAutoConfiguredSdk { public static OpenTelemetrySdk autoconfiguredSdk() { return AutoConfiguredOpenTelemetrySdk.builder() - // Optionally customize TextMapPropagator. - .addPropagatorCustomizer((textMapPropagator, configProperties) -> textMapPropagator) - // Optionally customize Resource. - .addResourceCustomizer((resource, configProperties) -> resource) - // Optionally customize Sampler. - .addSamplerCustomizer((sampler, configProperties) -> sampler) - // Optionally customize SpanExporter. - .addSpanExporterCustomizer((spanExporter, configProperties) -> spanExporter) - // Optionally customize SpanProcessor. - .addSpanProcessorCustomizer((spanProcessor, configProperties) -> spanProcessor) - // Optionally supply additional properties. - .addPropertiesSupplier(Collections::emptyMap) - // Optionally customize ConfigProperties. - .addPropertiesCustomizer(configProperties -> Collections.emptyMap()) - // Optionally customize SdkTracerProviderBuilder. - .addTracerProviderCustomizer((builder, configProperties) -> builder) - // Optionally customize SdkMeterProviderBuilder. - .addMeterProviderCustomizer((builder, configProperties) -> builder) - // Optionally customize MetricExporter. - .addMetricExporterCustomizer((metricExporter, configProperties) -> metricExporter) - // Optionally customize MetricReader. - .addMetricReaderCustomizer((metricReader, configProperties) -> metricReader) - // Optionally customize SdkLoggerProviderBuilder. - .addLoggerProviderCustomizer((builder, configProperties) -> builder) - // Optionally customize LogRecordExporter. - .addLogRecordExporterCustomizer((logRecordExporter, configProperties) -> logRecordExporter) - // Optionally customize LogRecordProcessor. - .addLogRecordProcessorCustomizer((processor, configProperties) -> processor) - .build() - .getOpenTelemetrySdk(); + // Optionally customize TextMapPropagator. + .addPropagatorCustomizer((textMapPropagator, configProperties) -> textMapPropagator) + // Optionally customize Resource. + .addResourceCustomizer((resource, configProperties) -> resource) + // Optionally customize Sampler. + .addSamplerCustomizer((sampler, configProperties) -> sampler) + // Optionally customize SpanExporter. + .addSpanExporterCustomizer((spanExporter, configProperties) -> spanExporter) + // Optionally customize SpanProcessor. + .addSpanProcessorCustomizer((spanProcessor, configProperties) -> spanProcessor) + // Optionally supply additional properties. + .addPropertiesSupplier(Collections::emptyMap) + // Optionally customize ConfigProperties. + .addPropertiesCustomizer(configProperties -> Collections.emptyMap()) + // Optionally customize SdkTracerProviderBuilder. + .addTracerProviderCustomizer((builder, configProperties) -> builder) + // Optionally customize SdkMeterProviderBuilder. + .addMeterProviderCustomizer((builder, configProperties) -> builder) + // Optionally customize MetricExporter. + .addMetricExporterCustomizer((metricExporter, configProperties) -> metricExporter) + // Optionally customize MetricReader. + .addMetricReaderCustomizer((metricReader, configProperties) -> metricReader) + // Optionally customize SdkLoggerProviderBuilder. + .addLoggerProviderCustomizer((builder, configProperties) -> builder) + // Optionally customize LogRecordExporter. + .addLogRecordExporterCustomizer((logRecordExporter, configProperties) -> logRecordExporter) + // Optionally customize LogRecordProcessor. + .addLogRecordProcessorCustomizer((processor, configProperties) -> processor) + .build() + .getOpenTelemetrySdk(); } } ``` From 2eb185e62e50183fd598301e2e65518f9032f92b Mon Sep 17 00:00:00 2001 From: Jack Berg Date: Tue, 8 Oct 2024 09:56:08 -0500 Subject: [PATCH 05/13] PR feedback --- .../en/docs/languages/java/api-components.md | 29 +++++++++---------- 1 file changed, 14 insertions(+), 15 deletions(-) diff --git a/content/en/docs/languages/java/api-components.md b/content/en/docs/languages/java/api-components.md index 2e15aaf6f6c0..8fea462306a6 100644 --- a/content/en/docs/languages/java/api-components.md +++ b/content/en/docs/languages/java/api-components.md @@ -20,7 +20,7 @@ The API is a set of classes and interfaces for recording telemetry across key observability signals. The [SDK](../sdk/) is the built-in reference implementation of the API, [configured](../configuration/) to process and export telemetry. This page is a conceptual overview of the API, including -descriptions, links to relevant Javadocs, artifact coordinates, sample API +descriptions, links to relevant Javadocs, artifact coordinates, and sample API usage. The API consists of the following top-level components: @@ -79,7 +79,7 @@ It consists of: propagating `Context` across application boundaries. The `io.opentelemetry:opentelemetry-extension-kotlint:{{% param vers.otel %}}` -is an extension with tool for propagating context into coroutines. +is an extension with tools for propagating context into coroutines. ### Context @@ -96,7 +96,7 @@ argument. Context is a recurring concept in the OpenTelemetry API: [exemplars](/docs/specs/otel/metrics/data-model/#exemplars) and defaulting to whatever span is currently in context. - [LogRecords](#logrecordbuilder) accept a context argument, used to link log - records spans and defaulting to whatever span is currently in context. + record spans and defaulting to whatever span is currently in context. The following code snippet explores `Context` API usage: @@ -383,8 +383,8 @@ scope: {{% alert %}} {{% param logBridgeWarning %}} {{% /alert %}} A scope is identified by the triplet (name, version, schemaUrl). Care must be -taken to ensure to the scope identity is unique. A typical approach is to set -the scope name to the package name or fully qualified class name, and to set the +taken to ensure the scope identity is unique. A typical approach is to set the +scope name to the package name or fully qualified class name, and to set the scope version to the library version. If emitting telemetry for multiple signals (i.e. metrics and traces), the same scope should be used. See [instrumentation scope](/docs/concepts/instrumentation-scope/) for details. @@ -455,10 +455,9 @@ is a bundle of key value pairs representing the [standard attribute definition](/docs/specs/otel/common/#standard-attribute). `Attributes` are a recurring concept in the OpenTelemetry API: -- [Spans](#span), span events, and span links have attributes -- The measurements recorded to [metric instruments](#meter) have attributes -- [LogRecords](#logrecordbuilder) have attributes -- and more +- [Spans](#span), span events, and span links have attributes. +- The measurements recorded to [metric instruments](#meter) have attributes. +- [LogRecords](#logrecordbuilder) have attributes. See [semantic attributes](#semantic-attributes) for attribute constants generated from the semantic conventions. @@ -653,7 +652,7 @@ public class GlobalOpenTelemetryUsage { ### TracerProvider [TracerProvider](https://www.javadoc.io/doc/io.opentelemetry/opentelemetry-api/latest/io/opentelemetry/api/trace/TracerProvider.html) -is the API entry point for traces, and provides [Tracers](#tracer). See +is the API entry point for traces and provides [Tracers](#tracer). See [providers and scopes](#providers-and-scopes) for information on providers and scopes. @@ -772,13 +771,13 @@ public class SpanUsage { Span parenting is an important aspect of tracing. Each span has an optional parent. By collecting all the spans in a trace and following each span's parent, -we can construct a hierarchy. The span APIs are build on top of +we can construct a hierarchy. The span APIs are built on top of [context](#context), which allows span context to be implicitly passed around an application and across threads. When a span is created, its parent is set to the whatever span is present in `Context.current()` unless there is no span or the context is explicitly overridden. -Most of the context API usage guidance applies to span. Span context is +Most of the context API usage guidance applies to spans. Span context is propagated across application boundaries with the [W3CTraceContextPropagator](https://www.javadoc.io/doc/io.opentelemetry/opentelemetry-api/latest/io/opentelemetry/api/trace/propagation/W3CTraceContextPropagator.html) and other [TextMapPropagators](../sdk/#textmappropagator). @@ -847,7 +846,7 @@ public class SpanAndContextUsage { ### MeterProvider [MeterProvider](https://www.javadoc.io/doc/io.opentelemetry/opentelemetry-api/latest/io/opentelemetry/api/metrics/MeterProvider.html) -is the API entry point for metrics, and provides [Meters](#meter). See +is the API entry point for metrics and provides [Meters](#meter). See [providers and scopes](#providers-and-scopes) for information on providers and scopes. @@ -858,7 +857,7 @@ is used to obtain instruments for a particular [instrumentation scope](#providers-and-scopes). See [providers and scopes](#providers-and-scopes) for information on providers and scopes. There are a variety of instruments, each with different semantics and -default behavior in the SDK. Its important to choose the right instrument for +default behavior in the SDK. It's important to choose the right instrument for each particular use case: | Instrument | Sync or Async | Description | Example | Default SDK Aggregation | @@ -1328,7 +1327,7 @@ public class AsyncGaugeUsage { ### LoggerProvider [LoggerProvider](https://www.javadoc.io/doc/io.opentelemetry/opentelemetry-api/latest/io/opentelemetry/api/logs/LoggerProvider.html) -is the API entry point for logs, and provides [Loggers](#logger). See +is the API entry point for logs and provides [Loggers](#logger). See [providers and scopes](#providers-and-scopes) for information on providers and scopes. From 5df49eb2c2539c59250d9ef3135118b81d34eca3 Mon Sep 17 00:00:00 2001 From: Jack Berg Date: Tue, 8 Oct 2024 09:58:57 -0500 Subject: [PATCH 06/13] Update code excerpts with PR feedback --- content-modules/opentelemetry-java-examples | 2 +- content/en/docs/languages/java/api-components.md | 12 ++++++------ 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/content-modules/opentelemetry-java-examples b/content-modules/opentelemetry-java-examples index dd12ee9dc30f..08fa4901d2b5 160000 --- a/content-modules/opentelemetry-java-examples +++ b/content-modules/opentelemetry-java-examples @@ -1 +1 @@ -Subproject commit dd12ee9dc30ff6370f5c238336e478d49fc3a4ba +Subproject commit 08fa4901d2b511c83c50acc81a217df5155a290a diff --git a/content/en/docs/languages/java/api-components.md b/content/en/docs/languages/java/api-components.md index 8fea462306a6..21c874dce110 100644 --- a/content/en/docs/languages/java/api-components.md +++ b/content/en/docs/languages/java/api-components.md @@ -154,10 +154,10 @@ public class ContextUsage { ExecutorService executorService = Executors.newSingleThreadExecutor(); ScheduledExecutorService scheduledExecutorService = Executors.newScheduledThreadPool(1); - // Context instances can be explicitly passed around application code, but its more convenient + // Context instances can be explicitly passed around application code, but it's more convenient // to use implicit context, calling Context.makeCurrent() and accessing via Context.current(). // Context provides a number of utilities for implicit context propagation. These utilities wrap - // utility classes like Scheduler, and ExecutorService, ScheduledExecutorService, Runnable, + // utility classes like Scheduler, ExecutorService, ScheduledExecutorService, Runnable, // Callable, Consumer, Supplier, Function, etc and modify their behavior to call // Context.makeCurrent() before running. context.wrap(ContextUsage::callable).call(); @@ -995,7 +995,7 @@ public class AsyncCounterUsage { // Uncomment to optionally change the type to double // .ofDoubles() .buildWithCallback( - // the callback is invoked a MetricReader reads metrics + // the callback is invoked when a MetricReader reads metrics observableMeasurement -> { long currentWidgetCount = widgetCount.get(); @@ -1116,7 +1116,7 @@ public class AsyncUpDownCounterUsage { // Uncomment to optionally change the type to double // .ofDoubles() .buildWithCallback( - // the callback is invoked a MetricReader reads metrics + // the callback is invoked when a MetricReader reads metrics observableMeasurement -> { long currentWidgetCount = queueLength.get(); @@ -1229,7 +1229,7 @@ public class GaugeUsage { private static final Attributes WIDGET_RED_CIRCLE = Util.WIDGET_RED_CIRCLE; public static void gaugeUsage(Meter meter) { - // Construct a gauge to record measurements as they occur when cannot be spatially + // Construct a gauge to record measurements as they occur, which cannot be spatially // re-aggregated. DoubleGauge gauge = meter @@ -1299,7 +1299,7 @@ public class AsyncGaugeUsage { // Uncomment to optionally change the type to long // .ofLongs() .buildWithCallback( - // the callback is invoked a MetricReader reads metrics + // the callback is invoked when a MetricReader reads metrics observableMeasurement -> { double currentWidgetCount = processingLineTemp.get(); From 371691076e795548cd5d2a51a2d59976de04a07c Mon Sep 17 00:00:00 2001 From: Jack Berg Date: Wed, 9 Oct 2024 09:12:25 -0500 Subject: [PATCH 07/13] Update opentelemetry-java-examples ref to latest --- content-modules/opentelemetry-java-examples | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/content-modules/opentelemetry-java-examples b/content-modules/opentelemetry-java-examples index 08fa4901d2b5..0f736eca6a4b 160000 --- a/content-modules/opentelemetry-java-examples +++ b/content-modules/opentelemetry-java-examples @@ -1 +1 @@ -Subproject commit 08fa4901d2b511c83c50acc81a217df5155a290a +Subproject commit 0f736eca6a4b6865fb62b00033a53369e69440f7 From e7377cdd3606812f6f3600bc616c3a07057c3d1e Mon Sep 17 00:00:00 2001 From: Jack Berg Date: Wed, 9 Oct 2024 09:16:16 -0500 Subject: [PATCH 08/13] Update pin in .gitmodules --- .gitmodules | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitmodules b/.gitmodules index b3e0735ae018..ec8382827470 100644 --- a/.gitmodules +++ b/.gitmodules @@ -31,4 +31,4 @@ [submodule "content-modules/opentelemetry-java-examples"] path = content-modules/opentelemetry-java-examples url = https://github.com/open-telemetry/opentelemetry-java-examples.git - javaexamples-pin = 8fe9a11 + javaexamples-pin = 0f736ec From 2e41c0b7c547349b0530d3efaa5038198e2ecd72 Mon Sep 17 00:00:00 2001 From: Jack Berg Date: Wed, 9 Oct 2024 14:18:40 -0500 Subject: [PATCH 09/13] Add callout for otel java agent --- content/en/docs/languages/java/instrumentation.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/content/en/docs/languages/java/instrumentation.md b/content/en/docs/languages/java/instrumentation.md index f4a0b88b24b9..0d4a189737fe 100644 --- a/content/en/docs/languages/java/instrumentation.md +++ b/content/en/docs/languages/java/instrumentation.md @@ -30,6 +30,12 @@ instrumentation topics: - [Log instrumentation](#log-instrumentation): The semantic conventions define how to produce telemetry for standard operations. +{{% alert %}} While [instrumentation categories](#instrumentation-categories) +enumerates several options for instrumenting an application, we recommend users +start with the [Java agent](#zero-code-java-agent). The Java agent has a simple +installation process, and automatically detects and installs instrumentation +from a large library. {{% /alert %}} + ## Instrumentation categories There are several categories of instrumentation: From 02b600a70bf56b70cd4ec09b502c0c9ceca4d2b2 Mon Sep 17 00:00:00 2001 From: Jack Berg Date: Mon, 14 Oct 2024 11:27:14 -0500 Subject: [PATCH 10/13] Merge java libraries into intrumentation ecosystem --- .../en/docs/languages/java/instrumentation.md | 33 ++-- content/en/docs/languages/java/libraries.md | 187 ------------------ layouts/partials/docs/native-libraries.md | 31 +++ .../docs/languages/libraries-intro.md | 22 +-- .../docs/languages/native-libraries.md | 1 + 5 files changed, 52 insertions(+), 222 deletions(-) delete mode 100644 content/en/docs/languages/java/libraries.md create mode 100644 layouts/partials/docs/native-libraries.md create mode 100644 layouts/shortcodes/docs/languages/native-libraries.md diff --git a/content/en/docs/languages/java/instrumentation.md b/content/en/docs/languages/java/instrumentation.md index 0d4a189737fe..0a0761102493 100644 --- a/content/en/docs/languages/java/instrumentation.md +++ b/content/en/docs/languages/java/instrumentation.md @@ -5,6 +5,7 @@ aliases: - /docs/java/manual_instrumentation - manual - manual_instrumentation + - /docs/languages/java/libraries/ weight: 10 description: Instrumentation ecosystem in OpenTelemetry Java cSpell:ignore: Logback logback @@ -63,8 +64,9 @@ Library instrumentation. ### Zero-code: Java agent -The Java agent is a form of zero-code instrumentation that dynamically -manipulations application bytecode. +The Java agent is a form of zero-code +[automatic instrumentation](/docs/specs/otel/glossary/#automatic-instrumentation) +that dynamically manipulations application bytecode. For a list of libraries instrumented by the Java agent, see the "Auto-instrumented versions" column on @@ -74,8 +76,9 @@ See [Java agent](/docs/zero-code/java/agent/) for more details. ### Zero-code: Spring Boot starter -The Spring Boot starter is a form of zero-code instrumentation that leverages -spring autoconfigure to install +The Spring Boot starter is a form of zero-code +[automatic instrumentation](/docs/specs/otel/glossary/#automatic-instrumentation) +that leverages spring autoconfigure to install [library instrumentation](#library-instrumentation). See [Spring Boot starter](/docs/zero-code/java/spring-boot-starter/) for @@ -83,8 +86,9 @@ details. ### Library instrumentation -Library instrumentation wraps or uses extension points to instrument a library, -requiring users to install and/or adapt library usage. +[Library instrumentation](/docs/specs/otel/glossary/#instrumentation-library) +wraps or uses extension points to instrument a library, requiring users to +install and/or adapt library usage. For a list of instrumentation libraries, see the "Standalone Library Instrumentation" column on @@ -92,20 +96,21 @@ Instrumentation" column on ### Native instrumentation -Native instrumentation is built directly into libraries or frameworks. -OpenTelemetry encourages library authors to add native instrumentation using the -[API](../api-components/). In the long term, we hope the native instrumentation -becomes the norm, and view the instrumentation maintained by OpenTelemetry in +[Native instrumentation](/docs/specs/otel/glossary/#natively-instrumented) is +built directly into libraries or frameworks. OpenTelemetry encourages library +authors to add native instrumentation using the [API](../api-components/). In +the long term, we hope the native instrumentation becomes the norm, and view the +instrumentation maintained by OpenTelemetry in [opentelemetry-java-instrumentation](https://github.com/open-telemetry/opentelemetry-java-instrumentation) as a temporary means of filling the gap. -For a list of libraries with native instrumentation, look for entries with the -"native" badge in the [registry](/ecosystem/registry/?language=java). +{{% docs/languages/native-libraries "java" %}} ### Manual instrumentation -Manual instrumentation is written by application authors, and typically specific -to the application domain. +[Manual instrumentation](/docs/specs/otel/glossary/#manual-instrumentation) is +written by application authors, and typically specific to the application +domain. ### Shims diff --git a/content/en/docs/languages/java/libraries.md b/content/en/docs/languages/java/libraries.md deleted file mode 100644 index e222378b2738..000000000000 --- a/content/en/docs/languages/java/libraries.md +++ /dev/null @@ -1,187 +0,0 @@ ---- -title: Using instrumentation libraries -linkTitle: Libraries -weight: 40 -cSpell:ignore: getenv httpclient println ---- - -{{% docs/languages/libraries-intro "java" %}} - -## Use Instrumentation Libraries - -If a library does not come with OpenTelemetry out of the box, you can use -[instrumentation libraries](/docs/specs/otel/glossary/#instrumentation-library) -in order to generate telemetry data for a library or framework. - -The Java agent for automatic instrumentation includes instrumentation libraries -for many common Java frameworks. Most are turned on by default. If you need to -turn off certain instrumentation libraries, you can -[suppress them](/docs/zero-code/java/agent/disable/). - -If you use [code-based instrumentation](../instrumentation), you can leverage -some instrumentation libraries for your dependencies standalone. To find out -which standalone instrumentation libraries are available, take a look at -[this list](https://github.com/open-telemetry/opentelemetry-java-instrumentation/blob/main/docs/supported-libraries.md#libraries--frameworks). -Follow the instructions of each instrumentation library to set them up. - -## Example app - -The following example instruments an HTTP client application using library -instrumentation which calls an HTTP server. - -You can use the dice example app as HTTP server from -[Getting Started](../getting-started/) or you can create your own HTTP server. - -### Dependencies - -Set up an environment in a new directory named `java-simple-http-client`. Inside -the directory, create a file named `build.gradle.kts` with the following -content: - -{{% alert title="Note" color="info" %}} The example is built using Gradle. You -might need to amend the directory structure and `pom.xml` to run using Maven. -{{% /alert %}} - -{{< tabpane text=true >}} {{% tab Gradle %}} - -```kotlin -plugins { - id("java") - id("application") -} - -application { - mainClass.set("otel.SampleHttpClient") -} - -sourceSets { - main { - java.setSrcDirs(setOf(".")) - } -} - -repositories { - mavenCentral() -} - -dependencies { - implementation("io.opentelemetry:opentelemetry-api:{{% param vers.otel %}}"); - implementation("io.opentelemetry:opentelemetry-sdk:{{% param vers.otel %}}"); - implementation("io.opentelemetry:opentelemetry-exporter-logging:{{% param vers.otel %}}"); - implementation("io.opentelemetry:opentelemetry-sdk-extension-autoconfigure:{{% param vers.otel %}}"); - implementation("io.opentelemetry.instrumentation:opentelemetry-java-http-client:{{% param vers.instrumentation %}}-alpha"); -} -``` - -{{% /tab %}} {{% tab Maven %}} - -```xml - - - io.opentelemetry.instrumentation - opentelemetry-java-http-client - {{% param vers.instrumentation %}}-alpha - - -``` - -{{< /tab >}} {{< /tabpane>}} - -### Setup - -The following example shows how you can instrument external API calls using -[Java HTTP client library](https://github.com/open-telemetry/opentelemetry-java-instrumentation/tree/main/instrumentation/java-http-client/library): - -```java -// SampleHttpClient.java -package otel; - -import io.opentelemetry.api.OpenTelemetry; -import io.opentelemetry.sdk.autoconfigure.AutoConfiguredOpenTelemetrySdk; -import io.opentelemetry.instrumentation.httpclient.JavaHttpClientTelemetry; -import java.net.http.HttpClient; - -import java.net.URI; -import java.net.http.HttpClient; -import java.net.http.HttpHeaders; -import java.net.http.HttpRequest; -import java.net.http.HttpResponse; - -public final class SampleHttpClient { - //Init OpenTelemetry - private static final OpenTelemetry openTelemetry = AutoConfiguredOpenTelemetrySdk.initialize().getOpenTelemetrySdk(); - - //Use this HttpClient implementation for making standard http client calls. - public HttpClient createTracedClient(OpenTelemetry openTelemetry) { - return JavaHttpClientTelemetry.builder(openTelemetry).build().newHttpClient(createClient()); - } - - //your configuration of the Java HTTP Client goes here: - private HttpClient createClient() { - return HttpClient.newBuilder().build(); - } - - public static void main(String[] args) throws Exception { - HttpRequest request = HttpRequest.newBuilder() - .GET() - .uri(URI.create(System.getenv().getOrDefault("EXTERNAL_API_ENDPOINT", "http://localhost:8080/rolldice"))) - //.setHeader("User-Agent", "Java 11 HttpClient Bot") // add request header - .build(); - - SampleHttpClient s = new SampleHttpClient(); - HttpResponse response = s.createTracedClient(openTelemetry).send(request, HttpResponse.BodyHandlers.ofString()); - // print response headers - HttpHeaders headers = response.headers(); - headers.map().forEach((k, v) -> System.out.println(k + ":" + v)); - // print status code - System.out.println(response.statusCode()); - // print response body - System.out.println(response.body()); - - } -} -``` - -### Run - -Set the `EXTERNAL_API_ENDPOINT` environment variable to specify the external API -endpoint. By default, it points to `http://localhost:8080/rolldice`, where -[example dice app](../getting-started/#example-application) is running. - -To check your code, run the app: - -```sh -env \ -OTEL_SERVICE_NAME=http-client \ -OTEL_TRACES_EXPORTER=logging \ -OTEL_METRICS_EXPORTER=logging \ -OTEL_LOGS_EXPORTER=logging \ -gradle run -``` - -When you run the app, the instrumentation libraries do the following: - -- Start a new trace. -- Generate a span that represents the request made to the external API endpoint. -- If you use an instrumented HTTP server, as in the - [dice app](../getting-started/#example-application), more trace spans are - generated with the same trace ID. - -## Available instrumentation libraries - -For a full list of instrumentation libraries, see -[opentelemetry-java-instrumentation](https://github.com/open-telemetry/opentelemetry-java-instrumentation/blob/main/docs/supported-libraries.md#libraries--frameworks). - -## Next steps - -After you've set up instrumentation libraries, you might want to add -[additional instrumentation](../instrumentation) to collect custom telemetry -data. - -You might also want to [configure the SDK](../configuration/) to export to one -or more telemetry backends. - -For existing library instrumentations, also see -[Java agent](/docs/zero-code/java/agent/). - -[opentelemetry-java](https://github.com/open-telemetry/opentelemetry-java) diff --git a/layouts/partials/docs/native-libraries.md b/layouts/partials/docs/native-libraries.md new file mode 100644 index 000000000000..15f392695be0 --- /dev/null +++ b/layouts/partials/docs/native-libraries.md @@ -0,0 +1,31 @@ + +{{ $howMany := .Get 1 | default 10 -}} +{{ $langIndex := .Get 0 }} +{{ $lang := index $.Site.Data.instrumentation $langIndex -}} +{{ $integrations := where (slice ) ".language" $langIndex -}} + +{{ $integrations := slice }} {{ range $entry := $.Site.Data.registry }} +{{ if and (and (eq $entry.language $langIndex) (eq $entry.isNative true)) (eq $entry.registryType "instrumentation") }} +{{ $integrations = $integrations | append $entry }} {{ end }} {{ end }} + +{{ range first $howMany (sort $integrations "name") -}} + + +- [{{ .title }}]({{ .urls.docs }}) +{{- end }} + +{{ if eq (len $integrations) 0 -}} + + +{{ else -}} + +{{ end -}} diff --git a/layouts/shortcodes/docs/languages/libraries-intro.md b/layouts/shortcodes/docs/languages/libraries-intro.md index 00a40302dbe3..614e46f3ae41 100644 --- a/layouts/shortcodes/docs/languages/libraries-intro.md +++ b/layouts/shortcodes/docs/languages/libraries-intro.md @@ -31,24 +31,4 @@ OpenTelemetry SDK with your app. The library might require some additional configuration for the instrumentation. Go to the documentation for that library to learn more. -{{ range first $howMany (sort $integrations "name") -}} - - -- [{{ .title }}]({{ .urls.docs }}) -{{- end }} - -{{ if eq (len $integrations) 0 -}} - - -{{ else -}} - -{{ end -}} +{{ partial "docs/native-libraries.md" . }} diff --git a/layouts/shortcodes/docs/languages/native-libraries.md b/layouts/shortcodes/docs/languages/native-libraries.md new file mode 100644 index 000000000000..53f520730de3 --- /dev/null +++ b/layouts/shortcodes/docs/languages/native-libraries.md @@ -0,0 +1 @@ +{{ partial "docs/native-libraries.md" . }} From 0c6157baec7241977c7ca26599b1701a252bcb24 Mon Sep 17 00:00:00 2001 From: Jack Berg Date: Mon, 14 Oct 2024 12:10:29 -0500 Subject: [PATCH 11/13] Remove duplicate linkTitle from front matter --- content/en/docs/languages/java/api-components.md | 1 - 1 file changed, 1 deletion(-) diff --git a/content/en/docs/languages/java/api-components.md b/content/en/docs/languages/java/api-components.md index 21c874dce110..40d5b87bf03b 100644 --- a/content/en/docs/languages/java/api-components.md +++ b/content/en/docs/languages/java/api-components.md @@ -1,6 +1,5 @@ --- title: Record Telemetry with API -linkTitle: Record Telemetry with API weight: 11 logBridgeWarning: > While the `LoggerProvider` / `Logger` APIs are structurally similar to the From 1a458dea73e8908204e6f8bee44d4187d9d4634c Mon Sep 17 00:00:00 2001 From: Jack Berg Date: Mon, 14 Oct 2024 12:19:35 -0500 Subject: [PATCH 12/13] Fix typos --- content/en/docs/languages/java/api-components.md | 4 ++-- content/en/docs/languages/java/instrumentation.md | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/content/en/docs/languages/java/api-components.md b/content/en/docs/languages/java/api-components.md index 40d5b87bf03b..c5df547cdf7a 100644 --- a/content/en/docs/languages/java/api-components.md +++ b/content/en/docs/languages/java/api-components.md @@ -1530,8 +1530,8 @@ to breaking changes, the intent is to stabilize `opentelemetry-semconv` and leave the `-alpha` suffix on `opentelemetry-semconv-incubating` permanently. Libraries can use `opentelemetry-semconv-incubating` for testing, but should not include it as a dependency: since attributes may come and go from version to -version, including as a dependency may expose end users to runtime errors when -transitive version conflicts occur. {{% /alert %}} +version, including it as a dependency may expose end users to runtime errors +when transitive version conflicts occur. {{% /alert %}} The attribute constants generated from semantic conventions are instances of `AttributeKey`, and can be used anywhere the OpenTelemetry API accepts diff --git a/content/en/docs/languages/java/instrumentation.md b/content/en/docs/languages/java/instrumentation.md index 0a0761102493..f21ba632da1f 100644 --- a/content/en/docs/languages/java/instrumentation.md +++ b/content/en/docs/languages/java/instrumentation.md @@ -66,7 +66,7 @@ Library instrumentation. The Java agent is a form of zero-code [automatic instrumentation](/docs/specs/otel/glossary/#automatic-instrumentation) -that dynamically manipulations application bytecode. +that dynamically manipulates application bytecode. For a list of libraries instrumented by the Java agent, see the "Auto-instrumented versions" column on From 80b69a7c26b20b1500bc768ec8d424f39dc56203 Mon Sep 17 00:00:00 2001 From: Patrice Chalin Date: Wed, 16 Oct 2024 20:14:56 -0400 Subject: [PATCH 13/13] Fix links, and ignore non-en pages that aren't up-to-date --- .htmltest.yml | 2 ++ content/en/blog/2023/spring-native/index.md | 10 +++++----- content/en/docs/languages/java/instrumentation.md | 2 +- 3 files changed, 8 insertions(+), 6 deletions(-) diff --git a/.htmltest.yml b/.htmltest.yml index 9ad637f30f5d..58774c8382e5 100644 --- a/.htmltest.yml +++ b/.htmltest.yml @@ -10,6 +10,8 @@ IgnoreDirs: - ^blog/(\d+/)?page/\d+ # TODO drop after https://github.com/open-telemetry/opentelemetry.io/issues/5267 is fixed: - zh/docs/contributing/pr-checks + # TODO drop after https://github.com/open-telemetry/opentelemetry.io/issues/5423 is fixed: + - (ja|pt)/docs/concepts/instrumentation/libraries/ IgnoreInternalURLs: # list of paths IgnoreURLs: # list of regexs of paths or URLs to be ignored - ^/api$ diff --git a/content/en/blog/2023/spring-native/index.md b/content/en/blog/2023/spring-native/index.md index acb1127a0601..5c4aaab586fe 100644 --- a/content/en/blog/2023/spring-native/index.md +++ b/content/en/blog/2023/spring-native/index.md @@ -37,11 +37,11 @@ Boot 3) out of the box: ``` To get even more visibility, the Starter can be combined with -[instrumentation libraries](/docs/languages/java/libraries/). For this purpose, -the OpenTelemetry Java contributors have improved the JDBC (database) libraries -and logging instrumentation libraries. For example, for the Logback logging -library, they have added GraalVM configuration to make the library work in -native mode[^1]. +[instrumentation libraries](/docs/languages/java/instrumentation/). For this +purpose, the OpenTelemetry Java contributors have improved the JDBC (database) +libraries and logging instrumentation libraries. For example, for the Logback +logging library, they have added GraalVM configuration to make the library work +in native mode[^1]. Furthermore, they have worked to reduce the configuration to set up the logging and database instrumentation with the Starter. For example, if your application diff --git a/content/en/docs/languages/java/instrumentation.md b/content/en/docs/languages/java/instrumentation.md index f21ba632da1f..9cf2e297ac27 100644 --- a/content/en/docs/languages/java/instrumentation.md +++ b/content/en/docs/languages/java/instrumentation.md @@ -5,7 +5,7 @@ aliases: - /docs/java/manual_instrumentation - manual - manual_instrumentation - - /docs/languages/java/libraries/ + - libraries weight: 10 description: Instrumentation ecosystem in OpenTelemetry Java cSpell:ignore: Logback logback