ddtrace 3.11.0rc1__cp312-cp312-win_amd64.whl → 3.11.0rc3__cp312-cp312-win_amd64.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.

Potentially problematic release.


This version of ddtrace might be problematic. Click here for more details.

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-win_amd64.pyd +0 -0
  42. ddtrace/internal/_encoding.pyi +1 -1
  43. ddtrace/internal/_rand.cp312-win_amd64.pyd +0 -0
  44. ddtrace/internal/_tagset.cp312-win_amd64.pyd +0 -0
  45. ddtrace/internal/_threads.cp312-win_amd64.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-win_amd64.pyd +0 -0
  52. ddtrace/internal/datadog/profiling/ddup/_ddup.cp312-win_amd64.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-win_amd64.pyd +0 -0
  57. ddtrace/internal/schema/processor.py +6 -2
  58. ddtrace/internal/telemetry/metrics_namespaces.cp312-win_amd64.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-win_amd64.pyd +0 -0
  79. ddtrace/profiling/collector/_memalloc.cp312-win_amd64.pyd +0 -0
  80. ddtrace/profiling/collector/_task.cp312-win_amd64.pyd +0 -0
  81. ddtrace/profiling/collector/_traceback.cp312-win_amd64.pyd +0 -0
  82. ddtrace/profiling/collector/stack.cp312-win_amd64.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-win_amd64.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
@@ -3,10 +3,8 @@ import sys
3
3
  from typing import Any
4
4
  from typing import Dict
5
5
  from typing import Optional
6
- from typing import Union
7
6
 
8
7
  import langchain
9
- from pydantic import SecretStr
10
8
 
11
9
 
12
10
  try:
@@ -38,11 +36,9 @@ except ImportError:
38
36
  import wrapt
39
37
 
40
38
  from ddtrace import config
41
- from ddtrace.contrib.internal.langchain.constants import API_KEY
42
39
  from ddtrace.contrib.internal.langchain.constants import text_embedding_models
43
40
  from ddtrace.contrib.internal.langchain.constants import vectorstore_classes
44
41
  from ddtrace.contrib.internal.langchain.utils import shared_stream
45
- from ddtrace.contrib.internal.langchain.utils import tag_general_message_input
46
42
  from ddtrace.contrib.internal.trace_utils import unwrap
47
43
  from ddtrace.contrib.internal.trace_utils import with_traced_module
48
44
  from ddtrace.contrib.internal.trace_utils import wrap
@@ -69,7 +65,6 @@ def get_version():
69
65
  config._add(
70
66
  "langchain",
71
67
  {
72
- "span_prompt_completion_sample_rate": float(os.getenv("DD_LANGCHAIN_SPAN_PROMPT_COMPLETION_SAMPLE_RATE", 1.0)),
73
68
  "span_char_limit": int(os.getenv("DD_LANGCHAIN_SPAN_CHAR_LIMIT", 128)),
74
69
  },
75
70
  )
@@ -87,91 +82,12 @@ def _extract_model_name(instance: Any) -> Optional[str]:
87
82
  return None
88
83
 
89
84
 
90
- def _format_api_key(api_key: Union[str, SecretStr]) -> str:
91
- """Obfuscate a given LLM provider API key by returning the last four characters."""
92
- if hasattr(api_key, "get_secret_value"):
93
- api_key = api_key.get_secret_value()
94
-
95
- if not api_key or len(api_key) < 4:
96
- return ""
97
- return "...%s" % api_key[-4:]
98
-
99
-
100
- def _extract_api_key(instance: Any) -> str:
101
- """
102
- Extract and format LLM-provider API key from instance.
103
- Note that langchain's LLM/ChatModel/Embeddings interfaces do not have a
104
- standard attribute name for storing the provider-specific API key, so make a
105
- best effort here by checking for attributes that end with `api_key/api_token`.
106
- """
107
- api_key_attrs = [a for a in dir(instance) if a.endswith(("api_token", "api_key"))]
108
- if api_key_attrs and hasattr(instance, str(api_key_attrs[0])):
109
- api_key = getattr(instance, api_key_attrs[0], None)
110
- if api_key:
111
- return _format_api_key(api_key)
112
- return ""
113
-
114
-
115
- def _tag_openai_token_usage(span: Span, llm_output: Dict[str, Any]) -> None:
116
- """
117
- Extract token usage from llm_output, tag on span.
118
- Calculate the total cost for each LLM/chat_model, then propagate those values up the trace so that
119
- the root span will store the total token_usage/cost of all of its descendants.
120
- """
121
- for token_type in ("prompt", "completion", "total"):
122
- current_metric_value = span.get_metric("langchain.tokens.%s_tokens" % token_type) or 0
123
- metric_value = llm_output["token_usage"].get("%s_tokens" % token_type, 0)
124
- span.set_metric("langchain.tokens.%s_tokens" % token_type, current_metric_value + metric_value)
125
-
126
-
127
- def _is_openai_llm_instance(instance):
128
- """Safely check if a traced instance is an OpenAI LLM.
129
- langchain_community does not automatically import submodules which may result in AttributeErrors.
130
- """
131
- try:
132
- if langchain_openai:
133
- return isinstance(instance, langchain_openai.OpenAI)
134
- if langchain_community:
135
- return isinstance(instance, langchain_community.llms.OpenAI)
136
- return False
137
- except (AttributeError, ModuleNotFoundError, ImportError):
138
- return False
139
-
140
-
141
- def _is_openai_chat_instance(instance):
142
- """Safely check if a traced instance is an OpenAI Chat Model.
143
- langchain_community does not automatically import submodules which may result in AttributeErrors.
144
- """
145
- try:
146
- if langchain_openai:
147
- return isinstance(instance, langchain_openai.ChatOpenAI)
148
- if langchain_community:
149
- return isinstance(instance, langchain_community.chat_models.ChatOpenAI)
150
- return False
151
- except (AttributeError, ModuleNotFoundError, ImportError):
152
- return False
153
-
154
-
155
- def _is_pinecone_vectorstore_instance(instance):
156
- """Safely check if a traced instance is a Pinecone VectorStore.
157
- langchain_community does not automatically import submodules which may result in AttributeErrors.
158
- """
159
- try:
160
- if langchain_pinecone:
161
- return isinstance(instance, langchain_pinecone.PineconeVectorStore)
162
- if langchain_community:
163
- return isinstance(instance, langchain_community.vectorstores.Pinecone)
164
- return False
165
- except (AttributeError, ModuleNotFoundError, ImportError):
166
- return False
167
-
168
-
169
85
  @with_traced_module
170
86
  def traced_llm_generate(langchain, pin, func, instance, args, kwargs):
171
87
  llm_provider = instance._llm_type
172
- prompts = get_argument_value(args, kwargs, 0, "prompts")
173
88
  integration = langchain._datadog_integration
174
89
  model = _extract_model_name(instance)
90
+ prompts = get_argument_value(args, kwargs, 0, "prompts")
175
91
  span = integration.trace(
176
92
  pin,
177
93
  "%s.%s" % (instance.__module__, instance.__class__.__name__),
@@ -179,7 +95,6 @@ def traced_llm_generate(langchain, pin, func, instance, args, kwargs):
179
95
  interface_type="llm",
180
96
  provider=llm_provider,
181
97
  model=model,
182
- api_key=_extract_api_key(instance),
183
98
  instance=instance,
184
99
  )
185
100
  completions = None
@@ -187,39 +102,13 @@ def traced_llm_generate(langchain, pin, func, instance, args, kwargs):
187
102
  integration.record_instance(instance, span)
188
103
 
189
104
  try:
190
- if integration.is_pc_sampled_span(span):
191
- for idx, prompt in enumerate(prompts):
192
- span.set_tag_str("langchain.request.prompts.%d" % idx, integration.trunc(str(prompt)))
193
- for param, val in getattr(instance, "_identifying_params", {}).items():
194
- if isinstance(val, dict):
195
- for k, v in val.items():
196
- span.set_tag_str("langchain.request.%s.parameters.%s.%s" % (llm_provider, param, k), str(v))
197
- else:
198
- span.set_tag_str("langchain.request.%s.parameters.%s" % (llm_provider, param), str(val))
199
-
200
105
  completions = func(*args, **kwargs)
201
-
202
106
  core.dispatch("langchain.llm.generate.after", (prompts, completions))
203
-
204
- if _is_openai_llm_instance(instance):
205
- _tag_openai_token_usage(span, completions.llm_output)
206
-
207
- for idx, completion in enumerate(completions.generations):
208
- if integration.is_pc_sampled_span(span):
209
- span.set_tag_str("langchain.response.completions.%d.text" % idx, integration.trunc(completion[0].text))
210
- if completion and completion[0].generation_info is not None:
211
- span.set_tag_str(
212
- "langchain.response.completions.%d.finish_reason" % idx,
213
- str(completion[0].generation_info.get("finish_reason")),
214
- )
215
- span.set_tag_str(
216
- "langchain.response.completions.%d.logprobs" % idx,
217
- str(completion[0].generation_info.get("logprobs")),
218
- )
219
107
  except Exception:
220
108
  span.set_exc_info(*sys.exc_info())
221
109
  raise
222
110
  finally:
111
+ kwargs["_dd.identifying_params"] = instance._identifying_params
223
112
  integration.llmobs_set_tags(span, args=args, kwargs=kwargs, response=completions, operation="llm")
224
113
  span.finish()
225
114
  return completions
@@ -238,7 +127,6 @@ async def traced_llm_agenerate(langchain, pin, func, instance, args, kwargs):
238
127
  interface_type="llm",
239
128
  provider=llm_provider,
240
129
  model=model,
241
- api_key=_extract_api_key(instance),
242
130
  instance=instance,
243
131
  )
244
132
 
@@ -246,39 +134,13 @@ async def traced_llm_agenerate(langchain, pin, func, instance, args, kwargs):
246
134
 
247
135
  completions = None
248
136
  try:
249
- if integration.is_pc_sampled_span(span):
250
- for idx, prompt in enumerate(prompts):
251
- span.set_tag_str("langchain.request.prompts.%d" % idx, integration.trunc(str(prompt)))
252
- for param, val in getattr(instance, "_identifying_params", {}).items():
253
- if isinstance(val, dict):
254
- for k, v in val.items():
255
- span.set_tag_str("langchain.request.%s.parameters.%s.%s" % (llm_provider, param, k), str(v))
256
- else:
257
- span.set_tag_str("langchain.request.%s.parameters.%s" % (llm_provider, param), str(val))
258
-
259
137
  completions = await func(*args, **kwargs)
260
-
261
138
  core.dispatch("langchain.llm.agenerate.after", (prompts, completions))
262
-
263
- if _is_openai_llm_instance(instance):
264
- _tag_openai_token_usage(span, completions.llm_output)
265
-
266
- for idx, completion in enumerate(completions.generations):
267
- if integration.is_pc_sampled_span(span):
268
- span.set_tag_str("langchain.response.completions.%d.text" % idx, integration.trunc(completion[0].text))
269
- if completion and completion[0].generation_info is not None:
270
- span.set_tag_str(
271
- "langchain.response.completions.%d.finish_reason" % idx,
272
- str(completion[0].generation_info.get("finish_reason")),
273
- )
274
- span.set_tag_str(
275
- "langchain.response.completions.%d.logprobs" % idx,
276
- str(completion[0].generation_info.get("logprobs")),
277
- )
278
139
  except Exception:
279
140
  span.set_exc_info(*sys.exc_info())
280
141
  raise
281
142
  finally:
143
+ kwargs["_dd.identifying_params"] = instance._identifying_params
282
144
  integration.llmobs_set_tags(span, args=args, kwargs=kwargs, response=completions, operation="llm")
283
145
  span.finish()
284
146
  return completions
@@ -296,7 +158,6 @@ def traced_chat_model_generate(langchain, pin, func, instance, args, kwargs):
296
158
  interface_type="chat_model",
297
159
  provider=llm_provider,
298
160
  model=_extract_model_name(instance),
299
- api_key=_extract_api_key(instance),
300
161
  instance=instance,
301
162
  )
302
163
 
@@ -304,78 +165,13 @@ def traced_chat_model_generate(langchain, pin, func, instance, args, kwargs):
304
165
 
305
166
  chat_completions = None
306
167
  try:
307
- for message_set_idx, message_set in enumerate(chat_messages):
308
- for message_idx, message in enumerate(message_set):
309
- if integration.is_pc_sampled_span(span):
310
- if isinstance(message, dict):
311
- span.set_tag_str(
312
- "langchain.request.messages.%d.%d.content" % (message_set_idx, message_idx),
313
- integration.trunc(str(message.get("content", ""))),
314
- )
315
- else:
316
- span.set_tag_str(
317
- "langchain.request.messages.%d.%d.content" % (message_set_idx, message_idx),
318
- integration.trunc(str(getattr(message, "content", ""))),
319
- )
320
- span.set_tag_str(
321
- "langchain.request.messages.%d.%d.message_type" % (message_set_idx, message_idx),
322
- message.__class__.__name__,
323
- )
324
- for param, val in getattr(instance, "_identifying_params", {}).items():
325
- if isinstance(val, dict):
326
- for k, v in val.items():
327
- span.set_tag_str("langchain.request.%s.parameters.%s.%s" % (llm_provider, param, k), str(v))
328
- else:
329
- span.set_tag_str("langchain.request.%s.parameters.%s" % (llm_provider, param), str(val))
330
-
331
168
  chat_completions = func(*args, **kwargs)
332
-
333
169
  core.dispatch("langchain.chatmodel.generate.after", (chat_messages, chat_completions))
334
-
335
- if _is_openai_chat_instance(instance):
336
- _tag_openai_token_usage(span, chat_completions.llm_output)
337
-
338
- for message_set_idx, message_set in enumerate(chat_completions.generations):
339
- for idx, chat_completion in enumerate(message_set):
340
- if integration.is_pc_sampled_span(span):
341
- text = chat_completion.text
342
- message = chat_completion.message
343
- # tool calls aren't available on this property for legacy chains
344
- tool_calls = getattr(message, "tool_calls", None)
345
-
346
- if text:
347
- span.set_tag_str(
348
- "langchain.response.completions.%d.%d.content" % (message_set_idx, idx),
349
- integration.trunc(chat_completion.text),
350
- )
351
- if tool_calls:
352
- if not isinstance(tool_calls, list):
353
- tool_calls = [tool_calls]
354
- for tool_call_idx, tool_call in enumerate(tool_calls):
355
- span.set_tag_str(
356
- "langchain.response.completions.%d.%d.tool_calls.%d.id"
357
- % (message_set_idx, idx, tool_call_idx),
358
- str(tool_call.get("id", "")),
359
- )
360
- span.set_tag_str(
361
- "langchain.response.completions.%d.%d.tool_calls.%d.name"
362
- % (message_set_idx, idx, tool_call_idx),
363
- str(tool_call.get("name", "")),
364
- )
365
- for arg_name, arg_value in tool_call.get("args", {}).items():
366
- span.set_tag_str(
367
- "langchain.response.completions.%d.%d.tool_calls.%d.args.%s"
368
- % (message_set_idx, idx, tool_call_idx, arg_name),
369
- integration.trunc(str(arg_value)),
370
- )
371
- span.set_tag_str(
372
- "langchain.response.completions.%d.%d.message_type" % (message_set_idx, idx),
373
- chat_completion.message.__class__.__name__,
374
- )
375
170
  except Exception:
376
171
  span.set_exc_info(*sys.exc_info())
377
172
  raise
378
173
  finally:
174
+ kwargs["_dd.identifying_params"] = instance._identifying_params
379
175
  integration.llmobs_set_tags(span, args=args, kwargs=kwargs, response=chat_completions, operation="chat")
380
176
  span.finish()
381
177
  return chat_completions
@@ -393,7 +189,6 @@ async def traced_chat_model_agenerate(langchain, pin, func, instance, args, kwar
393
189
  interface_type="chat_model",
394
190
  provider=llm_provider,
395
191
  model=_extract_model_name(instance),
396
- api_key=_extract_api_key(instance),
397
192
  instance=instance,
398
193
  )
399
194
 
@@ -401,77 +196,13 @@ async def traced_chat_model_agenerate(langchain, pin, func, instance, args, kwar
401
196
 
402
197
  chat_completions = None
403
198
  try:
404
- for message_set_idx, message_set in enumerate(chat_messages):
405
- for message_idx, message in enumerate(message_set):
406
- if integration.is_pc_sampled_span(span):
407
- if isinstance(message, dict):
408
- span.set_tag_str(
409
- "langchain.request.messages.%d.%d.content" % (message_set_idx, message_idx),
410
- integration.trunc(str(message.get("content", ""))),
411
- )
412
- else:
413
- span.set_tag_str(
414
- "langchain.request.messages.%d.%d.content" % (message_set_idx, message_idx),
415
- integration.trunc(str(getattr(message, "content", ""))),
416
- )
417
- span.set_tag_str(
418
- "langchain.request.messages.%d.%d.message_type" % (message_set_idx, message_idx),
419
- message.__class__.__name__,
420
- )
421
- for param, val in getattr(instance, "_identifying_params", {}).items():
422
- if isinstance(val, dict):
423
- for k, v in val.items():
424
- span.set_tag_str("langchain.request.%s.parameters.%s.%s" % (llm_provider, param, k), str(v))
425
- else:
426
- span.set_tag_str("langchain.request.%s.parameters.%s" % (llm_provider, param), str(val))
427
-
428
199
  chat_completions = await func(*args, **kwargs)
429
-
430
200
  core.dispatch("langchain.chatmodel.agenerate.after", (chat_messages, chat_completions))
431
-
432
- if _is_openai_chat_instance(instance):
433
- _tag_openai_token_usage(span, chat_completions.llm_output)
434
-
435
- for message_set_idx, message_set in enumerate(chat_completions.generations):
436
- for idx, chat_completion in enumerate(message_set):
437
- if integration.is_pc_sampled_span(span):
438
- text = chat_completion.text
439
- message = chat_completion.message
440
- tool_calls = getattr(message, "tool_calls", None)
441
-
442
- if text:
443
- span.set_tag_str(
444
- "langchain.response.completions.%d.%d.content" % (message_set_idx, idx),
445
- integration.trunc(chat_completion.text),
446
- )
447
- if tool_calls:
448
- if not isinstance(tool_calls, list):
449
- tool_calls = [tool_calls]
450
- for tool_call_idx, tool_call in enumerate(tool_calls):
451
- span.set_tag_str(
452
- "langchain.response.completions.%d.%d.tool_calls.%d.id"
453
- % (message_set_idx, idx, tool_call_idx),
454
- str(tool_call.get("id", "")),
455
- )
456
- span.set_tag_str(
457
- "langchain.response.completions.%d.%d.tool_calls.%d.name"
458
- % (message_set_idx, idx, tool_call_idx),
459
- str(tool_call.get("name", "")),
460
- )
461
- for arg_name, arg_value in tool_call.get("args", {}).items():
462
- span.set_tag_str(
463
- "langchain.response.completions.%d.%d.tool_calls.%d.args.%s"
464
- % (message_set_idx, idx, tool_call_idx, arg_name),
465
- integration.trunc(str(arg_value)),
466
- )
467
- span.set_tag_str(
468
- "langchain.response.completions.%d.%d.message_type" % (message_set_idx, idx),
469
- chat_completion.message.__class__.__name__,
470
- )
471
201
  except Exception:
472
202
  span.set_exc_info(*sys.exc_info())
473
203
  raise
474
204
  finally:
205
+ kwargs["_dd.identifying_params"] = instance._identifying_params
475
206
  integration.llmobs_set_tags(span, args=args, kwargs=kwargs, response=chat_completions, operation="chat")
476
207
  span.finish()
477
208
  return chat_completions
@@ -483,11 +214,6 @@ def traced_embedding(langchain, pin, func, instance, args, kwargs):
483
214
  This traces both embed_query(text) and embed_documents(texts), so we need to make sure
484
215
  we get the right arg/kwarg.
485
216
  """
486
- try:
487
- input_texts = get_argument_value(args, kwargs, 0, "texts")
488
- except ArgumentError:
489
- input_texts = get_argument_value(args, kwargs, 0, "text")
490
-
491
217
  provider = instance.__class__.__name__.split("Embeddings")[0].lower()
492
218
  integration = langchain._datadog_integration
493
219
  span = integration.trace(
@@ -497,7 +223,6 @@ def traced_embedding(langchain, pin, func, instance, args, kwargs):
497
223
  interface_type="embedding",
498
224
  provider=provider,
499
225
  model=_extract_model_name(instance),
500
- api_key=_extract_api_key(instance),
501
226
  instance=instance,
502
227
  )
503
228
 
@@ -505,23 +230,7 @@ def traced_embedding(langchain, pin, func, instance, args, kwargs):
505
230
 
506
231
  embeddings = None
507
232
  try:
508
- if isinstance(input_texts, str):
509
- if integration.is_pc_sampled_span(span):
510
- span.set_tag_str("langchain.request.inputs.0.text", integration.trunc(input_texts))
511
- span.set_metric("langchain.request.input_count", 1)
512
- else:
513
- if integration.is_pc_sampled_span(span):
514
- for idx, text in enumerate(input_texts):
515
- span.set_tag_str("langchain.request.inputs.%d.text" % idx, integration.trunc(text))
516
- span.set_metric("langchain.request.input_count", len(input_texts))
517
- # langchain currently does not support token tracking for OpenAI embeddings:
518
- # https://github.com/hwchase17/langchain/issues/945
519
233
  embeddings = func(*args, **kwargs)
520
- if isinstance(embeddings, list) and embeddings and isinstance(embeddings[0], list):
521
- for idx, embedding in enumerate(embeddings):
522
- span.set_metric("langchain.response.outputs.%d.embedding_length" % idx, len(embedding))
523
- else:
524
- span.set_metric("langchain.response.outputs.embedding_length", len(embeddings))
525
234
  except Exception:
526
235
  span.set_exc_info(*sys.exc_info())
527
236
  raise
@@ -563,22 +272,9 @@ def traced_lcel_runnable_sequence(langchain, pin, func, instance, args, kwargs):
563
272
  inputs = get_argument_value(args, kwargs, 0, "input")
564
273
  except ArgumentError:
565
274
  inputs = get_argument_value(args, kwargs, 0, "inputs")
566
- if integration.is_pc_sampled_span(span):
567
- if not isinstance(inputs, list):
568
- inputs = [inputs]
569
- for idx, inp in enumerate(inputs):
570
- if not isinstance(inp, dict):
571
- span.set_tag_str("langchain.request.inputs.%d" % idx, integration.trunc(str(inp)))
572
- else:
573
- for k, v in inp.items():
574
- span.set_tag_str("langchain.request.inputs.%d.%s" % (idx, k), integration.trunc(str(v)))
275
+ if not isinstance(inputs, list):
276
+ inputs = [inputs]
575
277
  final_output = func(*args, **kwargs)
576
- if integration.is_pc_sampled_span(span):
577
- final_outputs = final_output # separate variable as to return correct value later
578
- if not isinstance(final_outputs, list):
579
- final_outputs = [final_outputs]
580
- for idx, output in enumerate(final_outputs):
581
- span.set_tag_str("langchain.response.outputs.%d" % idx, integration.trunc(str(output)))
582
278
  except Exception:
583
279
  span.set_exc_info(*sys.exc_info())
584
280
  raise
@@ -611,22 +307,9 @@ async def traced_lcel_runnable_sequence_async(langchain, pin, func, instance, ar
611
307
  inputs = get_argument_value(args, kwargs, 0, "input")
612
308
  except ArgumentError:
613
309
  inputs = get_argument_value(args, kwargs, 0, "inputs")
614
- if integration.is_pc_sampled_span(span):
615
- if not isinstance(inputs, list):
616
- inputs = [inputs]
617
- for idx, inp in enumerate(inputs):
618
- if not isinstance(inp, dict):
619
- span.set_tag_str("langchain.request.inputs.%d" % idx, integration.trunc(str(inp)))
620
- else:
621
- for k, v in inp.items():
622
- span.set_tag_str("langchain.request.inputs.%d.%s" % (idx, k), integration.trunc(str(v)))
310
+ if not isinstance(inputs, list):
311
+ inputs = [inputs]
623
312
  final_output = await func(*args, **kwargs)
624
- if integration.is_pc_sampled_span(span):
625
- final_outputs = final_output # separate variable as to return correct value later
626
- if not isinstance(final_outputs, list):
627
- final_outputs = [final_outputs]
628
- for idx, output in enumerate(final_outputs):
629
- span.set_tag_str("langchain.response.outputs.%d" % idx, integration.trunc(str(output)))
630
313
  except Exception:
631
314
  span.set_exc_info(*sys.exc_info())
632
315
  raise
@@ -639,8 +322,6 @@ async def traced_lcel_runnable_sequence_async(langchain, pin, func, instance, ar
639
322
  @with_traced_module
640
323
  def traced_similarity_search(langchain, pin, func, instance, args, kwargs):
641
324
  integration = langchain._datadog_integration
642
- query = get_argument_value(args, kwargs, 0, "query")
643
- k = kwargs.get("k", args[1] if len(args) >= 2 else None)
644
325
  provider = instance.__class__.__name__.lower()
645
326
  span = integration.trace(
646
327
  pin,
@@ -648,7 +329,6 @@ def traced_similarity_search(langchain, pin, func, instance, args, kwargs):
648
329
  submit_to_llmobs=True,
649
330
  interface_type="similarity_search",
650
331
  provider=provider,
651
- api_key=_extract_api_key(instance),
652
332
  instance=instance,
653
333
  )
654
334
 
@@ -656,37 +336,7 @@ def traced_similarity_search(langchain, pin, func, instance, args, kwargs):
656
336
 
657
337
  documents = []
658
338
  try:
659
- if integration.is_pc_sampled_span(span):
660
- span.set_tag_str("langchain.request.query", integration.trunc(query))
661
- if k is not None:
662
- span.set_tag_str("langchain.request.k", str(k))
663
- for kwarg_key, v in kwargs.items():
664
- span.set_tag_str("langchain.request.%s" % kwarg_key, str(v))
665
- if _is_pinecone_vectorstore_instance(instance) and hasattr(instance._index, "configuration"):
666
- span.set_tag_str(
667
- "langchain.request.pinecone.environment",
668
- instance._index.configuration.server_variables.get("environment", ""),
669
- )
670
- span.set_tag_str(
671
- "langchain.request.pinecone.index_name",
672
- instance._index.configuration.server_variables.get("index_name", ""),
673
- )
674
- span.set_tag_str(
675
- "langchain.request.pinecone.project_name",
676
- instance._index.configuration.server_variables.get("project_name", ""),
677
- )
678
- api_key = instance._index.configuration.api_key.get("ApiKeyAuth", "")
679
- span.set_tag_str(API_KEY, _format_api_key(api_key)) # override api_key for Pinecone
680
339
  documents = func(*args, **kwargs)
681
- span.set_metric("langchain.response.document_count", len(documents))
682
- for idx, document in enumerate(documents):
683
- span.set_tag_str(
684
- "langchain.response.document.%d.page_content" % idx, integration.trunc(str(document.page_content))
685
- )
686
- for kwarg_key, v in document.metadata.items():
687
- span.set_tag_str(
688
- "langchain.response.document.%d.metadata.%s" % (idx, kwarg_key), integration.trunc(str(v))
689
- )
690
340
  except Exception:
691
341
  span.set_exc_info(*sys.exc_info())
692
342
  raise
@@ -702,17 +352,6 @@ def traced_chain_stream(langchain, pin, func, instance, args, kwargs):
702
352
 
703
353
  def _on_span_started(span: Span):
704
354
  integration.record_instance(instance, span)
705
- inputs = get_argument_value(args, kwargs, 0, "input")
706
- if not integration.is_pc_sampled_span(span):
707
- return
708
- if not isinstance(inputs, list):
709
- inputs = [inputs]
710
- for idx, inp in enumerate(inputs):
711
- if not isinstance(inp, dict):
712
- span.set_tag_str("langchain.request.inputs.%d" % idx, integration.trunc(str(inp)))
713
- continue
714
- for k, v in inp.items():
715
- span.set_tag_str("langchain.request.inputs.%d.%s" % (idx, k), integration.trunc(str(v)))
716
355
 
717
356
  def _on_span_finished(span: Span, streamed_chunks):
718
357
  maybe_parser = instance.steps[-1] if instance.steps else None
@@ -735,9 +374,6 @@ def traced_chain_stream(langchain, pin, func, instance, args, kwargs):
735
374
  # best effort to join chunks together
736
375
  content = "".join([str(chunk) for chunk in streamed_chunks])
737
376
  integration.llmobs_set_tags(span, args=args, kwargs=kwargs, response=content, operation="chain")
738
- if span.error or not integration.is_pc_sampled_span(span):
739
- return
740
- span.set_tag_str("langchain.response.outputs", integration.trunc(content))
741
377
 
742
378
  return shared_stream(
743
379
  integration=integration,
@@ -760,41 +396,13 @@ def traced_chat_stream(langchain, pin, func, instance, args, kwargs):
760
396
 
761
397
  def _on_span_started(span: Span):
762
398
  integration.record_instance(instance, span)
763
- if not integration.is_pc_sampled_span(span):
764
- return
765
- chat_messages = get_argument_value(args, kwargs, 0, "input")
766
- tag_general_message_input(span, chat_messages, integration, langchain_core)
767
-
768
- for param, val in getattr(instance, "_identifying_params", {}).items():
769
- if not isinstance(val, dict):
770
- span.set_tag_str("langchain.request.%s.parameters.%s" % (llm_provider, param), str(val))
771
- continue
772
- for k, v in val.items():
773
- span.set_tag_str("langchain.request.%s.parameters.%s.%s" % (llm_provider, param, k), str(v))
774
399
 
775
400
  def _on_span_finished(span: Span, streamed_chunks):
776
401
  joined_chunks = streamed_chunks[0]
777
402
  for chunk in streamed_chunks[1:]:
778
403
  joined_chunks += chunk # base message types support __add__ for concatenation
404
+ kwargs["_dd.identifying_params"] = instance._identifying_params
779
405
  integration.llmobs_set_tags(span, args=args, kwargs=kwargs, response=joined_chunks, operation="chat")
780
- if (
781
- span.error
782
- or not integration.is_pc_sampled_span(span)
783
- or streamed_chunks is None
784
- or len(streamed_chunks) == 0
785
- ):
786
- return
787
- content = str(getattr(joined_chunks, "content", joined_chunks))
788
- role = joined_chunks.__class__.__name__.replace("Chunk", "") # AIMessageChunk --> AIMessage
789
- span.set_tag_str("langchain.response.content", integration.trunc(content))
790
- if role:
791
- span.set_tag_str("langchain.response.message_type", role)
792
-
793
- usage = streamed_chunks and getattr(streamed_chunks[-1], "usage_metadata", None)
794
- if not usage or not isinstance(usage, dict):
795
- return
796
- for k, v in usage.items():
797
- span.set_tag_str("langchain.response.usage_metadata.%s" % k, str(v))
798
406
 
799
407
  return shared_stream(
800
408
  integration=integration,
@@ -806,7 +414,6 @@ def traced_chat_stream(langchain, pin, func, instance, args, kwargs):
806
414
  interface_type="chat_model",
807
415
  on_span_started=_on_span_started,
808
416
  on_span_finished=_on_span_finished,
809
- api_key=_extract_api_key(instance),
810
417
  provider=llm_provider,
811
418
  model=model,
812
419
  )
@@ -820,23 +427,11 @@ def traced_llm_stream(langchain, pin, func, instance, args, kwargs):
820
427
 
821
428
  def _on_span_start(span: Span):
822
429
  integration.record_instance(instance, span)
823
- if not integration.is_pc_sampled_span(span):
824
- return
825
- inp = get_argument_value(args, kwargs, 0, "input")
826
- tag_general_message_input(span, inp, integration, langchain_core)
827
- for param, val in getattr(instance, "_identifying_params", {}).items():
828
- if not isinstance(val, dict):
829
- span.set_tag_str("langchain.request.%s.parameters.%s" % (llm_provider, param), str(val))
830
- continue
831
- for k, v in val.items():
832
- span.set_tag_str("langchain.request.%s.parameters.%s.%s" % (llm_provider, param, k), str(v))
833
430
 
834
431
  def _on_span_finished(span: Span, streamed_chunks):
835
432
  content = "".join([str(chunk) for chunk in streamed_chunks])
433
+ kwargs["_dd.identifying_params"] = instance._identifying_params
836
434
  integration.llmobs_set_tags(span, args=args, kwargs=kwargs, response=content, operation="llm")
837
- if span.error or not integration.is_pc_sampled_span(span):
838
- return
839
- span.set_tag_str("langchain.response.content", integration.trunc(content))
840
435
 
841
436
  return shared_stream(
842
437
  integration=integration,
@@ -848,7 +443,6 @@ def traced_llm_stream(langchain, pin, func, instance, args, kwargs):
848
443
  interface_type="llm",
849
444
  on_span_started=_on_span_start,
850
445
  on_span_finished=_on_span_finished,
851
- api_key=_extract_api_key(instance),
852
446
  provider=llm_provider,
853
447
  model=model,
854
448
  )
@@ -876,28 +470,15 @@ def traced_base_tool_invoke(langchain, pin, func, instance, args, kwargs):
876
470
  for attribute in ("name", "description"):
877
471
  value = getattr(instance, attribute, None)
878
472
  tool_info[attribute] = value
879
- if value is not None:
880
- span.set_tag_str("langchain.request.tool.%s" % attribute, str(value))
881
473
 
882
474
  metadata = getattr(instance, "metadata", {})
883
475
  if metadata:
884
476
  tool_info["metadata"] = metadata
885
- for key, meta_value in metadata.items():
886
- span.set_tag_str("langchain.request.tool.metadata.%s" % key, str(meta_value))
887
477
  tags = getattr(instance, "tags", [])
888
478
  if tags:
889
479
  tool_info["tags"] = tags
890
- for idx, tag in tags:
891
- span.set_tag_str("langchain.request.tool.tags.%d" % idx, str(value))
892
-
893
- if tool_input and integration.is_pc_sampled_span(span):
894
- span.set_tag_str("langchain.request.input", integration.trunc(str(tool_input)))
895
- if config:
896
- span.set_tag_str("langchain.request.config", safe_json(config))
897
480
 
898
481
  tool_output = func(*args, **kwargs)
899
- if tool_output and integration.is_pc_sampled_span(span):
900
- span.set_tag_str("langchain.response.output", integration.trunc(str(tool_output)))
901
482
  except Exception:
902
483
  span.set_exc_info(*sys.exc_info())
903
484
  raise
@@ -930,28 +511,15 @@ async def traced_base_tool_ainvoke(langchain, pin, func, instance, args, kwargs)
930
511
  for attribute in ("name", "description"):
931
512
  value = getattr(instance, attribute, None)
932
513
  tool_info[attribute] = value
933
- if value is not None:
934
- span.set_tag_str("langchain.request.tool.%s" % attribute, str(value))
935
514
 
936
515
  metadata = getattr(instance, "metadata", {})
937
516
  if metadata:
938
517
  tool_info["metadata"] = metadata
939
- for key, meta_value in metadata.items():
940
- span.set_tag_str("langchain.request.tool.metadata.%s" % key, str(meta_value))
941
518
  tags = getattr(instance, "tags", [])
942
519
  if tags:
943
520
  tool_info["tags"] = tags
944
- for idx, tag in tags:
945
- span.set_tag_str("langchain.request.tool.tags.%d" % idx, str(value))
946
-
947
- if tool_input and integration.is_pc_sampled_span(span):
948
- span.set_tag_str("langchain.request.input", integration.trunc(str(tool_input)))
949
- if config:
950
- span.set_tag_str("langchain.request.config", safe_json(config))
951
521
 
952
522
  tool_output = await func(*args, **kwargs)
953
- if tool_output and integration.is_pc_sampled_span(span):
954
- span.set_tag_str("langchain.response.output", integration.trunc(str(tool_output)))
955
523
  except Exception:
956
524
  span.set_exc_info(*sys.exc_info())
957
525
  raise