Skip to content

Commit 1dd528c

Browse files
authored
fix(lib-injection): fix SSI abort telemetry metrics (#11627)
1 parent 0581d4d commit 1dd528c

File tree

2 files changed

+106
-54
lines changed

2 files changed

+106
-54
lines changed

lib-injection/sources/sitecustomize.py

+102-54
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ def parse_version(version):
3131
return Version((0, 0), "")
3232

3333

34+
TELEMETRY_DATA = []
3435
SCRIPT_DIR = os.path.dirname(__file__)
3536
RUNTIMES_ALLOW_LIST = {
3637
"cpython": {
@@ -68,49 +69,58 @@ def get_oci_ddtrace_version():
6869
def build_installed_pkgs():
6970
installed_packages = {}
7071
if sys.version_info >= (3, 8):
71-
from importlib import metadata as importlib_metadata
72+
try:
73+
from importlib import metadata as importlib_metadata
7274

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")
7478
else:
7579
try:
7680
import pkg_resources
7781

7882
installed_packages = {pkg.key: pkg.version for pkg in pkg_resources.working_set}
79-
except ImportError:
83+
except Exception:
8084
try:
8185
import importlib_metadata
8286

8387
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")
8690
return {key.lower(): value for key, value in installed_packages.items()}
8791

8892

8993
def build_min_pkgs():
9094
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")
100107
return min_pkgs
101108

102109

103110
def build_denied_executables():
104111
denied_executables = set()
105112
_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")
114124
return denied_executables
115125

116126

@@ -228,13 +238,14 @@ def _inject():
228238
global PYTHON_RUNTIME
229239
global PKGS_ALLOW_LIST
230240
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()
231245
DDTRACE_VERSION = get_oci_ddtrace_version()
232246
INSTALLED_PACKAGES = build_installed_pkgs()
233-
PYTHON_RUNTIME = platform.python_implementation().lower()
234-
PYTHON_VERSION = platform.python_version()
235247
PKGS_ALLOW_LIST = build_min_pkgs()
236248
EXECUTABLES_DENY_LIST = build_denied_executables()
237-
telemetry_data = []
238249
integration_incomp = False
239250
runtime_incomp = False
240251
os.environ["_DD_INJECT_WAS_ATTEMPTED"] = "true"
@@ -260,12 +271,14 @@ def _inject():
260271
_log("ddtrace_pkgs path is %r" % pkgs_path, level="debug")
261272
_log("ddtrace_pkgs contents: %r" % os.listdir(pkgs_path), level="debug")
262273

274+
abort = False
263275
incompatible_sysarg = get_first_incompatible_sysarg()
264276
if incompatible_sysarg is not None:
265277
_log("Found incompatible executable: %s." % incompatible_sysarg, level="debug")
266278
if not FORCE_INJECT:
267279
_log("Aborting dd-trace-py instrumentation.", level="debug")
268-
telemetry_data.append(
280+
abort = True
281+
TELEMETRY_DATA.append(
269282
create_count_metric(
270283
"library_entrypoint.abort.integration",
271284
)
@@ -287,9 +300,10 @@ def _inject():
287300
integration_incomp = True
288301
if not FORCE_INJECT:
289302
_log("Aborting dd-trace-py instrumentation.", level="debug")
303+
abort = True
290304

291305
for key, value in incompatible_packages.items():
292-
telemetry_data.append(
306+
TELEMETRY_DATA.append(
293307
create_count_metric(
294308
"library_entrypoint.abort.integration",
295309
[
@@ -313,24 +327,23 @@ def _inject():
313327
runtime_incomp = True
314328
if not FORCE_INJECT:
315329
_log("Aborting dd-trace-py instrumentation.", level="debug")
330+
abort = True
316331

317-
telemetry_data.append(create_count_metric("library_entrypoint.abort.runtime"))
332+
TELEMETRY_DATA.append(create_count_metric("library_entrypoint.abort.runtime"))
318333
else:
319334
_log(
320335
"DD_INJECT_FORCE set to True, allowing unsupported runtimes and continuing.",
321336
level="debug",
322337
)
323-
if telemetry_data:
324-
telemetry_data.append(
338+
if abort:
339+
TELEMETRY_DATA.append(
325340
create_count_metric(
326341
"library_entrypoint.abort",
327342
[
328343
"reason:integration" if integration_incomp else "reason:incompatible_runtime",
329344
],
330345
)
331346
)
332-
telemetry_event = gen_telemetry_payload(telemetry_data, DDTRACE_VERSION)
333-
send_telemetry(telemetry_event)
334347
return
335348

336349
site_pkgs_path = os.path.join(
@@ -339,6 +352,12 @@ def _inject():
339352
_log("site-packages path is %r" % site_pkgs_path, level="debug")
340353
if not os.path.exists(site_pkgs_path):
341354
_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+
)
342361
return
343362

344363
# Add the custom site-packages directory to the Python path to load the ddtrace package.
@@ -349,6 +368,17 @@ def _inject():
349368

350369
except BaseException as e:
351370
_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+
352382
return
353383
else:
354384
try:
@@ -377,38 +407,56 @@ def _inject():
377407
os.environ["PYTHONPATH"] = python_path
378408

379409
_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+
)
390422
)
391-
send_telemetry(event)
392423
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+
)
396433
)
397-
send_telemetry(event)
398434
_log("failed to load ddtrace.bootstrap.sitecustomize: %s" % e, level="error")
399435
return
400436
else:
401437
module_origin = spec.origin if spec else None
402438
_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+
)
403447

404448

405449
try:
406-
_inject()
407-
except Exception as e:
408450
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+
)
411457
)
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
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
---
2+
fixes:
3+
- |
4+
lib-injection: Fix missing lib-injection telemetry for common abort scenarios.

0 commit comments

Comments
 (0)