paid-python 0.3.5__py3-none-any.whl → 0.4.0__py3-none-any.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.
paid/tracing/__init__.py CHANGED
@@ -7,13 +7,14 @@ from .distributed_tracing import (
7
7
  unset_tracing_token,
8
8
  )
9
9
  from .signal import signal
10
- from .tracing import initialize_tracing
10
+ from .tracing import initialize_tracing, get_paid_tracer_provider
11
11
 
12
12
  __all__ = [
13
13
  "generate_tracing_token",
14
14
  "paid_autoinstrument",
15
15
  "paid_tracing",
16
16
  "initialize_tracing",
17
+ "get_paid_tracer_provider",
17
18
  "set_tracing_token",
18
19
  "unset_tracing_token",
19
20
  "signal",
@@ -44,7 +44,7 @@ except ImportError:
44
44
  BEDROCK_AVAILABLE = False
45
45
 
46
46
  try:
47
- from opentelemetry.instrumentation.langchain import LangchainInstrumentor
47
+ from openinference.instrumentation.langchain import LangChainInstrumentor
48
48
 
49
49
  LANGCHAIN_AVAILABLE = True
50
50
  except ImportError:
@@ -196,16 +196,14 @@ def _instrument_bedrock() -> None:
196
196
 
197
197
  def _instrument_langchain() -> None:
198
198
  """
199
- Instrument LangChain using opentelemetry-instrumentation-langchain.
199
+ Instrument LangChain using openinference-instrumentation-langchain.
200
200
  """
201
201
  if not LANGCHAIN_AVAILABLE:
202
202
  logger.warning("LangChain instrumentation library not available, skipping instrumentation")
203
203
  return
204
204
 
205
205
  # Instrument LangChain with Paid's tracer provider
206
- LangchainInstrumentor(disable_trace_context_propagation=True).instrument(
207
- tracer_provider=tracing.paid_tracer_provider
208
- )
206
+ LangChainInstrumentor().instrument(tracer_provider=tracing.paid_tracer_provider)
209
207
 
210
208
  _initialized_instrumentors.append("langchain")
211
209
  logger.info("LangChain auto-instrumentation enabled")
paid/tracing/tracing.py CHANGED
@@ -56,6 +56,22 @@ def set_token(token: str) -> None:
56
56
  # Initialized at module load with defaults, never None (uses no-op provider if not initialized or API key isn't available)
57
57
  paid_tracer_provider: Union[TracerProvider, NoOpTracerProvider] = NoOpTracerProvider()
58
58
 
59
+ def get_paid_tracer_provider() -> Optional[TracerProvider]:
60
+ """Export the tracer provider to the user.
61
+ Initialize tracing if not already. Never return NoOpTracerProvider.
62
+
63
+ Returns:
64
+ The tracer provider instance.
65
+ """
66
+ global paid_tracer_provider
67
+
68
+ if get_token() is None:
69
+ initialize_tracing()
70
+
71
+ if not isinstance(paid_tracer_provider, TracerProvider):
72
+ return None
73
+
74
+ return paid_tracer_provider
59
75
 
60
76
  class PaidSpanProcessor(SpanProcessor):
61
77
  """
@@ -63,25 +79,36 @@ class PaidSpanProcessor(SpanProcessor):
63
79
  1. Prefixes all span names with 'paid.trace.'
64
80
  2. Automatically adds external_customer_id and external_agent_id attributes
65
81
  to all spans based on context variables set by the tracing decorator.
82
+ 3. Filters out prompt/response data unless store_prompt=True.
83
+ 4. Filters out duplicate LangChain spans that may duplicate information from other instrumentations.
66
84
  """
67
85
 
68
86
  SPAN_NAME_PREFIX = "paid.trace."
69
87
  PROMPT_ATTRIBUTES_SUBSTRINGS = {
70
- "prompt",
71
- # "gen_ai.prompt",
72
88
  "gen_ai.completion",
73
89
  "gen_ai.request.messages",
74
90
  "gen_ai.response.messages",
75
91
  "llm.output_message",
76
92
  "llm.input_message",
77
93
  "llm.invocation_parameters",
94
+ "gen_ai.prompt",
95
+ "langchain.prompt",
78
96
  "output.value",
79
97
  "input.value",
80
- # "langchain.prompt",
81
98
  }
82
99
 
83
100
  def on_start(self, span: Span, parent_context: Optional[Context] = None) -> None:
84
101
  """Called when a span is started. Prefix the span name and add attributes."""
102
+
103
+ LANGCHAIN_SPAN_FILTERS = ["ChatOpenAI", "ChatAnthropic"]
104
+ if any(f in span.name for f in LANGCHAIN_SPAN_FILTERS):
105
+ # HACK TO FILTER DUPLICATE SPANS CREATED BY LANGCHAIN INSTRUMENTATION.
106
+ # Langchain instrumentation creates spans, that are created by other instrumentations (ex. OpenAI, Anthropic).
107
+ # Not all spans need filtering (ex. ChatGoogleGenerativeAI), so first test actual telemetry before adding filters.
108
+ # TODO: maybe consider a dropping sampler for such spans instead of raising an exception?
109
+ logger.debug(f"Dropping Langchain span: {span.name}")
110
+ raise Exception(f"Dropping Langchain span: {span.name}")
111
+
85
112
  # Prefix the span name
86
113
  if span.name and not span.name.startswith(self.SPAN_NAME_PREFIX):
87
114
  span.update_name(f"{self.SPAN_NAME_PREFIX}{span.name}")
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: paid-python
3
- Version: 0.3.5
3
+ Version: 0.4.0
4
4
  Summary:
5
5
  Requires-Python: >=3.9,<3.14
6
6
  Classifier: Intended Audience :: Developers
@@ -21,11 +21,11 @@ Requires-Dist: httpx (>=0.21.0)
21
21
  Requires-Dist: mutagen (>=1.47.0)
22
22
  Requires-Dist: openinference-instrumentation-bedrock (>=0.1.0)
23
23
  Requires-Dist: openinference-instrumentation-google-genai (>=0.1.8)
24
+ Requires-Dist: openinference-instrumentation-langchain (>=0.1.55)
24
25
  Requires-Dist: openinference-instrumentation-openai-agents (>=1.0.0)
25
26
  Requires-Dist: opentelemetry-api (>=1.23.0)
26
27
  Requires-Dist: opentelemetry-exporter-otlp-proto-http (>=1.23.0)
27
28
  Requires-Dist: opentelemetry-instrumentation-anthropic (>=0.47.0)
28
- Requires-Dist: opentelemetry-instrumentation-langchain (>=0.47.0)
29
29
  Requires-Dist: opentelemetry-sdk (>=1.23.0)
30
30
  Requires-Dist: pydantic (>=1.9.0)
31
31
  Requires-Dist: pydantic-core (>=2.18.0)
@@ -767,6 +767,14 @@ async def do_work():
767
767
  await do_work()
768
768
  ```
769
769
 
770
+ ### Paid OTEL Tracer Provider
771
+
772
+ If you would like to use the Paid OTEL tracer provider:
773
+ ```python
774
+ from paid.tracing import get_paid_tracer_provider
775
+ paid_tracer_provider = get_paid_tracer_provider()
776
+ ```
777
+
770
778
  ## Contributing
771
779
 
772
780
  While we value open-source contributions to this SDK, this library is generated programmatically.
@@ -56,13 +56,13 @@ paid/orders/lines/client.py,sha256=GqSwiXdlu49KLHt7uccS_H4nkVQosM1_PQOcPA9v82A,4
56
56
  paid/orders/lines/raw_client.py,sha256=KZN_yBokCOkf1lUb4ZJtX_NZbqmTqCdJNoaIOdWar8I,4590
57
57
  paid/orders/raw_client.py,sha256=650e1Sj2vi9KVJc15M3ENXIKYoth0qMz66dzvXy1Sb4,16245
58
58
  paid/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
59
- paid/tracing/__init__.py,sha256=Pe55koIwqJ6Vv5-9Wqi8xIdwCS2BbxZds-MK5fD-F5Y,506
60
- paid/tracing/autoinstrumentation.py,sha256=Vdd0PrjLSzyxXujY45S9a0tAKjtLs8-SHbg81v23WkY,7784
59
+ paid/tracing/__init__.py,sha256=WScAVz67nxynERd9lZhmrobPMa0uScbB2nSly2vA3r4,564
60
+ paid/tracing/autoinstrumentation.py,sha256=kH2d1wGPLE6Ore60nNAwFUKAWkH-3N_B_6urJYoobMg,7732
61
61
  paid/tracing/context_data.py,sha256=oiLocz-9qDqB5nQzJlrLsc2Mkr9MaNt_yF_hjppobKc,3298
62
62
  paid/tracing/context_manager.py,sha256=ZQtsJ9JPxTwn2t4AW26WpYboaOEZdI2T1Sw0Rwsbf-E,8470
63
63
  paid/tracing/distributed_tracing.py,sha256=Vht3U8QJmT5jlRVnrybTn-cI1RPuVtyb3V4eTu6gA4g,3991
64
64
  paid/tracing/signal.py,sha256=PfYxF6EFQS8j7RY5_C5NXrCBVu9Hq2E2tyG4fdQScJk,3252
65
- paid/tracing/tracing.py,sha256=0eMY357by892_32a2qCT6nRCUOHt03gxKCmUH2wDjVg,15184
65
+ paid/tracing/tracing.py,sha256=MCIqzRELFB6VbvFrnpIp7bLX7HYfpHnmUapDLcAEioE,16478
66
66
  paid/tracing/wrappers/__init__.py,sha256=IIleLB_JUbzLw7FshrU2VHZAKF3dZHMGy1O5zCBwwqM,1588
67
67
  paid/tracing/wrappers/anthropic/__init__.py,sha256=_x1fjySAQxuT5cIGO_jU09LiGcZH-WQLqKg8mUFAu2w,115
68
68
  paid/tracing/wrappers/anthropic/anthropicWrapper.py,sha256=pGchbOb41CbTxc7H8xXoM-LjR085spqrzXqCVC_rrFk,4913
@@ -119,7 +119,7 @@ paid/usage/__init__.py,sha256=_VhToAyIt_5axN6CLJwtxg3-CO7THa_23pbUzqhXJa4,85
119
119
  paid/usage/client.py,sha256=280WJuepoovk3BAVbAx2yN2Q_qBdvx3CcPkLu8lXslc,3030
120
120
  paid/usage/raw_client.py,sha256=2acg5C4lxuZodZjepU9QYF0fmBxgG-3ZgXs1zUJG-wM,3709
121
121
  paid/version.py,sha256=QIpDFnOrxMxrs86eL0iNH0mSZ1DO078wWHYY9TYAoew,78
122
- paid_python-0.3.5.dist-info/LICENSE,sha256=Nz4baY1zvv0Qy7lqrQtbaiMhmEeGr2Q7A93aqzpml4c,1071
123
- paid_python-0.3.5.dist-info/METADATA,sha256=V99x_8mHOv0uUo6pwD7rcf2AEOYhSouqgMlJZAawyDI,23632
124
- paid_python-0.3.5.dist-info/WHEEL,sha256=Zb28QaM1gQi8f4VCBhsUklF61CTlNYfs9YAZn-TOGFk,88
125
- paid_python-0.3.5.dist-info/RECORD,,
122
+ paid_python-0.4.0.dist-info/LICENSE,sha256=Nz4baY1zvv0Qy7lqrQtbaiMhmEeGr2Q7A93aqzpml4c,1071
123
+ paid_python-0.4.0.dist-info/METADATA,sha256=CmtqOI_FpMWGVBkeDa8OogiYVw6smGXeoUBnuzNP_yc,23834
124
+ paid_python-0.4.0.dist-info/WHEEL,sha256=Zb28QaM1gQi8f4VCBhsUklF61CTlNYfs9YAZn-TOGFk,88
125
+ paid_python-0.4.0.dist-info/RECORD,,