stemtrace 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.
- stemtrace/__init__.py +173 -0
- stemtrace/core/__init__.py +15 -0
- stemtrace/core/events.py +67 -0
- stemtrace/core/exceptions.py +25 -0
- stemtrace/core/graph.py +348 -0
- stemtrace/core/ports.py +42 -0
- stemtrace/library/__init__.py +1 -0
- stemtrace/library/bootsteps.py +169 -0
- stemtrace/library/config.py +55 -0
- stemtrace/library/scrubbing.py +195 -0
- stemtrace/library/signals.py +434 -0
- stemtrace/library/transports/__init__.py +36 -0
- stemtrace/library/transports/memory.py +33 -0
- stemtrace/library/transports/redis.py +92 -0
- stemtrace/py.typed +0 -0
- stemtrace/server/__init__.py +24 -0
- stemtrace/server/__main__.py +136 -0
- stemtrace/server/api/__init__.py +29 -0
- stemtrace/server/api/routes.py +270 -0
- stemtrace/server/api/schemas.py +136 -0
- stemtrace/server/api/websocket.py +28 -0
- stemtrace/server/consumer.py +133 -0
- stemtrace/server/fastapi/__init__.py +13 -0
- stemtrace/server/fastapi/auth.py +77 -0
- stemtrace/server/fastapi/extension.py +121 -0
- stemtrace/server/fastapi/router.py +42 -0
- stemtrace/server/store.py +260 -0
- stemtrace/server/ui/__init__.py +5 -0
- stemtrace/server/ui/frontend/biome.json +58 -0
- stemtrace/server/ui/frontend/dist/assets/index-CCs7iO1n.css +1 -0
- stemtrace/server/ui/frontend/dist/assets/index-Dao0_Q6x.js +14 -0
- stemtrace/server/ui/frontend/dist/index.html +17 -0
- stemtrace/server/ui/frontend/index.html +16 -0
- stemtrace/server/ui/frontend/package-lock.json +4049 -0
- stemtrace/server/ui/frontend/package.json +46 -0
- stemtrace/server/ui/frontend/playwright.config.ts +40 -0
- stemtrace/server/ui/frontend/postcss.config.js +5 -0
- stemtrace/server/ui/frontend/src/api/client.ts +173 -0
- stemtrace/server/ui/frontend/src/api/queries.ts +151 -0
- stemtrace/server/ui/frontend/src/components/DateRangePicker.tsx +244 -0
- stemtrace/server/ui/frontend/src/components/Filters.tsx +116 -0
- stemtrace/server/ui/frontend/src/components/TaskGraph.tsx +453 -0
- stemtrace/server/ui/frontend/src/components/TaskList.tsx +172 -0
- stemtrace/server/ui/frontend/src/components/TaskStateBadge.tsx +27 -0
- stemtrace/server/ui/frontend/src/components/TaskTimeline.tsx +144 -0
- stemtrace/server/ui/frontend/src/components/TimelineBar.tsx +224 -0
- stemtrace/server/ui/frontend/src/components/Tooltip.tsx +54 -0
- stemtrace/server/ui/frontend/src/hooks/WebSocketContext.tsx +143 -0
- stemtrace/server/ui/frontend/src/hooks/useInfiniteScroll.ts +56 -0
- stemtrace/server/ui/frontend/src/index.css +104 -0
- stemtrace/server/ui/frontend/src/main.tsx +44 -0
- stemtrace/server/ui/frontend/src/routes/__root.tsx +103 -0
- stemtrace/server/ui/frontend/src/routes/graph.$rootId.tsx +51 -0
- stemtrace/server/ui/frontend/src/routes/graphs.tsx +186 -0
- stemtrace/server/ui/frontend/src/routes/index.tsx +119 -0
- stemtrace/server/ui/frontend/src/routes/registry.tsx +211 -0
- stemtrace/server/ui/frontend/src/routes/tasks.$taskId.tsx +313 -0
- stemtrace/server/ui/frontend/src/utils/format.ts +38 -0
- stemtrace/server/ui/frontend/tests/graphs.spec.ts +485 -0
- stemtrace/server/ui/frontend/tests/registry.spec.ts +117 -0
- stemtrace/server/ui/frontend/tests/task-detail.spec.ts +147 -0
- stemtrace/server/ui/frontend/tests/tasks.spec.ts +92 -0
- stemtrace/server/ui/frontend/tsconfig.json +32 -0
- stemtrace/server/ui/frontend/tsconfig.tsbuildinfo +1 -0
- stemtrace/server/ui/frontend/vite.config.ts +30 -0
- stemtrace/server/ui/static.py +56 -0
- stemtrace/server/websocket.py +99 -0
- stemtrace-0.1.0.dist-info/METADATA +428 -0
- stemtrace-0.1.0.dist-info/RECORD +72 -0
- stemtrace-0.1.0.dist-info/WHEEL +4 -0
- stemtrace-0.1.0.dist-info/entry_points.txt +2 -0
- stemtrace-0.1.0.dist-info/licenses/LICENSE +21 -0
|
@@ -0,0 +1,428 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: stemtrace
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: A lightweight Celery task flow visualizer
|
|
5
|
+
Project-URL: Homepage, https://github.com/iansokolskyi/stemtrace
|
|
6
|
+
Project-URL: Documentation, https://github.com/iansokolskyi/stemtrace#readme
|
|
7
|
+
Project-URL: Repository, https://github.com/iansokolskyi/stemtrace
|
|
8
|
+
Project-URL: Issues, https://github.com/iansokolskyi/stemtrace/issues
|
|
9
|
+
Project-URL: Changelog, https://github.com/iansokolskyi/stemtrace/blob/main/CHANGELOG.md
|
|
10
|
+
Author-email: Ian Sokolskyi <iansokolskyi@gmail.com>
|
|
11
|
+
License: MIT
|
|
12
|
+
License-File: LICENSE
|
|
13
|
+
Keywords: celery,monitoring,queue,task,visualization,workflow
|
|
14
|
+
Classifier: Development Status :: 3 - Alpha
|
|
15
|
+
Classifier: Environment :: Console
|
|
16
|
+
Classifier: Environment :: Web Environment
|
|
17
|
+
Classifier: Framework :: Celery
|
|
18
|
+
Classifier: Intended Audience :: Developers
|
|
19
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
20
|
+
Classifier: Operating System :: OS Independent
|
|
21
|
+
Classifier: Programming Language :: Python :: 3
|
|
22
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
23
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
24
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
25
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
26
|
+
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
27
|
+
Classifier: Topic :: System :: Monitoring
|
|
28
|
+
Classifier: Typing :: Typed
|
|
29
|
+
Requires-Python: >=3.10
|
|
30
|
+
Requires-Dist: celery>=5.0.0
|
|
31
|
+
Requires-Dist: fastapi>=0.100.0
|
|
32
|
+
Requires-Dist: httpx>=0.24.0
|
|
33
|
+
Requires-Dist: pydantic>=2.0.0
|
|
34
|
+
Requires-Dist: redis>=4.0.0
|
|
35
|
+
Requires-Dist: typer>=0.9.0
|
|
36
|
+
Requires-Dist: typing-extensions>=4.0.0
|
|
37
|
+
Requires-Dist: uvicorn[standard]>=0.20.0
|
|
38
|
+
Provides-Extra: dev
|
|
39
|
+
Requires-Dist: build>=1.0.0; extra == 'dev'
|
|
40
|
+
Requires-Dist: bump-my-version>=0.28.0; extra == 'dev'
|
|
41
|
+
Requires-Dist: hatchling>=1.20.0; extra == 'dev'
|
|
42
|
+
Requires-Dist: mypy>=1.0.0; extra == 'dev'
|
|
43
|
+
Requires-Dist: pika>=1.3.0; extra == 'dev'
|
|
44
|
+
Requires-Dist: pre-commit>=3.0.0; extra == 'dev'
|
|
45
|
+
Requires-Dist: pytest-asyncio>=0.21.0; extra == 'dev'
|
|
46
|
+
Requires-Dist: pytest-cov>=4.0.0; extra == 'dev'
|
|
47
|
+
Requires-Dist: pytest>=7.0.0; extra == 'dev'
|
|
48
|
+
Requires-Dist: ruff>=0.1.0; extra == 'dev'
|
|
49
|
+
Requires-Dist: twine>=5.0.0; extra == 'dev'
|
|
50
|
+
Requires-Dist: types-redis>=4.0.0; extra == 'dev'
|
|
51
|
+
Requires-Dist: websockets>=12.0; extra == 'dev'
|
|
52
|
+
Provides-Extra: rabbitmq
|
|
53
|
+
Requires-Dist: pika>=1.3.0; extra == 'rabbitmq'
|
|
54
|
+
Description-Content-Type: text/markdown
|
|
55
|
+
|
|
56
|
+
# stemtrace 🌿
|
|
57
|
+
|
|
58
|
+
**Zero-infrastructure Celery task flow visualizer**
|
|
59
|
+
|
|
60
|
+
[](https://badge.fury.io/py/stemtrace)
|
|
61
|
+
[](https://pypi.org/project/stemtrace/)
|
|
62
|
+
[](https://github.com/iansokolskyi/stemtrace/actions/workflows/ci.yml)
|
|
63
|
+
[](https://codecov.io/gh/iansokolskyi/stemtrace)
|
|
64
|
+
[](https://opensource.org/licenses/MIT)
|
|
65
|
+
[](https://github.com/astral-sh/ruff)
|
|
66
|
+
[](https://mypy-lang.org/)
|
|
67
|
+
|
|
68
|
+
---
|
|
69
|
+
|
|
70
|
+
> **Flower answers "what exists". stemtrace answers "what happened".**
|
|
71
|
+
|
|
72
|
+
`stemtrace` models Celery as a graph of executions derived from events. Visualize task flows, timelines, retries, and parent-child relationships — using your existing broker with zero new infrastructure.
|
|
73
|
+
|
|
74
|
+
## ✨ Features
|
|
75
|
+
|
|
76
|
+
- **Task Flow Graphs** — Visualize parent → child chains, groups, and chords as DAGs
|
|
77
|
+
- **Canvas Awareness** — Synthetic GROUP nodes for `group()` and `chord()` visualization
|
|
78
|
+
- **Execution Timeline** — See queued → received → started → retried → finished states
|
|
79
|
+
- **Full Lifecycle Capture** — PENDING, RECEIVED, STARTED, RETRY, SUCCESS, FAILURE states
|
|
80
|
+
- **Arguments & Results** — View task inputs and outputs with sensitive data scrubbing
|
|
81
|
+
- **Exception Capture** — Full traceback visibility on retries and failures
|
|
82
|
+
- **Task Registry** — Browse all discovered task definitions
|
|
83
|
+
- **Timing Visibility** — Start time and duration shown directly in graph nodes
|
|
84
|
+
- **Correlation Tracking** — Trace requests across multiple tasks via `trace_id`
|
|
85
|
+
- **Retry Visibility** — Know exactly which retries happened and why
|
|
86
|
+
- **Zero Infrastructure** — Uses your existing broker; no database required
|
|
87
|
+
- **Broker-Agnostic** — Works with Redis, RabbitMQ, and other Celery brokers
|
|
88
|
+
- **FastAPI Pluggable** — Mount directly into your existing FastAPI app
|
|
89
|
+
- **Zero Config** — Auto-detects your Celery broker configuration
|
|
90
|
+
- **Read-Only** — Safe for production; never modifies your task queue
|
|
91
|
+
|
|
92
|
+
## 🚀 Quick Start
|
|
93
|
+
|
|
94
|
+
### 1. Install
|
|
95
|
+
|
|
96
|
+
```bash
|
|
97
|
+
pip install stemtrace
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
### 2. Instrument your Celery app
|
|
101
|
+
|
|
102
|
+
```python
|
|
103
|
+
from celery import Celery
|
|
104
|
+
import stemtrace
|
|
105
|
+
|
|
106
|
+
app = Celery("myapp", broker="redis://localhost:6379/0")
|
|
107
|
+
|
|
108
|
+
# One line to enable flow tracking
|
|
109
|
+
stemtrace.init(app)
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
### 3. Run the visualizer
|
|
113
|
+
|
|
114
|
+
```bash
|
|
115
|
+
stemtrace server
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
Open [http://localhost:8000](http://localhost:8000) and watch your task flows come alive.
|
|
119
|
+
|
|
120
|
+
> By default, connects to `redis://localhost:6379/0`. Override with `--broker-url` or `STEMTRACE_BROKER_URL` env var.
|
|
121
|
+
|
|
122
|
+
See [Deployment Options](#️-deployment-options) for FastAPI integration and production setups.
|
|
123
|
+
|
|
124
|
+
## 📦 Architecture
|
|
125
|
+
|
|
126
|
+
stemtrace is designed as two decoupled components:
|
|
127
|
+
|
|
128
|
+
```text
|
|
129
|
+
┌──────────────────────────────────────────────────────────────────┐
|
|
130
|
+
│ Your Application │
|
|
131
|
+
│ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │
|
|
132
|
+
│ │ Celery Worker│ │ Celery Worker│ │ Celery Worker│ │
|
|
133
|
+
│ │ + stemtrace │ │ + stemtrace │ │ + stemtrace │ │
|
|
134
|
+
│ └──────┬───────┘ └──────┬───────┘ └──────┬───────┘ │
|
|
135
|
+
│ │ │ │ │
|
|
136
|
+
│ └───────────────────┼───────────────────┘ │
|
|
137
|
+
│ │ events │
|
|
138
|
+
│ ▼ │
|
|
139
|
+
│ ┌───────────────┐ │
|
|
140
|
+
│ │ Broker │ │
|
|
141
|
+
│ └───────┬───────┘ │
|
|
142
|
+
│ │ │
|
|
143
|
+
└─────────────────────────────┼────────────────────────────────────┘
|
|
144
|
+
│
|
|
145
|
+
▼
|
|
146
|
+
┌───────────────────┐
|
|
147
|
+
│ stemtrace │
|
|
148
|
+
│ server (viewer) │
|
|
149
|
+
│ ┌─────────────┐ │
|
|
150
|
+
│ │ Web UI │ │
|
|
151
|
+
│ └─────────────┘ │
|
|
152
|
+
└───────────────────┘
|
|
153
|
+
```
|
|
154
|
+
|
|
155
|
+
### Library (`stemtrace`)
|
|
156
|
+
- Hooks into Celery signals
|
|
157
|
+
- Captures task lifecycle events
|
|
158
|
+
- Sends normalized events to the broker
|
|
159
|
+
- **Zero overhead in critical path** — fire-and-forget writes
|
|
160
|
+
|
|
161
|
+
### Server (`stemtrace server`)
|
|
162
|
+
- Reads events from the broker
|
|
163
|
+
- Builds task graphs
|
|
164
|
+
- Serves the web UI
|
|
165
|
+
- **Completely read-only** — safe for production
|
|
166
|
+
|
|
167
|
+
## 🔧 Configuration
|
|
168
|
+
|
|
169
|
+
### Library Options
|
|
170
|
+
|
|
171
|
+
```python
|
|
172
|
+
import stemtrace
|
|
173
|
+
|
|
174
|
+
stemtrace.init(
|
|
175
|
+
app,
|
|
176
|
+
# Optional: override broker URL (defaults to Celery's broker_url)
|
|
177
|
+
transport_url="redis://localhost:6379/0",
|
|
178
|
+
prefix="stemtrace", # Key/queue prefix
|
|
179
|
+
ttl=86400, # Event TTL in seconds (default: 24h)
|
|
180
|
+
|
|
181
|
+
# Data capture (all enabled by default)
|
|
182
|
+
capture_args=True, # Capture task args/kwargs
|
|
183
|
+
capture_result=True, # Capture return values
|
|
184
|
+
|
|
185
|
+
# Sensitive data scrubbing (Sentry-style)
|
|
186
|
+
scrub_sensitive_data=True, # Scrub passwords, API keys, etc.
|
|
187
|
+
additional_sensitive_keys=frozenset({"my_secret"}), # Add custom keys
|
|
188
|
+
safe_keys=frozenset({"public_key"}), # Never scrub these keys
|
|
189
|
+
)
|
|
190
|
+
|
|
191
|
+
# Introspection (after init)
|
|
192
|
+
stemtrace.is_initialized() # -> True
|
|
193
|
+
stemtrace.get_config() # -> StemtraceConfig
|
|
194
|
+
stemtrace.get_transport() # -> EventTransport (for testing)
|
|
195
|
+
```
|
|
196
|
+
|
|
197
|
+
#### Sensitive Data Scrubbing
|
|
198
|
+
|
|
199
|
+
By default, stemtrace scrubs common sensitive keys from task arguments:
|
|
200
|
+
- Passwords: `password`, `passwd`, `pwd`, `secret`
|
|
201
|
+
- API keys: `api_key`, `apikey`, `token`, `bearer`, `authorization`
|
|
202
|
+
- Financial: `credit_card`, `cvv`, `ssn`
|
|
203
|
+
- Session: `cookie`, `session`, `csrf`
|
|
204
|
+
|
|
205
|
+
Scrubbed values appear as `[Filtered]` in the UI.
|
|
206
|
+
|
|
207
|
+
### Canvas Graph Visualization
|
|
208
|
+
|
|
209
|
+
stemtrace automatically detects and visualizes Celery canvas constructs:
|
|
210
|
+
|
|
211
|
+
```text
|
|
212
|
+
# Parent-spawned group: GROUP is child of parent
|
|
213
|
+
batch_processor
|
|
214
|
+
└── ┌─ GROUP ──────────┐
|
|
215
|
+
│ ├── add(1, 2) │
|
|
216
|
+
│ ├── add(3, 4) │
|
|
217
|
+
│ └── add(5, 6) │
|
|
218
|
+
└──────────────────┘
|
|
219
|
+
|
|
220
|
+
# Standalone group: GROUP is a root node
|
|
221
|
+
┌─ GROUP ──────────┐
|
|
222
|
+
│ ├── add(1, 1) │
|
|
223
|
+
│ ├── add(2, 2) │
|
|
224
|
+
│ └── add(3, 3) │
|
|
225
|
+
└──────────────────┘
|
|
226
|
+
|
|
227
|
+
# Chord: header tasks inside, callback outside with edges
|
|
228
|
+
┌─ CHORD ──────────┐
|
|
229
|
+
│ ├── add(10, 10) │──┐
|
|
230
|
+
│ ├── add(20, 20) │──┼──► aggregate_results
|
|
231
|
+
│ └── add(30, 30) │──┘
|
|
232
|
+
└──────────────────┘
|
|
233
|
+
```
|
|
234
|
+
|
|
235
|
+
- **Synthetic containers** — GROUP/CHORD nodes are always created when 2+ tasks share a `group_id`
|
|
236
|
+
- **Parent linking** — When spawned from a parent task, the container becomes a child of that parent
|
|
237
|
+
- **Chord callbacks** — Rendered outside the container with edges from each header task
|
|
238
|
+
- **Timing** — Each node displays start time and duration directly in the graph
|
|
239
|
+
- **Aggregate state** — Container shows running/success/failure based on member states
|
|
240
|
+
|
|
241
|
+
### Environment Variables
|
|
242
|
+
|
|
243
|
+
| Variable | Description | Default |
|
|
244
|
+
|----------|-------------|---------|
|
|
245
|
+
| `STEMTRACE_BROKER_URL` | Broker connection URL | Auto-detect from Celery |
|
|
246
|
+
| `STEMTRACE_TTL` | Event TTL in seconds | `86400` |
|
|
247
|
+
| `STEMTRACE_PREFIX` | Key/queue prefix | `stemtrace` |
|
|
248
|
+
|
|
249
|
+
### Supported Brokers
|
|
250
|
+
|
|
251
|
+
| Broker | URL Scheme | Status |
|
|
252
|
+
|--------|------------|--------|
|
|
253
|
+
| Redis | `redis://`, `rediss://` | ✅ Supported |
|
|
254
|
+
| RabbitMQ | `amqp://`, `amqps://` | 🚧 Planned |
|
|
255
|
+
| Amazon SQS | `sqs://` | 🚧 Planned |
|
|
256
|
+
|
|
257
|
+
## 🐳 Docker
|
|
258
|
+
|
|
259
|
+
```bash
|
|
260
|
+
# With Redis
|
|
261
|
+
docker run -p 8000:8000 \
|
|
262
|
+
-e STEMTRACE_BROKER_URL=redis://host.docker.internal:6379/0 \
|
|
263
|
+
ghcr.io/stemtrace/server
|
|
264
|
+
|
|
265
|
+
# With RabbitMQ
|
|
266
|
+
docker run -p 8000:8000 \
|
|
267
|
+
-e STEMTRACE_BROKER_URL=amqp://guest:guest@host.docker.internal:5672/ \
|
|
268
|
+
ghcr.io/stemtrace/server
|
|
269
|
+
```
|
|
270
|
+
|
|
271
|
+
Or with Docker Compose:
|
|
272
|
+
|
|
273
|
+
```yaml
|
|
274
|
+
services:
|
|
275
|
+
stemtrace:
|
|
276
|
+
image: ghcr.io/stemtrace/server
|
|
277
|
+
ports:
|
|
278
|
+
- "8000:8000"
|
|
279
|
+
environment:
|
|
280
|
+
- STEMTRACE_BROKER_URL=redis://redis:6379/0
|
|
281
|
+
```
|
|
282
|
+
|
|
283
|
+
## 🖥️ Deployment Options
|
|
284
|
+
|
|
285
|
+
stemtrace offers two deployment modes depending on your needs:
|
|
286
|
+
|
|
287
|
+
| Mode | Best For | Command |
|
|
288
|
+
|------|----------|---------|
|
|
289
|
+
| **Standalone Server** | Dedicated monitoring, simple setup | `stemtrace server` |
|
|
290
|
+
| **FastAPI Embedded** | Single-app deployment, existing FastAPI apps | `StemtraceExtension` |
|
|
291
|
+
|
|
292
|
+
### Option 1: Standalone Server (Recommended)
|
|
293
|
+
|
|
294
|
+
The simplest way to run stemtrace — a dedicated monitoring service:
|
|
295
|
+
|
|
296
|
+
```bash
|
|
297
|
+
pip install stemtrace
|
|
298
|
+
|
|
299
|
+
stemtrace server
|
|
300
|
+
```
|
|
301
|
+
|
|
302
|
+
Open [http://localhost:8000](http://localhost:8000) to view the dashboard.
|
|
303
|
+
|
|
304
|
+
#### Server Options
|
|
305
|
+
|
|
306
|
+
```bash
|
|
307
|
+
stemtrace server \
|
|
308
|
+
--broker-url redis://myredis:6379/0 \
|
|
309
|
+
--host 0.0.0.0 \
|
|
310
|
+
--port 8000 \
|
|
311
|
+
--reload # For development
|
|
312
|
+
```
|
|
313
|
+
|
|
314
|
+
#### High-Scale Production Setup
|
|
315
|
+
|
|
316
|
+
For high-throughput environments, run the consumer separately from the web server:
|
|
317
|
+
|
|
318
|
+
```bash
|
|
319
|
+
# Terminal 1: Run consumer (processes events)
|
|
320
|
+
stemtrace consume
|
|
321
|
+
|
|
322
|
+
# Terminal 2: Run API server (separate process, shares state via broker)
|
|
323
|
+
stemtrace server
|
|
324
|
+
```
|
|
325
|
+
### Option 2: FastAPI Embedded
|
|
326
|
+
|
|
327
|
+
Mount stemtrace directly into your existing FastAPI application:
|
|
328
|
+
|
|
329
|
+
```python
|
|
330
|
+
from fastapi import FastAPI
|
|
331
|
+
from stemtrace.server import StemtraceExtension
|
|
332
|
+
|
|
333
|
+
flow = StemtraceExtension(broker_url="redis://localhost:6379/0")
|
|
334
|
+
app = FastAPI(lifespan=flow.lifespan)
|
|
335
|
+
app.include_router(flow.router, prefix="/stemtrace")
|
|
336
|
+
```
|
|
337
|
+
|
|
338
|
+
Access the dashboard at `/stemtrace/` within your app.
|
|
339
|
+
|
|
340
|
+
#### With Custom Authentication
|
|
341
|
+
|
|
342
|
+
Use your existing auth middleware:
|
|
343
|
+
|
|
344
|
+
```python
|
|
345
|
+
from fastapi import Depends
|
|
346
|
+
from stemtrace.server import StemtraceExtension
|
|
347
|
+
from your_app.auth import require_admin
|
|
348
|
+
|
|
349
|
+
flow = StemtraceExtension(
|
|
350
|
+
broker_url="redis://localhost:6379/0",
|
|
351
|
+
auth_dependency=Depends(require_admin),
|
|
352
|
+
)
|
|
353
|
+
app = FastAPI(lifespan=flow.lifespan)
|
|
354
|
+
app.include_router(flow.router, prefix="/stemtrace")
|
|
355
|
+
```
|
|
356
|
+
|
|
357
|
+
Or use built-in auth helpers:
|
|
358
|
+
|
|
359
|
+
```python
|
|
360
|
+
from stemtrace.server import StemtraceExtension, require_basic_auth
|
|
361
|
+
|
|
362
|
+
flow = StemtraceExtension(
|
|
363
|
+
broker_url="redis://localhost:6379/0",
|
|
364
|
+
auth_dependency=require_basic_auth("admin", "secret"),
|
|
365
|
+
)
|
|
366
|
+
app = FastAPI(lifespan=flow.lifespan)
|
|
367
|
+
app.include_router(flow.router, prefix="/stemtrace")
|
|
368
|
+
```
|
|
369
|
+
|
|
370
|
+
#### Embedded Consumer Modes
|
|
371
|
+
|
|
372
|
+
| Mode | Use Case | Setup |
|
|
373
|
+
|------|----------|-------|
|
|
374
|
+
| Embedded | Development, simple apps | Default — consumer runs in FastAPI process |
|
|
375
|
+
| External | Production, high scale | Run `stemtrace consume` separately |
|
|
376
|
+
|
|
377
|
+
## 🗺️ Roadmap
|
|
378
|
+
|
|
379
|
+
### Completed
|
|
380
|
+
|
|
381
|
+
- [x] Task lifecycle tracking via signals
|
|
382
|
+
- [x] Broker-agnostic event transport (Redis Streams)
|
|
383
|
+
- [x] FastAPI pluggable integration
|
|
384
|
+
- [x] React SPA dashboard with real-time WebSocket updates
|
|
385
|
+
- [x] Task flow graph visualization
|
|
386
|
+
- [x] Execution timeline view
|
|
387
|
+
- [x] Task args/kwargs capture with sensitive data scrubbing
|
|
388
|
+
- [x] Exception and traceback capture
|
|
389
|
+
- [x] Task registry (browse all discovered tasks)
|
|
390
|
+
- [x] PENDING/RECEIVED state capture
|
|
391
|
+
- [x] E2E test suite (Docker API tests + Playwright browser tests)
|
|
392
|
+
- [x] Canvas graph reconstruction (`group_id` capture, synthetic GROUP/CHORD nodes)
|
|
393
|
+
- [x] Chord callback linking (CHORD node → callback edge)
|
|
394
|
+
- [x] Timing display in graph nodes (start time, duration)
|
|
395
|
+
|
|
396
|
+
### Planned
|
|
397
|
+
|
|
398
|
+
- [ ] Worker/queue tracking in events
|
|
399
|
+
- [ ] Monitoring APIs (workers, stats, orphan detection)
|
|
400
|
+
- [ ] UI reorganization (Dashboard, unified Executions, enhanced Registry)
|
|
401
|
+
- [ ] RabbitMQ transport
|
|
402
|
+
- [ ] OpenTelemetry export
|
|
403
|
+
- [ ] Webhook event export
|
|
404
|
+
- [ ] JSON export API
|
|
405
|
+
|
|
406
|
+
## 🤝 Contributing
|
|
407
|
+
|
|
408
|
+
Contributions are welcome! Please read our [Contributing Guide](CONTRIBUTING.md) first.
|
|
409
|
+
|
|
410
|
+
```bash
|
|
411
|
+
# Clone the repo
|
|
412
|
+
git clone https://github.com/iansokolskyi/stemtrace.git
|
|
413
|
+
cd stemtrace
|
|
414
|
+
|
|
415
|
+
# Install dependencies (requires uv)
|
|
416
|
+
uv sync --all-extras
|
|
417
|
+
|
|
418
|
+
# Run checks
|
|
419
|
+
make check
|
|
420
|
+
```
|
|
421
|
+
|
|
422
|
+
## 📄 License
|
|
423
|
+
|
|
424
|
+
MIT License — see [LICENSE](LICENSE) for details.
|
|
425
|
+
|
|
426
|
+
---
|
|
427
|
+
|
|
428
|
+
**stemtrace** is not affiliated with the Celery project. Celery is a trademark of Ask Solem.
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
stemtrace/__init__.py,sha256=VCi7FsIzWLrjuc1U1Fck4lo9LHGzsoo8yNSvi4OzjAE,4981
|
|
2
|
+
stemtrace/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
3
|
+
stemtrace/core/__init__.py,sha256=0xTAr5JzuVnkrEL5kNMMEn6gco_ua7bqpks03eOlzrU,403
|
|
4
|
+
stemtrace/core/events.py,sha256=biwfWmKvUpuGIJxIsTiAfQG6XmCG9Q1CrgTDJbdtMzQ,2195
|
|
5
|
+
stemtrace/core/exceptions.py,sha256=NB5pixKgogcqtZAiwZSQNK5WtPkwiA-mjy2zFV49sHY,686
|
|
6
|
+
stemtrace/core/graph.py,sha256=UiNREghBjwahid65jr3rVIIiLPTmHeFI74qmpjYL0nA,14360
|
|
7
|
+
stemtrace/core/ports.py,sha256=eG3hBs0eeT54eASJwSQLUtfOlaJugw9Wft-mV7zqwzE,1256
|
|
8
|
+
stemtrace/library/__init__.py,sha256=ALeKSzpGbdXRHJmeCY5PmOW3yqr8KaJtZA0uY8Uaf58,46
|
|
9
|
+
stemtrace/library/bootsteps.py,sha256=kbbHWjgf-BNfi4_tuZ6DlkJyO6AhWwIvK3wE6PvGLh4,5951
|
|
10
|
+
stemtrace/library/config.py,sha256=Eg2r9k2IkPcbafYGz5ObQzx6v441bYRuIT9koUjGd20,1685
|
|
11
|
+
stemtrace/library/scrubbing.py,sha256=jasysLmHj3QrFyxLo5oCwcuEN0x-8_fffTM8HUnGVDU,5806
|
|
12
|
+
stemtrace/library/signals.py,sha256=N6nBwj9lFqXw1Wz05i3UOtaEHaO_MzvHUuc9-4v-p40,13259
|
|
13
|
+
stemtrace/library/transports/__init__.py,sha256=6T4g0PbwmPDPOfpqsyIFdCHlNmIMqHtLezS0Ui-5mBA,952
|
|
14
|
+
stemtrace/library/transports/memory.py,sha256=SgcmKQrhMKx-jy52CrRQokFlY2cby6krkWl5y8Fmtro,861
|
|
15
|
+
stemtrace/library/transports/redis.py,sha256=UN_-r42eBtnIvDq_fm7v2w3106UxZRcrtTuY-GRyxVQ,2823
|
|
16
|
+
stemtrace/server/__init__.py,sha256=LKUW0aSjqdmM1ClwCnsaSBS0PUO_YyHkxpHtSoI4TaA,587
|
|
17
|
+
stemtrace/server/__main__.py,sha256=wTEPquBo78VYXHMpFbRO5fyUGYQ97iwPsst_2ngp9yk,3581
|
|
18
|
+
stemtrace/server/consumer.py,sha256=vg3jyXaqtSRUb1Qg2juxwoWMBCZfsUxGnCkdG_Lfu8A,3994
|
|
19
|
+
stemtrace/server/store.py,sha256=uRwxW1WdyKGlFFv-YO2lw84m1rZdvuRol3005cXa20M,9162
|
|
20
|
+
stemtrace/server/websocket.py,sha256=pwFPsv8o9px432FpzJadAY_U1k4jYjL83dvFaKv-JKA,3520
|
|
21
|
+
stemtrace/server/api/__init__.py,sha256=tZBo4R6F59KC9eUYwJxTNm-4O4b4iywUWJZb1wau-E0,699
|
|
22
|
+
stemtrace/server/api/routes.py,sha256=vKhImnvzvoVxv-ZJlcsVWHyrp1Qv9VAH1VSlaNkOw8o,9358
|
|
23
|
+
stemtrace/server/api/schemas.py,sha256=lRKzQif67VFDJjHf1PLCf4OZPbqnnbbbYzYLc-O8HVA,3117
|
|
24
|
+
stemtrace/server/api/websocket.py,sha256=OpZBvCK7JY1yPqARDBakuyUqZ3rm-RuR1yYJHufye5o,857
|
|
25
|
+
stemtrace/server/fastapi/__init__.py,sha256=uK1rAAGvhTokZ05c3l3pEVLFJYzL0hPgDAxWG2pEEdU,372
|
|
26
|
+
stemtrace/server/fastapi/auth.py,sha256=TXOtDXRJuJfzSRJDab6rGef6ANP_pZbnWcg6J94WrYI,2303
|
|
27
|
+
stemtrace/server/fastapi/extension.py,sha256=vc8HosBCUhZHR-SqGYMHBRvn80OHoJpQ_yZIVAHBjYk,3835
|
|
28
|
+
stemtrace/server/fastapi/router.py,sha256=ttQ4pH6_cvHB9DD5d801oliciJNPT1bFQ3KPQKZTw60,1241
|
|
29
|
+
stemtrace/server/ui/__init__.py,sha256=5SJ0J1k0AcUQhDsvIRM4Fssh2U2gtlMOBFEqPB4SfqA,179
|
|
30
|
+
stemtrace/server/ui/static.py,sha256=FcYS-_FgW1uzASFrnRqpYguFUB5gl7iTBz28m9DnVw4,1835
|
|
31
|
+
stemtrace/server/ui/frontend/biome.json,sha256=kX0OM-agwyiGsjevcL09JfjzZAcSyCMAAqsVr4LegUA,1185
|
|
32
|
+
stemtrace/server/ui/frontend/index.html,sha256=yxl3UpLiqoKS1SQJ7v9uGGrvQyULWvG7RZDqaDuReiI,656
|
|
33
|
+
stemtrace/server/ui/frontend/package-lock.json,sha256=iXT5FT2_JrzP2ZdEuHDbbRKYn3F8CUkomwbSiUFl2IY,136799
|
|
34
|
+
stemtrace/server/ui/frontend/package.json,sha256=CkKoky9EIb_Bu9AZ-uTy-aGst6qH7eqxiP5fXfbMdN4,1281
|
|
35
|
+
stemtrace/server/ui/frontend/playwright.config.ts,sha256=amsln86idhc-UMPyeAjEVaTkAxL68fHG7UTkraAF7AQ,1032
|
|
36
|
+
stemtrace/server/ui/frontend/postcss.config.js,sha256=P8jRwTrZY7v32gTVkCTTjMKtFFY7Nq_XG8i0PHFI3SU,69
|
|
37
|
+
stemtrace/server/ui/frontend/tsconfig.json,sha256=V0r2aFumnBIEdaU3-RHKlvKZxATrn4mt-bnp9UuwWo8,713
|
|
38
|
+
stemtrace/server/ui/frontend/tsconfig.tsbuildinfo,sha256=IWAH8V54aeckBxPJdIJ3HyAW90vPSwKqz8DTUhQV7Ic,449
|
|
39
|
+
stemtrace/server/ui/frontend/vite.config.ts,sha256=HytXV_BlGUCgHnLKLYWxZueZEu0zJh-U2Dv3Fki3W3I,644
|
|
40
|
+
stemtrace/server/ui/frontend/dist/index.html,sha256=MoSLb1oQqZxPYUDUye-cspCt9lZ-2R0FO-KWgykio58,754
|
|
41
|
+
stemtrace/server/ui/frontend/dist/assets/index-CCs7iO1n.css,sha256=2-1pM0g4_5PBEDbyT6kcuovUwmA1KfeLLtzEx7-kcUg,55961
|
|
42
|
+
stemtrace/server/ui/frontend/dist/assets/index-Dao0_Q6x.js,sha256=HNXt8CWq6SaKYhTd3aukmWDOC93W8wi_abm1l1TKzsc,545168
|
|
43
|
+
stemtrace/server/ui/frontend/src/index.css,sha256=X_-gO_nIhdb8kYS4DXlGvi9GJV5RbHTsxrZmjafdZgA,2231
|
|
44
|
+
stemtrace/server/ui/frontend/src/main.tsx,sha256=A9JRlExwral6oVS2hI6k84OcU6QugDtN3Te86kdj7QY,1048
|
|
45
|
+
stemtrace/server/ui/frontend/src/api/client.ts,sha256=k_BS8dUPdij3w30kaMI7XpSElMNVVvMo4UYcoHiuaI8,4687
|
|
46
|
+
stemtrace/server/ui/frontend/src/api/queries.ts,sha256=dm1_-wBPm4Z0WCvZQOYxJcRvZYCPAJ-dXBxSfANrDDU,4307
|
|
47
|
+
stemtrace/server/ui/frontend/src/components/DateRangePicker.tsx,sha256=-CA6A0lDpPYVAwBedd-NL6NjmneuD7b2SchXOYUzg5I,6831
|
|
48
|
+
stemtrace/server/ui/frontend/src/components/Filters.tsx,sha256=s9qbzHL70gS-3WTTOx7lONcaQE-K2CzKIzHGRBOM1QU,3591
|
|
49
|
+
stemtrace/server/ui/frontend/src/components/TaskGraph.tsx,sha256=Cfr52R2lyYhkRQ2-dUEmpnfPwrnOYWd7Cci3gL394vU,15510
|
|
50
|
+
stemtrace/server/ui/frontend/src/components/TaskList.tsx,sha256=kiLHn8o2KjqzqO95W8OnPY5SWLUq_r_AzGUG5N4rP5c,5151
|
|
51
|
+
stemtrace/server/ui/frontend/src/components/TaskStateBadge.tsx,sha256=Ur-f1yNlFRpr-iH3pr4ZgUluxS7ut4eME_ho6BAp-As,704
|
|
52
|
+
stemtrace/server/ui/frontend/src/components/TaskTimeline.tsx,sha256=SL2cdG24UoerbTGautFBLkltxDPfifz2Xy6Guqi1VY0,4581
|
|
53
|
+
stemtrace/server/ui/frontend/src/components/TimelineBar.tsx,sha256=ezT3z3ZjoA_c3fYcxe6MAHaRWZThegHVleISBYpGOuI,7158
|
|
54
|
+
stemtrace/server/ui/frontend/src/components/Tooltip.tsx,sha256=daoBzyjYc_V6dfLvN-iUS8BAFJzEQpx6D4kwwYpDjJk,1789
|
|
55
|
+
stemtrace/server/ui/frontend/src/hooks/WebSocketContext.tsx,sha256=9HZyORmTTjMt77-FrPV1_E8rCgrW8E9KDad7joKQLMk,4066
|
|
56
|
+
stemtrace/server/ui/frontend/src/hooks/useInfiniteScroll.ts,sha256=Fi0Lz7n2c4pP9dg-6XvNanhTypd3d9YqqLMHnJjqaL8,1246
|
|
57
|
+
stemtrace/server/ui/frontend/src/routes/__root.tsx,sha256=f96fRT7Ab0AJ8PRvMJjl57yr8klpFhz4C8mkvF-uBdY,3751
|
|
58
|
+
stemtrace/server/ui/frontend/src/routes/graph.$rootId.tsx,sha256=hYDb9FOaIn14VZUq_sSixOzSD5JYO9ZPYnrnBbMnAAg,1532
|
|
59
|
+
stemtrace/server/ui/frontend/src/routes/graphs.tsx,sha256=SWOMIkT3Bxk-3ZM9QYmp4ioDe2ABM5aj0nHespMzPEY,6016
|
|
60
|
+
stemtrace/server/ui/frontend/src/routes/index.tsx,sha256=nQ_vRZZHU3pc5wWgUFbS2AdRQsrBNW10W_Ml5mNNrLQ,3398
|
|
61
|
+
stemtrace/server/ui/frontend/src/routes/registry.tsx,sha256=r4vcnSgvogXwjVXlo9sTjVk5QnGF2vlDJOvr3uV6Y1I,6881
|
|
62
|
+
stemtrace/server/ui/frontend/src/routes/tasks.$taskId.tsx,sha256=-zo6Bd_7405wIi5EZ-sn7Yb5sJFw0mXlDuYfUYuHfWI,11400
|
|
63
|
+
stemtrace/server/ui/frontend/src/utils/format.ts,sha256=_8WyC7qebk1QkZS8EOaWy5ZO5-NaSrqeD_WbL6C3DoM,1146
|
|
64
|
+
stemtrace/server/ui/frontend/tests/graphs.spec.ts,sha256=MEhcH8-5pxdIeuRCmMMDs1oKMrlcCCaNApjW-O74LIM,15382
|
|
65
|
+
stemtrace/server/ui/frontend/tests/registry.spec.ts,sha256=SuxsUSq-JzLyJ0IONESlvUbdYUH78IeS6iU_Nro0IgI,3626
|
|
66
|
+
stemtrace/server/ui/frontend/tests/task-detail.spec.ts,sha256=NbjSG6ilmIDU2VpptNI7o2r_UICmDrcY8lV0vJS3gZ8,4540
|
|
67
|
+
stemtrace/server/ui/frontend/tests/tasks.spec.ts,sha256=w9juNZ6hQZZSmlMAx4HbtW7yKa5yQtkB4GZln1c39o4,2823
|
|
68
|
+
stemtrace-0.1.0.dist-info/METADATA,sha256=00Knm6jKBq_kIDA1PbTqxu-Wm8vIljiVwA1nNfTmFnw,15838
|
|
69
|
+
stemtrace-0.1.0.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
|
|
70
|
+
stemtrace-0.1.0.dist-info/entry_points.txt,sha256=eXdGn8NKvgXel-4_nCMG_E6vCp2Ri6SGlgQPbvJ5MXQ,61
|
|
71
|
+
stemtrace-0.1.0.dist-info/licenses/LICENSE,sha256=JcXwyyW0EPCs0zFfx5gI2bpaJ6WX9Wz74tAwEOOLNN0,1070
|
|
72
|
+
stemtrace-0.1.0.dist-info/RECORD,,
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 Ian Sokolskyi
|
|
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.
|