diff --git a/dd-trace-examples/spring-boot-jdbc/README.md b/dd-trace-examples/spring-boot-jdbc/README.md index 335ce3afab..6181e979b3 100644 --- a/dd-trace-examples/spring-boot-jdbc/README.md +++ b/dd-trace-examples/spring-boot-jdbc/README.md @@ -4,29 +4,77 @@ This project aims at demonstrating how to instrument legacy code based on the SpringBoot framework and a MySQL JDBC connection. -Along with the [opentracing agent](https://github.com/opentracing-contrib/java-agent) we use 2 Opentracing contributions: - * The JDBC contrib, that intercepts and trace all the calls to the DB - * The Spring-Boot contrib, which intercepts and trace all incoming HTTP calls +We are using the [opentracing contributions](https://github.com/opentracing-contrib) in order to trace: + * All the JDBC queries and calls to the DB + * All incoming HTTP calls + + +The instrumentation is injected via the Datadog Java Agent. Java agents allows developers to execute +some code before starting the legacy application. All operations for instrumenting the code are done +at this time. -Each contribution hides the complexity to the developers. - ### Run the demo +The demo consistes into a very simple backend backed by a MySQL db. The Spring Boot application exposes +2 endpoints that can be reached via an HTTP request. + #### Prerequisites -1. Please make sure that you read and executed the prerequisites provided [on this page](../../../raclette-java-examples/README.md) -2. Make also sure that you have a MySQL DB running (and an access to it). Then [Update your settings here](src/main/resources/application.properties). +1. Run the latest version of Datadog Agent. For instance, you can run it through a docker container: + `docker run -d --name dd-agent -v /var/run/docker.sock:/var/run/docker.sock:ro -v /proc/:/host/proc/:ro -v /sys/fs/cgroup/:/host/sys/fs/cgroup:ro -e API_KEY= -e SD_BACKEND=docker -p 8126:8126 -P datadog/docker-dd-agent:latest` +2. Run an instance of MyQSL. This could also be done using docker: + `docker run -dt --name mysql -e MYSQL_ROOT_PASSWORD=root -p 3306:3306 -e MYSQL_DATABASE=springdb mysql` #### Run the application -If you want to enable tracing you have to launch the application with the datadog java agent. +The first step is to edit the Spring configuration file and the Datadog Tracer file and check if the +connection properties are okay. -That can be done by providing the following JVM argument (assuming the `M2_REPO` env variable is set and we run version `{version}`): -`-javaagent:${M2_REPO}/com/datadoghq/dd-java-agent/{version}/dd-java-agent-{version}.jar`. +```properties +# file: src/resources/application.properties -There are 2 ways to test it: +spring.datasource.driver-class-name= io.opentracing.contrib.jdbc.TracingDriver +spring.datasource.url= jdbc:tracing:mysql://localhost:3306/springdb +spring.datasource.username=root +spring.datasource.password=root +``` -- Either with Maven: `mvn spring-boot:run -Djavaagent:${M2_REPO}/com/datadoghq/dd-java-agent/{version}/dd-java-agent-{version}.jar` -- Or if you prefer with your IDE providing the java agent command +```yaml +# file: src/resources/dd-trace.yaml + +# Service name used if none is provided in the app +defaultServiceName: spring-app + +# The writer to use. +writer: + type: DDAgentWriter + host: localhost + port: 8126 + +# The sampler to use. +sampler: + type: AllSampler +``` + +Then, is to run the Spring Application along the Datadog Java Agent. + +- So first download the `jar` file from the main repository. + +``` +# use latest version +curl -OL http://central.maven.org/maven2/com/datadoghq/dd-java-agent/{version}/dd-java-agent-{version}.jar +``` + +- Then add the following JVM argument when launching your application (in IDE, using Maven run or simply in collaboration with the `>java -jar` command): + +``` +-javaagent:/path/to/the/dd-java-agent-{version}.jar +``` + +- Finally, run the application through your IDE or Maven with the `javaagent` option. + +``` +mvn spring-boot:run -Djavaagent:/path/to/the/dd-java-agent-{version}.jar +``` ### Generate traces diff --git a/dd-trace/README.md b/dd-trace/README.md index fea1c8e44c..dcdcd292f7 100644 --- a/dd-trace/README.md +++ b/dd-trace/README.md @@ -1,17 +1,18 @@ -## Datadog Java Tracer +# Datadog Opentracing Tracer -### Motivations +## Motivations -The Datadog Java Tracer is an OpenTracing-compatible tracer. It provides all resources needed to instrument your code. +The Datadog Tracer is an [Opentracing](http://opentracing.io/) compatible tracer. It provides all resources needed to instrument your code +and report each operation and each trace directly to a Datadog APM platform. -Opentracing introduces the concept of the **span**. A span is **timed operation** representing "a bounded process" in the code. -The spans can **be linked together**. And a **trace** is a list of spans, each related to the same top action/operation. +Opentracing uses the concept of the **span**. A span is **timed operation** representing a bunch of work executed. +Spans can **be linked together**. And a **trace** is a collection of spans, related to the same top action/operation. Let's see an example. -The workflow can be a client requesting, via a HTTP endpoint, some resources store in a DB. -Look at the following scheme. +For instance, a client requesting a resource through an HTTP endpoint. +Look at the following workflow. ```` TRACE: @@ -31,27 +32,31 @@ As just described, the tracer produces a trace composed of 4 spans, each represe 2. Span2 is the Span1's first child, representing the amount of time to understand the query, and perform the query on the DB. 3. Span3, a Span1' grandchild, represents the DB time used to retrieve the data -4. Span4 is a child of Span2 and followed Span3. It represents a business process for instance. +4. Span4 is a child of Span2 and followed Span3. It represents a business/legacy operation. This is a very simple example of how works [Opentracing](http://opentracing.io/). -Do not hesitate to go deeper and read the full documentation: http://opentracing.io/ +To dig deeper, read the full documentation: http://opentracing.io/ -### How to instrument well-known framework? +## How to instrument your application? -Datadog instruments many frameworks and libraries by default: SpringBoot, JDBC, Mongo, JMS, Tomcat, etc. -Check the dedicated project and agent: [dd-java-agent](../dd-java-agent) +In order to start to instrument your application, you need to: +1. [Configure the Datadog Tracer](#config) +2. Choose one of the 3 ways to instrument an application: + 1. [Use the autotracing agent for supported frawemorks](#framework) + 2. [Use the Opentracing API](#api) + 3. [Use annotations](#annotation) -### How the Datadog Tracer (DDTrace) is loaded in the project? +### Datadog Tracer configuration -This current implementation uses the trace-resolver feature provides by Opentracing. -That means you can add and load the tracer using a Java Agent directly with the JVM. - -The DDTrace is autoconfigured using the YAML file provided in the project: `dd-trace.yaml`. -By default, the DDTrace tries to reach a local Datadog Agent, but you can change the settings and use a different +The DDTracer is auto-configured using this YAML file. + +By default, the DDTracer tries to reach a local Datadog Agent, but you can change the settings and use a different location. In order to do that, please, refer you to the latest configuration: [dd-trace.yaml](src/main/resources/dd-trace.yaml) +*Make sure that file is present in your classpath*. + ```yaml # Service name used if none is provided in the app defaultServiceName: unnamed-java-app @@ -76,78 +81,162 @@ sampler: type: AllSampler ``` -To attach the agent to the JVM, you simply have to declare the provided `jar` file in your -JVM arguments as a valid `-javaagent:`. We assume that your `${M2_REPO}` env variable is properly set. -Don't forget to replace the `{version}` placeholder in the following commands. + +### Use the Datadog Java agent for well-known framework -So first download the `jar` file from the main Maven repository: +Datadog uses instrumentation contributed by [the community](https://github.com/opentracing-contrib) to instrument many frameworks: +SpringBoot, JDBC, Mongo, JMS, Tomcat, etc. By using the Datadog Java agent, you just need to follow few steps in order to get traces. + + +Get the latest version of the Datadog Java agent (Do not forget to replace the version `${version}` by the appropriate one). +```bash +version=0.1.1 +curl -OL http://central.maven.org/maven2/com/datadoghq/dd-java-agent/${version}/dd-java-agent-${version}.jar ``` -> mvn dependency:get -Dartifact=io.opentracing-contrib:opentracing-agent:${version} -``` -Then add the following JVM argument when launching your application (in IDE, using Maven run or simply in collaboration with the `>java -jar` command): +Then, attach the Java agent to your JVM using th `javaagent` option. -``` --javaagent:${M2_REPO}/io/opentracing-contrib/opentracing-agent/${version}/opentracing-agent-${version}.jar +```bash +java -javaagent:/path/to/dd-java-agent-${version}.jar ... ``` - -At this point, the DDTrace is loaded in the project. Let's see now how to instrument it. - -### How to use the Datadog Tracer (DDTrace) for instrumenting legacy code? - -Once, the DDTrace is loaded, you can start to instrument your code using the Opentracing SDK or the `@Trace` annotation. -`@Trace` is actually a Datadog specific, but we plan to submit it to Opentracing foundation. - -To use them, you have to add the dependency to the DDTrace. -Just edit you `pom.xml` and add this: - -```xml - - com.datadoghq - dd-trace - ${dd-trace-java.version} - -``` +If you have a local Datadog agent running on your host, traces are visible in your Datadog account. -You can start as shown below, here is an example how to use both of them to instrument 2 simple methods. +You can choose which framework you want to instrument, or sending traces to a remote Datadog agent by configuring the Datadog Java Agent YAML file. +Check the dedicated project for the full documentation: [dd-java-agent](../dd-java-agent) + + +### 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). + +Let's look at a simple example. + ```java class InstrumentedClass { + - @Trace - void methodAnnoted() { - // The annotation will do the same thing as the manual instrumentation below - //Do some thing here ... - Thread.sleep(1_000); - } - - void methodSDK() { + void method0() { // Retrieve the tracer using the resolver provided // Make sure you have : // 1. added the agent to the jvm (-javaagent;/path/to/agent.jar) // 2. a dd-trace.yaml file in your resources directory Tracer tracer = io.opentracing.util.GlobalTracer.get(); - Span span = tracer.buildSpan("operation-name").build(); + Span span = tracer.buildSpan("operation-name").startActive(); + new io.opentracing.tag.StringTag("service-name").set(span, "new-service-name"); + //Do some thing here ... Thread.sleep(1_000); // Close the span, the trace will automatically reported to the writer configured - span.close(); + span.finish(); } } +``` + +The method above is now instrumented. As you can see, the tracer is retrieved from a global registry, called `GlobalTracer`. + +The last thing you have to do is providing a configured tracer. This can be easily done by using the `TracerFactory` or manually +in the bootstrap method (like the `main`). + +```java +public class Application { + + public static void main(String[] args) { + + // Init the tracer from the configuration file + Tracer tracer = DDTracerFactory.createFromConfigurationFile(); + io.opentracing.util.GlobalTracer.register(tracer); + + // Init the tracer from the API + Writer writer = new com.datadoghq.trace.writer.DDAgentWriter(); + Sampler sampler = new com.datadoghq.trace.sampling.AllSampler(); + Tracer tracer = new com.datadoghq.trace.DDTracer(writer, sampler); + io.opentracing.util.GlobalTracer.register(tracer); + + // ... + } +} ``` -If you have a running Datadog Agent with the [APM feature enabled](http://docs.datadoghq.com/tracing/), you should -see traces directly to your Datadog account. +The factory looks for a `dd-trace.yaml` file in the classpath. + +Finally, do not forget to add the corresponding dependencies to your project. +``` + + + io.opentracing + opentracing-api + ${opentracing.version} + + + + + com.datadoghq + dd-trace + ${dd-trace-java.version} + + + compile group: 'io.opentracing', name: 'opentracing-api', version: '${opentracing.version}' + compile group: 'com.datadoghq', name: 'dd-trace', version: '${dd-trace-java.version}' -### Other useful resources +``` + + +### Custom instrumentations using Annotation + +Datadog provides a third way to instrument your code: annotations. +The following example is the same as above. Just add `@Trace` to the methods you want to instrument. + +```java +class InstrumentedClass { + + @Trace(operationName = "operation-name-1") + void method1() { + + //Do some thing here ... + Thread.sleep(1_000); + } + + @Trace(operationName = "operation-name-2") + void method2() { + + // You can get the current span and add tag as follow + Span current = io.opentracing.util.GlobalTracer.get().activeSpan(); + new io.opentracing.tag.StringTag("service-name").set(current, "new-service-name"); + + //Do some thing here ... + Thread.sleep(1_000); + } +} +``` + +In order to use annotations, the only required dependency is that package. +``` + + + com.datadoghq + dd-trace-annotations + ${dd-trace-java.version} + + + compile group: 'com.datadoghq', name: 'dd-trace-annotations', version: '${dd-trace-java.version}' +``` +The annotations are resolved at the runtime by the Datadog Java agent. If you want to use the annotations, +so you must run the Datadog Java Agent. + +To run the agent, please refer to the Datadog Java agent documentation: [dd-java-agent](../dd-java-agent) + + +## Other useful resources Before instrumenting your own project you might want to run the provided examples: diff --git a/dd-trace/docs/opentracing-api.md b/dd-trace/docs/opentracing-api.md new file mode 100644 index 0000000000..338f6b49a3 --- /dev/null +++ b/dd-trace/docs/opentracing-api.md @@ -0,0 +1,110 @@ +# Opentracing API + + +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 + +There are several concepts expose 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. + + +## Opentracing Core API + +Official documentation link: [Opentracting Tracer specification](https://github.com/opentracing/specification/blob/master/specification.md#tracer) + +The core API exposes 3 main objects: + +* A **Tracer** +* A **Span** +* A collection of **Tags** + + + +The tracer is in charge of instantiate new spans, and sending them to the appropriate sink. + +The tracer instantiate depends of the implementation you chose. For instance, the Datadog Java Tracer 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(); +``` + +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" + Span current = tracer.buildSpan("componentTracking").startActive(); +``` + +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. + +**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()` + method instead. + + +```java + // 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. +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() +``` + +**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. + + +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). + +Opentracing Tags are standardized meta and allow developers to add more value to the span. + +```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(); + + + // 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) + +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). + +```java + // Like tags, you can add baggage item to the span + valuableSpan.setBaggageItem("username", "@gpolaert"); +``` + + +## Opentracing Asynchronous API +see WIP: https://github.com/opentracing/specification/issues/23 \ No newline at end of file