From 6c29e2f658ab69c003e21d4def41a8589e4e2cd0 Mon Sep 17 00:00:00 2001 From: Tyler Benson Date: Wed, 12 Jul 2017 16:28:10 -0700 Subject: [PATCH] Add more to the opentracing quick start guide --- dd-trace/README.md | 4 +- dd-trace/docs/opentracing-api.md | 142 +++++++++++++++++++------------ 2 files changed, 91 insertions(+), 55 deletions(-) diff --git a/dd-trace/README.md b/dd-trace/README.md index 3dc90b6c9e..2c5c1d90b2 100644 --- a/dd-trace/README.md +++ b/dd-trace/README.md @@ -109,8 +109,8 @@ Check the dedicated project for the full documentation: [dd-java-agent](../dd-ja ### Custom instrumentations using OpenTracing API -If you want to add custom instrumenting to your code, you have to use the OpenTracing API. -The official documentation can be found right here: [](https://github.com/opentracing/opentracing-java). +Rather than referencing classes directly from `dd-trace` (other than registering `DDTracer`), we strongly suggest using the [OpenTracing API](https://github.com/opentracing/opentracing-java). +[Additional documentation on the api](docs/opentracing-api.md) is also available. Let's look at a simple example. diff --git a/dd-trace/docs/opentracing-api.md b/dd-trace/docs/opentracing-api.md index 38f075e33c..3fdbed59e6 100644 --- a/dd-trace/docs/opentracing-api.md +++ b/dd-trace/docs/opentracing-api.md @@ -2,109 +2,145 @@ The Opentraction group offers an API to instrument your code. -This document is a kind of a "Quick start for the" official specifications: https://github.com/opentracing/specification +This document is a kind of a "quick start" for the official specification: https://github.com/opentracing/specification -There are several concepts expose by the OpenTracing API: +There are several concepts exposed by the OpenTracing API: * The core API used for instrumenting the code -* The tracer implementations, in charge of generating physically the traces. For instance the Datadog Java Tracer generates -traces that can be consumed by the Datadog agent. -* The Asynchronous API to help developers managing their spans and traces in a concurrency context. +* The tracer implementations are in charge of capturing and reporting the traces. For instance `dd-trace` generates and reports traces to the Datadog trace agent. +* In-process trace propagation for trace consistency in a concurrent/asynchronous request context. +* Distributed trace propagation for when receiving a request and making external calls. ## OpenTracing Core API -Official documentation link: [Opentracting Tracer specification](https://github.com/opentracing/specification/blob/master/specification.md#tracer) +Official documentation link: [Opentracting Tracer specification](https://github.com/opentracing/specification/blob/master/specification.md) The core API exposes 3 main objects: -* A **Tracer** -* A **Span** -* A collection of **Tags** +* A [Tracer](https://github.com/opentracing/specification/blob/master/specification.md#tracer) +* A [Span](https://github.com/opentracing/specification/blob/master/specification.md#span) +* A collection of **Tags** associated with a Span +### Tracers -The tracer is in charge of instantiate new spans, and sending them to the appropriate sink. +The tracer is in charge of instantiating new spans for a given context, and sending them to the appropriate sink when complete. -The tracer instantiate depends of the implementation you chose. For instance, the Datadog Java Tracer allows you +The tracer instantiation depends of the implementation you chose. For instance, `dd-trace` allows you to send the traces to a logger or directly to a running Datadog agent. ```java - // Initialize the Datadog Java Tracer - Tracer tracer = new DDTracer(); + // Initialize the Datadog Java Tracer to write traces to the log: + Tracer tracer = new DDTracer(); ``` -Once a tracer is instantiated, you can use it to create and manage span. OpenTracing defines a SpanBuilder accessible through -the method `buildSpan(String operationName)` to serve this purpose. - +After a tracer is created, you will usually want to register it with the `GlobalTracer` +to make it accessible all OpenTracing instrumentation in your JVM. ```java - // Create a new Span with the operation name "componentTracking" - Span current = tracer.buildSpan("componentTracking").startActive(); + io.opentracing.util.GlobalTracer.register(tracer); ``` -This example creates a simple span referenced "componentTracking". The `startActive()` method starts a new span and set it -as the active. This means that all new spans created after will be related to this one as children. If a span is already -the active one, the new span will replace it. +### Spans +Once a tracer is instantiated, you can use it to create and manage span. OpenTracing defines a SpanBuilder +accessible through the method `buildSpan(String operationName)` to serve this purpose. + +```java + // Create a new Span with the operation name "componentTracking" + ActiveSpan current = tracer.buildSpan("componentTracking").startActive(); +``` + +This example creates a simple span referenced "componentTracking". The `startActive()` method starts a new span and sets it +as the active span. This means that any new span created going forward on the same thread will reference this as its' parent. +If another span is already active, the new span will replace it. **A collection of related spans is called a trace.** -But, sometimes you need to create a span without promoting it as the active. If you want to do that, use the `startManual()` +Sometimes you need to create a span without promoting it as the active. If you want to do that, use the `startManual()` method instead. - ```java - // Create a span, but do not promoting it as the active span - Span anotherSpan = tracer.buildSpan("componentTracking").startManual(); + // Create a span, but do not promoting it as the active span + Span anotherSpan = tracer.buildSpan("componentTracking").startManual(); ``` - -Typically, span creations are made in the begging of the methods you want to trace. +Typically, span creations are made in the beginning of the methods you want to trace. And of course, you need to finish/close the span in order to get the operation duration. This is achieving using the `finish` method. ```java - // Finishing the tracing operation - current.finish() + // Finishing the tracing operation + current.finish() ``` -**Be careful!!** You have to be sure that all children spans are finished/closed before calling the method on the root span. -If you don't do this, you may face to span incomplete issues or some traces/spans will not be reported by the tracer. +**Be careful!!** All children spans must be finished/closed before finishing the root span. +If child spans are unfinished when the parent attempts to finish, the span will remain incomplete and risk being unreported. Now, you are able to create, start and stop very simple spans. -You can manipulate them at any time and add extra information using the tags. -Tags are local to the span. So, no tags will be inherit from the parent. In order to propagate meta accross all spans of a -trace, use the `baggageItems` (see right after). +You can manipulate them at any time and add contextual information using tags. -OpenTracing Tags are standardized meta and allow developers to add more value to the span. +### Tags + +Tags are local to each span and no tags will be inherited from the parent. Information relevant to all spans in a trace +should be stored as [baggage](#baggage). + +OpenTracing defines a [standard set of tags](https://github.com/opentracing/specification/blob/master/semantic_conventions.md#standard-span-tags-and-log-fields) and should be used appropriately. Custom tags can also be defined as needed. ```java - // Create a span, but do not promoting it as the active span - Span valuableSpan = tracer. - buildSpan("componentTracking") - .withTag("custom-meta", "some-useful-value") - .withTag(Tags.COMPONENT, "my-component-mysql") - .startActive(); + // Create a span and set it as the active span + ActiveSpan valuableSpan = tracer. + buildSpan("componentTracking") + .withTag("custom-meta", "some-useful-value") + .withTag(Tags.COMPONENT, "my-component-mysql") + .startActive(); - // Somewhere further in the code - Tags.HTTP_URL.setTag(valuableSpan, "https://my-endpoint/resource/item"); - Tags.HTTP_STATUS.setTag(valuableSpan, 200); + // Somewhere further in the code + Tags.HTTP_URL.setTag(valuableSpan, "https://my-endpoint/resource/item"); + Tags.HTTP_STATUS.setTag(valuableSpan, 200); ``` -All standardized tags can be consulted there: [OpenTracing Semantic specification](https://github.com/opentracing/specification/blob/master/semantic_conventions.md) +### Baggage -So, tags are local to the span. If you want set for meta for a trace, you have to use `baggabeItems` instead. -Baggage are very similar to the tags, but they have a powerful capabilities: -* A baggage is attached to all spans of a trace. -* A baggage is propagated outside the trace context via Http or Tcp protocols (depends of the tracer implementation). +Information relevant for the entire trace is stored as baggage. +Baggage is very similar to tags, but has important distinctions. Baggage is: +* Associated with all spans for a trace. +* Propagated outside the trace context via HTTP or Messaging protocols (depends of the tracer implementation). ```java - // Like tags, you can add baggage item to the span - valuableSpan.setBaggageItem("username", "@gpolaert"); + // Like tags, you can add baggage item to the span + valuableSpan.setBaggageItem("username", "modernmajorgeneral"); ``` - ## OpenTracing Asynchronous API -see WIP: https://github.com/opentracing/specification/issues/23 + +An `ActiveSpan` can generate a `Continuation` as a way of propagating traces from across a thread boundary. + +On the parent thread: +```java + Continuation spanContinuation = valuableSpan.capture(); + // pass the continuation onto a new thread +``` + +On a different thread: +```java + ActiveSpan valuableSpan = spanContinuation.activate(); + // span is now active on the new thread +``` + +## OpenTracing Cross Process Propagation + +Spans are associated across processes in a trace via the `Tracer.extract` and `Tracer.inject` methods. + +```java + // On the start of a new trace in an application, associate incoming request with existing traces. + SpanContext spanCtx = tracer.extract(Format.Builtin.HTTP_HEADERS, someTextMapInstance); + ActiveSpan currentSpan = tracer.buildSpan("componentTracking").asChildOf(spanCtx).startActive(); +``` + +```java + // When making an external call propagate the trace by injecting it into the carrier... + tracer.inject(currentSpan.context(), Format.Builtin.HTTP_HEADERS, someTextMapInstance); +```