tracectrl-enterprise 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.
- tracectrl_enterprise-0.1.0/.gitignore +50 -0
- tracectrl_enterprise-0.1.0/LICENSE +190 -0
- tracectrl_enterprise-0.1.0/PKG-INFO +110 -0
- tracectrl_enterprise-0.1.0/README.md +82 -0
- tracectrl_enterprise-0.1.0/pyproject.toml +72 -0
- tracectrl_enterprise-0.1.0/src/tracectrl_enterprise/__init__.py +25 -0
- tracectrl_enterprise-0.1.0/src/tracectrl_enterprise/_version.py +8 -0
- tracectrl_enterprise-0.1.0/src/tracectrl_enterprise/api.py +144 -0
- tracectrl_enterprise-0.1.0/src/tracectrl_enterprise/config.py +78 -0
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
# Python
|
|
2
|
+
__pycache__/
|
|
3
|
+
*.py[cod]
|
|
4
|
+
*.egg-info/
|
|
5
|
+
*.egg
|
|
6
|
+
dist/
|
|
7
|
+
build/
|
|
8
|
+
.venv/
|
|
9
|
+
venv/
|
|
10
|
+
.pytest_cache/
|
|
11
|
+
.ruff_cache/
|
|
12
|
+
|
|
13
|
+
# Node
|
|
14
|
+
node_modules/
|
|
15
|
+
ui/dist/
|
|
16
|
+
|
|
17
|
+
# Environment
|
|
18
|
+
.env
|
|
19
|
+
|
|
20
|
+
# IDE
|
|
21
|
+
.vscode/
|
|
22
|
+
.idea/
|
|
23
|
+
*.swp
|
|
24
|
+
*.swo
|
|
25
|
+
.DS_Store
|
|
26
|
+
|
|
27
|
+
# Docker
|
|
28
|
+
clickhouse-data/
|
|
29
|
+
|
|
30
|
+
# Internal planning docs (docs/ itself IS tracked — it's the shared team+agent docs)
|
|
31
|
+
docs/launch-plan.md
|
|
32
|
+
docs/meetings-actionables-for-launch.md
|
|
33
|
+
docs/licensing-study.md
|
|
34
|
+
docs/*.pdf
|
|
35
|
+
|
|
36
|
+
# Agent skills (installed via `skills add`)
|
|
37
|
+
.agents/
|
|
38
|
+
.claude/
|
|
39
|
+
.kiro/
|
|
40
|
+
skills/
|
|
41
|
+
skills-lock.json
|
|
42
|
+
|
|
43
|
+
videos/
|
|
44
|
+
.mcp.json
|
|
45
|
+
|
|
46
|
+
# Personal Folder
|
|
47
|
+
dylan-todo/
|
|
48
|
+
|
|
49
|
+
# OCB-generated collector distribution (built from collector/builder-config.yaml)
|
|
50
|
+
collector/_build/
|
|
@@ -0,0 +1,190 @@
|
|
|
1
|
+
Apache License
|
|
2
|
+
Version 2.0, January 2004
|
|
3
|
+
http://www.apache.org/licenses/
|
|
4
|
+
|
|
5
|
+
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
|
6
|
+
|
|
7
|
+
1. Definitions.
|
|
8
|
+
|
|
9
|
+
"License" shall mean the terms and conditions for use, reproduction,
|
|
10
|
+
and distribution as defined by Sections 1 through 9 of this document.
|
|
11
|
+
|
|
12
|
+
"Licensor" shall mean the copyright owner or entity authorized by
|
|
13
|
+
the copyright owner that is granting the License.
|
|
14
|
+
|
|
15
|
+
"Legal Entity" shall mean the union of the acting entity and all
|
|
16
|
+
other entities that control, are controlled by, or are under common
|
|
17
|
+
control with that entity. For the purposes of this definition,
|
|
18
|
+
"control" means (i) the power, direct or indirect, to cause the
|
|
19
|
+
direction or management of such entity, whether by contract or
|
|
20
|
+
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
|
21
|
+
outstanding shares, or (iii) beneficial ownership of such entity.
|
|
22
|
+
|
|
23
|
+
"You" (or "Your") shall mean an individual or Legal Entity
|
|
24
|
+
exercising permissions granted by this License.
|
|
25
|
+
|
|
26
|
+
"Source" form shall mean the preferred form for making modifications,
|
|
27
|
+
including but not limited to software source code, documentation
|
|
28
|
+
source, and configuration files.
|
|
29
|
+
|
|
30
|
+
"Object" form shall mean any form resulting from mechanical
|
|
31
|
+
transformation or translation of a Source form, including but
|
|
32
|
+
not limited to compiled object code, generated documentation,
|
|
33
|
+
and conversions to other media types.
|
|
34
|
+
|
|
35
|
+
"Work" shall mean the work of authorship, whether in Source or
|
|
36
|
+
Object form, made available under the License, as indicated by a
|
|
37
|
+
copyright notice that is included in or attached to the work
|
|
38
|
+
(an example is provided in the Appendix below).
|
|
39
|
+
|
|
40
|
+
"Derivative Works" shall mean any work, whether in Source or Object
|
|
41
|
+
form, that is based on (or derived from) the Work and for which the
|
|
42
|
+
editorial revisions, annotations, elaborations, or other modifications
|
|
43
|
+
represent, as a whole, an original work of authorship. For the purposes
|
|
44
|
+
of this License, Derivative Works shall not include works that remain
|
|
45
|
+
separable from, or merely link (or bind by name) to the interfaces of,
|
|
46
|
+
the Work and Derivative Works thereof.
|
|
47
|
+
|
|
48
|
+
"Contribution" shall mean any work of authorship, including
|
|
49
|
+
the original version of the Work and any modifications or additions
|
|
50
|
+
to that Work or Derivative Works thereof, that is intentionally
|
|
51
|
+
submitted to Licensor for inclusion in the Work by the copyright owner
|
|
52
|
+
or by an individual or Legal Entity authorized to submit on behalf of
|
|
53
|
+
the copyright owner. For the purposes of this definition, "submitted"
|
|
54
|
+
means any form of electronic, verbal, or written communication sent
|
|
55
|
+
to the Licensor or its representatives, including but not limited to
|
|
56
|
+
communication on electronic mailing lists, source code control systems,
|
|
57
|
+
and issue tracking systems that are managed by, or on behalf of, the
|
|
58
|
+
Licensor for the purpose of discussing and improving the Work, but
|
|
59
|
+
excluding communication that is conspicuously marked or otherwise
|
|
60
|
+
designated in writing by the copyright owner as "Not a Contribution."
|
|
61
|
+
|
|
62
|
+
"Contributor" shall mean Licensor and any individual or Legal Entity
|
|
63
|
+
on behalf of whom a Contribution has been received by Licensor and
|
|
64
|
+
subsequently incorporated within the Work.
|
|
65
|
+
|
|
66
|
+
2. Grant of Copyright License. Subject to the terms and conditions of
|
|
67
|
+
this License, each Contributor hereby grants to You a perpetual,
|
|
68
|
+
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
|
69
|
+
copyright license to reproduce, prepare Derivative Works of,
|
|
70
|
+
publicly display, publicly perform, sublicense, and distribute the
|
|
71
|
+
Work and such Derivative Works in Source or Object form.
|
|
72
|
+
|
|
73
|
+
3. Grant of Patent License. Subject to the terms and conditions of
|
|
74
|
+
this License, each Contributor hereby grants to You a perpetual,
|
|
75
|
+
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
|
76
|
+
(except as stated in this section) patent license to make, have made,
|
|
77
|
+
use, offer to sell, sell, import, and otherwise transfer the Work,
|
|
78
|
+
where such license applies only to those patent claims licensable
|
|
79
|
+
by such Contributor that are necessarily infringed by their
|
|
80
|
+
Contribution(s) alone or by combination of their Contribution(s)
|
|
81
|
+
with the Work to which such Contribution(s) was submitted. If You
|
|
82
|
+
institute patent litigation against any entity (including a
|
|
83
|
+
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
|
84
|
+
or a Contribution incorporated within the Work constitutes direct
|
|
85
|
+
or contributory patent infringement, then any patent licenses
|
|
86
|
+
granted to You under this License for that Work shall terminate
|
|
87
|
+
as of the date such litigation is filed.
|
|
88
|
+
|
|
89
|
+
4. Redistribution. You may reproduce and distribute copies of the
|
|
90
|
+
Work or Derivative Works thereof in any medium, with or without
|
|
91
|
+
modifications, and in Source or Object form, provided that You
|
|
92
|
+
meet the following conditions:
|
|
93
|
+
|
|
94
|
+
(a) You must give any other recipients of the Work or
|
|
95
|
+
Derivative Works a copy of this License; and
|
|
96
|
+
|
|
97
|
+
(b) You must cause any modified files to carry prominent notices
|
|
98
|
+
stating that You changed the files; and
|
|
99
|
+
|
|
100
|
+
(c) You must retain, in the Source form of any Derivative Works
|
|
101
|
+
that You distribute, all copyright, patent, trademark, and
|
|
102
|
+
attribution notices from the Source form of the Work,
|
|
103
|
+
excluding those notices that do not pertain to any part of
|
|
104
|
+
the Derivative Works; and
|
|
105
|
+
|
|
106
|
+
(d) If the Work includes a "NOTICE" text file as part of its
|
|
107
|
+
distribution, then any Derivative Works that You distribute must
|
|
108
|
+
include a readable copy of the attribution notices contained
|
|
109
|
+
within such NOTICE file, excluding those notices that do not
|
|
110
|
+
pertain to any part of the Derivative Works, in at least one
|
|
111
|
+
of the following places: within a NOTICE text file distributed
|
|
112
|
+
as part of the Derivative Works; within the Source form or
|
|
113
|
+
documentation, if provided along with the Derivative Works; or,
|
|
114
|
+
within a display generated by the Derivative Works, if and
|
|
115
|
+
wherever such third-party notices normally appear. The contents
|
|
116
|
+
of the NOTICE file are for informational purposes only and
|
|
117
|
+
do not modify the License. You may add Your own attribution
|
|
118
|
+
notices within Derivative Works that You distribute, alongside
|
|
119
|
+
or as an addendum to the NOTICE text from the Work, provided
|
|
120
|
+
that such additional attribution notices cannot be construed
|
|
121
|
+
as modifying the License.
|
|
122
|
+
|
|
123
|
+
You may add Your own copyright statement to Your modifications and
|
|
124
|
+
may provide additional or different license terms and conditions
|
|
125
|
+
for use, reproduction, or distribution of Your modifications, or
|
|
126
|
+
for any such Derivative Works as a whole, provided Your use,
|
|
127
|
+
reproduction, and distribution of the Work otherwise complies with
|
|
128
|
+
the conditions stated in this License.
|
|
129
|
+
|
|
130
|
+
5. Submission of Contributions. Unless You explicitly state otherwise,
|
|
131
|
+
any Contribution intentionally submitted for inclusion in the Work
|
|
132
|
+
by You to the Licensor shall be under the terms and conditions of
|
|
133
|
+
this License, without any additional terms or conditions.
|
|
134
|
+
Notwithstanding the above, nothing herein shall supersede or modify
|
|
135
|
+
the terms of any separate license agreement you may have executed
|
|
136
|
+
with Licensor regarding such Contributions.
|
|
137
|
+
|
|
138
|
+
6. Trademarks. This License does not grant permission to use the trade
|
|
139
|
+
names, trademarks, service marks, or product names of the Licensor,
|
|
140
|
+
except as required for describing the origin of the Work and
|
|
141
|
+
reproducing the content of the NOTICE file.
|
|
142
|
+
|
|
143
|
+
7. Disclaimer of Warranty. Unless required by applicable law or
|
|
144
|
+
agreed to in writing, Licensor provides the Work (and each
|
|
145
|
+
Contributor provides its Contributions) on an "AS IS" BASIS,
|
|
146
|
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
|
147
|
+
implied, including, without limitation, any warranties or conditions
|
|
148
|
+
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
|
149
|
+
PARTICULAR PURPOSE. You are solely responsible for determining the
|
|
150
|
+
appropriateness of using or redistributing the Work and assume any
|
|
151
|
+
risks associated with Your exercise of permissions under this License.
|
|
152
|
+
|
|
153
|
+
8. Limitation of Liability. In no event and under no legal theory,
|
|
154
|
+
whether in tort (including negligence), contract, or otherwise,
|
|
155
|
+
unless required by applicable law (such as deliberate and grossly
|
|
156
|
+
negligent acts) or agreed to in writing, shall any Contributor be
|
|
157
|
+
liable to You for damages, including any direct, indirect, special,
|
|
158
|
+
incidental, or consequential damages of any character arising as a
|
|
159
|
+
result of this License or out of the use or inability to use the
|
|
160
|
+
Work (including but not limited to damages for loss of goodwill,
|
|
161
|
+
work stoppage, computer failure or malfunction, or any and all
|
|
162
|
+
other commercial damages or losses), even if such Contributor
|
|
163
|
+
has been advised of the possibility of such damages.
|
|
164
|
+
|
|
165
|
+
9. Accepting Warranty or Support. While redistributing the Work or
|
|
166
|
+
Derivative Works thereof, You may choose to offer, and charge a
|
|
167
|
+
fee for, acceptance of support, warranty, indemnity, or other
|
|
168
|
+
liability obligations and/or rights consistent with this License.
|
|
169
|
+
However, in accepting such obligations, You may act only on Your
|
|
170
|
+
own behalf and on Your sole responsibility, not on behalf of any
|
|
171
|
+
other Contributor, and only if You agree to indemnify, defend,
|
|
172
|
+
and hold each Contributor harmless for any liability incurred by,
|
|
173
|
+
or claims asserted against, such Contributor by reason of your
|
|
174
|
+
accepting any such warranty or support.
|
|
175
|
+
|
|
176
|
+
END OF TERMS AND CONDITIONS
|
|
177
|
+
|
|
178
|
+
Copyright 2026 CloudsineAI
|
|
179
|
+
|
|
180
|
+
Licensed under the Apache License, Version 2.0 (the "License");
|
|
181
|
+
you may not use this file except in compliance with the License.
|
|
182
|
+
You may obtain a copy of the License at
|
|
183
|
+
|
|
184
|
+
http://www.apache.org/licenses/LICENSE-2.0
|
|
185
|
+
|
|
186
|
+
Unless required by applicable law or agreed to in writing, software
|
|
187
|
+
distributed under the License is distributed on an "AS IS" BASIS,
|
|
188
|
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
189
|
+
See the License for the specific language governing permissions and
|
|
190
|
+
limitations under the License.
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: tracectrl-enterprise
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: TraceCtrl Enterprise SDK — agentic AI security observability for the enterprise platform
|
|
5
|
+
Project-URL: Homepage, https://tracectrl.ai
|
|
6
|
+
Project-URL: Repository, https://github.com/tracectrl/tracectrl-enterprise
|
|
7
|
+
Project-URL: Documentation, https://github.com/tracectrl/tracectrl-enterprise/blob/main/sdk/tracectrl-enterprise/README.md
|
|
8
|
+
Author: CloudsineAI
|
|
9
|
+
License-Expression: Apache-2.0
|
|
10
|
+
License-File: LICENSE
|
|
11
|
+
Keywords: agents,ai,observability,opentelemetry,security
|
|
12
|
+
Classifier: Development Status :: 3 - Alpha
|
|
13
|
+
Classifier: License :: OSI Approved :: Apache Software License
|
|
14
|
+
Classifier: Programming Language :: Python :: 3
|
|
15
|
+
Classifier: Programming Language :: Python :: 3 :: Only
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
20
|
+
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
21
|
+
Classifier: Topic :: System :: Monitoring
|
|
22
|
+
Requires-Python: >=3.10
|
|
23
|
+
Requires-Dist: tracectrl<0.4,>=0.3
|
|
24
|
+
Provides-Extra: dev
|
|
25
|
+
Requires-Dist: pytest>=8.0; extra == 'dev'
|
|
26
|
+
Requires-Dist: ruff>=0.6; extra == 'dev'
|
|
27
|
+
Description-Content-Type: text/markdown
|
|
28
|
+
|
|
29
|
+
# tracectrl-enterprise
|
|
30
|
+
|
|
31
|
+
TraceCtrl Enterprise SDK — instrument your agentic AI application to send traces
|
|
32
|
+
to a TraceCtrl Enterprise deployment.
|
|
33
|
+
|
|
34
|
+
Apache 2.0 licensed. Thin wrapper over the OSS [`tracectrl`](https://pypi.org/project/tracectrl/)
|
|
35
|
+
package — `tracectrl` does the OpenTelemetry SDK heavy lifting; this package
|
|
36
|
+
adds enterprise-specific defaults (collector endpoint, required ingest-key
|
|
37
|
+
auth, fail-loud behaviour) and the `tag_agent()` API for self-identifying
|
|
38
|
+
agent spans.
|
|
39
|
+
|
|
40
|
+
## Install
|
|
41
|
+
|
|
42
|
+
```bash
|
|
43
|
+
pip install tracectrl-enterprise
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
## Quickstart
|
|
47
|
+
|
|
48
|
+
```python
|
|
49
|
+
import os
|
|
50
|
+
from tracectrl_enterprise import configure, tag_agent
|
|
51
|
+
|
|
52
|
+
configure(ingest_key=os.environ["TRACECTRL_INGEST_KEY"])
|
|
53
|
+
|
|
54
|
+
@tag_agent(
|
|
55
|
+
id="payment-bot",
|
|
56
|
+
name="PaymentAgent",
|
|
57
|
+
framework="strands", # framework you're running on; informational
|
|
58
|
+
role="payment_processing",
|
|
59
|
+
)
|
|
60
|
+
def run_payment(query: str) -> str:
|
|
61
|
+
# ... your agent logic ...
|
|
62
|
+
return "ok"
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
Every call to `run_payment` creates an OpenTelemetry span with the canonical
|
|
66
|
+
TraceCtrl attributes (`openinference.span.kind=AGENT`,
|
|
67
|
+
`tracectrl.agent.id`, `tracectrl.agent.name`, etc.), exported via OTLP/gRPC
|
|
68
|
+
with `Authorization: Bearer <ingest_key>` to your TraceCtrl Enterprise
|
|
69
|
+
collector. The collector resolves your ingest key to a tenant and stamps
|
|
70
|
+
`tracectrl.tenant_id` on every span — your SDK doesn't (and can't) set
|
|
71
|
+
tenancy itself; the collector is the trust boundary.
|
|
72
|
+
|
|
73
|
+
## Configuration
|
|
74
|
+
|
|
75
|
+
`configure(ingest_key=..., endpoint=..., service_name=...)` accepts:
|
|
76
|
+
|
|
77
|
+
| Argument | Env var | Default | Required |
|
|
78
|
+
|---|---|---|---|
|
|
79
|
+
| `ingest_key` | `TRACECTRL_INGEST_KEY` | — | **yes** — fails loud if not set |
|
|
80
|
+
| `endpoint` | `TRACECTRL_ENDPOINT` | `https://app.tracectrl.ai/ingest` | no |
|
|
81
|
+
| `service_name` | `TRACECTRL_SERVICE_NAME` | `tracectrl-agent` | no |
|
|
82
|
+
|
|
83
|
+
If you call `configure()` without an `ingest_key` argument, it reads
|
|
84
|
+
`TRACECTRL_INGEST_KEY` from the environment. If neither is set, it raises
|
|
85
|
+
`ValueError` — unlike the OSS SDK which can be configured to fail silently,
|
|
86
|
+
enterprise installs always fail loud on missing auth.
|
|
87
|
+
|
|
88
|
+
## Framework instrumentation
|
|
89
|
+
|
|
90
|
+
For automatic tracing of supported frameworks (Strands, etc.), install the OSS
|
|
91
|
+
instrumentor package alongside this one:
|
|
92
|
+
|
|
93
|
+
```bash
|
|
94
|
+
pip install tracectrl-instrumentation-strands
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
The instrumentor hooks into the same global OpenTelemetry TracerProvider that
|
|
98
|
+
`tracectrl-enterprise.configure()` sets up, so spans from instrumented
|
|
99
|
+
framework calls are exported the same way as your `@tag_agent`-decorated
|
|
100
|
+
functions.
|
|
101
|
+
|
|
102
|
+
## License
|
|
103
|
+
|
|
104
|
+
Apache 2.0. The TraceCtrl Enterprise server-side platform (engine, collector,
|
|
105
|
+
UI) is BUSL-licensed; the SDK is permissively licensed so it can be
|
|
106
|
+
embedded in your proprietary code without restriction.
|
|
107
|
+
|
|
108
|
+
## Reporting issues
|
|
109
|
+
|
|
110
|
+
https://github.com/tracectrl/tracectrl-enterprise/issues
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
# tracectrl-enterprise
|
|
2
|
+
|
|
3
|
+
TraceCtrl Enterprise SDK — instrument your agentic AI application to send traces
|
|
4
|
+
to a TraceCtrl Enterprise deployment.
|
|
5
|
+
|
|
6
|
+
Apache 2.0 licensed. Thin wrapper over the OSS [`tracectrl`](https://pypi.org/project/tracectrl/)
|
|
7
|
+
package — `tracectrl` does the OpenTelemetry SDK heavy lifting; this package
|
|
8
|
+
adds enterprise-specific defaults (collector endpoint, required ingest-key
|
|
9
|
+
auth, fail-loud behaviour) and the `tag_agent()` API for self-identifying
|
|
10
|
+
agent spans.
|
|
11
|
+
|
|
12
|
+
## Install
|
|
13
|
+
|
|
14
|
+
```bash
|
|
15
|
+
pip install tracectrl-enterprise
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
## Quickstart
|
|
19
|
+
|
|
20
|
+
```python
|
|
21
|
+
import os
|
|
22
|
+
from tracectrl_enterprise import configure, tag_agent
|
|
23
|
+
|
|
24
|
+
configure(ingest_key=os.environ["TRACECTRL_INGEST_KEY"])
|
|
25
|
+
|
|
26
|
+
@tag_agent(
|
|
27
|
+
id="payment-bot",
|
|
28
|
+
name="PaymentAgent",
|
|
29
|
+
framework="strands", # framework you're running on; informational
|
|
30
|
+
role="payment_processing",
|
|
31
|
+
)
|
|
32
|
+
def run_payment(query: str) -> str:
|
|
33
|
+
# ... your agent logic ...
|
|
34
|
+
return "ok"
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
Every call to `run_payment` creates an OpenTelemetry span with the canonical
|
|
38
|
+
TraceCtrl attributes (`openinference.span.kind=AGENT`,
|
|
39
|
+
`tracectrl.agent.id`, `tracectrl.agent.name`, etc.), exported via OTLP/gRPC
|
|
40
|
+
with `Authorization: Bearer <ingest_key>` to your TraceCtrl Enterprise
|
|
41
|
+
collector. The collector resolves your ingest key to a tenant and stamps
|
|
42
|
+
`tracectrl.tenant_id` on every span — your SDK doesn't (and can't) set
|
|
43
|
+
tenancy itself; the collector is the trust boundary.
|
|
44
|
+
|
|
45
|
+
## Configuration
|
|
46
|
+
|
|
47
|
+
`configure(ingest_key=..., endpoint=..., service_name=...)` accepts:
|
|
48
|
+
|
|
49
|
+
| Argument | Env var | Default | Required |
|
|
50
|
+
|---|---|---|---|
|
|
51
|
+
| `ingest_key` | `TRACECTRL_INGEST_KEY` | — | **yes** — fails loud if not set |
|
|
52
|
+
| `endpoint` | `TRACECTRL_ENDPOINT` | `https://app.tracectrl.ai/ingest` | no |
|
|
53
|
+
| `service_name` | `TRACECTRL_SERVICE_NAME` | `tracectrl-agent` | no |
|
|
54
|
+
|
|
55
|
+
If you call `configure()` without an `ingest_key` argument, it reads
|
|
56
|
+
`TRACECTRL_INGEST_KEY` from the environment. If neither is set, it raises
|
|
57
|
+
`ValueError` — unlike the OSS SDK which can be configured to fail silently,
|
|
58
|
+
enterprise installs always fail loud on missing auth.
|
|
59
|
+
|
|
60
|
+
## Framework instrumentation
|
|
61
|
+
|
|
62
|
+
For automatic tracing of supported frameworks (Strands, etc.), install the OSS
|
|
63
|
+
instrumentor package alongside this one:
|
|
64
|
+
|
|
65
|
+
```bash
|
|
66
|
+
pip install tracectrl-instrumentation-strands
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
The instrumentor hooks into the same global OpenTelemetry TracerProvider that
|
|
70
|
+
`tracectrl-enterprise.configure()` sets up, so spans from instrumented
|
|
71
|
+
framework calls are exported the same way as your `@tag_agent`-decorated
|
|
72
|
+
functions.
|
|
73
|
+
|
|
74
|
+
## License
|
|
75
|
+
|
|
76
|
+
Apache 2.0. The TraceCtrl Enterprise server-side platform (engine, collector,
|
|
77
|
+
UI) is BUSL-licensed; the SDK is permissively licensed so it can be
|
|
78
|
+
embedded in your proprietary code without restriction.
|
|
79
|
+
|
|
80
|
+
## Reporting issues
|
|
81
|
+
|
|
82
|
+
https://github.com/tracectrl/tracectrl-enterprise/issues
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["hatchling"]
|
|
3
|
+
build-backend = "hatchling.build"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "tracectrl-enterprise"
|
|
7
|
+
description = "TraceCtrl Enterprise SDK — agentic AI security observability for the enterprise platform"
|
|
8
|
+
readme = "README.md"
|
|
9
|
+
requires-python = ">=3.10"
|
|
10
|
+
license = "Apache-2.0"
|
|
11
|
+
license-files = ["LICENSE"]
|
|
12
|
+
authors = [{ name = "CloudsineAI" }]
|
|
13
|
+
keywords = ["opentelemetry", "observability", "agents", "ai", "security"]
|
|
14
|
+
classifiers = [
|
|
15
|
+
"Development Status :: 3 - Alpha",
|
|
16
|
+
"License :: OSI Approved :: Apache Software License",
|
|
17
|
+
"Programming Language :: Python :: 3",
|
|
18
|
+
"Programming Language :: Python :: 3 :: Only",
|
|
19
|
+
"Programming Language :: Python :: 3.10",
|
|
20
|
+
"Programming Language :: Python :: 3.11",
|
|
21
|
+
"Programming Language :: Python :: 3.12",
|
|
22
|
+
"Programming Language :: Python :: 3.13",
|
|
23
|
+
"Topic :: Software Development :: Libraries :: Python Modules",
|
|
24
|
+
"Topic :: System :: Monitoring",
|
|
25
|
+
]
|
|
26
|
+
dynamic = ["version"]
|
|
27
|
+
|
|
28
|
+
# The OSS `tracectrl` core handles every piece of the OTel SDK plumbing —
|
|
29
|
+
# TracerProvider, BatchSpanProcessor, OTLP exporter, attribute marshalling.
|
|
30
|
+
# This package is a thin wrapper that adds the enterprise-specific bits:
|
|
31
|
+
# required ingest-key auth, fail-loud defaults, and the `tag_agent()` API.
|
|
32
|
+
#
|
|
33
|
+
# Pin the OSS minor (>=0.3, <0.4) so semver-compatible bug fixes flow in
|
|
34
|
+
# automatically but a future 0.4.0 with breaking changes can't silently
|
|
35
|
+
# break customer installs. Bump the upper bound deliberately when we
|
|
36
|
+
# qualify against a new OSS minor.
|
|
37
|
+
dependencies = [
|
|
38
|
+
"tracectrl>=0.3,<0.4",
|
|
39
|
+
]
|
|
40
|
+
|
|
41
|
+
[project.optional-dependencies]
|
|
42
|
+
# `dev` is for SDK contributors (us). Customers don't install this.
|
|
43
|
+
dev = [
|
|
44
|
+
"pytest>=8.0",
|
|
45
|
+
"ruff>=0.6",
|
|
46
|
+
]
|
|
47
|
+
|
|
48
|
+
[project.urls]
|
|
49
|
+
Homepage = "https://tracectrl.ai"
|
|
50
|
+
Repository = "https://github.com/tracectrl/tracectrl-enterprise"
|
|
51
|
+
Documentation = "https://github.com/tracectrl/tracectrl-enterprise/blob/main/sdk/tracectrl-enterprise/README.md"
|
|
52
|
+
|
|
53
|
+
[tool.hatch.version]
|
|
54
|
+
path = "src/tracectrl_enterprise/_version.py"
|
|
55
|
+
|
|
56
|
+
[tool.hatch.build.targets.wheel]
|
|
57
|
+
packages = ["src/tracectrl_enterprise"]
|
|
58
|
+
|
|
59
|
+
[tool.hatch.build.targets.sdist]
|
|
60
|
+
include = [
|
|
61
|
+
"src/tracectrl_enterprise/**",
|
|
62
|
+
"README.md",
|
|
63
|
+
"LICENSE",
|
|
64
|
+
"pyproject.toml",
|
|
65
|
+
]
|
|
66
|
+
|
|
67
|
+
[tool.ruff]
|
|
68
|
+
line-length = 100
|
|
69
|
+
target-version = "py310"
|
|
70
|
+
|
|
71
|
+
[tool.pytest.ini_options]
|
|
72
|
+
testpaths = ["tests"]
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
"""TraceCtrl Enterprise SDK — public API.
|
|
2
|
+
|
|
3
|
+
Two exports that customers should use:
|
|
4
|
+
|
|
5
|
+
from tracectrl_enterprise import configure, tag_agent
|
|
6
|
+
|
|
7
|
+
`configure()` initialises the OpenTelemetry pipeline against the enterprise
|
|
8
|
+
collector with a required ingest key.
|
|
9
|
+
|
|
10
|
+
`tag_agent()` is a decorator (and context manager) that wraps an agent
|
|
11
|
+
function/block to emit a span with the canonical TraceCtrl attribute set —
|
|
12
|
+
`openinference.span.kind=AGENT`, `tracectrl.agent.id`, etc. The collector's
|
|
13
|
+
normalize processor relies on these being stamped at the source, not
|
|
14
|
+
reconstructed from heuristics downstream.
|
|
15
|
+
|
|
16
|
+
See README.md for a quickstart and the engine's span attribute contract
|
|
17
|
+
(`docs/project/06-span-attribute-contract.md` in the source repo) for the
|
|
18
|
+
full canonical attribute layout.
|
|
19
|
+
"""
|
|
20
|
+
|
|
21
|
+
from ._version import __version__
|
|
22
|
+
from .api import tag_agent
|
|
23
|
+
from .config import configure
|
|
24
|
+
|
|
25
|
+
__all__ = ["configure", "tag_agent", "__version__"]
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
"""Single source of truth for the package version.
|
|
2
|
+
|
|
3
|
+
Hatchling reads this at build time (see pyproject.toml `[tool.hatch.version]`)
|
|
4
|
+
so the PyPI artifact, the importable `tracectrl_enterprise.__version__`, and
|
|
5
|
+
git tags all stay in lockstep. Bump by editing this file and tagging.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
__version__ = "0.1.0"
|
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
"""The ``tag_agent`` API — self-identifying agent spans.
|
|
2
|
+
|
|
3
|
+
The TraceCtrl Enterprise pipeline relies on the SDK stamping canonical
|
|
4
|
+
attributes at the source so the collector + worker never have to reconstruct
|
|
5
|
+
agent identity from span-name heuristics (which is lossy and rename-fragile).
|
|
6
|
+
See ``docs/project/06-span-attribute-contract.md`` in the source repo for the
|
|
7
|
+
full attribute contract.
|
|
8
|
+
|
|
9
|
+
This module exposes ``tag_agent`` as both a decorator and a context manager:
|
|
10
|
+
|
|
11
|
+
@tag_agent(id="payment-bot", name="PaymentAgent", framework="strands")
|
|
12
|
+
def run_agent(query: str) -> str:
|
|
13
|
+
...
|
|
14
|
+
|
|
15
|
+
with tag_agent(id="payment-bot", name="PaymentAgent", framework="strands"):
|
|
16
|
+
# block-level usage
|
|
17
|
+
...
|
|
18
|
+
|
|
19
|
+
Both forms emit one span per invocation with the canonical TraceCtrl
|
|
20
|
+
attribute set.
|
|
21
|
+
"""
|
|
22
|
+
|
|
23
|
+
from __future__ import annotations
|
|
24
|
+
|
|
25
|
+
import functools
|
|
26
|
+
from contextlib import contextmanager
|
|
27
|
+
from typing import Any, Callable, Iterator
|
|
28
|
+
|
|
29
|
+
from opentelemetry import trace
|
|
30
|
+
|
|
31
|
+
# OpenInference span-kind values — the canonical ``openinference.span.kind``
|
|
32
|
+
# attribute. ``AGENT`` is what every agent span carries; the rest are stamped
|
|
33
|
+
# by other helpers (e.g. tool-call decorators we may add later) or by the
|
|
34
|
+
# OSS framework instrumentors.
|
|
35
|
+
SPAN_KIND_AGENT = "AGENT"
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
def tag_agent(
|
|
39
|
+
*,
|
|
40
|
+
id: str,
|
|
41
|
+
name: str,
|
|
42
|
+
framework: str,
|
|
43
|
+
role: str | None = None,
|
|
44
|
+
session_id: str | None = None,
|
|
45
|
+
):
|
|
46
|
+
"""Mark a function or block as an agent invocation.
|
|
47
|
+
|
|
48
|
+
Stamps the canonical attribute set the TraceCtrl collector's normalize
|
|
49
|
+
processor expects:
|
|
50
|
+
|
|
51
|
+
* ``openinference.span.kind = "AGENT"``
|
|
52
|
+
* ``tracectrl.agent.id`` = ``id``
|
|
53
|
+
* ``tracectrl.agent.name`` = ``name``
|
|
54
|
+
* ``tracectrl.agent.framework`` = ``framework``
|
|
55
|
+
* ``tracectrl.agent.role`` = ``role`` (if given)
|
|
56
|
+
* ``tracectrl.session_id`` = ``session_id`` (if given)
|
|
57
|
+
|
|
58
|
+
Args:
|
|
59
|
+
id: Stable agent identifier (e.g. "payment-bot"). Used for inventory +
|
|
60
|
+
topology aggregation; must be deterministic across runs.
|
|
61
|
+
name: Human-readable name surfaced in the UI.
|
|
62
|
+
framework: Agent framework name (e.g. "strands", "agno", "langchain").
|
|
63
|
+
role: Optional free-form role/purpose label.
|
|
64
|
+
session_id: Optional session identifier for multi-turn grouping. Pass
|
|
65
|
+
the customer's own conversation/session id (e.g. a chat thread id)
|
|
66
|
+
to group all spans from that session together.
|
|
67
|
+
|
|
68
|
+
Returns:
|
|
69
|
+
A callable that's either a decorator (when used as ``@tag_agent(...)``)
|
|
70
|
+
or a context manager (when used in a ``with`` statement) — same
|
|
71
|
+
object, both protocols.
|
|
72
|
+
"""
|
|
73
|
+
# Build the attribute dict once; the same span attributes apply to every
|
|
74
|
+
# invocation. Empty values are omitted so the collector's normalize
|
|
75
|
+
# processor doesn't see "" and treat it as a real value.
|
|
76
|
+
span_attrs: dict[str, Any] = {
|
|
77
|
+
"openinference.span.kind": SPAN_KIND_AGENT,
|
|
78
|
+
"tracectrl.agent.id": id,
|
|
79
|
+
"tracectrl.agent.name": name,
|
|
80
|
+
"tracectrl.agent.framework": framework,
|
|
81
|
+
}
|
|
82
|
+
if role:
|
|
83
|
+
span_attrs["tracectrl.agent.role"] = role
|
|
84
|
+
if session_id:
|
|
85
|
+
span_attrs["tracectrl.session_id"] = session_id
|
|
86
|
+
|
|
87
|
+
# The span name surfaces in the trace UI as the operation label. Use a
|
|
88
|
+
# deterministic format so it's easy to grep / group in the dashboard.
|
|
89
|
+
span_name = f"agent:{id}"
|
|
90
|
+
|
|
91
|
+
return _AgentTagger(span_name=span_name, attributes=span_attrs)
|
|
92
|
+
|
|
93
|
+
|
|
94
|
+
class _AgentTagger:
|
|
95
|
+
"""Dual decorator + context manager produced by ``tag_agent``.
|
|
96
|
+
|
|
97
|
+
Customers never instantiate this directly; ``tag_agent(...)`` returns it.
|
|
98
|
+
Implementing ``__call__`` enables the decorator syntax; ``__enter__`` /
|
|
99
|
+
``__exit__`` enable the ``with`` syntax.
|
|
100
|
+
"""
|
|
101
|
+
|
|
102
|
+
def __init__(self, span_name: str, attributes: dict[str, Any]) -> None:
|
|
103
|
+
self._span_name = span_name
|
|
104
|
+
self._attributes = attributes
|
|
105
|
+
self._cm: Iterator[trace.Span] | None = None
|
|
106
|
+
|
|
107
|
+
# --- decorator path -----------------------------------------------------
|
|
108
|
+
|
|
109
|
+
def __call__(self, fn: Callable[..., Any]) -> Callable[..., Any]:
|
|
110
|
+
"""Decorator: wrap a callable so each call emits a tagged span."""
|
|
111
|
+
|
|
112
|
+
@functools.wraps(fn)
|
|
113
|
+
def wrapper(*args: Any, **kwargs: Any) -> Any:
|
|
114
|
+
with _agent_span(self._span_name, self._attributes):
|
|
115
|
+
return fn(*args, **kwargs)
|
|
116
|
+
|
|
117
|
+
return wrapper
|
|
118
|
+
|
|
119
|
+
# --- context-manager path ----------------------------------------------
|
|
120
|
+
|
|
121
|
+
def __enter__(self) -> trace.Span:
|
|
122
|
+
self._cm = _agent_span(self._span_name, self._attributes)
|
|
123
|
+
return self._cm.__enter__()
|
|
124
|
+
|
|
125
|
+
def __exit__(self, exc_type, exc, tb) -> None:
|
|
126
|
+
assert self._cm is not None
|
|
127
|
+
self._cm.__exit__(exc_type, exc, tb)
|
|
128
|
+
self._cm = None
|
|
129
|
+
|
|
130
|
+
|
|
131
|
+
@contextmanager
|
|
132
|
+
def _agent_span(name: str, attrs: dict[str, Any]) -> Iterator[trace.Span]:
|
|
133
|
+
"""Lowest-level helper: open a span with the canonical attrs, yield, close.
|
|
134
|
+
|
|
135
|
+
Uses the globally-installed TracerProvider set up by ``configure()``. If
|
|
136
|
+
``configure()`` hasn't been called, the OTel SDK falls back to a no-op
|
|
137
|
+
provider — spans are still created but never exported. This matches the
|
|
138
|
+
OSS SDK's permissive default; the cost is only paid if the customer
|
|
139
|
+
forgets to call ``configure()`` (and they'd see no data in the dashboard,
|
|
140
|
+
which is its own loud signal).
|
|
141
|
+
"""
|
|
142
|
+
tracer = trace.get_tracer("tracectrl_enterprise")
|
|
143
|
+
with tracer.start_as_current_span(name, attributes=attrs) as span:
|
|
144
|
+
yield span
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
"""Enterprise configuration entry point.
|
|
2
|
+
|
|
3
|
+
Thin wrapper over OSS ``tracectrl.configure()`` that adds the enterprise
|
|
4
|
+
defaults and policies the customer-facing surface depends on:
|
|
5
|
+
|
|
6
|
+
* **required ingest key** — unauthenticated traffic never reaches the
|
|
7
|
+
enterprise collector (it rejects at the trust boundary). Calling
|
|
8
|
+
``configure()`` without an ingest key raises ``ValueError`` immediately
|
|
9
|
+
rather than silently exporting spans the collector will reject.
|
|
10
|
+
* **enterprise endpoint default** — ``https://app.tracectrl.ai/ingest``
|
|
11
|
+
rather than localhost; overridable for staging or self-hosted deploys.
|
|
12
|
+
* **fail-loud** — OSS supports ``fail_silently=True`` for dev convenience;
|
|
13
|
+
enterprise sets ``False`` so misconfiguration surfaces during local
|
|
14
|
+
testing, not in production.
|
|
15
|
+
|
|
16
|
+
The OSS package does everything else: TracerProvider setup, BatchSpanProcessor,
|
|
17
|
+
OTLP exporter, resource attributes. We import its ``configure`` and delegate.
|
|
18
|
+
"""
|
|
19
|
+
|
|
20
|
+
from __future__ import annotations
|
|
21
|
+
|
|
22
|
+
import os
|
|
23
|
+
|
|
24
|
+
from tracectrl import configure as _oss_configure # type: ignore[import-untyped]
|
|
25
|
+
|
|
26
|
+
# Production collector — the nginx /ingest/ route on the SaaS deploy. Override
|
|
27
|
+
# via VITE-style env var or the `endpoint=` arg for staging / self-hosted.
|
|
28
|
+
DEFAULT_ENDPOINT = "https://app.tracectrl.ai/ingest"
|
|
29
|
+
DEFAULT_SERVICE_NAME = "tracectrl-agent"
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
def configure(
|
|
33
|
+
*,
|
|
34
|
+
ingest_key: str | None = None,
|
|
35
|
+
endpoint: str | None = None,
|
|
36
|
+
service_name: str | None = None,
|
|
37
|
+
) -> None:
|
|
38
|
+
"""Initialise the OpenTelemetry pipeline against TraceCtrl Enterprise.
|
|
39
|
+
|
|
40
|
+
Call once at application startup, before any instrumented code runs.
|
|
41
|
+
|
|
42
|
+
Args:
|
|
43
|
+
ingest_key: The customer's ingest key from the TraceCtrl admin console.
|
|
44
|
+
Reads ``TRACECTRL_INGEST_KEY`` from env if not given. Required;
|
|
45
|
+
raises ``ValueError`` if neither argument nor env is set.
|
|
46
|
+
endpoint: The OTLP/gRPC collector endpoint. Defaults to
|
|
47
|
+
``https://app.tracectrl.ai/ingest``. Override via this argument or
|
|
48
|
+
``TRACECTRL_ENDPOINT`` env var for staging / self-hosted.
|
|
49
|
+
service_name: ``service.name`` resource attribute, surfaces in the
|
|
50
|
+
``ServiceName`` column. Defaults to ``tracectrl-agent``; override via
|
|
51
|
+
this argument or ``TRACECTRL_SERVICE_NAME`` env var.
|
|
52
|
+
|
|
53
|
+
Raises:
|
|
54
|
+
ValueError: if no ingest key is provided.
|
|
55
|
+
"""
|
|
56
|
+
key = ingest_key or os.getenv("TRACECTRL_INGEST_KEY")
|
|
57
|
+
if not key:
|
|
58
|
+
raise ValueError(
|
|
59
|
+
"tracectrl-enterprise requires an ingest key. "
|
|
60
|
+
"Pass ingest_key=... or set TRACECTRL_INGEST_KEY in the environment. "
|
|
61
|
+
"Get one from your TraceCtrl admin console."
|
|
62
|
+
)
|
|
63
|
+
|
|
64
|
+
resolved_endpoint = endpoint or os.getenv("TRACECTRL_ENDPOINT") or DEFAULT_ENDPOINT
|
|
65
|
+
resolved_service = (
|
|
66
|
+
service_name or os.getenv("TRACECTRL_SERVICE_NAME") or DEFAULT_SERVICE_NAME
|
|
67
|
+
)
|
|
68
|
+
|
|
69
|
+
# Delegate to OSS — it handles TracerProvider, BatchSpanProcessor, OTLP
|
|
70
|
+
# exporter wiring. The `api_key` arg becomes the `Authorization: Bearer`
|
|
71
|
+
# header on every OTLP export (OSS reads it and sets the exporter's
|
|
72
|
+
# gRPC metadata).
|
|
73
|
+
_oss_configure(
|
|
74
|
+
endpoint=resolved_endpoint,
|
|
75
|
+
service_name=resolved_service,
|
|
76
|
+
api_key=key,
|
|
77
|
+
fail_silently=False,
|
|
78
|
+
)
|