Files
new-api/LOGGING.md

261 lines
6.9 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 日志系统说明
本项目使用 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`: 错误信息
## ⚙️ 配置方式
### 环境变量配置
```bash
# 日志目录(必需,否则只输出到控制台)
--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
```
### 命令行参数
```bash
# 启动时指定日志目录
./new-api --log-dir=./logs
# 如果不指定日志目录,日志只输出到控制台
./new-api
```
## 📝 使用示例
### 基础使用
```go
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 格式**:
```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. 生产环境配置
```bash
# 使用 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. 开发环境配置
```bash
# 使用 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. 容器环境配置
```bash
# 只输出到标准输出,由容器运行时管理日志
./new-api
# 或者使用 JSON 格式便于日志收集系统处理
export LOG_FORMAT=json
./new-api
```
## 🔍 日志分析
### 使用 grep 分析文本日志
```bash
# 查找错误日志
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 日志
```bash
# 提取所有错误日志
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
## 📖 相关文档
- [Go slog 官方文档](https://pkg.go.dev/log/slog)
- [结构化日志最佳实践](https://go.dev/blog/slog)