@@ -31,6 +31,7 @@ def parse_version(version):
31
31
return Version ((0 , 0 ), "" )
32
32
33
33
34
+ TELEMETRY_DATA = []
34
35
SCRIPT_DIR = os .path .dirname (__file__ )
35
36
RUNTIMES_ALLOW_LIST = {
36
37
"cpython" : {
@@ -68,49 +69,58 @@ def get_oci_ddtrace_version():
68
69
def build_installed_pkgs ():
69
70
installed_packages = {}
70
71
if sys .version_info >= (3 , 8 ):
71
- from importlib import metadata as importlib_metadata
72
+ try :
73
+ from importlib import metadata as importlib_metadata
72
74
73
- installed_packages = {pkg .metadata ["Name" ]: pkg .version for pkg in importlib_metadata .distributions ()}
75
+ installed_packages = {pkg .metadata ["Name" ]: pkg .version for pkg in importlib_metadata .distributions ()}
76
+ except Exception as e :
77
+ _log ("Failed to build installed packages list: %s" % e , level = "debug" )
74
78
else :
75
79
try :
76
80
import pkg_resources
77
81
78
82
installed_packages = {pkg .key : pkg .version for pkg in pkg_resources .working_set }
79
- except ImportError :
83
+ except Exception :
80
84
try :
81
85
import importlib_metadata
82
86
83
87
installed_packages = {pkg .metadata ["Name" ]: pkg .version for pkg in importlib_metadata .distributions ()}
84
- except ImportError :
85
- pass
88
+ except Exception as e :
89
+ _log ( "Failed to build installed packages list: %s" % e , level = "debug" )
86
90
return {key .lower (): value for key , value in installed_packages .items ()}
87
91
88
92
89
93
def build_min_pkgs ():
90
94
min_pkgs = dict ()
91
- for location in VERSION_COMPAT_FILE_LOCATIONS :
92
- if os .path .exists (location ):
93
- with open (location , "r" ) as csvfile :
94
- csv_reader = csv .reader (csvfile , delimiter = "," )
95
- for idx , row in enumerate (csv_reader ):
96
- if idx < 2 :
97
- continue
98
- min_pkgs [row [0 ].lower ()] = parse_version (row [1 ])
99
- break
95
+ try :
96
+ for location in VERSION_COMPAT_FILE_LOCATIONS :
97
+ if os .path .exists (location ):
98
+ with open (location , "r" ) as csvfile :
99
+ csv_reader = csv .reader (csvfile , delimiter = "," )
100
+ for idx , row in enumerate (csv_reader ):
101
+ if idx < 2 :
102
+ continue
103
+ min_pkgs [row [0 ].lower ()] = parse_version (row [1 ])
104
+ break
105
+ except Exception as e :
106
+ _log ("Failed to build min-pkgs list: %s" % e , level = "debug" )
100
107
return min_pkgs
101
108
102
109
103
110
def build_denied_executables ():
104
111
denied_executables = set ()
105
112
_log ("Checking denied-executables list" , level = "debug" )
106
- if os .path .exists (EXECUTABLE_DENY_LOCATION ):
107
- with open (EXECUTABLE_DENY_LOCATION , "r" ) as denyfile :
108
- _log ("Found deny-list file" , level = "debug" )
109
- for line in denyfile .readlines ():
110
- cleaned = line .strip ("\n " )
111
- denied_executables .add (cleaned )
112
- denied_executables .add (os .path .basename (cleaned ))
113
- _log ("Built denied-executables list of %s entries" % (len (denied_executables ),), level = "debug" )
113
+ try :
114
+ if os .path .exists (EXECUTABLE_DENY_LOCATION ):
115
+ with open (EXECUTABLE_DENY_LOCATION , "r" ) as denyfile :
116
+ _log ("Found deny-list file" , level = "debug" )
117
+ for line in denyfile .readlines ():
118
+ cleaned = line .strip ("\n " )
119
+ denied_executables .add (cleaned )
120
+ denied_executables .add (os .path .basename (cleaned ))
121
+ _log ("Built denied-executables list of %s entries" % (len (denied_executables ),), level = "debug" )
122
+ except Exception as e :
123
+ _log ("Failed to build denied-executables list: %s" % e , level = "debug" )
114
124
return denied_executables
115
125
116
126
@@ -228,13 +238,14 @@ def _inject():
228
238
global PYTHON_RUNTIME
229
239
global PKGS_ALLOW_LIST
230
240
global EXECUTABLES_DENY_LIST
241
+ global TELEMETRY_DATA
242
+ # Try to get the version of the Python runtime first so we have it for telemetry
243
+ PYTHON_VERSION = platform .python_version ()
244
+ PYTHON_RUNTIME = platform .python_implementation ().lower ()
231
245
DDTRACE_VERSION = get_oci_ddtrace_version ()
232
246
INSTALLED_PACKAGES = build_installed_pkgs ()
233
- PYTHON_RUNTIME = platform .python_implementation ().lower ()
234
- PYTHON_VERSION = platform .python_version ()
235
247
PKGS_ALLOW_LIST = build_min_pkgs ()
236
248
EXECUTABLES_DENY_LIST = build_denied_executables ()
237
- telemetry_data = []
238
249
integration_incomp = False
239
250
runtime_incomp = False
240
251
os .environ ["_DD_INJECT_WAS_ATTEMPTED" ] = "true"
@@ -260,12 +271,14 @@ def _inject():
260
271
_log ("ddtrace_pkgs path is %r" % pkgs_path , level = "debug" )
261
272
_log ("ddtrace_pkgs contents: %r" % os .listdir (pkgs_path ), level = "debug" )
262
273
274
+ abort = False
263
275
incompatible_sysarg = get_first_incompatible_sysarg ()
264
276
if incompatible_sysarg is not None :
265
277
_log ("Found incompatible executable: %s." % incompatible_sysarg , level = "debug" )
266
278
if not FORCE_INJECT :
267
279
_log ("Aborting dd-trace-py instrumentation." , level = "debug" )
268
- telemetry_data .append (
280
+ abort = True
281
+ TELEMETRY_DATA .append (
269
282
create_count_metric (
270
283
"library_entrypoint.abort.integration" ,
271
284
)
@@ -287,9 +300,10 @@ def _inject():
287
300
integration_incomp = True
288
301
if not FORCE_INJECT :
289
302
_log ("Aborting dd-trace-py instrumentation." , level = "debug" )
303
+ abort = True
290
304
291
305
for key , value in incompatible_packages .items ():
292
- telemetry_data .append (
306
+ TELEMETRY_DATA .append (
293
307
create_count_metric (
294
308
"library_entrypoint.abort.integration" ,
295
309
[
@@ -313,24 +327,23 @@ def _inject():
313
327
runtime_incomp = True
314
328
if not FORCE_INJECT :
315
329
_log ("Aborting dd-trace-py instrumentation." , level = "debug" )
330
+ abort = True
316
331
317
- telemetry_data .append (create_count_metric ("library_entrypoint.abort.runtime" ))
332
+ TELEMETRY_DATA .append (create_count_metric ("library_entrypoint.abort.runtime" ))
318
333
else :
319
334
_log (
320
335
"DD_INJECT_FORCE set to True, allowing unsupported runtimes and continuing." ,
321
336
level = "debug" ,
322
337
)
323
- if telemetry_data :
324
- telemetry_data .append (
338
+ if abort :
339
+ TELEMETRY_DATA .append (
325
340
create_count_metric (
326
341
"library_entrypoint.abort" ,
327
342
[
328
343
"reason:integration" if integration_incomp else "reason:incompatible_runtime" ,
329
344
],
330
345
)
331
346
)
332
- telemetry_event = gen_telemetry_payload (telemetry_data , DDTRACE_VERSION )
333
- send_telemetry (telemetry_event )
334
347
return
335
348
336
349
site_pkgs_path = os .path .join (
@@ -339,6 +352,12 @@ def _inject():
339
352
_log ("site-packages path is %r" % site_pkgs_path , level = "debug" )
340
353
if not os .path .exists (site_pkgs_path ):
341
354
_log ("ddtrace site-packages not found in %r, aborting" % site_pkgs_path , level = "error" )
355
+ TELEMETRY_DATA .append (
356
+ gen_telemetry_payload (
357
+ [create_count_metric ("library_entrypoint.abort" , ["reason:missing_" + site_pkgs_path ])],
358
+ DDTRACE_VERSION ,
359
+ )
360
+ )
342
361
return
343
362
344
363
# Add the custom site-packages directory to the Python path to load the ddtrace package.
@@ -349,6 +368,17 @@ def _inject():
349
368
350
369
except BaseException as e :
351
370
_log ("failed to load ddtrace module: %s" % e , level = "error" )
371
+ TELEMETRY_DATA .append (
372
+ gen_telemetry_payload (
373
+ [
374
+ create_count_metric (
375
+ "library_entrypoint.error" , ["error_type:import_ddtrace_" + type (e ).__name__ .lower ()]
376
+ )
377
+ ],
378
+ DDTRACE_VERSION ,
379
+ )
380
+ )
381
+
352
382
return
353
383
else :
354
384
try :
@@ -377,38 +407,56 @@ def _inject():
377
407
os .environ ["PYTHONPATH" ] = python_path
378
408
379
409
_log ("successfully configured ddtrace package, python path is %r" % os .environ ["PYTHONPATH" ])
380
- event = gen_telemetry_payload (
381
- [
382
- create_count_metric (
383
- "library_entrypoint.complete" ,
384
- [
385
- "injection_forced:" + str (runtime_incomp or integration_incomp ).lower (),
386
- ],
387
- )
388
- ],
389
- DDTRACE_VERSION ,
410
+ TELEMETRY_DATA .append (
411
+ gen_telemetry_payload (
412
+ [
413
+ create_count_metric (
414
+ "library_entrypoint.complete" ,
415
+ [
416
+ "injection_forced:" + str (runtime_incomp or integration_incomp ).lower (),
417
+ ],
418
+ )
419
+ ],
420
+ DDTRACE_VERSION ,
421
+ )
390
422
)
391
- send_telemetry (event )
392
423
except Exception as e :
393
- event = gen_telemetry_payload (
394
- [create_count_metric ("library_entrypoint.error" , ["error_type:" + type (e ).__name__ .lower ()])],
395
- DDTRACE_VERSION ,
424
+ TELEMETRY_DATA .append (
425
+ gen_telemetry_payload (
426
+ [
427
+ create_count_metric (
428
+ "library_entrypoint.error" , ["error_type:init_ddtrace_" + type (e ).__name__ .lower ()]
429
+ )
430
+ ],
431
+ DDTRACE_VERSION ,
432
+ )
396
433
)
397
- send_telemetry (event )
398
434
_log ("failed to load ddtrace.bootstrap.sitecustomize: %s" % e , level = "error" )
399
435
return
400
436
else :
401
437
module_origin = spec .origin if spec else None
402
438
_log ("user-installed ddtrace found: %s, aborting site-packages injection" % module_origin , level = "warning" )
439
+ TELEMETRY_DATA .append (
440
+ create_count_metric (
441
+ "library_entrypoint.abort" ,
442
+ [
443
+ "reason:ddtrace_already_present" ,
444
+ ],
445
+ )
446
+ )
403
447
404
448
405
449
try :
406
- _inject ()
407
- except Exception as e :
408
450
try :
409
- event = gen_telemetry_payload (
410
- [create_count_metric ("library_entrypoint.error" , ["error_type:" + type (e ).__name__ .lower ()])]
451
+ _inject ()
452
+ except Exception as e :
453
+ TELEMETRY_DATA .append (
454
+ gen_telemetry_payload (
455
+ [create_count_metric ("library_entrypoint.error" , ["error_type:main_" + type (e ).__name__ .lower ()])]
456
+ )
411
457
)
412
- send_telemetry (event )
413
- except Exception :
414
- pass # absolutely never allow exceptions to propagate to the app
458
+ finally :
459
+ if TELEMETRY_DATA :
460
+ send_telemetry (TELEMETRY_DATA )
461
+ except Exception :
462
+ pass # absolutely never allow exceptions to propagate to the app
0 commit comments