insider-python 0.1.3__tar.gz → 0.1.4__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.
- {insider_python-0.1.3 → insider_python-0.1.4}/PKG-INFO +71 -29
- insider_python-0.1.4/README.md +146 -0
- {insider_python-0.1.3 → insider_python-0.1.4}/pyproject.toml +1 -1
- {insider_python-0.1.3 → insider_python-0.1.4}/src/insider/__init__.py +7 -0
- {insider_python-0.1.3 → insider_python-0.1.4}/src/insider/_envelope.py +2 -2
- insider_python-0.1.4/src/insider/_footprint.py +64 -0
- {insider_python-0.1.3 → insider_python-0.1.4}/src/insider/_version.py +1 -1
- {insider_python-0.1.3 → insider_python-0.1.4}/src/insider/client.py +298 -4
- {insider_python-0.1.3 → insider_python-0.1.4}/src/insider/integrations/__init__.py +4 -0
- {insider_python-0.1.3 → insider_python-0.1.4}/src/insider/integrations/django/__init__.py +12 -2
- {insider_python-0.1.3 → insider_python-0.1.4}/src/insider/integrations/django/capture.py +12 -10
- insider_python-0.1.4/src/insider/integrations/django/handler.py +71 -0
- insider_python-0.1.4/src/insider/integrations/django/perf.py +38 -0
- insider_python-0.1.4/src/insider/integrations/logging/__init__.py +66 -0
- insider_python-0.1.4/src/insider/integrations/logging/handler.py +74 -0
- insider_python-0.1.4/src/insider/integrations/logging/levels.py +29 -0
- insider_python-0.1.4/src/insider/scope.py +195 -0
- {insider_python-0.1.3 → insider_python-0.1.4}/src/insider_python.egg-info/PKG-INFO +71 -29
- {insider_python-0.1.3 → insider_python-0.1.4}/src/insider_python.egg-info/SOURCES.txt +8 -0
- insider_python-0.1.4/tests/test_capture_log.py +41 -0
- insider_python-0.1.4/tests/test_capture_perf.py +60 -0
- insider_python-0.1.4/tests/test_django.py +93 -0
- {insider_python-0.1.3 → insider_python-0.1.4}/tests/test_django_integration.py +29 -11
- {insider_python-0.1.3 → insider_python-0.1.4}/tests/test_drf_integration.py +16 -12
- insider_python-0.1.4/tests/test_logging_integration.py +97 -0
- insider_python-0.1.3/README.md +0 -104
- insider_python-0.1.3/src/insider/integrations/django/handler.py +0 -42
- insider_python-0.1.3/src/insider/scope.py +0 -54
- insider_python-0.1.3/tests/test_django.py +0 -101
- {insider_python-0.1.3 → insider_python-0.1.4}/setup.cfg +0 -0
- {insider_python-0.1.3 → insider_python-0.1.4}/src/insider/contrib/__init__.py +0 -0
- {insider_python-0.1.3 → insider_python-0.1.4}/src/insider/contrib/django/__init__.py +0 -0
- {insider_python-0.1.3 → insider_python-0.1.4}/src/insider/contrib/django/apps.py +0 -0
- {insider_python-0.1.3 → insider_python-0.1.4}/src/insider/contrib/django/middleware.py +0 -0
- {insider_python-0.1.3 → insider_python-0.1.4}/src/insider/dsn.py +0 -0
- {insider_python-0.1.3 → insider_python-0.1.4}/src/insider/integrations/django/drf.py +0 -0
- {insider_python-0.1.3 → insider_python-0.1.4}/src/insider/integrations/django/request.py +0 -0
- {insider_python-0.1.3 → insider_python-0.1.4}/src/insider/integrations/django/signals.py +0 -0
- {insider_python-0.1.3 → insider_python-0.1.4}/src/insider/integrations/django/wsgi.py +0 -0
- {insider_python-0.1.3 → insider_python-0.1.4}/src/insider/py.typed +0 -0
- {insider_python-0.1.3 → insider_python-0.1.4}/src/insider/safety.py +0 -0
- {insider_python-0.1.3 → insider_python-0.1.4}/src/insider/scrubbing.py +0 -0
- {insider_python-0.1.3 → insider_python-0.1.4}/src/insider/stacktrace.py +0 -0
- {insider_python-0.1.3 → insider_python-0.1.4}/src/insider/transport.py +0 -0
- {insider_python-0.1.3 → insider_python-0.1.4}/src/insider_python.egg-info/dependency_links.txt +0 -0
- {insider_python-0.1.3 → insider_python-0.1.4}/src/insider_python.egg-info/requires.txt +0 -0
- {insider_python-0.1.3 → insider_python-0.1.4}/src/insider_python.egg-info/top_level.txt +0 -0
- {insider_python-0.1.3 → insider_python-0.1.4}/tests/test_capture.py +0 -0
- {insider_python-0.1.3 → insider_python-0.1.4}/tests/test_dsn.py +0 -0
- {insider_python-0.1.3 → insider_python-0.1.4}/tests/test_envelope.py +0 -0
- {insider_python-0.1.3 → insider_python-0.1.4}/tests/test_never_crash.py +0 -0
- {insider_python-0.1.3 → insider_python-0.1.4}/tests/test_safety.py +0 -0
- {insider_python-0.1.3 → insider_python-0.1.4}/tests/test_scrubbing.py +0 -0
- {insider_python-0.1.3 → insider_python-0.1.4}/tests/test_stacktrace.py +0 -0
- {insider_python-0.1.3 → insider_python-0.1.4}/tests/test_transport.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: insider-python
|
|
3
|
-
Version: 0.1.
|
|
3
|
+
Version: 0.1.4
|
|
4
4
|
Summary: Python SDK for Insider — ship Beacons to your Insider server.
|
|
5
5
|
Author: Insider
|
|
6
6
|
License-Expression: MIT
|
|
@@ -63,10 +63,11 @@ try:
|
|
|
63
63
|
risky()
|
|
64
64
|
except Exception as exc:
|
|
65
65
|
insider.capture_exception(exc)
|
|
66
|
-
|
|
67
|
-
insider.capture_message("cache miss spiked", level="warning")
|
|
68
66
|
```
|
|
69
67
|
|
|
68
|
+
Out-of-band events (background jobs, explicit calls) use standalone beacons:
|
|
69
|
+
`capture_exception`, `capture_log`, `capture_perf`.
|
|
70
|
+
|
|
70
71
|
### Django
|
|
71
72
|
|
|
72
73
|
Initialize in `wsgi.py` (or `asgi.py`) before `get_wsgi_application()`:
|
|
@@ -75,57 +76,98 @@ Initialize in `wsgi.py` (or `asgi.py`) before `get_wsgi_application()`:
|
|
|
75
76
|
import os
|
|
76
77
|
import insider
|
|
77
78
|
from insider.integrations.django import DjangoIntegration
|
|
79
|
+
from insider.integrations.logging import LoggingIntegration
|
|
78
80
|
|
|
79
81
|
insider.init(
|
|
80
82
|
dsn=os.environ.get("INSIDER_DSN"),
|
|
81
83
|
environment="production",
|
|
82
84
|
release="1.2.3",
|
|
83
|
-
|
|
85
|
+
enable_logs=True,
|
|
86
|
+
integrations=[DjangoIntegration(), LoggingIntegration()],
|
|
84
87
|
)
|
|
85
88
|
|
|
86
89
|
from django.core.wsgi import get_wsgi_application
|
|
87
90
|
application = get_wsgi_application()
|
|
88
91
|
```
|
|
89
92
|
|
|
90
|
-
That's the whole setup. Every
|
|
91
|
-
|
|
93
|
+
That's the whole setup. **Every HTTP request** emits **one** `kind=request`
|
|
94
|
+
beacon containing:
|
|
95
|
+
|
|
96
|
+
- timing (duration, method, path, status)
|
|
97
|
+
- request context (headers, path, query string)
|
|
98
|
+
- stdlib logs during that request (when `enable_logs=True`)
|
|
99
|
+
- unhandled exception + stack trace (when the request fails)
|
|
100
|
+
|
|
92
101
|
No middleware, no `INSTALLED_APPS`, and no `EXCEPTION_HANDLER` wiring.
|
|
93
102
|
|
|
94
|
-
|
|
95
|
-
`INSTALLED_APPS` and `InsiderMiddleware` to `MIDDLEWARE`. Prefer the
|
|
96
|
-
`wsgi.py` pattern for new projects.
|
|
103
|
+
Disable auto capture on high-traffic apps until sampling lands:
|
|
97
104
|
|
|
98
|
-
|
|
105
|
+
```python
|
|
106
|
+
integrations=[DjangoIntegration(auto_perf=False)]
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
### Logging
|
|
110
|
+
|
|
111
|
+
During an HTTP request, stdlib `logging` lines are **buffered into the
|
|
112
|
+
request envelope** — not beamed as separate rows:
|
|
113
|
+
|
|
114
|
+
```python
|
|
115
|
+
import logging
|
|
116
|
+
|
|
117
|
+
logger = logging.getLogger(__name__)
|
|
118
|
+
logger.info("checkout completed") # → payload.logs[] on the request beacon
|
|
119
|
+
```
|
|
99
120
|
|
|
100
|
-
|
|
121
|
+
Requires `enable_logs=True`, `LoggingIntegration()`, and a configured
|
|
122
|
+
logger level (see your app's `LOGGING` settings).
|
|
101
123
|
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
124
|
+
Outside an HTTP request, stdlib logs still beam as standalone `kind=log`
|
|
125
|
+
beacons. For explicit structured events, use `capture_log()`:
|
|
126
|
+
|
|
127
|
+
```python
|
|
128
|
+
insider.capture_log(
|
|
129
|
+
"User checkout completed",
|
|
130
|
+
level="info",
|
|
131
|
+
source="checkout.service",
|
|
132
|
+
tags={"feature": "checkout"},
|
|
133
|
+
)
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
Manual perf timings (Celery, custom spans):
|
|
137
|
+
|
|
138
|
+
```python
|
|
139
|
+
insider.capture_perf(
|
|
140
|
+
op="celery.tasks.send_email",
|
|
141
|
+
duration_ms=842,
|
|
142
|
+
)
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
## Footprint kinds
|
|
146
|
+
|
|
147
|
+
| Kind | When |
|
|
148
|
+
|------|------|
|
|
149
|
+
| `request` | One per HTTP request (DjangoIntegration) |
|
|
150
|
+
| `error` | Manual `capture_exception()` outside request cycle |
|
|
151
|
+
| `log` | Manual `capture_log()` or stdlib logs outside request cycle |
|
|
152
|
+
| `perf` | Manual `capture_perf()` for non-HTTP timings |
|
|
153
|
+
|
|
154
|
+
## Configuration
|
|
106
155
|
|
|
107
156
|
If no DSN is found anywhere, the SDK enters **disabled mode**: every
|
|
108
|
-
public call is a no-op
|
|
157
|
+
public call is a no-op.
|
|
109
158
|
|
|
110
159
|
| Option | Default | Notes |
|
|
111
160
|
|--------|---------|-------|
|
|
112
161
|
| `dsn` | env `INSIDER_DSN` | If absent, SDK is disabled |
|
|
113
|
-
| `environment` | `"production"` | Top-level
|
|
114
|
-
| `release` | `None` | Top-level
|
|
115
|
-
| `
|
|
116
|
-
| `
|
|
117
|
-
| `
|
|
118
|
-
| `in_app_include` | `None` | Filename prefixes considered "your code" |
|
|
119
|
-
| `transport_queue_size` | `1000` | Bounded; drops on overflow |
|
|
120
|
-
| `transport_flush_timeout` | `2.0` | Seconds. Used by `close()` / `flush()` |
|
|
121
|
-
| `debug` | `False` | Print SDK's own warnings to stderr |
|
|
162
|
+
| `environment` | `"production"` | Top-level Footprint field |
|
|
163
|
+
| `release` | `None` | Top-level Footprint field |
|
|
164
|
+
| `enable_logs` | `False` | Buffer stdlib logs into request envelopes |
|
|
165
|
+
| `send_default_pii` | `False` | Required to capture request bodies |
|
|
166
|
+
| `debug` | `False` | Print SDK warnings to stderr |
|
|
122
167
|
|
|
123
168
|
## Promise
|
|
124
169
|
|
|
125
|
-
The SDK never raises into your code.
|
|
126
|
-
`Exception` at its boundary; if something goes wrong inside the SDK,
|
|
127
|
-
you get nothing back and a debug log (if enabled). Your app keeps
|
|
128
|
-
running.
|
|
170
|
+
The SDK never raises into your code.
|
|
129
171
|
|
|
130
172
|
## License
|
|
131
173
|
|
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
# insider-python
|
|
2
|
+
|
|
3
|
+
The Python SDK for [Insider](https://insider.moraks.cloud/).
|
|
4
|
+
|
|
5
|
+
Beam Beacons from your Python service to your Insider server with a
|
|
6
|
+
one-line setup. No runtime overhead on your request path. Never raises
|
|
7
|
+
into your code, no matter what.
|
|
8
|
+
|
|
9
|
+
## Install
|
|
10
|
+
|
|
11
|
+
```bash
|
|
12
|
+
pip install insider-python
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
For the Django integration:
|
|
16
|
+
|
|
17
|
+
```bash
|
|
18
|
+
pip install "insider-python[django]"
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
## Quick start
|
|
22
|
+
|
|
23
|
+
### Plain Python
|
|
24
|
+
|
|
25
|
+
```python
|
|
26
|
+
import insider
|
|
27
|
+
|
|
28
|
+
insider.init(
|
|
29
|
+
dsn="https://<beacon_token>@insider.example.com/<project_uuid>",
|
|
30
|
+
environment="production",
|
|
31
|
+
release="1.2.3",
|
|
32
|
+
)
|
|
33
|
+
|
|
34
|
+
try:
|
|
35
|
+
risky()
|
|
36
|
+
except Exception as exc:
|
|
37
|
+
insider.capture_exception(exc)
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
Out-of-band events (background jobs, explicit calls) use standalone beacons:
|
|
41
|
+
`capture_exception`, `capture_log`, `capture_perf`.
|
|
42
|
+
|
|
43
|
+
### Django
|
|
44
|
+
|
|
45
|
+
Initialize in `wsgi.py` (or `asgi.py`) before `get_wsgi_application()`:
|
|
46
|
+
|
|
47
|
+
```python
|
|
48
|
+
import os
|
|
49
|
+
import insider
|
|
50
|
+
from insider.integrations.django import DjangoIntegration
|
|
51
|
+
from insider.integrations.logging import LoggingIntegration
|
|
52
|
+
|
|
53
|
+
insider.init(
|
|
54
|
+
dsn=os.environ.get("INSIDER_DSN"),
|
|
55
|
+
environment="production",
|
|
56
|
+
release="1.2.3",
|
|
57
|
+
enable_logs=True,
|
|
58
|
+
integrations=[DjangoIntegration(), LoggingIntegration()],
|
|
59
|
+
)
|
|
60
|
+
|
|
61
|
+
from django.core.wsgi import get_wsgi_application
|
|
62
|
+
application = get_wsgi_application()
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
That's the whole setup. **Every HTTP request** emits **one** `kind=request`
|
|
66
|
+
beacon containing:
|
|
67
|
+
|
|
68
|
+
- timing (duration, method, path, status)
|
|
69
|
+
- request context (headers, path, query string)
|
|
70
|
+
- stdlib logs during that request (when `enable_logs=True`)
|
|
71
|
+
- unhandled exception + stack trace (when the request fails)
|
|
72
|
+
|
|
73
|
+
No middleware, no `INSTALLED_APPS`, and no `EXCEPTION_HANDLER` wiring.
|
|
74
|
+
|
|
75
|
+
Disable auto capture on high-traffic apps until sampling lands:
|
|
76
|
+
|
|
77
|
+
```python
|
|
78
|
+
integrations=[DjangoIntegration(auto_perf=False)]
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
### Logging
|
|
82
|
+
|
|
83
|
+
During an HTTP request, stdlib `logging` lines are **buffered into the
|
|
84
|
+
request envelope** — not beamed as separate rows:
|
|
85
|
+
|
|
86
|
+
```python
|
|
87
|
+
import logging
|
|
88
|
+
|
|
89
|
+
logger = logging.getLogger(__name__)
|
|
90
|
+
logger.info("checkout completed") # → payload.logs[] on the request beacon
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
Requires `enable_logs=True`, `LoggingIntegration()`, and a configured
|
|
94
|
+
logger level (see your app's `LOGGING` settings).
|
|
95
|
+
|
|
96
|
+
Outside an HTTP request, stdlib logs still beam as standalone `kind=log`
|
|
97
|
+
beacons. For explicit structured events, use `capture_log()`:
|
|
98
|
+
|
|
99
|
+
```python
|
|
100
|
+
insider.capture_log(
|
|
101
|
+
"User checkout completed",
|
|
102
|
+
level="info",
|
|
103
|
+
source="checkout.service",
|
|
104
|
+
tags={"feature": "checkout"},
|
|
105
|
+
)
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
Manual perf timings (Celery, custom spans):
|
|
109
|
+
|
|
110
|
+
```python
|
|
111
|
+
insider.capture_perf(
|
|
112
|
+
op="celery.tasks.send_email",
|
|
113
|
+
duration_ms=842,
|
|
114
|
+
)
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
## Footprint kinds
|
|
118
|
+
|
|
119
|
+
| Kind | When |
|
|
120
|
+
|------|------|
|
|
121
|
+
| `request` | One per HTTP request (DjangoIntegration) |
|
|
122
|
+
| `error` | Manual `capture_exception()` outside request cycle |
|
|
123
|
+
| `log` | Manual `capture_log()` or stdlib logs outside request cycle |
|
|
124
|
+
| `perf` | Manual `capture_perf()` for non-HTTP timings |
|
|
125
|
+
|
|
126
|
+
## Configuration
|
|
127
|
+
|
|
128
|
+
If no DSN is found anywhere, the SDK enters **disabled mode**: every
|
|
129
|
+
public call is a no-op.
|
|
130
|
+
|
|
131
|
+
| Option | Default | Notes |
|
|
132
|
+
|--------|---------|-------|
|
|
133
|
+
| `dsn` | env `INSIDER_DSN` | If absent, SDK is disabled |
|
|
134
|
+
| `environment` | `"production"` | Top-level Footprint field |
|
|
135
|
+
| `release` | `None` | Top-level Footprint field |
|
|
136
|
+
| `enable_logs` | `False` | Buffer stdlib logs into request envelopes |
|
|
137
|
+
| `send_default_pii` | `False` | Required to capture request bodies |
|
|
138
|
+
| `debug` | `False` | Print SDK warnings to stderr |
|
|
139
|
+
|
|
140
|
+
## Promise
|
|
141
|
+
|
|
142
|
+
The SDK never raises into your code.
|
|
143
|
+
|
|
144
|
+
## License
|
|
145
|
+
|
|
146
|
+
MIT
|
|
@@ -6,6 +6,7 @@ Public API:
|
|
|
6
6
|
insider.init(dsn=..., environment=..., release=..., ...)
|
|
7
7
|
insider.capture_exception(exc, level="error", tags=..., extra=...)
|
|
8
8
|
insider.capture_message("text", level="info", tags=..., extra=...)
|
|
9
|
+
insider.capture_perf("GET /api/users/", duration_ms=45, status_code=200)
|
|
9
10
|
insider.flush(timeout=2.0)
|
|
10
11
|
insider.close(timeout=2.0)
|
|
11
12
|
|
|
@@ -17,12 +18,15 @@ from ._version import __version__
|
|
|
17
18
|
from .client import (
|
|
18
19
|
Client,
|
|
19
20
|
capture_exception,
|
|
21
|
+
capture_log,
|
|
20
22
|
capture_message,
|
|
23
|
+
capture_perf,
|
|
21
24
|
close,
|
|
22
25
|
flush,
|
|
23
26
|
init,
|
|
24
27
|
)
|
|
25
28
|
from .dsn import DSN, InvalidDSNError
|
|
29
|
+
from .integrations.logging import LoggingIntegration
|
|
26
30
|
|
|
27
31
|
__all__ = [
|
|
28
32
|
"Client",
|
|
@@ -30,8 +34,11 @@ __all__ = [
|
|
|
30
34
|
"InvalidDSNError",
|
|
31
35
|
"__version__",
|
|
32
36
|
"capture_exception",
|
|
37
|
+
"capture_log",
|
|
33
38
|
"capture_message",
|
|
39
|
+
"capture_perf",
|
|
34
40
|
"close",
|
|
35
41
|
"flush",
|
|
36
42
|
"init",
|
|
43
|
+
"LoggingIntegration",
|
|
37
44
|
]
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
"""
|
|
2
|
-
|
|
2
|
+
Footprint envelope construction + size-budget enforcement.
|
|
3
3
|
|
|
4
4
|
`build_envelope` is called from the capture functions in `client.py`. It
|
|
5
5
|
takes the raw bits (kind, level, message, exception payload, scope,
|
|
@@ -58,7 +58,7 @@ def build_envelope(
|
|
|
58
58
|
occurred_at: Optional[str] = None,
|
|
59
59
|
commit_hash: Optional[str] = None,
|
|
60
60
|
) -> Dict[str, Any]:
|
|
61
|
-
"""Assemble the
|
|
61
|
+
"""Assemble the Footprint envelope. Pure: no I/O, no globals."""
|
|
62
62
|
body: Dict[str, Any] = dict(payload or {})
|
|
63
63
|
if tags:
|
|
64
64
|
body["tags"] = tags
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
"""Build flat footprint payloads for beam ingest."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from typing import Any, Dict, Optional
|
|
6
|
+
|
|
7
|
+
from ._version import __version__
|
|
8
|
+
from .stacktrace import runtime_payload
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
def build_footprint_payload(
|
|
12
|
+
*,
|
|
13
|
+
request_id: Optional[str],
|
|
14
|
+
request_path: str,
|
|
15
|
+
request_method: Optional[str],
|
|
16
|
+
request_user: str = "anonymous",
|
|
17
|
+
request_body: Any = None,
|
|
18
|
+
response_body: Any = None,
|
|
19
|
+
response_time: float,
|
|
20
|
+
status_code: int,
|
|
21
|
+
system_logs: Optional[list] = None,
|
|
22
|
+
ip_address: Optional[str] = None,
|
|
23
|
+
user_agent: Optional[str] = None,
|
|
24
|
+
db_query_count: int = 0,
|
|
25
|
+
exception_block: Optional[Dict[str, Any]] = None,
|
|
26
|
+
environment: str = "production",
|
|
27
|
+
release: Optional[str] = None,
|
|
28
|
+
service_name: Optional[str] = None,
|
|
29
|
+
commit_hash: Optional[str] = None,
|
|
30
|
+
) -> Dict[str, Any]:
|
|
31
|
+
runtime = runtime_payload(__version__)
|
|
32
|
+
stack_trace = None
|
|
33
|
+
exception_name = None
|
|
34
|
+
if exception_block:
|
|
35
|
+
exception_name = exception_block.get("type")
|
|
36
|
+
stack_trace = dict(exception_block)
|
|
37
|
+
if commit_hash:
|
|
38
|
+
stack_trace["commit_hash"] = commit_hash
|
|
39
|
+
|
|
40
|
+
body = request_body
|
|
41
|
+
if body is not None and not isinstance(body, (dict, list, str, int, float, bool)):
|
|
42
|
+
body = str(body)
|
|
43
|
+
|
|
44
|
+
return {
|
|
45
|
+
"request_id": request_id,
|
|
46
|
+
"request_user": request_user,
|
|
47
|
+
"request_path": request_path,
|
|
48
|
+
"request_body": body if body is not None else None,
|
|
49
|
+
"request_method": (request_method or "").lower() or None,
|
|
50
|
+
"response_body": response_body,
|
|
51
|
+
"response_time": float(response_time),
|
|
52
|
+
"status_code": status_code,
|
|
53
|
+
"system_logs": system_logs,
|
|
54
|
+
"ip_address": ip_address,
|
|
55
|
+
"user_agent": user_agent,
|
|
56
|
+
"db_query_count": db_query_count,
|
|
57
|
+
"exception_name": exception_name,
|
|
58
|
+
"stack_trace": stack_trace,
|
|
59
|
+
"service_name": service_name,
|
|
60
|
+
"environment": environment,
|
|
61
|
+
"language": runtime.get("language"),
|
|
62
|
+
"framework": runtime.get("framework"),
|
|
63
|
+
"release": release,
|
|
64
|
+
}
|