日志系统设计

2026-06-22 · 6 阅读 · 326字
Node.js微服务监控

日志系统设计

日志的重要性

日志是系统可观测性的三大支柱之一(日志、指标、链路追踪)。良好的日志系统可以帮助我们:

  • 故障排查:快速定位问题根因
  • 行为审计:记录用户操作和系统变更
  • 监控告警:基于日志内容触发告警
  • 数据分析:从日志中挖掘业务洞察

日志级别

const (
    DEBUG   = 0 // 调试信息,开发环境使用
    INFO    = 1 // 常规信息,系统正常运行
    WARN    = 2 // 警告,可能存在问题
    ERROR   = 3 // 错误,需要关注
    FATAL   = 4 // 致命错误,系统不可用
)

级别使用规范

级别 使用场景 示例
DEBUG 开发调试 SQL 语句、函数入参
INFO 业务记录 用户注册、订单创建
WARN 异常但不影响 重试操作、配置缺失
ERROR 功能不可用 DB 连接失败、请求超时
FATAL 进程无法继续 端口被占用、配置错误

结构化日志

结构化日志使用键值对格式(如 JSON),便于机器解析和搜索:

// 不推荐:非结构化
log.Printf("User %s logged in from IP %s", userID, ip)

// 推荐:结构化
logger.Info("user_login",
    log.String("user_id", userID),
    log.String("ip", ip),
    log.String("user_agent", ua),
    log.Duration("duration", dur),
)

输出示例:

{
    "level": "info",
    "time": "2024-01-15T10:30:00Z",
    "message": "user_login",
    "user_id": "u12345",
    "ip": "192.168.1.1",
    "duration_ms": 42
}

日志收集架构

传统 ELK 方案

应用 → Filebeat → Logstash → Elasticsearch → Kibana

轻量级 Loki 方案

应用 → Promtail → Loki → Grafana

推荐架构

应用 → 标准输出 → 容器 stdout → 日志采集 Agent → 消息队列 → 存储 → 查询

采集 Agent:Filebeat / Fluentd / Promtail
消息队列:Kafka(可选,用于流量缓冲)
存储:Elasticsearch / Loki / ClickHouse
查询:Kibana / Grafana

日志实践规范

必须包含的字段

{
    "timestamp": "2024-01-15T10:30:00.123Z",
    "level": "ERROR",
    "service": "user-service",
    "trace_id": "abc123def456",
    "message": "database connection failed",
    "error": {
        "type": "connection_refused",
        "message": "dial tcp 127.0.0.1:5432: connect: connection refused"
    },
    "metadata": {
        "host": "pod-123",
        "environment": "production",
        "version": "1.2.3"
    }
}

注意事项

DO

  • 包含 trace_id 支持链路关联
  • 记录请求耗时用于性能分析
  • 日志及时刷新(设置 buffer 或即时刷新)
  • 敏感信息脱敏(密码、Token、身份证号)
// 脱敏示例
func maskEmail(email string) string {
    parts := strings.Split(email, "@")
    if len(parts) != 2 {
        return email
    }
    return parts[0][:1] + "***@" + parts[1]
}

DON'T

  • 不要在循环中输出日志
  • 不要记录用户的密码和密钥
  • 不要使用 string 拼接构造日志消息
  • 不要将日志级别设置为 DEBUG 上生产

日志轮转

// Go 中使用 lumberjack 实现日志轮转
logger := &lumberjack.Logger{
    Filename:   "/var/log/app/app.log",
    MaxSize:    100,  // MB
    MaxAge:     30,   // 天
    MaxBackups: 10,
    Compress:   true,
}