1313 SamplingPriority ,
1414 TraceHeader ,
1515 XraySubsegment ,
16+ Source ,
1617)
18+ from datadog_lambda .trace_wrapper import trace_wrapper
1719
1820logger = logging .getLogger (__name__ )
1921
@@ -38,8 +40,32 @@ def _convert_xray_sampling(xray_sampled):
3840 """
3941 Convert X-Ray sampled (True/False) to its Datadog counterpart.
4042 """
41- return str (SamplingPriority .USER_KEEP ) if xray_sampled \
43+ return (
44+ str (SamplingPriority .USER_KEEP )
45+ if xray_sampled
4246 else str (SamplingPriority .USER_REJECT )
47+ )
48+
49+
50+ def _get_xray_trace_context ():
51+ if not is_lambda_context ():
52+ return None
53+
54+ xray_trace_entity = xray_recorder .get_trace_entity () # xray (sub)segment
55+ return {
56+ "trace-id" : _convert_xray_trace_id (xray_trace_entity .trace_id ),
57+ "parent-id" : _convert_xray_entity_id (xray_trace_entity .id ),
58+ "sampling-priority" : _convert_xray_sampling (xray_trace_entity .sampled ),
59+ "source" : Source .XRAY ,
60+ }
61+
62+
63+ def _context_obj_to_headers (obj ):
64+ return {
65+ TraceHeader .TRACE_ID : obj .get ("trace_id" ),
66+ TraceHeader .PARENT_ID : obj .get ("parent_id" ),
67+ TraceHeader .SAMPLING_PRIORITY : obj .get ("sampling_priority" ),
68+ }
4369
4470
4571def extract_dd_trace_context (event ):
@@ -54,33 +80,32 @@ def extract_dd_trace_context(event):
5480 the correct context.
5581 """
5682 global dd_trace_context
57- headers = event .get (' headers' , {})
83+ headers = event .get (" headers" , {})
5884 lowercase_headers = {k .lower (): v for k , v in headers .items ()}
5985
6086 trace_id = lowercase_headers .get (TraceHeader .TRACE_ID )
6187 parent_id = lowercase_headers .get (TraceHeader .PARENT_ID )
6288 sampling_priority = lowercase_headers .get (TraceHeader .SAMPLING_PRIORITY )
6389 if trace_id and parent_id and sampling_priority :
64- logger .debug (' Extracted Datadog trace context from headers' )
90+ logger .debug (" Extracted Datadog trace context from headers" )
6591 dd_trace_context = {
66- 'trace-id' : trace_id ,
67- 'parent-id' : parent_id ,
68- 'sampling-priority' : sampling_priority ,
92+ "trace-id" : trace_id ,
93+ "parent-id" : parent_id ,
94+ "sampling-priority" : sampling_priority ,
95+ "source" : Source .EVENT ,
6996 }
7097 xray_recorder .begin_subsegment (XraySubsegment .NAME )
7198 subsegment = xray_recorder .current_subsegment ()
7299 subsegment .put_metadata (
73- XraySubsegment .KEY ,
74- dd_trace_context ,
75- XraySubsegment .NAMESPACE
100+ XraySubsegment .KEY , dd_trace_context , XraySubsegment .NAMESPACE
76101 )
77102 xray_recorder .end_subsegment ()
78103 else :
79104 # AWS Lambda runtime caches global variables between invocations,
80105 # reset to avoid using the context from the last invocation.
81- dd_trace_context = {}
82-
83- logger . debug ( 'extracted dd trace context %s' , dd_trace_context )
106+ dd_trace_context = _get_xray_trace_context ()
107+ logger . debug ( "extracted dd trace context %s" , dd_trace_context )
108+ return dd_trace_context
84109
85110
86111def get_dd_trace_context ():
@@ -95,30 +120,25 @@ def get_dd_trace_context():
95120 automatically, but this function can be used to manually inject the trace
96121 context to an outgoing request.
97122 """
98- if not is_lambda_context ():
99- logger .debug ('get_dd_trace_context is only supported in LambdaContext' )
100- return {}
101-
102123 global dd_trace_context
103- xray_trace_entity = xray_recorder .get_trace_entity () # xray (sub)segment
104- if dd_trace_context :
105- return {
106- TraceHeader .TRACE_ID :
107- dd_trace_context ['trace-id' ],
108- TraceHeader .PARENT_ID : _convert_xray_entity_id (
109- xray_trace_entity .id ),
110- TraceHeader .SAMPLING_PRIORITY :
111- dd_trace_context ['sampling-priority' ],
112- }
113- else :
114- return {
115- TraceHeader .TRACE_ID : _convert_xray_trace_id (
116- xray_trace_entity .trace_id ),
117- TraceHeader .PARENT_ID : _convert_xray_entity_id (
118- xray_trace_entity .id ),
119- TraceHeader .SAMPLING_PRIORITY : _convert_xray_sampling (
120- xray_trace_entity .sampled ),
121- }
124+
125+ if not dd_trace_context :
126+ return None
127+ trace_context = _context_obj_to_headers (dd_trace_context )
128+ datadog_context = trace_wrapper .trace_context
129+ if datadog_context :
130+ logger .debug ("get_dd_trace_context using dd-trace context" )
131+ return datadog_context
132+ try :
133+ xray_context = _get_xray_trace_context () # xray (sub)segment
134+ if xray_context :
135+ trace_context [TraceHeader .PARENT_ID ] = xray_context ["parent_id" ]
136+ except Exception as e :
137+ logger .debug (
138+ "get_dd_trace_context couldn't read from segment from x-ray, with error %s"
139+ % e
140+ )
141+ return trace_context
122142
123143
124144def set_correlation_ids ():
@@ -130,16 +150,16 @@ def set_correlation_ids():
130150 TODO: Remove me when Datadog tracer is natively supported in Lambda.
131151 """
132152 if not is_lambda_context ():
133- logger .debug (' set_correlation_ids is only supported in LambdaContext' )
153+ logger .debug (" set_correlation_ids is only supported in LambdaContext" )
134154 return
135155
136156 context = get_dd_trace_context ()
137157
138- span = tracer .trace (' dummy.span' )
158+ span = tracer .trace (" dummy.span" )
139159 span .trace_id = context [TraceHeader .TRACE_ID ]
140160 span .span_id = context [TraceHeader .PARENT_ID ]
141161
142- logger .debug (' correlation ids set' )
162+ logger .debug (" correlation ids set" )
143163
144164
145165def inject_correlation_ids ():
@@ -153,17 +173,19 @@ def inject_correlation_ids():
153173 # Override the log format of the AWS provided LambdaLoggerHandler
154174 root_logger = logging .getLogger ()
155175 for handler in root_logger .handlers :
156- if handler .__class__ .__name__ == 'LambdaLoggerHandler' :
157- handler .setFormatter (logging .Formatter (
158- '[%(levelname)s]\t %(asctime)s.%(msecs)dZ\t %(aws_request_id)s\t '
159- '[dd.trace_id=%(dd.trace_id)s dd.span_id=%(dd.span_id)s]\t %(message)s\n ' ,
160- '%Y-%m-%dT%H:%M:%S'
161- ))
176+ if handler .__class__ .__name__ == "LambdaLoggerHandler" :
177+ handler .setFormatter (
178+ logging .Formatter (
179+ "[%(levelname)s]\t %(asctime)s.%(msecs)dZ\t %(aws_request_id)s\t "
180+ "[dd.trace_id=%(dd.trace_id)s dd.span_id=%(dd.span_id)s]\t %(message)s\n " ,
181+ "%Y-%m-%dT%H:%M:%S" ,
182+ )
183+ )
162184
163185 # Patch `logging.Logger.makeRecord` to actually inject correlation ids
164186 patch (logging = True )
165187
166- logger .debug (' logs injection configured' )
188+ logger .debug (" logs injection configured" )
167189
168190
169191def is_lambda_context ():
0 commit comments