ddtrace 3.11.0rc1__cp312-cp312-win32.whl → 3.11.0rc3__cp312-cp312-win32.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- ddtrace/_logger.py +5 -6
- ddtrace/_trace/product.py +1 -1
- ddtrace/_trace/sampling_rule.py +25 -33
- ddtrace/_trace/trace_handlers.py +12 -50
- ddtrace/_trace/utils_botocore/span_tags.py +48 -0
- ddtrace/_version.py +2 -2
- ddtrace/appsec/_asm_request_context.py +3 -1
- ddtrace/appsec/_constants.py +7 -0
- ddtrace/appsec/_handlers.py +11 -0
- ddtrace/appsec/_iast/_listener.py +12 -2
- ddtrace/appsec/_processor.py +1 -1
- ddtrace/contrib/integration_registry/registry.yaml +10 -0
- ddtrace/contrib/internal/aiobotocore/patch.py +8 -0
- ddtrace/contrib/internal/avro/__init__.py +17 -0
- ddtrace/contrib/internal/azure_functions/patch.py +23 -12
- ddtrace/contrib/internal/azure_functions/utils.py +14 -0
- ddtrace/contrib/internal/boto/patch.py +14 -0
- ddtrace/contrib/internal/botocore/__init__.py +153 -0
- ddtrace/contrib/internal/botocore/services/bedrock.py +3 -27
- ddtrace/contrib/internal/django/patch.py +31 -8
- ddtrace/contrib/{_freezegun.py → internal/freezegun/__init__.py} +1 -1
- ddtrace/contrib/internal/google_genai/_utils.py +2 -2
- ddtrace/contrib/internal/google_genai/patch.py +7 -7
- ddtrace/contrib/internal/google_generativeai/patch.py +7 -5
- ddtrace/contrib/internal/langchain/patch.py +11 -443
- ddtrace/contrib/internal/langchain/utils.py +0 -26
- ddtrace/contrib/internal/logbook/patch.py +1 -2
- ddtrace/contrib/internal/logging/patch.py +4 -7
- ddtrace/contrib/internal/loguru/patch.py +1 -3
- ddtrace/contrib/internal/openai_agents/patch.py +44 -1
- ddtrace/contrib/internal/protobuf/__init__.py +17 -0
- ddtrace/contrib/internal/pytest/__init__.py +62 -0
- ddtrace/contrib/internal/pytest/_plugin_v2.py +13 -4
- ddtrace/contrib/internal/pytest_bdd/__init__.py +23 -0
- ddtrace/contrib/internal/pytest_benchmark/__init__.py +3 -0
- ddtrace/contrib/internal/structlog/patch.py +2 -4
- ddtrace/contrib/internal/unittest/__init__.py +36 -0
- ddtrace/contrib/internal/vertexai/patch.py +7 -5
- ddtrace/ext/ci.py +20 -0
- ddtrace/ext/git.py +66 -11
- ddtrace/internal/_encoding.cp312-win32.pyd +0 -0
- ddtrace/internal/_encoding.pyi +1 -1
- ddtrace/internal/_rand.cp312-win32.pyd +0 -0
- ddtrace/internal/_tagset.cp312-win32.pyd +0 -0
- ddtrace/internal/_threads.cp312-win32.pyd +0 -0
- ddtrace/internal/ci_visibility/encoder.py +126 -49
- ddtrace/internal/ci_visibility/utils.py +4 -4
- ddtrace/internal/core/__init__.py +5 -2
- ddtrace/internal/datadog/profiling/dd_wrapper-unknown-amd64.dll +0 -0
- ddtrace/internal/datadog/profiling/dd_wrapper-unknown-amd64.lib +0 -0
- ddtrace/internal/datadog/profiling/ddup/_ddup.cp312-win32.pyd +0 -0
- ddtrace/internal/datadog/profiling/ddup/_ddup.cp312-win32.pyd.lib +0 -0
- ddtrace/internal/datadog/profiling/ddup/dd_wrapper-unknown-amd64.dll +0 -0
- ddtrace/internal/datadog/profiling/ddup/dd_wrapper-unknown-amd64.lib +0 -0
- ddtrace/internal/endpoints.py +76 -0
- ddtrace/internal/native/_native.cp312-win32.pyd +0 -0
- ddtrace/internal/schema/processor.py +6 -2
- ddtrace/internal/telemetry/metrics_namespaces.cp312-win32.pyd +0 -0
- ddtrace/internal/telemetry/writer.py +18 -0
- ddtrace/internal/test_visibility/coverage_lines.py +4 -4
- ddtrace/internal/writer/writer.py +24 -11
- ddtrace/llmobs/_constants.py +3 -0
- ddtrace/llmobs/_experiment.py +75 -10
- ddtrace/llmobs/_integrations/bedrock.py +4 -0
- ddtrace/llmobs/_integrations/bedrock_agents.py +5 -1
- ddtrace/llmobs/_integrations/crewai.py +52 -3
- ddtrace/llmobs/_integrations/gemini.py +7 -7
- ddtrace/llmobs/_integrations/google_genai.py +10 -10
- ddtrace/llmobs/_integrations/{google_genai_utils.py → google_utils.py} +103 -7
- ddtrace/llmobs/_integrations/langchain.py +29 -20
- ddtrace/llmobs/_integrations/openai_agents.py +145 -0
- ddtrace/llmobs/_integrations/pydantic_ai.py +67 -26
- ddtrace/llmobs/_integrations/utils.py +68 -158
- ddtrace/llmobs/_integrations/vertexai.py +8 -8
- ddtrace/llmobs/_llmobs.py +83 -14
- ddtrace/llmobs/_telemetry.py +20 -5
- ddtrace/llmobs/_utils.py +27 -0
- ddtrace/profiling/_threading.cp312-win32.pyd +0 -0
- ddtrace/profiling/collector/_memalloc.cp312-win32.pyd +0 -0
- ddtrace/profiling/collector/_task.cp312-win32.pyd +0 -0
- ddtrace/profiling/collector/_traceback.cp312-win32.pyd +0 -0
- ddtrace/profiling/collector/stack.cp312-win32.pyd +0 -0
- ddtrace/settings/_config.py +1 -2
- ddtrace/settings/asm.py +9 -2
- ddtrace/settings/profiling.py +0 -9
- ddtrace/vendor/psutil/_psutil_windows.cp312-win32.pyd +0 -0
- {ddtrace-3.11.0rc1.dist-info → ddtrace-3.11.0rc3.dist-info}/METADATA +1 -1
- {ddtrace-3.11.0rc1.dist-info → ddtrace-3.11.0rc3.dist-info}/RECORD +171 -177
- ddtrace/contrib/_avro.py +0 -17
- ddtrace/contrib/_botocore.py +0 -153
- ddtrace/contrib/_protobuf.py +0 -17
- ddtrace/contrib/_pytest.py +0 -62
- ddtrace/contrib/_pytest_bdd.py +0 -23
- ddtrace/contrib/_pytest_benchmark.py +0 -3
- ddtrace/contrib/_unittest.py +0 -36
- /ddtrace/contrib/{_aiobotocore.py → internal/aiobotocore/__init__.py} +0 -0
- /ddtrace/contrib/{_aiohttp_jinja2.py → internal/aiohttp_jinja2/__init__.py} +0 -0
- /ddtrace/contrib/{_aiomysql.py → internal/aiomysql/__init__.py} +0 -0
- /ddtrace/contrib/{_aiopg.py → internal/aiopg/__init__.py} +0 -0
- /ddtrace/contrib/{_aioredis.py → internal/aioredis/__init__.py} +0 -0
- /ddtrace/contrib/{_algoliasearch.py → internal/algoliasearch/__init__.py} +0 -0
- /ddtrace/contrib/{_anthropic.py → internal/anthropic/__init__.py} +0 -0
- /ddtrace/contrib/{_aredis.py → internal/aredis/__init__.py} +0 -0
- /ddtrace/contrib/{_asyncio.py → internal/asyncio/__init__.py} +0 -0
- /ddtrace/contrib/{_asyncpg.py → internal/asyncpg/__init__.py} +0 -0
- /ddtrace/contrib/{_aws_lambda.py → internal/aws_lambda/__init__.py} +0 -0
- /ddtrace/contrib/{_azure_functions.py → internal/azure_functions/__init__.py} +0 -0
- /ddtrace/contrib/{_azure_servicebus.py → internal/azure_servicebus/__init__.py} +0 -0
- /ddtrace/contrib/{_boto.py → internal/boto/__init__.py} +0 -0
- /ddtrace/contrib/{_cassandra.py → internal/cassandra/__init__.py} +0 -0
- /ddtrace/contrib/{_consul.py → internal/consul/__init__.py} +0 -0
- /ddtrace/contrib/{_coverage.py → internal/coverage/__init__.py} +0 -0
- /ddtrace/contrib/{_crewai.py → internal/crewai/__init__.py} +0 -0
- /ddtrace/contrib/{_django.py → internal/django/__init__.py} +0 -0
- /ddtrace/contrib/{_dogpile_cache.py → internal/dogpile_cache/__init__.py} +0 -0
- /ddtrace/contrib/{_dramatiq.py → internal/dramatiq/__init__.py} +0 -0
- /ddtrace/contrib/{_elasticsearch.py → internal/elasticsearch/__init__.py} +0 -0
- /ddtrace/contrib/{_fastapi.py → internal/fastapi/__init__.py} +0 -0
- /ddtrace/contrib/{_flask.py → internal/flask/__init__.py} +0 -0
- /ddtrace/contrib/{_futures.py → internal/futures/__init__.py} +0 -0
- /ddtrace/contrib/{_gevent.py → internal/gevent/__init__.py} +0 -0
- /ddtrace/contrib/{_google_genai.py → internal/google_genai/__init__.py} +0 -0
- /ddtrace/contrib/{_google_generativeai.py → internal/google_generativeai/__init__.py} +0 -0
- /ddtrace/contrib/{_graphql.py → internal/graphql/__init__.py} +0 -0
- /ddtrace/contrib/{_grpc.py → internal/grpc/__init__.py} +0 -0
- /ddtrace/contrib/{_gunicorn.py → internal/gunicorn/__init__.py} +0 -0
- /ddtrace/contrib/{_httplib.py → internal/httplib/__init__.py} +0 -0
- /ddtrace/contrib/{_httpx.py → internal/httpx/__init__.py} +0 -0
- /ddtrace/contrib/{_jinja2.py → internal/jinja2/__init__.py} +0 -0
- /ddtrace/contrib/{_kafka.py → internal/kafka/__init__.py} +0 -0
- /ddtrace/contrib/{_kombu.py → internal/kombu/__init__.py} +0 -0
- /ddtrace/contrib/{_langchain.py → internal/langchain/__init__.py} +0 -0
- /ddtrace/contrib/{_langgraph.py → internal/langgraph/__init__.py} +0 -0
- /ddtrace/contrib/{_litellm.py → internal/litellm/__init__.py} +0 -0
- /ddtrace/contrib/{_logbook.py → internal/logbook/__init__.py} +0 -0
- /ddtrace/contrib/{_logging.py → internal/logging/__init__.py} +0 -0
- /ddtrace/contrib/{_loguru.py → internal/loguru/__init__.py} +0 -0
- /ddtrace/contrib/{_mako.py → internal/mako/__init__.py} +0 -0
- /ddtrace/contrib/{_mariadb.py → internal/mariadb/__init__.py} +0 -0
- /ddtrace/contrib/{_mcp.py → internal/mcp/__init__.py} +0 -0
- /ddtrace/contrib/{_molten.py → internal/molten/__init__.py} +0 -0
- /ddtrace/contrib/{_mongoengine.py → internal/mongoengine/__init__.py} +0 -0
- /ddtrace/contrib/{_mysql.py → internal/mysql/__init__.py} +0 -0
- /ddtrace/contrib/{_mysqldb.py → internal/mysqldb/__init__.py} +0 -0
- /ddtrace/contrib/{_openai.py → internal/openai/__init__.py} +0 -0
- /ddtrace/contrib/{_openai_agents.py → internal/openai_agents/__init__.py} +0 -0
- /ddtrace/contrib/{_psycopg.py → internal/psycopg/__init__.py} +0 -0
- /ddtrace/contrib/{_pydantic_ai.py → internal/pydantic_ai/__init__.py} +0 -0
- /ddtrace/contrib/{_pymemcache.py → internal/pymemcache/__init__.py} +0 -0
- /ddtrace/contrib/{_pymongo.py → internal/pymongo/__init__.py} +0 -0
- /ddtrace/contrib/{_pymysql.py → internal/pymysql/__init__.py} +0 -0
- /ddtrace/contrib/{_pynamodb.py → internal/pynamodb/__init__.py} +0 -0
- /ddtrace/contrib/{_pyodbc.py → internal/pyodbc/__init__.py} +0 -0
- /ddtrace/contrib/{_redis.py → internal/redis/__init__.py} +0 -0
- /ddtrace/contrib/{_rediscluster.py → internal/rediscluster/__init__.py} +0 -0
- /ddtrace/contrib/{_rq.py → internal/rq/__init__.py} +0 -0
- /ddtrace/contrib/{_sanic.py → internal/sanic/__init__.py} +0 -0
- /ddtrace/contrib/{_selenium.py → internal/selenium/__init__.py} +0 -0
- /ddtrace/contrib/{_snowflake.py → internal/snowflake/__init__.py} +0 -0
- /ddtrace/contrib/{_sqlite3.py → internal/sqlite3/__init__.py} +0 -0
- /ddtrace/contrib/{_starlette.py → internal/starlette/__init__.py} +0 -0
- /ddtrace/contrib/{_structlog.py → internal/structlog/__init__.py} +0 -0
- /ddtrace/contrib/{_subprocess.py → internal/subprocess/__init__.py} +0 -0
- /ddtrace/contrib/{_urllib.py → internal/urllib/__init__.py} +0 -0
- /ddtrace/contrib/{_urllib3.py → internal/urllib3/__init__.py} +0 -0
- /ddtrace/contrib/{_vertexai.py → internal/vertexai/__init__.py} +0 -0
- /ddtrace/contrib/{_vertica.py → internal/vertica/__init__.py} +0 -0
- /ddtrace/contrib/{_webbrowser.py → internal/webbrowser/__init__.py} +0 -0
- /ddtrace/contrib/{_yaaredis.py → internal/yaaredis/__init__.py} +0 -0
- {ddtrace-3.11.0rc1.dist-info → ddtrace-3.11.0rc3.dist-info}/WHEEL +0 -0
- {ddtrace-3.11.0rc1.dist-info → ddtrace-3.11.0rc3.dist-info}/entry_points.txt +0 -0
- {ddtrace-3.11.0rc1.dist-info → ddtrace-3.11.0rc3.dist-info}/licenses/LICENSE +0 -0
- {ddtrace-3.11.0rc1.dist-info → ddtrace-3.11.0rc3.dist-info}/licenses/LICENSE.Apache +0 -0
- {ddtrace-3.11.0rc1.dist-info → ddtrace-3.11.0rc3.dist-info}/licenses/LICENSE.BSD3 +0 -0
- {ddtrace-3.11.0rc1.dist-info → ddtrace-3.11.0rc3.dist-info}/licenses/NOTICE +0 -0
- {ddtrace-3.11.0rc1.dist-info → ddtrace-3.11.0rc3.dist-info}/top_level.txt +0 -0
@@ -106,32 +106,6 @@ def shared_stream(
|
|
106
106
|
raise
|
107
107
|
|
108
108
|
|
109
|
-
def tag_general_message_input(span, inputs, integration, langchain_core):
|
110
|
-
if langchain_core and isinstance(inputs, langchain_core.prompt_values.PromptValue):
|
111
|
-
inputs = inputs.to_messages()
|
112
|
-
elif not isinstance(inputs, list):
|
113
|
-
inputs = [inputs]
|
114
|
-
for input_idx, inp in enumerate(inputs):
|
115
|
-
if isinstance(inp, dict):
|
116
|
-
span.set_tag_str(
|
117
|
-
"langchain.request.messages.%d.content" % (input_idx),
|
118
|
-
integration.trunc(str(inp.get("content", ""))),
|
119
|
-
)
|
120
|
-
role = inp.get("role")
|
121
|
-
if role is not None:
|
122
|
-
span.set_tag_str(
|
123
|
-
"langchain.request.messages.%d.message_type" % (input_idx),
|
124
|
-
str(inp.get("role", "")),
|
125
|
-
)
|
126
|
-
elif langchain_core and isinstance(inp, langchain_core.messages.BaseMessage):
|
127
|
-
content = inp.content
|
128
|
-
role = inp.__class__.__name__
|
129
|
-
span.set_tag_str("langchain.request.messages.%d.content" % (input_idx), integration.trunc(str(content)))
|
130
|
-
span.set_tag_str("langchain.request.messages.%d.message_type" % (input_idx), str(role))
|
131
|
-
else:
|
132
|
-
span.set_tag_str("langchain.request.messages.%d.content" % (input_idx), integration.trunc(str(inp)))
|
133
|
-
|
134
|
-
|
135
109
|
def _get_chunk_callback(interface_type, args, kwargs):
|
136
110
|
results = core.dispatch_with_results("langchain.stream.chunk.callback", (interface_type, args, kwargs))
|
137
111
|
callbacks = []
|
@@ -5,7 +5,6 @@ from wrapt import wrap_function_wrapper as _w
|
|
5
5
|
|
6
6
|
import ddtrace
|
7
7
|
from ddtrace import config
|
8
|
-
from ddtrace._logger import LogInjectionState
|
9
8
|
from ddtrace.contrib.internal.trace_utils import unwrap as _u
|
10
9
|
from ddtrace.internal.utils import get_argument_value
|
11
10
|
|
@@ -27,7 +26,7 @@ def _supported_versions() -> Dict[str, str]:
|
|
27
26
|
|
28
27
|
def _w_process_record(func, instance, args, kwargs):
|
29
28
|
# patch logger to include datadog info before logging
|
30
|
-
if config._logs_injection
|
29
|
+
if config._logs_injection:
|
31
30
|
record = get_argument_value(args, kwargs, 0, "record")
|
32
31
|
record.extra.update(ddtrace.tracer.get_log_correlation_context())
|
33
32
|
return func(*args, **kwargs)
|
@@ -5,7 +5,6 @@ from wrapt import wrap_function_wrapper as _w
|
|
5
5
|
|
6
6
|
import ddtrace
|
7
7
|
from ddtrace import config
|
8
|
-
from ddtrace._logger import LogInjectionState
|
9
8
|
from ddtrace._logger import set_log_formatting
|
10
9
|
from ddtrace.contrib.internal.trace_utils import unwrap as _u
|
11
10
|
from ddtrace.internal.constants import LOG_ATTR_ENV
|
@@ -54,15 +53,13 @@ class DDLogRecord:
|
|
54
53
|
def _w_makeRecord(func, instance, args, kwargs):
|
55
54
|
# Get the LogRecord instance for this log
|
56
55
|
record = func(*args, **kwargs)
|
57
|
-
if config._logs_injection
|
58
|
-
|
59
|
-
return record
|
60
|
-
record.__dict__.update(ddtrace.tracer.get_log_correlation_context())
|
56
|
+
if config._logs_injection:
|
57
|
+
record.__dict__.update(ddtrace.tracer.get_log_correlation_context())
|
61
58
|
return record
|
62
59
|
|
63
60
|
|
64
61
|
def _w_StrFormatStyle_format(func, instance, args, kwargs):
|
65
|
-
if config._logs_injection
|
62
|
+
if not config._logs_injection:
|
66
63
|
return func(*args, **kwargs)
|
67
64
|
# The format string "dd.service={dd.service}" expects
|
68
65
|
# the record to have a "dd" property which is an object that
|
@@ -103,7 +100,7 @@ def patch():
|
|
103
100
|
_w(logging.Logger, "makeRecord", _w_makeRecord)
|
104
101
|
_w(logging.StrFormatStyle, "_format", _w_StrFormatStyle_format)
|
105
102
|
|
106
|
-
if config._logs_injection
|
103
|
+
if config._logs_injection:
|
107
104
|
# Only set the formatter is DD_LOGS_INJECTION is set to True. We do not want to modify
|
108
105
|
# unstructured logs if a user has not enabled logs injection.
|
109
106
|
# Also, the Datadog log format must be set after the logging module has been patched,
|
@@ -5,7 +5,6 @@ from wrapt import wrap_function_wrapper as _w
|
|
5
5
|
|
6
6
|
import ddtrace
|
7
7
|
from ddtrace import config
|
8
|
-
from ddtrace._logger import LogInjectionState
|
9
8
|
from ddtrace.contrib.internal.trace_utils import unwrap as _u
|
10
9
|
|
11
10
|
|
@@ -25,12 +24,11 @@ def _supported_versions() -> Dict[str, str]:
|
|
25
24
|
|
26
25
|
|
27
26
|
def _tracer_injection(event_dict):
|
28
|
-
if config._logs_injection
|
27
|
+
if not config._logs_injection:
|
29
28
|
# log injection is opt-out for structured logging
|
30
29
|
return event_dict
|
31
30
|
event_dd_attributes = ddtrace.tracer.get_log_correlation_context()
|
32
31
|
event_dict.update(event_dd_attributes)
|
33
|
-
|
34
32
|
return event_dd_attributes
|
35
33
|
|
36
34
|
|
@@ -5,6 +5,10 @@ from agents.tracing import add_trace_processor
|
|
5
5
|
|
6
6
|
from ddtrace import config
|
7
7
|
from ddtrace.contrib.internal.openai_agents.processor import LLMObsTraceProcessor
|
8
|
+
from ddtrace.contrib.trace_utils import unwrap
|
9
|
+
from ddtrace.contrib.trace_utils import with_traced_module_async
|
10
|
+
from ddtrace.contrib.trace_utils import wrap
|
11
|
+
from ddtrace.internal.utils.version import parse_version
|
8
12
|
from ddtrace.llmobs._integrations.openai_agents import OpenAIAgentsIntegration
|
9
13
|
from ddtrace.trace import Pin
|
10
14
|
|
@@ -22,6 +26,29 @@ def _supported_versions() -> Dict[str, str]:
|
|
22
26
|
return {"agents": ">=0.0.2"}
|
23
27
|
|
24
28
|
|
29
|
+
OPENAI_AGENTS_VERSION = parse_version(get_version())
|
30
|
+
|
31
|
+
|
32
|
+
@with_traced_module_async
|
33
|
+
async def patched_run_single_turn(agents, pin, func, instance, args, kwargs):
|
34
|
+
return await _patched_run_single_turn(agents, pin, func, instance, args, kwargs, agent_index=0)
|
35
|
+
|
36
|
+
|
37
|
+
@with_traced_module_async
|
38
|
+
async def patched_run_single_turn_streamed(agents, pin, func, instance, args, kwargs):
|
39
|
+
return await _patched_run_single_turn(agents, pin, func, instance, args, kwargs, agent_index=1)
|
40
|
+
|
41
|
+
|
42
|
+
async def _patched_run_single_turn(agents, pin, func, instance, args, kwargs, agent_index=0):
|
43
|
+
current_span = pin.tracer.current_span()
|
44
|
+
result = await func(*args, **kwargs)
|
45
|
+
|
46
|
+
integration = agents._datadog_integration
|
47
|
+
integration.tag_agent_manifest(current_span, args, kwargs, agent_index)
|
48
|
+
|
49
|
+
return result
|
50
|
+
|
51
|
+
|
25
52
|
def patch():
|
26
53
|
"""
|
27
54
|
Patch the instrumented methods
|
@@ -33,7 +60,16 @@ def patch():
|
|
33
60
|
|
34
61
|
Pin().onto(agents)
|
35
62
|
|
36
|
-
|
63
|
+
integration = OpenAIAgentsIntegration(integration_config=config.openai_agents)
|
64
|
+
add_trace_processor(LLMObsTraceProcessor(integration))
|
65
|
+
agents._datadog_integration = integration
|
66
|
+
|
67
|
+
if OPENAI_AGENTS_VERSION >= (0, 0, 19):
|
68
|
+
wrap(agents.run.AgentRunner, "_run_single_turn", patched_run_single_turn(agents))
|
69
|
+
wrap(agents.run.AgentRunner, "_run_single_turn_streamed", patched_run_single_turn_streamed(agents))
|
70
|
+
else:
|
71
|
+
wrap(agents.run.Runner, "_run_single_turn", patched_run_single_turn(agents))
|
72
|
+
wrap(agents.run.Runner, "_run_single_turn_streamed", patched_run_single_turn_streamed(agents))
|
37
73
|
|
38
74
|
|
39
75
|
def unpatch():
|
@@ -44,3 +80,10 @@ def unpatch():
|
|
44
80
|
return
|
45
81
|
|
46
82
|
agents._datadog_patch = False
|
83
|
+
|
84
|
+
if OPENAI_AGENTS_VERSION >= (0, 0, 19):
|
85
|
+
unwrap(agents.run.AgentRunner, "_run_single_turn")
|
86
|
+
unwrap(agents.run.AgentRunner, "_run_single_turn_streamed")
|
87
|
+
else:
|
88
|
+
unwrap(agents.run.Runner, "_run_single_turn")
|
89
|
+
unwrap(agents.run.Runner, "_run_single_turn_streamed")
|
@@ -0,0 +1,17 @@
|
|
1
|
+
"""
|
2
|
+
The Protobuf integration will trace all Protobuf read / write calls made with the ``google.protobuf``
|
3
|
+
library. This integration is enabled by default.
|
4
|
+
|
5
|
+
Enabling
|
6
|
+
~~~~~~~~
|
7
|
+
|
8
|
+
The protobuf integration is enabled by default. Use
|
9
|
+
:func:`patch()<ddtrace.patch>` to enable the integration::
|
10
|
+
|
11
|
+
from ddtrace import patch
|
12
|
+
patch(protobuf=True)
|
13
|
+
|
14
|
+
Configuration
|
15
|
+
~~~~~~~~~~~~~
|
16
|
+
|
17
|
+
"""
|
@@ -0,0 +1,62 @@
|
|
1
|
+
"""
|
2
|
+
The pytest integration traces test executions.
|
3
|
+
|
4
|
+
Enabling
|
5
|
+
~~~~~~~~
|
6
|
+
|
7
|
+
Enable traced execution of tests using ``pytest`` runner by
|
8
|
+
running ``pytest --ddtrace`` or by modifying any configuration
|
9
|
+
file read by pytest (``pytest.ini``, ``setup.cfg``, ...)::
|
10
|
+
|
11
|
+
[pytest]
|
12
|
+
ddtrace = 1
|
13
|
+
|
14
|
+
|
15
|
+
If you need to disable it, the option ``--no-ddtrace`` will take
|
16
|
+
precedence over ``--ddtrace`` and (``pytest.ini``, ``setup.cfg``, ...)
|
17
|
+
|
18
|
+
You can enable all integrations by using the ``--ddtrace-patch-all`` option
|
19
|
+
alongside ``--ddtrace`` or by adding this to your configuration::
|
20
|
+
|
21
|
+
[pytest]
|
22
|
+
ddtrace = 1
|
23
|
+
ddtrace-patch-all = 1
|
24
|
+
|
25
|
+
|
26
|
+
.. note::
|
27
|
+
The ddtrace plugin for pytest has the side effect of importing the ddtrace
|
28
|
+
package and starting a global tracer.
|
29
|
+
|
30
|
+
If this is causing issues for your pytest runs where traced execution of
|
31
|
+
tests is not enabled, you can deactivate the plugin::
|
32
|
+
|
33
|
+
[pytest]
|
34
|
+
addopts = -p no:ddtrace
|
35
|
+
|
36
|
+
See the `pytest documentation
|
37
|
+
<https://docs.pytest.org/en/7.1.x/how-to/plugins.html#deactivating-unregistering-a-plugin-by-name>`_
|
38
|
+
for more details.
|
39
|
+
|
40
|
+
|
41
|
+
Global Configuration
|
42
|
+
~~~~~~~~~~~~~~~~~~~~
|
43
|
+
|
44
|
+
.. py:data:: ddtrace.config.pytest["service"]
|
45
|
+
|
46
|
+
The service name reported by default for pytest traces.
|
47
|
+
|
48
|
+
This option can also be set with the integration specific ``DD_PYTEST_SERVICE`` environment
|
49
|
+
variable, or more generally with the `DD_SERVICE` environment variable.
|
50
|
+
|
51
|
+
Default: Name of the repository being tested, otherwise ``"pytest"`` if the repository name cannot be found.
|
52
|
+
|
53
|
+
|
54
|
+
.. py:data:: ddtrace.config.pytest["operation_name"]
|
55
|
+
|
56
|
+
The operation name reported by default for pytest traces.
|
57
|
+
|
58
|
+
This option can also be set with the ``DD_PYTEST_OPERATION_NAME`` environment
|
59
|
+
variable.
|
60
|
+
|
61
|
+
Default: ``"pytest.test"``
|
62
|
+
"""
|
@@ -237,11 +237,12 @@ def _pytest_load_initial_conftests_pre_yield(early_config, parser, args):
|
|
237
237
|
ModuleCodeCollector has a tangible impact on the time it takes to load modules, so it should only be installed if
|
238
238
|
coverage collection is requested by the backend.
|
239
239
|
"""
|
240
|
+
take_over_logger_stream_handler()
|
241
|
+
|
240
242
|
if not _is_enabled_early(early_config, args):
|
241
243
|
return
|
242
244
|
|
243
245
|
try:
|
244
|
-
take_over_logger_stream_handler()
|
245
246
|
dd_config.test_visibility.itr_skipping_level = ITR_SKIPPING_LEVEL.SUITE
|
246
247
|
enable_test_visibility(config=dd_config.pytest)
|
247
248
|
if InternalTestSession.should_collect_coverage():
|
@@ -344,7 +345,7 @@ def pytest_sessionstart(session: pytest.Session) -> None:
|
|
344
345
|
test_impact_analysis="1" if _pytest_version_supports_itr() else None,
|
345
346
|
test_management_quarantine="1",
|
346
347
|
test_management_disable="1",
|
347
|
-
test_management_attempt_to_fix="
|
348
|
+
test_management_attempt_to_fix="5" if _pytest_version_supports_attempt_to_fix() else None,
|
348
349
|
)
|
349
350
|
|
350
351
|
InternalTestSession.discover(
|
@@ -824,8 +825,16 @@ def _pytest_sessionfinish(session: pytest.Session, exitstatus: int) -> None:
|
|
824
825
|
run_coverage_report()
|
825
826
|
|
826
827
|
lines_pct_value = _coverage_data.get(PCT_COVERED_KEY, None)
|
827
|
-
if
|
828
|
-
log.
|
828
|
+
if lines_pct_value is None:
|
829
|
+
log.debug("Unable to retrieve coverage data for the session span")
|
830
|
+
elif not isinstance(lines_pct_value, (float, int)):
|
831
|
+
t = type(lines_pct_value)
|
832
|
+
log.warning(
|
833
|
+
"Unexpected format for total covered percentage: type=%s.%s, value=%r",
|
834
|
+
t.__module__,
|
835
|
+
t.__name__,
|
836
|
+
lines_pct_value,
|
837
|
+
)
|
829
838
|
else:
|
830
839
|
InternalTestSession.set_covered_lines_pct(lines_pct_value)
|
831
840
|
|
@@ -0,0 +1,23 @@
|
|
1
|
+
"""
|
2
|
+
The pytest-bdd integration traces executions of scenarios and steps.
|
3
|
+
|
4
|
+
Enabling
|
5
|
+
~~~~~~~~
|
6
|
+
|
7
|
+
Please follow the instructions for enabling `pytest` integration.
|
8
|
+
|
9
|
+
.. note::
|
10
|
+
The ddtrace.pytest_bdd plugin for pytest-bdd has the side effect of importing
|
11
|
+
the ddtrace package and starting a global tracer.
|
12
|
+
|
13
|
+
If this is causing issues for your pytest-bdd runs where traced execution of
|
14
|
+
tests is not enabled, you can deactivate the plugin::
|
15
|
+
|
16
|
+
[pytest]
|
17
|
+
addopts = -p no:ddtrace.pytest_bdd
|
18
|
+
|
19
|
+
See the `pytest documentation
|
20
|
+
<https://docs.pytest.org/en/7.1.x/how-to/plugins.html#deactivating-unregistering-a-plugin-by-name>`_
|
21
|
+
for more details.
|
22
|
+
|
23
|
+
"""
|
@@ -4,7 +4,6 @@ import structlog
|
|
4
4
|
|
5
5
|
import ddtrace
|
6
6
|
from ddtrace import config
|
7
|
-
from ddtrace._logger import LogInjectionState
|
8
7
|
from ddtrace.contrib.internal.trace_utils import unwrap as _u
|
9
8
|
from ddtrace.contrib.internal.trace_utils import wrap as _w
|
10
9
|
from ddtrace.internal.utils import get_argument_value
|
@@ -27,9 +26,8 @@ def _supported_versions() -> Dict[str, str]:
|
|
27
26
|
|
28
27
|
|
29
28
|
def _tracer_injection(_, __, event_dict):
|
30
|
-
if config._logs_injection
|
31
|
-
|
32
|
-
event_dict.update(ddtrace.tracer.get_log_correlation_context())
|
29
|
+
if config._logs_injection:
|
30
|
+
event_dict.update(ddtrace.tracer.get_log_correlation_context())
|
33
31
|
return event_dict
|
34
32
|
|
35
33
|
|
@@ -0,0 +1,36 @@
|
|
1
|
+
"""
|
2
|
+
The unittest integration traces test executions.
|
3
|
+
|
4
|
+
|
5
|
+
Enabling
|
6
|
+
~~~~~~~~
|
7
|
+
|
8
|
+
The unittest integration is enabled automatically when using
|
9
|
+
:ref:`ddtrace-run<ddtracerun>` or :ref:`import ddtrace.auto<ddtraceauto>`.
|
10
|
+
|
11
|
+
Alternately, use :func:`patch()<ddtrace.patch>` to manually enable the integration::
|
12
|
+
|
13
|
+
from ddtrace import patch
|
14
|
+
patch(unittest=True)
|
15
|
+
|
16
|
+
Global Configuration
|
17
|
+
~~~~~~~~~~~~~~~~~~~~
|
18
|
+
|
19
|
+
.. py:data:: ddtrace.config.unittest["operation_name"]
|
20
|
+
|
21
|
+
The operation name reported by default for unittest traces.
|
22
|
+
|
23
|
+
This option can also be set with the ``DD_UNITTEST_OPERATION_NAME`` environment
|
24
|
+
variable.
|
25
|
+
|
26
|
+
Default: ``"unittest.test"``
|
27
|
+
|
28
|
+
.. py:data:: ddtrace.config.unittest["strict_naming"]
|
29
|
+
|
30
|
+
Requires all ``unittest`` tests to start with ``test`` as stated in the Python documentation
|
31
|
+
|
32
|
+
This option can also be set with the ``DD_CIVISIBILITY_UNITTEST_STRICT_NAMING`` environment
|
33
|
+
variable.
|
34
|
+
|
35
|
+
Default: ``True``
|
36
|
+
"""
|
@@ -14,7 +14,7 @@ from ddtrace.contrib.internal.trace_utils import wrap
|
|
14
14
|
from ddtrace.contrib.internal.vertexai._utils import TracedAsyncVertexAIStreamResponse
|
15
15
|
from ddtrace.contrib.internal.vertexai._utils import TracedVertexAIStreamResponse
|
16
16
|
from ddtrace.llmobs._integrations import VertexAIIntegration
|
17
|
-
from ddtrace.llmobs._integrations.
|
17
|
+
from ddtrace.llmobs._integrations.google_utils import extract_provider_and_model_name
|
18
18
|
from ddtrace.trace import Pin
|
19
19
|
|
20
20
|
|
@@ -60,11 +60,12 @@ def _traced_generate(vertexai, pin, func, instance, args, kwargs, model_instance
|
|
60
60
|
integration = vertexai._datadog_integration
|
61
61
|
stream = kwargs.get("stream", False)
|
62
62
|
generations = None
|
63
|
+
provider_name, model_name = extract_provider_and_model_name(instance=model_instance, model_name_attr="_model_name")
|
63
64
|
span = integration.trace(
|
64
65
|
pin,
|
65
66
|
"%s.%s" % (instance.__class__.__name__, func.__name__),
|
66
|
-
provider=
|
67
|
-
model=
|
67
|
+
provider=provider_name,
|
68
|
+
model=model_name,
|
68
69
|
submit_to_llmobs=True,
|
69
70
|
)
|
70
71
|
# history must be copied since it is modified during the LLM interaction
|
@@ -92,11 +93,12 @@ async def _traced_agenerate(vertexai, pin, func, instance, args, kwargs, model_i
|
|
92
93
|
integration = vertexai._datadog_integration
|
93
94
|
stream = kwargs.get("stream", False)
|
94
95
|
generations = None
|
96
|
+
provider_name, model_name = extract_provider_and_model_name(instance=model_instance, model_name_attr="_model_name")
|
95
97
|
span = integration.trace(
|
96
98
|
pin,
|
97
99
|
"%s.%s" % (instance.__class__.__name__, func.__name__),
|
98
|
-
provider=
|
99
|
-
model=
|
100
|
+
provider=provider_name,
|
101
|
+
model=model_name,
|
100
102
|
submit_to_llmobs=True,
|
101
103
|
)
|
102
104
|
# history must be copied since it is modified during the LLM interaction
|
ddtrace/ext/ci.py
CHANGED
@@ -105,6 +105,16 @@ def tags(env=None, cwd=None):
|
|
105
105
|
break
|
106
106
|
|
107
107
|
git_info = git.extract_git_metadata(cwd=cwd)
|
108
|
+
|
109
|
+
# Whenever the HEAD commit SHA is present in the tags that come from the CI provider, we assume that
|
110
|
+
# the CI provider added a commit on top of the user's HEAD commit (e.g., GitHub Actions add a merge
|
111
|
+
# commit when triggered by a pull request). In that case, we extract the metadata for that commit specifically
|
112
|
+
# and add it to the tags.
|
113
|
+
head_commit_sha = tags.get(git.COMMIT_HEAD_SHA)
|
114
|
+
if head_commit_sha:
|
115
|
+
git_head_info = git.extract_git_head_metadata(head_commit_sha=head_commit_sha, cwd=cwd)
|
116
|
+
git_info.update(git_head_info)
|
117
|
+
|
108
118
|
try:
|
109
119
|
git_info[WORKSPACE_PATH] = git.extract_workspace_path(cwd=cwd)
|
110
120
|
except git.GitNotFoundError:
|
@@ -349,6 +359,15 @@ def extract_github_actions(env):
|
|
349
359
|
github_run_id,
|
350
360
|
)
|
351
361
|
|
362
|
+
git_commit_head_sha = None
|
363
|
+
if "GITHUB_EVENT_PATH" in env:
|
364
|
+
try:
|
365
|
+
with open(env["GITHUB_EVENT_PATH"]) as f:
|
366
|
+
github_event_data = json.load(f)
|
367
|
+
git_commit_head_sha = github_event_data.get("pull_request", {}).get("head", {}).get("sha")
|
368
|
+
except Exception as e:
|
369
|
+
log.error("Failed to read or parse GITHUB_EVENT_PATH: %s", e)
|
370
|
+
|
352
371
|
env_vars = {
|
353
372
|
"GITHUB_SERVER_URL": github_server_url,
|
354
373
|
"GITHUB_REPOSITORY": github_repository,
|
@@ -362,6 +381,7 @@ def extract_github_actions(env):
|
|
362
381
|
git.BRANCH: env.get("GITHUB_HEAD_REF") or env.get("GITHUB_REF"),
|
363
382
|
git.COMMIT_SHA: git_commit_sha,
|
364
383
|
git.REPOSITORY_URL: "{0}/{1}.git".format(github_server_url, github_repository),
|
384
|
+
git.COMMIT_HEAD_SHA: git_commit_head_sha,
|
365
385
|
JOB_URL: "{0}/{1}/commit/{2}/checks".format(github_server_url, github_repository, git_commit_sha),
|
366
386
|
PIPELINE_ID: github_run_id,
|
367
387
|
PIPELINE_NAME: env.get("GITHUB_WORKFLOW"),
|
ddtrace/ext/git.py
CHANGED
@@ -33,6 +33,30 @@ BRANCH = "git.branch"
|
|
33
33
|
# Git Commit SHA
|
34
34
|
COMMIT_SHA = "git.commit.sha"
|
35
35
|
|
36
|
+
# Git Commit HEAD SHA
|
37
|
+
COMMIT_HEAD_SHA = "git.commit.head.sha"
|
38
|
+
|
39
|
+
# Git Commit HEAD message
|
40
|
+
COMMIT_HEAD_MESSAGE = "git.commit.head.message"
|
41
|
+
|
42
|
+
# Git Commit HEAD author date
|
43
|
+
COMMIT_HEAD_AUTHOR_DATE = "git.commit.head.author.date"
|
44
|
+
|
45
|
+
# Git Commit HEAD author email
|
46
|
+
COMMIT_HEAD_AUTHOR_EMAIL = "git.commit.head.author.email"
|
47
|
+
|
48
|
+
# Git Commit HEAD author name
|
49
|
+
COMMIT_HEAD_AUTHOR_NAME = "git.commit.head.author.name"
|
50
|
+
|
51
|
+
# Git Commit HEAD committer date
|
52
|
+
COMMIT_HEAD_COMMITTER_DATE = "git.commit.head.committer.date"
|
53
|
+
|
54
|
+
# Git Commit HEAD committer email
|
55
|
+
COMMIT_HEAD_COMMITTER_EMAIL = "git.commit.head.committer.email"
|
56
|
+
|
57
|
+
# Git Commit HEAD committer name
|
58
|
+
COMMIT_HEAD_COMMITTER_NAME = "git.commit.head.committer.name"
|
59
|
+
|
36
60
|
# Git Repository URL
|
37
61
|
REPOSITORY_URL = "git.repository_url"
|
38
62
|
|
@@ -173,11 +197,12 @@ def _get_device_for_path(path):
|
|
173
197
|
return os.stat(path).st_dev
|
174
198
|
|
175
199
|
|
176
|
-
def _unshallow_repository_with_details(
|
177
|
-
|
200
|
+
def _unshallow_repository_with_details(
|
201
|
+
cwd: Optional[str] = None, repo: Optional[str] = None, refspec: Optional[str] = None, parent_only: bool = False
|
202
|
+
) -> _GitSubprocessDetails:
|
178
203
|
cmd = [
|
179
204
|
"fetch",
|
180
|
-
'--shallow-since="1 month ago"',
|
205
|
+
"--deepen=1" if parent_only else '--shallow-since="1 month ago"',
|
181
206
|
"--update-shallow",
|
182
207
|
"--filter=blob:none",
|
183
208
|
"--recurse-submodules=no",
|
@@ -190,18 +215,22 @@ def _unshallow_repository_with_details(cwd=None, repo=None, refspec=None):
|
|
190
215
|
return _git_subprocess_cmd_with_details(*cmd, cwd=cwd)
|
191
216
|
|
192
217
|
|
193
|
-
def _unshallow_repository(
|
194
|
-
|
195
|
-
|
218
|
+
def _unshallow_repository(
|
219
|
+
cwd: Optional[str] = None,
|
220
|
+
repo: Optional[str] = None,
|
221
|
+
refspec: Optional[str] = None,
|
222
|
+
parent_only: bool = False,
|
223
|
+
) -> None:
|
224
|
+
_unshallow_repository_with_details(cwd, repo, refspec, parent_only)
|
196
225
|
|
197
226
|
|
198
|
-
def extract_user_info(cwd=None):
|
199
|
-
# type: (Optional[str]) -> Dict[str, Tuple[str, str, str]]
|
227
|
+
def extract_user_info(cwd: Optional[str] = None, commit_sha: Optional[str] = None) -> Dict[str, Tuple[str, str, str]]:
|
200
228
|
"""Extract commit author info from the git repository in the current directory or one specified by ``cwd``."""
|
201
229
|
# Note: `git show -s --format... --date...` is supported since git 2.1.4 onwards
|
202
|
-
|
203
|
-
|
204
|
-
|
230
|
+
cmd = "show -s --format=%an|||%ae|||%ad|||%cn|||%ce|||%cd --date=format:%Y-%m-%dT%H:%M:%S%z"
|
231
|
+
if commit_sha:
|
232
|
+
cmd += " " + commit_sha
|
233
|
+
stdout = _git_subprocess_cmd(cmd=cmd, cwd=cwd)
|
205
234
|
author_name, author_email, author_date, committer_name, committer_email, committer_date = stdout.split("|||")
|
206
235
|
return {
|
207
236
|
"author": (author_name, author_email, author_date),
|
@@ -316,6 +345,32 @@ def extract_commit_sha(cwd=None):
|
|
316
345
|
return commit_sha
|
317
346
|
|
318
347
|
|
348
|
+
def extract_git_head_metadata(head_commit_sha: str, cwd: Optional[str] = None) -> Dict[str, Optional[str]]:
|
349
|
+
tags: Dict[str, Optional[str]] = {}
|
350
|
+
|
351
|
+
is_shallow, *_ = _is_shallow_repository_with_details(cwd=cwd)
|
352
|
+
if is_shallow:
|
353
|
+
_unshallow_repository(cwd=cwd, repo=None, refspec=None, parent_only=True)
|
354
|
+
|
355
|
+
try:
|
356
|
+
users = extract_user_info(cwd=cwd, commit_sha=head_commit_sha)
|
357
|
+
tags[COMMIT_HEAD_AUTHOR_NAME] = users["author"][0]
|
358
|
+
tags[COMMIT_HEAD_AUTHOR_EMAIL] = users["author"][1]
|
359
|
+
tags[COMMIT_HEAD_AUTHOR_DATE] = users["author"][2]
|
360
|
+
tags[COMMIT_HEAD_COMMITTER_NAME] = users["committer"][0]
|
361
|
+
tags[COMMIT_HEAD_COMMITTER_EMAIL] = users["committer"][1]
|
362
|
+
tags[COMMIT_HEAD_COMMITTER_DATE] = users["committer"][2]
|
363
|
+
tags[COMMIT_HEAD_MESSAGE] = _git_subprocess_cmd(" ".join(("log -n 1 --format=%B", head_commit_sha)), cwd)
|
364
|
+
except GitNotFoundError:
|
365
|
+
log.error("Git executable not found, cannot extract git metadata.")
|
366
|
+
except ValueError as e:
|
367
|
+
debug_mode = log.isEnabledFor(logging.DEBUG)
|
368
|
+
stderr = str(e)
|
369
|
+
log.error("Error extracting git metadata: %s", stderr, exc_info=debug_mode)
|
370
|
+
|
371
|
+
return tags
|
372
|
+
|
373
|
+
|
319
374
|
def extract_git_metadata(cwd=None):
|
320
375
|
# type: (Optional[str]) -> Dict[str, Optional[str]]
|
321
376
|
"""Extract git commit metadata."""
|
Binary file
|
ddtrace/internal/_encoding.pyi
CHANGED
@@ -23,7 +23,7 @@ class BufferedEncoder(object):
|
|
23
23
|
def __init__(self, max_size: int, max_item_size: int) -> None: ...
|
24
24
|
def __len__(self) -> int: ...
|
25
25
|
def put(self, item: Any) -> None: ...
|
26
|
-
def encode(self) -> Tuple[Optional[bytes], int]: ...
|
26
|
+
def encode(self) -> List[Tuple[Optional[bytes], int]]: ...
|
27
27
|
@property
|
28
28
|
def size(self) -> int: ...
|
29
29
|
|
Binary file
|
Binary file
|
Binary file
|