traccia 0.1.2__py3-none-any.whl → 0.1.6__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.
Files changed (57) hide show
  1. traccia/__init__.py +73 -0
  2. traccia/auto.py +748 -0
  3. traccia/auto_instrumentation.py +74 -0
  4. traccia/cli.py +349 -0
  5. traccia/config.py +699 -0
  6. traccia/context/__init__.py +33 -0
  7. traccia/context/context.py +67 -0
  8. traccia/context/propagators.py +283 -0
  9. traccia/errors.py +48 -0
  10. traccia/exporter/__init__.py +8 -0
  11. traccia/exporter/console_exporter.py +31 -0
  12. traccia/exporter/file_exporter.py +178 -0
  13. traccia/exporter/http_exporter.py +214 -0
  14. traccia/exporter/otlp_exporter.py +190 -0
  15. traccia/instrumentation/__init__.py +26 -0
  16. traccia/instrumentation/anthropic.py +92 -0
  17. traccia/instrumentation/decorator.py +263 -0
  18. traccia/instrumentation/fastapi.py +38 -0
  19. traccia/instrumentation/http_client.py +21 -0
  20. traccia/instrumentation/http_server.py +25 -0
  21. traccia/instrumentation/openai.py +358 -0
  22. traccia/instrumentation/requests.py +68 -0
  23. traccia/integrations/__init__.py +39 -0
  24. traccia/integrations/langchain/__init__.py +14 -0
  25. traccia/integrations/langchain/callback.py +418 -0
  26. traccia/integrations/langchain/utils.py +129 -0
  27. traccia/integrations/openai_agents/__init__.py +73 -0
  28. traccia/integrations/openai_agents/processor.py +262 -0
  29. traccia/pricing_config.py +58 -0
  30. traccia/processors/__init__.py +35 -0
  31. traccia/processors/agent_enricher.py +159 -0
  32. traccia/processors/batch_processor.py +140 -0
  33. traccia/processors/cost_engine.py +71 -0
  34. traccia/processors/cost_processor.py +70 -0
  35. traccia/processors/drop_policy.py +44 -0
  36. traccia/processors/logging_processor.py +31 -0
  37. traccia/processors/rate_limiter.py +223 -0
  38. traccia/processors/sampler.py +22 -0
  39. traccia/processors/token_counter.py +216 -0
  40. traccia/runtime_config.py +127 -0
  41. traccia/tracer/__init__.py +15 -0
  42. traccia/tracer/otel_adapter.py +577 -0
  43. traccia/tracer/otel_utils.py +24 -0
  44. traccia/tracer/provider.py +155 -0
  45. traccia/tracer/span.py +286 -0
  46. traccia/tracer/span_context.py +16 -0
  47. traccia/tracer/tracer.py +243 -0
  48. traccia/utils/__init__.py +19 -0
  49. traccia/utils/helpers.py +95 -0
  50. {traccia-0.1.2.dist-info → traccia-0.1.6.dist-info}/METADATA +72 -15
  51. traccia-0.1.6.dist-info/RECORD +55 -0
  52. traccia-0.1.6.dist-info/top_level.txt +1 -0
  53. traccia-0.1.2.dist-info/RECORD +0 -6
  54. traccia-0.1.2.dist-info/top_level.txt +0 -1
  55. {traccia-0.1.2.dist-info → traccia-0.1.6.dist-info}/WHEEL +0 -0
  56. {traccia-0.1.2.dist-info → traccia-0.1.6.dist-info}/entry_points.txt +0 -0
  57. {traccia-0.1.2.dist-info → traccia-0.1.6.dist-info}/licenses/LICENSE +0 -0
@@ -0,0 +1,19 @@
1
+ """Utility functions for Traccia SDK."""
2
+
3
+ from traccia.utils.helpers import (
4
+ get_duration_ns,
5
+ get_parent_span_id,
6
+ format_trace_id,
7
+ format_span_id,
8
+ parse_trace_id,
9
+ parse_span_id,
10
+ )
11
+
12
+ __all__ = [
13
+ "get_duration_ns",
14
+ "get_parent_span_id",
15
+ "format_trace_id",
16
+ "format_span_id",
17
+ "parse_trace_id",
18
+ "parse_span_id",
19
+ ]
@@ -0,0 +1,95 @@
1
+ """Helper functions for OpenTelemetry compatibility."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from typing import Optional
6
+
7
+ from opentelemetry.trace import Span as OTelSpan
8
+
9
+
10
+ def get_duration_ns(span: OTelSpan) -> Optional[int]:
11
+ """
12
+ Get span duration in nanoseconds.
13
+
14
+ Args:
15
+ span: OpenTelemetry Span instance
16
+
17
+ Returns:
18
+ Duration in nanoseconds, or None if span hasn't ended
19
+ """
20
+ if span.end_time is None:
21
+ return None
22
+ return span.end_time - span.start_time
23
+
24
+
25
+ def get_parent_span_id(span: OTelSpan) -> Optional[int]:
26
+ """
27
+ Get parent span ID from span context.
28
+
29
+ Args:
30
+ span: OpenTelemetry Span instance
31
+
32
+ Returns:
33
+ Parent span ID (int64), or None if no parent
34
+ """
35
+ # OTel doesn't expose parent_span_id directly
36
+ # We need to get it from the span's parent context if available
37
+ # For now, return None - parent relationship is maintained via context
38
+ # This can be enhanced if needed by tracking parent during span creation
39
+ return None
40
+
41
+
42
+ def format_trace_id(trace_id: int) -> str:
43
+ """
44
+ Format OTel trace_id (int64) to hex string.
45
+
46
+ Args:
47
+ trace_id: OTel trace_id as int64
48
+
49
+ Returns:
50
+ 32-character hex string
51
+ """
52
+ return format(trace_id, '032x')
53
+
54
+
55
+ def format_span_id(span_id: int) -> str:
56
+ """
57
+ Format OTel span_id (int64) to hex string.
58
+
59
+ Args:
60
+ span_id: OTel span_id as int64
61
+
62
+ Returns:
63
+ 16-character hex string
64
+ """
65
+ return format(span_id, '016x')
66
+
67
+
68
+ def parse_trace_id(hex_string: str) -> int:
69
+ """
70
+ Parse hex string trace_id to OTel int64.
71
+
72
+ Args:
73
+ hex_string: 32-character hex string
74
+
75
+ Returns:
76
+ OTel trace_id as int64
77
+ """
78
+ if not hex_string:
79
+ return 0
80
+ return int(hex_string, 16)
81
+
82
+
83
+ def parse_span_id(hex_string: str) -> int:
84
+ """
85
+ Parse hex string span_id to OTel int64.
86
+
87
+ Args:
88
+ hex_string: 16-character hex string
89
+
90
+ Returns:
91
+ OTel span_id as int64
92
+ """
93
+ if not hex_string:
94
+ return 0
95
+ return int(hex_string, 16)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: traccia
3
- Version: 0.1.2
3
+ Version: 0.1.6
4
4
  Summary: Production-ready distributed tracing SDK for AI agents and LLM applications
5
5
  License: Apache-2.0
6
6
  Project-URL: Homepage, https://github.com/traccia-ai/traccia
@@ -32,6 +32,8 @@ Requires-Dist: opentelemetry-semantic-conventions>=0.40b0
32
32
  Requires-Dist: tomli>=2.0.0; python_version < "3.11"
33
33
  Requires-Dist: toml>=0.10.0
34
34
  Requires-Dist: pydantic>=2.0.0
35
+ Provides-Extra: langchain
36
+ Requires-Dist: langchain-core>=0.1.0; extra == "langchain"
35
37
  Dynamic: license-file
36
38
 
37
39
  # Traccia
@@ -43,6 +45,7 @@ Traccia is a lightweight, high-performance Python SDK for observability and trac
43
45
  ## ✨ Features
44
46
 
45
47
  - **🔍 Automatic Instrumentation**: Auto-patch OpenAI, Anthropic, requests, and HTTP libraries
48
+ - **🤖 Framework Integrations**: Support for LangChain and OpenAI Agents SDK
46
49
  - **📊 LLM-Aware Tracing**: Track tokens, costs, prompts, and completions automatically
47
50
  - **⚡ Zero-Config Start**: Simple `init()` call with automatic config discovery
48
51
  - **🎯 Decorator-Based**: Trace any function with `@observe` decorator
@@ -101,6 +104,59 @@ def generate_text(prompt: str) -> str:
101
104
  text = generate_text("Write a haiku about Python")
102
105
  ```
103
106
 
107
+ ### LangChain
108
+
109
+ Create a callback handler and pass it to `config={"callbacks": [traccia_handler]}`. Install the optional extra: `pip install traccia[langchain]`.
110
+
111
+ ```python
112
+ from traccia import init
113
+ from traccia.integrations.langchain import CallbackHandler # or TracciaCallbackHandler
114
+ from langchain_openai import ChatOpenAI
115
+
116
+ init()
117
+
118
+ # Create Traccia handler (no args)
119
+ traccia_handler = CallbackHandler()
120
+
121
+ # Use with any LangChain runnable
122
+ llm = ChatOpenAI(model="gpt-4o-mini")
123
+ result = llm.invoke(
124
+ "Tell me a joke",
125
+ config={"callbacks": [traccia_handler]}
126
+ )
127
+ ```
128
+
129
+ Spans for LLM/chat model runs are created automatically with the same attributes as direct OpenAI instrumentation (model, prompt, usage, cost).
130
+
131
+ **Note:** `pip install traccia[langchain]` installs traccia plus `langchain-core`; you need this extra to use the callback handler. If you already have `langchain-core` (e.g. from `langchain` or `langchain-openai`), base `pip install traccia` may be enough at runtime, but `traccia[langchain]` is the supported way to get a compatible dependency.
132
+
133
+ ### OpenAI Agents SDK
134
+
135
+ Traccia **automatically** detects and instruments the OpenAI Agents SDK when installed. No extra code needed:
136
+
137
+ ```python
138
+ from traccia import init
139
+ from agents import Agent, Runner
140
+
141
+ init() # Automatically enables Agents SDK tracing
142
+
143
+ agent = Agent(
144
+ name="Assistant",
145
+ instructions="You are a helpful assistant"
146
+ )
147
+ result = Runner.run_sync(agent, "Write a haiku about recursion")
148
+ ```
149
+
150
+ **Configuration**: Auto-enabled by default when `openai-agents` is installed. To disable:
151
+
152
+ ```python
153
+ init(openai_agents=False) # Explicit parameter
154
+ # OR set environment variable: TRACCIA_OPENAI_AGENTS=false
155
+ # OR in traccia.toml under [instrumentation]: openai_agents = false
156
+ ```
157
+
158
+ **Compatibility**: If you have `openai-agents` installed but don't use it (e.g., using LangChain or pure OpenAI instead), the integration is registered but never invoked—no overhead or extra spans.
159
+
104
160
  ---
105
161
 
106
162
  ## 📖 Configuration
@@ -141,6 +197,7 @@ reset_trace_file = false # Reset file on initialization
141
197
  enable_patching = true # Auto-patch libraries (OpenAI, Anthropic, requests)
142
198
  enable_token_counting = true # Count tokens for LLM calls
143
199
  enable_costs = true # Calculate costs
200
+ openai_agents = true # Auto-enable OpenAI Agents SDK integration
144
201
  auto_instrument_tools = false # Auto-instrument tool calls (experimental)
145
202
  max_tool_spans = 100 # Max tool spans to create
146
203
  max_span_depth = 10 # Max nested span depth
@@ -470,18 +527,6 @@ init(debug=True)
470
527
  - Increase `max_queue_size` if spans are queued
471
528
  - Check `traccia doctor` output
472
529
 
473
- #### **Import errors after upgrade**
474
-
475
- If you're migrating from `traccia_sdk`:
476
-
477
- ```python
478
- # OLD (will raise helpful error)
479
- from traccia_sdk import init # ❌ ImportError with migration guide
480
-
481
- # NEW
482
- from traccia import init # ✅ Correct
483
- ```
484
-
485
530
  ---
486
531
 
487
532
  ## 📚 API Reference
@@ -537,13 +582,14 @@ Create a span context manager.
537
582
 
538
583
  ### Decorator
539
584
 
540
- #### `@observe(name=None, *, attributes=None, as_type="span", skip_args=None, skip_result=False)`
585
+ #### `@observe(name=None, *, attributes=None, tags=None, as_type="span", skip_args=None, skip_result=False)`
541
586
 
542
587
  Decorate a function to create spans automatically.
543
588
 
544
589
  **Parameters**:
545
590
  - `name` (str, optional): Span name (default: function name)
546
591
  - `attributes` (dict, optional): Initial attributes
592
+ - `tags` (list[str], optional): User-defined identifiers for the observed method
547
593
  - `as_type` (str): Span type (`"span"`, `"llm"`, `"tool"`)
548
594
  - `skip_args` (list, optional): Arguments to skip capturing
549
595
  - `skip_result` (bool): Skip capturing return value
@@ -590,6 +636,17 @@ Application Code (@observe)
590
636
  Backend (Grafana Tempo / Jaeger / Zipkin / etc.)
591
637
  ```
592
638
 
639
+ ### Instrumentation vs Integrations
640
+
641
+ - **`traccia.instrumentation.*`**: Infrastructure and vendor instrumentation.
642
+ - HTTP client/server helpers (including FastAPI middleware).
643
+ - Vendor SDK hooks and monkey patching (e.g., OpenAI, Anthropic, `requests`).
644
+ - Decorators and utilities used for auto-instrumenting arbitrary functions.
645
+
646
+ - **`traccia.integrations.*`**: AI/agent framework integrations.
647
+ - Adapters that plug into higher-level frameworks via their official extension points (e.g., LangChain callbacks).
648
+ - Work at the level of chains, tools, agents, and workflows rather than raw HTTP or SDK calls.
649
+
593
650
  ---
594
651
 
595
652
  ## 🤝 Contributing
@@ -649,7 +706,7 @@ pytest traccia/tests/ --cov=traccia --cov-report=html
649
706
 
650
707
  ## 📄 License
651
708
 
652
- MIT License - see [LICENSE](LICENSE) for details
709
+ Apache License 2.0 - see [LICENSE](LICENSE) for full terms and conditions.
653
710
 
654
711
  ---
655
712
 
@@ -0,0 +1,55 @@
1
+ traccia/__init__.py,sha256=O2Hs3GFVcFsmeBlJwJhqPvFH9kB-pAJarEfB9G4xLZU,1998
2
+ traccia/auto.py,sha256=zr4zTMIPEn7epm1KO8APzpdzuaYroeW_ZKB8L41AFXk,26302
3
+ traccia/auto_instrumentation.py,sha256=e2Gzt2AtGSXbv6BSZpAApAtMcTlEwc08dgZgQMfrREU,2107
4
+ traccia/cli.py,sha256=lQJU-dAxxcWyOew7OCBi2u7RbMXcwOxtLyfzFwlZ4f0,12362
5
+ traccia/config.py,sha256=BByH9VOjjXKHLeJlWXXEA2Vlq3k9AqriNggdrlUrff0,24798
6
+ traccia/errors.py,sha256=CMIS01M3pnr3oRhtzQkyKYkDgYkJNlGd6D9Zg2AohA0,1158
7
+ traccia/pricing_config.py,sha256=ZTccshJbAySWJw9Rdvpj2SMaHkEio325t8NkfJfNzfY,1732
8
+ traccia/runtime_config.py,sha256=c6Cto1pQjKy4Jb6pSClQrgzQRv8flZrePNpK1wxbx3s,2735
9
+ traccia/context/__init__.py,sha256=_tNDOoVZ3GgbYtw9I3F8YSKuPovQBa0orjtd7CtfI1w,738
10
+ traccia/context/context.py,sha256=hBvsrYV_-2cHCC7jTH5iGKHzxZRGpMH2vc0oTW2cqAY,1967
11
+ traccia/context/propagators.py,sha256=Tq3O-JYEBqkshrrhGYn-j_2V718gfLiFDaVzsDdVmms,8747
12
+ traccia/exporter/__init__.py,sha256=4Gh7X6XoccGpiIErIZGvDPpT8qzl91wwqJzDhc9gi3Q,360
13
+ traccia/exporter/console_exporter.py,sha256=IKR9S_DJbOqB7aRaDHGtl7GlDiV3GLHTh7I9Anmj7Ao,873
14
+ traccia/exporter/file_exporter.py,sha256=4TcHvhCs6yGCfU-HKVtA8oKjnlzlSfGiI0TMTdVvdsc,6922
15
+ traccia/exporter/http_exporter.py,sha256=kLcDn0WoFbSc6pAawj_-MNqOASGMEiFKki-Y3FeieKU,8039
16
+ traccia/exporter/otlp_exporter.py,sha256=sy74xOgKyLofG_S9QHTuQo4HB4LaKnVVWKYv1cHRZx0,7692
17
+ traccia/instrumentation/__init__.py,sha256=kOs72xJCraJknhDAtbxgiVNUgwI-efAGGFB3tXJsRhI,967
18
+ traccia/instrumentation/anthropic.py,sha256=R4vL1plLHgt0TXkDwt1Priic9HppIp2Oyt11IJZZ9Ug,3444
19
+ traccia/instrumentation/decorator.py,sha256=BTZvtFpNA2MVuNkoMbbZtgVK_c_su1M3V1OIuBoTEl0,10049
20
+ traccia/instrumentation/fastapi.py,sha256=LpenJ5aIrcTTWZb6_6GsQ_6cXrVMDjdfeyfQeGvDUTs,1271
21
+ traccia/instrumentation/http_client.py,sha256=fBZx2RNcMxH73cmTrDjlQVYxerBUKQnw8OANyfak5HE,586
22
+ traccia/instrumentation/http_server.py,sha256=RTMklczBEam8PE-pPVMUWBo8YtU7_ISa6-G0Zqjbptk,913
23
+ traccia/instrumentation/openai.py,sha256=nItQnjpq3GXNfM1VE3DIt2YIHRlg5e495KtvpQjFjFs,14862
24
+ traccia/instrumentation/requests.py,sha256=I7Oc_px9RDtliQ2ktQVymPUc2Zkaz1NdepxWQygMb24,2267
25
+ traccia/integrations/__init__.py,sha256=bkLPf2DyX7c6-_p12aKgdgsM9EOyF2EZ7y2-jNjxDzw,1150
26
+ traccia/integrations/langchain/__init__.py,sha256=98umBkI8DePI4eUJBZtBUgjMsmaUNF2EfMPK2bWH3iM,524
27
+ traccia/integrations/langchain/callback.py,sha256=xwHVMKRa6TduLm2bU4NNuDvK2AySQsmnQWWqA8whYOQ,14771
28
+ traccia/integrations/langchain/utils.py,sha256=TjkEUKprTL2CfkSjVG4jSO0fLk_n3wvTgxv5NN_wHeI,4258
29
+ traccia/integrations/openai_agents/__init__.py,sha256=bFxSf5rvnKzl87Ux8MkFylUYY0vagil3cTTrb0HeNeg,2028
30
+ traccia/integrations/openai_agents/processor.py,sha256=DpwSISq9R3dUiS0so95T7bSCLwcRnG8IcsiXCsRg_fY,10450
31
+ traccia/processors/__init__.py,sha256=-hwG9SXM6JbGJaIol2KnS3aWwr9P_TVbJ4AZtGTe2zY,1192
32
+ traccia/processors/agent_enricher.py,sha256=Ur1QvqXSCWT9RgZQw6s53P6URfGmH0KsC7WRJlCYRew,6434
33
+ traccia/processors/batch_processor.py,sha256=JTZzWQs5jXlIiqI7PqukfrHil3V81ZC4tRsqeGYv_v8,4832
34
+ traccia/processors/cost_engine.py,sha256=nMbGwRqWdsOEyIYGdjsX_Srww8f3rxMMDmdUlLqBZn8,2391
35
+ traccia/processors/cost_processor.py,sha256=pJO4NOhWwEOCfSS5zYAR-5qufBjfLcnINObhzkjgdZw,2469
36
+ traccia/processors/drop_policy.py,sha256=dxRiLt79ox4_7DFVMxt_Y0zOIOEV8AQirl8vq_jaVU0,1164
37
+ traccia/processors/logging_processor.py,sha256=2BzTz7_jGF3uVOWc_B-BM3Ab8nyU3crLOt5pcXshgSg,921
38
+ traccia/processors/rate_limiter.py,sha256=PycOYVyiVA4xFEXewOgqiw-rxzFhXu4b9Zw0RdywXck,7878
39
+ traccia/processors/sampler.py,sha256=_jKSRVlt94Bg317j8rfRtt5sdLuCaoI8v9IkgpaEiVs,548
40
+ traccia/processors/token_counter.py,sha256=o91y9nFVFnfRNKcTywNshcEuh8FzXPVH3WOd3Kzpgbs,7676
41
+ traccia/tracer/__init__.py,sha256=VI-EQcz5NtPWV07BJbqPi-DSL-1f81G3y22ngdLidjA,375
42
+ traccia/tracer/otel_adapter.py,sha256=X-1DEeyeHnCJNNqGOldLEpHosz-rjs3jsg49AVTOskw,21006
43
+ traccia/tracer/otel_utils.py,sha256=94HZV1GgeC07w7qWhK3Vu5uzAqiL3LV8yZHOsd5CACM,807
44
+ traccia/tracer/provider.py,sha256=MlQUt_sk0hHEyKBVmv-g9XG9GIEWnwvtGoFBsQcTmxA,5180
45
+ traccia/tracer/span.py,sha256=6SFZDa9HM0SIAznpdIoC9ym_naSPCkipQgthsfSJYLU,9446
46
+ traccia/tracer/span_context.py,sha256=Y6J5Rr6bu-WG2-K2tyncLyyjdAK74b3fbSpIkLOQorg,356
47
+ traccia/tracer/tracer.py,sha256=oxXJnkR95-UnQeVhdtOOW7q0iAqWf_M9YmvCEcvRhkg,9496
48
+ traccia/utils/__init__.py,sha256=JelSlN-M6Sv8y_MLpYAz_kBUguBnxFSuzvhg4eFIdpg,357
49
+ traccia/utils/helpers.py,sha256=yhihp2Jw2TLTPxffGee5nE8nRcZ5C2aWgyLHKZek3Cc,2107
50
+ traccia-0.1.6.dist-info/licenses/LICENSE,sha256=HNl57LOj88EfKh-IWmeqWxsDRh_FF6lj0l-E2A4Hr8w,10757
51
+ traccia-0.1.6.dist-info/METADATA,sha256=IJnHGuC2bOBkvx0YdRIpwNWndQOg7x8AgJS2afj1Aj0,20676
52
+ traccia-0.1.6.dist-info/WHEEL,sha256=wUyA8OaulRlbfwMtmQsvNngGrxQHAvkKcvRmdizlJi0,92
53
+ traccia-0.1.6.dist-info/entry_points.txt,sha256=SG7gacPRmFzLw2HYTblUZsmC_TO3n14-dNi28SL-C2k,45
54
+ traccia-0.1.6.dist-info/top_level.txt,sha256=Kc56JudupqSkzJPOnuQ6mPHJmhtike7pssNX0u_p59w,8
55
+ traccia-0.1.6.dist-info/RECORD,,
@@ -0,0 +1 @@
1
+ traccia
@@ -1,6 +0,0 @@
1
- traccia-0.1.2.dist-info/licenses/LICENSE,sha256=HNl57LOj88EfKh-IWmeqWxsDRh_FF6lj0l-E2A4Hr8w,10757
2
- traccia-0.1.2.dist-info/METADATA,sha256=LNuwcEuYE5OCjPFHV-VvLzoND4KR5_BNYbBuDD6jI_k,17986
3
- traccia-0.1.2.dist-info/WHEEL,sha256=wUyA8OaulRlbfwMtmQsvNngGrxQHAvkKcvRmdizlJi0,92
4
- traccia-0.1.2.dist-info/entry_points.txt,sha256=SG7gacPRmFzLw2HYTblUZsmC_TO3n14-dNi28SL-C2k,45
5
- traccia-0.1.2.dist-info/top_level.txt,sha256=AbpHGcgLb-kRsJGnwFEktk7uzpZOCcBY74-YBdrKVGs,1
6
- traccia-0.1.2.dist-info/RECORD,,
@@ -1 +0,0 @@
1
-