日志管理 #
概述 #
日志是运维和故障排查的重要工具,Caddy 提供了灵活的日志配置,支持多种输出方式和格式。
text
┌─────────────────────────────────────────────────────────────┐
│ Caddy 日志架构 │
├─────────────────────────────────────────────────────────────┤
│ │
│ 请求 → Caddy → 日志处理器 │
│ ↓ │
│ ┌─────────────┐ │
│ │ 格式化器 │ │
│ └──────┬──────┘ │
│ ↓ │
│ ┌─────────────┐ │
│ │ 输出器 │ │
│ └──────┬──────┘ │
│ ↓ │
│ ┌─────────┬─────────┬─────────┬─────────┐ │
│ │ 文件 │ 控制台 │ Syslog │ 网络 │ │
│ └─────────┴─────────┴─────────┴─────────┘ │
│ │
└─────────────────────────────────────────────────────────────┘
基本配置 #
最简单的日志配置 #
caddyfile
example.com {
log
respond "Hello"
}
文件日志 #
caddyfile
example.com {
log {
output file /var/log/caddy/access.log
}
respond "Hello"
}
完整日志配置 #
caddyfile
example.com {
log {
output file /var/log/caddy/access.log {
roll_size 100mb
roll_keep 10
roll_keep_for 168h
}
format json
}
respond "Hello"
}
日志输出 #
文件输出 #
caddyfile
example.com {
log {
output file /var/log/caddy/access.log
}
}
文件轮转配置 #
caddyfile
example.com {
log {
output file /var/log/caddy/access.log {
# 单个文件最大大小
roll_size 100mb
# 保留文件数量
roll_keep 10
# 保留时间
roll_keep_for 168h # 7 天
# 文件名格式
roll_name_format "access-2006-01-02T15-04-05.000.log"
}
}
}
控制台输出 #
caddyfile
example.com {
log {
output stdout
}
}
标准错误输出 #
caddyfile
example.com {
log {
output stderr
}
}
禁用日志 #
caddyfile
example.com {
log off
}
多输出 #
caddyfile
example.com {
log {
output file /var/log/caddy/access.log
output stdout
}
}
日志格式 #
JSON 格式 #
caddyfile
example.com {
log {
format json
}
}
JSON 格式输出示例:
json
{
"level": "info",
"ts": 1704067200.123456,
"logger": "http.log.access",
"msg": "handled request",
"request": {
"remote_ip": "192.168.1.100",
"remote_port": "54321",
"proto": "HTTP/2.0",
"method": "GET",
"host": "example.com",
"uri": "/api/users",
"headers": {
"User-Agent": ["curl/7.68.0"],
"Accept": ["*/*"]
}
},
"duration": 0.001234,
"size": 1234,
"status": 200
}
控制台格式 #
caddyfile
example.com {
log {
format console
}
}
自定义格式 #
caddyfile
example.com {
log {
format console {
# 时间格式
time_format "2006-01-02 15:04:05"
# 时间戳格式
time_format "rfc3339"
}
}
}
自定义日志字段 #
caddyfile
example.com {
log {
format json {
# 添加自定义字段
time_format "rfc3339"
}
}
}
日志级别 #
全局日志级别 #
caddyfile
{
# 全局日志级别
log default {
level DEBUG
}
}
example.com {
respond "Hello"
}
日志级别说明 #
| 级别 | 说明 |
|---|---|
| DEBUG | 调试信息 |
| INFO | 一般信息 |
| WARN | 警告信息 |
| ERROR | 错误信息 |
| PANIC | 严重错误 |
| FATAL | 致命错误 |
站点日志级别 #
caddyfile
example.com {
log {
level DEBUG
}
}
日志字段 #
常用日志字段 #
caddyfile
example.com {
log {
format json
}
# 可用的日志字段:
# {request} - 完整请求信息
# {duration} - 请求处理时间
# {size} - 响应大小
# {status} - 响应状态码
# {remote_host} - 客户端 IP
# {host} - 请求主机
# {uri} - 请求 URI
# {method} - 请求方法
# {proto} - 协议版本
# {headers} - 请求头
}
自定义日志消息 #
caddyfile
example.com {
log {
output file /var/log/caddy/access.log
format json
}
# 在响应中记录日志
handle /api/* {
log msg "API request received"
reverse_proxy localhost:3000
}
}
条件日志 #
基于路径的日志 #
caddyfile
example.com {
# API 路径记录详细日志
handle /api/* {
log {
output file /var/log/caddy/api.log
format json
}
reverse_proxy localhost:3000
}
# 静态文件简单日志
handle {
log {
output file /var/log/caddy/static.log
format console
}
file_server
}
}
基于状态码的日志 #
caddyfile
example.com {
log {
output file /var/log/caddy/access.log
}
# 错误日志单独记录
handle_errors {
log {
output file /var/log/caddy/error.log
level ERROR
}
respond "{http.error.status_code} {http.error.status_text}"
}
}
排除健康检查 #
caddyfile
example.com {
# 排除健康检查日志
@health path /health
log @health off
log {
output file /var/log/caddy/access.log
}
respond "Hello"
}
全局日志配置 #
全局日志 #
caddyfile
{
log {
output file /var/log/caddy/global.log
format json
}
}
example.com {
respond "Hello"
}
多日志器 #
caddyfile
{
log main {
output file /var/log/caddy/main.log
}
log debug {
output file /var/log/caddy/debug.log
level DEBUG
}
}
example.com {
log main
respond "Hello"
}
日志分析 #
使用 jq 分析 JSON 日志 #
bash
# 统计状态码分布
cat /var/log/caddy/access.log | jq -r '.status' | sort | uniq -c | sort -rn
# 统计请求最多的路径
cat /var/log/caddy/access.log | jq -r '.request.uri' | sort | uniq -c | sort -rn | head -20
# 统计慢请求(>1s)
cat /var/log/caddy/access.log | jq 'select(.duration > 1)'
# 统计错误请求
cat /var/log/caddy/access.log | jq 'select(.status >= 400)'
# 统计 IP 访问量
cat /var/log/caddy/access.log | jq -r '.request.remote_ip' | sort | uniq -c | sort -rn | head -20
# 统计 User-Agent
cat /var/log/caddy/access.log | jq -r '.request.headers.User-Agent[0]' | sort | uniq -c | sort -rn | head -10
使用 grep 分析文本日志 #
bash
# 查找错误
grep -i error /var/log/caddy/access.log
# 查找特定 IP
grep "192.168.1.100" /var/log/caddy/access.log
# 查找特定路径
grep "/api/users" /var/log/caddy/access.log
# 统计状态码
grep -o '"status":[0-9]*' /var/log/caddy/access.log | cut -d: -f2 | sort | uniq -c
实时监控日志 #
bash
# 实时查看日志
tail -f /var/log/caddy/access.log
# 实时查看并过滤
tail -f /var/log/caddy/access.log | grep --line-buffered "error"
# 实时查看 JSON 日志
tail -f /var/log/caddy/access.log | jq
# 实时统计
tail -f /var/log/caddy/access.log | jq -r '.status' | awk '{count[$1]++} END {for (s in count) print s, count[s]}'
日志轮转 #
使用 logrotate #
bash
# /etc/logrotate.d/caddy
/var/log/caddy/*.log {
daily
rotate 14
compress
delaycompress
missingok
notifempty
create 0644 caddy caddy
postrotate
systemctl reload caddy
endscript
}
Caddy 内置轮转 #
caddyfile
example.com {
log {
output file /var/log/caddy/access.log {
roll_size 100mb
roll_keep 14
roll_keep_for 336h
}
}
}
完整示例 #
生产环境日志配置 #
caddyfile
{
log {
output file /var/log/caddy/caddy.log {
roll_size 50mb
roll_keep 10
}
format json
level INFO
}
}
example.com {
# 访问日志
log {
output file /var/log/caddy/access.log {
roll_size 100mb
roll_keep 30
roll_keep_for 720h
}
format json
}
# API 日志
handle /api/* {
log {
output file /var/log/caddy/api.log {
roll_size 50mb
roll_keep 14
}
format json
}
reverse_proxy localhost:3000
}
# 静态文件
handle {
root * /var/www/html
file_server
}
# 错误日志
handle_errors {
log {
output file /var/log/caddy/error.log
level ERROR
}
respond "{http.error.status_code} {http.error.status_text}"
}
}
多站点日志配置 #
caddyfile
# 共享日志配置
(logging) {
log {
output file /var/log/caddy/{host}.log {
roll_size 50mb
roll_keep 14
}
format json
}
}
site1.example.com {
import logging
root * /var/www/site1
file_server
}
site2.example.com {
import logging
reverse_proxy localhost:3000
}
api.example.com {
log {
output file /var/log/caddy/api.log {
roll_size 100mb
roll_keep 30
}
format json
}
reverse_proxy localhost:3001
}
开发环境日志配置 #
caddyfile
{
debug
}
localhost {
log {
output stdout
format console {
time_format "15:04:05"
}
level DEBUG
}
respond "Development server"
}
日志最佳实践 #
1. 使用 JSON 格式 #
caddyfile
log {
format json # 便于解析和分析
}
2. 合理设置轮转 #
caddyfile
output file /var/log/caddy/access.log {
roll_size 100mb
roll_keep 14
}
3. 分离不同类型的日志 #
caddyfile
# 访问日志
log {
output file /var/log/caddy/access.log
}
# 错误日志
handle_errors {
log {
output file /var/log/caddy/error.log
level ERROR
}
}
4. 排除不必要的日志 #
caddyfile
# 排除健康检查
@health path /health
log @health off
5. 设置合适的日志级别 #
caddyfile
# 生产环境
log {
level INFO
}
# 开发环境
log {
level DEBUG
}
下一步 #
现在你已经掌握了日志管理配置,接下来学习 URL 重写 了解如何处理 URL 路由!
最后更新:2026-03-28