tracely-sdk 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.
- tracely_sdk-0.1.0/.github/release.yml +34 -0
- tracely_sdk-0.1.0/.github/workflows/ci.yml +30 -0
- tracely_sdk-0.1.0/.github/workflows/release.yml +95 -0
- tracely_sdk-0.1.0/LICENSE +21 -0
- tracely_sdk-0.1.0/PKG-INFO +205 -0
- tracely_sdk-0.1.0/README.md +170 -0
- tracely_sdk-0.1.0/RELEASE_NOTES.md +55 -0
- tracely_sdk-0.1.0/pyproject.toml +55 -0
- tracely_sdk-0.1.0/src/tracely/__init__.py +11 -0
- tracely_sdk-0.1.0/src/tracely/capture.py +210 -0
- tracely_sdk-0.1.0/src/tracely/config.py +39 -0
- tracely_sdk-0.1.0/src/tracely/context.py +55 -0
- tracely_sdk-0.1.0/src/tracely/detection.py +49 -0
- tracely_sdk-0.1.0/src/tracely/exporter.py +120 -0
- tracely_sdk-0.1.0/src/tracely/instrumentation/__init__.py +47 -0
- tracely_sdk-0.1.0/src/tracely/instrumentation/base.py +30 -0
- tracely_sdk-0.1.0/src/tracely/instrumentation/dbapi.py +264 -0
- tracely_sdk-0.1.0/src/tracely/instrumentation/django_inst.py +155 -0
- tracely_sdk-0.1.0/src/tracely/instrumentation/fastapi_inst.py +203 -0
- tracely_sdk-0.1.0/src/tracely/instrumentation/flask_inst.py +215 -0
- tracely_sdk-0.1.0/src/tracely/instrumentation/generic.py +38 -0
- tracely_sdk-0.1.0/src/tracely/instrumentation/httpx_inst.py +130 -0
- tracely_sdk-0.1.0/src/tracely/log_handler.py +55 -0
- tracely_sdk-0.1.0/src/tracely/logging_api.py +38 -0
- tracely_sdk-0.1.0/src/tracely/otlp.py +128 -0
- tracely_sdk-0.1.0/src/tracely/py.typed +0 -0
- tracely_sdk-0.1.0/src/tracely/redaction.py +196 -0
- tracely_sdk-0.1.0/src/tracely/sdk.py +192 -0
- tracely_sdk-0.1.0/src/tracely/span.py +168 -0
- tracely_sdk-0.1.0/src/tracely/span_processor.py +110 -0
- tracely_sdk-0.1.0/src/tracely/tracing.py +59 -0
- tracely_sdk-0.1.0/src/tracely/transport.py +134 -0
- tracely_sdk-0.1.0/tests/test_capture.py +311 -0
- tracely_sdk-0.1.0/tests/test_config.py +104 -0
- tracely_sdk-0.1.0/tests/test_context.py +102 -0
- tracely_sdk-0.1.0/tests/test_custom_span.py +132 -0
- tracely_sdk-0.1.0/tests/test_dbapi.py +290 -0
- tracely_sdk-0.1.0/tests/test_detection.py +143 -0
- tracely_sdk-0.1.0/tests/test_django_inst.py +341 -0
- tracely_sdk-0.1.0/tests/test_exporter.py +217 -0
- tracely_sdk-0.1.0/tests/test_fastapi_inst.py +523 -0
- tracely_sdk-0.1.0/tests/test_flask_inst.py +332 -0
- tracely_sdk-0.1.0/tests/test_generic_inst.py +42 -0
- tracely_sdk-0.1.0/tests/test_httpx_inst.py +218 -0
- tracely_sdk-0.1.0/tests/test_instrumentation.py +143 -0
- tracely_sdk-0.1.0/tests/test_log_handler.py +161 -0
- tracely_sdk-0.1.0/tests/test_otlp.py +303 -0
- tracely_sdk-0.1.0/tests/test_package.py +35 -0
- tracely_sdk-0.1.0/tests/test_performance.py +41 -0
- tracely_sdk-0.1.0/tests/test_pipeline_integration.py +292 -0
- tracely_sdk-0.1.0/tests/test_redaction.py +584 -0
- tracely_sdk-0.1.0/tests/test_sdk.py +115 -0
- tracely_sdk-0.1.0/tests/test_span.py +227 -0
- tracely_sdk-0.1.0/tests/test_span_events.py +206 -0
- tracely_sdk-0.1.0/tests/test_span_processor.py +131 -0
- tracely_sdk-0.1.0/tests/test_transport.py +244 -0
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
changelog:
|
|
2
|
+
exclude:
|
|
3
|
+
labels:
|
|
4
|
+
- skip-changelog
|
|
5
|
+
- dependencies
|
|
6
|
+
authors:
|
|
7
|
+
- dependabot
|
|
8
|
+
- github-actions
|
|
9
|
+
|
|
10
|
+
categories:
|
|
11
|
+
- title: "New Features"
|
|
12
|
+
labels:
|
|
13
|
+
- feature
|
|
14
|
+
- enhancement
|
|
15
|
+
- title: "Bug Fixes"
|
|
16
|
+
labels:
|
|
17
|
+
- bug
|
|
18
|
+
- fix
|
|
19
|
+
- title: "Instrumentation"
|
|
20
|
+
labels:
|
|
21
|
+
- instrumentation
|
|
22
|
+
- fastapi
|
|
23
|
+
- flask
|
|
24
|
+
- django
|
|
25
|
+
- title: "Performance"
|
|
26
|
+
labels:
|
|
27
|
+
- performance
|
|
28
|
+
- title: "Documentation"
|
|
29
|
+
labels:
|
|
30
|
+
- documentation
|
|
31
|
+
- docs
|
|
32
|
+
- title: "Other Changes"
|
|
33
|
+
labels:
|
|
34
|
+
- "*"
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
name: CI
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches: [main]
|
|
6
|
+
pull_request:
|
|
7
|
+
branches: [main]
|
|
8
|
+
|
|
9
|
+
jobs:
|
|
10
|
+
test:
|
|
11
|
+
name: Test (Python ${{ matrix.python-version }})
|
|
12
|
+
runs-on: ubuntu-latest
|
|
13
|
+
strategy:
|
|
14
|
+
matrix:
|
|
15
|
+
python-version: ["3.10", "3.11", "3.12", "3.13"]
|
|
16
|
+
steps:
|
|
17
|
+
- uses: actions/checkout@v4
|
|
18
|
+
|
|
19
|
+
- name: Set up Python ${{ matrix.python-version }}
|
|
20
|
+
uses: actions/setup-python@v5
|
|
21
|
+
with:
|
|
22
|
+
python-version: ${{ matrix.python-version }}
|
|
23
|
+
|
|
24
|
+
- name: Install dependencies
|
|
25
|
+
run: |
|
|
26
|
+
python -m pip install --upgrade pip
|
|
27
|
+
pip install -e ".[dev]"
|
|
28
|
+
|
|
29
|
+
- name: Run tests
|
|
30
|
+
run: python -m pytest tests/ -v --tb=short
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
name: Release to PyPI
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
release:
|
|
5
|
+
types: [published]
|
|
6
|
+
|
|
7
|
+
permissions:
|
|
8
|
+
contents: write
|
|
9
|
+
id-token: write
|
|
10
|
+
|
|
11
|
+
jobs:
|
|
12
|
+
test:
|
|
13
|
+
name: Run tests
|
|
14
|
+
runs-on: ubuntu-latest
|
|
15
|
+
strategy:
|
|
16
|
+
matrix:
|
|
17
|
+
python-version: ["3.10", "3.11", "3.12", "3.13"]
|
|
18
|
+
steps:
|
|
19
|
+
- uses: actions/checkout@v4
|
|
20
|
+
|
|
21
|
+
- name: Set up Python ${{ matrix.python-version }}
|
|
22
|
+
uses: actions/setup-python@v5
|
|
23
|
+
with:
|
|
24
|
+
python-version: ${{ matrix.python-version }}
|
|
25
|
+
|
|
26
|
+
- name: Install dependencies
|
|
27
|
+
run: |
|
|
28
|
+
python -m pip install --upgrade pip
|
|
29
|
+
pip install -e ".[dev]"
|
|
30
|
+
|
|
31
|
+
- name: Run tests
|
|
32
|
+
run: python -m pytest tests/ -v --tb=short
|
|
33
|
+
|
|
34
|
+
build:
|
|
35
|
+
name: Build package
|
|
36
|
+
needs: test
|
|
37
|
+
runs-on: ubuntu-latest
|
|
38
|
+
steps:
|
|
39
|
+
- uses: actions/checkout@v4
|
|
40
|
+
|
|
41
|
+
- name: Set up Python
|
|
42
|
+
uses: actions/setup-python@v5
|
|
43
|
+
with:
|
|
44
|
+
python-version: "3.12"
|
|
45
|
+
|
|
46
|
+
- name: Install build tools
|
|
47
|
+
run: python -m pip install --upgrade pip build
|
|
48
|
+
|
|
49
|
+
- name: Build sdist and wheel
|
|
50
|
+
run: python -m build
|
|
51
|
+
|
|
52
|
+
- name: Upload build artifacts
|
|
53
|
+
uses: actions/upload-artifact@v4
|
|
54
|
+
with:
|
|
55
|
+
name: dist
|
|
56
|
+
path: dist/
|
|
57
|
+
|
|
58
|
+
attach-assets:
|
|
59
|
+
name: Attach build artifacts to release
|
|
60
|
+
needs: build
|
|
61
|
+
runs-on: ubuntu-latest
|
|
62
|
+
permissions:
|
|
63
|
+
contents: write
|
|
64
|
+
steps:
|
|
65
|
+
- name: Download build artifacts
|
|
66
|
+
uses: actions/download-artifact@v4
|
|
67
|
+
with:
|
|
68
|
+
name: dist
|
|
69
|
+
path: dist/
|
|
70
|
+
|
|
71
|
+
- name: Upload assets to GitHub Release
|
|
72
|
+
uses: softprops/action-gh-release@v2
|
|
73
|
+
with:
|
|
74
|
+
files: |
|
|
75
|
+
dist/*.whl
|
|
76
|
+
dist/*.tar.gz
|
|
77
|
+
|
|
78
|
+
publish-pypi:
|
|
79
|
+
name: Publish to PyPI
|
|
80
|
+
needs: build
|
|
81
|
+
runs-on: ubuntu-latest
|
|
82
|
+
environment:
|
|
83
|
+
name: pypi
|
|
84
|
+
url: https://pypi.org/p/tracely-sdk
|
|
85
|
+
steps:
|
|
86
|
+
- name: Download build artifacts
|
|
87
|
+
uses: actions/download-artifact@v4
|
|
88
|
+
with:
|
|
89
|
+
name: dist
|
|
90
|
+
path: dist/
|
|
91
|
+
|
|
92
|
+
- name: Publish to PyPI
|
|
93
|
+
uses: pypa/gh-action-pypi-publish@release/v1
|
|
94
|
+
with:
|
|
95
|
+
password: ${{ secrets.PYPI_API_TOKEN }}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025-2026 Charles Dzadu
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,205 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: tracely-sdk
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Lightweight observability SDK for Python web frameworks. Auto-instruments FastAPI, Flask, and Django with real-time tracing via OTLP/HTTP.
|
|
5
|
+
Project-URL: Homepage, https://tracely.sh
|
|
6
|
+
Project-URL: Documentation, https://docs.tracely.sh
|
|
7
|
+
Project-URL: Repository, https://github.com/TracelyOrg/tracely-sdk
|
|
8
|
+
Project-URL: Issues, https://github.com/TracelyOrg/tracely-sdk/issues
|
|
9
|
+
Author-email: Charles Dzadu <contact@tracely.sh>
|
|
10
|
+
License-Expression: MIT
|
|
11
|
+
License-File: LICENSE
|
|
12
|
+
Keywords: apm,django,fastapi,flask,monitoring,observability,opentelemetry,tracing
|
|
13
|
+
Classifier: Development Status :: 3 - Alpha
|
|
14
|
+
Classifier: Framework :: Django
|
|
15
|
+
Classifier: Framework :: FastAPI
|
|
16
|
+
Classifier: Framework :: Flask
|
|
17
|
+
Classifier: Intended Audience :: Developers
|
|
18
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
19
|
+
Classifier: Programming Language :: Python :: 3
|
|
20
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
21
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
22
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
23
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
24
|
+
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
25
|
+
Classifier: Topic :: System :: Monitoring
|
|
26
|
+
Classifier: Typing :: Typed
|
|
27
|
+
Requires-Python: >=3.10
|
|
28
|
+
Requires-Dist: httpx>=0.27
|
|
29
|
+
Requires-Dist: opentelemetry-proto>=1.20
|
|
30
|
+
Provides-Extra: dev
|
|
31
|
+
Requires-Dist: pytest-asyncio>=0.23; extra == 'dev'
|
|
32
|
+
Requires-Dist: pytest>=8.0; extra == 'dev'
|
|
33
|
+
Requires-Dist: respx>=0.21; extra == 'dev'
|
|
34
|
+
Description-Content-Type: text/markdown
|
|
35
|
+
|
|
36
|
+
# tracely-sdk
|
|
37
|
+
|
|
38
|
+
Lightweight observability SDK for Python web frameworks. Auto-instruments **FastAPI**, **Flask**, and **Django** with real-time distributed tracing via OTLP/HTTP.
|
|
39
|
+
|
|
40
|
+
[](https://pypi.org/project/tracely-sdk/)
|
|
41
|
+
[](https://pypi.org/project/tracely-sdk/)
|
|
42
|
+
[](https://opensource.org/licenses/MIT)
|
|
43
|
+
|
|
44
|
+
## Features
|
|
45
|
+
|
|
46
|
+
- **Zero-config auto-instrumentation** -- detects FastAPI, Flask, and Django automatically
|
|
47
|
+
- **Real-time pending spans** -- see requests the moment they start, not just when they finish
|
|
48
|
+
- **Full request/response capture** -- headers, body, query params with smart redaction
|
|
49
|
+
- **OTLP/HTTP protobuf export** -- standard OpenTelemetry wire format
|
|
50
|
+
- **Batch export with backoff** -- 1s flush interval, exponential retry on failure
|
|
51
|
+
- **Fail-silent design** -- SDK never crashes or degrades your application
|
|
52
|
+
- **Minimal dependencies** -- only `httpx` and `opentelemetry-proto`
|
|
53
|
+
|
|
54
|
+
## Installation
|
|
55
|
+
|
|
56
|
+
```bash
|
|
57
|
+
pip install tracely-sdk
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
## Quick Start
|
|
61
|
+
|
|
62
|
+
### FastAPI
|
|
63
|
+
|
|
64
|
+
```python
|
|
65
|
+
import tracely
|
|
66
|
+
from tracely.instrumentation.fastapi_inst import TracelyASGIMiddleware
|
|
67
|
+
|
|
68
|
+
tracely.init(api_key="trly_your_key_here")
|
|
69
|
+
|
|
70
|
+
from fastapi import FastAPI
|
|
71
|
+
app = FastAPI()
|
|
72
|
+
app.add_middleware(TracelyASGIMiddleware)
|
|
73
|
+
|
|
74
|
+
@app.get("/")
|
|
75
|
+
async def root():
|
|
76
|
+
return {"status": "ok"}
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
### Flask
|
|
80
|
+
|
|
81
|
+
```python
|
|
82
|
+
import tracely
|
|
83
|
+
from tracely.instrumentation.flask_inst import FlaskInstrumentor
|
|
84
|
+
|
|
85
|
+
tracely.init(api_key="trly_your_key_here")
|
|
86
|
+
|
|
87
|
+
from flask import Flask
|
|
88
|
+
app = Flask(__name__)
|
|
89
|
+
app.wsgi_app = FlaskInstrumentor.wrap_app(app.wsgi_app)
|
|
90
|
+
|
|
91
|
+
@app.route("/")
|
|
92
|
+
def root():
|
|
93
|
+
return {"status": "ok"}
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
### Django
|
|
97
|
+
|
|
98
|
+
Add the middleware to your `MIDDLEWARE` setting:
|
|
99
|
+
|
|
100
|
+
```python
|
|
101
|
+
# settings.py
|
|
102
|
+
MIDDLEWARE = [
|
|
103
|
+
"tracely.instrumentation.django_inst.TracelyDjangoMiddleware",
|
|
104
|
+
# ... other middleware
|
|
105
|
+
]
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
Then initialize in your app startup (e.g., `AppConfig.ready()`):
|
|
109
|
+
|
|
110
|
+
```python
|
|
111
|
+
import tracely
|
|
112
|
+
tracely.init(api_key="trly_your_key_here")
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
## Configuration
|
|
116
|
+
|
|
117
|
+
### Environment Variables
|
|
118
|
+
|
|
119
|
+
| Variable | Description | Default |
|
|
120
|
+
|----------|-------------|---------|
|
|
121
|
+
| `TRACELY_API_KEY` | API key for authentication | _(required)_ |
|
|
122
|
+
| `TRACELY_ENDPOINT` | Ingestion API endpoint | `https://i.tracely.sh` |
|
|
123
|
+
| `ENVIRONMENT` | Deployment environment (e.g., `production`) | `None` |
|
|
124
|
+
| `TRACELY_REDACT_FIELDS` | Comma-separated header/field names to redact | `None` |
|
|
125
|
+
|
|
126
|
+
### Programmatic Init
|
|
127
|
+
|
|
128
|
+
```python
|
|
129
|
+
import tracely
|
|
130
|
+
|
|
131
|
+
tracely.init(
|
|
132
|
+
api_key="trly_your_key_here",
|
|
133
|
+
environment="production",
|
|
134
|
+
service_name="my-api",
|
|
135
|
+
service_version="1.0.0",
|
|
136
|
+
)
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
## Custom Spans
|
|
140
|
+
|
|
141
|
+
Create manual spans for custom operations:
|
|
142
|
+
|
|
143
|
+
```python
|
|
144
|
+
import tracely
|
|
145
|
+
|
|
146
|
+
with tracely.span("db-query", kind="CLIENT") as s:
|
|
147
|
+
s.set_attribute("db.system", "postgres")
|
|
148
|
+
s.set_attribute("db.statement", "SELECT * FROM users")
|
|
149
|
+
result = db.execute("SELECT * FROM users")
|
|
150
|
+
```
|
|
151
|
+
|
|
152
|
+
## Span Events (Structured Logging)
|
|
153
|
+
|
|
154
|
+
Attach structured log events to the active span:
|
|
155
|
+
|
|
156
|
+
```python
|
|
157
|
+
import tracely
|
|
158
|
+
|
|
159
|
+
with tracely.span("process-order") as s:
|
|
160
|
+
tracely.info("Order received", order_id="123")
|
|
161
|
+
# ... process
|
|
162
|
+
tracely.debug("Validation passed")
|
|
163
|
+
tracely.warning("Inventory low", sku="WIDGET-42")
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
## Graceful Shutdown
|
|
167
|
+
|
|
168
|
+
Flush buffered spans before exit:
|
|
169
|
+
|
|
170
|
+
```python
|
|
171
|
+
import tracely
|
|
172
|
+
|
|
173
|
+
tracely.init(api_key="trly_your_key_here")
|
|
174
|
+
# ... application runs ...
|
|
175
|
+
tracely.shutdown() # flushes remaining spans
|
|
176
|
+
```
|
|
177
|
+
|
|
178
|
+
## How It Works
|
|
179
|
+
|
|
180
|
+
```
|
|
181
|
+
Your App
|
|
182
|
+
|
|
|
183
|
+
v
|
|
184
|
+
Middleware (FastAPI/Flask/Django)
|
|
185
|
+
|-- on_start --> SpanProcessor --> SpanBuffer (pending_span)
|
|
186
|
+
|-- on_end ----> SpanProcessor --> SpanBuffer (final span)
|
|
187
|
+
|
|
|
188
|
+
v
|
|
189
|
+
BatchSpanExporter (1s interval / 50 span threshold)
|
|
190
|
+
|
|
|
191
|
+
v
|
|
192
|
+
OTLP Protobuf Serialization
|
|
193
|
+
|
|
|
194
|
+
v
|
|
195
|
+
HttpTransport --> TRACELY API
|
|
196
|
+
(retry with exponential backoff)
|
|
197
|
+
```
|
|
198
|
+
|
|
199
|
+
## Documentation
|
|
200
|
+
|
|
201
|
+
Full docs at [docs.tracely.sh](https://docs.tracely.sh)
|
|
202
|
+
|
|
203
|
+
## License
|
|
204
|
+
|
|
205
|
+
MIT
|
|
@@ -0,0 +1,170 @@
|
|
|
1
|
+
# tracely-sdk
|
|
2
|
+
|
|
3
|
+
Lightweight observability SDK for Python web frameworks. Auto-instruments **FastAPI**, **Flask**, and **Django** with real-time distributed tracing via OTLP/HTTP.
|
|
4
|
+
|
|
5
|
+
[](https://pypi.org/project/tracely-sdk/)
|
|
6
|
+
[](https://pypi.org/project/tracely-sdk/)
|
|
7
|
+
[](https://opensource.org/licenses/MIT)
|
|
8
|
+
|
|
9
|
+
## Features
|
|
10
|
+
|
|
11
|
+
- **Zero-config auto-instrumentation** -- detects FastAPI, Flask, and Django automatically
|
|
12
|
+
- **Real-time pending spans** -- see requests the moment they start, not just when they finish
|
|
13
|
+
- **Full request/response capture** -- headers, body, query params with smart redaction
|
|
14
|
+
- **OTLP/HTTP protobuf export** -- standard OpenTelemetry wire format
|
|
15
|
+
- **Batch export with backoff** -- 1s flush interval, exponential retry on failure
|
|
16
|
+
- **Fail-silent design** -- SDK never crashes or degrades your application
|
|
17
|
+
- **Minimal dependencies** -- only `httpx` and `opentelemetry-proto`
|
|
18
|
+
|
|
19
|
+
## Installation
|
|
20
|
+
|
|
21
|
+
```bash
|
|
22
|
+
pip install tracely-sdk
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
## Quick Start
|
|
26
|
+
|
|
27
|
+
### FastAPI
|
|
28
|
+
|
|
29
|
+
```python
|
|
30
|
+
import tracely
|
|
31
|
+
from tracely.instrumentation.fastapi_inst import TracelyASGIMiddleware
|
|
32
|
+
|
|
33
|
+
tracely.init(api_key="trly_your_key_here")
|
|
34
|
+
|
|
35
|
+
from fastapi import FastAPI
|
|
36
|
+
app = FastAPI()
|
|
37
|
+
app.add_middleware(TracelyASGIMiddleware)
|
|
38
|
+
|
|
39
|
+
@app.get("/")
|
|
40
|
+
async def root():
|
|
41
|
+
return {"status": "ok"}
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
### Flask
|
|
45
|
+
|
|
46
|
+
```python
|
|
47
|
+
import tracely
|
|
48
|
+
from tracely.instrumentation.flask_inst import FlaskInstrumentor
|
|
49
|
+
|
|
50
|
+
tracely.init(api_key="trly_your_key_here")
|
|
51
|
+
|
|
52
|
+
from flask import Flask
|
|
53
|
+
app = Flask(__name__)
|
|
54
|
+
app.wsgi_app = FlaskInstrumentor.wrap_app(app.wsgi_app)
|
|
55
|
+
|
|
56
|
+
@app.route("/")
|
|
57
|
+
def root():
|
|
58
|
+
return {"status": "ok"}
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
### Django
|
|
62
|
+
|
|
63
|
+
Add the middleware to your `MIDDLEWARE` setting:
|
|
64
|
+
|
|
65
|
+
```python
|
|
66
|
+
# settings.py
|
|
67
|
+
MIDDLEWARE = [
|
|
68
|
+
"tracely.instrumentation.django_inst.TracelyDjangoMiddleware",
|
|
69
|
+
# ... other middleware
|
|
70
|
+
]
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
Then initialize in your app startup (e.g., `AppConfig.ready()`):
|
|
74
|
+
|
|
75
|
+
```python
|
|
76
|
+
import tracely
|
|
77
|
+
tracely.init(api_key="trly_your_key_here")
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
## Configuration
|
|
81
|
+
|
|
82
|
+
### Environment Variables
|
|
83
|
+
|
|
84
|
+
| Variable | Description | Default |
|
|
85
|
+
|----------|-------------|---------|
|
|
86
|
+
| `TRACELY_API_KEY` | API key for authentication | _(required)_ |
|
|
87
|
+
| `TRACELY_ENDPOINT` | Ingestion API endpoint | `https://i.tracely.sh` |
|
|
88
|
+
| `ENVIRONMENT` | Deployment environment (e.g., `production`) | `None` |
|
|
89
|
+
| `TRACELY_REDACT_FIELDS` | Comma-separated header/field names to redact | `None` |
|
|
90
|
+
|
|
91
|
+
### Programmatic Init
|
|
92
|
+
|
|
93
|
+
```python
|
|
94
|
+
import tracely
|
|
95
|
+
|
|
96
|
+
tracely.init(
|
|
97
|
+
api_key="trly_your_key_here",
|
|
98
|
+
environment="production",
|
|
99
|
+
service_name="my-api",
|
|
100
|
+
service_version="1.0.0",
|
|
101
|
+
)
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
## Custom Spans
|
|
105
|
+
|
|
106
|
+
Create manual spans for custom operations:
|
|
107
|
+
|
|
108
|
+
```python
|
|
109
|
+
import tracely
|
|
110
|
+
|
|
111
|
+
with tracely.span("db-query", kind="CLIENT") as s:
|
|
112
|
+
s.set_attribute("db.system", "postgres")
|
|
113
|
+
s.set_attribute("db.statement", "SELECT * FROM users")
|
|
114
|
+
result = db.execute("SELECT * FROM users")
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
## Span Events (Structured Logging)
|
|
118
|
+
|
|
119
|
+
Attach structured log events to the active span:
|
|
120
|
+
|
|
121
|
+
```python
|
|
122
|
+
import tracely
|
|
123
|
+
|
|
124
|
+
with tracely.span("process-order") as s:
|
|
125
|
+
tracely.info("Order received", order_id="123")
|
|
126
|
+
# ... process
|
|
127
|
+
tracely.debug("Validation passed")
|
|
128
|
+
tracely.warning("Inventory low", sku="WIDGET-42")
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
## Graceful Shutdown
|
|
132
|
+
|
|
133
|
+
Flush buffered spans before exit:
|
|
134
|
+
|
|
135
|
+
```python
|
|
136
|
+
import tracely
|
|
137
|
+
|
|
138
|
+
tracely.init(api_key="trly_your_key_here")
|
|
139
|
+
# ... application runs ...
|
|
140
|
+
tracely.shutdown() # flushes remaining spans
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
## How It Works
|
|
144
|
+
|
|
145
|
+
```
|
|
146
|
+
Your App
|
|
147
|
+
|
|
|
148
|
+
v
|
|
149
|
+
Middleware (FastAPI/Flask/Django)
|
|
150
|
+
|-- on_start --> SpanProcessor --> SpanBuffer (pending_span)
|
|
151
|
+
|-- on_end ----> SpanProcessor --> SpanBuffer (final span)
|
|
152
|
+
|
|
|
153
|
+
v
|
|
154
|
+
BatchSpanExporter (1s interval / 50 span threshold)
|
|
155
|
+
|
|
|
156
|
+
v
|
|
157
|
+
OTLP Protobuf Serialization
|
|
158
|
+
|
|
|
159
|
+
v
|
|
160
|
+
HttpTransport --> TRACELY API
|
|
161
|
+
(retry with exponential backoff)
|
|
162
|
+
```
|
|
163
|
+
|
|
164
|
+
## Documentation
|
|
165
|
+
|
|
166
|
+
Full docs at [docs.tracely.sh](https://docs.tracely.sh)
|
|
167
|
+
|
|
168
|
+
## License
|
|
169
|
+
|
|
170
|
+
MIT
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
# v0.1.0
|
|
2
|
+
|
|
3
|
+
First public release of the TRACELY SDK -- lightweight observability for Python web frameworks.
|
|
4
|
+
|
|
5
|
+
## Highlights
|
|
6
|
+
|
|
7
|
+
Zero-config auto-instrumentation for **FastAPI**, **Flask**, and **Django** with real-time distributed tracing. The SDK captures full request/response data, exports via OTLP/HTTP protobuf, and never crashes your application.
|
|
8
|
+
|
|
9
|
+
## Features
|
|
10
|
+
|
|
11
|
+
### Core SDK
|
|
12
|
+
- **Zero-config initialization** -- `tracely.init(api_key="...")` reads from env vars or explicit params by @charlesdzadu
|
|
13
|
+
- **Framework auto-detection** -- automatically detects FastAPI, Flask, and Django at import time by @charlesdzadu
|
|
14
|
+
- **Graceful shutdown** -- `tracely.shutdown()` flushes all buffered spans before exit by @charlesdzadu
|
|
15
|
+
|
|
16
|
+
### Auto-Instrumentation
|
|
17
|
+
- **FastAPI ASGI middleware** -- `TracelyASGIMiddleware` wraps async apps with full request/response capture by @charlesdzadu
|
|
18
|
+
- **Flask WSGI middleware** -- `TracelyWSGIMiddleware` wraps sync WSGI apps with request/response capture by @charlesdzadu
|
|
19
|
+
- **Django middleware** -- `TracelyDjangoMiddleware` follows Django middleware protocol by @charlesdzadu
|
|
20
|
+
- **HTTPX client instrumentation** -- traces outbound HTTP calls as child spans by @charlesdzadu
|
|
21
|
+
- **Database API instrumentation** -- traces DB queries via Python DB-API 2.0 by @charlesdzadu
|
|
22
|
+
|
|
23
|
+
### Tracing & Spans
|
|
24
|
+
- **Span creation with trace hierarchy** -- root and child spans with automatic parent propagation by @charlesdzadu
|
|
25
|
+
- **Custom spans API** -- `tracely.span("name")` context manager for manual instrumentation by @charlesdzadu
|
|
26
|
+
- **Pending span pattern** -- spans exported immediately on start (`pending_span`) for real-time dashboard visibility by @charlesdzadu
|
|
27
|
+
- **Span events / structured logging** -- `tracely.info()`, `tracely.debug()`, `tracely.warning()`, `tracely.error()` by @charlesdzadu
|
|
28
|
+
|
|
29
|
+
### Data Capture & Privacy
|
|
30
|
+
- **Full request/response data capture** -- headers, body, query params, status codes by @charlesdzadu
|
|
31
|
+
- **Smart data redaction** -- auto-redacts Authorization, Cookie, passwords, tokens, API keys by @charlesdzadu
|
|
32
|
+
- **Custom redaction fields** -- `TRACELY_REDACT_FIELDS` env var for additional sensitive fields by @charlesdzadu
|
|
33
|
+
- **Binary body detection** -- replaces binary content with `[binary]` placeholder by @charlesdzadu
|
|
34
|
+
|
|
35
|
+
### Transport & Export
|
|
36
|
+
- **OTLP/HTTP protobuf export** -- standard OpenTelemetry wire format via `opentelemetry-proto` by @charlesdzadu
|
|
37
|
+
- **Batch span exporter** -- background daemon thread with 1s flush interval or 50-span threshold by @charlesdzadu
|
|
38
|
+
- **Exponential backoff retry** -- 1s, 2s, 4s, max 30s on transport failure by @charlesdzadu
|
|
39
|
+
- **Buffer limit** -- 1000 span cap, drops oldest when full by @charlesdzadu
|
|
40
|
+
- **Fail-silent design** -- all SDK operations catch errors silently, host app never affected by @charlesdzadu
|
|
41
|
+
|
|
42
|
+
## Dependencies
|
|
43
|
+
|
|
44
|
+
- `httpx>=0.27`
|
|
45
|
+
- `opentelemetry-proto>=1.20`
|
|
46
|
+
- Python 3.10+
|
|
47
|
+
|
|
48
|
+
## Contributors
|
|
49
|
+
|
|
50
|
+
@charlesdzadu
|
|
51
|
+
|
|
52
|
+
## Assets
|
|
53
|
+
|
|
54
|
+
- `tracely_sdk-0.1.0-py3-none-any.whl`
|
|
55
|
+
- `tracely_sdk-0.1.0.tar.gz`
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["hatchling"]
|
|
3
|
+
build-backend = "hatchling.build"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "tracely-sdk"
|
|
7
|
+
version = "0.1.0"
|
|
8
|
+
description = "Lightweight observability SDK for Python web frameworks. Auto-instruments FastAPI, Flask, and Django with real-time tracing via OTLP/HTTP."
|
|
9
|
+
readme = "README.md"
|
|
10
|
+
requires-python = ">=3.10"
|
|
11
|
+
license = "MIT"
|
|
12
|
+
authors = [
|
|
13
|
+
{name = "Charles Dzadu", email = "contact@tracely.sh"},
|
|
14
|
+
]
|
|
15
|
+
keywords = ["observability", "tracing", "opentelemetry", "fastapi", "flask", "django", "monitoring", "apm"]
|
|
16
|
+
classifiers = [
|
|
17
|
+
"Development Status :: 3 - Alpha",
|
|
18
|
+
"Intended Audience :: Developers",
|
|
19
|
+
"License :: OSI Approved :: MIT License",
|
|
20
|
+
"Programming Language :: Python :: 3",
|
|
21
|
+
"Programming Language :: Python :: 3.10",
|
|
22
|
+
"Programming Language :: Python :: 3.11",
|
|
23
|
+
"Programming Language :: Python :: 3.12",
|
|
24
|
+
"Programming Language :: Python :: 3.13",
|
|
25
|
+
"Topic :: System :: Monitoring",
|
|
26
|
+
"Topic :: Software Development :: Libraries :: Python Modules",
|
|
27
|
+
"Framework :: FastAPI",
|
|
28
|
+
"Framework :: Flask",
|
|
29
|
+
"Framework :: Django",
|
|
30
|
+
"Typing :: Typed",
|
|
31
|
+
]
|
|
32
|
+
dependencies = [
|
|
33
|
+
"opentelemetry-proto>=1.20",
|
|
34
|
+
"httpx>=0.27",
|
|
35
|
+
]
|
|
36
|
+
|
|
37
|
+
[project.optional-dependencies]
|
|
38
|
+
dev = [
|
|
39
|
+
"pytest>=8.0",
|
|
40
|
+
"pytest-asyncio>=0.23",
|
|
41
|
+
"respx>=0.21",
|
|
42
|
+
]
|
|
43
|
+
|
|
44
|
+
[project.urls]
|
|
45
|
+
Homepage = "https://tracely.sh"
|
|
46
|
+
Documentation = "https://docs.tracely.sh"
|
|
47
|
+
Repository = "https://github.com/TracelyOrg/tracely-sdk"
|
|
48
|
+
Issues = "https://github.com/TracelyOrg/tracely-sdk/issues"
|
|
49
|
+
|
|
50
|
+
[tool.hatch.build.targets.wheel]
|
|
51
|
+
packages = ["src/tracely"]
|
|
52
|
+
|
|
53
|
+
[tool.pytest.ini_options]
|
|
54
|
+
asyncio_mode = "auto"
|
|
55
|
+
testpaths = ["tests"]
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
"""TRACELY SDK - Lightweight observability for Python web frameworks."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
__version__ = "0.1.0"
|
|
6
|
+
|
|
7
|
+
from tracely.sdk import init, shutdown
|
|
8
|
+
from tracely.tracing import span
|
|
9
|
+
from tracely.logging_api import debug, info, warning, error
|
|
10
|
+
|
|
11
|
+
__all__ = ["init", "shutdown", "span", "debug", "info", "warning", "error", "__version__"]
|