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.
Files changed (176) hide show
  1. ddtrace/_logger.py +5 -6
  2. ddtrace/_trace/product.py +1 -1
  3. ddtrace/_trace/sampling_rule.py +25 -33
  4. ddtrace/_trace/trace_handlers.py +12 -50
  5. ddtrace/_trace/utils_botocore/span_tags.py +48 -0
  6. ddtrace/_version.py +2 -2
  7. ddtrace/appsec/_asm_request_context.py +3 -1
  8. ddtrace/appsec/_constants.py +7 -0
  9. ddtrace/appsec/_handlers.py +11 -0
  10. ddtrace/appsec/_iast/_listener.py +12 -2
  11. ddtrace/appsec/_processor.py +1 -1
  12. ddtrace/contrib/integration_registry/registry.yaml +10 -0
  13. ddtrace/contrib/internal/aiobotocore/patch.py +8 -0
  14. ddtrace/contrib/internal/avro/__init__.py +17 -0
  15. ddtrace/contrib/internal/azure_functions/patch.py +23 -12
  16. ddtrace/contrib/internal/azure_functions/utils.py +14 -0
  17. ddtrace/contrib/internal/boto/patch.py +14 -0
  18. ddtrace/contrib/internal/botocore/__init__.py +153 -0
  19. ddtrace/contrib/internal/botocore/services/bedrock.py +3 -27
  20. ddtrace/contrib/internal/django/patch.py +31 -8
  21. ddtrace/contrib/{_freezegun.py → internal/freezegun/__init__.py} +1 -1
  22. ddtrace/contrib/internal/google_genai/_utils.py +2 -2
  23. ddtrace/contrib/internal/google_genai/patch.py +7 -7
  24. ddtrace/contrib/internal/google_generativeai/patch.py +7 -5
  25. ddtrace/contrib/internal/langchain/patch.py +11 -443
  26. ddtrace/contrib/internal/langchain/utils.py +0 -26
  27. ddtrace/contrib/internal/logbook/patch.py +1 -2
  28. ddtrace/contrib/internal/logging/patch.py +4 -7
  29. ddtrace/contrib/internal/loguru/patch.py +1 -3
  30. ddtrace/contrib/internal/openai_agents/patch.py +44 -1
  31. ddtrace/contrib/internal/protobuf/__init__.py +17 -0
  32. ddtrace/contrib/internal/pytest/__init__.py +62 -0
  33. ddtrace/contrib/internal/pytest/_plugin_v2.py +13 -4
  34. ddtrace/contrib/internal/pytest_bdd/__init__.py +23 -0
  35. ddtrace/contrib/internal/pytest_benchmark/__init__.py +3 -0
  36. ddtrace/contrib/internal/structlog/patch.py +2 -4
  37. ddtrace/contrib/internal/unittest/__init__.py +36 -0
  38. ddtrace/contrib/internal/vertexai/patch.py +7 -5
  39. ddtrace/ext/ci.py +20 -0
  40. ddtrace/ext/git.py +66 -11
  41. ddtrace/internal/_encoding.cp312-win32.pyd +0 -0
  42. ddtrace/internal/_encoding.pyi +1 -1
  43. ddtrace/internal/_rand.cp312-win32.pyd +0 -0
  44. ddtrace/internal/_tagset.cp312-win32.pyd +0 -0
  45. ddtrace/internal/_threads.cp312-win32.pyd +0 -0
  46. ddtrace/internal/ci_visibility/encoder.py +126 -49
  47. ddtrace/internal/ci_visibility/utils.py +4 -4
  48. ddtrace/internal/core/__init__.py +5 -2
  49. ddtrace/internal/datadog/profiling/dd_wrapper-unknown-amd64.dll +0 -0
  50. ddtrace/internal/datadog/profiling/dd_wrapper-unknown-amd64.lib +0 -0
  51. ddtrace/internal/datadog/profiling/ddup/_ddup.cp312-win32.pyd +0 -0
  52. ddtrace/internal/datadog/profiling/ddup/_ddup.cp312-win32.pyd.lib +0 -0
  53. ddtrace/internal/datadog/profiling/ddup/dd_wrapper-unknown-amd64.dll +0 -0
  54. ddtrace/internal/datadog/profiling/ddup/dd_wrapper-unknown-amd64.lib +0 -0
  55. ddtrace/internal/endpoints.py +76 -0
  56. ddtrace/internal/native/_native.cp312-win32.pyd +0 -0
  57. ddtrace/internal/schema/processor.py +6 -2
  58. ddtrace/internal/telemetry/metrics_namespaces.cp312-win32.pyd +0 -0
  59. ddtrace/internal/telemetry/writer.py +18 -0
  60. ddtrace/internal/test_visibility/coverage_lines.py +4 -4
  61. ddtrace/internal/writer/writer.py +24 -11
  62. ddtrace/llmobs/_constants.py +3 -0
  63. ddtrace/llmobs/_experiment.py +75 -10
  64. ddtrace/llmobs/_integrations/bedrock.py +4 -0
  65. ddtrace/llmobs/_integrations/bedrock_agents.py +5 -1
  66. ddtrace/llmobs/_integrations/crewai.py +52 -3
  67. ddtrace/llmobs/_integrations/gemini.py +7 -7
  68. ddtrace/llmobs/_integrations/google_genai.py +10 -10
  69. ddtrace/llmobs/_integrations/{google_genai_utils.py → google_utils.py} +103 -7
  70. ddtrace/llmobs/_integrations/langchain.py +29 -20
  71. ddtrace/llmobs/_integrations/openai_agents.py +145 -0
  72. ddtrace/llmobs/_integrations/pydantic_ai.py +67 -26
  73. ddtrace/llmobs/_integrations/utils.py +68 -158
  74. ddtrace/llmobs/_integrations/vertexai.py +8 -8
  75. ddtrace/llmobs/_llmobs.py +83 -14
  76. ddtrace/llmobs/_telemetry.py +20 -5
  77. ddtrace/llmobs/_utils.py +27 -0
  78. ddtrace/profiling/_threading.cp312-win32.pyd +0 -0
  79. ddtrace/profiling/collector/_memalloc.cp312-win32.pyd +0 -0
  80. ddtrace/profiling/collector/_task.cp312-win32.pyd +0 -0
  81. ddtrace/profiling/collector/_traceback.cp312-win32.pyd +0 -0
  82. ddtrace/profiling/collector/stack.cp312-win32.pyd +0 -0
  83. ddtrace/settings/_config.py +1 -2
  84. ddtrace/settings/asm.py +9 -2
  85. ddtrace/settings/profiling.py +0 -9
  86. ddtrace/vendor/psutil/_psutil_windows.cp312-win32.pyd +0 -0
  87. {ddtrace-3.11.0rc1.dist-info → ddtrace-3.11.0rc3.dist-info}/METADATA +1 -1
  88. {ddtrace-3.11.0rc1.dist-info → ddtrace-3.11.0rc3.dist-info}/RECORD +171 -177
  89. ddtrace/contrib/_avro.py +0 -17
  90. ddtrace/contrib/_botocore.py +0 -153
  91. ddtrace/contrib/_protobuf.py +0 -17
  92. ddtrace/contrib/_pytest.py +0 -62
  93. ddtrace/contrib/_pytest_bdd.py +0 -23
  94. ddtrace/contrib/_pytest_benchmark.py +0 -3
  95. ddtrace/contrib/_unittest.py +0 -36
  96. /ddtrace/contrib/{_aiobotocore.py → internal/aiobotocore/__init__.py} +0 -0
  97. /ddtrace/contrib/{_aiohttp_jinja2.py → internal/aiohttp_jinja2/__init__.py} +0 -0
  98. /ddtrace/contrib/{_aiomysql.py → internal/aiomysql/__init__.py} +0 -0
  99. /ddtrace/contrib/{_aiopg.py → internal/aiopg/__init__.py} +0 -0
  100. /ddtrace/contrib/{_aioredis.py → internal/aioredis/__init__.py} +0 -0
  101. /ddtrace/contrib/{_algoliasearch.py → internal/algoliasearch/__init__.py} +0 -0
  102. /ddtrace/contrib/{_anthropic.py → internal/anthropic/__init__.py} +0 -0
  103. /ddtrace/contrib/{_aredis.py → internal/aredis/__init__.py} +0 -0
  104. /ddtrace/contrib/{_asyncio.py → internal/asyncio/__init__.py} +0 -0
  105. /ddtrace/contrib/{_asyncpg.py → internal/asyncpg/__init__.py} +0 -0
  106. /ddtrace/contrib/{_aws_lambda.py → internal/aws_lambda/__init__.py} +0 -0
  107. /ddtrace/contrib/{_azure_functions.py → internal/azure_functions/__init__.py} +0 -0
  108. /ddtrace/contrib/{_azure_servicebus.py → internal/azure_servicebus/__init__.py} +0 -0
  109. /ddtrace/contrib/{_boto.py → internal/boto/__init__.py} +0 -0
  110. /ddtrace/contrib/{_cassandra.py → internal/cassandra/__init__.py} +0 -0
  111. /ddtrace/contrib/{_consul.py → internal/consul/__init__.py} +0 -0
  112. /ddtrace/contrib/{_coverage.py → internal/coverage/__init__.py} +0 -0
  113. /ddtrace/contrib/{_crewai.py → internal/crewai/__init__.py} +0 -0
  114. /ddtrace/contrib/{_django.py → internal/django/__init__.py} +0 -0
  115. /ddtrace/contrib/{_dogpile_cache.py → internal/dogpile_cache/__init__.py} +0 -0
  116. /ddtrace/contrib/{_dramatiq.py → internal/dramatiq/__init__.py} +0 -0
  117. /ddtrace/contrib/{_elasticsearch.py → internal/elasticsearch/__init__.py} +0 -0
  118. /ddtrace/contrib/{_fastapi.py → internal/fastapi/__init__.py} +0 -0
  119. /ddtrace/contrib/{_flask.py → internal/flask/__init__.py} +0 -0
  120. /ddtrace/contrib/{_futures.py → internal/futures/__init__.py} +0 -0
  121. /ddtrace/contrib/{_gevent.py → internal/gevent/__init__.py} +0 -0
  122. /ddtrace/contrib/{_google_genai.py → internal/google_genai/__init__.py} +0 -0
  123. /ddtrace/contrib/{_google_generativeai.py → internal/google_generativeai/__init__.py} +0 -0
  124. /ddtrace/contrib/{_graphql.py → internal/graphql/__init__.py} +0 -0
  125. /ddtrace/contrib/{_grpc.py → internal/grpc/__init__.py} +0 -0
  126. /ddtrace/contrib/{_gunicorn.py → internal/gunicorn/__init__.py} +0 -0
  127. /ddtrace/contrib/{_httplib.py → internal/httplib/__init__.py} +0 -0
  128. /ddtrace/contrib/{_httpx.py → internal/httpx/__init__.py} +0 -0
  129. /ddtrace/contrib/{_jinja2.py → internal/jinja2/__init__.py} +0 -0
  130. /ddtrace/contrib/{_kafka.py → internal/kafka/__init__.py} +0 -0
  131. /ddtrace/contrib/{_kombu.py → internal/kombu/__init__.py} +0 -0
  132. /ddtrace/contrib/{_langchain.py → internal/langchain/__init__.py} +0 -0
  133. /ddtrace/contrib/{_langgraph.py → internal/langgraph/__init__.py} +0 -0
  134. /ddtrace/contrib/{_litellm.py → internal/litellm/__init__.py} +0 -0
  135. /ddtrace/contrib/{_logbook.py → internal/logbook/__init__.py} +0 -0
  136. /ddtrace/contrib/{_logging.py → internal/logging/__init__.py} +0 -0
  137. /ddtrace/contrib/{_loguru.py → internal/loguru/__init__.py} +0 -0
  138. /ddtrace/contrib/{_mako.py → internal/mako/__init__.py} +0 -0
  139. /ddtrace/contrib/{_mariadb.py → internal/mariadb/__init__.py} +0 -0
  140. /ddtrace/contrib/{_mcp.py → internal/mcp/__init__.py} +0 -0
  141. /ddtrace/contrib/{_molten.py → internal/molten/__init__.py} +0 -0
  142. /ddtrace/contrib/{_mongoengine.py → internal/mongoengine/__init__.py} +0 -0
  143. /ddtrace/contrib/{_mysql.py → internal/mysql/__init__.py} +0 -0
  144. /ddtrace/contrib/{_mysqldb.py → internal/mysqldb/__init__.py} +0 -0
  145. /ddtrace/contrib/{_openai.py → internal/openai/__init__.py} +0 -0
  146. /ddtrace/contrib/{_openai_agents.py → internal/openai_agents/__init__.py} +0 -0
  147. /ddtrace/contrib/{_psycopg.py → internal/psycopg/__init__.py} +0 -0
  148. /ddtrace/contrib/{_pydantic_ai.py → internal/pydantic_ai/__init__.py} +0 -0
  149. /ddtrace/contrib/{_pymemcache.py → internal/pymemcache/__init__.py} +0 -0
  150. /ddtrace/contrib/{_pymongo.py → internal/pymongo/__init__.py} +0 -0
  151. /ddtrace/contrib/{_pymysql.py → internal/pymysql/__init__.py} +0 -0
  152. /ddtrace/contrib/{_pynamodb.py → internal/pynamodb/__init__.py} +0 -0
  153. /ddtrace/contrib/{_pyodbc.py → internal/pyodbc/__init__.py} +0 -0
  154. /ddtrace/contrib/{_redis.py → internal/redis/__init__.py} +0 -0
  155. /ddtrace/contrib/{_rediscluster.py → internal/rediscluster/__init__.py} +0 -0
  156. /ddtrace/contrib/{_rq.py → internal/rq/__init__.py} +0 -0
  157. /ddtrace/contrib/{_sanic.py → internal/sanic/__init__.py} +0 -0
  158. /ddtrace/contrib/{_selenium.py → internal/selenium/__init__.py} +0 -0
  159. /ddtrace/contrib/{_snowflake.py → internal/snowflake/__init__.py} +0 -0
  160. /ddtrace/contrib/{_sqlite3.py → internal/sqlite3/__init__.py} +0 -0
  161. /ddtrace/contrib/{_starlette.py → internal/starlette/__init__.py} +0 -0
  162. /ddtrace/contrib/{_structlog.py → internal/structlog/__init__.py} +0 -0
  163. /ddtrace/contrib/{_subprocess.py → internal/subprocess/__init__.py} +0 -0
  164. /ddtrace/contrib/{_urllib.py → internal/urllib/__init__.py} +0 -0
  165. /ddtrace/contrib/{_urllib3.py → internal/urllib3/__init__.py} +0 -0
  166. /ddtrace/contrib/{_vertexai.py → internal/vertexai/__init__.py} +0 -0
  167. /ddtrace/contrib/{_vertica.py → internal/vertica/__init__.py} +0 -0
  168. /ddtrace/contrib/{_webbrowser.py → internal/webbrowser/__init__.py} +0 -0
  169. /ddtrace/contrib/{_yaaredis.py → internal/yaaredis/__init__.py} +0 -0
  170. {ddtrace-3.11.0rc1.dist-info → ddtrace-3.11.0rc3.dist-info}/WHEEL +0 -0
  171. {ddtrace-3.11.0rc1.dist-info → ddtrace-3.11.0rc3.dist-info}/entry_points.txt +0 -0
  172. {ddtrace-3.11.0rc1.dist-info → ddtrace-3.11.0rc3.dist-info}/licenses/LICENSE +0 -0
  173. {ddtrace-3.11.0rc1.dist-info → ddtrace-3.11.0rc3.dist-info}/licenses/LICENSE.Apache +0 -0
  174. {ddtrace-3.11.0rc1.dist-info → ddtrace-3.11.0rc3.dist-info}/licenses/LICENSE.BSD3 +0 -0
  175. {ddtrace-3.11.0rc1.dist-info → ddtrace-3.11.0rc3.dist-info}/licenses/NOTICE +0 -0
  176. {ddtrace-3.11.0rc1.dist-info → ddtrace-3.11.0rc3.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,153 @@
1
+ """
2
+ The Botocore integration will trace all AWS calls made with the botocore
3
+ library. Libraries like Boto3 that use Botocore will also be patched.
4
+
5
+ Enabling
6
+ ~~~~~~~~
7
+
8
+ The botocore integration is enabled automatically when using
9
+ :ref:`ddtrace-run<ddtracerun>` or :ref:`import ddtrace.auto<ddtraceauto>`.
10
+
11
+ Or use :func:`patch()<ddtrace.patch>` to manually enable the integration::
12
+
13
+ from ddtrace import patch
14
+ patch(botocore=True)
15
+
16
+ To patch only specific botocore modules, pass a list of the module names instead::
17
+
18
+ from ddtrace import patch
19
+ patch(botocore=['s3', 'sns'])
20
+
21
+ Configuration
22
+ ~~~~~~~~~~~~~
23
+
24
+ .. py:data:: ddtrace.config.botocore['distributed_tracing']
25
+
26
+ Whether to inject distributed tracing data to requests in SQS, SNS, EventBridge, Kinesis Streams and Lambda.
27
+
28
+ Can also be enabled with the ``DD_BOTOCORE_DISTRIBUTED_TRACING`` environment variable.
29
+
30
+ Example::
31
+
32
+ from ddtrace import config
33
+
34
+ # Enable distributed tracing
35
+ config.botocore['distributed_tracing'] = True
36
+
37
+
38
+ Default: ``True``
39
+
40
+
41
+ .. py:data:: ddtrace.config.botocore['invoke_with_legacy_context']
42
+
43
+ This preserves legacy behavior when tracing directly invoked Python and Node Lambda
44
+ functions instrumented with datadog-lambda-python < v41 or datadog-lambda-js < v3.58.0.
45
+
46
+ Legacy support for older libraries is available with
47
+ ``ddtrace.config.botocore.invoke_with_legacy_context = True`` or by setting the environment
48
+ variable ``DD_BOTOCORE_INVOKE_WITH_LEGACY_CONTEXT=true``.
49
+
50
+
51
+ Default: ``False``
52
+
53
+
54
+ .. py:data:: ddtrace.config.botocore['operations'][<operation>].error_statuses = "<error statuses>"
55
+
56
+ Definition of which HTTP status codes to consider for making a span as an error span.
57
+
58
+ By default response status codes of ``'500-599'`` are considered as errors for all endpoints.
59
+
60
+ Example marking 404, and 5xx as errors for ``s3.headobject`` API calls::
61
+
62
+ from ddtrace import config
63
+
64
+ config.botocore['operations']['s3.headobject'].error_statuses = '404,500-599'
65
+
66
+
67
+ See :ref:`HTTP - Custom Error Codes<http-custom-error>` documentation for more examples.
68
+
69
+ .. py:data:: ddtrace.config.botocore['tag_no_params']
70
+
71
+ This opts out of the default behavior of collecting a narrow set of API parameters as span tags.
72
+
73
+ To not collect any API parameters, ``ddtrace.config.botocore.tag_no_params = True`` or by setting the environment
74
+ variable ``DD_AWS_TAG_NO_PARAMS=true``.
75
+
76
+
77
+ Default: ``False``
78
+
79
+
80
+ .. py:data:: ddtrace.config.botocore['instrument_internals']
81
+
82
+ This opts into collecting spans for some internal functions, including ``parsers.ResponseParser.parse``.
83
+
84
+ Can also be enabled with the ``DD_BOTOCORE_INSTRUMENT_INTERNALS`` environment variable.
85
+
86
+ Default: ``False``
87
+
88
+
89
+ .. py:data:: ddtrace.config.botocore['span_prompt_completion_sample_rate']
90
+
91
+ Configure the sample rate for the collection of bedrock prompts and completions as span tags.
92
+
93
+ Alternatively, you can set this option with the ``DD_BEDROCK_SPAN_PROMPT_COMPLETION_SAMPLE_RATE`` environment
94
+ variable.
95
+
96
+ Default: ``1.0``
97
+
98
+
99
+ .. py:data:: (beta) ddtrace.config.botocore["span_char_limit"]
100
+
101
+ Configure the maximum number of characters for bedrock span tags for prompt/response text.
102
+
103
+ Text exceeding the maximum number of characters is truncated to the character limit
104
+ and has ``...`` appended to the end.
105
+
106
+ Alternatively, you can set this option with the ``DD_BEDROCK_SPAN_CHAR_LIMIT`` environment
107
+ variable.
108
+
109
+ Default: ``128``
110
+
111
+
112
+ .. py:data:: ddtrace.config.botocore['dynamodb_primary_key_names_for_tables']
113
+
114
+ This enables DynamoDB API calls to be instrumented with span pointers. Many
115
+ DynamoDB API calls do not include the Item's Primary Key fields as separate
116
+ values, so they need to be provided to the tracer separately. This field
117
+ should be structured as a ``dict`` keyed by the table names as ``str``.
118
+ Each value should be the ``set`` of primary key field names (as ``str``)
119
+ for the associated table. The set may have exactly one or two elements,
120
+ depending on the Table's Primary Key schema.
121
+
122
+ In python this would look like::
123
+
124
+ ddtrace.config.botocore['dynamodb_primary_key_names_for_tables'] = {
125
+ 'table_name': {'key1', 'key2'},
126
+ 'other_table': {'other_key'},
127
+ }
128
+
129
+ Can also be enabled with the ``DD_BOTOCORE_DYNAMODB_TABLE_PRIMARY_KEYS``
130
+ environment variable which is parsed as a JSON object with strings for keys
131
+ and lists of strings for values.
132
+
133
+ This would look something like::
134
+
135
+ export DD_BOTOCORE_DYNAMODB_TABLE_PRIMARY_KEYS='{
136
+ "table_name": ["key1", "key2"],
137
+ "other_table": ["other_key"]
138
+ }'
139
+
140
+ Default: ``{}``
141
+
142
+
143
+ .. py:data:: ddtrace.config.botocore['add_span_pointers']
144
+
145
+ This enables the addition of span pointers to spans associated with
146
+ successful AWS API calls.
147
+
148
+ Alternatively, you can set this option with the
149
+ ``DD_BOTOCORE_ADD_SPAN_POINTERS`` environment variable.
150
+
151
+ Default: ``True``
152
+
153
+ """
@@ -48,12 +48,9 @@ class TracedBotocoreStreamingBody(wrapt.ObjectProxy):
48
48
  self._body.append(json.loads(body))
49
49
  if self.__wrapped__.tell() == int(self.__wrapped__._content_length):
50
50
  formatted_response = _extract_text_and_response_reason(self._execution_ctx, self._body[0])
51
- model_provider = self._execution_ctx["model_provider"]
52
- model_name = self._execution_ctx["model_name"]
53
- should_set_choice_ids = model_provider == _COHERE and "embed" not in model_name
54
51
  core.dispatch(
55
52
  "botocore.bedrock.process_response",
56
- [self._execution_ctx, formatted_response, None, self._body[0], should_set_choice_ids],
53
+ [self._execution_ctx, formatted_response],
57
54
  )
58
55
  return body
59
56
  except Exception:
@@ -67,12 +64,9 @@ class TracedBotocoreStreamingBody(wrapt.ObjectProxy):
67
64
  for line in lines:
68
65
  self._body.append(json.loads(line))
69
66
  formatted_response = _extract_text_and_response_reason(self._execution_ctx, self._body[0])
70
- model_provider = self._execution_ctx["model_provider"]
71
- model_name = self._execution_ctx["model_name"]
72
- should_set_choice_ids = model_provider == _COHERE and "embed" not in model_name
73
67
  core.dispatch(
74
68
  "botocore.bedrock.process_response",
75
- [self._execution_ctx, formatted_response, None, self._body[0], should_set_choice_ids],
69
+ [self._execution_ctx, formatted_response],
76
70
  )
77
71
  return lines
78
72
  except Exception:
@@ -93,16 +87,10 @@ class TracedBotocoreStreamingBody(wrapt.ObjectProxy):
93
87
  finally:
94
88
  if exception_raised:
95
89
  return
96
- metadata = _extract_streamed_response_metadata(self._execution_ctx, self._body)
97
90
  formatted_response = _extract_streamed_response(self._execution_ctx, self._body)
98
- model_provider = self._execution_ctx["model_provider"]
99
- model_name = self._execution_ctx["model_name"]
100
- should_set_choice_ids = (
101
- model_provider == _COHERE and "is_finished" not in self._body[0] and "embed" not in model_name
102
- )
103
91
  core.dispatch(
104
92
  "botocore.bedrock.process_response",
105
- [self._execution_ctx, formatted_response, metadata, self._body, should_set_choice_ids],
93
+ [self._execution_ctx, formatted_response],
106
94
  )
107
95
 
108
96
 
@@ -443,18 +431,6 @@ def handle_bedrock_response(
443
431
  safe_token_count(cache_write_tokens),
444
432
  )
445
433
 
446
- # for both converse & invoke, dispatch success event to store basic metrics
447
- core.dispatch(
448
- "botocore.patched_bedrock_api_call.success",
449
- [
450
- ctx,
451
- str(metadata.get("RequestId", "")),
452
- request_latency,
453
- str(input_tokens),
454
- str(output_tokens),
455
- ],
456
- )
457
-
458
434
  if ctx["resource"] == "Converse":
459
435
  core.dispatch("botocore.bedrock.process_response_converse", [ctx, result])
460
436
  return result
@@ -49,6 +49,7 @@ from ddtrace.internal.utils.formats import asbool
49
49
  from ddtrace.internal.utils.importlib import func_name
50
50
  from ddtrace.propagation._database_monitoring import _DBM_Propagator
51
51
  from ddtrace.settings.asm import config as asm_config
52
+ from ddtrace.settings.asm import endpoint_collection
52
53
  from ddtrace.settings.integration import IntegrationConfig
53
54
  from ddtrace.trace import Pin
54
55
  from ddtrace.vendor.packaging.version import parse as parse_version
@@ -81,6 +82,7 @@ config._add(
81
82
  use_legacy_resource_format=asbool(os.getenv("DD_DJANGO_USE_LEGACY_RESOURCE_FORMAT", default=False)),
82
83
  _trace_asgi_websocket=os.getenv("DD_ASGI_TRACE_WEBSOCKET", default=False),
83
84
  obfuscate_404_resource=os.getenv("DD_ASGI_OBFUSCATE_404_RESOURCE", default=False),
85
+ views={},
84
86
  ),
85
87
  )
86
88
 
@@ -598,7 +600,7 @@ def traced_template_render(django, pin, wrapped, instance, args, kwargs):
598
600
  return wrapped(*args, **kwargs)
599
601
 
600
602
 
601
- def instrument_view(django, view):
603
+ def instrument_view(django, view, path=None):
602
604
  """
603
605
  Helper to wrap Django views.
604
606
 
@@ -608,10 +610,24 @@ def instrument_view(django, view):
608
610
  for cls in reversed(getmro(view)):
609
611
  _instrument_view(django, cls)
610
612
 
611
- return _instrument_view(django, view)
613
+ return _instrument_view(django, view, path=path)
612
614
 
613
615
 
614
- def _instrument_view(django, view):
616
+ def extract_request_method_list(view):
617
+ try:
618
+ while "view_func" in view.__code__.co_freevars:
619
+ view = view.__closure__[view.__code__.co_freevars.index("view_func")].cell_contents
620
+ if "request_method_list" in view.__code__.co_freevars:
621
+ return view.__closure__[view.__code__.co_freevars.index("request_method_list")].cell_contents
622
+ return []
623
+ except Exception:
624
+ return []
625
+
626
+
627
+ _DEFAULT_METHODS = ("get", "delete", "post", "options", "head")
628
+
629
+
630
+ def _instrument_view(django, view, path=None):
615
631
  """Helper to wrap Django views."""
616
632
  from . import utils
617
633
 
@@ -620,9 +636,14 @@ def _instrument_view(django, view):
620
636
  return view
621
637
 
622
638
  # Patch view HTTP methods and lifecycle methods
623
- http_method_names = getattr(view, "http_method_names", ("get", "delete", "post", "options", "head"))
639
+
640
+ http_method_names = getattr(view, "http_method_names", ())
641
+ request_method_list = extract_request_method_list(view) or http_method_names
642
+ if path is not None:
643
+ for method in request_method_list or ["*"]:
644
+ endpoint_collection.add_endpoint(method, path, operation_name="django.request")
624
645
  lifecycle_methods = ("setup", "dispatch", "http_method_not_allowed")
625
- for name in list(http_method_names) + list(lifecycle_methods):
646
+ for name in list(request_method_list or _DEFAULT_METHODS) + list(lifecycle_methods):
626
647
  try:
627
648
  func = getattr(view, name, None)
628
649
  if not func or isinstance(func, wrapt.ObjectProxy):
@@ -665,18 +686,20 @@ def traced_urls_path(django, pin, wrapped, instance, args, kwargs):
665
686
  try:
666
687
  from_args = False
667
688
  view = kwargs.pop("view", None)
689
+ path = kwargs.pop("path", None)
668
690
  if view is None:
669
691
  view = args[1]
670
692
  from_args = True
693
+ if path is None:
694
+ path = args[0]
671
695
 
672
696
  core.dispatch("service_entrypoint.patch", (unwrap(view),))
673
-
674
697
  if from_args:
675
698
  args = list(args)
676
- args[1] = instrument_view(django, view)
699
+ args[1] = instrument_view(django, view, path=path)
677
700
  args = tuple(args)
678
701
  else:
679
- kwargs["view"] = instrument_view(django, view)
702
+ kwargs["view"] = instrument_view(django, view, path=path)
680
703
  except Exception:
681
704
  log.debug("Failed to instrument Django url path %r %r", args, kwargs, exc_info=True)
682
705
  return wrapped(*args, **kwargs)
@@ -1,5 +1,5 @@
1
1
  """
2
- The freezegun integration reconfigures freezegun's default ignore list to ignore ddtrace.
2
+ The freezegun integration updates freezegun's default ignore list to ignore ddtrace.
3
3
 
4
4
  Enabling
5
5
  ~~~~~~~~
@@ -6,7 +6,7 @@ from typing import Optional
6
6
 
7
7
  import wrapt
8
8
 
9
- from ddtrace.llmobs._integrations.google_genai_utils import DEFAULT_MODEL_ROLE
9
+ from ddtrace.llmobs._integrations.google_utils import GOOGLE_GENAI_DEFAULT_MODEL_ROLE
10
10
  from ddtrace.llmobs._utils import _get_attr
11
11
 
12
12
 
@@ -32,7 +32,7 @@ def _join_chunks(chunks: List[Any]) -> Optional[Dict[str, Any]]:
32
32
  continue
33
33
 
34
34
  if role is None:
35
- role = _get_attr(content, "role", DEFAULT_MODEL_ROLE)
35
+ role = _get_attr(content, "role", GOOGLE_GENAI_DEFAULT_MODEL_ROLE)
36
36
 
37
37
  parts = _get_attr(content, "parts", [])
38
38
  for part in parts:
@@ -9,7 +9,7 @@ from ddtrace.contrib.internal.trace_utils import unwrap
9
9
  from ddtrace.contrib.internal.trace_utils import with_traced_module
10
10
  from ddtrace.contrib.internal.trace_utils import wrap
11
11
  from ddtrace.llmobs._integrations import GoogleGenAIIntegration
12
- from ddtrace.llmobs._integrations.google_genai_utils import extract_provider_and_model_name
12
+ from ddtrace.llmobs._integrations.google_utils import extract_provider_and_model_name
13
13
  from ddtrace.trace import Pin
14
14
 
15
15
 
@@ -27,7 +27,7 @@ def get_version() -> str:
27
27
  @with_traced_module
28
28
  def traced_generate(genai, pin, func, instance, args, kwargs):
29
29
  integration = genai._datadog_integration
30
- provider_name, model_name = extract_provider_and_model_name(kwargs)
30
+ provider_name, model_name = extract_provider_and_model_name(kwargs=kwargs)
31
31
  with integration.trace(
32
32
  pin,
33
33
  "%s.%s" % (instance.__class__.__name__, func.__name__),
@@ -46,7 +46,7 @@ def traced_generate(genai, pin, func, instance, args, kwargs):
46
46
  @with_traced_module
47
47
  async def traced_async_generate(genai, pin, func, instance, args, kwargs):
48
48
  integration = genai._datadog_integration
49
- provider_name, model_name = extract_provider_and_model_name(kwargs)
49
+ provider_name, model_name = extract_provider_and_model_name(kwargs=kwargs)
50
50
  with integration.trace(
51
51
  pin,
52
52
  "%s.%s" % (instance.__class__.__name__, func.__name__),
@@ -65,7 +65,7 @@ async def traced_async_generate(genai, pin, func, instance, args, kwargs):
65
65
  @with_traced_module
66
66
  def traced_generate_stream(genai, pin, func, instance, args, kwargs):
67
67
  integration = genai._datadog_integration
68
- provider_name, model_name = extract_provider_and_model_name(kwargs)
68
+ provider_name, model_name = extract_provider_and_model_name(kwargs=kwargs)
69
69
  span = integration.trace(
70
70
  pin,
71
71
  "%s.%s" % (instance.__class__.__name__, func.__name__),
@@ -86,7 +86,7 @@ def traced_generate_stream(genai, pin, func, instance, args, kwargs):
86
86
  @with_traced_module
87
87
  async def traced_async_generate_stream(genai, pin, func, instance, args, kwargs):
88
88
  integration = genai._datadog_integration
89
- provider_name, model_name = extract_provider_and_model_name(kwargs)
89
+ provider_name, model_name = extract_provider_and_model_name(kwargs=kwargs)
90
90
  span = integration.trace(
91
91
  pin,
92
92
  "%s.%s" % (instance.__class__.__name__, func.__name__),
@@ -107,7 +107,7 @@ async def traced_async_generate_stream(genai, pin, func, instance, args, kwargs)
107
107
  @with_traced_module
108
108
  def traced_embed_content(genai, pin, func, instance, args, kwargs):
109
109
  integration = genai._datadog_integration
110
- provider_name, model_name = extract_provider_and_model_name(kwargs)
110
+ provider_name, model_name = extract_provider_and_model_name(kwargs=kwargs)
111
111
  with integration.trace(
112
112
  pin,
113
113
  "%s.%s" % (instance.__class__.__name__, func.__name__),
@@ -126,7 +126,7 @@ def traced_embed_content(genai, pin, func, instance, args, kwargs):
126
126
  @with_traced_module
127
127
  async def traced_async_embed_content(genai, pin, func, instance, args, kwargs):
128
128
  integration = genai._datadog_integration
129
- provider_name, model_name = extract_provider_and_model_name(kwargs)
129
+ provider_name, model_name = extract_provider_and_model_name(kwargs=kwargs)
130
130
  with integration.trace(
131
131
  pin,
132
132
  "%s.%s" % (instance.__class__.__name__, func.__name__),
@@ -11,7 +11,7 @@ from ddtrace.contrib.internal.trace_utils import unwrap
11
11
  from ddtrace.contrib.internal.trace_utils import with_traced_module
12
12
  from ddtrace.contrib.internal.trace_utils import wrap
13
13
  from ddtrace.llmobs._integrations import GeminiIntegration
14
- from ddtrace.llmobs._integrations.utils import extract_model_name_google
14
+ from ddtrace.llmobs._integrations.google_utils import extract_provider_and_model_name
15
15
  from ddtrace.trace import Pin
16
16
 
17
17
 
@@ -40,11 +40,12 @@ def traced_generate(genai, pin, func, instance, args, kwargs):
40
40
  integration = genai._datadog_integration
41
41
  stream = kwargs.get("stream", False)
42
42
  generations = None
43
+ provider_name, model_name = extract_provider_and_model_name(instance=instance, model_name_attr="model_name")
43
44
  span = integration.trace(
44
45
  pin,
45
46
  "%s.%s" % (instance.__class__.__name__, func.__name__),
46
- provider="google",
47
- model=extract_model_name_google(instance, "model_name"),
47
+ provider=provider_name,
48
+ model=model_name,
48
49
  submit_to_llmobs=True,
49
50
  )
50
51
  try:
@@ -68,11 +69,12 @@ async def traced_agenerate(genai, pin, func, instance, args, kwargs):
68
69
  integration = genai._datadog_integration
69
70
  stream = kwargs.get("stream", False)
70
71
  generations = None
72
+ provider_name, model_name = extract_provider_and_model_name(instance=instance, model_name_attr="model_name")
71
73
  span = integration.trace(
72
74
  pin,
73
75
  "%s.%s" % (instance.__class__.__name__, func.__name__),
74
- provider="google",
75
- model=extract_model_name_google(instance, "model_name"),
76
+ provider=provider_name,
77
+ model=model_name,
76
78
  submit_to_llmobs=True,
77
79
  )
78
80
  try: