tracely-sdk 0.1.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- tracely/__init__.py +11 -0
- tracely/capture.py +210 -0
- tracely/config.py +39 -0
- tracely/context.py +55 -0
- tracely/detection.py +49 -0
- tracely/exporter.py +120 -0
- tracely/instrumentation/__init__.py +47 -0
- tracely/instrumentation/base.py +30 -0
- tracely/instrumentation/dbapi.py +264 -0
- tracely/instrumentation/django_inst.py +155 -0
- tracely/instrumentation/fastapi_inst.py +203 -0
- tracely/instrumentation/flask_inst.py +215 -0
- tracely/instrumentation/generic.py +38 -0
- tracely/instrumentation/httpx_inst.py +130 -0
- tracely/log_handler.py +55 -0
- tracely/logging_api.py +38 -0
- tracely/otlp.py +128 -0
- tracely/py.typed +0 -0
- tracely/redaction.py +196 -0
- tracely/sdk.py +192 -0
- tracely/span.py +168 -0
- tracely/span_processor.py +110 -0
- tracely/tracing.py +59 -0
- tracely/transport.py +134 -0
- tracely_sdk-0.1.0.dist-info/METADATA +205 -0
- tracely_sdk-0.1.0.dist-info/RECORD +28 -0
- tracely_sdk-0.1.0.dist-info/WHEEL +4 -0
- tracely_sdk-0.1.0.dist-info/licenses/LICENSE +21 -0
tracely/tracing.py
ADDED
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
"""Public tracing API for custom spans (FR58, FR59).
|
|
2
|
+
|
|
3
|
+
Provides the `span()` context manager for developers to create
|
|
4
|
+
custom spans within their application code.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from __future__ import annotations
|
|
8
|
+
|
|
9
|
+
from contextlib import contextmanager
|
|
10
|
+
from typing import Any, Callable, Generator
|
|
11
|
+
|
|
12
|
+
from tracely.context import get_current_span, _span_context
|
|
13
|
+
from tracely.span import Span
|
|
14
|
+
from tracely.span_processor import on_span_end, on_span_start
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
@contextmanager
|
|
18
|
+
def span(
|
|
19
|
+
name: str,
|
|
20
|
+
*,
|
|
21
|
+
kind: str = "INTERNAL",
|
|
22
|
+
service_name: str | None = None,
|
|
23
|
+
on_end: Callable[[Span], None] | None = None,
|
|
24
|
+
) -> Generator[Span, None, None]:
|
|
25
|
+
"""Create a custom span as a child of the currently active span.
|
|
26
|
+
|
|
27
|
+
If no span is active, creates a root span. The span is automatically
|
|
28
|
+
ended when the context exits (including on exception).
|
|
29
|
+
|
|
30
|
+
Usage::
|
|
31
|
+
|
|
32
|
+
with tracely.span("my-operation") as s:
|
|
33
|
+
s.set_attribute("key", "value")
|
|
34
|
+
# do work
|
|
35
|
+
# span is ended here
|
|
36
|
+
|
|
37
|
+
Args:
|
|
38
|
+
name: Human-readable operation name.
|
|
39
|
+
kind: Span kind (INTERNAL, CLIENT, PRODUCER, CONSUMER).
|
|
40
|
+
service_name: Optional service name override.
|
|
41
|
+
on_end: Optional callback invoked when span ends.
|
|
42
|
+
"""
|
|
43
|
+
parent = get_current_span()
|
|
44
|
+
s = Span(
|
|
45
|
+
name=name,
|
|
46
|
+
parent=parent,
|
|
47
|
+
kind=kind,
|
|
48
|
+
service_name=service_name,
|
|
49
|
+
on_end=on_end or on_span_end,
|
|
50
|
+
)
|
|
51
|
+
|
|
52
|
+
# AR3: Export pending_span immediately for real-time dashboard
|
|
53
|
+
on_span_start(s)
|
|
54
|
+
|
|
55
|
+
with _span_context(s):
|
|
56
|
+
try:
|
|
57
|
+
yield s
|
|
58
|
+
finally:
|
|
59
|
+
s.end()
|
tracely/transport.py
ADDED
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
"""HTTP transport with buffering and retry for span data."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import asyncio
|
|
6
|
+
import logging
|
|
7
|
+
from collections import deque
|
|
8
|
+
from typing import Any
|
|
9
|
+
|
|
10
|
+
import httpx
|
|
11
|
+
|
|
12
|
+
logger = logging.getLogger("tracely")
|
|
13
|
+
|
|
14
|
+
DEFAULT_BATCH_SIZE = 50
|
|
15
|
+
DEFAULT_MAX_BUFFER = 1000
|
|
16
|
+
DEFAULT_MAX_RETRIES = 3
|
|
17
|
+
DEFAULT_BASE_DELAY = 1.0
|
|
18
|
+
DEFAULT_MAX_DELAY = 30.0
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
class SpanBuffer:
|
|
22
|
+
"""Thread-safe in-memory buffer for span data.
|
|
23
|
+
|
|
24
|
+
Drops oldest spans when max_size is exceeded.
|
|
25
|
+
"""
|
|
26
|
+
|
|
27
|
+
def __init__(
|
|
28
|
+
self,
|
|
29
|
+
max_size: int = DEFAULT_MAX_BUFFER,
|
|
30
|
+
batch_size: int = DEFAULT_BATCH_SIZE,
|
|
31
|
+
) -> None:
|
|
32
|
+
self._buffer: deque[dict[str, Any]] = deque(maxlen=max_size)
|
|
33
|
+
self._batch_size = batch_size
|
|
34
|
+
|
|
35
|
+
def enqueue(self, span: dict[str, Any]) -> None:
|
|
36
|
+
"""Add a span to the buffer. Oldest dropped if full."""
|
|
37
|
+
self._buffer.append(span)
|
|
38
|
+
|
|
39
|
+
def flush(self) -> list[dict[str, Any]]:
|
|
40
|
+
"""Return all buffered spans and clear the buffer."""
|
|
41
|
+
spans = list(self._buffer)
|
|
42
|
+
self._buffer.clear()
|
|
43
|
+
return spans
|
|
44
|
+
|
|
45
|
+
@property
|
|
46
|
+
def size(self) -> int:
|
|
47
|
+
"""Number of spans currently in buffer."""
|
|
48
|
+
return len(self._buffer)
|
|
49
|
+
|
|
50
|
+
@property
|
|
51
|
+
def is_ready(self) -> bool:
|
|
52
|
+
"""Buffer has reached the batch threshold."""
|
|
53
|
+
return len(self._buffer) >= self._batch_size
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
class HttpTransport:
|
|
57
|
+
"""Sends span data to the TRACELY API with retry and backoff.
|
|
58
|
+
|
|
59
|
+
All errors are caught silently — the host application must never be
|
|
60
|
+
affected by transport failures (FR10, NFR22).
|
|
61
|
+
"""
|
|
62
|
+
|
|
63
|
+
def __init__(
|
|
64
|
+
self,
|
|
65
|
+
endpoint: str,
|
|
66
|
+
api_key: str,
|
|
67
|
+
max_retries: int = DEFAULT_MAX_RETRIES,
|
|
68
|
+
base_delay: float = DEFAULT_BASE_DELAY,
|
|
69
|
+
max_delay: float = DEFAULT_MAX_DELAY,
|
|
70
|
+
) -> None:
|
|
71
|
+
self._endpoint = endpoint.rstrip("/")
|
|
72
|
+
self._api_key = api_key
|
|
73
|
+
self._max_retries = max_retries
|
|
74
|
+
self._base_delay = base_delay
|
|
75
|
+
self._max_delay = max_delay
|
|
76
|
+
self._client = httpx.AsyncClient(
|
|
77
|
+
timeout=httpx.Timeout(10.0),
|
|
78
|
+
headers={
|
|
79
|
+
"Authorization": f"Bearer {api_key}",
|
|
80
|
+
"Content-Type": "application/x-protobuf",
|
|
81
|
+
},
|
|
82
|
+
)
|
|
83
|
+
|
|
84
|
+
async def send(self, payload: bytes) -> bool:
|
|
85
|
+
"""Send OTLP protobuf payload to the API. Returns True on success.
|
|
86
|
+
|
|
87
|
+
Args:
|
|
88
|
+
payload: Serialized OTLP ExportTraceServiceRequest bytes.
|
|
89
|
+
|
|
90
|
+
Never raises — all exceptions are caught and logged (FR10, NFR22).
|
|
91
|
+
"""
|
|
92
|
+
if not payload:
|
|
93
|
+
return True
|
|
94
|
+
|
|
95
|
+
url = f"{self._endpoint}/v1/traces"
|
|
96
|
+
attempt = 0
|
|
97
|
+
max_attempts = 1 + self._max_retries
|
|
98
|
+
|
|
99
|
+
while attempt < max_attempts:
|
|
100
|
+
try:
|
|
101
|
+
response = await self._client.post(url, content=payload)
|
|
102
|
+
response.raise_for_status()
|
|
103
|
+
return True
|
|
104
|
+
except (httpx.HTTPStatusError, httpx.ConnectError, httpx.TimeoutException, ConnectionError, OSError) as exc:
|
|
105
|
+
attempt += 1
|
|
106
|
+
if attempt < max_attempts:
|
|
107
|
+
delay = min(
|
|
108
|
+
self._base_delay * (2 ** (attempt - 1)),
|
|
109
|
+
self._max_delay,
|
|
110
|
+
)
|
|
111
|
+
logger.debug(
|
|
112
|
+
"TRACELY transport retry %d/%d after %.1fs: %s",
|
|
113
|
+
attempt,
|
|
114
|
+
self._max_retries,
|
|
115
|
+
delay,
|
|
116
|
+
exc,
|
|
117
|
+
)
|
|
118
|
+
await asyncio.sleep(delay)
|
|
119
|
+
else:
|
|
120
|
+
logger.debug(
|
|
121
|
+
"TRACELY transport failed after %d attempts: %s",
|
|
122
|
+
max_attempts,
|
|
123
|
+
exc,
|
|
124
|
+
)
|
|
125
|
+
except Exception as exc:
|
|
126
|
+
# Catch-all: SDK must never crash the host app
|
|
127
|
+
logger.debug("TRACELY transport unexpected error: %s", exc)
|
|
128
|
+
return False
|
|
129
|
+
|
|
130
|
+
return False
|
|
131
|
+
|
|
132
|
+
async def close(self) -> None:
|
|
133
|
+
"""Close the HTTP client."""
|
|
134
|
+
await self._client.aclose()
|
|
@@ -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,28 @@
|
|
|
1
|
+
tracely/__init__.py,sha256=7CmCMoZ7kaz2nE7o-iRfZ4z6P2_LrVX9LlCGez4-sac,357
|
|
2
|
+
tracely/capture.py,sha256=_W0V1pdx9dUIQWwafOggm2hDisyfpY_fJsgz1H7Poyo,6636
|
|
3
|
+
tracely/config.py,sha256=F_ytza_-HEpn6rGxb8kBAbuoLrQu88BIey7SpZP9vJ0,1244
|
|
4
|
+
tracely/context.py,sha256=PjxtEph9ooC0T6jOLnX6a16nnThHlWg52183O-wV2bE,1613
|
|
5
|
+
tracely/detection.py,sha256=BI2z2b2ncfEPMA4_JmDulpxMGctQBy-rZSf2xT3JFvs,1460
|
|
6
|
+
tracely/exporter.py,sha256=ce3jfMzBHaa38YgG-I7CP6Q7dwljP4VanWXVPZP4LpM,4018
|
|
7
|
+
tracely/log_handler.py,sha256=BYxUnRTim1D8L79QOlALD9W_feLjSul8oMKrZiTGnys,1776
|
|
8
|
+
tracely/logging_api.py,sha256=KKGRu_mb2XZk7tgzUYWRl6bh0_G42KAar-X2yH_Wm9I,1264
|
|
9
|
+
tracely/otlp.py,sha256=pfeQVN641ZusnovMYz6A4_XkFqcblwO5hT4Cda8LLhQ,4265
|
|
10
|
+
tracely/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
11
|
+
tracely/redaction.py,sha256=ywsjD7o20RWu_qS6PYt3WnbxrJslHGA3IeAGS96jpTw,5949
|
|
12
|
+
tracely/sdk.py,sha256=-zvNUFw1Nx4KxR2i90FlW4ELSh0R0Cb2VFuG_o1zWbU,6072
|
|
13
|
+
tracely/span.py,sha256=bWo8LM_vR0Uc1g6o-6-wdYOnwPJ3UQENtcWdGumSwaI,5079
|
|
14
|
+
tracely/span_processor.py,sha256=P4f4192t-FBppw9LmPebHA1ciA5UKp4eseTY-3LAPWA,3370
|
|
15
|
+
tracely/tracing.py,sha256=NiwcrZ9S8-fqVWfYgc6PTlzc141v-Om311TOytowph4,1608
|
|
16
|
+
tracely/transport.py,sha256=mvrA9JqVmHydAs-Z_iPypBNywX8UgZYjooAU-HS11sQ,4131
|
|
17
|
+
tracely/instrumentation/__init__.py,sha256=QPCafxwszvO8nwLrsMkwcsD0j3hg_OG3T5GAd4DYr_E,1476
|
|
18
|
+
tracely/instrumentation/base.py,sha256=g5siRo1L6K88rrb47OS9tmg5riNtljEMlRUy1BENqdQ,860
|
|
19
|
+
tracely/instrumentation/dbapi.py,sha256=ax_wG5PUOASARKay3CCTQBGFeY9rCUBsdNp_Rel9tsc,8882
|
|
20
|
+
tracely/instrumentation/django_inst.py,sha256=wYO5c-TYW9ScyWLnCQw8UHiyKgx-OE0Ie9lNqrwP_X4,5560
|
|
21
|
+
tracely/instrumentation/fastapi_inst.py,sha256=1h4Kd6DTig4CcNFoVKclh0TjAHCFqcAJDzDpUiQMSSQ,7388
|
|
22
|
+
tracely/instrumentation/flask_inst.py,sha256=fCfC-hYKQy1pSNwy3e6VZQ0KF93F82CqnNAFnf-J_Bo,7646
|
|
23
|
+
tracely/instrumentation/generic.py,sha256=hjHlnVrJQXsXtVR3P0mVehf9OqAZ6UZFIR-GI0D0qeQ,1021
|
|
24
|
+
tracely/instrumentation/httpx_inst.py,sha256=hQ25EE37G7EoyLpR9g9r5Z5qVUgw5e4D5fTPKsSiZuE,4825
|
|
25
|
+
tracely_sdk-0.1.0.dist-info/METADATA,sha256=ks5_rxp34HGmqbEMC3tCGo5Y1kl5ryt9amimzY-d2tM,5889
|
|
26
|
+
tracely_sdk-0.1.0.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
|
|
27
|
+
tracely_sdk-0.1.0.dist-info/licenses/LICENSE,sha256=btzJ8TFbmXLjXC326W6a5ta0IBUtxUAo1X-mCFW_EhQ,1075
|
|
28
|
+
tracely_sdk-0.1.0.dist-info/RECORD,,
|
|
@@ -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.
|