observe-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.
- observe_sdk-0.1.0/MANIFEST.in +2 -0
- observe_sdk-0.1.0/PKG-INFO +194 -0
- observe_sdk-0.1.0/README.md +181 -0
- observe_sdk-0.1.0/pyproject.toml +17 -0
- observe_sdk-0.1.0/setup.cfg +4 -0
- observe_sdk-0.1.0/src/observe_sdk.egg-info/PKG-INFO +194 -0
- observe_sdk-0.1.0/src/observe_sdk.egg-info/SOURCES.txt +9 -0
- observe_sdk-0.1.0/src/observe_sdk.egg-info/dependency_links.txt +1 -0
- observe_sdk-0.1.0/src/observe_sdk.egg-info/requires.txt +1 -0
- observe_sdk-0.1.0/src/observe_sdk.egg-info/top_level.txt +1 -0
- observe_sdk-0.1.0/src/tracker.py +75 -0
|
@@ -0,0 +1,194 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: observe-sdk
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Lightweight observability SDK for Python
|
|
5
|
+
Author-email: Kelechukwu Amadi-Keke <favourkaycee23@gmail.com>
|
|
6
|
+
License: MIT
|
|
7
|
+
Project-URL: Homepage, https://observe.dev
|
|
8
|
+
Project-URL: Repository, https://github.com/im-kaycee/observability-python-sdk
|
|
9
|
+
Keywords: analytics,observability,monitoring
|
|
10
|
+
Requires-Python: >=3.9
|
|
11
|
+
Description-Content-Type: text/markdown
|
|
12
|
+
Requires-Dist: httpx>=0.27.0
|
|
13
|
+
|
|
14
|
+
# observe. — Python SDK
|
|
15
|
+
|
|
16
|
+
The Python SDK for observe. Track server-side events, capture exceptions, and monitor API performance from any Python application.
|
|
17
|
+
|
|
18
|
+
## Features
|
|
19
|
+
|
|
20
|
+
- Custom event tracking
|
|
21
|
+
- Exception capture with full stack traces
|
|
22
|
+
- User identification
|
|
23
|
+
- Fire and forget — sends in background threads, never blocks your app
|
|
24
|
+
- Works with FastAPI, Django, Flask, or plain Python
|
|
25
|
+
|
|
26
|
+
## Installation
|
|
27
|
+
|
|
28
|
+
```bash
|
|
29
|
+
pip install observe-sdk
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
> Until published to PyPI, copy `src/tracker.py` into your project directly.
|
|
33
|
+
|
|
34
|
+
## Quick start
|
|
35
|
+
|
|
36
|
+
```python
|
|
37
|
+
from tracker import Tracker
|
|
38
|
+
|
|
39
|
+
tracker = Tracker(
|
|
40
|
+
api_key="obs_your_secret_key",
|
|
41
|
+
server_url="https://api.observe.dev",
|
|
42
|
+
)
|
|
43
|
+
|
|
44
|
+
# track an event
|
|
45
|
+
tracker.track(
|
|
46
|
+
event_name="order_placed",
|
|
47
|
+
anonymous_id="anon_abc123",
|
|
48
|
+
properties={"plan": "pro"},
|
|
49
|
+
)
|
|
50
|
+
|
|
51
|
+
# capture an exception
|
|
52
|
+
try:
|
|
53
|
+
process_payment()
|
|
54
|
+
except Exception as e:
|
|
55
|
+
tracker.capture_exception(e, extra={"user_id": "user_123"})
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
## Framework guides
|
|
59
|
+
|
|
60
|
+
### FastAPI
|
|
61
|
+
|
|
62
|
+
Add the middleware to automatically track all requests:
|
|
63
|
+
|
|
64
|
+
```python
|
|
65
|
+
# main.py
|
|
66
|
+
from fastapi import FastAPI, Request
|
|
67
|
+
from tracker import Tracker
|
|
68
|
+
import time
|
|
69
|
+
|
|
70
|
+
app = FastAPI()
|
|
71
|
+
|
|
72
|
+
tracker = Tracker(
|
|
73
|
+
api_key="obs_your_secret_key",
|
|
74
|
+
server_url="https://api.observe.dev",
|
|
75
|
+
)
|
|
76
|
+
|
|
77
|
+
@app.middleware("http")
|
|
78
|
+
async def track_requests(request: Request, call_next):
|
|
79
|
+
start = time.time()
|
|
80
|
+
try:
|
|
81
|
+
response = await call_next(request)
|
|
82
|
+
duration_ms = round((time.time() - start) * 1000)
|
|
83
|
+
tracker.track(
|
|
84
|
+
event_name="api_request",
|
|
85
|
+
anonymous_id="server",
|
|
86
|
+
properties={
|
|
87
|
+
"method": request.method,
|
|
88
|
+
"path": request.url.path,
|
|
89
|
+
"status_code": response.status_code,
|
|
90
|
+
"duration_ms": duration_ms,
|
|
91
|
+
},
|
|
92
|
+
)
|
|
93
|
+
return response
|
|
94
|
+
except Exception as e:
|
|
95
|
+
tracker.capture_exception(e, extra={"path": request.url.path})
|
|
96
|
+
raise
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
### Django
|
|
100
|
+
|
|
101
|
+
Create a middleware file and add it to `settings.py`:
|
|
102
|
+
|
|
103
|
+
```python
|
|
104
|
+
# observe_middleware.py
|
|
105
|
+
import time
|
|
106
|
+
from tracker import Tracker
|
|
107
|
+
|
|
108
|
+
tracker = Tracker(
|
|
109
|
+
api_key="obs_your_secret_key",
|
|
110
|
+
server_url="https://api.observe.dev",
|
|
111
|
+
)
|
|
112
|
+
|
|
113
|
+
class ObserveMiddleware:
|
|
114
|
+
def __init__(self, get_response):
|
|
115
|
+
self.get_response = get_response
|
|
116
|
+
|
|
117
|
+
def __call__(self, request):
|
|
118
|
+
start = time.time()
|
|
119
|
+
response = self.get_response(request)
|
|
120
|
+
duration_ms = round((time.time() - start) * 1000)
|
|
121
|
+
|
|
122
|
+
tracker.track(
|
|
123
|
+
event_name="api_request",
|
|
124
|
+
anonymous_id=str(request.user.id) if request.user.is_authenticated else "anon",
|
|
125
|
+
properties={
|
|
126
|
+
"method": request.method,
|
|
127
|
+
"path": request.path,
|
|
128
|
+
"status_code": response.status_code,
|
|
129
|
+
"duration_ms": duration_ms,
|
|
130
|
+
},
|
|
131
|
+
)
|
|
132
|
+
return response
|
|
133
|
+
|
|
134
|
+
def process_exception(self, request, exception):
|
|
135
|
+
tracker.capture_exception(exception, extra={
|
|
136
|
+
"path": request.path,
|
|
137
|
+
"method": request.method,
|
|
138
|
+
})
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
```python
|
|
142
|
+
# settings.py
|
|
143
|
+
MIDDLEWARE = [
|
|
144
|
+
# ... existing middleware
|
|
145
|
+
"yourapp.observe_middleware.ObserveMiddleware",
|
|
146
|
+
]
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
## API reference
|
|
150
|
+
|
|
151
|
+
### `Tracker(api_key, server_url)`
|
|
152
|
+
|
|
153
|
+
| Parameter | Type | Required | Description |
|
|
154
|
+
|-----------|------|----------|-------------|
|
|
155
|
+
| `api_key` | str | Yes | Your project secret key |
|
|
156
|
+
| `server_url` | str | Yes | Your observe. server URL |
|
|
157
|
+
|
|
158
|
+
### `tracker.track(event_name, anonymous_id, properties?)`
|
|
159
|
+
|
|
160
|
+
| Parameter | Type | Required | Description |
|
|
161
|
+
|-----------|------|----------|-------------|
|
|
162
|
+
| `event_name` | str | Yes | Name of the event |
|
|
163
|
+
| `anonymous_id` | str | Yes | Session or visitor ID |
|
|
164
|
+
| `properties` | dict | No | Any additional data |
|
|
165
|
+
|
|
166
|
+
### `tracker.identify(anonymous_id, user_id)`
|
|
167
|
+
|
|
168
|
+
| Parameter | Type | Required | Description |
|
|
169
|
+
|-----------|------|----------|-------------|
|
|
170
|
+
| `anonymous_id` | str | Yes | Current session ID |
|
|
171
|
+
| `user_id` | str | Yes | Your user's ID |
|
|
172
|
+
|
|
173
|
+
### `tracker.capture_exception(exception, anonymous_id?, extra?)`
|
|
174
|
+
|
|
175
|
+
| Parameter | Type | Required | Description |
|
|
176
|
+
|-----------|------|----------|-------------|
|
|
177
|
+
| `exception` | Exception | Yes | The caught exception |
|
|
178
|
+
| `anonymous_id` | str | No | Defaults to `"server"` |
|
|
179
|
+
| `extra` | dict | No | Any additional context |
|
|
180
|
+
|
|
181
|
+
## Development
|
|
182
|
+
|
|
183
|
+
```bash
|
|
184
|
+
git clone https://github.com/yourname/observability-python-sdk.git
|
|
185
|
+
cd observability-python-sdk
|
|
186
|
+
pip install httpx
|
|
187
|
+
|
|
188
|
+
# run the example
|
|
189
|
+
python examples/basic.py
|
|
190
|
+
```
|
|
191
|
+
|
|
192
|
+
## License
|
|
193
|
+
|
|
194
|
+
MIT
|
|
@@ -0,0 +1,181 @@
|
|
|
1
|
+
# observe. — Python SDK
|
|
2
|
+
|
|
3
|
+
The Python SDK for observe. Track server-side events, capture exceptions, and monitor API performance from any Python application.
|
|
4
|
+
|
|
5
|
+
## Features
|
|
6
|
+
|
|
7
|
+
- Custom event tracking
|
|
8
|
+
- Exception capture with full stack traces
|
|
9
|
+
- User identification
|
|
10
|
+
- Fire and forget — sends in background threads, never blocks your app
|
|
11
|
+
- Works with FastAPI, Django, Flask, or plain Python
|
|
12
|
+
|
|
13
|
+
## Installation
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
pip install observe-sdk
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
> Until published to PyPI, copy `src/tracker.py` into your project directly.
|
|
20
|
+
|
|
21
|
+
## Quick start
|
|
22
|
+
|
|
23
|
+
```python
|
|
24
|
+
from tracker import Tracker
|
|
25
|
+
|
|
26
|
+
tracker = Tracker(
|
|
27
|
+
api_key="obs_your_secret_key",
|
|
28
|
+
server_url="https://api.observe.dev",
|
|
29
|
+
)
|
|
30
|
+
|
|
31
|
+
# track an event
|
|
32
|
+
tracker.track(
|
|
33
|
+
event_name="order_placed",
|
|
34
|
+
anonymous_id="anon_abc123",
|
|
35
|
+
properties={"plan": "pro"},
|
|
36
|
+
)
|
|
37
|
+
|
|
38
|
+
# capture an exception
|
|
39
|
+
try:
|
|
40
|
+
process_payment()
|
|
41
|
+
except Exception as e:
|
|
42
|
+
tracker.capture_exception(e, extra={"user_id": "user_123"})
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
## Framework guides
|
|
46
|
+
|
|
47
|
+
### FastAPI
|
|
48
|
+
|
|
49
|
+
Add the middleware to automatically track all requests:
|
|
50
|
+
|
|
51
|
+
```python
|
|
52
|
+
# main.py
|
|
53
|
+
from fastapi import FastAPI, Request
|
|
54
|
+
from tracker import Tracker
|
|
55
|
+
import time
|
|
56
|
+
|
|
57
|
+
app = FastAPI()
|
|
58
|
+
|
|
59
|
+
tracker = Tracker(
|
|
60
|
+
api_key="obs_your_secret_key",
|
|
61
|
+
server_url="https://api.observe.dev",
|
|
62
|
+
)
|
|
63
|
+
|
|
64
|
+
@app.middleware("http")
|
|
65
|
+
async def track_requests(request: Request, call_next):
|
|
66
|
+
start = time.time()
|
|
67
|
+
try:
|
|
68
|
+
response = await call_next(request)
|
|
69
|
+
duration_ms = round((time.time() - start) * 1000)
|
|
70
|
+
tracker.track(
|
|
71
|
+
event_name="api_request",
|
|
72
|
+
anonymous_id="server",
|
|
73
|
+
properties={
|
|
74
|
+
"method": request.method,
|
|
75
|
+
"path": request.url.path,
|
|
76
|
+
"status_code": response.status_code,
|
|
77
|
+
"duration_ms": duration_ms,
|
|
78
|
+
},
|
|
79
|
+
)
|
|
80
|
+
return response
|
|
81
|
+
except Exception as e:
|
|
82
|
+
tracker.capture_exception(e, extra={"path": request.url.path})
|
|
83
|
+
raise
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
### Django
|
|
87
|
+
|
|
88
|
+
Create a middleware file and add it to `settings.py`:
|
|
89
|
+
|
|
90
|
+
```python
|
|
91
|
+
# observe_middleware.py
|
|
92
|
+
import time
|
|
93
|
+
from tracker import Tracker
|
|
94
|
+
|
|
95
|
+
tracker = Tracker(
|
|
96
|
+
api_key="obs_your_secret_key",
|
|
97
|
+
server_url="https://api.observe.dev",
|
|
98
|
+
)
|
|
99
|
+
|
|
100
|
+
class ObserveMiddleware:
|
|
101
|
+
def __init__(self, get_response):
|
|
102
|
+
self.get_response = get_response
|
|
103
|
+
|
|
104
|
+
def __call__(self, request):
|
|
105
|
+
start = time.time()
|
|
106
|
+
response = self.get_response(request)
|
|
107
|
+
duration_ms = round((time.time() - start) * 1000)
|
|
108
|
+
|
|
109
|
+
tracker.track(
|
|
110
|
+
event_name="api_request",
|
|
111
|
+
anonymous_id=str(request.user.id) if request.user.is_authenticated else "anon",
|
|
112
|
+
properties={
|
|
113
|
+
"method": request.method,
|
|
114
|
+
"path": request.path,
|
|
115
|
+
"status_code": response.status_code,
|
|
116
|
+
"duration_ms": duration_ms,
|
|
117
|
+
},
|
|
118
|
+
)
|
|
119
|
+
return response
|
|
120
|
+
|
|
121
|
+
def process_exception(self, request, exception):
|
|
122
|
+
tracker.capture_exception(exception, extra={
|
|
123
|
+
"path": request.path,
|
|
124
|
+
"method": request.method,
|
|
125
|
+
})
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
```python
|
|
129
|
+
# settings.py
|
|
130
|
+
MIDDLEWARE = [
|
|
131
|
+
# ... existing middleware
|
|
132
|
+
"yourapp.observe_middleware.ObserveMiddleware",
|
|
133
|
+
]
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
## API reference
|
|
137
|
+
|
|
138
|
+
### `Tracker(api_key, server_url)`
|
|
139
|
+
|
|
140
|
+
| Parameter | Type | Required | Description |
|
|
141
|
+
|-----------|------|----------|-------------|
|
|
142
|
+
| `api_key` | str | Yes | Your project secret key |
|
|
143
|
+
| `server_url` | str | Yes | Your observe. server URL |
|
|
144
|
+
|
|
145
|
+
### `tracker.track(event_name, anonymous_id, properties?)`
|
|
146
|
+
|
|
147
|
+
| Parameter | Type | Required | Description |
|
|
148
|
+
|-----------|------|----------|-------------|
|
|
149
|
+
| `event_name` | str | Yes | Name of the event |
|
|
150
|
+
| `anonymous_id` | str | Yes | Session or visitor ID |
|
|
151
|
+
| `properties` | dict | No | Any additional data |
|
|
152
|
+
|
|
153
|
+
### `tracker.identify(anonymous_id, user_id)`
|
|
154
|
+
|
|
155
|
+
| Parameter | Type | Required | Description |
|
|
156
|
+
|-----------|------|----------|-------------|
|
|
157
|
+
| `anonymous_id` | str | Yes | Current session ID |
|
|
158
|
+
| `user_id` | str | Yes | Your user's ID |
|
|
159
|
+
|
|
160
|
+
### `tracker.capture_exception(exception, anonymous_id?, extra?)`
|
|
161
|
+
|
|
162
|
+
| Parameter | Type | Required | Description |
|
|
163
|
+
|-----------|------|----------|-------------|
|
|
164
|
+
| `exception` | Exception | Yes | The caught exception |
|
|
165
|
+
| `anonymous_id` | str | No | Defaults to `"server"` |
|
|
166
|
+
| `extra` | dict | No | Any additional context |
|
|
167
|
+
|
|
168
|
+
## Development
|
|
169
|
+
|
|
170
|
+
```bash
|
|
171
|
+
git clone https://github.com/yourname/observability-python-sdk.git
|
|
172
|
+
cd observability-python-sdk
|
|
173
|
+
pip install httpx
|
|
174
|
+
|
|
175
|
+
# run the example
|
|
176
|
+
python examples/basic.py
|
|
177
|
+
```
|
|
178
|
+
|
|
179
|
+
## License
|
|
180
|
+
|
|
181
|
+
MIT
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["setuptools>=61.0", "wheel"]
|
|
3
|
+
build-backend = "setuptools.build_meta"
|
|
4
|
+
[project]
|
|
5
|
+
name = "observe-sdk"
|
|
6
|
+
version = "0.1.0"
|
|
7
|
+
description = "Lightweight observability SDK for Python"
|
|
8
|
+
readme = "README.md"
|
|
9
|
+
license = { text = "MIT" }
|
|
10
|
+
authors = [{ name = "Kelechukwu Amadi-Keke", email = "favourkaycee23@gmail.com" }]
|
|
11
|
+
keywords = ["analytics", "observability", "monitoring"]
|
|
12
|
+
requires-python = ">=3.9"
|
|
13
|
+
dependencies = ["httpx>=0.27.0"]
|
|
14
|
+
|
|
15
|
+
[project.urls]
|
|
16
|
+
Homepage = "https://observe.dev"
|
|
17
|
+
Repository = "https://github.com/im-kaycee/observability-python-sdk"
|
|
@@ -0,0 +1,194 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: observe-sdk
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Lightweight observability SDK for Python
|
|
5
|
+
Author-email: Kelechukwu Amadi-Keke <favourkaycee23@gmail.com>
|
|
6
|
+
License: MIT
|
|
7
|
+
Project-URL: Homepage, https://observe.dev
|
|
8
|
+
Project-URL: Repository, https://github.com/im-kaycee/observability-python-sdk
|
|
9
|
+
Keywords: analytics,observability,monitoring
|
|
10
|
+
Requires-Python: >=3.9
|
|
11
|
+
Description-Content-Type: text/markdown
|
|
12
|
+
Requires-Dist: httpx>=0.27.0
|
|
13
|
+
|
|
14
|
+
# observe. — Python SDK
|
|
15
|
+
|
|
16
|
+
The Python SDK for observe. Track server-side events, capture exceptions, and monitor API performance from any Python application.
|
|
17
|
+
|
|
18
|
+
## Features
|
|
19
|
+
|
|
20
|
+
- Custom event tracking
|
|
21
|
+
- Exception capture with full stack traces
|
|
22
|
+
- User identification
|
|
23
|
+
- Fire and forget — sends in background threads, never blocks your app
|
|
24
|
+
- Works with FastAPI, Django, Flask, or plain Python
|
|
25
|
+
|
|
26
|
+
## Installation
|
|
27
|
+
|
|
28
|
+
```bash
|
|
29
|
+
pip install observe-sdk
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
> Until published to PyPI, copy `src/tracker.py` into your project directly.
|
|
33
|
+
|
|
34
|
+
## Quick start
|
|
35
|
+
|
|
36
|
+
```python
|
|
37
|
+
from tracker import Tracker
|
|
38
|
+
|
|
39
|
+
tracker = Tracker(
|
|
40
|
+
api_key="obs_your_secret_key",
|
|
41
|
+
server_url="https://api.observe.dev",
|
|
42
|
+
)
|
|
43
|
+
|
|
44
|
+
# track an event
|
|
45
|
+
tracker.track(
|
|
46
|
+
event_name="order_placed",
|
|
47
|
+
anonymous_id="anon_abc123",
|
|
48
|
+
properties={"plan": "pro"},
|
|
49
|
+
)
|
|
50
|
+
|
|
51
|
+
# capture an exception
|
|
52
|
+
try:
|
|
53
|
+
process_payment()
|
|
54
|
+
except Exception as e:
|
|
55
|
+
tracker.capture_exception(e, extra={"user_id": "user_123"})
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
## Framework guides
|
|
59
|
+
|
|
60
|
+
### FastAPI
|
|
61
|
+
|
|
62
|
+
Add the middleware to automatically track all requests:
|
|
63
|
+
|
|
64
|
+
```python
|
|
65
|
+
# main.py
|
|
66
|
+
from fastapi import FastAPI, Request
|
|
67
|
+
from tracker import Tracker
|
|
68
|
+
import time
|
|
69
|
+
|
|
70
|
+
app = FastAPI()
|
|
71
|
+
|
|
72
|
+
tracker = Tracker(
|
|
73
|
+
api_key="obs_your_secret_key",
|
|
74
|
+
server_url="https://api.observe.dev",
|
|
75
|
+
)
|
|
76
|
+
|
|
77
|
+
@app.middleware("http")
|
|
78
|
+
async def track_requests(request: Request, call_next):
|
|
79
|
+
start = time.time()
|
|
80
|
+
try:
|
|
81
|
+
response = await call_next(request)
|
|
82
|
+
duration_ms = round((time.time() - start) * 1000)
|
|
83
|
+
tracker.track(
|
|
84
|
+
event_name="api_request",
|
|
85
|
+
anonymous_id="server",
|
|
86
|
+
properties={
|
|
87
|
+
"method": request.method,
|
|
88
|
+
"path": request.url.path,
|
|
89
|
+
"status_code": response.status_code,
|
|
90
|
+
"duration_ms": duration_ms,
|
|
91
|
+
},
|
|
92
|
+
)
|
|
93
|
+
return response
|
|
94
|
+
except Exception as e:
|
|
95
|
+
tracker.capture_exception(e, extra={"path": request.url.path})
|
|
96
|
+
raise
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
### Django
|
|
100
|
+
|
|
101
|
+
Create a middleware file and add it to `settings.py`:
|
|
102
|
+
|
|
103
|
+
```python
|
|
104
|
+
# observe_middleware.py
|
|
105
|
+
import time
|
|
106
|
+
from tracker import Tracker
|
|
107
|
+
|
|
108
|
+
tracker = Tracker(
|
|
109
|
+
api_key="obs_your_secret_key",
|
|
110
|
+
server_url="https://api.observe.dev",
|
|
111
|
+
)
|
|
112
|
+
|
|
113
|
+
class ObserveMiddleware:
|
|
114
|
+
def __init__(self, get_response):
|
|
115
|
+
self.get_response = get_response
|
|
116
|
+
|
|
117
|
+
def __call__(self, request):
|
|
118
|
+
start = time.time()
|
|
119
|
+
response = self.get_response(request)
|
|
120
|
+
duration_ms = round((time.time() - start) * 1000)
|
|
121
|
+
|
|
122
|
+
tracker.track(
|
|
123
|
+
event_name="api_request",
|
|
124
|
+
anonymous_id=str(request.user.id) if request.user.is_authenticated else "anon",
|
|
125
|
+
properties={
|
|
126
|
+
"method": request.method,
|
|
127
|
+
"path": request.path,
|
|
128
|
+
"status_code": response.status_code,
|
|
129
|
+
"duration_ms": duration_ms,
|
|
130
|
+
},
|
|
131
|
+
)
|
|
132
|
+
return response
|
|
133
|
+
|
|
134
|
+
def process_exception(self, request, exception):
|
|
135
|
+
tracker.capture_exception(exception, extra={
|
|
136
|
+
"path": request.path,
|
|
137
|
+
"method": request.method,
|
|
138
|
+
})
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
```python
|
|
142
|
+
# settings.py
|
|
143
|
+
MIDDLEWARE = [
|
|
144
|
+
# ... existing middleware
|
|
145
|
+
"yourapp.observe_middleware.ObserveMiddleware",
|
|
146
|
+
]
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
## API reference
|
|
150
|
+
|
|
151
|
+
### `Tracker(api_key, server_url)`
|
|
152
|
+
|
|
153
|
+
| Parameter | Type | Required | Description |
|
|
154
|
+
|-----------|------|----------|-------------|
|
|
155
|
+
| `api_key` | str | Yes | Your project secret key |
|
|
156
|
+
| `server_url` | str | Yes | Your observe. server URL |
|
|
157
|
+
|
|
158
|
+
### `tracker.track(event_name, anonymous_id, properties?)`
|
|
159
|
+
|
|
160
|
+
| Parameter | Type | Required | Description |
|
|
161
|
+
|-----------|------|----------|-------------|
|
|
162
|
+
| `event_name` | str | Yes | Name of the event |
|
|
163
|
+
| `anonymous_id` | str | Yes | Session or visitor ID |
|
|
164
|
+
| `properties` | dict | No | Any additional data |
|
|
165
|
+
|
|
166
|
+
### `tracker.identify(anonymous_id, user_id)`
|
|
167
|
+
|
|
168
|
+
| Parameter | Type | Required | Description |
|
|
169
|
+
|-----------|------|----------|-------------|
|
|
170
|
+
| `anonymous_id` | str | Yes | Current session ID |
|
|
171
|
+
| `user_id` | str | Yes | Your user's ID |
|
|
172
|
+
|
|
173
|
+
### `tracker.capture_exception(exception, anonymous_id?, extra?)`
|
|
174
|
+
|
|
175
|
+
| Parameter | Type | Required | Description |
|
|
176
|
+
|-----------|------|----------|-------------|
|
|
177
|
+
| `exception` | Exception | Yes | The caught exception |
|
|
178
|
+
| `anonymous_id` | str | No | Defaults to `"server"` |
|
|
179
|
+
| `extra` | dict | No | Any additional context |
|
|
180
|
+
|
|
181
|
+
## Development
|
|
182
|
+
|
|
183
|
+
```bash
|
|
184
|
+
git clone https://github.com/yourname/observability-python-sdk.git
|
|
185
|
+
cd observability-python-sdk
|
|
186
|
+
pip install httpx
|
|
187
|
+
|
|
188
|
+
# run the example
|
|
189
|
+
python examples/basic.py
|
|
190
|
+
```
|
|
191
|
+
|
|
192
|
+
## License
|
|
193
|
+
|
|
194
|
+
MIT
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
httpx>=0.27.0
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
tracker
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import traceback
|
|
2
|
+
import threading
|
|
3
|
+
import httpx
|
|
4
|
+
from typing import Any
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
class Tracker:
|
|
8
|
+
def __init__(self, api_key: str, server_url: str):
|
|
9
|
+
if not api_key:
|
|
10
|
+
raise ValueError("Tracker: api_key is required")
|
|
11
|
+
if not server_url:
|
|
12
|
+
raise ValueError("Tracker: server_url is required")
|
|
13
|
+
|
|
14
|
+
self._api_key = api_key
|
|
15
|
+
self._server_url = server_url.rstrip("/")
|
|
16
|
+
self._headers = {
|
|
17
|
+
"Authorization": f"Bearer {self._api_key}",
|
|
18
|
+
"Content-Type": "application/json",
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
# ---- Tracking ----
|
|
22
|
+
|
|
23
|
+
def track(self, event_name: str, anonymous_id: str, properties: dict[str, Any] = {}):
|
|
24
|
+
"""Track a custom server-side event."""
|
|
25
|
+
if not event_name:
|
|
26
|
+
return
|
|
27
|
+
self._send("/ingest/events", {
|
|
28
|
+
"name": event_name,
|
|
29
|
+
"anonymous_id": anonymous_id,
|
|
30
|
+
"properties": properties,
|
|
31
|
+
})
|
|
32
|
+
|
|
33
|
+
def identify(self, anonymous_id: str, user_id: str):
|
|
34
|
+
"""Link an anonymous_id to a known user_id."""
|
|
35
|
+
self._send("/ingest/identify", {
|
|
36
|
+
"anonymous_id": anonymous_id,
|
|
37
|
+
"user_id": str(user_id),
|
|
38
|
+
})
|
|
39
|
+
|
|
40
|
+
def capture_exception(self, e: Exception, anonymous_id: str = "server", extra: dict = {}):
|
|
41
|
+
"""Capture an exception and send it as an event with the stack trace."""
|
|
42
|
+
self.track(
|
|
43
|
+
event_name="exception",
|
|
44
|
+
anonymous_id=anonymous_id,
|
|
45
|
+
properties={
|
|
46
|
+
"exception_type": type(e).__name__,
|
|
47
|
+
"message": str(e),
|
|
48
|
+
"stack_trace": traceback.format_exc(),
|
|
49
|
+
**extra,
|
|
50
|
+
},
|
|
51
|
+
)
|
|
52
|
+
|
|
53
|
+
# ---- Transport ----
|
|
54
|
+
|
|
55
|
+
def _send(self, endpoint: str, payload: dict):
|
|
56
|
+
"""Fire and forget — runs in a background thread so it never blocks."""
|
|
57
|
+
thread = threading.Thread(
|
|
58
|
+
target=self._post,
|
|
59
|
+
args=(endpoint, payload),
|
|
60
|
+
daemon=True,
|
|
61
|
+
)
|
|
62
|
+
thread.start()
|
|
63
|
+
|
|
64
|
+
def _post(self, endpoint: str, payload: dict):
|
|
65
|
+
try:
|
|
66
|
+
with httpx.Client() as client:
|
|
67
|
+
client.post(
|
|
68
|
+
f"{self._server_url}{endpoint}",
|
|
69
|
+
json=payload,
|
|
70
|
+
headers=self._headers,
|
|
71
|
+
timeout=5.0,
|
|
72
|
+
)
|
|
73
|
+
except Exception as e:
|
|
74
|
+
# fail silently — tracking should never crash the host app
|
|
75
|
+
print(f"Tracker: failed to send event — {e}")
|