日志是故障排查的黄金线索。一个成熟的日志体系能够让你在几分钟内定位问题,而不是花几小时翻找文件。从本地日志到集中式日志平台,这是DevOps的必经之路。
Level 0: 直接看文件 → tail -f /var/log/app.log Level 1: 日志轮转 → logrotate 自动切割压缩 Level 2: 集中收集 → Filebeat/Fluentd → Elasticsearch Level 3: 结构化日志 → JSON格式 + 链路ID Level 4: 可观测性平台 → 指标+日志+链路三位一体
传统文本日志难以搜索和分析,结构化日志(JSON格式)是现代应用的标准:
{
"timestamp": "2026-05-19T10:30:00.123Z",
"level": "ERROR",
"service": "order-service",
"trace_id": "abc123def456",
"span_id": "span789",
"user_id": "U10086",
"method": "POST",
"path": "/api/orders",
"status": 500,
"duration_ms": 2345,
"error": "database connection timeout",
"stack_trace": "at OrderService.create() ..."
}
# systemd日志
journalctl -u nginx -f # 实时跟踪nginx日志
journalctl -u nginx --since today # 今天的日志
journalctl -u nginx -n 100 # 最近100行
journalctl -p err # 只看error级别
journalctl --since "2026-05-19 10:00" --until "2026-05-19 11:00"
# 传统日志
tail -f /var/log/nginx/access.log # 实时跟踪
less +F /var/log/syslog # less的follow模式
head -100 /var/log/auth.log # 查看开头
# 搜索与过滤
grep -E "ERROR|FATAL" /var/log/app.log
grep "10.0.1.100" /var/log/nginx/access.log
awk '$9 >= 500' access.log # HTTP 5xx错误
journalctl -u docker --grep "OOM" # 搜索关键词
# 应用日志轮转配置
cat > /etc/logrotate.d/myapp << 'EOF'
/var/log/myapp/*.log {
daily
missingok
rotate 30
compress
delaycompress
notifempty
create 0644 appuser appgroup
sharedscripts
postrotate
systemctl reload myapp >/dev/null 2>&1 || true
endscript
}
EOF
# 手动测试轮转
logrotate -d /etc/logrotate.d/myapp # 调试模式
logrotate -f /etc/logrotate.d/myapp # 强制执行
# Nginx日志轮转
cat /etc/logrotate.d/nginx
# /var/log/nginx/*.log {
# daily
# rotate 14
# compress
# create 0640 www-data adm
# postrotate
# [ -f /var/run/nginx.pid ] && kill -USR1 $(cat /var/run/nginx.pid)
# endscript
# }
# 安装Fluentd(td-agent)
curl -L https://toolbelt.treasuredata.com/sh/install-ubuntu-jammy-td-agent4.sh | sh
# 配置Fluentd
cat > /etc/td-agent/td-agent.conf << 'EOF'
@type tail
path /var/log/nginx/access.log
pos_file /var/log/td-agent/nginx-access.pos
tag nginx.access
@type nginx
@type tail
path /var/log/app/*.log
pos_file /var/log/td-agent/app.pos
tag app.log
@type json
@type elasticsearch
host elasticsearch.internal
port 9200
logstash_format true
logstash_prefix fluentd
@type file
path /var/log/td-agent/buffer
flush_interval 10s
EOF
sudo systemctl restart td-agent
数据源 采集层 存储层 展示层 ┌──────┐ ┌─────────┐ ┌─────────┐ ┌─────────┐ │ Nginx│──文件────▶│ │ │ │ │ │ └──────┘ │ Fluentd │──bulk──▶│ Elastic │───▶│ Kibana │ ┌──────┐ │ /File │ ▶ │ search │ │ Dashboard│ │ App │──stdout──▶│ beat │ │ Engine │ └─────────┘ └──────┘ │ │ │ │ ┌──────┐ │ 解析 │ │ 索引 │ ┌─────────┐ │MySQL │──慢查询──▶│ 过滤 │ │ 生命周期│ │ Alert │ └──────┘ │ 标签 │ │ 管理 │───▶│ →钉钉 │ ┌──────┐ └─────────┘ └─────────┘ └─────────┘ │Syslog│──rsyslog──▶ └──────┘
# 紧急处理:清空日志但不删除文件
> /var/log/nginx/access.log # 保留文件,清空内容
# 或 truncate
truncate -s 0 /var/log/app.log
# 根本解决:配置logrotate
# 参见上方logrotate配置
# 检查日志增长速度
lsof | grep deleted | sort -k7 -rn | head
# 找到被删但未释放的大日志文件
| 级别 | 含义 | 生产环境 | 示例 |
|---|---|---|---|
| TRACE | 最详细的调试信息 | ❌ 关闭 | 函数入参出参 |
| DEBUG | 调试信息 | ❌ 关闭(排查时临时开启) | SQL查询、缓存命中 |
| INFO | 关键业务事件 | ✅ 开启 | 请求开始/结束、订单创建 |
| WARN | 潜在问题 | ✅ 开启 | 重试、降级、接近阈值 |
| ERROR | 错误但系统可继续 | ✅ 开启+告警 | 异常捕获、外部调用失败 |
| FATAL | 致命错误,系统停止 | ✅ 开启+紧急告警 | 数据库连接耗尽、OOM |
微服务架构下,一个请求可能经过多个服务。链路追踪通过trace_id串联所有日志,让你能追踪完整的请求路径:
# 请求流程:Gateway → User Service → Order Service → Payment
trace_id: abc-123-def
[Gateway] INFO trace=abc-123 "GET /api/orders" started
[User Service] INFO trace=abc-123 span=get-user "Fetching user U10086"
[Order Service] INFO trace=abc-123 span=create-order "Creating order"
[Payment] ERROR trace=abc-123 span=charge "Payment gateway timeout"
[Gateway] WARN trace=abc-123 "GET /api/orders" completed with 202
# 通过trace_id一键搜索所有相关日志!
# Docker Compose部署ELK
cat > /opt/elk/docker-compose.yml << 'EOF'
version: "3.8"
services:
elasticsearch:
image: elasticsearch:8.12.0
environment:
- discovery.type=single-node
- xpack.security.enabled=false
- "ES_JAVA_OPTS=-Xms1g -Xmx1g"
volumes:
- es_data:/usr/share/elasticsearch/data
ports:
- "9200:9200"
kibana:
image: kibana:8.12.0
environment:
- ELASTICSEARCH_HOSTS=http://elasticsearch:9200
ports:
- "5601:5601"
depends_on:
- elasticsearch
volumes:
es_data:
EOF
docker compose up -d
# Nginx日志实时分析
# Top 10 访问IP
awk '{print $1}' /var/log/nginx/access.log | sort | uniq -c | sort -rn | head
# 统计HTTP状态码分布
awk '{print $9}' /var/log/nginx/access.log | sort | uniq -c | sort -rn
# 用jq分析JSON日志
cat app.log | jq 'select(.level=="ERROR") | {timestamp, service, error}'
cat app.log | jq -s 'group_by(.service) | map({service: .[0].service, count: length}) | sort_by(-.count)'
# 查看集群健康状态
curl -s localhost:9200/_cluster/health?pretty
# 查看未分配分片
curl -s localhost:9200/_cat/shards?v | grep UNASSIGNED
# 常见原因与解决:
# 1. 磁盘满 → 清理或增加磁盘
# 2. 节点数不够 → 增加节点
# 3. 分片数超限 → 调整cluster.max_shards_per_node
掌握日志轮转、结构化日志、ELK/EFK日志平台——日志是故障排查的黄金线索。