89 lines
3.3 KiB
Markdown
89 lines
3.3 KiB
Markdown
---
|
|
id: ops/logging
|
|
name: Implement structured logging with tracing, file output, and fail2ban-compatible format
|
|
status: complete
|
|
depends_on: [setup/project-init]
|
|
scope: moderate
|
|
risk: low
|
|
impact: component
|
|
level: implementation
|
|
---
|
|
|
|
## Description
|
|
|
|
Implement structured logging using `tracing` and `tracing-subscriber` with dual output (file + stdout) and fail2ban-compatible log format.
|
|
|
|
### Log Types
|
|
|
|
1. **Access logs** (every proxied request, `info` level):
|
|
```
|
|
REQUEST client_ip=203.0.113.50 host=git.alk.dev method=GET path=/user/repo status=200 upstream=127.0.0.1:3000 duration_ms=45
|
|
```
|
|
|
|
2. **Event logs** (rate limits, TLS errors, upstream failures, config reloads):
|
|
```
|
|
RATE_LIMIT client_ip=203.0.113.50 host=git.alk.dev path=/login status=429
|
|
UPSTREAM_ERROR host=git.alk.dev upstream=127.0.0.1:3000 error="connection refused"
|
|
CONFIG_RELOAD status=success sites=1
|
|
```
|
|
|
|
### Dual Output
|
|
|
|
- **File** (primary): Written to `log_file_path` when configured. This is the authoritative source for fail2ban.
|
|
- **stdout/stderr** (always-on): For `docker logs`, `journalctl`, and development.
|
|
|
|
Use `tracing-subscriber` `Layer` composition to write to both simultaneously.
|
|
|
|
### Log Levels
|
|
|
|
| Level | Use |
|
|
|-------|-----|
|
|
| `error` | Unrecoverable failures (TLS handshake failure, config validation) |
|
|
| `warn` | Rate limit exceeded, upstream unreachable, upstream timeout |
|
|
| `info` | Access logs, config reloads, ACME events, startup/shutdown |
|
|
| `debug` | Request/response headers, connection details |
|
|
| `trace` | Detailed protocol-level information |
|
|
|
|
Configurable via `log_level` in StaticConfig.
|
|
|
|
### Configuration
|
|
|
|
- `logging.level`: Log verbosity (default: `"info"`)
|
|
- `logging.format`: `"text"` or `"json"` (default: `"text"`)
|
|
- `logging.log_file_path`: Optional file path; when set, logs are written to this file in addition to stdout
|
|
|
|
### File Logging and fail2ban
|
|
|
|
File logging is the primary integration point for fail2ban. In container deployments, the log directory is volume-mounted so fail2ban on the host can read it directly.
|
|
|
|
A corresponding fail2ban filter definition and jail configuration will be provided in the deployment task.
|
|
|
|
## Acceptance Criteria
|
|
|
|
- [ ] `tracing` and `tracing-subscriber` initialized with dual output (file + stdout)
|
|
- [ ] File output enabled when `log_file_path` is configured
|
|
- [ ] Stdout output always enabled
|
|
- [ ] Custom event format with `key=value` pairs
|
|
- [ ] `REQUEST` prefix for access logs
|
|
- [ ] `RATE_LIMIT` prefix for rate limit events
|
|
- [ ] `UPSTREAM_ERROR` prefix for upstream failures
|
|
- [ ] `CONFIG_RELOAD` prefix for config reload events
|
|
- [ ] Log level configurable via `logging.level`
|
|
- [ ] JSON format output when `logging.format = "json"`
|
|
- [ ] Text format output when `logging.format = "text"` (default)
|
|
- [ ] `duration_ms` field in access logs for response time
|
|
- [ ] Unit tests for log format output
|
|
|
|
## References
|
|
|
|
- docs/architecture/operations.md — logging section, log format
|
|
- docs/architecture/decisions/007-custom-log-format.md — custom log format rationale
|
|
- docs/architecture/decisions/020-container-deployment.md — file-primary logging rationale
|
|
|
|
## Notes
|
|
|
|
> The fail2ban filter and jail configuration are a separate deployment task. This task focuses on producing the correct log format.
|
|
|
|
## Summary
|
|
|
|
> To be filled on completion |