botgauge-tracing 0.1.0__tar.gz

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 (45) hide show
  1. botgauge_tracing-0.1.0/LICENSE +105 -0
  2. botgauge_tracing-0.1.0/MANIFEST.in +3 -0
  3. botgauge_tracing-0.1.0/PKG-INFO +457 -0
  4. botgauge_tracing-0.1.0/README.md +390 -0
  5. botgauge_tracing-0.1.0/pyproject.toml +195 -0
  6. botgauge_tracing-0.1.0/setup.cfg +4 -0
  7. botgauge_tracing-0.1.0/src/botgauge/tracing/__init__.py +239 -0
  8. botgauge_tracing-0.1.0/src/botgauge/tracing/_agent.py +34 -0
  9. botgauge_tracing-0.1.0/src/botgauge/tracing/_attributes.py +86 -0
  10. botgauge_tracing-0.1.0/src/botgauge/tracing/_classify.py +189 -0
  11. botgauge_tracing-0.1.0/src/botgauge/tracing/_commands.py +39 -0
  12. botgauge_tracing-0.1.0/src/botgauge/tracing/_context.py +162 -0
  13. botgauge_tracing-0.1.0/src/botgauge/tracing/_discovery.py +916 -0
  14. botgauge_tracing-0.1.0/src/botgauge/tracing/_env.py +31 -0
  15. botgauge_tracing-0.1.0/src/botgauge/tracing/_filter_processor.py +284 -0
  16. botgauge_tracing-0.1.0/src/botgauge/tracing/_isolation.py +67 -0
  17. botgauge_tracing-0.1.0/src/botgauge/tracing/_links.py +49 -0
  18. botgauge_tracing-0.1.0/src/botgauge/tracing/_native_producers.py +98 -0
  19. botgauge_tracing-0.1.0/src/botgauge/tracing/_privacy.py +3747 -0
  20. botgauge_tracing-0.1.0/src/botgauge/tracing/_processor.py +133 -0
  21. botgauge_tracing-0.1.0/src/botgauge/tracing/_producer_overlap.py +240 -0
  22. botgauge_tracing-0.1.0/src/botgauge/tracing/_propagation.py +77 -0
  23. botgauge_tracing-0.1.0/src/botgauge/tracing/_provider.py +1458 -0
  24. botgauge_tracing-0.1.0/src/botgauge/tracing/_scope.py +82 -0
  25. botgauge_tracing-0.1.0/src/botgauge/tracing/_shutdown.py +271 -0
  26. botgauge_tracing-0.1.0/src/botgauge/tracing/_skeleton.py +218 -0
  27. botgauge_tracing-0.1.0/src/botgauge/tracing/_topology.py +871 -0
  28. botgauge_tracing-0.1.0/src/botgauge/tracing/_turn.py +133 -0
  29. botgauge_tracing-0.1.0/src/botgauge/tracing/certified_profiles.v1.json +144 -0
  30. botgauge_tracing-0.1.0/src/botgauge/tracing/doctor.py +318 -0
  31. botgauge_tracing-0.1.0/src/botgauge/tracing/launcher/__init__.py +6 -0
  32. botgauge_tracing-0.1.0/src/botgauge/tracing/launcher/_bootstrap.py +375 -0
  33. botgauge_tracing-0.1.0/src/botgauge/tracing/launcher/_cli.py +251 -0
  34. botgauge_tracing-0.1.0/src/botgauge/tracing/launcher/_pythonpath.py +34 -0
  35. botgauge_tracing-0.1.0/src/botgauge/tracing/launcher/sitecustomize.py +47 -0
  36. botgauge_tracing-0.1.0/src/botgauge/tracing/probe.py +98 -0
  37. botgauge_tracing-0.1.0/src/botgauge/tracing/producer_compat.v1.json +170 -0
  38. botgauge_tracing-0.1.0/src/botgauge/tracing/py.typed +0 -0
  39. botgauge_tracing-0.1.0/src/botgauge/tracing/setup.py +64 -0
  40. botgauge_tracing-0.1.0/src/botgauge_tracing.egg-info/PKG-INFO +457 -0
  41. botgauge_tracing-0.1.0/src/botgauge_tracing.egg-info/SOURCES.txt +43 -0
  42. botgauge_tracing-0.1.0/src/botgauge_tracing.egg-info/dependency_links.txt +1 -0
  43. botgauge_tracing-0.1.0/src/botgauge_tracing.egg-info/entry_points.txt +8 -0
  44. botgauge_tracing-0.1.0/src/botgauge_tracing.egg-info/requires.txt +53 -0
  45. botgauge_tracing-0.1.0/src/botgauge_tracing.egg-info/top_level.txt +1 -0
@@ -0,0 +1,105 @@
1
+ # Functional Source License, Version 1.1, ALv2 Future License
2
+
3
+ ## Abbreviation
4
+
5
+ FSL-1.1-ALv2
6
+
7
+ ## Notice
8
+
9
+ Copyright 2026 BotGauge AI Inc.
10
+
11
+ ## Terms and Conditions
12
+
13
+ ### Licensor ("We")
14
+
15
+ The party offering the Software under these Terms and Conditions.
16
+
17
+ ### The Software
18
+
19
+ The "Software" is each version of the software that we make available under
20
+ these Terms and Conditions, as indicated by our inclusion of these Terms and
21
+ Conditions with the Software.
22
+
23
+ ### License Grant
24
+
25
+ Subject to your compliance with this License Grant and the Patents,
26
+ Redistribution and Trademark clauses below, we hereby grant you the right to
27
+ use, copy, modify, create derivative works, publicly perform, publicly display
28
+ and redistribute the Software for any Permitted Purpose identified below.
29
+
30
+ ### Permitted Purpose
31
+
32
+ A Permitted Purpose is any purpose other than a Competing Use. A Competing Use
33
+ means making the Software available to others in a commercial product or
34
+ service that:
35
+
36
+ 1. substitutes for the Software;
37
+
38
+ 2. substitutes for any other product or service we offer using the Software
39
+ that exists as of the date we make the Software available; or
40
+
41
+ 3. offers the same or substantially similar functionality as the Software.
42
+
43
+ Permitted Purposes specifically include using the Software:
44
+
45
+ 1. for your internal use and access;
46
+
47
+ 2. for non-commercial education;
48
+
49
+ 3. for non-commercial research; and
50
+
51
+ 4. in connection with professional services that you provide to a licensee
52
+ using the Software in accordance with these Terms and Conditions.
53
+
54
+ ### Patents
55
+
56
+ To the extent your use for a Permitted Purpose would necessarily infringe our
57
+ patents, the license grant above includes a license under our patents. If you
58
+ make a claim against any party that the Software infringes or contributes to
59
+ the infringement of any patent, then your patent license to the Software ends
60
+ immediately.
61
+
62
+ ### Redistribution
63
+
64
+ The Terms and Conditions apply to all copies, modifications and derivatives of
65
+ the Software.
66
+
67
+ If you redistribute any copies, modifications or derivatives of the Software,
68
+ you must include a copy of or a link to these Terms and Conditions and not
69
+ remove any copyright notices provided in or with the Software.
70
+
71
+ ### Disclaimer
72
+
73
+ THE SOFTWARE IS PROVIDED "AS IS" AND WITHOUT WARRANTIES OF ANY KIND, EXPRESS OR
74
+ IMPLIED, INCLUDING WITHOUT LIMITATION WARRANTIES OF FITNESS FOR A PARTICULAR
75
+ PURPOSE, MERCHANTABILITY, TITLE OR NON-INFRINGEMENT.
76
+
77
+ IN NO EVENT WILL WE HAVE ANY LIABILITY TO YOU ARISING OUT OF OR RELATED TO THE
78
+ SOFTWARE, INCLUDING INDIRECT, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES,
79
+ EVEN IF WE HAVE BEEN INFORMED OF THEIR POSSIBILITY IN ADVANCE.
80
+
81
+ ### Trademarks
82
+
83
+ Except for displaying the License Details and identifying us as the origin of
84
+ the Software, you have no right under these Terms and Conditions to use our
85
+ trademarks, trade names, service marks or product names.
86
+
87
+ ## Grant of Future License
88
+
89
+ We hereby irrevocably grant you an additional license to use the Software under
90
+ the Apache License, Version 2.0 that is effective on the second anniversary of
91
+ the date we make the Software available. On or after that date, you may use the
92
+ Software under the Apache License, Version 2.0, in which case the following
93
+ will apply:
94
+
95
+ Licensed under the Apache License, Version 2.0 (the "License"); you may not use
96
+ this file except in compliance with the License.
97
+
98
+ You may obtain a copy of the License at
99
+
100
+ http://www.apache.org/licenses/LICENSE-2.0
101
+
102
+ Unless required by applicable law or agreed to in writing, software distributed
103
+ under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
104
+ CONDITIONS OF ANY KIND, either express or implied. See the License for the
105
+ specific language governing permissions and limitations under the License.
@@ -0,0 +1,3 @@
1
+ # The sdist carries the package source only. Tests live in the repository; their fixtures are not
2
+ # packaged, so shipping the test files would ship tests that cannot run.
3
+ prune tests
@@ -0,0 +1,457 @@
1
+ Metadata-Version: 2.4
2
+ Name: botgauge-tracing
3
+ Version: 0.1.0
4
+ Summary: BotGauge captures AI-agent traces safely and privately without slowing the customer's application. Manual SDK tracing, zero-code instrumentation, and distributed trace propagation, built on OpenTelemetry.
5
+ Author-email: "BotGauge AI Inc." <support@botgauge.com>
6
+ License-Expression: FSL-1.1-ALv2
7
+ Project-URL: Homepage, https://www.botgauge.com/
8
+ Keywords: opentelemetry,otel,tracing,observability,llm,llm-observability,ai-agents,agents,langchain,openai,crewai,monitoring
9
+ Classifier: Development Status :: 4 - Beta
10
+ Classifier: Intended Audience :: Developers
11
+ Classifier: Framework :: OpenTelemetry
12
+ Classifier: Framework :: OpenTelemetry :: Distros
13
+ Classifier: Programming Language :: Python :: 3 :: Only
14
+ Classifier: Programming Language :: Python :: 3.10
15
+ Classifier: Programming Language :: Python :: 3.11
16
+ Classifier: Programming Language :: Python :: 3.12
17
+ Classifier: Programming Language :: Python :: 3.13
18
+ Classifier: Programming Language :: Python :: 3.14
19
+ Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
20
+ Classifier: Topic :: Software Development :: Libraries :: Python Modules
21
+ Classifier: Topic :: System :: Monitoring
22
+ Classifier: Typing :: Typed
23
+ Requires-Python: >=3.10
24
+ Description-Content-Type: text/markdown
25
+ License-File: LICENSE
26
+ Requires-Dist: botgauge-cli==0.1.0
27
+ Requires-Dist: opentelemetry-api>=1.26
28
+ Requires-Dist: opentelemetry-sdk>=1.26
29
+ Requires-Dist: opentelemetry-exporter-otlp-proto-http>=1.26
30
+ Provides-Extra: openai
31
+ Requires-Dist: openinference-instrumentation-openai==0.1.65; extra == "openai"
32
+ Provides-Extra: anthropic
33
+ Requires-Dist: openinference-instrumentation-anthropic==3.0.3; extra == "anthropic"
34
+ Provides-Extra: langchain
35
+ Requires-Dist: openinference-instrumentation-langchain==0.1.79; extra == "langchain"
36
+ Provides-Extra: langgraph
37
+ Requires-Dist: openinference-instrumentation-langchain==0.1.79; extra == "langgraph"
38
+ Provides-Extra: crewai
39
+ Requires-Dist: openinference-instrumentation-crewai==1.1.21; extra == "crewai"
40
+ Requires-Dist: openinference-instrumentation-openai==0.1.65; extra == "crewai"
41
+ Provides-Extra: llamaindex
42
+ Requires-Dist: openinference-instrumentation-llama-index==4.6.0; extra == "llamaindex"
43
+ Provides-Extra: google-adk
44
+ Requires-Dist: openinference-instrumentation-google-adk==1.0.4; extra == "google-adk"
45
+ Provides-Extra: openai-agents
46
+ Requires-Dist: openinference-instrumentation-openai-agents==2.5.3; extra == "openai-agents"
47
+ Provides-Extra: autogen-agentchat
48
+ Requires-Dist: openinference-instrumentation-autogen-agentchat==0.1.22; extra == "autogen-agentchat"
49
+ Provides-Extra: pydantic-ai
50
+ Requires-Dist: openinference-instrumentation-pydantic-ai==0.1.30; extra == "pydantic-ai"
51
+ Provides-Extra: mcp
52
+ Requires-Dist: openinference-instrumentation-mcp==2.0.13; extra == "mcp"
53
+ Provides-Extra: distributed
54
+ Requires-Dist: opentelemetry-instrumentation-requests>=0.40b0; extra == "distributed"
55
+ Requires-Dist: opentelemetry-instrumentation-httpx>=0.40b0; extra == "distributed"
56
+ Requires-Dist: opentelemetry-instrumentation-urllib3>=0.40b0; extra == "distributed"
57
+ Requires-Dist: opentelemetry-instrumentation-asgi>=0.40b0; extra == "distributed"
58
+ Requires-Dist: opentelemetry-instrumentation-wsgi>=0.40b0; extra == "distributed"
59
+ Requires-Dist: opentelemetry-instrumentation-fastapi>=0.40b0; extra == "distributed"
60
+ Requires-Dist: opentelemetry-instrumentation-starlette>=0.40b0; extra == "distributed"
61
+ Requires-Dist: opentelemetry-instrumentation-flask>=0.40b0; extra == "distributed"
62
+ Requires-Dist: opentelemetry-instrumentation-django>=0.40b0; extra == "distributed"
63
+ Requires-Dist: opentelemetry-instrumentation-grpc>=0.40b0; extra == "distributed"
64
+ Provides-Extra: frameworks
65
+ Requires-Dist: botgauge-tracing[anthropic,autogen-agentchat,crewai,distributed,google-adk,langchain,llamaindex,mcp,openai,openai-agents,pydantic-ai]; extra == "frameworks"
66
+ Dynamic: license-file
67
+
68
+ # botgauge-tracing
69
+
70
+ **Status: early release (0.x). Public API shapes may still change before 1.0. Every framework in
71
+ `producer_compat.v1.json` has a pinned, isolated certification test; combined or overlapping
72
+ producer profiles are not verified.**
73
+
74
+ > BotGauge captures AI-agent traces safely and privately without slowing the customer's
75
+ > application.
76
+
77
+ This is the `botgauge-tracing` distribution, the BotGauge tracing SDK, built
78
+ on stock OpenTelemetry (`opentelemetry-api`/`-sdk`/`-exporter-otlp-proto-http`; the only BotGauge
79
+ dependency is `botgauge-cli`, which provides the command). Customers install it through the `botgauge` meta-package
80
+ (`pip install botgauge`, extras forwarded: `pip install "botgauge[langchain]"`) and import it as
81
+ `from botgauge import tracing`; `botgauge` is a PEP 420 namespace that other BotGauge packages
82
+ join. Its commands (`instrument`, `doctor`, `probe`, `setup`) run
83
+ through the `botgauge` command, which belongs to `botgauge-cli` (a standard-library-only dependency);
84
+ apart from that it depends only on OpenTelemetry.
85
+
86
+ ## What works today
87
+
88
+ ### Manual SDK tracing
89
+
90
+ ```python
91
+ from botgauge import tracing
92
+
93
+ tracing.init(api_key="...") # or set BOTGAUGE_API_KEY and call tracing.init()
94
+
95
+ with tracing.turn(session_id="ses_123"):
96
+ with tracing.agent("billing-agent"):
97
+ tracer = tracing.get_tracer()
98
+ with tracer.start_as_current_span("check_balance"):
99
+ ...
100
+
101
+ tracing.flush()
102
+ tracing.shutdown()
103
+ ```
104
+
105
+ **Streaming generators:** Keep a `turn()` scope within one execution context. Do not
106
+ leave it open across `yield` when a framework may resume each chunk in a fresh
107
+ context (for example, a synchronous generator consumed through Starlette's thread
108
+ pool). Later chunks can lose their turn and parent span, and closing the scope can
109
+ log `Failed to detach context`. Finish traced work before yielding, or keep the
110
+ entire iteration in one context. If chunks run in separate contexts, start and end
111
+ each tracing scope within the context that processes that chunk; preserving one Turn
112
+ across the whole stream requires the application to preserve its context as well.
113
+
114
+ `init()` sends the key as `Authorization: Bearer <key>`, BotGauge's only credential. An
115
+ `Authorization` header passed in `headers=` replaces it. Arguments win over the environment:
116
+ without `api_key=` or `endpoint=`, `init()` reads `BOTGAUGE_API_KEY` / `BOTGAUGE_ENDPOINT`, and a key with no
117
+ endpoint exports to `https://api.botgauge.com/v1/traces`. It never reads `.env` files (load them
118
+ in your app, e.g. with python-dotenv) or `OTEL_EXPORTER_OTLP_*`. The first 401/403 from the
119
+ endpoint logs one `botgauge: BotGauge rejected the API key (...)` line with the server's reason.
120
+ The line names the Authorization header instead when `headers=` supplied it, and says that no
121
+ credential was sent when an endpoint is set without a key.
122
+
123
+ BotGauge disables export when a key or custom headers would be sent to a remote `http://`
124
+ endpoint, or to an endpoint with no `http://` or `https://` scheme. Local HTTP collectors remain
125
+ available. Use `https://` for remote collectors, and add a scheme to an endpoint that has none. If
126
+ you deliberately need remote cleartext HTTP, set `BOTGAUGE_ALLOW_INSECURE_HTTP=true`; BotGauge
127
+ still warns that the connection sends headers without transport encryption. Ambiguous URL
128
+ authorities are treated as remote.
129
+
130
+ With neither a key nor an endpoint, BotGauge emits a configuration notice to stderr and
131
+ discards its exports; it does not print spans. For local development only, set
132
+ `BOTGAUGE_CONSOLE_EXPORT=1` to explicitly send sanitized spans to stdout. A customer-owned
133
+ OTel exporter attached to the same provider continues to operate independently.
134
+
135
+ - One real OTel engine — no custom span class, no custom ID minting, no custom OTLP encoder.
136
+ - Never blocks the calling thread: spans export through a `BatchSpanProcessor`, off-thread.
137
+ - `tracing.agent()`/`tracing.turn()` stamp the frozen, dotted attribute names (see
138
+ `src/botgauge/tracing/_attributes.py`) onto every span created inside them.
139
+ - Attaches to an existing `TracerProvider` (bring-your-own-OTel) rather than replacing it, and
140
+ never creates a second one if one is already active.
141
+ - `flush()`/`shutdown()` enforce a hard deadline — a stuck exporter can't hang your process.
142
+ - A FULL/SKELETON/DROP topology filter keeps generic infrastructure spans (HTTP transport,
143
+ database calls) out of your trace by default, bridging only what's structurally necessary to
144
+ connect Agent→Agent hops (`BOTGAUGE_TRACE_SCOPE=all` to see everything).
145
+ - Privacy: `capture="metadata"|"text"|"full"` and `redacted=True|False`.
146
+ Defaults are `capture="text", redacted=True`: prompts, responses and tool data, but no images,
147
+ audio or embedding vectors (most tracing platforms keep media bytes out of spans by default;
148
+ `capture="full"` exports them inline when you ask for it). `metadata` selects structural attributes
149
+ (IDs, models, timing, usage counts, HTTP/RPC/DB structure); `text` adds readable prompts,
150
+ responses, tools, errors, events, and link attributes while excluding recognized media and
151
+ embedding vectors; `full` captures all supported content. With `redacted=True`, background
152
+ cleaning masks detected PII and credentials only. Harmless SQL, URL parameters/fragments,
153
+ exception details, custom metadata, names, and scope versions remain readable when selected.
154
+ Sensitive values within SQL, DB URLs, URLs, events, and links are cleaned without hiding the
155
+ complete record. The configured key (`api_key=`, or a Bearer token passed in `headers=`) is
156
+ removed from protected export copies.
157
+ To select extra metadata keys, use `capture_allow_keys=["app.tenant_tier", "myco.*"]` or
158
+ `BOTGAUGE_CAPTURE_ALLOW_KEYS=app.tenant_tier,myco.*`; protected values are still cleaned.
159
+ **`redacted=False` overrides capture selection in every mode**: metadata/false, text/false,
160
+ and full/false export the same original supported FULL records, including sensitive data,
161
+ without privacy scanning, masking, or sanitizer truncation. FULL/SKELETON/DROP topology
162
+ filtering still applies; skeletons remain minimal. Raw export cannot recover content already
163
+ discarded by a customer-owned producer or exceed OTel's supported data types and limits.
164
+ BotGauge-owned producers use capture controls matching the resolved policy; raw configuration
165
+ disables BotGauge's own content hiding. Your `OPENINFERENCE_HIDE_*` settings still apply to them
166
+ in every mode and can only hide more. Customer-owned instrumentation and exporters remain intact.
167
+ Privacy patterns do not detect every sensitive fact or credential format. Protected values
168
+ retain documented technical size/work limits. Supported numeric PII is inspected across
169
+ integers, integral floats, numeric strings, and serialized structures. Recognized numeric
170
+ usage, cost, and duration measurements retain their values and types; arbitrary numeric IDs
171
+ still receive PII inspection. A subtree beyond the sanitizer's depth limit is replaced by
172
+ `[omitted: inspection limit]`, indicating a technical omission rather than detected PII.
173
+ Native containers have an 8-level limit and parsed structures a 64-level limit. String caps
174
+ and sequence caps can truncate content separately: a list keeps its first 128 elements, and a
175
+ map its first 128 entries plus an `[omitted: inspection limit]` entry counting the rest. These
176
+ sanitizer limits do not apply with `redacted=False`. Metadata omissions and text media
177
+ exclusions are capture selection, separate from sensitive-value masking.
178
+ Zero-code settings are `BOTGAUGE_CAPTURE=metadata|text|full` and
179
+ `BOTGAUGE_REDACTED=true|false`. Invalid capture values, including the previous `redacted`
180
+ spelling, fall back to protected metadata. Migrate to `capture="text", redacted=True`.
181
+ Invalid boolean environment values enable protection. Reconfigure export policy through
182
+ `shutdown()` and a new `init()`; restart zero-code processes to change producer capture
183
+ controls. Forks preserve both settings. `doctor` reports requested/effective capture
184
+ and protection without payloads or credentials.
185
+ - With a customer `ConcurrentMultiSpanProcessor`, BotGauge runs its own start callbacks
186
+ through a caller-context bridge, preserving Agent/Revision/Session/Turn identity and the
187
+ customer's existing processor chain. The bridge is restored on shutdown; `doctor` reports
188
+ whether it is active.
189
+ - Zero BotGauge baggage, ever. Standard W3C trace-context propagation only — your own propagator
190
+ and baggage are never touched or replaced.
191
+
192
+ ### Zero-code instrumentation
193
+
194
+ ```bash
195
+ pip install "botgauge[langchain]" # install only the producer you need
196
+ export BOTGAUGE_API_KEY="..."
197
+ # export BOTGAUGE_ENDPOINT="https://your-collector/v1/traces" # only for a collector other than BotGauge's
198
+ botgauge instrument python your_app.py
199
+ ```
200
+
201
+ `botg` is a short alias for `botgauge` (`botg instrument python your_app.py`); `botgauge help` lists every
202
+ command the installed BotGauge packages provide.
203
+
204
+ Or keep the settings in a `.env` file: `botgauge instrument --env-file .env python your_app.py`.
205
+ It reads `KEY=VALUE` lines the way `uv run --env-file` and `docker run --env-file` do: comments,
206
+ an optional `export ` prefix, and quotes are handled, and variables aren't expanded. It never
207
+ overrides a variable that is already set, so real deployment settings win. The flag can be
208
+ repeated; an earlier file wins over a later one. Manual `tracing.init()` does not read `.env`;
209
+ load it in your app (e.g. with python-dotenv).
210
+
211
+ Run each capture mode separately with protection enabled. Use the virtual environment containing
212
+ the updated SDK and your application's dependencies, with the endpoint/API-key settings above:
213
+
214
+ ```bash
215
+ BOTGAUGE_CAPTURE=metadata BOTGAUGE_REDACTED=true botgauge instrument python your_app.py
216
+
217
+ BOTGAUGE_CAPTURE=text BOTGAUGE_REDACTED=true botgauge instrument python your_app.py
218
+
219
+ BOTGAUGE_CAPTURE=full BOTGAUGE_REDACTED=true botgauge instrument python your_app.py
220
+ ```
221
+
222
+ Replace `your_app.py` with your script. Each command starts a new process. Metadata selects
223
+ structural content, text adds readable text while excluding recognized media/vectors, and full
224
+ selects all supported content. With `BOTGAUGE_REDACTED=true`, selected content receives sensitive
225
+ value cleaning. Setting `BOTGAUGE_REDACTED=false` enables original supported FULL content in all
226
+ three modes, bypassing their capture exclusions and privacy cleaning.
227
+
228
+ Zero-code export reads only `BOTGAUGE_ENDPOINT` (default `https://api.botgauge.com/v1/traces`
229
+ when `BOTGAUGE_API_KEY` is set) for its destination. Customer
230
+ `OTEL_EXPORTER_OTLP_*` settings are left to the customer's OTel exporters in both
231
+ directions: BotGauge never uses them as a fallback destination for its connection token, and
232
+ BotGauge's own exporter ignores them, so customer collector headers, TLS files, timeout, and
233
+ compression are never applied to BotGauge export (which always uses gzip). With neither
234
+ variable set, BotGauge export is disabled by default and a configuration notice is
235
+ written to stderr; the explicit development-only `BOTGAUGE_CONSOLE_EXPORT=1` setting
236
+ still enables console output.
237
+
238
+ Selects certified framework producers from the versioned compatibility registry and activates
239
+ compatible OTel transport instrumentors via standard `opentelemetry_instrumentor` entry points.
240
+ The registry covers pinned LangChain/LangGraph, direct OpenAI, direct Anthropic,
241
+ LlamaIndex+OpenAI, CrewAI, OpenAI Agents, Google ADK, AutoGen AgentChat and MCP (each with only its own producer).
242
+ Certification records the versions BotGauge verified, as (framework, instrumentor) pairs: a
243
+ framework version is verified only with an instrumentor version it passed certification with. Only
244
+ those exact pairs are verified, never a range: a version older than the oldest verified, between
245
+ two verified versions, newer than the latest verified, or a pre-release is not verified. Verified
246
+ pairs stay verified when newer ones are added. It is not a requirement. An installed framework at
247
+ a version that isn't verified is still traced, and startup logs one line per framework saying why:
248
+ `botgauge: tracing openai at a version BotGauge has not verified: openai 3.40.0 is newer than the
249
+ latest version BotGauge verified (3.35.1); verified: ...`. Inside the app,
250
+ `tracing.doctor.report()["instrumentors"]["not_verified"]` returns them; a separate `botgauge doctor`
251
+ process cannot see the app's activation. Set `BOTGAUGE_VERIFIED_ONLY=1` to trace only verified
252
+ versions. Versions the registry lists as known to break tracing are never traced, and startup says
253
+ why. AI instrumentors that aren't in the registry are still skipped.
254
+ BotGauge checks
255
+ the public OTel already-instrumented marker and supports explicit customer ownership via
256
+ `BOTGAUGE_PRODUCER_OWNER=langchain=customer`. Set `BOTGAUGE_STRICT=1` to make selection failures
257
+ and versions that aren't verified fatal for CI (or use `botgauge instrument --strict python your_app.py`):
258
+ the launcher logs `botgauge: --strict: not starting the application: <reasons>` and exits 1
259
+ before the app runs. Ownership also accepts registered entry-point names such as
260
+ `llama_index=customer` (the canonical target is `llamaindex`); unknown names produce a warning.
261
+ A producer that traces several frameworks (the LangChain instrumentor also traces LangGraph) stays
262
+ off when the customer owns any of them; the others are then not traced by BotGauge, so they are not
263
+ reported as not verified, and importing one logs missing-producer guidance that names that ownership.
264
+ An installed producer extra without its framework is reported as `absent` and does not fail
265
+ strict mode. Resolve actual selection findings or disable strict mode; setting
266
+ `BOTGAUGE_VERIFIED_ONLY=1` alone does not clear strict failures. Strict mode also stops the app
267
+ if the target Python cannot import BotGauge
268
+ or if interpreter options `-I`, `-E`, or `-S` would bypass the startup hook. When an app imports a
269
+ registered framework without an active producer, startup logs one recommendation for the
270
+ BotGauge extra, or points to `botgauge doctor` if the extra is installed but did not activate. Client
271
+ libraries that frameworks import themselves (`openai`, `anthropic`, `mcp`) get no hint while a
272
+ framework producer is active, so `--strict` does not fail a correctly traced framework app;
273
+ importing `langchain_core` (as `langchain_openai` does) counts as importing LangChain. Unknown
274
+ frameworks are not guessed.
275
+ If a missing producer is discovered on a later framework import, strict mode logs the
276
+ guidance and exits the whole process with code 1, including when the import occurs in a
277
+ worker thread; the application may already have started by then.
278
+ Selected instrumentors use the same FULL/SKELETON/DROP filtering and privacy
279
+ pipeline. Works with `python -m pkg`, any `python3.x` binary, sibling imports next to your script,
280
+ and child processes your app spawns (they inherit instrumentation the same way `gunicorn --preload`
281
+ workers would). The directory you run `botgauge instrument` from is importable by the launched app,
282
+ after the standard library and installed packages so it can't shadow them. Unlike
283
+ `opentelemetry-instrument`, it is not put on `PYTHONPATH`: child processes don't inherit it, a
284
+ `sitecustomize.py` in it is never run, and `python -P` or `PYTHONSAFEPATH` keep it off the path.
285
+
286
+ Zero-code mode opens an implicit Turn only at a top-level certified **Agent** span, with no
287
+ active `tracing.turn()` and no inbound remote parent. An app that only runs
288
+ chains or LLM calls (a plain LangChain `prompt | llm`, or a LangGraph graph, whose root span is a
289
+ CHAIN) produces no Agent span, so its spans carry no `botgauge.turn.*` attributes; wrap each
290
+ interaction in `tracing.turn()` to group it. An Agent label set after a span starts is read when a
291
+ nested Agent decides whether it is top-level, but a label set on an outer span only after a nested
292
+ Agent's Turn decision (at its start, or at its end if it was labelled late) cannot move the root back
293
+ to the outer span; set the outer Agent's label at start, or use `tracing.turn()`.
294
+
295
+ Forking servers (`gunicorn --preload`, multiprocessing): under `botgauge instrument`, each forked
296
+ worker rebuilds its own BotGauge pipeline automatically (new exporter connection and batch thread,
297
+ same settings), so the application needs no `post_fork` hook. With manual `tracing.init()`, call
298
+ `init()` again after the fork, as before. Either way, a fork-context `multiprocessing` or billiard worker sends
299
+ its queued spans when it exits normally, waiting at most one second (none when export is already
300
+ failing). A pool closed with `terminate()`, which includes leaving a `with Pool(...) as pool:` block,
301
+ stops its workers before that, so their spans are lost: use `pool.close()` and `pool.join()`, or
302
+ call `tracing.flush()` at the end of each task. On macOS only, a forked worker that makes any HTTP request
303
+ after the parent has started threads is killed by the Objective-C runtime; this affects preload apps
304
+ with or without BotGauge, and not Linux. For local development on macOS, set
305
+ `OBJC_DISABLE_INITIALIZE_FORK_SAFETY=YES` in the server's environment.
306
+
307
+ PydanticAI is a zero-code producer at its verified versions (PydanticAI 1.25.1 and 2.57.0 with
308
+ `openinference-instrumentation-pydantic-ai` 0.1.30, and 1.25.1 with 0.1.27). It instruments itself natively and
309
+ OpenInference ships a span processor rather than an instrumentor, so BotGauge activates it
310
+ through its own `botgauge.native_producers` entry point: `botgauge instrument` calls
311
+ `Agent.instrument_all()` on BotGauge's provider (GenAI span names, text content recorded with
312
+ `capture="text"` or `"full"`, and with every raw override) and attaches `OpenInferenceSpanProcessor`. If your application already
313
+ instruments PydanticAI, BotGauge reports a duplicate and leaves it unchanged; set
314
+ `BOTGAUGE_PRODUCER_OWNER=pydantic-ai=customer` to declare that ownership explicitly. The PydanticAI 1.25
315
+ cohort runs on OTel 1.39.1, which conflicts with the currently tested non-PydanticAI multi-extra
316
+ OTel 1.44.0 constraints. A resolver dry-run with only PydanticAI's OTel 1.39.1 constraints
317
+ succeeds for `[frameworks]` (every instrumentor at once), but no installed combined runtime,
318
+ `pip check`, or framework tests have been validated. Do not infer that `[frameworks]` or a mixed
319
+ PydanticAI producer is verified merely
320
+ because the extra resolves.
321
+
322
+ ```bash
323
+ botgauge doctor # read-only report: what's active, what's missing, no side effects
324
+ botgauge doctor --strict # exit 1 for uninitialized tracing, propagation or selection problems
325
+ botgauge doctor --json # the same read-only report as machine-readable JSON
326
+ ```
327
+
328
+ `doctor` observes only the current process: running it separately from your app cannot inspect
329
+ the app's activation report. `doctor --strict` does not emit a probe span or mutate instrumentation.
330
+
331
+ `botgauge setup --detect` lists recommended producer extras without importing frameworks or installing anything. `botgauge setup --install` explicitly installs the listed extras with pip; no automatic installation occurs on startup.
332
+
333
+ `tracing.init(sample_ratio=0.5)` enables opt-in head sampling for a provider BotGauge creates; default is record everything, unless `OTEL_TRACES_SAMPLER` is set, in which case BotGauge says so at startup (see [Configuration](#configuration)). With the default sampler and with `sample_ratio` (both parent-based, as in OpenTelemetry), a request that continues a caller's trace follows the caller's sampling decision (the last two characters of its `traceparent`): `-00` is not recorded, and `-01` is recorded whatever `sample_ratio` says. An `OTEL_TRACES_SAMPLER` that isn't parent-based, such as `always_on` or `traceidratio`, decides on its own. For a service with untrusted callers, see [Public edges](#public-edges). After `shutdown()`, re-initialization may specify the same ratio for that BotGauge-created global provider. A different ratio or an existing customer provider is rejected because its sampler cannot be changed. A head-dropped trace can't be recovered downstream, and policy/authority/verifier evidence must never depend on sampling. Protected string attribute values are capped at 4096 characters after secret sanitization (only the first 5120 characters are inspected, so sanitizer cost stays bounded; the rest is discarded); TTFT/streaming fields are reserved in the attributes contract but not automatically measured by these isolated producers.
334
+
335
+ ### Explicit ingest diagnostic
336
+
337
+ ```bash
338
+ BOTGAUGE_API_KEY="..." botgauge probe --endpoint https://your-collector/v1/traces
339
+ ```
340
+
341
+ Unlike `doctor`, **`probe` sends data**: one metadata-only `botgauge.probe` span through the
342
+ BotGauge privacy/filter/batch pipeline to the specified OTLP HTTP endpoint. It requires an
343
+ explicit URL (no console fallback), runs in its own process, and exits nonzero if ingest
344
+ acceptance cannot be confirmed. A success confirms OTLP export was acknowledged, **not** that a
345
+ downstream worker normalized or stored the span. The key is read from the environment, not CLI
346
+ arguments. Never point it at production without authorization; it creates a real trace.
347
+
348
+ ## Configuration
349
+
350
+ ### BotGauge environment variables
351
+
352
+ Arguments to `tracing.init()` win over these. "Both" means `tracing.init()` and
353
+ `botgauge instrument`; "instrument" means only the zero-code launcher reads it (with `init()`, use
354
+ the matching argument).
355
+
356
+ | Variable | Read by | Default | Effect |
357
+ |---|---|---|---|
358
+ | `BOTGAUGE_API_KEY` | Both | unset | Your BotGauge key, sent only as `Authorization: Bearer <key>`. The one setting you need |
359
+ | `BOTGAUGE_ENDPOINT` | Both | `https://api.botgauge.com/v1/traces` when a key is set | Full OTLP/HTTP traces URL of the collector to send to |
360
+ | `BOTGAUGE_CAPTURE` | instrument | `text` | `metadata`, `text` or `full`; see the privacy notes above |
361
+ | `BOTGAUGE_REDACTED` | instrument | `true` | `false` exports the selected content without masking |
362
+ | `BOTGAUGE_CAPTURE_ALLOW_KEYS` | Both | empty | Comma-separated extra attribute keys to keep, globs allowed (`app.tenant_tier,myco.*`); merged with `capture_allow_keys=` |
363
+ | `BOTGAUGE_TRACE_SCOPE` | Both | filtered | `all` exports infrastructure spans (HTTP, database) in full instead of filtering them |
364
+ | `BOTGAUGE_STRICT` | instrument | off | `1` stops the app from starting on instrumentation problems (same as `--strict`) |
365
+ | `BOTGAUGE_VERIFIED_ONLY` | instrument | off | `1` traces only framework versions BotGauge verified |
366
+ | `BOTGAUGE_PRODUCER_OWNER` | instrument | empty | `langchain=customer` (comma-separated) leaves a framework you already instrument to you |
367
+ | `BOTGAUGE_ALLOW_INSECURE_HTTP` | Both | `false` | `true` allows sending the key to a remote `http://` endpoint. Local addresses need no opt-in |
368
+ | `BOTGAUGE_CONSOLE_EXPORT` | Both | off | `1` prints spans to stdout when no key or endpoint is set. Local development only |
369
+
370
+ ### OpenTelemetry environment variables
371
+
372
+ BotGauge is built on the OpenTelemetry SDK, so some standard variables affect it too. Where a row
373
+ says "when BotGauge creates the provider", it applies when you call `tracing.init()` without
374
+ `tracer_provider=` and no provider is set up yet; otherwise your own provider's configuration
375
+ applies.
376
+
377
+ | Variable | Effect on BotGauge |
378
+ |---|---|
379
+ | `OTEL_SDK_DISABLED=true` | **Turns tracing off.** No spans are recorded or exported, with or without your own provider. Use it to disable BotGauge in tests or one environment without changing code |
380
+ | `OTEL_SERVICE_NAME`, `OTEL_RESOURCE_ATTRIBUTES` | Added to the exported resource when BotGauge creates the provider |
381
+ | `OTEL_TRACES_SAMPLER`, `OTEL_TRACES_SAMPLER_ARG` | Apply when BotGauge creates the provider and `sample_ratio=` is not given. A sampler set for another tool therefore samples BotGauge's traces too; BotGauge prints a one-time warning at startup when it will drop traces, and `botgauge doctor` shows the active sampler. Pass `sample_ratio=1.0` to record everything regardless |
382
+ | `OTEL_BSP_SCHEDULE_DELAY`, `OTEL_BSP_MAX_QUEUE_SIZE`, `OTEL_BSP_MAX_EXPORT_BATCH_SIZE`, `OTEL_BSP_EXPORT_TIMEOUT` | Tune the batching of BotGauge's own export. An unusable value is logged once on the `botgauge` logger and OpenTelemetry's default is used |
383
+ | `OTEL_ATTRIBUTE_VALUE_LENGTH_LIMIT` and the other span limit variables | Apply when BotGauge creates the provider. Protected string values are already capped at 4096 characters |
384
+ | `OTEL_PROPAGATORS` | Which headers carry trace context between services. BotGauge never replaces your propagator. For a service with untrusted callers, see [Public edges](#public-edges). The values for this and the sampler variables are in [OpenTelemetry's SDK configuration](https://opentelemetry.io/docs/languages/sdk-configuration/general/) |
385
+ | `OTEL_EXPORTER_OTLP_*` | **Ignored** by BotGauge's exporter. They stay with your own exporters, which never receive the BotGauge key |
386
+
387
+ ### Logs
388
+
389
+ BotGauge reports problems (a rejected key, an invalid setting, an untraced framework) as warnings on
390
+ the standard Python logger named `botgauge`. Route or silence them like any other logger, for
391
+ example `logging.getLogger("botgauge").setLevel(logging.ERROR)`. For a full picture of what is
392
+ active, run `botgauge doctor`, or call `tracing.doctor.report()` inside your app.
393
+
394
+ ## Public edges
395
+
396
+ If your application accepts requests from an untrusted or public caller, that caller's own
397
+ `traceparent` header should not be trusted as the real parent span — an attacker could otherwise
398
+ inject an arbitrary trace/span ID with no authority consequences intended.
399
+
400
+ **If the service runs server or MCP instrumentation, turn off incoming trace context for the
401
+ whole process.** That includes `botgauge instrument` and any web framework instrumentation you add
402
+ (Flask, Django, FastAPI and other ASGI/WSGI servers, gRPC). These start the request's span from the
403
+ caller's `traceparent`, and the MCP instrumentation from a request's `_meta` field, over stdio as
404
+ well as HTTP, before your code runs. So the caller decides:
405
+
406
+ - the trace ID of everything the request records;
407
+ - whether the request is recorded at all: with OpenTelemetry's default sampler, a `traceparent`
408
+ ending in `-00` turns recording off for the whole request, and `-01` turns it on whatever
409
+ `sample_ratio` says.
410
+
411
+ `extract_context()` (below) can't undo this, because the caller's context is already current when
412
+ it runs. Turn incoming trace context off instead:
413
+
414
+ - `OTEL_PROPAGATORS=none`, on OpenTelemetry 1.33 or newer. Older versions don't accept `none` and
415
+ stop at startup with "Propagator none not found".
416
+ - On any version, once at startup:
417
+ ```python
418
+ from opentelemetry.propagate import set_global_textmap
419
+ from opentelemetry.propagators.composite import CompositePropagator
420
+
421
+ set_global_textmap(CompositePropagator([]))
422
+ ```
423
+
424
+ Both also stop the service sending trace context to the services it calls, so use them only in
425
+ processes that face untrusted callers. For HTTP only, removing `traceparent`, `tracestate` and
426
+ `baggage` from incoming requests in middleware that runs before the instrumentation also works.
427
+
428
+ **Without server or MCP instrumentation**, where your code reads the headers itself, extract
429
+ context at that specific boundary (e.g. one public-facing route, not your whole process) with
430
+ `trust_incoming_context=False`:
431
+
432
+ ```python
433
+ from botgauge import tracing
434
+
435
+ ctx, link = tracing.extract_context(request.headers, trust_incoming_context=False)
436
+ tracer = tracing.get_tracer()
437
+ with tracer.start_as_current_span("handle_request", context=ctx, links=[link] if link else []):
438
+ ...
439
+ ```
440
+
441
+ With `trust_incoming_context=False`, `extract_context()` retains the current local context for parenting
442
+ and returns a link to a valid incoming span. The example attaches that link with
443
+ `botgauge.link.relation="continuation"`; the untrusted claim is not used as the parent. A new
444
+ trace starts only when no valid local parent is active. Internal/trusted service-to-service
445
+ hops should keep the default (`trust_incoming_context=True`), which is what most calls need.
446
+
447
+ ## Known limits
448
+
449
+ - Each framework is verified on its own, at the exact versions the getting-started guide lists.
450
+ Combined or overlapping producer profiles are not verified.
451
+ - A direct OpenAI + Anthropic mixed-producer test covers shared turn context and
452
+ duplicate/ownership handling. With LangChain and direct OpenAI both active, explicit ownership
453
+ emits one LLM span; activating both producers emits two sibling LLM spans on the same client.
454
+ - PydanticAI 1.25.1 needs OpenTelemetry 1.39.1 in an isolated environment, so it is not part of
455
+ the compatible multi-extra set.
456
+ - A nightly job tests the latest framework versions; a passing drift test never expands the
457
+ pinned compatibility registry by itself.