From 1fc84b355e9b9244869b069fdb6332e248f36bae Mon Sep 17 00:00:00 2001 From: Mark Spicer Date: Thu, 24 Apr 2025 16:08:38 -0400 Subject: [PATCH 1/3] poc: Add injection metadata This commit adds additional metadata to the telemetry forwarder so that we can surface injection issues to the end user. --- lib-injection/sources/sitecustomize.py | 44 +++++++++++++++++++++++++- 1 file changed, 43 insertions(+), 1 deletion(-) diff --git a/lib-injection/sources/sitecustomize.py b/lib-injection/sources/sitecustomize.py index a5076da6cb7..ff594cae160 100644 --- a/lib-injection/sources/sitecustomize.py +++ b/lib-injection/sources/sitecustomize.py @@ -5,9 +5,11 @@ from collections import namedtuple import csv +import enum import json import os import platform +import psutil import re import subprocess import sys @@ -17,6 +19,12 @@ Version = namedtuple("Version", ["version", "constraint"]) +class InjectionResultType(enum.Enum): + SUCCESS = "success" + FAILED = "failed" + SKIPPED = "skipped" + + def parse_version(version): try: constraint_match = re.search(r"\d", version) @@ -57,6 +65,8 @@ def parse_version(version): EXECUTABLE_DENY_LOCATION = os.path.abspath(os.path.join(SCRIPT_DIR, "denied_executables.txt")) SITE_PKGS_MARKER = "site-packages-ddtrace-py" BOOTSTRAP_MARKER = "bootstrap" +INJECTION_RESULT = "" +RESULT_REASON = "" def get_oci_ddtrace_version(): @@ -124,6 +134,9 @@ def create_count_metric(metric, tags=None): def gen_telemetry_payload(telemetry_events, ddtrace_version): + pid = os.getpid() + proc = psutil.Process(pid) + return { "metadata": { "language_name": "python", @@ -131,7 +144,11 @@ def gen_telemetry_payload(telemetry_events, ddtrace_version): "runtime_name": PYTHON_RUNTIME, "runtime_version": PYTHON_VERSION, "tracer_version": ddtrace_version, - "pid": os.getpid(), + "component": "dd-trace-py", + "result": INJECTION_RESULT, + "reason": RESULT_REASON, + "pid": pid, + "start_time": proc.create_time, }, "points": telemetry_events, } @@ -245,6 +262,13 @@ def get_first_incompatible_sysarg(): return argument +def set_injection_result(result, reason): + global INJECTION_RESULT + global RESULT_REASON + INJECTION_RESULT = result + RESULT_REASON = reason + + def _inject(): global DDTRACE_VERSION global INSTALLED_PACKAGES @@ -297,6 +321,9 @@ def _inject(): "library_entrypoint.abort.integration", ) ) + set_injection_result( + InjectionResultType.SKIPPED, "Found incompatible executable: %s." % incompatible_sysarg + ) else: _log( "DD_INJECT_FORCE set to True, allowing unsupported executables and continuing.", @@ -327,6 +354,9 @@ def _inject(): ) ) + set_injection_result( + InjectionResultType.SKIPPED, "Found incompatible packages: %s." % incompatible_packages + ) else: _log( "DD_INJECT_FORCE set to True, allowing unsupported integrations and continuing.", @@ -344,6 +374,12 @@ def _inject(): abort = True TELEMETRY_DATA.append(create_count_metric("library_entrypoint.abort.runtime")) + + set_injection_result( + InjectionResultType.SKIPPED, + "Found incompatible runtime: %s %s. Supported runtimes: %s" + % (PYTHON_RUNTIME, PYTHON_VERSION, RUNTIMES_ALLOW_LIST), + ) else: _log( "DD_INJECT_FORCE set to True, allowing unsupported runtimes and continuing.", @@ -369,6 +405,9 @@ def _inject(): TELEMETRY_DATA.append( create_count_metric("library_entrypoint.abort", ["reason:missing_" + site_pkgs_path]), ) + set_injection_result( + InjectionResultType.SKIPPED, "ddtrace site-packages not found in %r, aborting" % site_pkgs_path + ) return # Add the custom site-packages directory to the Python path to load the ddtrace package. @@ -384,6 +423,7 @@ def _inject(): "library_entrypoint.error", ["error_type:import_ddtrace_" + type(e).__name__.lower()] ), ) + set_injection_result(InjectionResultType.FAILED, "failed to load ddtrace module: %s" % e) return else: @@ -430,6 +470,7 @@ def _inject(): ], ), ) + set_injection_result(InjectionResultType.SUCCESS, "successfully configured ddtrace package") except Exception as e: TELEMETRY_DATA.append( create_count_metric( @@ -449,6 +490,7 @@ def _inject(): ], ) ) + set_injection_result(InjectionResultType.SKIPPED, "the ddtrace package was already presentVy") try: From e2e9355a2bba8eaac4299df321f2b6fd6fb694f0 Mon Sep 17 00:00:00 2001 From: Mark Spicer Date: Thu, 24 Apr 2025 16:24:49 -0400 Subject: [PATCH 2/3] remove enum --- lib-injection/sources/sitecustomize.py | 31 ++++++++++---------------- 1 file changed, 12 insertions(+), 19 deletions(-) diff --git a/lib-injection/sources/sitecustomize.py b/lib-injection/sources/sitecustomize.py index ff594cae160..ab3205e4da3 100644 --- a/lib-injection/sources/sitecustomize.py +++ b/lib-injection/sources/sitecustomize.py @@ -5,24 +5,18 @@ from collections import namedtuple import csv -import enum import json import os import platform -import psutil import re import subprocess import sys import time - -Version = namedtuple("Version", ["version", "constraint"]) +import psutil -class InjectionResultType(enum.Enum): - SUCCESS = "success" - FAILED = "failed" - SKIPPED = "skipped" +Version = namedtuple("Version", ["version", "constraint"]) def parse_version(version): @@ -65,6 +59,9 @@ def parse_version(version): EXECUTABLE_DENY_LOCATION = os.path.abspath(os.path.join(SCRIPT_DIR, "denied_executables.txt")) SITE_PKGS_MARKER = "site-packages-ddtrace-py" BOOTSTRAP_MARKER = "bootstrap" +INJECT_RESULT_SUCCESS = "success" +INJECT_RESULT_FAILED = "failed" +INJECT_RESULT_SKIPPED = "skipped" INJECTION_RESULT = "" RESULT_REASON = "" @@ -321,9 +318,7 @@ def _inject(): "library_entrypoint.abort.integration", ) ) - set_injection_result( - InjectionResultType.SKIPPED, "Found incompatible executable: %s." % incompatible_sysarg - ) + set_injection_result(INJECT_RESULT_SKIPPED, "Found incompatible executable: %s." % incompatible_sysarg) else: _log( "DD_INJECT_FORCE set to True, allowing unsupported executables and continuing.", @@ -354,9 +349,7 @@ def _inject(): ) ) - set_injection_result( - InjectionResultType.SKIPPED, "Found incompatible packages: %s." % incompatible_packages - ) + set_injection_result(INJECT_RESULT_SKIPPED, "Found incompatible packages: %s." % incompatible_packages) else: _log( "DD_INJECT_FORCE set to True, allowing unsupported integrations and continuing.", @@ -376,7 +369,7 @@ def _inject(): TELEMETRY_DATA.append(create_count_metric("library_entrypoint.abort.runtime")) set_injection_result( - InjectionResultType.SKIPPED, + INJECT_RESULT_SKIPPED, "Found incompatible runtime: %s %s. Supported runtimes: %s" % (PYTHON_RUNTIME, PYTHON_VERSION, RUNTIMES_ALLOW_LIST), ) @@ -406,7 +399,7 @@ def _inject(): create_count_metric("library_entrypoint.abort", ["reason:missing_" + site_pkgs_path]), ) set_injection_result( - InjectionResultType.SKIPPED, "ddtrace site-packages not found in %r, aborting" % site_pkgs_path + INJECT_RESULT_SKIPPED, "ddtrace site-packages not found in %r, aborting" % site_pkgs_path ) return @@ -423,7 +416,7 @@ def _inject(): "library_entrypoint.error", ["error_type:import_ddtrace_" + type(e).__name__.lower()] ), ) - set_injection_result(InjectionResultType.FAILED, "failed to load ddtrace module: %s" % e) + set_injection_result(INJECT_RESULT_FAILED, "failed to load ddtrace module: %s" % e) return else: @@ -470,7 +463,7 @@ def _inject(): ], ), ) - set_injection_result(InjectionResultType.SUCCESS, "successfully configured ddtrace package") + set_injection_result(INJECT_RESULT_SUCCESS, "successfully configured ddtrace package") except Exception as e: TELEMETRY_DATA.append( create_count_metric( @@ -490,7 +483,7 @@ def _inject(): ], ) ) - set_injection_result(InjectionResultType.SKIPPED, "the ddtrace package was already presentVy") + set_injection_result(INJECT_RESULT_SKIPPED, "the ddtrace package was already presentVy") try: From 3fb0526e616dcc73f81583ee883992c79103a068 Mon Sep 17 00:00:00 2001 From: Mark Spicer Date: Fri, 25 Apr 2025 16:34:19 -0400 Subject: [PATCH 3/3] Add injection result class --- lib-injection/sources/sitecustomize.py | 52 ++++++++++++++------------ 1 file changed, 29 insertions(+), 23 deletions(-) diff --git a/lib-injection/sources/sitecustomize.py b/lib-injection/sources/sitecustomize.py index ab3205e4da3..d0c81f2ad1a 100644 --- a/lib-injection/sources/sitecustomize.py +++ b/lib-injection/sources/sitecustomize.py @@ -13,8 +13,6 @@ import sys import time -import psutil - Version = namedtuple("Version", ["version", "constraint"]) @@ -62,8 +60,9 @@ def parse_version(version): INJECT_RESULT_SUCCESS = "success" INJECT_RESULT_FAILED = "failed" INJECT_RESULT_SKIPPED = "skipped" -INJECTION_RESULT = "" -RESULT_REASON = "" +INJECT_RESULT = "" +INJECT_RESULT_REASON = "" +INJECT_RESULT_CLASS = "" def get_oci_ddtrace_version(): @@ -131,9 +130,6 @@ def create_count_metric(metric, tags=None): def gen_telemetry_payload(telemetry_events, ddtrace_version): - pid = os.getpid() - proc = psutil.Process(pid) - return { "metadata": { "language_name": "python", @@ -141,11 +137,10 @@ def gen_telemetry_payload(telemetry_events, ddtrace_version): "runtime_name": PYTHON_RUNTIME, "runtime_version": PYTHON_VERSION, "tracer_version": ddtrace_version, - "component": "dd-trace-py", - "result": INJECTION_RESULT, - "reason": RESULT_REASON, - "pid": pid, - "start_time": proc.create_time, + "pid": os.getpid(), + "inject_result": INJECT_RESULT, + "inject_result_reason": INJECT_RESULT_REASON, + "inject_result_class": INJECT_RESULT_CLASS, }, "points": telemetry_events, } @@ -259,11 +254,13 @@ def get_first_incompatible_sysarg(): return argument -def set_injection_result(result, reason): - global INJECTION_RESULT - global RESULT_REASON - INJECTION_RESULT = result - RESULT_REASON = reason +def set_injection_result(result, resultClass, reason): + global INJECT_RESULT + global INJECT_RESULT_REASON + global INJECT_RESULT_CLASS + INJECT_RESULT = result + INJECT_RESULT_REASON = reason + INJECT_RESULT_CLASS = resultClass def _inject(): @@ -318,7 +315,11 @@ def _inject(): "library_entrypoint.abort.integration", ) ) - set_injection_result(INJECT_RESULT_SKIPPED, "Found incompatible executable: %s." % incompatible_sysarg) + set_injection_result( + INJECT_RESULT_SKIPPED, + "incompatible_runtime", + "Found incompatible executable: %s." % incompatible_sysarg, + ) else: _log( "DD_INJECT_FORCE set to True, allowing unsupported executables and continuing.", @@ -349,7 +350,11 @@ def _inject(): ) ) - set_injection_result(INJECT_RESULT_SKIPPED, "Found incompatible packages: %s." % incompatible_packages) + set_injection_result( + INJECT_RESULT_SKIPPED, + "incompatible_runtime", + "Found incompatible packages: %s." % incompatible_packages, + ) else: _log( "DD_INJECT_FORCE set to True, allowing unsupported integrations and continuing.", @@ -370,6 +375,7 @@ def _inject(): set_injection_result( INJECT_RESULT_SKIPPED, + "incompatible_runtime", "Found incompatible runtime: %s %s. Supported runtimes: %s" % (PYTHON_RUNTIME, PYTHON_VERSION, RUNTIMES_ALLOW_LIST), ) @@ -399,7 +405,7 @@ def _inject(): create_count_metric("library_entrypoint.abort", ["reason:missing_" + site_pkgs_path]), ) set_injection_result( - INJECT_RESULT_SKIPPED, "ddtrace site-packages not found in %r, aborting" % site_pkgs_path + INJECT_RESULT_FAILED, "missing_dependency", "ddtrace site-packages not found in %r" % site_pkgs_path ) return @@ -416,7 +422,7 @@ def _inject(): "library_entrypoint.error", ["error_type:import_ddtrace_" + type(e).__name__.lower()] ), ) - set_injection_result(INJECT_RESULT_FAILED, "failed to load ddtrace module: %s" % e) + set_injection_result(INJECT_RESULT_FAILED, "missing_dependency", "failed to load ddtrace module: %s" % e) return else: @@ -463,7 +469,7 @@ def _inject(): ], ), ) - set_injection_result(INJECT_RESULT_SUCCESS, "successfully configured ddtrace package") + set_injection_result(INJECT_RESULT_SUCCESS, "", "successfully configured ddtrace package") except Exception as e: TELEMETRY_DATA.append( create_count_metric( @@ -483,7 +489,7 @@ def _inject(): ], ) ) - set_injection_result(INJECT_RESULT_SKIPPED, "the ddtrace package was already presentVy") + set_injection_result(INJECT_RESULT_SKIPPED, "already_instrumented", "the ddtrace package was already present") try: