logtide-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.
- logtide_sdk-0.1.0/LICENSE +21 -0
- logtide_sdk-0.1.0/PKG-INFO +615 -0
- logtide_sdk-0.1.0/README.md +571 -0
- logtide_sdk-0.1.0/logtide_sdk/__init__.py +36 -0
- logtide_sdk-0.1.0/logtide_sdk/circuit_breaker.py +99 -0
- logtide_sdk-0.1.0/logtide_sdk/client.py +650 -0
- logtide_sdk-0.1.0/logtide_sdk/enums.py +21 -0
- logtide_sdk-0.1.0/logtide_sdk/exceptions.py +19 -0
- logtide_sdk-0.1.0/logtide_sdk/middleware/__init__.py +11 -0
- logtide_sdk-0.1.0/logtide_sdk/middleware/django.py +162 -0
- logtide_sdk-0.1.0/logtide_sdk/middleware/fastapi.py +169 -0
- logtide_sdk-0.1.0/logtide_sdk/middleware/flask.py +179 -0
- logtide_sdk-0.1.0/logtide_sdk/models.py +106 -0
- logtide_sdk-0.1.0/logtide_sdk/py.typed +0 -0
- logtide_sdk-0.1.0/logtide_sdk.egg-info/PKG-INFO +615 -0
- logtide_sdk-0.1.0/logtide_sdk.egg-info/SOURCES.txt +20 -0
- logtide_sdk-0.1.0/logtide_sdk.egg-info/dependency_links.txt +1 -0
- logtide_sdk-0.1.0/logtide_sdk.egg-info/requires.txt +22 -0
- logtide_sdk-0.1.0/logtide_sdk.egg-info/top_level.txt +1 -0
- logtide_sdk-0.1.0/pyproject.toml +95 -0
- logtide_sdk-0.1.0/setup.cfg +4 -0
- logtide_sdk-0.1.0/tests/test_client.py +207 -0
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 Polliog
|
|
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,615 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: logtide-sdk
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Official Python SDK for LogTide - Self-hosted log management with batching, retry logic, circuit breaker, query API, and middleware support
|
|
5
|
+
Author-email: Polliog <giuseppe@solture.it>
|
|
6
|
+
License: MIT
|
|
7
|
+
Project-URL: Homepage, https://github.com/logtide/python-sdk
|
|
8
|
+
Project-URL: Repository, https://github.com/logtide/python-sdk
|
|
9
|
+
Project-URL: Documentation, https://logtide.dev/docs
|
|
10
|
+
Project-URL: Issues, https://github.com/logtide/python-sdk/issues
|
|
11
|
+
Keywords: logtide,logging,logs,log-management,monitoring,observability,self-hosted,tracing,circuit-breaker,flask,django,fastapi
|
|
12
|
+
Classifier: Development Status :: 4 - Beta
|
|
13
|
+
Classifier: Intended Audience :: Developers
|
|
14
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
15
|
+
Classifier: Programming Language :: Python :: 3
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.8
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.9
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
20
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
21
|
+
Classifier: Topic :: System :: Logging
|
|
22
|
+
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
23
|
+
Requires-Python: >=3.8
|
|
24
|
+
Description-Content-Type: text/markdown
|
|
25
|
+
License-File: LICENSE
|
|
26
|
+
Requires-Dist: requests>=2.31.0
|
|
27
|
+
Provides-Extra: async
|
|
28
|
+
Requires-Dist: aiohttp>=3.9.0; extra == "async"
|
|
29
|
+
Provides-Extra: dev
|
|
30
|
+
Requires-Dist: pytest>=7.4.0; extra == "dev"
|
|
31
|
+
Requires-Dist: pytest-asyncio>=0.21.0; extra == "dev"
|
|
32
|
+
Requires-Dist: black>=23.0.0; extra == "dev"
|
|
33
|
+
Requires-Dist: mypy>=1.5.0; extra == "dev"
|
|
34
|
+
Requires-Dist: ruff>=0.1.0; extra == "dev"
|
|
35
|
+
Requires-Dist: types-requests>=2.31.0; extra == "dev"
|
|
36
|
+
Provides-Extra: flask
|
|
37
|
+
Requires-Dist: flask>=2.0.0; extra == "flask"
|
|
38
|
+
Provides-Extra: django
|
|
39
|
+
Requires-Dist: django>=3.2.0; extra == "django"
|
|
40
|
+
Provides-Extra: fastapi
|
|
41
|
+
Requires-Dist: fastapi>=0.100.0; extra == "fastapi"
|
|
42
|
+
Requires-Dist: starlette>=0.27.0; extra == "fastapi"
|
|
43
|
+
Dynamic: license-file
|
|
44
|
+
|
|
45
|
+
# LogTide Python SDK
|
|
46
|
+
|
|
47
|
+
Official Python SDK for LogTide with advanced features: automatic batching, retry logic, circuit breaker, query API, live streaming, and middleware support.
|
|
48
|
+
|
|
49
|
+
## Features
|
|
50
|
+
|
|
51
|
+
- ✅ **Automatic batching** with configurable size and interval
|
|
52
|
+
- ✅ **Retry logic** with exponential backoff
|
|
53
|
+
- ✅ **Circuit breaker** pattern for fault tolerance
|
|
54
|
+
- ✅ **Max buffer size** with drop policy to prevent memory leaks
|
|
55
|
+
- ✅ **Query API** for searching and filtering logs
|
|
56
|
+
- ✅ **Live tail** with Server-Sent Events (SSE)
|
|
57
|
+
- ✅ **Trace ID context** for distributed tracing
|
|
58
|
+
- ✅ **Global metadata** added to all logs
|
|
59
|
+
- ✅ **Structured error serialization**
|
|
60
|
+
- ✅ **Internal metrics** (logs sent, errors, latency, etc.)
|
|
61
|
+
- ✅ **Flask, Django & FastAPI middleware** for auto-logging HTTP requests
|
|
62
|
+
- ✅ **Full Python 3.8+ support** with type hints
|
|
63
|
+
|
|
64
|
+
## Requirements
|
|
65
|
+
|
|
66
|
+
- Python 3.8 or higher
|
|
67
|
+
- pip or poetry
|
|
68
|
+
|
|
69
|
+
## Installation
|
|
70
|
+
|
|
71
|
+
```bash
|
|
72
|
+
pip install logtide-sdk
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
### Optional dependencies
|
|
76
|
+
|
|
77
|
+
```bash
|
|
78
|
+
# For async support
|
|
79
|
+
pip install logtide-sdk[async]
|
|
80
|
+
|
|
81
|
+
# For Flask middleware
|
|
82
|
+
pip install logtide-sdk[flask]
|
|
83
|
+
|
|
84
|
+
# For Django middleware
|
|
85
|
+
pip install logtide-sdk[django]
|
|
86
|
+
|
|
87
|
+
# For FastAPI middleware
|
|
88
|
+
pip install logtide-sdk[fastapi]
|
|
89
|
+
|
|
90
|
+
# Install all extras
|
|
91
|
+
pip install logtide-sdk[async,flask,django,fastapi]
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
## Quick Start
|
|
95
|
+
|
|
96
|
+
```python
|
|
97
|
+
from logtide_sdk import LogTideClient, ClientOptions
|
|
98
|
+
|
|
99
|
+
client = LogTideClient(
|
|
100
|
+
ClientOptions(
|
|
101
|
+
api_url='http://localhost:8080',
|
|
102
|
+
api_key='lp_your_api_key_here',
|
|
103
|
+
)
|
|
104
|
+
)
|
|
105
|
+
|
|
106
|
+
# Send logs
|
|
107
|
+
client.info('api-gateway', 'Server started', {'port': 3000})
|
|
108
|
+
client.error('database', 'Connection failed', Exception('Timeout'))
|
|
109
|
+
|
|
110
|
+
# Graceful shutdown (automatic via atexit, but can be called manually)
|
|
111
|
+
client.close()
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
---
|
|
115
|
+
|
|
116
|
+
## Configuration Options
|
|
117
|
+
|
|
118
|
+
### Basic Options
|
|
119
|
+
|
|
120
|
+
| Option | Type | Default | Description |
|
|
121
|
+
|--------|------|---------|-------------|
|
|
122
|
+
| `api_url` | `str` | **required** | Base URL of your LogTide instance |
|
|
123
|
+
| `api_key` | `str` | **required** | Project API key (starts with `lp_`) |
|
|
124
|
+
| `batch_size` | `int` | `100` | Number of logs to batch before sending |
|
|
125
|
+
| `flush_interval` | `int` | `5000` | Interval in ms to auto-flush logs |
|
|
126
|
+
|
|
127
|
+
### Advanced Options
|
|
128
|
+
|
|
129
|
+
| Option | Type | Default | Description |
|
|
130
|
+
|--------|------|---------|-------------|
|
|
131
|
+
| `max_buffer_size` | `int` | `10000` | Max logs in buffer (prevents memory leak) |
|
|
132
|
+
| `max_retries` | `int` | `3` | Max retry attempts on failure |
|
|
133
|
+
| `retry_delay_ms` | `int` | `1000` | Initial retry delay (exponential backoff) |
|
|
134
|
+
| `circuit_breaker_threshold` | `int` | `5` | Failures before opening circuit |
|
|
135
|
+
| `circuit_breaker_reset_ms` | `int` | `30000` | Time before retrying after circuit opens |
|
|
136
|
+
| `enable_metrics` | `bool` | `True` | Track internal metrics |
|
|
137
|
+
| `debug` | `bool` | `False` | Enable debug logging to console |
|
|
138
|
+
| `global_metadata` | `dict` | `{}` | Metadata added to all logs |
|
|
139
|
+
| `auto_trace_id` | `bool` | `False` | Auto-generate trace IDs for logs |
|
|
140
|
+
|
|
141
|
+
### Example: Full Configuration
|
|
142
|
+
|
|
143
|
+
```python
|
|
144
|
+
import os
|
|
145
|
+
|
|
146
|
+
client = LogTideClient(
|
|
147
|
+
ClientOptions(
|
|
148
|
+
api_url='http://localhost:8080',
|
|
149
|
+
api_key='lp_your_api_key_here',
|
|
150
|
+
|
|
151
|
+
# Batching
|
|
152
|
+
batch_size=100,
|
|
153
|
+
flush_interval=5000,
|
|
154
|
+
|
|
155
|
+
# Buffer management
|
|
156
|
+
max_buffer_size=10000,
|
|
157
|
+
|
|
158
|
+
# Retry with exponential backoff (1s → 2s → 4s)
|
|
159
|
+
max_retries=3,
|
|
160
|
+
retry_delay_ms=1000,
|
|
161
|
+
|
|
162
|
+
# Circuit breaker
|
|
163
|
+
circuit_breaker_threshold=5,
|
|
164
|
+
circuit_breaker_reset_ms=30000,
|
|
165
|
+
|
|
166
|
+
# Metrics & debugging
|
|
167
|
+
enable_metrics=True,
|
|
168
|
+
debug=True,
|
|
169
|
+
|
|
170
|
+
# Global context
|
|
171
|
+
global_metadata={
|
|
172
|
+
'env': os.getenv('APP_ENV'),
|
|
173
|
+
'version': '1.0.0',
|
|
174
|
+
'hostname': os.uname().nodename,
|
|
175
|
+
},
|
|
176
|
+
|
|
177
|
+
# Auto trace IDs
|
|
178
|
+
auto_trace_id=False,
|
|
179
|
+
)
|
|
180
|
+
)
|
|
181
|
+
```
|
|
182
|
+
|
|
183
|
+
---
|
|
184
|
+
|
|
185
|
+
## Logging Methods
|
|
186
|
+
|
|
187
|
+
### Basic Logging
|
|
188
|
+
|
|
189
|
+
```python
|
|
190
|
+
from logtide_sdk import LogLevel
|
|
191
|
+
|
|
192
|
+
client.debug('service-name', 'Debug message')
|
|
193
|
+
client.info('service-name', 'Info message', {'userId': 123})
|
|
194
|
+
client.warn('service-name', 'Warning message')
|
|
195
|
+
client.error('service-name', 'Error message', {'custom': 'data'})
|
|
196
|
+
client.critical('service-name', 'Critical message')
|
|
197
|
+
```
|
|
198
|
+
|
|
199
|
+
### Error Logging with Auto-Serialization
|
|
200
|
+
|
|
201
|
+
The SDK automatically serializes `Exception` objects:
|
|
202
|
+
|
|
203
|
+
```python
|
|
204
|
+
try:
|
|
205
|
+
raise RuntimeError('Database timeout')
|
|
206
|
+
except Exception as e:
|
|
207
|
+
# Automatically serializes error with stack trace
|
|
208
|
+
client.error('database', 'Query failed', e)
|
|
209
|
+
```
|
|
210
|
+
|
|
211
|
+
Generated log metadata:
|
|
212
|
+
```json
|
|
213
|
+
{
|
|
214
|
+
"error": {
|
|
215
|
+
"name": "RuntimeError",
|
|
216
|
+
"message": "Database timeout",
|
|
217
|
+
"stack": "Traceback (most recent call last):\n ..."
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
```
|
|
221
|
+
|
|
222
|
+
---
|
|
223
|
+
|
|
224
|
+
## Trace ID Context
|
|
225
|
+
|
|
226
|
+
Track requests across services with trace IDs.
|
|
227
|
+
|
|
228
|
+
### Manual Trace ID
|
|
229
|
+
|
|
230
|
+
```python
|
|
231
|
+
client.set_trace_id('request-123')
|
|
232
|
+
|
|
233
|
+
client.info('api', 'Request received')
|
|
234
|
+
client.info('database', 'Querying users')
|
|
235
|
+
client.info('api', 'Response sent')
|
|
236
|
+
|
|
237
|
+
client.set_trace_id(None) # Clear context
|
|
238
|
+
```
|
|
239
|
+
|
|
240
|
+
### Scoped Trace ID (Context Manager)
|
|
241
|
+
|
|
242
|
+
```python
|
|
243
|
+
with client.with_trace_id('request-456'):
|
|
244
|
+
client.info('api', 'Processing in context')
|
|
245
|
+
client.warn('cache', 'Cache miss')
|
|
246
|
+
# Trace ID automatically restored after context
|
|
247
|
+
```
|
|
248
|
+
|
|
249
|
+
### Auto-Generated Trace ID
|
|
250
|
+
|
|
251
|
+
```python
|
|
252
|
+
import uuid
|
|
253
|
+
|
|
254
|
+
with client.with_new_trace_id():
|
|
255
|
+
client.info('worker', 'Background job started')
|
|
256
|
+
client.info('worker', 'Job completed')
|
|
257
|
+
```
|
|
258
|
+
|
|
259
|
+
---
|
|
260
|
+
|
|
261
|
+
## Query API
|
|
262
|
+
|
|
263
|
+
Search and retrieve logs programmatically.
|
|
264
|
+
|
|
265
|
+
### Basic Query
|
|
266
|
+
|
|
267
|
+
```python
|
|
268
|
+
from datetime import datetime, timedelta
|
|
269
|
+
from logtide_sdk import QueryOptions, LogLevel
|
|
270
|
+
|
|
271
|
+
result = client.query(
|
|
272
|
+
QueryOptions(
|
|
273
|
+
service='api-gateway',
|
|
274
|
+
level=LogLevel.ERROR,
|
|
275
|
+
from_time=datetime.now() - timedelta(hours=24),
|
|
276
|
+
to_time=datetime.now(),
|
|
277
|
+
limit=100,
|
|
278
|
+
offset=0,
|
|
279
|
+
)
|
|
280
|
+
)
|
|
281
|
+
|
|
282
|
+
print(f"Found {result.total} logs")
|
|
283
|
+
for log in result.logs:
|
|
284
|
+
print(log)
|
|
285
|
+
```
|
|
286
|
+
|
|
287
|
+
### Full-Text Search
|
|
288
|
+
|
|
289
|
+
```python
|
|
290
|
+
result = client.query(QueryOptions(q='timeout', limit=50))
|
|
291
|
+
```
|
|
292
|
+
|
|
293
|
+
### Get Logs by Trace ID
|
|
294
|
+
|
|
295
|
+
```python
|
|
296
|
+
logs = client.get_by_trace_id('trace-123')
|
|
297
|
+
print(f"Trace has {len(logs)} logs")
|
|
298
|
+
```
|
|
299
|
+
|
|
300
|
+
### Aggregated Statistics
|
|
301
|
+
|
|
302
|
+
```python
|
|
303
|
+
from datetime import datetime, timedelta
|
|
304
|
+
from logtide_sdk import AggregatedStatsOptions
|
|
305
|
+
|
|
306
|
+
stats = client.get_aggregated_stats(
|
|
307
|
+
AggregatedStatsOptions(
|
|
308
|
+
from_time=datetime.now() - timedelta(days=7),
|
|
309
|
+
to_time=datetime.now(),
|
|
310
|
+
interval='1h',
|
|
311
|
+
)
|
|
312
|
+
)
|
|
313
|
+
|
|
314
|
+
for service in stats.top_services:
|
|
315
|
+
print(f"{service['service']}: {service['count']} logs")
|
|
316
|
+
```
|
|
317
|
+
|
|
318
|
+
---
|
|
319
|
+
|
|
320
|
+
## Live Streaming (SSE)
|
|
321
|
+
|
|
322
|
+
Stream logs in real-time using Server-Sent Events.
|
|
323
|
+
|
|
324
|
+
```python
|
|
325
|
+
def handle_log(log):
|
|
326
|
+
print(f"[{log['time']}] {log['level']}: {log['message']}")
|
|
327
|
+
|
|
328
|
+
def handle_error(error):
|
|
329
|
+
print(f"Stream error: {error}")
|
|
330
|
+
|
|
331
|
+
client.stream(
|
|
332
|
+
on_log=handle_log,
|
|
333
|
+
on_error=handle_error,
|
|
334
|
+
filters={
|
|
335
|
+
'service': 'api-gateway',
|
|
336
|
+
'level': 'error',
|
|
337
|
+
}
|
|
338
|
+
)
|
|
339
|
+
|
|
340
|
+
# Note: This blocks. Run in separate thread for production.
|
|
341
|
+
```
|
|
342
|
+
|
|
343
|
+
---
|
|
344
|
+
|
|
345
|
+
## Metrics
|
|
346
|
+
|
|
347
|
+
Track SDK performance and health.
|
|
348
|
+
|
|
349
|
+
```python
|
|
350
|
+
metrics = client.get_metrics()
|
|
351
|
+
|
|
352
|
+
print(f"Logs sent: {metrics.logs_sent}")
|
|
353
|
+
print(f"Logs dropped: {metrics.logs_dropped}")
|
|
354
|
+
print(f"Errors: {metrics.errors}")
|
|
355
|
+
print(f"Retries: {metrics.retries}")
|
|
356
|
+
print(f"Avg latency: {metrics.avg_latency_ms}ms")
|
|
357
|
+
print(f"Circuit breaker trips: {metrics.circuit_breaker_trips}")
|
|
358
|
+
|
|
359
|
+
# Get circuit breaker state
|
|
360
|
+
print(client.get_circuit_breaker_state()) # CLOSED|OPEN|HALF_OPEN
|
|
361
|
+
|
|
362
|
+
# Reset metrics
|
|
363
|
+
client.reset_metrics()
|
|
364
|
+
```
|
|
365
|
+
|
|
366
|
+
---
|
|
367
|
+
|
|
368
|
+
## Middleware
|
|
369
|
+
|
|
370
|
+
### Flask Middleware
|
|
371
|
+
|
|
372
|
+
Auto-log all HTTP requests and responses.
|
|
373
|
+
|
|
374
|
+
```python
|
|
375
|
+
from flask import Flask
|
|
376
|
+
from logtide_sdk import LogTideClient, ClientOptions
|
|
377
|
+
from logtide_sdk.middleware import LogTideFlaskMiddleware
|
|
378
|
+
|
|
379
|
+
app = Flask(__name__)
|
|
380
|
+
|
|
381
|
+
client = LogTideClient(
|
|
382
|
+
ClientOptions(
|
|
383
|
+
api_url='http://localhost:8080',
|
|
384
|
+
api_key='lp_your_api_key_here',
|
|
385
|
+
)
|
|
386
|
+
)
|
|
387
|
+
|
|
388
|
+
LogTideFlaskMiddleware(
|
|
389
|
+
app,
|
|
390
|
+
client=client,
|
|
391
|
+
service_name='flask-api',
|
|
392
|
+
log_requests=True,
|
|
393
|
+
log_responses=True,
|
|
394
|
+
skip_paths=['/metrics'],
|
|
395
|
+
)
|
|
396
|
+
```
|
|
397
|
+
|
|
398
|
+
**Logged automatically:**
|
|
399
|
+
- Request: `GET /api/users`
|
|
400
|
+
- Response: `GET /api/users 200 (45ms)`
|
|
401
|
+
- Errors: `Request error: Internal Server Error`
|
|
402
|
+
|
|
403
|
+
### Django Middleware
|
|
404
|
+
|
|
405
|
+
```python
|
|
406
|
+
# settings.py
|
|
407
|
+
MIDDLEWARE = [
|
|
408
|
+
'logtide_sdk.middleware.LogTideDjangoMiddleware',
|
|
409
|
+
]
|
|
410
|
+
|
|
411
|
+
from logtide_sdk import LogTideClient, ClientOptions
|
|
412
|
+
|
|
413
|
+
LOGTIDE_CLIENT = LogTideClient(
|
|
414
|
+
ClientOptions(
|
|
415
|
+
api_url='http://localhost:8080',
|
|
416
|
+
api_key='lp_your_api_key_here',
|
|
417
|
+
)
|
|
418
|
+
)
|
|
419
|
+
LOGTIDE_SERVICE_NAME = 'django-api'
|
|
420
|
+
```
|
|
421
|
+
|
|
422
|
+
### FastAPI Middleware
|
|
423
|
+
|
|
424
|
+
```python
|
|
425
|
+
from fastapi import FastAPI
|
|
426
|
+
from logtide_sdk import LogTideClient, ClientOptions
|
|
427
|
+
from logtide_sdk.middleware import LogTideFastAPIMiddleware
|
|
428
|
+
|
|
429
|
+
app = FastAPI()
|
|
430
|
+
|
|
431
|
+
client = LogTideClient(
|
|
432
|
+
ClientOptions(
|
|
433
|
+
api_url='http://localhost:8080',
|
|
434
|
+
api_key='lp_your_api_key_here',
|
|
435
|
+
)
|
|
436
|
+
)
|
|
437
|
+
|
|
438
|
+
app.add_middleware(
|
|
439
|
+
LogTideFastAPIMiddleware,
|
|
440
|
+
client=client,
|
|
441
|
+
service_name='fastapi-api',
|
|
442
|
+
)
|
|
443
|
+
```
|
|
444
|
+
|
|
445
|
+
---
|
|
446
|
+
|
|
447
|
+
## Examples
|
|
448
|
+
|
|
449
|
+
See the [examples/](./examples) directory for complete working examples:
|
|
450
|
+
|
|
451
|
+
- **[basic.py](./examples/basic.py)** - Simple usage
|
|
452
|
+
- **[advanced.py](./examples/advanced.py)** - All advanced features
|
|
453
|
+
- **[flask_example.py](./examples/flask_example.py)** - Flask integration
|
|
454
|
+
- **[fastapi_example.py](./examples/fastapi_example.py)** - FastAPI integration
|
|
455
|
+
|
|
456
|
+
---
|
|
457
|
+
|
|
458
|
+
## API Reference
|
|
459
|
+
|
|
460
|
+
### LogTideClient
|
|
461
|
+
|
|
462
|
+
#### Constructor
|
|
463
|
+
```python
|
|
464
|
+
client = LogTideClient(options: ClientOptions)
|
|
465
|
+
```
|
|
466
|
+
|
|
467
|
+
#### Logging Methods
|
|
468
|
+
- `log(entry: LogEntry) -> None`
|
|
469
|
+
- `debug(service: str, message: str, metadata: dict = None) -> None`
|
|
470
|
+
- `info(service: str, message: str, metadata: dict = None) -> None`
|
|
471
|
+
- `warn(service: str, message: str, metadata: dict = None) -> None`
|
|
472
|
+
- `error(service: str, message: str, metadata_or_error: dict | Exception = None) -> None`
|
|
473
|
+
- `critical(service: str, message: str, metadata_or_error: dict | Exception = None) -> None`
|
|
474
|
+
|
|
475
|
+
#### Context Methods
|
|
476
|
+
- `set_trace_id(trace_id: str | None) -> None`
|
|
477
|
+
- `get_trace_id() -> str | None`
|
|
478
|
+
- `with_trace_id(trace_id: str)` → context manager
|
|
479
|
+
- `with_new_trace_id()` → context manager
|
|
480
|
+
|
|
481
|
+
#### Query Methods
|
|
482
|
+
- `query(options: QueryOptions) -> LogsResponse`
|
|
483
|
+
- `get_by_trace_id(trace_id: str) -> list[dict]`
|
|
484
|
+
- `get_aggregated_stats(options: AggregatedStatsOptions) -> AggregatedStatsResponse`
|
|
485
|
+
|
|
486
|
+
#### Streaming
|
|
487
|
+
- `stream(on_log: callable, on_error: callable = None, filters: dict = None) -> None`
|
|
488
|
+
|
|
489
|
+
#### Metrics
|
|
490
|
+
- `get_metrics() -> ClientMetrics`
|
|
491
|
+
- `reset_metrics() -> None`
|
|
492
|
+
- `get_circuit_breaker_state() -> CircuitState`
|
|
493
|
+
|
|
494
|
+
#### Lifecycle
|
|
495
|
+
- `flush() -> None`
|
|
496
|
+
- `close() -> None`
|
|
497
|
+
|
|
498
|
+
---
|
|
499
|
+
|
|
500
|
+
## Best Practices
|
|
501
|
+
|
|
502
|
+
### 1. Always Close on Shutdown
|
|
503
|
+
|
|
504
|
+
```python
|
|
505
|
+
import atexit
|
|
506
|
+
|
|
507
|
+
# Automatic cleanup (already registered by client)
|
|
508
|
+
# Or manually:
|
|
509
|
+
atexit.register(client.close)
|
|
510
|
+
```
|
|
511
|
+
|
|
512
|
+
### 2. Use Global Metadata
|
|
513
|
+
|
|
514
|
+
```python
|
|
515
|
+
client = LogTideClient(
|
|
516
|
+
ClientOptions(
|
|
517
|
+
api_url='http://localhost:8080',
|
|
518
|
+
api_key='lp_your_api_key_here',
|
|
519
|
+
global_metadata={
|
|
520
|
+
'env': os.getenv('ENV'),
|
|
521
|
+
'version': '1.0.0',
|
|
522
|
+
'region': 'us-east-1',
|
|
523
|
+
},
|
|
524
|
+
)
|
|
525
|
+
)
|
|
526
|
+
```
|
|
527
|
+
|
|
528
|
+
### 3. Enable Debug Mode in Development
|
|
529
|
+
|
|
530
|
+
```python
|
|
531
|
+
client = LogTideClient(
|
|
532
|
+
ClientOptions(
|
|
533
|
+
api_url='http://localhost:8080',
|
|
534
|
+
api_key='lp_your_api_key_here',
|
|
535
|
+
debug=os.getenv('ENV') == 'development',
|
|
536
|
+
)
|
|
537
|
+
)
|
|
538
|
+
```
|
|
539
|
+
|
|
540
|
+
### 4. Monitor Metrics in Production
|
|
541
|
+
|
|
542
|
+
```python
|
|
543
|
+
import time
|
|
544
|
+
import threading
|
|
545
|
+
|
|
546
|
+
def monitor_metrics():
|
|
547
|
+
while True:
|
|
548
|
+
metrics = client.get_metrics()
|
|
549
|
+
|
|
550
|
+
if metrics.logs_dropped > 0:
|
|
551
|
+
print(f"⚠️ Logs dropped: {metrics.logs_dropped}")
|
|
552
|
+
|
|
553
|
+
if metrics.circuit_breaker_trips > 0:
|
|
554
|
+
print("🔴 Circuit breaker is OPEN!")
|
|
555
|
+
|
|
556
|
+
time.sleep(60)
|
|
557
|
+
|
|
558
|
+
# Run in background thread
|
|
559
|
+
monitor_thread = threading.Thread(target=monitor_metrics, daemon=True)
|
|
560
|
+
monitor_thread.start()
|
|
561
|
+
```
|
|
562
|
+
|
|
563
|
+
---
|
|
564
|
+
|
|
565
|
+
## Development
|
|
566
|
+
|
|
567
|
+
### Setup
|
|
568
|
+
|
|
569
|
+
```bash
|
|
570
|
+
# Clone repository
|
|
571
|
+
git clone https://github.com/logtide/python-sdk.git
|
|
572
|
+
cd logtide-sdk-python
|
|
573
|
+
|
|
574
|
+
# Create virtual environment
|
|
575
|
+
python -m venv venv
|
|
576
|
+
source venv/bin/activate # On Windows: venv\Scripts\activate
|
|
577
|
+
|
|
578
|
+
# Install dev dependencies
|
|
579
|
+
pip install -e ".[dev]"
|
|
580
|
+
```
|
|
581
|
+
|
|
582
|
+
### Testing
|
|
583
|
+
|
|
584
|
+
```bash
|
|
585
|
+
# Run tests
|
|
586
|
+
pytest tests/
|
|
587
|
+
|
|
588
|
+
# Type checking
|
|
589
|
+
mypy logtide_sdk/
|
|
590
|
+
|
|
591
|
+
# Code formatting
|
|
592
|
+
black logtide_sdk/ tests/ examples/
|
|
593
|
+
|
|
594
|
+
# Linting
|
|
595
|
+
ruff check logtide_sdk/
|
|
596
|
+
```
|
|
597
|
+
|
|
598
|
+
---
|
|
599
|
+
|
|
600
|
+
## License
|
|
601
|
+
|
|
602
|
+
MIT
|
|
603
|
+
|
|
604
|
+
---
|
|
605
|
+
|
|
606
|
+
## Contributing
|
|
607
|
+
|
|
608
|
+
Contributions are welcome! Please open an issue or PR on [GitHub](https://github.com/logtide/python-sdk).
|
|
609
|
+
|
|
610
|
+
---
|
|
611
|
+
|
|
612
|
+
## Support
|
|
613
|
+
|
|
614
|
+
- **Documentation**: [https://logtide.dev/docs](https://logtide.dev/docs)
|
|
615
|
+
- **Issues**: [GitHub Issues](https://github.com/logtide/python-sdk/issues)
|