1
1
package com .datadoghq .datadog_lambda_java ;
2
2
3
+ import io .opentracing .Scope ;
4
+ import io .opentracing .SpanContext ;
5
+ import io .opentracing .Tracer ;
6
+ import io .opentracing .Tracer .SpanBuilder ;
7
+ import io .opentracing .propagation .Format .Builtin ;
8
+ import io .opentracing .propagation .TextMapAdapter ;
3
9
import java .io .IOException ;
4
10
import java .net .URL ;
5
11
import java .net .URLConnection ;
@@ -28,8 +34,10 @@ public class DDLambda {
28
34
private String MDC_TRACE_CONTEXT_FIELD = "dd.trace_context" ;
29
35
private String JSON_TRACE_ID = "dd.trace_id" ;
30
36
private String JSON_SPAN_ID = "dd.span_id" ;
37
+ private String TRACE_ENABLED_ENV = "DD_TRACE_ENABLED" ;
31
38
private Tracing tracing ;
32
39
private boolean enhanced = true ;
40
+ private Scope tracingScope ;
33
41
34
42
/**
35
43
* Create a new DDLambda instrumenter given some Lambda context
@@ -41,7 +49,7 @@ public DDLambda(Context cxt) {
41
49
this .enhanced = checkEnhanced ();
42
50
recordEnhanced (INVOCATION , cxt );
43
51
addTraceContextToMDC ();
44
- addTagsToSpan ( cxt );
52
+ startSpan ( null , cxt );
45
53
}
46
54
47
55
/**
@@ -55,7 +63,7 @@ protected DDLambda(Context cxt, String xrayTraceInfo) {
55
63
this .enhanced = checkEnhanced ();
56
64
recordEnhanced (INVOCATION , cxt );
57
65
addTraceContextToMDC ();
58
- addTagsToSpan ( cxt );
66
+ startSpan ( null , cxt );
59
67
}
60
68
61
69
/**
@@ -71,7 +79,7 @@ public DDLambda(APIGatewayProxyRequestEvent req, Context cxt) {
71
79
this .tracing = new Tracing (req );
72
80
this .tracing .submitSegment ();
73
81
addTraceContextToMDC ();
74
- addTagsToSpan ( cxt );
82
+ startSpan ( req . getHeaders (), cxt );
75
83
}
76
84
77
85
/**
@@ -87,7 +95,7 @@ public DDLambda(APIGatewayV2ProxyRequestEvent req, Context cxt) {
87
95
this .tracing = new Tracing (req );
88
96
this .tracing .submitSegment ();
89
97
addTraceContextToMDC ();
90
- addTagsToSpan ( cxt );
98
+ startSpan ( req . getHeaders (), cxt );
91
99
}
92
100
93
101
/**
@@ -103,10 +111,69 @@ public DDLambda(Headerable req, Context cxt) {
103
111
this .tracing = new Tracing (req );
104
112
this .tracing .submitSegment ();
105
113
addTraceContextToMDC ();
106
- addTagsToSpan ( cxt );
114
+ startSpan ( req . getHeaders (), cxt );
107
115
}
108
116
109
- private void addTagsToSpan (Context cxt ) {
117
+ /**
118
+ * startSpan is called by the DDLambda constructors. If there is a dd-agent-java present, it will start
119
+ * a span. If not, startSpan is a noop.
120
+ * @param headers are the headers from the Lambda request. If Headers are null or empty, distributed tracing
121
+ * is impossible but a span will still start.
122
+ * @param cxt is the Lambda Context passed to the Handler function.
123
+ */
124
+ private void startSpan (Map <String ,String > headers , Context cxt ){
125
+ //If the user has not set DD_TRACE_ENABLED=true, don't start a span
126
+ if (!checkTraceEnabled ()){
127
+ return ;
128
+ }
129
+
130
+ String functionName = "" ;
131
+ if (cxt != null ){
132
+ functionName = cxt .getFunctionName ();
133
+ }
134
+
135
+ //Get the Datadog tracer, if it exists
136
+ Tracer tracer = GlobalTracer .get ();
137
+ //Datadog tracer will be able to extract datadog trace headers from an incoming request
138
+ SpanContext parentContext = tracer .extract (Builtin .HTTP_HEADERS , new TextMapAdapter (headers ));
139
+
140
+ SpanBuilder spanBuilder = tracer .buildSpan (functionName ).asChildOf (parentContext );
141
+ spanBuilder = addDDTags (spanBuilder , cxt );
142
+ Span thisSpan = spanBuilder .start ();
143
+
144
+ //Hang on to the scope, we'll need it later to close.
145
+ this .tracingScope = tracer .activateSpan (thisSpan );
146
+ }
147
+
148
+ /**
149
+ * Finish the active span. If you have installed the dd-trace-java Lambda
150
+ * layer, you MUST call DDLambda.finish() at the end of your Handler
151
+ * in order to finish spans.
152
+ */
153
+ public void finish (){
154
+ Span span = GlobalTracer .get ().activeSpan ();
155
+
156
+ if (this .tracingScope == null ){
157
+ DDLogger .getLoggerImpl ().debug ("Unable to close tracing scope because it is null." );
158
+ return ;
159
+ }
160
+ this .tracingScope .close ();
161
+
162
+ if (span != null ) {
163
+ span .finish ();
164
+ } else {
165
+ DDLogger .getLoggerImpl ().debug ("Unable to finish span because it is null." );
166
+ return ;
167
+ }
168
+ }
169
+
170
+ /**
171
+ * addDDTags adds Datadog tags to a span's tags.
172
+ * @param spanBuilder is the SpanBuilder being used to build the span to which these tags will be applied
173
+ * @param cxt is the Lambda Context that contains the information necessary to build these tags
174
+ * @return a SpanBuilder with the necessary tags.
175
+ */
176
+ private SpanBuilder addDDTags (SpanBuilder spanBuilder , Context cxt ) {
110
177
String requestId = "" ;
111
178
String functionName = "" ;
112
179
String functionArn = "" ;
@@ -116,17 +183,19 @@ private void addTagsToSpan(Context cxt) {
116
183
functionName = cxt .getFunctionName ();
117
184
functionArn = santitizeFunctionArn (cxt .getInvokedFunctionArn ());
118
185
functionVersion = cxt .getFunctionVersion ();
186
+ } else {
187
+ return spanBuilder ;
119
188
}
120
- Span span = GlobalTracer .get ().activeSpan ();
121
- if (span != null ) {
122
- span .setTag ("request_id" , requestId );
123
- span .setTag ("service" , "aws.lambda" );
124
- span .setTag ("function_arn" , functionArn );
125
- span .setTag ("cold_start" , ColdStart .getColdStart (cxt ));
126
- span .setTag ("datadog_lambda" , BuildConfig .datadog_lambda_version );
127
- span .setTag ("resource_names" , functionName );
128
- span .setTag ("function_version" , functionVersion );
189
+ if (spanBuilder != null ) {
190
+ spanBuilder .withTag ("request_id" , requestId );
191
+ spanBuilder .withTag ("service" , "aws.lambda" );
192
+ spanBuilder .withTag ("function_arn" , functionArn );
193
+ spanBuilder .withTag ("cold_start" , ColdStart .getColdStart (cxt ));
194
+ spanBuilder .withTag ("datadog_lambda" , BuildConfig .datadog_lambda_version );
195
+ spanBuilder .withTag ("resource_names" , functionName );
196
+ spanBuilder .withTag ("function_version" , functionVersion );
129
197
}
198
+ return spanBuilder ;
130
199
}
131
200
132
201
protected String santitizeFunctionArn (String functionArn ){
@@ -169,6 +238,22 @@ protected boolean checkEnhanced() {
169
238
return true ;
170
239
}
171
240
241
+ /**
242
+ * Check to see if the user has set DD_TRACE_ENABLED
243
+ * @return true if DD_TRACE_ENABLED has been set to "true" (or "TRUE" or "tRuE" or ...), false otherwise
244
+ */
245
+ protected boolean checkTraceEnabled (){
246
+ String sysTraceEnabled = System .getenv (TRACE_ENABLED_ENV );
247
+ if (sysTraceEnabled == null ) {
248
+ return false ;
249
+ }
250
+
251
+ if (sysTraceEnabled .toLowerCase ().equals ("true" )){
252
+ return true ;
253
+ }
254
+ return false ;
255
+ }
256
+
172
257
/**
173
258
* metric allows the user to record their own custom metric that will be sent to Datadog.
174
259
*
0 commit comments