Added Redis instrumentation via Jedis client 2.9 and changed spring-boot-jdbc to spring-boot-jdbc-redis
This commit is contained in:
parent
53ceb74912
commit
cef86291e3
|
@ -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
|
||||
}
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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)
|
||||
|
||||
|
||||
|
|
|
@ -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).
|
|
@ -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"
|
|
@ -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"]
|
||||
}
|
||||
}
|
||||
|
|
@ -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();
|
||||
}
|
||||
}
|
|
@ -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();
|
|
@ -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
|
|
@ -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'
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue