or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

application-wrappers.mdasync-integration.mdconfiguration.mdevents.mdindex.mdlogging.mdmiddleware.mdserver-execution.mdtypes.mdutilities.md

logging.mddocs/

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

```