Added Redis instrumentation via Jedis client 2.9 and changed spring-boot-jdbc to spring-boot-jdbc-redis

This commit is contained in:
Gihad Murad 2018-02-05 12:59:42 -05:00
parent 53ceb74912
commit cef86291e3
19 changed files with 137 additions and 21 deletions

View File

@ -0,0 +1,13 @@
apply from: "${rootDir}/gradle/java.gradle"
dependencies {
compileOnly group: 'redis.clients', name: 'jedis', version: '2.9.0'
compile project(':dd-trace-ot')
compile project(':dd-java-agent:tooling')
compile deps.bytebuddy
compile deps.opentracing
compile deps.autoservice
}

View File

@ -0,0 +1,74 @@
package datadog.trace.instrumentation.jedis;
import static net.bytebuddy.matcher.ElementMatchers.hasSuperType;
import static net.bytebuddy.matcher.ElementMatchers.isInterface;
import static net.bytebuddy.matcher.ElementMatchers.isMethod;
import static net.bytebuddy.matcher.ElementMatchers.isProtected;
import static net.bytebuddy.matcher.ElementMatchers.nameStartsWith;
import static net.bytebuddy.matcher.ElementMatchers.named;
import static net.bytebuddy.matcher.ElementMatchers.not;
import static net.bytebuddy.matcher.ElementMatchers.takesArgument;
import com.google.auto.service.AutoService;
import datadog.trace.agent.tooling.DDAdvice;
import datadog.trace.agent.tooling.Instrumenter;
import datadog.trace.api.DDTags;
import io.opentracing.Scope;
import io.opentracing.Span;
import io.opentracing.tag.Tags;
import io.opentracing.util.GlobalTracer;
import java.util.Collections;
import net.bytebuddy.agent.builder.AgentBuilder;
import net.bytebuddy.asm.Advice;
import redis.clients.jedis.Protocol.Command;
@AutoService(Instrumenter.class)
public final class JedisInstrumentation implements Instrumenter {
@Override
public AgentBuilder instrument(final AgentBuilder agentBuilder) {
return agentBuilder
.type(not(isInterface()).and(hasSuperType(named("redis.clients.jedis.Connection"))))
.transform(
DDAdvice.create()
.advice(
isMethod()
.and(isProtected())
.and(nameStartsWith("sendCommand"))
.and(takesArgument(1, byte[][].class)),
JedisAdvice.class.getName()))
.asDecorator();
}
public static class JedisAdvice {
@Advice.OnMethodEnter(suppress = Throwable.class)
public static Scope nameResource(@Advice.Argument(0) final Command command) {
final Scope scope = GlobalTracer.get().buildSpan("redis.command").startActive(true);
final Span span = scope.span();
Tags.DB_TYPE.set(span, "redis");
Tags.SPAN_KIND.set(span, Tags.SPAN_KIND_CLIENT);
Tags.COMPONENT.set(span, "redis-command");
span.setTag(DDTags.RESOURCE_NAME, command.name());
span.setTag(DDTags.SERVICE_NAME, "redis");
span.setTag(DDTags.SPAN_TYPE, "redis");
span.setTag("span.origin.type", command.getClass().getName());
return scope;
}
@Advice.OnMethodExit(onThrowable = Throwable.class, suppress = Throwable.class)
public static void stopSpan(
@Advice.Enter final Scope scope, @Advice.Thrown final Throwable throwable) {
if (throwable != null) {
final Span span = scope.span();
Tags.ERROR.set(span, true);
span.log(Collections.singletonMap("error.object", throwable));
}
scope.close();
}
}
}

View File

@ -7,7 +7,7 @@ using the OpenTracing API and the DD Tracer.
Here are the examples
* [Dropwizard (Jax-Rs) + Mongo database + HTTP Client](dropwizard-mongo-client/README.md)
* [Spring-boot + MySQL JDBC database](spring-boot-jdbc/README.md)
* [Spring-boot + MySQL JDBC database + Redis (Jedis client)](spring-boot-jdbc-redis/README.md)
* [Instrumenting using a Java Agent](javaagent/README.md)

View File

@ -15,9 +15,9 @@ all libraries and examples launching from the ``dd-trace-java`` root folder:
./gradlew clean shadowJar bootRepackage
```
Then you can launch the Datadog agent as follows:
Then you can launch the Datadog agent and a Redis instance as follows:
```bash
cd examples/spring-boot-jdbc
cd examples/spring-boot-jdbc-redis
DD_API_KEY=<your_datadog_api_key> docker-compose up -d
```
@ -31,12 +31,12 @@ To launch the application, just:
```
*Note: The ``bootRun`` Gradle command appends automatically the ``-javaagent`` argument, so that you don't need to specify
the path of the Java Agent. Gradle executes the ``:examples:spring-boot-jdbc:bootRun`` task until you
the path of the Java Agent. Gradle executes the ``:examples:spring-boot-jdbc-redis:bootRun`` task until you
stop it.*
Or as an executable jar:
```bash
java -javaagent:../../dd-java-agent/build/libs/dd-java-agent-{version}.jar -Ddd.service.name=spring-boot-jdbc -jar build/libs/spring-boot-jdbc-demo.jar
java -javaagent:../../dd-java-agent/build/libs/dd-java-agent-{version}.jar -Ddd.service.name=spring-boot-jdbc-redis -jar build/libs/spring-boot-jdbc-redis-demo.jar
```
### Generate traces
@ -45,6 +45,7 @@ Once the Gradle task is running. Go to the following urls:
* [http://localhost:8080/user/add?name=foo&email=bar](http://localhost:8080/user/add?name=foo&email=bar)
* [http://localhost:8080/user/all](http://localhost:8080/user/all)
* [http://localhost:8080/user/all](http://localhost:8080/user/random)
Then get back to Datadog and wait a bit to see a trace coming.
@ -55,5 +56,6 @@ instruments:
- The java servlet filters
- The JDBC driver
- The Jedis Redis client
The Java Agent embeds the [OpenTracing Java Agent](https://github.com/opentracing-contrib/java-agent).

View File

@ -5,3 +5,7 @@ ddagent:
- DD_API_KEY
ports:
- "127.0.0.1:8126:8126"
redis:
image: redis
ports:
- "127.0.0.1:6379:6379"

View File

@ -1,19 +1,21 @@
plugins {
id 'org.springframework.boot' version '1.5.4.RELEASE'
id 'org.springframework.boot' version '1.5.10.RELEASE'
}
apply from: "${rootDir}/gradle/java.gradle"
apply from: "${rootDir}/gradle/jacoco.gradle"
version = 'demo'
description = 'spring-boot-jdbc'
description = 'spring-boot-jdbc-redis'
dependencies {
compile group: 'org.apache.httpcomponents', name: 'httpclient', version: '4.5.3'
compile group: 'com.h2database', name: 'h2', version: '1.4.196'
compile group: 'org.springframework.boot', name: 'spring-boot-starter-web', version: '1.5.4.RELEASE'
compile group: 'org.springframework.boot', name: 'spring-boot-starter-data-jpa', version: '1.5.4.RELEASE'
compile group: 'org.springframework.boot', name: 'spring-boot-starter-web', version: '1.5.10.RELEASE'
compile group: 'org.springframework.boot', name: 'spring-boot-starter-data-jpa', version: '1.5.10.RELEASE'
compile group: 'org.springframework.boot', name: 'spring-boot-starter-data-redis', version: '1.5.10.RELEASE'
}
bootRepackage {
@ -22,9 +24,9 @@ bootRepackage {
bootRun {
if (project.hasProperty('javaagent')) {
jvmArgs = ["-javaagent:$javaagent", "-Ddd.service.name=spring-boot-jdbc"]
jvmArgs = ["-javaagent:$javaagent", "-Ddd.service.name=spring-boot-jdbc-redis"]
} else {
jvmArgs = ["-javaagent:${project(':dd-java-agent').tasks.shadowJar.outputs.files.getFiles().iterator().next()}", "-Ddd.service.name=spring-boot-jdbc"]
jvmArgs = ["-javaagent:${project(':dd-java-agent').tasks.shadowJar.outputs.files.getFiles().iterator().next()}", "-Ddd.service.name=spring-boot-jdbc-redis"]
}
}

View File

@ -3,6 +3,8 @@ package datadog.examples.resources;
import datadog.examples.entities.User;
import datadog.examples.entities.UserRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.core.ValueOperations;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
@ -17,9 +19,16 @@ public class DBResource {
// Which is auto-generated by Spring, we will use it to handle the data
private UserRepository userRepository;
private ValueOperations<String, String> ops;
public DBResource(@Autowired StringRedisTemplate template) {
this.ops = template.opsForValue();
}
@GetMapping(path = "/add") // Map ONLY GET Requests
public @ResponseBody String addNewUser(
@RequestParam final String name, @RequestParam final String email) {
// @ResponseBody means the returned String is the response, not a view name
// @RequestParam means it is a parameter from the GET or POST request
@ -27,6 +36,10 @@ public class DBResource {
n.setName(name);
n.setEmail(email);
userRepository.save(n);
// Also save to redis as key/value
ops.set(name, email);
return "Saved";
}
@ -38,7 +51,17 @@ public class DBResource {
@GetMapping(path = "/get")
public @ResponseBody User getUser(@RequestParam final int id) {
// This returns a JSON or XML with the users
// This returns a JSON or XML with the user
return userRepository.findOne(id);
}
@GetMapping(path = "/getredis")
public @ResponseBody String getUserRedis(@RequestParam final String name) {
return ops.get(name);
}
@GetMapping(path = "/random")
public @ResponseBody String flushRedis() {
return ops.getOperations().randomKey();
}
}

View File

@ -15,9 +15,13 @@ public class HomeResource {
template.append("Demo links");
template.append("<ul>");
template.append("<li><a href=\"/user/add?name=name&email=f@example.com\">Add a user</a></li>");
template.append(
"<li><a href=\"/user/add?name=unnamed&email=unnamed@example.com\">Add a user</a></li>");
template.append("<li><a href=\"/user/all\">List all users</a></li>");
template.append("<li><a href=\"/user/get?id=1\">Get user with id=1</a></li>");
template.append(
"<li><a href=\"/user/getredis?name=unnamed\">Get user with name=unnamed</a></li>");
template.append("<li><a href=\"/user/random\">Get a random user's name</a></li>");
template.append("</ul>");
return template.toString();

View File

@ -1,7 +0,0 @@
# you must set the following so that OpenTracing traced driver is used
spring.datasource.driver-class-name=org.h2.Driver
spring.datasource.url=jdbc:h2:mem:spring-test;DB_CLOSE_ON_EXIT=FALSE
# set the logging level
logging.level.root=INFO
logging.level.datadog.trace=DEBUG

View File

@ -12,6 +12,7 @@ include ':dd-java-agent:instrumentation:apache-httpclient-4.3'
include ':dd-java-agent:instrumentation:aws-sdk'
include ':dd-java-agent:instrumentation:datastax-cassandra-3.2'
include ':dd-java-agent:instrumentation:jdbc'
include ':dd-java-agent:instrumentation:jedis-2.9'
include ':dd-java-agent:instrumentation:jms-1'
include ':dd-java-agent:instrumentation:jms-2'
include ':dd-java-agent:instrumentation:mongo-3.1'
@ -31,7 +32,7 @@ if (JavaVersion.current().isJava8Compatible()) {
// examples
include ':examples:dropwizard-mongo-client'
include ':examples:spring-boot-jdbc'
include ':examples:spring-boot-jdbc-redis'
include ':examples:rest-spark'
}