Skip to content

Commit f2bf3ca

Browse files
authored
Deprecate old HTTP wrapping methods and add instructions for installing dd-trace-java. (#31)
* Deprecate old HTTP wrapping methods and start on trace/log correlation instructions * Check for traceId 0 * Change distributed tracing notes * Add trace/log correlation notes * README.md * Publish latest tracer layer * Add more docs, bump version
1 parent dedef5a commit f2bf3ca

File tree

4 files changed

+128
-152
lines changed

4 files changed

+128
-152
lines changed

README.md

Lines changed: 84 additions & 143 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,8 @@ to the Datadog API.
1414

1515
## Installation
1616

17-
This library will be distributed through JFrog [Bintray](https://bintray.com/beta/#/datadog/datadog-maven/datadog-lambda-java). Follow the [installation instructions](https://docs.datadoghq.com/serverless/installation/java/), and view your function's enhanced metrics, traces and logs in Datadog.
17+
This library will be distributed through JFrog [Bintray](https://bintray.com/beta/#/datadog/datadog-maven/datadog-lambda-java).
18+
Follow the [installation instructions](https://docs.datadoghq.com/serverless/installation/java/), and view your function's enhanced metrics, traces and logs in Datadog.
1819

1920
## Environment Variables
2021

@@ -38,191 +39,131 @@ Once [installed](#installation), you should be able to submit custom metrics fro
3839

3940
Check out the instructions for [submitting custom metrics from AWS Lambda functions](https://docs.datadoghq.com/integrations/amazon_lambda/?tab=java#custom-metrics).
4041

41-
## Distributed Tracing
42+
## Installing the Java Tracer
4243

43-
Wrap your outbound HTTP requests with trace headers to see your lambda in context in APM.
44-
The Lambda Java Client Library provides instrumented HTTP connection objects as well as helper methods for
45-
instrumenting HTTP connections made with any of the following libraries:
44+
The [Java Tracer](https://docs.datadoghq.com/tracing/setup_overview/setup/java/?tab=containers)
45+
is an optional component that allows you to trace the execution of your Java Lambda function.
46+
The traces will be viewable from your Serverless function details page within Datadog.
4647

47-
- java.net.HttpUrlConnection
48-
- Apache HTTP Client
49-
- OKHttp3
48+
Briefly, in order to use the Java tracer, the following prerquisites must be met (detailed below):
49+
1. The `datadog-lambda-java` library must be included in your project, following these [installation instructions](https://docs.datadoghq.com/serverless/installation/java/)
50+
1. You must use a compatible Java runtime
51+
1. You must attach the Java Tracer lambda layer
52+
1. Several environment variables must be set
53+
1. Your handler must instantiate a `new DDLambda` in order to start traces, and call `DDLambda#finish` in order to end traces.
54+
5055

51-
Don't see your favorite client? Open an issue and request it. Datadog is adding to
52-
this library all the time.
56+
### Cold start considerations
5357

54-
### HttpUrlConnection examples
58+
The Java Tracer adds a nontrivial cold start penalty.
59+
Expect roughly 6 seconds per cold start if your Lambda function is configured with 3008MB of memory.
60+
Lambda runtime CPU scales with the amount of memory allocated, so allocating more memory may help alleviate cold start issues.
61+
Also consider using provisioned concurrency to keep your lambda function warm.
5562

56-
```java
57-
public class Handler implements RequestHandler<APIGatewayV2ProxyRequestEvent, APIGatewayV2ProxyResponseEvent> {
58-
public Integer handleRequest(APIGatewayV2ProxyRequestEvent request, Context context){
59-
DDLambda dd = new DDLambda(request, lambda);
60-
61-
URL url = new URL("https://example.com");
62-
HttpURLConnection instrumentedUrlConnection = dd.makeUrlConnection(url); //Trace headers included
63+
### Compatible Java runtimes
6364

64-
instrumentedUrlConnection.connect();
65-
66-
return 7;
67-
}
68-
}
69-
```
70-
71-
Alternatively, if you want to do something more complex:
65+
- java8.al2 (aka Java 8 (Corretto))
66+
- java11 (aka Java 11 (Corretto))
7267

73-
```java
74-
public class Handler implements RequestHandler<APIGatewayV2ProxyRequestEvent, APIGatewayV2ProxyResponseEvent> {
75-
public Integer handleRequest(APIGatewayV2ProxyRequestEvent request, Context context){
76-
DDLambda dd = new DDLambda(request, lambda);
77-
78-
URL url = new URL("https://example.com");
79-
HttpURLConnection hc = (HttpURLConnection)url.openConnection();
68+
If your lambda function is using Java 8, please change it to Java 8 Corretto.
69+
It's called java8.al2 if you're editing serverless.yaml.
8070

81-
//Add the distributed tracing headers
82-
hc = (HttpURLConnection) dd.addTraceHeaders(hc);
71+
### Required Lambda Layer containing the Java Tracer
8372

84-
hc.connect();
85-
86-
return 7;
87-
}
88-
}
73+
```
74+
arn:aws:lambda:[REGION]:464622532012:layer:dd-trace-java:2
8975
```
9076

91-
### Apache HTTP Client examples
77+
The lambda layer version (in this case, `2`) will always correspond with the minor version of the `datadog-lambda-java` library.
9278

93-
```java
94-
public class Handler implements RequestHandler<APIGatewayV2ProxyRequestEvent, APIGatewayV2ProxyResponseEvent> {
95-
public Integer handleRequest(APIGatewayV2ProxyRequestEvent request, Context context){
96-
DDLambda dd = new DDLambda(request, lambda);
97-
98-
HttpClient client = HttpClientBuilder.create().build();
99-
100-
HttpGet hg = dd.makeHttpGet("https://example.com"); //Trace headers included
101-
102-
HttpResponse hr = client.execute(hg);
103-
return 7;
104-
}
105-
}
79+
### Required environment variables for the Java Tracer
80+
81+
```bash
82+
JAVA_TOOL_OPTIONS: "-javaagent:\"/opt/java/lib/dd-java-agent.jar\""
83+
DD_LOGS_INJECTION: "true"
84+
DD_JMXFETCH_ENABLED: "false"
85+
DD_TRACE_ENABLED: "true"
10686
```
10787

108-
Alternatively, if you want to do something more complex:
88+
### Required code modification for the Java Tracer
89+
90+
In order to use the Java Tracer, you must instantiate a new `DDLambda` at the beginning of your Lambda function and call `DDLambda#finish()` at the end of it.
10991

11092
```java
111-
public class Handler implements RequestHandler<APIGatewayV2ProxyRequestEvent, APIGatewayV2ProxyResponseEvent> {
112-
public Integer handleRequest(APIGatewayV2ProxyRequestEvent request, Context context){
113-
DDLambda dd = new DDLambda(request, lambda);
114-
115-
HttpClient client = HttpClientBuilder.create().build();
116-
HttpGet hg = new HttpGet("https://example.com");
117-
118-
//Add the distributed tracing headers
119-
hg = (HttpGet) dd.addTraceHeaders(hg);
120-
121-
HttpResponse hr = client.execute(hg);
122-
return 7;
123-
}
124-
}
125-
```
93+
public class Handler{
12694

95+
public ApiGatewayResponse handleRequest(APIGatewayProxyRequestEvent input, Context context){
96+
DDLambda ddl = new DDLambda(input, context); // required to set various tags inside the tracer
12797

128-
### OKHttp3 Client examples
98+
ddl.metric("foo.bar", 42, null);
99+
do_some_stuff();
100+
make_some_http_requests();
129101

130-
```java
131-
public class Handler implements RequestHandler<APIGatewayV2ProxyRequestEvent, APIGatewayV2ProxyResponseEvent> {
132-
public Integer handleRequest(APIGatewayV2ProxyRequestEvent request, Context context){
133-
DDLambda dd = new DDLambda(request, lambda);
134-
135-
HttpClient client = HttpClientBuilder.create().build();
136-
OkHttpClient okHttpClient = new OkHttpClient.Builder().build();
137-
Request okHttpRequest = dd.makeRequestBuilder() // Trace headers included
138-
.url("https://example.com")
139-
.build();
140-
141-
Response resp = okHttpClient.newCall(okHttpRequest).execute();
142-
143-
return 7;
144-
}
102+
ddl.finish(); // Required to complete the trace
103+
return new ApiGatewayResponse();
104+
}
145105
}
146106
```
147107

148-
Alternatively:
108+
`DDLambda ddl = new DDLambda(input, context);` starts a new trace (if the Java Tracer agent is attached to the JRE)
109+
and sets tags based on the Lambda context. If there is a trace context attached to the request, that will be used
110+
to set the trace ID and the parent of the span.
149111

150-
```java
151-
public class Handler implements RequestHandler<APIGatewayV2ProxyRequestEvent, APIGatewayV2ProxyResponseEvent> {
152-
public Integer handleRequest(APIGatewayV2ProxyRequestEvent request, Context context){
153-
DDLambda dd = new DDLambda(request, lambda);
154-
155-
HttpClient client = HttpClientBuilder.create().build();
156-
OkHttpClient okHttpClient = new OkHttpClient.Builder().build();
157-
Request okHttpRequest = new Request.Builder()
158-
.url("https://example.com")
159-
.build();
160-
161-
//Add the distributed tracing headers
162-
okHttpRequest = dd.addTraceHeaders(okHttpRequest);
163-
164-
Response resp = okHttpClient.newCall(okHttpRequest).execute();
165-
166-
return 7;
167-
}
168-
}
169-
```
112+
`ddl.finish();` finishes the active span and closes the active trace scope.
113+
The tracer will flush the trace to Cloudwatch logs once this is called.
170114

171-
### Trace/Log Correlations
115+
# Distributed Tracing
172116

173-
In order to correlate your traces with your logs, you must inject the trace context
174-
into your log messages. We've added the these into the slf4j MDC under the key `dd.trace_context`
175-
and provided convenience methods to get it automatically. The trace context is added to the MDC as a side
176-
effect of instantiating any `new DDLambda(...)`.
117+
## Upstream Requests
177118

178-
This is an example trace context: `[dd.trace_id=3371139772690049666 dd.span_id=13006875827893840236]`
119+
You may want to include this Lambda invocation as a child span of some larger trace.
120+
If so, you should anticipate that the event triggering the Lambda will have some trace context attached to it.
121+
If this is the case, then you MUST instantiate `DDLambda` with both the request and the lambda context in order for it to extract the trace context.
122+
E.g. `DDLambda ddl = new DDLambda(request, context);`.
123+
Currently supported events are:
179124

180-
#### JSON Logs
125+
- `APIGatewayProxyRequestEvent`
126+
- `APIGatewayV2ProxyRequestEvent`
181127

182-
If you are using JSON logs, add the trace ID and span ID to each log message with the keys
183-
`dd.trace_id` and `dd.span_id` respectively. To get a map containing trace and span IDs,
184-
call `DDLambda.getTraceContext()`. Union this map with the JSON data being logged.
128+
If you are using a different event with trace context, you may choose to create a class that implements `Headerable` and supply that as the event instead.
185129

186-
#### Plain text logs
130+
## Downstream Requests
187131

188-
If you are using plain text logs, then you must create a new [Parser](https://docs.datadoghq.com/logs/processing/parsing/?tab=matcher)
189-
by cloning the existing Lambda Pipeline. The new parser can extract the trace context from the correct position in the logs.
190-
Use the helper `_trace_context` to extract the trace context. For example, if your log line looked like:
132+
The dd-trace-java tracer will automatically add trace context to outgoing requests for a number of popular services.
133+
The list of instrumented services can be found here: https://docs.datadoghq.com/tracing/setup_overview/compatibility_requirements/java/ .
134+
If you wish to enable a beta integration, please note that you must do so using an environment variable.
191135

192-
```
193-
INFO 2020-11-11T14:00:00Z LAMBDA_REQUEST_ID [dd.trace_id=12345 dd.span_id=67890] This is a log message
194-
```
136+
# Trace/Log Correlation
195137

196-
Then your parser rule would look like:
138+
Please see [Connecting Java Logs and Traces](https://docs.datadoghq.com/tracing/connect_logs_and_traces/java/?tab=log4j2)
197139

198-
```
199-
my_custom_rule \[%{word:level}\]?\s+%{_timestamp}\s+%{notSpace:lambda.request_id}%{_trace_context}?.*
200-
```
140+
In brief, if you set the environment variable `DD_LOGS_INJECTION=true`, your trace ID and span ID are automatically injected into the MDC.
141+
If you are using JSON-formatted logs and logging using Logback, there is nothing left to do.
201142

202-
#### Log4j / SLF4J
143+
## Raw-formatted logs (Log4J, etc.)
203144

204-
We have added the Trace ID into the slf4j MDC under the key `dd.trace_context`. That can be accessed
205-
using the `%X{dd.trace_context}` operator. Here is an example `log4j.properties`:
145+
For raw formatted logs, you must update your log format and your log parser. Instructions for both are below.
206146

207-
```
208-
log = .
209-
log4j.rootLogger = DEBUG, LAMBDA
147+
### Log Format
210148

211-
log4j.appender.LAMBDA=com.amazonaws.services.lambda.runtime.log4j.LambdaAppender
212-
log4j.appender.LAMBDA.layout=org.apache.log4j.PatternLayout
213-
log4j.appender.LAMBDA.layout.conversionPattern=%d{yyyy-MM-dd HH:mm:ss} %X{dd.trace_context} %-5p %c:%L - %m%n
149+
If you are using raw formatted logs, update your formatter to include `dd.trace_context`. E.g.
150+
151+
```xml
152+
<Pattern>"%d{yyyy-MM-dd HH:mm:ss} <%X{AWSRequestId}> %-5p %c:%L %X{dd.trace_context} %m%n"</Pattern>
153+
<!--Please note: Request ID Trace Context -->
214154
```
215155
216-
would result in log lines looking like `2020-11-13 19:21:53 [dd.trace_id=1168910694192328743 dd.span_id=3204959397041471598] INFO com.serverless.Handler:20 - Test Log Message`
156+
Please note that `RequestId` has also been added.
157+
RequestId is not strictly necessary for Trace/Log correlation, but it is useful for correlating logs and invocations.
217158
218-
Just like the **Plain Text Logs** in the previous section, you must create a new [Parser](https://docs.datadoghq.com/logs/processing/parsing/?tab=matcher) in order to parse the trace context correctly.
219159
160+
### Grok Parser
220161
221-
#### Other logging solutions
162+
The following grok parser parses Java logs formatted using the pattern in the previous section.
222163
223-
If you are using a different logging solution, the trace ID can be accessed using the method
224-
`DDLambda.getTraceContextString()`. That returns your trace ID as a string that can be added
225-
to any log message.
164+
```
165+
java_tracer %{date("yyyy-MM-dd HH:mm:ss"):timestamp}\s\<%{uuid:lambda.request_id}\>\s%{word:level}\s+%{data:call_site}%{_trace_context}%{data:message}
166+
```
226167
227168
## Opening Issues
228169

build.gradle

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ sourceCompatibility = 1.8
4646
targetCompatibility = 1.8
4747

4848
group = 'com.datadoghq'
49-
version= '0.0.11'
49+
version= '0.2.0'
5050

5151
allprojects {
5252
repositories {

0 commit comments

Comments
 (0)