Record Telemetry with API
You are viewing the English version of this page because it has not yet been fully translated. Interested in helping out? See Contributing.
The API is a set of classes and interfaces for recording telemetry across key observability signals. The SDK is the built-in reference implementation of the API, configured to process and export telemetry. This page is a conceptual overview of the API, including descriptions, links to relevant Javadocs, artifact coordinates, and sample API usage.
The API consists of the following top-level components:
- Context: A standalone API for propagating context throughout an application and across application boundaries, including trace context and baggage.
- TracerProvider: The API entry point for traces.
- MeterProvider: The API entry point for metrics.
- LoggerProvider: The API entry point for logs.
- 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 reference implementation. This is the right choice for most users.
- No-op 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, zero transitive dependencies, and supports Java 8+. 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.
For the Javadoc reference of all OpenTelemetry Java components, see javadoc.io/doc/io.opentelemetry.
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:1.66.0
artifact contains standalone APIs (i.e. packaged separately from
OpenTelemetry API) for propagating context throughout an
application and across application boundaries.
It consists of:
- Context: An immutable bundle of key value pairs which is implicitly or explicitly propagated through an application.
- ContextStorage: A mechanism for storing and retrieving the current context, defaulting to thread local.
- ContextPropagators: A container of registered propagators for
propagating
Contextacross application boundaries.
The io.opentelemetry:opentelemetry-extension-kotlint:1.66.0
is an extension with tools for propagating context into coroutines.
Context
Context 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 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 accept a context argument, used to link measurements to spans via exemplars and defaulting to whatever span is currently in context.
- LogRecords accept a context argument, used to link log record spans and defaulting to whatever span is currently in context.
The following code snippet explores Context API usage:
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<String> 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.current().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 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, 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
is a mechanism for storing and retrieving the current Context.
The default ContextStorage implementation stores Context in thread local.
ContextPropagators
ContextPropagators
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 for propagator implementations.
The following code snippet explores ContextPropagators API for injection:
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<HttpRequest.Builder> 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<HttpRequest.Builder> {