0
# Logging Integration
1
2
Raven provides native Python logging integration, automatically capturing log records as Sentry events with configurable filtering, formatting, and context inclusion.
3
4
## Capabilities
5
6
### Sentry Logging Handler
7
8
Python logging handler that sends log records to Sentry as events.
9
10
```python { .api }
11
from raven.handlers.logging import SentryHandler
12
13
class SentryHandler(logging.Handler):
14
def __init__(self, client=None, dsn=None, level=logging.NOTSET,
15
client_cls=None, tags=None, extra=None, **kwargs):
16
"""
17
Logging handler for Sentry integration.
18
19
Parameters:
20
- client (Client): Existing Sentry client instance
21
- dsn (str): Sentry DSN for new client creation
22
- level (int): Minimum logging level
23
- client_cls (type): Custom client class
24
- tags (dict): Default tags for all log events
25
- extra (dict): Default extra data for all log events
26
"""
27
28
def emit(self, record):
29
"""
30
Process log record and send to Sentry.
31
32
Parameters:
33
- record (LogRecord): Python logging record
34
"""
35
36
def can_record(self, record):
37
"""
38
Determine if record should be processed.
39
40
Parameters:
41
- record (LogRecord): Python logging record
42
43
Returns:
44
bool: True if record should be sent to Sentry
45
"""
46
```
47
48
### Logbook Integration
49
50
Integration with the Logbook logging library.
51
52
```python { .api }
53
from raven.handlers.logbook import SentryHandler as LogbookSentryHandler
54
55
class SentryHandler(logbook.Handler):
56
def __init__(self, client=None, dsn=None, level=logbook.NOTSET, **kwargs):
57
"""
58
Logbook handler for Sentry integration.
59
60
Parameters:
61
- client (Client): Existing Sentry client instance
62
- dsn (str): Sentry DSN for new client creation
63
- level (int): Minimum logging level
64
"""
65
66
def emit(self, record):
67
"""Process Logbook record and send to Sentry."""
68
```
69
70
### Logging Configuration
71
72
Utility function for configuring logging to pipe to Sentry.
73
74
```python { .api }
75
from raven.conf import setup_logging, EXCLUDE_LOGGER_DEFAULTS
76
77
def setup_logging(handler, exclude=EXCLUDE_LOGGER_DEFAULTS):
78
"""
79
Configure logging to pipe to Sentry.
80
81
Parameters:
82
- handler (Handler): Sentry logging handler instance
83
- exclude (tuple): Logger names to exclude from Sentry
84
85
Returns:
86
bool: True if logging was successfully configured
87
"""
88
89
# Default excluded loggers
90
EXCLUDE_LOGGER_DEFAULTS = (
91
'raven',
92
'gunicorn',
93
'south',
94
'sentry.errors',
95
'django.request',
96
'dill',
97
)
98
```
99
100
## Usage Examples
101
102
### Basic Logging Setup
103
104
```python
105
import logging
106
from raven import Client
107
from raven.handlers.logging import SentryHandler
108
from raven.conf import setup_logging
109
110
# Create client and handler
111
client = Client('https://your-dsn@sentry.io/project-id')
112
handler = SentryHandler(client)
113
handler.setLevel(logging.ERROR)
114
115
# Setup logging
116
setup_logging(handler)
117
118
# Use logging normally
119
logger = logging.getLogger(__name__)
120
121
logger.info('This will not be sent to Sentry')
122
logger.error('This error will be sent to Sentry')
123
logger.exception('This exception will be sent with stack trace')
124
```
125
126
### Advanced Handler Configuration
127
128
```python
129
import logging
130
from raven.handlers.logging import SentryHandler
131
132
# Handler with custom tags and extra data
133
handler = SentryHandler(
134
dsn='https://your-dsn@sentry.io/project-id',
135
level=logging.WARNING,
136
tags={'component': 'auth', 'environment': 'prod'},
137
extra={'server': 'web-01', 'version': '1.2.3'}
138
)
139
140
# Add to specific logger
141
logger = logging.getLogger('myapp.auth')
142
logger.addHandler(handler)
143
logger.setLevel(logging.WARNING)
144
145
# Log with additional context
146
logger.warning('Login attempt failed', extra={
147
'user_id': 123,
148
'ip_address': '192.168.1.1',
149
'user_agent': 'Mozilla/5.0...'
150
})
151
```
152
153
### Custom Handler with Filtering
154
155
```python
156
import logging
157
from raven.handlers.logging import SentryHandler
158
159
class FilteredSentryHandler(SentryHandler):
160
def can_record(self, record):
161
# Skip sensitive operations
162
if hasattr(record, 'funcName') and 'password' in record.funcName:
163
return False
164
165
# Only send errors from specific modules
166
if record.levelno >= logging.ERROR:
167
return record.name.startswith('myapp.')
168
169
return super().can_record(record)
170
171
handler = FilteredSentryHandler('https://your-dsn@sentry.io/project-id')
172
```
173
174
### Structured Logging Configuration
175
176
```python
177
import logging.config
178
179
LOGGING_CONFIG = {
180
'version': 1,
181
'disable_existing_loggers': False,
182
'formatters': {
183
'verbose': {
184
'format': '{levelname} {asctime} {module} {process:d} {thread:d} {message}',
185
'style': '{',
186
},
187
},
188
'handlers': {
189
'console': {
190
'class': 'logging.StreamHandler',
191
'formatter': 'verbose',
192
},
193
'sentry': {
194
'class': 'raven.handlers.logging.SentryHandler',
195
'dsn': 'https://your-dsn@sentry.io/project-id',
196
'level': 'ERROR',
197
'tags': {'environment': 'production'},
198
},
199
},
200
'loggers': {
201
'myapp': {
202
'handlers': ['console', 'sentry'],
203
'level': 'INFO',
204
'propagate': False,
205
},
206
'django': {
207
'handlers': ['console'],
208
'level': 'INFO',
209
'propagate': False,
210
},
211
},
212
'root': {
213
'handlers': ['console', 'sentry'],
214
'level': 'WARNING',
215
},
216
}
217
218
logging.config.dictConfig(LOGGING_CONFIG)
219
```
220
221
### Logbook Integration
222
223
```python
224
import logbook
225
from raven.handlers.logbook import SentryHandler
226
227
# Setup Logbook with Sentry
228
handler = SentryHandler('https://your-dsn@sentry.io/project-id')
229
230
with handler:
231
logger = logbook.Logger(__name__)
232
233
logger.info('This is just info')
234
logger.error('This error goes to Sentry')
235
236
try:
237
1/0
238
except ZeroDivisionError:
239
logger.exception('Division by zero error')
240
```
241
242
### Context-Aware Logging
243
244
```python
245
import logging
246
from raven import Client
247
from raven.handlers.logging import SentryHandler
248
249
client = Client('https://your-dsn@sentry.io/project-id')
250
handler = SentryHandler(client)
251
252
logger = logging.getLogger(__name__)
253
logger.addHandler(handler)
254
logger.setLevel(logging.ERROR)
255
256
def process_user_request(user_id, request_data):
257
# Set context for all events in this request
258
client.user_context({'id': user_id})
259
client.tags_context({'operation': 'user_request'})
260
261
try:
262
result = complex_operation(request_data)
263
logger.info('Request processed successfully')
264
return result
265
except Exception as e:
266
# This will include the user context
267
logger.exception('Request processing failed')
268
raise
269
```
270
271
### Performance Considerations
272
273
```python
274
import logging
275
from raven.handlers.logging import SentryHandler
276
277
class ThrottledSentryHandler(SentryHandler):
278
def __init__(self, *args, **kwargs):
279
super().__init__(*args, **kwargs)
280
self._error_counts = {}
281
self._max_errors_per_minute = 10
282
283
def can_record(self, record):
284
if not super().can_record(record):
285
return False
286
287
# Throttling logic to prevent spam
288
import time
289
now = time.time()
290
minute = int(now // 60)
291
292
key = f"{record.name}:{record.levelno}"
293
if key not in self._error_counts:
294
self._error_counts[key] = {}
295
296
current_count = self._error_counts[key].get(minute, 0)
297
if current_count >= self._max_errors_per_minute:
298
return False
299
300
self._error_counts[key][minute] = current_count + 1
301
302
# Clean old entries
303
for k in list(self._error_counts.keys()):
304
self._error_counts[k] = {
305
m: c for m, c in self._error_counts[k].items()
306
if m >= minute - 5
307
}
308
309
return True
310
```