0
# Logging
1
2
Comprehensive logging framework with access log formatting, structured logging, and StatsD metrics integration for monitoring and observability. Hypercorn provides flexible logging capabilities suitable for both development and production environments.
3
4
## Capabilities
5
6
### Logger Class
7
8
Main logging class that provides async logging methods and access log functionality with configurable formatting and output destinations.
9
10
```python { .api }
11
class Logger:
12
"""
13
Main logging class for Hypercorn.
14
15
Provides async logging methods for different log levels and
16
specialized access logging with configurable formatting.
17
Supports multiple output destinations and structured logging.
18
"""
19
20
def __init__(self, config: Config):
21
"""
22
Initialize logger with configuration.
23
24
Args:
25
config: Config object containing logging settings
26
including log files, levels, and formatting
27
"""
28
29
@property
30
def handlers(self) -> list:
31
"""
32
List of active log handlers.
33
34
Returns:
35
List of logging handlers (file, stream, etc.)
36
"""
37
38
async def critical(self, message: str, *args, **kwargs):
39
"""
40
Log critical error message.
41
42
Args:
43
message: Log message string (supports % formatting)
44
*args: Positional arguments for message formatting
45
**kwargs: Keyword arguments for message formatting
46
47
Critical messages indicate severe errors that may cause
48
the server to terminate or become unusable.
49
"""
50
51
async def error(self, message: str, *args, **kwargs):
52
"""
53
Log error message.
54
55
Args:
56
message: Log message string (supports % formatting)
57
*args: Positional arguments for message formatting
58
**kwargs: Keyword arguments for message formatting
59
60
Error messages indicate problems that don't prevent
61
continued operation but need attention.
62
"""
63
64
async def warning(self, message: str, *args, **kwargs):
65
"""
66
Log warning message.
67
68
Args:
69
message: Log message string (supports % formatting)
70
*args: Positional arguments for message formatting
71
**kwargs: Keyword arguments for message formatting
72
73
Warning messages indicate potential issues or
74
unexpected conditions that don't prevent operation.
75
"""
76
77
async def info(self, message: str, *args, **kwargs):
78
"""
79
Log informational message.
80
81
Args:
82
message: Log message string (supports % formatting)
83
*args: Positional arguments for message formatting
84
**kwargs: Keyword arguments for message formatting
85
86
Info messages provide general operational information
87
about server status and request processing.
88
"""
89
90
async def debug(self, message: str, *args, **kwargs):
91
"""
92
Log debug message.
93
94
Args:
95
message: Log message string (supports % formatting)
96
*args: Positional arguments for message formatting
97
**kwargs: Keyword arguments for message formatting
98
99
Debug messages provide detailed information for
100
troubleshooting and development purposes.
101
"""
102
103
async def exception(self, message: str, *args, **kwargs):
104
"""
105
Log exception with traceback.
106
107
Args:
108
message: Log message string (supports % formatting)
109
*args: Positional arguments for message formatting
110
**kwargs: Keyword arguments for message formatting
111
112
Exception messages include full stack traces and are
113
typically called from exception handlers.
114
"""
115
116
async def log(self, level: int, message: str, *args, **kwargs):
117
"""
118
Log message at specified level.
119
120
Args:
121
level: Logging level (from logging module constants)
122
message: Log message string (supports % formatting)
123
*args: Positional arguments for message formatting
124
**kwargs: Keyword arguments for message formatting
125
126
Generic logging method that can log at any level.
127
"""
128
129
async def access(self, request, response, request_time: float):
130
"""
131
Log access entry for HTTP request.
132
133
Args:
134
request: Request object containing request information
135
response: Response object containing response information
136
request_time: Time taken to process request in seconds
137
138
Creates formatted access log entries using the configured
139
access log format string and available log atoms.
140
"""
141
142
def atoms(self, request, response, request_time: float) -> dict[str, str]:
143
"""
144
Get access log atoms for formatting.
145
146
Args:
147
request: Request object containing request information
148
response: Response object containing response information
149
request_time: Time taken to process request in seconds
150
151
Returns:
152
Dictionary of format atoms for access log formatting
153
"""
154
```
155
156
### Access Log Atoms
157
158
Dictionary-like class that provides access log formatting variables for creating custom access log formats.
159
160
```python { .api }
161
class AccessLogAtoms:
162
"""
163
Dictionary-like class for access log formatting.
164
165
Provides access to various request and response attributes
166
for use in access log format strings. Similar to Apache's
167
log format variables.
168
"""
169
170
def __init__(self, request, response, request_time: float):
171
"""
172
Initialize access log atoms.
173
174
Args:
175
request: HTTP request object
176
response: HTTP response object
177
request_time: Request processing time in seconds
178
"""
179
180
# Available atoms (accessed via dictionary interface):
181
# h - Remote hostname/IP address
182
# l - Remote logname (always '-')
183
# u - Remote user (from authentication)
184
# t - Time of request in common log format
185
# r - First line of request ("GET /path HTTP/1.1")
186
# s - Response status code
187
# b - Response body size in bytes
188
# f - Referer header
189
# a - User agent header
190
# T - Request processing time in seconds
191
# D - Request processing time in microseconds
192
# L - Request processing time in decimal seconds
193
# p - Server port
194
# P - Process ID
195
# {header}i - Request header value
196
# {header}o - Response header value
197
# {variable}e - Environment variable value
198
```
199
200
### StatsD Logger
201
202
Extended logger class that integrates with StatsD metrics systems for monitoring and observability, providing both logging and metrics collection.
203
204
```python { .api }
205
class StatsdLogger(Logger):
206
"""
207
Logger with StatsD metrics integration.
208
209
Extends the base Logger class with StatsD metrics capabilities,
210
enabling both traditional logging and metrics collection for
211
monitoring, alerting, and performance analysis.
212
"""
213
214
def __init__(self, config: Config, statsd_host: str = "localhost", statsd_port: int = 8125):
215
"""
216
Initialize StatsD logger.
217
218
Args:
219
config: Config object with logging settings
220
statsd_host: StatsD server hostname
221
statsd_port: StatsD server port
222
"""
223
224
def increment(self, name: str, value: int = 1, tags: dict | None = None):
225
"""
226
Increment a counter metric.
227
228
Args:
229
name: Metric name (e.g., "requests.total")
230
value: Increment value (default: 1)
231
tags: Optional tags/labels dictionary
232
233
Increments a counter metric by the specified value.
234
Used for counting events like requests, errors, etc.
235
"""
236
237
def decrement(self, name: str, value: int = 1, tags: dict | None = None):
238
"""
239
Decrement a counter metric.
240
241
Args:
242
name: Metric name (e.g., "connections.active")
243
value: Decrement value (default: 1)
244
tags: Optional tags/labels dictionary
245
246
Decrements a counter metric by the specified value.
247
"""
248
249
def histogram(self, name: str, value: float, tags: dict | None = None):
250
"""
251
Record a histogram/timing metric.
252
253
Args:
254
name: Metric name (e.g., "request.duration")
255
value: Metric value (typically timing in seconds)
256
tags: Optional tags/labels dictionary
257
258
Records a timing or distribution metric value.
259
Used for request durations, response sizes, etc.
260
"""
261
262
def gauge(self, name: str, value: float, tags: dict | None = None):
263
"""
264
Set a gauge metric value.
265
266
Args:
267
name: Metric name (e.g., "memory.usage")
268
value: Current metric value
269
tags: Optional tags/labels dictionary
270
271
Sets a gauge metric to the specified value.
272
Used for current state metrics like memory usage,
273
active connections, queue sizes, etc.
274
"""
275
```
276
277
## Usage Examples
278
279
### Basic Logger Usage
280
281
```python
282
from hypercorn.config import Config
283
from hypercorn.logging import Logger
284
285
# Create logger with configuration
286
config = Config()
287
config.errorlog = "/var/log/hypercorn-error.log"
288
config.accesslog = "/var/log/hypercorn-access.log"
289
config.access_log_format = '%(h)s "%(r)s" %(s)s %(b)s "%(f)s" "%(a)s"'
290
291
logger = Logger(config)
292
293
# Use async logging methods
294
async def handle_request():
295
await logger.info("Processing request")
296
297
try:
298
# Process request
299
result = await process_request()
300
await logger.debug("Request processed successfully")
301
return result
302
except Exception as e:
303
await logger.error("Request processing failed: %s", str(e))
304
await logger.exception("Full exception details")
305
raise
306
```
307
308
### Access Logging
309
310
```python
311
# Access logging is typically handled automatically by Hypercorn
312
# but can be used manually:
313
314
async def log_request_completion(request, response, start_time):
315
request_time = time.time() - start_time
316
await logger.access(request, response, request_time)
317
318
# Custom access log format in config
319
config.access_log_format = (
320
'%(h)s - %(u)s [%(t)s] "%(r)s" %(s)s %(b)s '
321
'"%(f)s" "%(a)s" %(T)s'
322
)
323
```
324
325
### StatsD Integration
326
327
```python
328
from hypercorn.logging import StatsdLogger
329
330
# Create StatsD logger
331
config = Config()
332
statsd_logger = StatsdLogger(
333
config,
334
statsd_host="metrics.example.com",
335
statsd_port=8125
336
)
337
338
# Use metrics alongside logging
339
async def handle_request():
340
# Increment request counter
341
statsd_logger.increment("requests.total", tags={"method": "GET"})
342
343
start_time = time.time()
344
try:
345
# Process request
346
result = await process_request()
347
348
# Record success metrics
349
statsd_logger.increment("requests.success")
350
statsd_logger.histogram("request.duration", time.time() - start_time)
351
352
await statsd_logger.info("Request completed successfully")
353
return result
354
355
except Exception as e:
356
# Record error metrics
357
statsd_logger.increment("requests.error", tags={"error_type": type(e).__name__})
358
await statsd_logger.error("Request failed: %s", str(e))
359
raise
360
```
361
362
### Custom Access Log Format
363
364
```python
365
# Configure custom access log format
366
config = Config()
367
368
# Apache Common Log Format
369
config.access_log_format = '%(h)s - %(u)s [%(t)s] "%(r)s" %(s)s %(b)s'
370
371
# Apache Combined Log Format
372
config.access_log_format = (
373
'%(h)s - %(u)s [%(t)s] "%(r)s" %(s)s %(b)s '
374
'"%(f)s" "%(a)s"'
375
)
376
377
# Custom format with timing
378
config.access_log_format = (
379
'%(h)s "%(r)s" %(s)s %(b)s %(T)s '
380
'pid=%(P)s port=%(p)s'
381
)
382
383
# JSON format for structured logging
384
config.access_log_format = (
385
'{"remote_addr": "%(h)s", "request": "%(r)s", '
386
'"status": %(s)s, "bytes": %(b)s, "duration": %(T)s}'
387
)
388
```
389
390
### Production Logging Setup
391
392
```python
393
from hypercorn.config import Config
394
from hypercorn.logging import StatsdLogger
395
396
# Production logging configuration
397
config = Config()
398
399
# Log files with rotation (handled by external tools)
400
config.errorlog = "/var/log/hypercorn/error.log"
401
config.accesslog = "/var/log/hypercorn/access.log"
402
403
# Structured access logs
404
config.access_log_format = (
405
'{"timestamp": "%(t)s", "client_ip": "%(h)s", '
406
'"method": "%(m)s", "path": "%(U)s", "status": %(s)s, '
407
'"bytes": %(b)s, "duration": %(T)s, "user_agent": "%(a)s"}'
408
)
409
410
# Create StatsD logger for metrics
411
logger = StatsdLogger(config, statsd_host="metrics.internal")
412
413
# Set up log levels
414
import logging
415
logging.getLogger("hypercorn.error").setLevel(logging.INFO)
416
logging.getLogger("hypercorn.access").setLevel(logging.INFO)
417
```
418
419
### Development Logging
420
421
```python
422
# Development configuration with debug output
423
config = Config()
424
config.debug = True
425
426
# Log to stdout/stderr for development
427
config.errorlog = "-" # stderr
428
config.accesslog = "-" # stdout
429
430
# Simple access log format
431
config.access_log_format = '%(h)s "%(r)s" %(s)s %(T)s'
432
433
logger = Logger(config)
434
435
# Enable debug logging
436
import logging
437
logging.getLogger("hypercorn").setLevel(logging.DEBUG)
438
```