chub-dev 0.1.0 → 0.1.2-beta.0
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.
- package/README.md +55 -0
- package/bin/chub-mcp +2 -0
- package/dist/airtable/docs/database/javascript/DOC.md +1437 -0
- package/dist/airtable/docs/database/python/DOC.md +1735 -0
- package/dist/amplitude/docs/analytics/javascript/DOC.md +1282 -0
- package/dist/amplitude/docs/analytics/python/DOC.md +1199 -0
- package/dist/anthropic/docs/claude-api/javascript/DOC.md +503 -0
- package/dist/anthropic/docs/claude-api/python/DOC.md +389 -0
- package/dist/asana/docs/tasks/DOC.md +1396 -0
- package/dist/assemblyai/docs/transcription/DOC.md +1043 -0
- package/dist/atlassian/docs/confluence/javascript/DOC.md +1347 -0
- package/dist/atlassian/docs/confluence/python/DOC.md +1604 -0
- package/dist/auth0/docs/identity/javascript/DOC.md +968 -0
- package/dist/auth0/docs/identity/python/DOC.md +1199 -0
- package/dist/aws/docs/s3/javascript/DOC.md +1773 -0
- package/dist/aws/docs/s3/python/DOC.md +1807 -0
- package/dist/binance/docs/trading/javascript/DOC.md +1315 -0
- package/dist/binance/docs/trading/python/DOC.md +1454 -0
- package/dist/braintree/docs/gateway/javascript/DOC.md +1278 -0
- package/dist/braintree/docs/gateway/python/DOC.md +1179 -0
- package/dist/chromadb/docs/embeddings-db/javascript/DOC.md +1263 -0
- package/dist/chromadb/docs/embeddings-db/python/DOC.md +1707 -0
- package/dist/clerk/docs/auth/javascript/DOC.md +1220 -0
- package/dist/clerk/docs/auth/python/DOC.md +274 -0
- package/dist/cloudflare/docs/workers/javascript/DOC.md +918 -0
- package/dist/cloudflare/docs/workers/python/DOC.md +994 -0
- package/dist/cockroachdb/docs/distributed-db/DOC.md +1500 -0
- package/dist/cohere/docs/llm/DOC.md +1335 -0
- package/dist/datadog/docs/monitoring/javascript/DOC.md +1740 -0
- package/dist/datadog/docs/monitoring/python/DOC.md +1815 -0
- package/dist/deepgram/docs/speech/javascript/DOC.md +885 -0
- package/dist/deepgram/docs/speech/python/DOC.md +685 -0
- package/dist/deepl/docs/translation/javascript/DOC.md +887 -0
- package/dist/deepl/docs/translation/python/DOC.md +944 -0
- package/dist/deepseek/docs/llm/DOC.md +1220 -0
- package/dist/directus/docs/headless-cms/javascript/DOC.md +1128 -0
- package/dist/directus/docs/headless-cms/python/DOC.md +1276 -0
- package/dist/discord/docs/bot/javascript/DOC.md +1090 -0
- package/dist/discord/docs/bot/python/DOC.md +1130 -0
- package/dist/elasticsearch/docs/search/DOC.md +1634 -0
- package/dist/elevenlabs/docs/text-to-speech/javascript/DOC.md +336 -0
- package/dist/elevenlabs/docs/text-to-speech/python/DOC.md +552 -0
- package/dist/firebase/docs/auth/DOC.md +1015 -0
- package/dist/gemini/docs/genai/javascript/DOC.md +691 -0
- package/dist/gemini/docs/genai/python/DOC.md +555 -0
- package/dist/github/docs/octokit/DOC.md +1560 -0
- package/dist/google/docs/bigquery/javascript/DOC.md +1688 -0
- package/dist/google/docs/bigquery/python/DOC.md +1503 -0
- package/dist/hubspot/docs/crm/javascript/DOC.md +1805 -0
- package/dist/hubspot/docs/crm/python/DOC.md +2033 -0
- package/dist/huggingface/docs/transformers/DOC.md +948 -0
- package/dist/intercom/docs/messaging/javascript/DOC.md +1844 -0
- package/dist/intercom/docs/messaging/python/DOC.md +1797 -0
- package/dist/jira/docs/issues/javascript/DOC.md +1420 -0
- package/dist/jira/docs/issues/python/DOC.md +1492 -0
- package/dist/kafka/docs/streaming/javascript/DOC.md +1671 -0
- package/dist/kafka/docs/streaming/python/DOC.md +1464 -0
- package/dist/landingai-ade/docs/api/DOC.md +620 -0
- package/dist/landingai-ade/docs/sdk/python/DOC.md +489 -0
- package/dist/landingai-ade/docs/sdk/typescript/DOC.md +542 -0
- package/dist/landingai-ade/skills/SKILL.md +489 -0
- package/dist/launchdarkly/docs/feature-flags/javascript/DOC.md +1191 -0
- package/dist/launchdarkly/docs/feature-flags/python/DOC.md +1671 -0
- package/dist/linear/docs/tracker/DOC.md +1554 -0
- package/dist/livekit/docs/realtime/javascript/DOC.md +303 -0
- package/dist/livekit/docs/realtime/python/DOC.md +163 -0
- package/dist/mailchimp/docs/marketing/DOC.md +1420 -0
- package/dist/meilisearch/docs/search/DOC.md +1241 -0
- package/dist/microsoft/docs/onedrive/javascript/DOC.md +1421 -0
- package/dist/microsoft/docs/onedrive/python/DOC.md +1549 -0
- package/dist/mongodb/docs/atlas/DOC.md +2041 -0
- package/dist/notion/docs/workspace-api/javascript/DOC.md +1435 -0
- package/dist/notion/docs/workspace-api/python/DOC.md +1400 -0
- package/dist/okta/docs/identity/javascript/DOC.md +1171 -0
- package/dist/okta/docs/identity/python/DOC.md +1401 -0
- package/dist/openai/docs/chat/javascript/DOC.md +407 -0
- package/dist/openai/docs/chat/python/DOC.md +568 -0
- package/dist/paypal/docs/checkout/DOC.md +278 -0
- package/dist/pinecone/docs/sdk/javascript/DOC.md +984 -0
- package/dist/pinecone/docs/sdk/python/DOC.md +1395 -0
- package/dist/plaid/docs/banking/javascript/DOC.md +1163 -0
- package/dist/plaid/docs/banking/python/DOC.md +1203 -0
- package/dist/playwright-community/skills/login-flows/SKILL.md +108 -0
- package/dist/postmark/docs/transactional-email/DOC.md +1168 -0
- package/dist/prisma/docs/orm/javascript/DOC.md +1419 -0
- package/dist/prisma/docs/orm/python/DOC.md +1317 -0
- package/dist/qdrant/docs/vector-search/javascript/DOC.md +1221 -0
- package/dist/qdrant/docs/vector-search/python/DOC.md +1653 -0
- package/dist/rabbitmq/docs/message-queue/javascript/DOC.md +1193 -0
- package/dist/rabbitmq/docs/message-queue/python/DOC.md +1243 -0
- package/dist/razorpay/docs/payments/javascript/DOC.md +1219 -0
- package/dist/razorpay/docs/payments/python/DOC.md +1330 -0
- package/dist/redis/docs/key-value/javascript/DOC.md +1851 -0
- package/dist/redis/docs/key-value/python/DOC.md +2054 -0
- package/dist/registry.json +2817 -0
- package/dist/replicate/docs/model-hosting/DOC.md +1318 -0
- package/dist/resend/docs/email/DOC.md +1271 -0
- package/dist/salesforce/docs/crm/javascript/DOC.md +1241 -0
- package/dist/salesforce/docs/crm/python/DOC.md +1183 -0
- package/dist/search-index.json +1 -0
- package/dist/sendgrid/docs/email-api/javascript/DOC.md +371 -0
- package/dist/sendgrid/docs/email-api/python/DOC.md +656 -0
- package/dist/sentry/docs/error-tracking/javascript/DOC.md +1073 -0
- package/dist/sentry/docs/error-tracking/python/DOC.md +1309 -0
- package/dist/shopify/docs/storefront/DOC.md +457 -0
- package/dist/slack/docs/workspace/javascript/DOC.md +933 -0
- package/dist/slack/docs/workspace/python/DOC.md +271 -0
- package/dist/square/docs/payments/javascript/DOC.md +1855 -0
- package/dist/square/docs/payments/python/DOC.md +1728 -0
- package/dist/stripe/docs/api/DOC.md +1727 -0
- package/dist/stripe/docs/payments/DOC.md +1726 -0
- package/dist/stytch/docs/auth/javascript/DOC.md +1813 -0
- package/dist/stytch/docs/auth/python/DOC.md +1962 -0
- package/dist/supabase/docs/client/DOC.md +1606 -0
- package/dist/twilio/docs/messaging/python/DOC.md +469 -0
- package/dist/twilio/docs/messaging/typescript/DOC.md +946 -0
- package/dist/vercel/docs/platform/DOC.md +1940 -0
- package/dist/weaviate/docs/vector-db/javascript/DOC.md +1268 -0
- package/dist/weaviate/docs/vector-db/python/DOC.md +1388 -0
- package/dist/zendesk/docs/support/javascript/DOC.md +2150 -0
- package/dist/zendesk/docs/support/python/DOC.md +2297 -0
- package/package.json +22 -6
- package/skills/get-api-docs/SKILL.md +84 -0
- package/src/commands/annotate.js +83 -0
- package/src/commands/build.js +12 -1
- package/src/commands/feedback.js +150 -0
- package/src/commands/get.js +83 -42
- package/src/commands/search.js +7 -0
- package/src/index.js +43 -17
- package/src/lib/analytics.js +90 -0
- package/src/lib/annotations.js +57 -0
- package/src/lib/bm25.js +170 -0
- package/src/lib/cache.js +69 -6
- package/src/lib/config.js +8 -3
- package/src/lib/identity.js +99 -0
- package/src/lib/registry.js +103 -20
- package/src/lib/telemetry.js +86 -0
- package/src/mcp/server.js +177 -0
- package/src/mcp/tools.js +251 -0
|
@@ -0,0 +1,1309 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: error-tracking
|
|
3
|
+
description: "Sentry Python SDK for error tracking, performance monitoring, and distributed tracing in Python applications."
|
|
4
|
+
metadata:
|
|
5
|
+
languages: "python"
|
|
6
|
+
versions: "2.43.0"
|
|
7
|
+
updated-on: "2026-03-01"
|
|
8
|
+
source: maintainer
|
|
9
|
+
tags: "sentry,monitoring,error-tracking,performance,tracing"
|
|
10
|
+
---
|
|
11
|
+
|
|
12
|
+
# Sentry Python SDK (2.43.0)
|
|
13
|
+
|
|
14
|
+
## Golden Rule
|
|
15
|
+
|
|
16
|
+
**ALWAYS use `sentry-sdk` for Python applications.**
|
|
17
|
+
|
|
18
|
+
The current stable version is **2.43.0**. Do not use deprecated packages like `raven`.
|
|
19
|
+
|
|
20
|
+
## Installation
|
|
21
|
+
|
|
22
|
+
```bash
|
|
23
|
+
pip install sentry-sdk
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
### With Framework Support
|
|
27
|
+
|
|
28
|
+
```bash
|
|
29
|
+
# Django
|
|
30
|
+
pip install sentry-sdk[django]
|
|
31
|
+
|
|
32
|
+
# Flask
|
|
33
|
+
pip install sentry-sdk[flask]
|
|
34
|
+
|
|
35
|
+
# FastAPI
|
|
36
|
+
pip install sentry-sdk[fastapi]
|
|
37
|
+
|
|
38
|
+
# Celery
|
|
39
|
+
pip install sentry-sdk[celery]
|
|
40
|
+
|
|
41
|
+
# SQLAlchemy
|
|
42
|
+
pip install sentry-sdk[sqlalchemy]
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
### Environment Variables Setup
|
|
46
|
+
|
|
47
|
+
Create a `.env` file:
|
|
48
|
+
|
|
49
|
+
```env
|
|
50
|
+
SENTRY_DSN=https://examplePublicKey@o0.ingest.sentry.io/0
|
|
51
|
+
SENTRY_ENVIRONMENT=production
|
|
52
|
+
SENTRY_RELEASE=my-project@1.0.0
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
Load environment variables:
|
|
56
|
+
|
|
57
|
+
```python
|
|
58
|
+
import os
|
|
59
|
+
from dotenv import load_dotenv
|
|
60
|
+
|
|
61
|
+
load_dotenv()
|
|
62
|
+
|
|
63
|
+
SENTRY_DSN = os.getenv("SENTRY_DSN")
|
|
64
|
+
SENTRY_ENVIRONMENT = os.getenv("SENTRY_ENVIRONMENT", "development")
|
|
65
|
+
SENTRY_RELEASE = os.getenv("SENTRY_RELEASE")
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
## Initialization
|
|
69
|
+
|
|
70
|
+
### Basic Initialization
|
|
71
|
+
|
|
72
|
+
Configuration should happen as **early as possible** in your application's lifecycle.
|
|
73
|
+
|
|
74
|
+
```python
|
|
75
|
+
import sentry_sdk
|
|
76
|
+
|
|
77
|
+
sentry_sdk.init(
|
|
78
|
+
dsn="https://examplePublicKey@o0.ingest.sentry.io/0",
|
|
79
|
+
|
|
80
|
+
# Environment and release tracking
|
|
81
|
+
environment="production",
|
|
82
|
+
release="my-project@1.0.0",
|
|
83
|
+
|
|
84
|
+
# Performance Monitoring
|
|
85
|
+
traces_sample_rate=1.0, # Capture 100% of transactions
|
|
86
|
+
|
|
87
|
+
# Profiling
|
|
88
|
+
profiles_sample_rate=1.0, # Profile 100% of transactions
|
|
89
|
+
|
|
90
|
+
# Send user IP and cookies
|
|
91
|
+
send_default_pii=True,
|
|
92
|
+
|
|
93
|
+
# Enable logging to Sentry
|
|
94
|
+
enable_logs=True,
|
|
95
|
+
)
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
### Django Initialization
|
|
99
|
+
|
|
100
|
+
In `settings.py`:
|
|
101
|
+
|
|
102
|
+
```python
|
|
103
|
+
import sentry_sdk
|
|
104
|
+
|
|
105
|
+
sentry_sdk.init(
|
|
106
|
+
dsn="https://examplePublicKey@o0.ingest.sentry.io/0",
|
|
107
|
+
|
|
108
|
+
# Performance Monitoring
|
|
109
|
+
traces_sample_rate=1.0,
|
|
110
|
+
|
|
111
|
+
# Profiling
|
|
112
|
+
profiles_sample_rate=1.0,
|
|
113
|
+
|
|
114
|
+
# Send user PII
|
|
115
|
+
send_default_pii=True,
|
|
116
|
+
)
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
### Flask Initialization
|
|
120
|
+
|
|
121
|
+
```python
|
|
122
|
+
from flask import Flask
|
|
123
|
+
import sentry_sdk
|
|
124
|
+
|
|
125
|
+
sentry_sdk.init(
|
|
126
|
+
dsn="https://examplePublicKey@o0.ingest.sentry.io/0",
|
|
127
|
+
traces_sample_rate=1.0,
|
|
128
|
+
profiles_sample_rate=1.0,
|
|
129
|
+
send_default_pii=True,
|
|
130
|
+
)
|
|
131
|
+
|
|
132
|
+
app = Flask(__name__)
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
### FastAPI Initialization
|
|
136
|
+
|
|
137
|
+
```python
|
|
138
|
+
from fastapi import FastAPI
|
|
139
|
+
import sentry_sdk
|
|
140
|
+
|
|
141
|
+
sentry_sdk.init(
|
|
142
|
+
dsn="https://examplePublicKey@o0.ingest.sentry.io/0",
|
|
143
|
+
traces_sample_rate=1.0,
|
|
144
|
+
profiles_sample_rate=1.0,
|
|
145
|
+
send_default_pii=True,
|
|
146
|
+
)
|
|
147
|
+
|
|
148
|
+
app = FastAPI()
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
### Async Application Initialization
|
|
152
|
+
|
|
153
|
+
For async applications, initialize within an async function:
|
|
154
|
+
|
|
155
|
+
```python
|
|
156
|
+
import asyncio
|
|
157
|
+
import sentry_sdk
|
|
158
|
+
|
|
159
|
+
async def main():
|
|
160
|
+
sentry_sdk.init(
|
|
161
|
+
dsn="https://examplePublicKey@o0.ingest.sentry.io/0",
|
|
162
|
+
traces_sample_rate=1.0,
|
|
163
|
+
)
|
|
164
|
+
|
|
165
|
+
# Your async code here
|
|
166
|
+
await run_application()
|
|
167
|
+
|
|
168
|
+
if __name__ == "__main__":
|
|
169
|
+
asyncio.run(main())
|
|
170
|
+
```
|
|
171
|
+
|
|
172
|
+
## Error Tracking
|
|
173
|
+
|
|
174
|
+
### Capture Exceptions
|
|
175
|
+
|
|
176
|
+
**Automatic Error Capture:**
|
|
177
|
+
|
|
178
|
+
Sentry automatically captures unhandled exceptions.
|
|
179
|
+
|
|
180
|
+
```python
|
|
181
|
+
# This error will be automatically captured
|
|
182
|
+
raise Exception("Something went wrong!")
|
|
183
|
+
```
|
|
184
|
+
|
|
185
|
+
**Manual Error Capture:**
|
|
186
|
+
|
|
187
|
+
```python
|
|
188
|
+
import sentry_sdk
|
|
189
|
+
|
|
190
|
+
try:
|
|
191
|
+
some_failing_function()
|
|
192
|
+
except Exception as e:
|
|
193
|
+
sentry_sdk.capture_exception(e)
|
|
194
|
+
```
|
|
195
|
+
|
|
196
|
+
**Capture with Context:**
|
|
197
|
+
|
|
198
|
+
```python
|
|
199
|
+
try:
|
|
200
|
+
process_payment(user_id)
|
|
201
|
+
except Exception as e:
|
|
202
|
+
with sentry_sdk.push_scope() as scope:
|
|
203
|
+
scope.set_tag("payment_method", "credit_card")
|
|
204
|
+
scope.set_user({"id": user_id})
|
|
205
|
+
scope.set_level("error")
|
|
206
|
+
sentry_sdk.capture_exception(e)
|
|
207
|
+
```
|
|
208
|
+
|
|
209
|
+
### Capture Messages
|
|
210
|
+
|
|
211
|
+
```python
|
|
212
|
+
import sentry_sdk
|
|
213
|
+
|
|
214
|
+
# Simple message
|
|
215
|
+
sentry_sdk.capture_message("User completed checkout")
|
|
216
|
+
|
|
217
|
+
# Message with severity level
|
|
218
|
+
sentry_sdk.capture_message("Payment processing slow", "warning")
|
|
219
|
+
|
|
220
|
+
# Available levels: "fatal", "error", "warning", "log", "info", "debug"
|
|
221
|
+
sentry_sdk.capture_message("Critical system failure", "fatal")
|
|
222
|
+
```
|
|
223
|
+
|
|
224
|
+
### Message with Context
|
|
225
|
+
|
|
226
|
+
```python
|
|
227
|
+
with sentry_sdk.push_scope() as scope:
|
|
228
|
+
scope.set_tag("section", "checkout")
|
|
229
|
+
scope.set_extra("cart_total", 129.99)
|
|
230
|
+
sentry_sdk.capture_message("Checkout completed", "info")
|
|
231
|
+
```
|
|
232
|
+
|
|
233
|
+
### Capture from Try-Except
|
|
234
|
+
|
|
235
|
+
```python
|
|
236
|
+
import sentry_sdk
|
|
237
|
+
|
|
238
|
+
def process_data(data):
|
|
239
|
+
try:
|
|
240
|
+
result = risky_operation(data)
|
|
241
|
+
return result
|
|
242
|
+
except ValueError as e:
|
|
243
|
+
sentry_sdk.capture_exception(e)
|
|
244
|
+
return None
|
|
245
|
+
except Exception as e:
|
|
246
|
+
sentry_sdk.capture_exception(e)
|
|
247
|
+
raise
|
|
248
|
+
```
|
|
249
|
+
|
|
250
|
+
## Enriching Error Data
|
|
251
|
+
|
|
252
|
+
### Set User Information
|
|
253
|
+
|
|
254
|
+
```python
|
|
255
|
+
sentry_sdk.set_user({
|
|
256
|
+
"id": "12345",
|
|
257
|
+
"email": "user@example.com",
|
|
258
|
+
"username": "john_doe",
|
|
259
|
+
"ip_address": "{{auto}}", # Automatically capture IP
|
|
260
|
+
})
|
|
261
|
+
|
|
262
|
+
# Clear user data
|
|
263
|
+
sentry_sdk.set_user(None)
|
|
264
|
+
```
|
|
265
|
+
|
|
266
|
+
### Set Tags
|
|
267
|
+
|
|
268
|
+
Tags are searchable key-value pairs:
|
|
269
|
+
|
|
270
|
+
```python
|
|
271
|
+
import sentry_sdk
|
|
272
|
+
|
|
273
|
+
# Set single tag
|
|
274
|
+
sentry_sdk.set_tag("page_locale", "en-us")
|
|
275
|
+
sentry_sdk.set_tag("environment", "staging")
|
|
276
|
+
|
|
277
|
+
# Set multiple tags using scope
|
|
278
|
+
with sentry_sdk.push_scope() as scope:
|
|
279
|
+
scope.set_tag("user_type", "premium")
|
|
280
|
+
scope.set_tag("platform", "web")
|
|
281
|
+
sentry_sdk.capture_message("User action")
|
|
282
|
+
```
|
|
283
|
+
|
|
284
|
+
### Set Context
|
|
285
|
+
|
|
286
|
+
Context adds structured data to events:
|
|
287
|
+
|
|
288
|
+
```python
|
|
289
|
+
import sentry_sdk
|
|
290
|
+
|
|
291
|
+
sentry_sdk.set_context("character", {
|
|
292
|
+
"name": "Mighty Fighter",
|
|
293
|
+
"age": 19,
|
|
294
|
+
"attack_type": "melee",
|
|
295
|
+
"level": 42
|
|
296
|
+
})
|
|
297
|
+
|
|
298
|
+
sentry_sdk.set_context("order", {
|
|
299
|
+
"id": "ORD-12345",
|
|
300
|
+
"total": 249.99,
|
|
301
|
+
"items": 5,
|
|
302
|
+
"shipping_method": "express"
|
|
303
|
+
})
|
|
304
|
+
```
|
|
305
|
+
|
|
306
|
+
### Set Extra Data
|
|
307
|
+
|
|
308
|
+
```python
|
|
309
|
+
sentry_sdk.set_extra("debug_data", {
|
|
310
|
+
"last_query": "SELECT * FROM users",
|
|
311
|
+
"response_time": 1234,
|
|
312
|
+
})
|
|
313
|
+
|
|
314
|
+
# Or using scope
|
|
315
|
+
with sentry_sdk.push_scope() as scope:
|
|
316
|
+
scope.set_extra("additional_info", {"key": "value"})
|
|
317
|
+
sentry_sdk.capture_exception(Exception("Error with extra data"))
|
|
318
|
+
```
|
|
319
|
+
|
|
320
|
+
### Add Breadcrumbs
|
|
321
|
+
|
|
322
|
+
Breadcrumbs create a trail of events leading to an error:
|
|
323
|
+
|
|
324
|
+
```python
|
|
325
|
+
import sentry_sdk
|
|
326
|
+
|
|
327
|
+
# Manual breadcrumb
|
|
328
|
+
sentry_sdk.add_breadcrumb(
|
|
329
|
+
category='auth',
|
|
330
|
+
message='User logged in',
|
|
331
|
+
level='info',
|
|
332
|
+
)
|
|
333
|
+
|
|
334
|
+
sentry_sdk.add_breadcrumb(
|
|
335
|
+
category='api',
|
|
336
|
+
message='API request to /users',
|
|
337
|
+
level='info',
|
|
338
|
+
data={
|
|
339
|
+
'url': '/api/users',
|
|
340
|
+
'method': 'GET',
|
|
341
|
+
'status_code': 200,
|
|
342
|
+
}
|
|
343
|
+
)
|
|
344
|
+
|
|
345
|
+
sentry_sdk.add_breadcrumb(
|
|
346
|
+
category='navigation',
|
|
347
|
+
message='User navigated to checkout',
|
|
348
|
+
level='info',
|
|
349
|
+
data={
|
|
350
|
+
'from': '/cart',
|
|
351
|
+
'to': '/checkout',
|
|
352
|
+
}
|
|
353
|
+
)
|
|
354
|
+
```
|
|
355
|
+
|
|
356
|
+
**Automatic Breadcrumbs:**
|
|
357
|
+
|
|
358
|
+
The SDK automatically captures:
|
|
359
|
+
- HTTP requests
|
|
360
|
+
- Database queries
|
|
361
|
+
- Logging calls
|
|
362
|
+
- Framework-specific events
|
|
363
|
+
|
|
364
|
+
**Filter Breadcrumbs:**
|
|
365
|
+
|
|
366
|
+
```python
|
|
367
|
+
import sentry_sdk
|
|
368
|
+
from sentry_sdk.types import Breadcrumb, BreadcrumbHint
|
|
369
|
+
|
|
370
|
+
def before_breadcrumb(crumb: Breadcrumb, hint: BreadcrumbHint):
|
|
371
|
+
# Filter out spammy breadcrumbs
|
|
372
|
+
if crumb.get('category') == 'a.spammy.Logger':
|
|
373
|
+
return None
|
|
374
|
+
|
|
375
|
+
# Modify breadcrumb
|
|
376
|
+
if crumb.get('category') == 'console':
|
|
377
|
+
crumb['level'] = 'debug'
|
|
378
|
+
|
|
379
|
+
return crumb
|
|
380
|
+
|
|
381
|
+
sentry_sdk.init(
|
|
382
|
+
dsn="https://examplePublicKey@o0.ingest.sentry.io/0",
|
|
383
|
+
before_breadcrumb=before_breadcrumb,
|
|
384
|
+
)
|
|
385
|
+
```
|
|
386
|
+
|
|
387
|
+
## Scopes
|
|
388
|
+
|
|
389
|
+
Scopes contain data that is attached to events.
|
|
390
|
+
|
|
391
|
+
### Push Scope
|
|
392
|
+
|
|
393
|
+
```python
|
|
394
|
+
import sentry_sdk
|
|
395
|
+
|
|
396
|
+
# Create temporary scope for specific error
|
|
397
|
+
with sentry_sdk.push_scope() as scope:
|
|
398
|
+
scope.set_tag("section", "payment")
|
|
399
|
+
scope.set_level("warning")
|
|
400
|
+
scope.set_user({"id": "12345"})
|
|
401
|
+
sentry_sdk.capture_exception(Exception("Payment failed"))
|
|
402
|
+
|
|
403
|
+
# This error won't have the above tags
|
|
404
|
+
sentry_sdk.capture_exception(Exception("Another error"))
|
|
405
|
+
```
|
|
406
|
+
|
|
407
|
+
### Configure Scope
|
|
408
|
+
|
|
409
|
+
```python
|
|
410
|
+
import sentry_sdk
|
|
411
|
+
|
|
412
|
+
def process_request(request):
|
|
413
|
+
with sentry_sdk.configure_scope() as scope:
|
|
414
|
+
scope.set_tag("request_id", request.id)
|
|
415
|
+
scope.set_user({
|
|
416
|
+
"id": request.user.id,
|
|
417
|
+
"email": request.user.email,
|
|
418
|
+
})
|
|
419
|
+
scope.set_extra("request_data", request.data)
|
|
420
|
+
```
|
|
421
|
+
|
|
422
|
+
### Global Scope
|
|
423
|
+
|
|
424
|
+
```python
|
|
425
|
+
import sentry_sdk
|
|
426
|
+
|
|
427
|
+
# Set data on global scope (affects all events)
|
|
428
|
+
with sentry_sdk.configure_scope() as scope:
|
|
429
|
+
scope.set_tag("app_version", "1.0.0")
|
|
430
|
+
scope.set_context("app_info", {
|
|
431
|
+
"name": "My App",
|
|
432
|
+
"version": "1.0.0"
|
|
433
|
+
})
|
|
434
|
+
```
|
|
435
|
+
|
|
436
|
+
### Isolation Scope
|
|
437
|
+
|
|
438
|
+
```python
|
|
439
|
+
import sentry_sdk
|
|
440
|
+
|
|
441
|
+
# Get isolation scope
|
|
442
|
+
scope = sentry_sdk.get_isolation_scope()
|
|
443
|
+
scope.set_tag("isolation_tag", "value")
|
|
444
|
+
```
|
|
445
|
+
|
|
446
|
+
### Current Scope
|
|
447
|
+
|
|
448
|
+
```python
|
|
449
|
+
import sentry_sdk
|
|
450
|
+
|
|
451
|
+
# Get current scope
|
|
452
|
+
scope = sentry_sdk.get_current_scope()
|
|
453
|
+
scope.set_tag("current_tag", "value")
|
|
454
|
+
```
|
|
455
|
+
|
|
456
|
+
## Performance Monitoring
|
|
457
|
+
|
|
458
|
+
### Basic Transaction
|
|
459
|
+
|
|
460
|
+
```python
|
|
461
|
+
import sentry_sdk
|
|
462
|
+
|
|
463
|
+
def eat_pizza(pizza):
|
|
464
|
+
with sentry_sdk.start_transaction(op="task", name="Eat Pizza"):
|
|
465
|
+
while pizza.slices > 0:
|
|
466
|
+
eat_slice(pizza.slices.pop())
|
|
467
|
+
```
|
|
468
|
+
|
|
469
|
+
### Transaction with Spans
|
|
470
|
+
|
|
471
|
+
```python
|
|
472
|
+
import sentry_sdk
|
|
473
|
+
|
|
474
|
+
def eat_pizza(pizza):
|
|
475
|
+
with sentry_sdk.start_transaction(op="task", name="Eat Pizza"):
|
|
476
|
+
while pizza.slices > 0:
|
|
477
|
+
with sentry_sdk.start_span(name="Eat Slice"):
|
|
478
|
+
eat_slice(pizza.slices.pop())
|
|
479
|
+
```
|
|
480
|
+
|
|
481
|
+
### Nested Spans
|
|
482
|
+
|
|
483
|
+
```python
|
|
484
|
+
import sentry_sdk
|
|
485
|
+
|
|
486
|
+
def chew():
|
|
487
|
+
# Chewing logic
|
|
488
|
+
pass
|
|
489
|
+
|
|
490
|
+
def eat_slice(slice):
|
|
491
|
+
with sentry_sdk.start_span(name="Eat Slice"):
|
|
492
|
+
with sentry_sdk.start_span(name="Chew"):
|
|
493
|
+
chew()
|
|
494
|
+
```
|
|
495
|
+
|
|
496
|
+
### Using Decorators
|
|
497
|
+
|
|
498
|
+
```python
|
|
499
|
+
import sentry_sdk
|
|
500
|
+
|
|
501
|
+
@sentry_sdk.trace
|
|
502
|
+
def eat_slice(slice):
|
|
503
|
+
# This function is automatically traced
|
|
504
|
+
pass
|
|
505
|
+
|
|
506
|
+
def eat_pizza(pizza):
|
|
507
|
+
with sentry_sdk.start_transaction(op="task", name="Eat Pizza"):
|
|
508
|
+
while pizza.slices > 0:
|
|
509
|
+
eat_slice(pizza.slices.pop())
|
|
510
|
+
```
|
|
511
|
+
|
|
512
|
+
### Nested Decorators
|
|
513
|
+
|
|
514
|
+
```python
|
|
515
|
+
import sentry_sdk
|
|
516
|
+
|
|
517
|
+
@sentry_sdk.trace
|
|
518
|
+
def chew():
|
|
519
|
+
# Chewing logic
|
|
520
|
+
pass
|
|
521
|
+
|
|
522
|
+
@sentry_sdk.trace
|
|
523
|
+
def eat_slice(slice):
|
|
524
|
+
chew()
|
|
525
|
+
|
|
526
|
+
@sentry_sdk.trace
|
|
527
|
+
def eat_pizza(pizza):
|
|
528
|
+
while pizza.slices > 0:
|
|
529
|
+
eat_slice(pizza.slices.pop())
|
|
530
|
+
|
|
531
|
+
# Start transaction
|
|
532
|
+
with sentry_sdk.start_transaction(op="task", name="Lunch"):
|
|
533
|
+
eat_pizza(pizza)
|
|
534
|
+
```
|
|
535
|
+
|
|
536
|
+
### Manual Span Management
|
|
537
|
+
|
|
538
|
+
```python
|
|
539
|
+
import sentry_sdk
|
|
540
|
+
|
|
541
|
+
def eat_slice(slice):
|
|
542
|
+
pass
|
|
543
|
+
|
|
544
|
+
def eat_pizza(pizza):
|
|
545
|
+
with sentry_sdk.start_transaction(op="task", name="Eat Pizza"):
|
|
546
|
+
while pizza.slices > 0:
|
|
547
|
+
span = sentry_sdk.start_span(name="Eat Slice")
|
|
548
|
+
eat_slice(pizza.slices.pop())
|
|
549
|
+
span.finish()
|
|
550
|
+
```
|
|
551
|
+
|
|
552
|
+
### Manual Nested Spans
|
|
553
|
+
|
|
554
|
+
```python
|
|
555
|
+
import sentry_sdk
|
|
556
|
+
|
|
557
|
+
def chew():
|
|
558
|
+
pass
|
|
559
|
+
|
|
560
|
+
def eat_slice(slice):
|
|
561
|
+
parent_span = sentry_sdk.start_span(name="Eat Slice")
|
|
562
|
+
|
|
563
|
+
child_span = parent_span.start_child(name="Chew")
|
|
564
|
+
chew()
|
|
565
|
+
child_span.finish()
|
|
566
|
+
|
|
567
|
+
parent_span.finish()
|
|
568
|
+
```
|
|
569
|
+
|
|
570
|
+
### Decorator with Custom Parameters
|
|
571
|
+
|
|
572
|
+
```python
|
|
573
|
+
import sentry_sdk
|
|
574
|
+
|
|
575
|
+
@sentry_sdk.trace(op="my_op", name="ProcessItem", attributes={"x": True})
|
|
576
|
+
def my_function(i):
|
|
577
|
+
# Function logic
|
|
578
|
+
pass
|
|
579
|
+
|
|
580
|
+
@sentry_sdk.trace
|
|
581
|
+
def root_function():
|
|
582
|
+
for i in range(3):
|
|
583
|
+
my_function(i)
|
|
584
|
+
|
|
585
|
+
# Start transaction
|
|
586
|
+
with sentry_sdk.start_transaction(op="task", name="Root"):
|
|
587
|
+
root_function()
|
|
588
|
+
```
|
|
589
|
+
|
|
590
|
+
### Decorator with Template
|
|
591
|
+
|
|
592
|
+
```python
|
|
593
|
+
import sentry_sdk
|
|
594
|
+
from sentry_sdk.consts import SPANTEMPLATE
|
|
595
|
+
|
|
596
|
+
@sentry_sdk.trace(template=SPANTEMPLATE.AI_AGENT)
|
|
597
|
+
def my_ai_function(i):
|
|
598
|
+
# AI logic
|
|
599
|
+
pass
|
|
600
|
+
|
|
601
|
+
@sentry_sdk.trace
|
|
602
|
+
def root_function():
|
|
603
|
+
for i in range(3):
|
|
604
|
+
my_ai_function(i)
|
|
605
|
+
|
|
606
|
+
# Start transaction
|
|
607
|
+
with sentry_sdk.start_transaction(op="task", name="AI Processing"):
|
|
608
|
+
root_function()
|
|
609
|
+
```
|
|
610
|
+
|
|
611
|
+
### Centralized Function Tracing
|
|
612
|
+
|
|
613
|
+
```python
|
|
614
|
+
import sentry_sdk
|
|
615
|
+
|
|
616
|
+
functions_to_trace = [
|
|
617
|
+
{"qualified_name": "mymodule.eat_slice"},
|
|
618
|
+
{"qualified_name": "mymodule.swallow"},
|
|
619
|
+
{"qualified_name": "mymodule.chew"},
|
|
620
|
+
{"qualified_name": "mymodule.submodule.another.some_function"},
|
|
621
|
+
{"qualified_name": "mymodule.SomePizzaClass.some_method"},
|
|
622
|
+
]
|
|
623
|
+
|
|
624
|
+
sentry_sdk.init(
|
|
625
|
+
dsn="https://examplePublicKey@o0.ingest.sentry.io/0",
|
|
626
|
+
traces_sample_rate=1.0,
|
|
627
|
+
functions_to_trace=functions_to_trace,
|
|
628
|
+
)
|
|
629
|
+
```
|
|
630
|
+
|
|
631
|
+
### Access Current Transaction
|
|
632
|
+
|
|
633
|
+
```python
|
|
634
|
+
import sentry_sdk
|
|
635
|
+
|
|
636
|
+
def eat_pizza(pizza):
|
|
637
|
+
transaction = sentry_sdk.get_current_scope().transaction
|
|
638
|
+
|
|
639
|
+
if transaction is not None:
|
|
640
|
+
transaction.set_tag("num_of_slices", len(pizza.slices))
|
|
641
|
+
transaction.set_data("pizza_type", pizza.type)
|
|
642
|
+
|
|
643
|
+
while pizza.slices > 0:
|
|
644
|
+
eat_slice(pizza.slices.pop())
|
|
645
|
+
```
|
|
646
|
+
|
|
647
|
+
### Access Current Span
|
|
648
|
+
|
|
649
|
+
```python
|
|
650
|
+
import sentry_sdk
|
|
651
|
+
|
|
652
|
+
@sentry_sdk.trace
|
|
653
|
+
def eat_slice(slice):
|
|
654
|
+
span = sentry_sdk.get_current_span()
|
|
655
|
+
|
|
656
|
+
if span is not None:
|
|
657
|
+
span.set_tag("slice_id", slice.id)
|
|
658
|
+
span.set_data("slice_size", slice.size)
|
|
659
|
+
```
|
|
660
|
+
|
|
661
|
+
### Add Data to Transactions
|
|
662
|
+
|
|
663
|
+
```python
|
|
664
|
+
import sentry_sdk
|
|
665
|
+
|
|
666
|
+
with sentry_sdk.start_transaction(name="my-transaction") as transaction:
|
|
667
|
+
transaction.set_data("my-data-attribute-1", "value1")
|
|
668
|
+
transaction.set_data("my-data-attribute-2", 42)
|
|
669
|
+
transaction.set_data("my-data-attribute-3", True)
|
|
670
|
+
|
|
671
|
+
transaction.set_data("my-data-attribute-4", ["value1", "value2", "value3"])
|
|
672
|
+
transaction.set_data("my-data-attribute-5", [42, 43, 44])
|
|
673
|
+
transaction.set_data("my-data-attribute-6", [True, False, True])
|
|
674
|
+
```
|
|
675
|
+
|
|
676
|
+
### Add Data to Spans
|
|
677
|
+
|
|
678
|
+
```python
|
|
679
|
+
import sentry_sdk
|
|
680
|
+
|
|
681
|
+
with sentry_sdk.start_span(name="my-span") as span:
|
|
682
|
+
span.set_data("my-data-attribute-1", "value1")
|
|
683
|
+
span.set_data("my-data-attribute-2", 42)
|
|
684
|
+
span.set_data("my-data-attribute-3", True)
|
|
685
|
+
|
|
686
|
+
span.set_data("my-data-attribute-4", ["value1", "value2", "value3"])
|
|
687
|
+
span.set_data("my-data-attribute-5", [42, 43, 44])
|
|
688
|
+
span.set_data("my-data-attribute-6", [True, False, True])
|
|
689
|
+
```
|
|
690
|
+
|
|
691
|
+
### Update Current Span
|
|
692
|
+
|
|
693
|
+
```python
|
|
694
|
+
import sentry_sdk
|
|
695
|
+
|
|
696
|
+
@sentry_sdk.trace(op="my_op", name="Paul", attributes={"x": True})
|
|
697
|
+
def my_function(i):
|
|
698
|
+
sentry_sdk.update_current_span(
|
|
699
|
+
op="myOp",
|
|
700
|
+
name=f"Paul{i}",
|
|
701
|
+
attributes={"y": i},
|
|
702
|
+
)
|
|
703
|
+
|
|
704
|
+
@sentry_sdk.trace
|
|
705
|
+
def root_function():
|
|
706
|
+
for i in range(3):
|
|
707
|
+
my_function(i)
|
|
708
|
+
|
|
709
|
+
# Start transaction
|
|
710
|
+
with sentry_sdk.start_transaction(op="task", name="Root"):
|
|
711
|
+
root_function()
|
|
712
|
+
```
|
|
713
|
+
|
|
714
|
+
### Async Transactions
|
|
715
|
+
|
|
716
|
+
```python
|
|
717
|
+
import asyncio
|
|
718
|
+
import sentry_sdk
|
|
719
|
+
|
|
720
|
+
async def fetch_data():
|
|
721
|
+
# Async data fetching
|
|
722
|
+
await asyncio.sleep(1)
|
|
723
|
+
return {"data": "value"}
|
|
724
|
+
|
|
725
|
+
async def process_request():
|
|
726
|
+
with sentry_sdk.start_transaction(op="http.server", name="Process Request"):
|
|
727
|
+
with sentry_sdk.start_span(name="Fetch Data"):
|
|
728
|
+
data = await fetch_data()
|
|
729
|
+
|
|
730
|
+
with sentry_sdk.start_span(name="Process Data"):
|
|
731
|
+
result = process_data(data)
|
|
732
|
+
|
|
733
|
+
return result
|
|
734
|
+
|
|
735
|
+
# Run async function
|
|
736
|
+
asyncio.run(process_request())
|
|
737
|
+
```
|
|
738
|
+
|
|
739
|
+
## Event Filtering
|
|
740
|
+
|
|
741
|
+
### Before Send Hook
|
|
742
|
+
|
|
743
|
+
```python
|
|
744
|
+
import sentry_sdk
|
|
745
|
+
from sentry_sdk.types import Event, Hint
|
|
746
|
+
|
|
747
|
+
def before_send(event: Event, hint: Hint):
|
|
748
|
+
# Don't send events in development
|
|
749
|
+
if event.get("environment") == "development":
|
|
750
|
+
return None
|
|
751
|
+
|
|
752
|
+
# Filter out specific errors
|
|
753
|
+
if "exc_info" in hint:
|
|
754
|
+
exc_type, exc_value, tb = hint["exc_info"]
|
|
755
|
+
if isinstance(exc_value, ConnectionError):
|
|
756
|
+
return None
|
|
757
|
+
|
|
758
|
+
# Modify event
|
|
759
|
+
if event.get("user"):
|
|
760
|
+
event["user"].pop("ip_address", None)
|
|
761
|
+
|
|
762
|
+
return event
|
|
763
|
+
|
|
764
|
+
sentry_sdk.init(
|
|
765
|
+
dsn="https://examplePublicKey@o0.ingest.sentry.io/0",
|
|
766
|
+
before_send=before_send,
|
|
767
|
+
)
|
|
768
|
+
```
|
|
769
|
+
|
|
770
|
+
### Before Send Transaction Hook
|
|
771
|
+
|
|
772
|
+
```python
|
|
773
|
+
import sentry_sdk
|
|
774
|
+
from sentry_sdk.types import Event, Hint
|
|
775
|
+
|
|
776
|
+
def before_send_transaction(event: Event, hint: Hint):
|
|
777
|
+
# Don't send health check transactions
|
|
778
|
+
if event.get("transaction") == "GET /health":
|
|
779
|
+
return None
|
|
780
|
+
|
|
781
|
+
# Add custom data to all spans
|
|
782
|
+
for span in event.get("spans", []):
|
|
783
|
+
span["data"] = span.get("data", {})
|
|
784
|
+
span["data"]["foo"] = "bar"
|
|
785
|
+
|
|
786
|
+
# Add data to root transaction
|
|
787
|
+
if "contexts" in event and "trace" in event["contexts"]:
|
|
788
|
+
event["contexts"]["trace"]["data"] = event["contexts"]["trace"].get("data", {})
|
|
789
|
+
event["contexts"]["trace"]["data"]["foo"] = "bar"
|
|
790
|
+
|
|
791
|
+
return event
|
|
792
|
+
|
|
793
|
+
sentry_sdk.init(
|
|
794
|
+
dsn="https://examplePublicKey@o0.ingest.sentry.io/0",
|
|
795
|
+
traces_sample_rate=1.0,
|
|
796
|
+
before_send_transaction=before_send_transaction,
|
|
797
|
+
)
|
|
798
|
+
```
|
|
799
|
+
|
|
800
|
+
### Event Processors
|
|
801
|
+
|
|
802
|
+
```python
|
|
803
|
+
import sentry_sdk
|
|
804
|
+
|
|
805
|
+
def strip_sensitive_data(event, hint):
|
|
806
|
+
# Remove sensitive data from event
|
|
807
|
+
if "request" in event:
|
|
808
|
+
if "headers" in event["request"]:
|
|
809
|
+
event["request"]["headers"].pop("Authorization", None)
|
|
810
|
+
event["request"]["headers"].pop("Cookie", None)
|
|
811
|
+
|
|
812
|
+
return event
|
|
813
|
+
|
|
814
|
+
# Add globally
|
|
815
|
+
sentry_sdk.add_event_processor(strip_sensitive_data)
|
|
816
|
+
|
|
817
|
+
# Or add to specific scope
|
|
818
|
+
with sentry_sdk.push_scope() as scope:
|
|
819
|
+
scope.add_event_processor(strip_sensitive_data)
|
|
820
|
+
sentry_sdk.capture_exception(Exception("Error"))
|
|
821
|
+
```
|
|
822
|
+
|
|
823
|
+
## Sampling
|
|
824
|
+
|
|
825
|
+
### Error Sampling
|
|
826
|
+
|
|
827
|
+
```python
|
|
828
|
+
sentry_sdk.init(
|
|
829
|
+
dsn="https://examplePublicKey@o0.ingest.sentry.io/0",
|
|
830
|
+
|
|
831
|
+
# Sample 50% of errors
|
|
832
|
+
sample_rate=0.5,
|
|
833
|
+
)
|
|
834
|
+
```
|
|
835
|
+
|
|
836
|
+
### Performance Sampling
|
|
837
|
+
|
|
838
|
+
```python
|
|
839
|
+
sentry_sdk.init(
|
|
840
|
+
dsn="https://examplePublicKey@o0.ingest.sentry.io/0",
|
|
841
|
+
|
|
842
|
+
# Sample 25% of transactions
|
|
843
|
+
traces_sample_rate=0.25,
|
|
844
|
+
)
|
|
845
|
+
```
|
|
846
|
+
|
|
847
|
+
### Dynamic Performance Sampling
|
|
848
|
+
|
|
849
|
+
```python
|
|
850
|
+
def traces_sampler(sampling_context):
|
|
851
|
+
# Sample critical paths at 100%
|
|
852
|
+
if "/checkout" in sampling_context.get("wsgi_environ", {}).get("PATH_INFO", ""):
|
|
853
|
+
return 1.0
|
|
854
|
+
|
|
855
|
+
# Sample health checks at 10%
|
|
856
|
+
if "/health" in sampling_context.get("wsgi_environ", {}).get("PATH_INFO", ""):
|
|
857
|
+
return 0.1
|
|
858
|
+
|
|
859
|
+
# Default to 25%
|
|
860
|
+
return 0.25
|
|
861
|
+
|
|
862
|
+
sentry_sdk.init(
|
|
863
|
+
dsn="https://examplePublicKey@o0.ingest.sentry.io/0",
|
|
864
|
+
traces_sampler=traces_sampler,
|
|
865
|
+
)
|
|
866
|
+
```
|
|
867
|
+
|
|
868
|
+
### Profile Sampling
|
|
869
|
+
|
|
870
|
+
```python
|
|
871
|
+
sentry_sdk.init(
|
|
872
|
+
dsn="https://examplePublicKey@o0.ingest.sentry.io/0",
|
|
873
|
+
|
|
874
|
+
# Profile 10% of transactions
|
|
875
|
+
profiles_sample_rate=0.1,
|
|
876
|
+
)
|
|
877
|
+
```
|
|
878
|
+
|
|
879
|
+
## Releases and Deploys
|
|
880
|
+
|
|
881
|
+
### Set Release
|
|
882
|
+
|
|
883
|
+
```python
|
|
884
|
+
sentry_sdk.init(
|
|
885
|
+
dsn="https://examplePublicKey@o0.ingest.sentry.io/0",
|
|
886
|
+
release="my-project@1.2.3",
|
|
887
|
+
environment="production",
|
|
888
|
+
)
|
|
889
|
+
```
|
|
890
|
+
|
|
891
|
+
### Automatic Release Detection
|
|
892
|
+
|
|
893
|
+
```python
|
|
894
|
+
import sentry_sdk
|
|
895
|
+
|
|
896
|
+
# Sentry can auto-detect from environment variables:
|
|
897
|
+
# SENTRY_RELEASE
|
|
898
|
+
# HEROKU_SLUG_COMMIT
|
|
899
|
+
# SOURCE_VERSION
|
|
900
|
+
|
|
901
|
+
sentry_sdk.init(
|
|
902
|
+
dsn="https://examplePublicKey@o0.ingest.sentry.io/0",
|
|
903
|
+
)
|
|
904
|
+
```
|
|
905
|
+
|
|
906
|
+
## Testing Sentry Setup
|
|
907
|
+
|
|
908
|
+
### Test Error
|
|
909
|
+
|
|
910
|
+
```python
|
|
911
|
+
import sentry_sdk
|
|
912
|
+
|
|
913
|
+
# Must be run from a file, not Python shell
|
|
914
|
+
def test_sentry():
|
|
915
|
+
sentry_sdk.init(
|
|
916
|
+
dsn="https://examplePublicKey@o0.ingest.sentry.io/0",
|
|
917
|
+
)
|
|
918
|
+
|
|
919
|
+
raise Exception("Sentry Test Error - This is intentional!")
|
|
920
|
+
|
|
921
|
+
if __name__ == "__main__":
|
|
922
|
+
test_sentry()
|
|
923
|
+
```
|
|
924
|
+
|
|
925
|
+
### Test Message
|
|
926
|
+
|
|
927
|
+
```python
|
|
928
|
+
import sentry_sdk
|
|
929
|
+
|
|
930
|
+
sentry_sdk.init(
|
|
931
|
+
dsn="https://examplePublicKey@o0.ingest.sentry.io/0",
|
|
932
|
+
)
|
|
933
|
+
|
|
934
|
+
sentry_sdk.capture_message("Sentry is configured correctly!", "info")
|
|
935
|
+
```
|
|
936
|
+
|
|
937
|
+
### Test Transaction
|
|
938
|
+
|
|
939
|
+
```python
|
|
940
|
+
import sentry_sdk
|
|
941
|
+
|
|
942
|
+
sentry_sdk.init(
|
|
943
|
+
dsn="https://examplePublicKey@o0.ingest.sentry.io/0",
|
|
944
|
+
traces_sample_rate=1.0,
|
|
945
|
+
)
|
|
946
|
+
|
|
947
|
+
with sentry_sdk.start_transaction(op="test", name="Test Transaction"):
|
|
948
|
+
print("Testing Sentry performance monitoring")
|
|
949
|
+
```
|
|
950
|
+
|
|
951
|
+
## Django Integration
|
|
952
|
+
|
|
953
|
+
### Settings Configuration
|
|
954
|
+
|
|
955
|
+
```python
|
|
956
|
+
import sentry_sdk
|
|
957
|
+
|
|
958
|
+
sentry_sdk.init(
|
|
959
|
+
dsn="https://examplePublicKey@o0.ingest.sentry.io/0",
|
|
960
|
+
|
|
961
|
+
# Performance Monitoring
|
|
962
|
+
traces_sample_rate=1.0,
|
|
963
|
+
|
|
964
|
+
# Send user PII
|
|
965
|
+
send_default_pii=True,
|
|
966
|
+
|
|
967
|
+
# Environment
|
|
968
|
+
environment="production",
|
|
969
|
+
)
|
|
970
|
+
```
|
|
971
|
+
|
|
972
|
+
### Capture User Info
|
|
973
|
+
|
|
974
|
+
Django integration automatically captures user information from `request.user`.
|
|
975
|
+
|
|
976
|
+
```python
|
|
977
|
+
# User info is automatically captured in Django views
|
|
978
|
+
from django.http import JsonResponse
|
|
979
|
+
|
|
980
|
+
def my_view(request):
|
|
981
|
+
# User from request.user is automatically sent to Sentry
|
|
982
|
+
if request.user.is_authenticated:
|
|
983
|
+
# Sentry will capture user.id, user.email, user.username
|
|
984
|
+
pass
|
|
985
|
+
|
|
986
|
+
return JsonResponse({"status": "ok"})
|
|
987
|
+
```
|
|
988
|
+
|
|
989
|
+
### Custom Transaction Names
|
|
990
|
+
|
|
991
|
+
```python
|
|
992
|
+
from django.http import JsonResponse
|
|
993
|
+
import sentry_sdk
|
|
994
|
+
|
|
995
|
+
def my_view(request):
|
|
996
|
+
with sentry_sdk.start_transaction(op="http.server", name="Custom View Name"):
|
|
997
|
+
# View logic
|
|
998
|
+
return JsonResponse({"status": "ok"})
|
|
999
|
+
```
|
|
1000
|
+
|
|
1001
|
+
## Flask Integration
|
|
1002
|
+
|
|
1003
|
+
### Basic Setup
|
|
1004
|
+
|
|
1005
|
+
```python
|
|
1006
|
+
from flask import Flask
|
|
1007
|
+
import sentry_sdk
|
|
1008
|
+
|
|
1009
|
+
sentry_sdk.init(
|
|
1010
|
+
dsn="https://examplePublicKey@o0.ingest.sentry.io/0",
|
|
1011
|
+
traces_sample_rate=1.0,
|
|
1012
|
+
send_default_pii=True,
|
|
1013
|
+
)
|
|
1014
|
+
|
|
1015
|
+
app = Flask(__name__)
|
|
1016
|
+
|
|
1017
|
+
@app.route("/")
|
|
1018
|
+
def index():
|
|
1019
|
+
return "Hello World!"
|
|
1020
|
+
|
|
1021
|
+
@app.route("/error")
|
|
1022
|
+
def error():
|
|
1023
|
+
raise Exception("Test error")
|
|
1024
|
+
|
|
1025
|
+
if __name__ == "__main__":
|
|
1026
|
+
app.run()
|
|
1027
|
+
```
|
|
1028
|
+
|
|
1029
|
+
### Capture User Info
|
|
1030
|
+
|
|
1031
|
+
```python
|
|
1032
|
+
from flask import Flask, request
|
|
1033
|
+
import sentry_sdk
|
|
1034
|
+
|
|
1035
|
+
app = Flask(__name__)
|
|
1036
|
+
|
|
1037
|
+
@app.before_request
|
|
1038
|
+
def set_user_info():
|
|
1039
|
+
user = get_current_user() # Your user retrieval logic
|
|
1040
|
+
if user:
|
|
1041
|
+
sentry_sdk.set_user({
|
|
1042
|
+
"id": user.id,
|
|
1043
|
+
"email": user.email,
|
|
1044
|
+
"username": user.username,
|
|
1045
|
+
})
|
|
1046
|
+
```
|
|
1047
|
+
|
|
1048
|
+
## FastAPI Integration
|
|
1049
|
+
|
|
1050
|
+
### Basic Setup
|
|
1051
|
+
|
|
1052
|
+
```python
|
|
1053
|
+
from fastapi import FastAPI, Request
|
|
1054
|
+
import sentry_sdk
|
|
1055
|
+
|
|
1056
|
+
sentry_sdk.init(
|
|
1057
|
+
dsn="https://examplePublicKey@o0.ingest.sentry.io/0",
|
|
1058
|
+
traces_sample_rate=1.0,
|
|
1059
|
+
send_default_pii=True,
|
|
1060
|
+
)
|
|
1061
|
+
|
|
1062
|
+
app = FastAPI()
|
|
1063
|
+
|
|
1064
|
+
@app.get("/")
|
|
1065
|
+
async def root():
|
|
1066
|
+
return {"message": "Hello World"}
|
|
1067
|
+
|
|
1068
|
+
@app.get("/error")
|
|
1069
|
+
async def error():
|
|
1070
|
+
raise Exception("Test error")
|
|
1071
|
+
```
|
|
1072
|
+
|
|
1073
|
+
### Capture User Info
|
|
1074
|
+
|
|
1075
|
+
```python
|
|
1076
|
+
from fastapi import FastAPI, Request, Depends
|
|
1077
|
+
import sentry_sdk
|
|
1078
|
+
|
|
1079
|
+
app = FastAPI()
|
|
1080
|
+
|
|
1081
|
+
def get_current_user(request: Request):
|
|
1082
|
+
# Your user retrieval logic
|
|
1083
|
+
return {"id": "12345", "email": "user@example.com"}
|
|
1084
|
+
|
|
1085
|
+
@app.middleware("http")
|
|
1086
|
+
async def add_user_to_sentry(request: Request, call_next):
|
|
1087
|
+
user = get_current_user(request)
|
|
1088
|
+
sentry_sdk.set_user(user)
|
|
1089
|
+
response = await call_next(request)
|
|
1090
|
+
return response
|
|
1091
|
+
```
|
|
1092
|
+
|
|
1093
|
+
## Celery Integration
|
|
1094
|
+
|
|
1095
|
+
### Basic Setup
|
|
1096
|
+
|
|
1097
|
+
```python
|
|
1098
|
+
from celery import Celery
|
|
1099
|
+
import sentry_sdk
|
|
1100
|
+
|
|
1101
|
+
sentry_sdk.init(
|
|
1102
|
+
dsn="https://examplePublicKey@o0.ingest.sentry.io/0",
|
|
1103
|
+
traces_sample_rate=1.0,
|
|
1104
|
+
)
|
|
1105
|
+
|
|
1106
|
+
app = Celery("tasks", broker="redis://localhost:6379")
|
|
1107
|
+
|
|
1108
|
+
@app.task
|
|
1109
|
+
def process_data(data):
|
|
1110
|
+
# Task logic
|
|
1111
|
+
return result
|
|
1112
|
+
```
|
|
1113
|
+
|
|
1114
|
+
### Task Error Handling
|
|
1115
|
+
|
|
1116
|
+
```python
|
|
1117
|
+
from celery import Celery
|
|
1118
|
+
import sentry_sdk
|
|
1119
|
+
|
|
1120
|
+
app = Celery("tasks", broker="redis://localhost:6379")
|
|
1121
|
+
|
|
1122
|
+
@app.task(bind=True)
|
|
1123
|
+
def process_data(self, data):
|
|
1124
|
+
try:
|
|
1125
|
+
# Task logic
|
|
1126
|
+
result = risky_operation(data)
|
|
1127
|
+
return result
|
|
1128
|
+
except Exception as e:
|
|
1129
|
+
sentry_sdk.capture_exception(e)
|
|
1130
|
+
raise self.retry(exc=e, countdown=60)
|
|
1131
|
+
```
|
|
1132
|
+
|
|
1133
|
+
## Logging Integration
|
|
1134
|
+
|
|
1135
|
+
### Basic Logging Setup
|
|
1136
|
+
|
|
1137
|
+
```python
|
|
1138
|
+
import logging
|
|
1139
|
+
import sentry_sdk
|
|
1140
|
+
|
|
1141
|
+
sentry_sdk.init(
|
|
1142
|
+
dsn="https://examplePublicKey@o0.ingest.sentry.io/0",
|
|
1143
|
+
enable_logs=True,
|
|
1144
|
+
)
|
|
1145
|
+
|
|
1146
|
+
# Configure logging
|
|
1147
|
+
logging.basicConfig(level=logging.INFO)
|
|
1148
|
+
|
|
1149
|
+
# Logs will automatically be sent to Sentry
|
|
1150
|
+
logging.error("This is an error log")
|
|
1151
|
+
logging.warning("This is a warning log")
|
|
1152
|
+
logging.info("This is an info log")
|
|
1153
|
+
```
|
|
1154
|
+
|
|
1155
|
+
### Custom Log Handler
|
|
1156
|
+
|
|
1157
|
+
```python
|
|
1158
|
+
import logging
|
|
1159
|
+
import sentry_sdk
|
|
1160
|
+
from sentry_sdk.integrations.logging import LoggingIntegration
|
|
1161
|
+
|
|
1162
|
+
# Configure Sentry with logging
|
|
1163
|
+
sentry_logging = LoggingIntegration(
|
|
1164
|
+
level=logging.INFO, # Capture info and above as breadcrumbs
|
|
1165
|
+
event_level=logging.ERROR # Send errors as events
|
|
1166
|
+
)
|
|
1167
|
+
|
|
1168
|
+
sentry_sdk.init(
|
|
1169
|
+
dsn="https://examplePublicKey@o0.ingest.sentry.io/0",
|
|
1170
|
+
integrations=[sentry_logging],
|
|
1171
|
+
)
|
|
1172
|
+
|
|
1173
|
+
logger = logging.getLogger(__name__)
|
|
1174
|
+
logger.error("This will be sent to Sentry as an event")
|
|
1175
|
+
logger.info("This will be captured as a breadcrumb")
|
|
1176
|
+
```
|
|
1177
|
+
|
|
1178
|
+
## Advanced Configuration
|
|
1179
|
+
|
|
1180
|
+
### Custom Client Options
|
|
1181
|
+
|
|
1182
|
+
```python
|
|
1183
|
+
import sentry_sdk
|
|
1184
|
+
|
|
1185
|
+
sentry_sdk.init(
|
|
1186
|
+
dsn="https://examplePublicKey@o0.ingest.sentry.io/0",
|
|
1187
|
+
|
|
1188
|
+
# Maximum breadcrumbs
|
|
1189
|
+
max_breadcrumbs=50, # Default is 100
|
|
1190
|
+
|
|
1191
|
+
# Attach stack traces to messages
|
|
1192
|
+
attach_stacktrace=True,
|
|
1193
|
+
|
|
1194
|
+
# Server name
|
|
1195
|
+
server_name="server-001",
|
|
1196
|
+
|
|
1197
|
+
# Debug mode
|
|
1198
|
+
debug=True,
|
|
1199
|
+
|
|
1200
|
+
# Transport options
|
|
1201
|
+
transport=sentry_sdk.transports.HttpTransport,
|
|
1202
|
+
|
|
1203
|
+
# Shutdown timeout
|
|
1204
|
+
shutdown_timeout=2,
|
|
1205
|
+
)
|
|
1206
|
+
```
|
|
1207
|
+
|
|
1208
|
+
### Multiple Sentry Instances
|
|
1209
|
+
|
|
1210
|
+
```python
|
|
1211
|
+
import sentry_sdk
|
|
1212
|
+
|
|
1213
|
+
# Create client for primary app
|
|
1214
|
+
primary_client = sentry_sdk.Client(
|
|
1215
|
+
dsn="https://primary@sentry.io/0",
|
|
1216
|
+
)
|
|
1217
|
+
|
|
1218
|
+
# Create client for background jobs
|
|
1219
|
+
jobs_client = sentry_sdk.Client(
|
|
1220
|
+
dsn="https://jobs@sentry.io/1",
|
|
1221
|
+
)
|
|
1222
|
+
|
|
1223
|
+
# Use specific client
|
|
1224
|
+
with sentry_sdk.Hub(primary_client):
|
|
1225
|
+
sentry_sdk.capture_exception(Exception("Primary app error"))
|
|
1226
|
+
|
|
1227
|
+
with sentry_sdk.Hub(jobs_client):
|
|
1228
|
+
sentry_sdk.capture_exception(Exception("Background job error"))
|
|
1229
|
+
```
|
|
1230
|
+
|
|
1231
|
+
### Custom Integrations
|
|
1232
|
+
|
|
1233
|
+
```python
|
|
1234
|
+
import sentry_sdk
|
|
1235
|
+
from sentry_sdk.integrations.logging import LoggingIntegration
|
|
1236
|
+
from sentry_sdk.integrations.redis import RedisIntegration
|
|
1237
|
+
from sentry_sdk.integrations.sqlalchemy import SqlalchemyIntegration
|
|
1238
|
+
|
|
1239
|
+
sentry_sdk.init(
|
|
1240
|
+
dsn="https://examplePublicKey@o0.ingest.sentry.io/0",
|
|
1241
|
+
integrations=[
|
|
1242
|
+
LoggingIntegration(
|
|
1243
|
+
level=logging.INFO,
|
|
1244
|
+
event_level=logging.ERROR
|
|
1245
|
+
),
|
|
1246
|
+
RedisIntegration(),
|
|
1247
|
+
SqlalchemyIntegration(),
|
|
1248
|
+
],
|
|
1249
|
+
)
|
|
1250
|
+
```
|
|
1251
|
+
|
|
1252
|
+
### Disable Default Integrations
|
|
1253
|
+
|
|
1254
|
+
```python
|
|
1255
|
+
import sentry_sdk
|
|
1256
|
+
|
|
1257
|
+
sentry_sdk.init(
|
|
1258
|
+
dsn="https://examplePublicKey@o0.ingest.sentry.io/0",
|
|
1259
|
+
default_integrations=False, # Disable all default integrations
|
|
1260
|
+
)
|
|
1261
|
+
```
|
|
1262
|
+
|
|
1263
|
+
### Flush and Shutdown
|
|
1264
|
+
|
|
1265
|
+
```python
|
|
1266
|
+
import sentry_sdk
|
|
1267
|
+
|
|
1268
|
+
# Flush events (wait up to 2 seconds)
|
|
1269
|
+
sentry_sdk.flush(timeout=2)
|
|
1270
|
+
|
|
1271
|
+
# Close and flush (wait up to 2 seconds)
|
|
1272
|
+
sentry_sdk.close(timeout=2)
|
|
1273
|
+
```
|
|
1274
|
+
|
|
1275
|
+
## Context Managers
|
|
1276
|
+
|
|
1277
|
+
### Hub Context
|
|
1278
|
+
|
|
1279
|
+
```python
|
|
1280
|
+
import sentry_sdk
|
|
1281
|
+
|
|
1282
|
+
with sentry_sdk.Hub(sentry_sdk.Hub.current):
|
|
1283
|
+
# Operations in isolated hub
|
|
1284
|
+
sentry_sdk.capture_message("Isolated message")
|
|
1285
|
+
```
|
|
1286
|
+
|
|
1287
|
+
### Configure Scope Context
|
|
1288
|
+
|
|
1289
|
+
```python
|
|
1290
|
+
import sentry_sdk
|
|
1291
|
+
|
|
1292
|
+
with sentry_sdk.configure_scope() as scope:
|
|
1293
|
+
scope.set_tag("section", "api")
|
|
1294
|
+
scope.set_user({"id": "12345"})
|
|
1295
|
+
# All events in this block will have these tags
|
|
1296
|
+
```
|
|
1297
|
+
|
|
1298
|
+
### Push Scope Context
|
|
1299
|
+
|
|
1300
|
+
```python
|
|
1301
|
+
import sentry_sdk
|
|
1302
|
+
|
|
1303
|
+
with sentry_sdk.push_scope() as scope:
|
|
1304
|
+
scope.set_tag("temporary", "yes")
|
|
1305
|
+
sentry_sdk.capture_exception(Exception("Scoped error"))
|
|
1306
|
+
|
|
1307
|
+
# Tag is not present in subsequent errors
|
|
1308
|
+
sentry_sdk.capture_exception(Exception("Unscoped error"))
|
|
1309
|
+
```
|