routeflow-python 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.
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2024 Routeflow
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,453 @@
1
+ Metadata-Version: 2.4
2
+ Name: routeflow-python
3
+ Version: 0.1.0
4
+ Summary: Python SDK for Routeflow backend telemetry
5
+ Author: Routeflow Team
6
+ License: MIT
7
+ Project-URL: Homepage, https://github.com/fatherGoose1/routeflow-python
8
+ Project-URL: Repository, https://github.com/fatherGoose1/routeflow-python
9
+ Classifier: Development Status :: 4 - Beta
10
+ Classifier: Intended Audience :: Developers
11
+ Classifier: License :: OSI Approved :: MIT License
12
+ Classifier: Programming Language :: Python :: 3
13
+ Classifier: Programming Language :: Python :: 3.10
14
+ Classifier: Programming Language :: Python :: 3.11
15
+ Classifier: Programming Language :: Python :: 3.12
16
+ Classifier: Framework :: Flask
17
+ Classifier: Framework :: FastAPI
18
+ Classifier: Framework :: Django
19
+ Requires-Python: >=3.10
20
+ Description-Content-Type: text/markdown
21
+ License-File: LICENSE
22
+ Requires-Dist: requests>=2.28.0
23
+ Provides-Extra: flask
24
+ Requires-Dist: flask>=2.0.0; extra == "flask"
25
+ Provides-Extra: fastapi
26
+ Requires-Dist: fastapi>=0.100.0; extra == "fastapi"
27
+ Requires-Dist: uvicorn>=0.20.0; extra == "fastapi"
28
+ Provides-Extra: django
29
+ Requires-Dist: django>=3.2.0; extra == "django"
30
+ Provides-Extra: all
31
+ Requires-Dist: flask>=2.0.0; extra == "all"
32
+ Requires-Dist: fastapi>=0.100.0; extra == "all"
33
+ Requires-Dist: uvicorn>=0.20.0; extra == "all"
34
+ Requires-Dist: django>=3.2.0; extra == "all"
35
+ Provides-Extra: dev
36
+ Requires-Dist: flask>=2.0.0; extra == "dev"
37
+ Requires-Dist: fastapi>=0.100.0; extra == "dev"
38
+ Requires-Dist: uvicorn>=0.20.0; extra == "dev"
39
+ Requires-Dist: django>=3.2.0; extra == "dev"
40
+ Requires-Dist: pytest>=7.0.0; extra == "dev"
41
+ Requires-Dist: pytest-cov>=4.0.0; extra == "dev"
42
+ Requires-Dist: requests-mock>=1.9.0; extra == "dev"
43
+ Requires-Dist: httpx>=0.24.0; extra == "dev"
44
+ Dynamic: license-file
45
+
46
+ # Routeflow Python SDK
47
+
48
+ **Production-ready backend instrumentation for Flask, FastAPI, and Django applications.**
49
+
50
+ Automatically capture and send backend request telemetry to Routeflow with zero per-route changes. Non-blocking, efficient, and privacy-focused.
51
+
52
+ ## Features
53
+
54
+ - ✅ **One-line integration** - Just `init_routeflow(app)`
55
+ - ✅ **Non-blocking** - Background worker with batching, no request latency
56
+ - ✅ **Privacy-first** - No request bodies, headers (except trace headers), or query strings
57
+ - ✅ **Production-ready** - Retry logic, queue limits, graceful degradation
58
+ - ✅ **Lightweight** - Minimal dependencies (just `requests`)
59
+ - ✅ **Observable** - Built-in stats for monitoring SDK behavior
60
+
61
+ ## Installation
62
+
63
+ ```bash
64
+ pip install routeflow-python
65
+ ```
66
+
67
+ Or install with your framework:
68
+
69
+ ```bash
70
+ # For Flask
71
+ pip install routeflow-python[flask]
72
+
73
+ # For FastAPI
74
+ pip install routeflow-python[fastapi]
75
+
76
+ # For Django
77
+ pip install routeflow-python[django]
78
+
79
+ # For all frameworks
80
+ pip install routeflow-python[all]
81
+ ```
82
+
83
+ ## Quick Start
84
+
85
+ ### 1. Set Environment Variables
86
+
87
+ ```bash
88
+ export ROUTEFLOW_INGEST_KEY=rf_live_your-ingest-key-here
89
+ export ROUTEFLOW_ENV=production
90
+ ```
91
+
92
+ The Routeflow SDK automatically sends data to Routeflow Cloud.
93
+
94
+ ### 2. Initialize in Your App
95
+
96
+ Choose your framework:
97
+
98
+ #### Flask
99
+
100
+ ```python
101
+ from flask import Flask
102
+ from routeflow_python import init_routeflow
103
+
104
+ app = Flask(__name__)
105
+
106
+ # ONE LINE - that's it!
107
+ init_routeflow(app)
108
+
109
+ @app.route('/api/users')
110
+ def get_users():
111
+ return {'users': []}
112
+
113
+ @app.route('/api/users/<user_id>')
114
+ def get_user(user_id):
115
+ return {'id': user_id, 'name': 'John'}
116
+
117
+ if __name__ == '__main__':
118
+ app.run()
119
+ ```
120
+
121
+ #### FastAPI
122
+
123
+ ```python
124
+ from fastapi import FastAPI
125
+ from routeflow_python import init_routeflow_fastapi
126
+
127
+ app = FastAPI()
128
+
129
+ # ONE LINE - that's it!
130
+ init_routeflow_fastapi(app)
131
+
132
+ @app.get("/api/users")
133
+ def get_users():
134
+ return {"users": []}
135
+
136
+ @app.get("/api/users/{user_id}")
137
+ def get_user(user_id: int):
138
+ return {"id": user_id, "name": "John"}
139
+
140
+ if __name__ == "__main__":
141
+ import uvicorn
142
+ uvicorn.run(app, host="0.0.0.0", port=8000)
143
+ ```
144
+
145
+ #### Django
146
+
147
+ Add middleware in `settings.py`:
148
+
149
+ ```python
150
+ # settings.py
151
+ from routeflow_python import init_routeflow_django
152
+
153
+ MIDDLEWARE = [
154
+ 'django.middleware.security.SecurityMiddleware',
155
+ # ... other middleware
156
+ 'routeflow_python.django.RouteflowDjangoMiddleware', # Add this
157
+ ]
158
+
159
+ # Initialize Routeflow
160
+ init_routeflow_django()
161
+ ```
162
+
163
+ Then define views as normal:
164
+
165
+ ```python
166
+ # views.py
167
+ from django.http import JsonResponse
168
+
169
+ def get_users(request):
170
+ return JsonResponse({"users": []})
171
+
172
+ def get_user(request, user_id):
173
+ return JsonResponse({"id": user_id, "name": "John"})
174
+
175
+ # urls.py
176
+ from django.urls import path
177
+ from .views import get_users, get_user
178
+
179
+ urlpatterns = [
180
+ path('api/users/', get_users),
181
+ path('api/users/<int:user_id>/', get_user),
182
+ ]
183
+ ```
184
+
185
+ ### 3. That's It! 🎉
186
+
187
+ Routeflow will now automatically capture:
188
+ - Request timestamps
189
+ - HTTP methods and routes (e.g., `GET /api/users/<user_id>`)
190
+ - Status codes
191
+ - Latency
192
+ - Environment info
193
+ - Code version (from CI variables)
194
+
195
+ ## What Data is Collected?
196
+
197
+ ### ✅ Collected
198
+
199
+ - **Timestamp**: When the request started
200
+ - **Trace ID**: From `x-routeflow-trace-id` header or auto-generated
201
+ - **Frontend Route**: From `x-routeflow-frontend-route` header (e.g., `/checkout`)
202
+ - **Backend Method**: HTTP method (GET, POST, etc.)
203
+ - **Backend Path**: Route pattern (e.g., `/api/orders`, `/api/users/{user_id}`)
204
+ - **Handler**: Endpoint/view name (e.g., `api.create_order`, `myapp.views.get_user`)
205
+ - **Status Code**: HTTP response status
206
+ - **Latency**: Request duration in milliseconds
207
+ - **Environment**: From `ROUTEFLOW_ENV`
208
+ - **Code Version**: From `ROUTEFLOW_CODE_VERSION` or CI variables
209
+
210
+ ### ❌ NOT Collected
211
+
212
+ - Request bodies
213
+ - Request headers (except trace headers)
214
+ - Query strings
215
+ - Path parameters
216
+ - User data
217
+ - Secrets or credentials
218
+ - Exception messages or stack traces
219
+
220
+ **Privacy is built-in.** Routes are automatically sanitized to remove query strings.
221
+
222
+ ## Configuration
223
+
224
+ ### Environment Variables
225
+
226
+ | Variable | Required | Default | Description |
227
+ |----------|----------|---------|-------------|
228
+ | `ROUTEFLOW_INGEST_KEY` | ✅ Yes | - | API key for authentication |
229
+ | `ROUTEFLOW_ENV` | No | `development` | Environment name |
230
+ | `ROUTEFLOW_ENABLED` | No | `true` | Enable/disable SDK |
231
+ | `ROUTEFLOW_SAMPLE_RATE` | No | `1.0` | Sampling rate (0.0-1.0) |
232
+ | `ROUTEFLOW_CODE_VERSION` | No | Auto-detected | Code/git version |
233
+ | `ROUTEFLOW_MAX_EVENTS_PER_BATCH` | No | `50` | Max events per batch |
234
+ | `ROUTEFLOW_FLUSH_INTERVAL_MS` | No | `1000` | Flush interval in ms |
235
+ | `ROUTEFLOW_QUEUE_MAXSIZE` | No | `5000` | Max queue size |
236
+ | `ROUTEFLOW_TIMEOUT_MS` | No | `1500` | HTTP timeout in ms |
237
+
238
+ ### Programmatic Configuration
239
+
240
+ You can override environment variables programmatically:
241
+
242
+ ```python
243
+ init_routeflow(
244
+ app,
245
+ ingest_key="rf_live_your-key",
246
+ environment="production",
247
+ sample_rate=0.1, # Sample 10% of requests
248
+ )
249
+ ```
250
+
251
+ ## Performance & Behavior
252
+
253
+ ### Non-Blocking Design
254
+
255
+ The SDK is designed to **never slow down your application**:
256
+
257
+ 1. **No I/O on request thread** - Events are enqueued instantly
258
+ 2. **Background worker** - Separate thread batches and sends events
259
+ 3. **Bounded queue** - If queue fills, events are dropped (not blocked)
260
+ 4. **Graceful degradation** - Backend down? Events are dropped safely
261
+
262
+ ### Batching
263
+
264
+ Events are batched for efficiency:
265
+ - Batches up to 50 events (configurable)
266
+ - Flushes every 1000ms (configurable)
267
+ - Automatic flush on process exit (best-effort)
268
+
269
+ ### Retry Logic
270
+
271
+ - **5xx errors**: Retry with exponential backoff (3 attempts max)
272
+ - **4xx errors**: No retry (validation/auth errors)
273
+ - **Network errors**: Retry with backoff
274
+ - **Final failure**: Drop batch and increment counter
275
+
276
+ ### Queue Behavior
277
+
278
+ If the queue fills up (5000 events by default):
279
+ - New events are **dropped immediately**
280
+ - A warning is logged
281
+ - Counter `dropped_queue_full` is incremented
282
+ - **Your app is never blocked**
283
+
284
+ ## Monitoring SDK Health
285
+
286
+ Get real-time statistics:
287
+
288
+ ```python
289
+ from routeflow_python import get_routeflow_stats
290
+
291
+ stats = get_routeflow_stats()
292
+ print(stats)
293
+ ```
294
+
295
+ Output:
296
+ ```python
297
+ {
298
+ 'enqueued': 1523,
299
+ 'sent': 1500,
300
+ 'dropped_queue_full': 0,
301
+ 'dropped_sampled': 23,
302
+ 'dropped_validation': 0,
303
+ 'dropped_http_4xx': 0,
304
+ 'dropped_http_5xx': 0,
305
+ 'retries': 2,
306
+ 'last_error_at': None
307
+ }
308
+ ```
309
+
310
+ ### Metrics Explained
311
+
312
+ - `enqueued`: Events successfully queued
313
+ - `sent`: Events successfully delivered
314
+ - `dropped_sampled`: Events skipped due to sampling
315
+ - `dropped_queue_full`: Events dropped due to full queue
316
+ - `dropped_validation`: Events failed validation
317
+ - `dropped_http_4xx`: Events dropped due to 4xx errors
318
+ - `dropped_http_5xx`: Events dropped after retries failed
319
+ - `retries`: Number of retry attempts
320
+ - `last_error_at`: Timestamp of last error (ISO 8601)
321
+
322
+ ## Frontend Integration
323
+
324
+ Your frontend should send these headers:
325
+
326
+ ```javascript
327
+ fetch('/api/users', {
328
+ headers: {
329
+ 'x-routeflow-trace-id': generateTraceId(), // UUID
330
+ 'x-routeflow-frontend-route': window.location.pathname, // e.g., "/checkout"
331
+ }
332
+ })
333
+ ```
334
+
335
+ If these headers are not present:
336
+ - `trace_id` is auto-generated
337
+ - `frontend_route` defaults to `"__unknown__"`
338
+
339
+ ## Advanced Usage
340
+
341
+ ### Manual Shutdown
342
+
343
+ For testing or graceful shutdown:
344
+
345
+ ```python
346
+ from routeflow_python import shutdown_routeflow
347
+
348
+ # Flush events and stop worker (waits up to 2 seconds)
349
+ shutdown_routeflow(timeout_sec=2.0)
350
+ ```
351
+
352
+ This is called automatically on process exit via `atexit`.
353
+
354
+ ### Sampling
355
+
356
+ Sample only a percentage of requests:
357
+
358
+ ```python
359
+ # Sample 10% of requests
360
+ init_routeflow(app, sample_rate=0.1)
361
+ ```
362
+
363
+ Or via environment:
364
+ ```bash
365
+ export ROUTEFLOW_SAMPLE_RATE=0.1
366
+ ```
367
+
368
+ ### Disable in Development
369
+
370
+ ```bash
371
+ export ROUTEFLOW_ENABLED=false
372
+ ```
373
+
374
+ Or:
375
+ ```python
376
+ init_routeflow(app, enabled=False)
377
+ ```
378
+
379
+ ## Example Application
380
+
381
+ ```python
382
+ from flask import Flask, jsonify
383
+ from routeflow_python import init_routeflow, get_routeflow_stats
384
+
385
+ app = Flask(__name__)
386
+ init_routeflow(app)
387
+
388
+ @app.route('/')
389
+ def index():
390
+ return {'message': 'Hello World'}
391
+
392
+ @app.route('/api/users/<int:user_id>')
393
+ def get_user(user_id):
394
+ return {'id': user_id, 'name': 'John'}
395
+
396
+ @app.route('/_stats/routeflow')
397
+ def routeflow_stats():
398
+ """Endpoint to check SDK health."""
399
+ return jsonify(get_routeflow_stats())
400
+
401
+ if __name__ == '__main__':
402
+ app.run(debug=True)
403
+ ```
404
+
405
+ Test it:
406
+ ```bash
407
+ curl http://localhost:5000/api/users/123
408
+ curl http://localhost:5000/_stats/routeflow
409
+ ```
410
+
411
+ ## Error Handling
412
+
413
+ The SDK is designed to **never crash your application**:
414
+
415
+ - All exceptions are caught and logged
416
+ - Failed events are dropped, not retried indefinitely
417
+ - Queue overflow drops events instead of blocking
418
+ - Invalid configuration logs warnings but doesn't crash
419
+
420
+ ## Code Version Detection
421
+
422
+ The SDK automatically detects code version from:
423
+
424
+ 1. `ROUTEFLOW_CODE_VERSION` (explicit)
425
+ 2. `VERCEL_GIT_COMMIT_SHA` (Vercel)
426
+ 3. `GIT_SHA` (generic)
427
+ 4. `COMMIT_SHA` (generic)
428
+ 5. `SOURCE_VERSION` (Azure)
429
+ 6. `HEROKU_SLUG_COMMIT` (Heroku)
430
+
431
+ Or set it explicitly:
432
+ ```bash
433
+ export ROUTEFLOW_CODE_VERSION=$(git rev-parse HEAD)
434
+ ```
435
+
436
+ ## Requirements
437
+
438
+ - Python 3.10+
439
+ - requests >= 2.28.0
440
+
441
+ **Framework-specific:**
442
+ - Flask 2.x or 3.x (for Flask integration)
443
+ - FastAPI 0.100+ (for FastAPI integration)
444
+ - Django 3.2+ / 4.x / 5.x (for Django integration)
445
+
446
+ ## License
447
+
448
+ MIT
449
+
450
+ ## Support
451
+
452
+ For issues, questions, or feature requests, visit the [Routeflow repository](https://github.com/routeflow/routeflow).
453
+ # routeflow-python