10
10
11
11
from wrapt import wrap_function_wrapper as wrap
12
12
from wrapt .importer import when_imported
13
+ from ddtrace import patch_all as patch_all_dd
13
14
14
- from datadog_lambda .tracing import get_dd_trace_context
15
+ from datadog_lambda .tracing import (
16
+ get_dd_trace_context ,
17
+ dd_tracing_enabled ,
18
+ )
15
19
16
20
logger = logging .getLogger (__name__ )
17
21
18
22
if sys .version_info >= (3 , 0 , 0 ):
19
23
httplib_module = "http.client"
24
+ from collections .abc import MutableMapping
20
25
else :
21
26
httplib_module = "httplib"
27
+ from collections import MutableMapping
22
28
23
29
_httplib_patched = False
24
30
_requests_patched = False
31
+ _integration_tests_patched = False
25
32
26
33
27
34
def patch_all ():
28
35
"""
29
- Patch the widely-used HTTP clients to automatically inject
30
- Datadog trace context.
36
+ Patch third-party libraries for tracing.
31
37
"""
32
- _patch_httplib ()
33
- _ensure_patch_requests ()
38
+ _patch_for_integration_tests ()
39
+
40
+ if dd_tracing_enabled :
41
+ patch_all_dd ()
42
+ else :
43
+ _patch_httplib ()
44
+ _ensure_patch_requests ()
45
+
46
+
47
+ def _patch_for_integration_tests ():
48
+ """
49
+ Patch `requests` to log the outgoing requests for integration tests.
50
+ """
51
+ global _integration_tests_patched
52
+ is_in_tests = os .environ .get ("DD_INTEGRATION_TEST" , "false" ).lower () == "true"
53
+ if not _integration_tests_patched and is_in_tests :
54
+ wrap ("requests" , "Session.send" , _log_request )
55
+ _integration_tests_patched = True
34
56
35
57
36
58
def _patch_httplib ():
@@ -80,17 +102,13 @@ def _wrap_requests_request(func, instance, args, kwargs):
80
102
into the outgoing requests.
81
103
"""
82
104
context = get_dd_trace_context ()
83
- if "headers" in kwargs and isinstance (kwargs ["headers" ], dict ):
105
+ if "headers" in kwargs and isinstance (kwargs ["headers" ], MutableMapping ):
84
106
kwargs ["headers" ].update (context )
85
- elif len (args ) >= 5 and isinstance (args [4 ], dict ):
107
+ elif len (args ) >= 5 and isinstance (args [4 ], MutableMapping ):
86
108
args [4 ].update (context )
87
109
else :
88
110
kwargs ["headers" ] = context
89
111
90
- # If we're in an integration test, log the HTTP requests made
91
- if os .environ .get ("DD_INTEGRATION_TEST" , "false" ).lower () == "true" :
92
- _print_request_string (args , kwargs )
93
-
94
112
return func (* args , ** kwargs )
95
113
96
114
@@ -100,43 +118,38 @@ def _wrap_httplib_request(func, instance, args, kwargs):
100
118
the Datadog trace headers into the outgoing requests.
101
119
"""
102
120
context = get_dd_trace_context ()
103
- if "headers" in kwargs and isinstance (kwargs ["headers" ], dict ):
121
+ if "headers" in kwargs and isinstance (kwargs ["headers" ], MutableMapping ):
104
122
kwargs ["headers" ].update (context )
105
- elif len (args ) >= 4 and isinstance (args [3 ], dict ):
123
+ elif len (args ) >= 4 and isinstance (args [3 ], MutableMapping ):
106
124
args [3 ].update (context )
107
125
else :
108
126
kwargs ["headers" ] = context
109
127
110
128
return func (* args , ** kwargs )
111
129
112
130
113
- def _print_request_string (args , kwargs ):
131
+ def _log_request (func , instance , args , kwargs ):
132
+ request = kwargs .get ("request" ) or args [0 ]
133
+ _print_request_string (request )
134
+ return func (* args , ** kwargs )
135
+
136
+
137
+ def _print_request_string (request ):
114
138
"""Print the request so that it can be checked in integration tests
115
139
116
140
Only used by integration tests.
117
141
"""
118
- # Normalizes the different ways args can be passed to a request
119
- # to prevent test flakiness
120
- method = None
121
- if len (args ) > 0 :
122
- method = args [0 ]
123
- else :
124
- method = kwargs .get ("method" , "" ).upper ()
125
-
126
- url = None
127
- if len (args ) > 1 :
128
- url = args [1 ]
129
- else :
130
- url = kwargs .get ("url" )
142
+ method = request .method
143
+ url = request .url
131
144
132
145
# Sort the datapoints POSTed by their name so that snapshots always align
133
- data = kwargs . get ( "data" , "{}" )
146
+ data = request . body or "{}"
134
147
data_dict = json .loads (data )
135
148
data_dict .get ("series" , []).sort (key = lambda series : series .get ("metric" ))
136
149
sorted_data = json .dumps (data_dict )
137
150
138
151
# Sort headers to prevent any differences in ordering
139
- headers = kwargs . get ( " headers" , {})
152
+ headers = request . headers or {}
140
153
sorted_headers = sorted (
141
154
"{}:{}" .format (key , value ) for key , value in headers .items ()
142
155
)
0 commit comments