ddtrace-api Usage Guide¶
Warning
The current case is tested with the corresponding version of ddtrace
Prerequisites¶
-
Enable DataKit ddtrace Collector
-
Prepare Shell
java -javaagent:dd-java-agent-v1.34.0-guance.jar \
-Ddd.service.name=ddtrace-server \
-Ddd.agent.port=9529 \
-jar springboot-ddtrace-server.jar
Installation and Deployment¶
Add Maven pom Dependency¶
<dependency>
<groupId>com.datadoghq</groupId>
<artifactId>dd-trace-api</artifactId>
<version>1.34.0</version>
</dependency>
<dependency>
<groupId>io.opentracing</groupId>
<artifactId>opentracing-api</artifactId>
<version>0.33.0</version>
</dependency>
<dependency>
<groupId>io.opentracing</groupId>
<artifactId>opentracing-mock</artifactId>
<version>0.33.0</version>
</dependency>
<dependency>
<groupId>io.opentracing</groupId>
<artifactId>opentracing-util</artifactId>
<version>0.33.0</version>
</dependency>
Obtain Tracer¶
Get the Tracer object via GlobalTracer
Tracer tracer = GlobalTracer.get();
Through Tracer, you can get information about the current span.
Span span = tracer.activeSpan();
// Get tracer object
Tracer tracer = GlobalTracer.get();
// Get current span object
Span span = tracer.activeSpan();
if (span!=null) {
// Get traceId
String traceId = span.context().toTraceId();
// Get spanId
String spanId = span.context().toSpanId();
}
Function-level Instrumentation¶
In addition to the dd.trace.methods
method for proactive instrumentation of methods, ddtrace provides an API method that allows more flexible instrumentation of business logic.
- Add the
@Trace
annotation to the corresponding method that needs instrumentation.
- Then call this in the
gateway
method.
- Restart and access gateway
Note: Intrusive instrumentation does not mean that the agent is not required when starting the application. Without the agent,
@Trace
will also be invalid. The@Trace
annotation has a default operation nametrace.annotation
, while tracked methods have resources by default.
You can modify the corresponding names.
@Trace(resourceName = "apiTrace",operationName = "apiTrace")
public String apiTrace(){
return "apiTrace";
}
After modification, the effect is as follows:
Using Baggage to Pass Business Critical Tags Through Backend Chains¶
ddtrace provides the Baggage
method. More accurately, ddtrace uses the Baggage
feature provided by OpenTracing to pass specified tags through the chain. For example, username, position information, etc., which makes it easier to analyze user behavior.
1 Write TraceBaggageFilter¶
By using the TraceBaggageFilter
method to intercept requests and pass related parameters from request header
through Baggage
.
package com.zy.observable.ddtrace;
import io.opentracing.Span;
import io.opentracing.util.GlobalTracer;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Component;
import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
import java.util.Enumeration;
/**
* Baggage can pass tags between chains, by obtaining the current request header, set the headers with a specified prefix as Baggage.
* @author liurui
* @date 2022/7/19 14:59
*/
@Component
public class TraceBaggageFilter implements Filter {
/**
* Pass headers with a specified prefix through the chain
*/
private static final String PREFIX = "dd-";
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
final Span span = GlobalTracer.get().activeSpan();
if (span != null) {
HttpServletRequest request = (HttpServletRequest)servletRequest;
Enumeration<String> headerNames = request.getHeaderNames();
while (headerNames.hasMoreElements()) {
final String header = headerNames.nextElement();
String value = request.getHeader(header);
if (StringUtils.startsWith(header,PREFIX) && StringUtils.isNotBlank(value)){
// Baggage can be passed between chains, while ordinary tags cannot
span.setBaggageItem(header.replace(PREFIX,""),value);
}
}
}
filterChain.doFilter(servletRequest,servletResponse);
}
}
2 DataKit Configuration¶
This requires using the ddtrace collector configuration of DataKit together. You need to add custom tags through the customer_tags
method; otherwise, this data will only exist in meta
.
3 Initiate a Request¶
Initiate a gateway request carrying two headers: dd-username
and dd-job
. The system will recognize dd
prefixed header parameters and pass them through all current chain spans.
Effect Display¶
Customization¶
Custom traceId¶
Please refer to the best practices document: <Implementing custom traceId using extract + TextMapAdapter>
Custom span¶
Usually, applications handle business logic exceptions, and related chains may not be marked as error, leading to inability to normally count the application's error traces. Generally, these are try-catch or global exception captures.
At this point, marking the chain is needed. By customizing the span, these spans can be marked as error spans, and marking can be done at the catch location.
- Get current span information via the following method.
- Mark span as error.
If the current method is placed inside a catch block, the track information can also be output to the span.
The error span handling logic can be made into a common function for global use. The code is shown below:
private void buildErrorTrace(Exception ex) {
final Span span = GlobalTracer.get().activeSpan();
if (span != null) {
span.setTag(Tags.ERROR, true);
span.log(Collections.singletonMap(Fields.ERROR_OBJECT, ex));
span.setTag(DDTags.ERROR_MSG, ex.getMessage());
span.setTag(DDTags.ERROR_TYPE, ex.getClass().getName());
final StringWriter errorString = new StringWriter();
ex.printStackTrace(new PrintWriter(errorString));
span.setTag(DDTags.ERROR_STACK, errorString.toString());
}
}
Caller code
@GetMapping("/gateway")
@ResponseBody
public String gateway(String tag) {
......
try {
if (client) {
httpTemplate.getForEntity("http://" + extraHost + ":8081/client", String.class).getBody();
}
} catch (Exception e) {
buildErrorTrace(e);
}
return httpTemplate.getForEntity(apiUrl + "/billing?tag=" + tag, String.class).getBody();
}