Files
new-api/LOGGING.md

6.9 KiB
Raw Blame History

日志系统说明

本项目使用 Go 标准库的 log/slog 实现结构化日志记录。

📋 功能特性

1. 标准的文件存储结构

  • 当前日志文件: oneapi.log - 实时写入的日志文件
  • 归档日志文件: oneapi.2024-01-02-153045.log - 自动轮转后的历史日志

2. 自动日志轮转

日志文件会在以下情况自动轮转:

  • 按大小轮转: 当日志文件超过指定大小时(默认 100MB
  • 启动时日期检查: 程序启动时如果检测到日志文件是旧日期创建的,会自动轮转
  • 自动清理: 只保留最近 N 个日志文件(默认 7 个)

3. 结构化日志

所有日志都包含以下结构化字段:

time=2024-01-02T15:30:45 level=INFO msg="user logged in" request_id=abc123 user_id=1001

4. 多种输出格式

  • Text 格式 (默认): 人类可读的文本格式
  • JSON 格式: 便于日志分析工具解析

5. 灵活的日志级别

支持四个日志级别:

  • DEBUG: 调试信息
  • INFO: 一般信息
  • WARN: 警告信息
  • ERROR: 错误信息

⚙️ 配置方式

环境变量配置

# 日志目录(必需,否则只输出到控制台)
--log-dir=./logs

# 日志级别(可选,默认: INFODEBUG 模式除外)
export LOG_LEVEL=DEBUG        # 可选值: DEBUG, INFO, WARN, ERROR

# 日志格式(可选,默认: text
export LOG_FORMAT=json        # 可选值: text, json

# 单个日志文件最大大小(可选,默认: 100单位: MB
export LOG_MAX_SIZE_MB=200

# 保留的日志文件数量(可选,默认: 7
export LOG_MAX_FILES=14

# 启用调试模式(会自动将日志级别设为 DEBUG
export DEBUG=true

命令行参数

# 启动时指定日志目录
./new-api --log-dir=./logs

# 如果不指定日志目录,日志只输出到控制台
./new-api

📝 使用示例

基础使用

import (
    "context"
    "github.com/QuantumNous/new-api/logger"
)

// 记录信息日志
logger.LogInfo(ctx, "user registered successfully")

// 记录警告日志
logger.LogWarn(ctx, "API rate limit approaching")

// 记录错误日志
logger.LogError(ctx, "failed to connect to database")

// 记录调试日志(只在 DEBUG 模式下输出)
logger.LogDebug(ctx, "processing request with params: %v", params)

// 记录系统日志(无 context
logger.LogSystemInfo("application started")
logger.LogSystemError("critical system error")

日志输出示例

Text 格式 (易读格式):

[INFO] 2024/01/02 - 15:30:45 | SYSTEM | application started
[INFO] 2024/01/02 - 15:30:46 | abc123 | user registered successfully
[WARN] 2024/01/02 - 15:30:47 | def456 | API rate limit approaching | remaining=10, limit=100
[ERROR] 2024/01/02 - 15:30:48 | ghi789 | failed to connect to database | error="connection timeout"

格式说明:[级别] 时间 | 请求ID/组件 | 消息 | 额外属性(如有)

JSON 格式:

{"time":"2024-01-02 15:30:45","level":"INFO","msg":"application started","request_id":"SYSTEM"}
{"time":"2024-01-02 15:30:46","level":"INFO","msg":"user registered successfully","request_id":"abc123"}
{"time":"2024-01-02 15:30:47","level":"WARN","msg":"API rate limit approaching","request_id":"def456"}

📂 日志文件结构

logs/
├── oneapi.log                      # 当前活动日志文件
├── oneapi.2024-01-01-090000.log  # 昨天的日志
├── oneapi.2024-01-01-150000.log  # 昨天下午的日志(如果超过大小限制)
├── oneapi.2023-12-31-090000.log  # 更早的日志
└── ...                            # 最多保留配置数量的历史文件

🔄 日志轮转机制

轮转触发条件

  1. 文件大小检查: 每写入 1000 条日志后检查一次文件大小
  2. 启动时日期检查: 程序启动时检查日志文件的修改日期,如果不是今天则轮转
  3. 自动清理: 轮转时自动删除超过保留数量的旧日志文件

注意: 日志不会在运行时动态检查日期变化。如果需要每天自动轮转日志,建议:

  • 使用定时任务(如 cron每天重启服务
  • 或者配置较小的日志文件大小,让它自动按大小轮转

轮转流程

  1. 检测到需要轮转时,关闭当前日志文件
  2. oneapi.log 重命名为 oneapi.YYYY-MM-DD-HHmmss.log
  3. 创建新的 oneapi.log 文件
  4. 异步清理超过数量限制的旧日志文件
  5. 记录轮转事件到新日志文件

🎯 最佳实践

1. 生产环境配置

# 使用 INFO 级别,避免过多调试信息
export LOG_LEVEL=INFO

# 使用 JSON 格式,便于日志分析工具处理
export LOG_FORMAT=json

# 设置合适的文件大小和保留数量
export LOG_MAX_SIZE_MB=500
export LOG_MAX_FILES=30

# 指定日志目录
./new-api --log-dir=/var/log/oneapi

2. 开发环境配置

# 使用 DEBUG 级别查看详细信息
export DEBUG=true

# 使用 Text 格式,便于阅读
export LOG_FORMAT=text

# 较小的文件大小和保留数量
export LOG_MAX_SIZE_MB=50
export LOG_MAX_FILES=7

./new-api --log-dir=./logs

3. 容器环境配置

# 只输出到标准输出,由容器运行时管理日志
./new-api

# 或者使用 JSON 格式便于日志收集系统处理
export LOG_FORMAT=json
./new-api

🔍 日志分析

使用 grep 分析文本日志

# 查找错误日志
grep '\[ERROR\]' logs/oneapi.log

# 查找特定请求的所有日志
grep 'abc123' logs/*.log

# 查看最近的警告和错误
tail -f logs/oneapi.log | grep -E '\[(WARN|ERROR)\]'

# 查找包含特定关键词的日志
grep 'database' logs/oneapi.log

# 查看今天的所有错误
grep "\[ERROR\] $(date +%Y/%m/%d)" logs/oneapi.log

使用 jq 分析 JSON 日志

# 提取所有错误日志
cat logs/oneapi.log | jq 'select(.level=="ERROR")'

# 统计各级别日志数量
cat logs/oneapi.log | jq -r '.level' | sort | uniq -c

# 查找特定时间范围的日志
cat logs/oneapi.log | jq 'select(.time >= "2024-01-02 15:00:00" and .time <= "2024-01-02 16:00:00")'

📊 性能优化

  1. 异步日志轮转: 轮转操作在后台 goroutine 中执行,不阻塞主程序
  2. 批量写入检查: 每 1000 次写入才检查一次轮转条件,减少 I/O 开销
  3. 读写锁: 使用 sync.RWMutex 保护日志器,提高并发性能
  4. 零分配: slog 库在大多数情况下实现零内存分配

🚨 故障排查

日志文件未创建

  • 检查日志目录是否存在且有写入权限
  • 确认启动时指定了 --log-dir 参数

日志文件过多

  • 调整 LOG_MAX_FILES 环境变量
  • 手动清理不需要的旧日志文件

日志级别不正确

  • 检查 LOG_LEVEL 环境变量是否正确设置
  • 确认 DEBUG 环境变量的值(会覆盖 LOG_LEVEL

📖 相关文档