Skip to content

Commit

Permalink
Make OpenTelemetrySdk implement the OpenTelemetry interface and have …
Browse files Browse the repository at this point in the history
…SPI find it.
  • Loading branch information
Anuraag Agrawal committed Oct 22, 2020
1 parent ed5136b commit 949bfec
Show file tree
Hide file tree
Showing 8 changed files with 539 additions and 155 deletions.
128 changes: 73 additions & 55 deletions QUICKSTART.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

<!-- toc -->

- [Setting up the SDK](#setting-up-the-sdk)
- [Tracing](#tracing)
* [Create basic Span](#create-basic-span)
* [Create nested Spans](#create-nested-spans)
Expand Down Expand Up @@ -31,10 +32,34 @@ configuration must be provided by **Applications** which should also depend on t
libraries will obtain a real implementation only if the user application is configured for it. For
more details, check out the [Library Guidelines].

## Setting up the SDK

To get started, setup the OpenTelemetry SDK - note that if you are using a different implementation
of the OpenTelemetry API, you should refer to the configuration instructions for that SDK. Also, if
you are using the Auto-Instrumentation Agent, the SDK is configured by the agent itself and you
should not setup your own.

You can setup a basic configuration that exports traces to a logging stream like this:

```java
OpenTelemetry openTelemetry = OpenTelemetrySdk.builder()
.setTracerProvider(
TracerSdkProvider.builder()
.setSpanProcessors(
SimpleSpanProcessor.builder(new LoggingSpanExporter()).build())
.build())
.build();
```

Note that a preconfigured `OpenTelemetry` can be retrieved by calling `OpenTelemetry.get()`. If you
are using the Auto-Instrumentation Agent, it will be the `OpenTelemetry` that the agent configured.
Otherwise, it will enable propagation of context to remote servers but will not export any spans.

Refer to [Tracing SDK Configuration](#tracing-sdk-configuration) for more advanced configuration.

## Tracing

In the following, we present how to trace code using the OpenTelemetry API. **Note:** Methods of the
OpenTelemetry SDK should never be called.
In the following, we present how to trace code using the OpenTelemetry API that you instantiated.

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
Expand All @@ -43,15 +68,15 @@ monitored. More information is available in the specification chapter [Obtaining

```java
Tracer tracer =
OpenTelemetry.getTracer("instrumentation-library-name","semver:1.0.0");
openTelemetry.getTracer("instrumentation-library-name","semver:1.0.0");
```

### Create basic Span
To create a basic span, 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.
```java
Span span = tracer.spanBuilder("my span").startSpan();
try (Scope scope = TracingContextUtils.currentContextWith(span)) {
try (Scope scope = tracer.withSpan(span)) {
// your use case
...
} catch (Throwable t) {
Expand Down Expand Up @@ -87,7 +112,7 @@ The OpenTelemetry API offers also an automated way to propagate the `parentSpan`
```java
void a() {
Span parentSpan = tracer.spanBuilder("a").startSpan();
try(Scope scope = TracingContextUtils.currentContextWith(parentSpan)) {
try(Scope scope = tracer.withSpan(parentSpan)) {
b();
} finally {
parentSpan.end();
Expand All @@ -96,9 +121,9 @@ void a() {
void b() {
Span childSpan = tracer.spanBuilder("b")
// NOTE: setParent(parentSpan) is not required;
// `TracingContextUtils.getCurrentSpan()` is automatically added as parent
// `tracer.getCurrentSpan()` is automatically added as parent
.startSpan();
try(Scope scope = TracingContextUtils.currentContextWith(childSpan)) {
try(Scope scope = tracer.withSpan(childSpan)) {
// do stuff
} finally {
childSpan.end();
Expand Down Expand Up @@ -185,14 +210,14 @@ TextMapPropagator.Setter<HttpURLConnection> setter =

URL url = new URL("http://127.0.0.1:8080/resource");
Span outGoing = tracer.spanBuilder("/resource").setSpanKind(Span.Kind.CLIENT).startSpan();
try (Scope scope = TracingContextUtils.currentContextWith(outGoing)) {
try (Scope scope = tracer.withSpan(outGoing)) {
// Semantic Convention.
// (Observe that to set these, Span does not *need* to be the current instance.)
outGoing.setAttribute("http.method", "GET");
outGoing.setAttribute("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);
openTelemetry.getPropagators().getTextMapPropagator().inject(Context.current(), transportLayer, setter);
// Make outgoing call
} finally {
outGoing.end();
Expand All @@ -218,7 +243,7 @@ TextMapPropagator.Getter<HttpExchange> getter =
...
public void handle(HttpExchange httpExchange) {
// Extract the SpanContext and other elements from the request.
Context extractedContext = OpenTelemetry.getPropagators().getTextMapPropagator()
Context extractedContext = openTelemetry.getPropagators().getTextMapPropagator()
.extract(Context.current(), httpExchange, getter);
Span serverSpan = null;
try (Scope scope = ContextUtils.withScopedContext(extractedContext)) {
Expand Down Expand Up @@ -254,7 +279,7 @@ The following is an example of counter usage:

```java
// Gets or creates a named meter instance
Meter meter = OpenTelemetry.getMeter("instrumentation-library-name","semver:1.0.0");
Meter meter = openTelemetry.getMeter("instrumentation-library-name","semver:1.0.0");

// Build counter e.g. LongCounter
LongCounter counter = meter
Expand Down Expand Up @@ -304,23 +329,6 @@ The configuration examples reported in this document only apply to the SDK provi
`opentelemetry-sdk`. Other implementation of the API might provide different configuration
mechanisms.

The application has to install a span processor with an exporter and may customize the behavior of
the OpenTelemetry SDK.

For example, a basic configuration instantiates the SDK tracer registry and sets to export the
traces to a logging stream.

```java
// Get the tracer
TracerSdkManagement tracerSdkManagement = OpenTelemetrySdk.getTracerManagement();

// Set to export the traces to a logging stream
tracerSdkManagement.addSpanProcessor(
SimpleSpanProcessor.builder(
new LoggingSpanExporter()
).build());
```

### Sampler

It is not always feasible to trace and export every user request in an application.
Expand All @@ -345,10 +353,14 @@ TraceConfig alwaysOff = TraceConfig.getDefault().toBuilder().setSampler(
TraceConfig half = TraceConfig.getDefault().toBuilder().setSampler(
Samplers.probability(0.5)
).build();
// Configure the sampler to use
tracerProvider.updateActiveTraceConfig(
half
);
// Configure the sampler to use when initializing the SDK
OpenTelemetry openTelemetry = OpenTelemetrySdk.builder()
.setTracerProvider(
TracerSdkProvider.builder()
...
.setTraceConfig(half)
.build())
.build();
```

### Span Processor
Expand All @@ -359,16 +371,18 @@ in bulk. Multiple Span processors can be configured to be active at the same tim
`MultiSpanProcessor`.

```java
tracerSdkManagement.addSpanProcessor(
SimpleSpanProcessor.builder(new LoggingSpanExporter()).build()
);
tracerSdkManagement.addSpanProcessor(
BatchSpanProcessor.builder(new LoggingSpanExporter()).build()
);
tracerSdkManagement.addSpanProcessor(MultiSpanProcessor.create(Arrays.asList(
SimpleSpanProcessor.builder(new LoggingSpanExporter()).build(),
BatchSpanProcessor.builder(new LoggingSpanExporter()).build()
)));
TracerSdkProvider.builder()
.setSpanProcessor(SimpleSpanProcessor.builder(new LoggingSpanExporter()).build())

TracerSdkProvider.builder()
.setSpanProcessor(BatchSpanProcessor.builder(new LoggingSpanExporter()).build())

TracerSdkProvider.builder()
.setSpanProcessor(
MultiSpanProcessor.create(
Arrays.asList(
SimpleSpanProcessor.builder(new LoggingSpanExporter()).build(),
BatchSpanProcessor.builder(new LoggingSpanExporter()).build()))
```

### Exporter
Expand All @@ -384,19 +398,18 @@ a particular backend. OpenTelemetry offers four exporters out of the box:
Other exporters can be found in the [OpenTelemetry Registry].

```java
tracerSdkManagement.addSpanProcessor(
SimpleSpanProcessor.builder(InMemorySpanExporter.create()).build());
tracerSdkManagement.addSpanProcessor(
SimpleSpanProcessor.builder(new LoggingSpanExporter()).build());
TracerSdkProvider.builder()
.setSpanProcessor(SimpleSpanProcessor.builder(InMemorySpanExporter.create()).build())
TracerSdkProvider.builder()
.setSpanProcessor(SimpleSpanProcessor.builder(new LoggingSpanExporter()).build())

ManagedChannel jaegerChannel =
ManagedChannelBuilder.forAddress([ip:String], [port:int]).usePlaintext().build();
JaegerGrpcSpanExporter jaegerExporter = JaegerGrpcSpanExporter.builder()
.setServiceName("example").setChannel(jaegerChannel).setDeadline(30000)
.build();
tracerSdkManagement.addSpanProcessor(BatchSpanProcessor.builder(
jaegerExporter
).build());
TracerSdkProvider.builder()
.setSpanProcessor(BatchSpanProcessor.builder(jaegerExporter).build())
```

### TraceConfig
Expand All @@ -406,7 +419,7 @@ environment variables and builder `set*` methods.

```java
// Get TraceConfig associated with TracerSdk
TracerConfig traceConfig = OpenTelemetrySdk.getTracerManagement().getActiveTraceConfig();
TracerConfig traceConfig = OpenTelemetrySdk.getGlobalTracerManagement().getActiveTraceConfig();

// Get TraceConfig Builder
Builder builder = traceConfig.toBuilder();
Expand All @@ -421,17 +434,23 @@ builder.readEnvironmentVariables()
builder.setMaxNumberOfLinks(10);

// Update the resulting TraceConfig instance
OpenTelemetrySdk.getTracerManagement().updateActiveTraceConfig(builder.build());
OpenTelemetry openTelemetry = OpenTelemetrySdk.builder()
.setTracerProvider(
TracerSdkProvider.builder()
...
.setTraceConfig(builder.build())
.build())
.build();
```

Supported system properties and environment variables:

| System property | Environment variable | Purpose |
|----------------------------------|----------------------------------|-----------------------------------------------------------------------------------------------------|
| otel.config.sampler.probability | OTEL_CONFIG_SAMPLER_PROBABILITY | Sampler which is used when constructing a new span (default: 1) |
| otel.span.attribute.count.limit | OTEL_SPAN_ATTRIBUTE_COUNT_LIMIT | Max number of attributes per span, extra will be dropped (default: 1000) |
| otel.span.event.count.limit | OTEL_SPAN_EVENT_COUNT_LIMIT | Max number of Events per span, extra will be dropped (default: 1000) |
| otel.span.link.count.limit | OTEL_SPAN_LINK_COUNT_LIMIT | Max number of Link entries per span, extra will be dropped (default: 1000) |
| otel.config.max.attrs | OTEL_CONFIG_MAX_ATTRS | Max number of attributes per span, extra will be dropped (default: 32) |
| otel.config.max.events | OTEL_CONFIG_MAX_EVENTS | Max number of Events per span, extra will be dropped (default: 128) |
| otel.config.max.links | OTEL_CONFIG_MAX_LINKS | Max number of Link entries per span, extra will be dropped (default: 32) |
| otel.config.max.event.attrs | OTEL_CONFIG_MAX_EVENT_ATTRS | Max number of attributes per event, extra will be dropped (default: 32) |
| otel.config.max.link.attrs | OTEL_CONFIG_MAX_LINK_ATTRS | Max number of attributes per link, extra will be dropped (default: 32) |
| otel.config.max.attr.length | OTEL_CONFIG_MAX_ATTR_LENGTH | Max length of string attribute value in characters, too long will be truncated (default: unlimited) |
Expand Down Expand Up @@ -500,4 +519,3 @@ public class IgnoreExportErrorsFilter implements Filter {
## Registering the custom filter on the BatchSpanProcessor
io.opentelemetry.sdk.trace.export.BatchSpanProcessor = io.opentelemetry.extensions.logging.IgnoreExportErrorsFilter
```

Loading

0 comments on commit 949bfec

Please sign in to comment.