add log
This commit is contained in:
69
.gitignore
vendored
69
.gitignore
vendored
@@ -1,66 +1,39 @@
|
|||||||
# Binaries for programs and plugins
|
# 日志文件
|
||||||
*.exe
|
logs/
|
||||||
*.exe~
|
*.log
|
||||||
*.dll
|
|
||||||
*.so
|
|
||||||
*.dylib
|
|
||||||
|
|
||||||
# Test binary, built with `go test -c`
|
# 编译输出
|
||||||
*.test
|
bin/
|
||||||
|
dist/
|
||||||
|
|
||||||
# Output of the go coverage tool, specifically when used with LiteIDE
|
# IDE文件
|
||||||
*.out
|
|
||||||
|
|
||||||
# Dependency directories (remove the comment below to include it)
|
|
||||||
vendor/
|
|
||||||
|
|
||||||
# Go workspace file
|
|
||||||
go.work
|
|
||||||
|
|
||||||
# IDE
|
|
||||||
.vscode/
|
.vscode/
|
||||||
.idea/
|
.idea/
|
||||||
*.swp
|
*.swp
|
||||||
*.swo
|
*.swo
|
||||||
*~
|
|
||||||
|
|
||||||
# OS
|
# 操作系统文件
|
||||||
.DS_Store
|
.DS_Store
|
||||||
.DS_Store?
|
|
||||||
._*
|
|
||||||
.Spotlight-V100
|
|
||||||
.Trashes
|
|
||||||
ehthumbs.db
|
|
||||||
Thumbs.db
|
Thumbs.db
|
||||||
|
|
||||||
# Local environment files
|
# 环境变量文件
|
||||||
.env
|
.env
|
||||||
.env.local
|
.env.local
|
||||||
.env.*.local
|
.env.production
|
||||||
|
|
||||||
# Log files
|
# 临时文件
|
||||||
*.log
|
|
||||||
logs/
|
|
||||||
|
|
||||||
# Database
|
|
||||||
*.db
|
|
||||||
*.sqlite
|
|
||||||
*.sqlite3
|
|
||||||
|
|
||||||
# Temporary files
|
|
||||||
tmp/
|
tmp/
|
||||||
temp/
|
temp/
|
||||||
|
|
||||||
# Build directories
|
# 依赖目录
|
||||||
build/
|
vendor/
|
||||||
dist/
|
|
||||||
|
|
||||||
# Temporary directories
|
# 测试覆盖率文件
|
||||||
tmp/
|
coverage.out
|
||||||
|
coverage.html
|
||||||
|
|
||||||
# Compiled binary
|
# 其他
|
||||||
main
|
*.exe
|
||||||
tyapi-server
|
*.dll
|
||||||
|
*.so
|
||||||
# Docker volumes
|
*.dylib
|
||||||
docker-data/
|
|
||||||
@@ -48,12 +48,13 @@ logger:
|
|||||||
level: "info"
|
level: "info"
|
||||||
format: "console"
|
format: "console"
|
||||||
output: "stdout"
|
output: "stdout"
|
||||||
file_path: "logs/app.log"
|
log_dir: "logs"
|
||||||
max_size: 100
|
max_size: 100
|
||||||
max_backups: 3
|
max_backups: 3
|
||||||
max_age: 7
|
max_age: 7
|
||||||
compress: true
|
compress: true
|
||||||
use_color: true
|
use_color: true
|
||||||
|
use_daily: false
|
||||||
|
|
||||||
jwt:
|
jwt:
|
||||||
secret: "default-jwt-secret-key-change-in-env-config"
|
secret: "default-jwt-secret-key-change-in-env-config"
|
||||||
|
|||||||
@@ -40,6 +40,13 @@ redis:
|
|||||||
logger:
|
logger:
|
||||||
level: warn
|
level: warn
|
||||||
format: json
|
format: json
|
||||||
|
output: "file"
|
||||||
|
log_dir: "/app/logs"
|
||||||
|
max_size: 100
|
||||||
|
max_backups: 5
|
||||||
|
max_age: 30
|
||||||
|
compress: true
|
||||||
|
use_daily: true
|
||||||
# ===========================================
|
# ===========================================
|
||||||
# 🔐 JWT配置
|
# 🔐 JWT配置
|
||||||
# ===========================================
|
# ===========================================
|
||||||
|
|||||||
@@ -122,7 +122,7 @@ services:
|
|||||||
ports:
|
ports:
|
||||||
- "25000:8080"
|
- "25000:8080"
|
||||||
volumes:
|
volumes:
|
||||||
- app_logs:/app/logs
|
- ./logs:/app/logs
|
||||||
networks:
|
networks:
|
||||||
- tyapi-network
|
- tyapi-network
|
||||||
depends_on:
|
depends_on:
|
||||||
@@ -163,8 +163,6 @@ volumes:
|
|||||||
driver: local
|
driver: local
|
||||||
redis_data:
|
redis_data:
|
||||||
driver: local
|
driver: local
|
||||||
app_logs:
|
|
||||||
driver: local
|
|
||||||
|
|
||||||
networks:
|
networks:
|
||||||
tyapi-network:
|
tyapi-network:
|
||||||
|
|||||||
298
docs/日志系统说明.md
Normal file
298
docs/日志系统说明.md
Normal file
@@ -0,0 +1,298 @@
|
|||||||
|
# 📝 日志系统说明
|
||||||
|
|
||||||
|
## 概述
|
||||||
|
|
||||||
|
本项目使用增强的日志系统,支持按日分包和按大小分包,使用 `lumberjack` 进行日志轮转管理。
|
||||||
|
|
||||||
|
## 功能特性
|
||||||
|
|
||||||
|
### ✅ 按日分包
|
||||||
|
- 日志按日期自动分包存储
|
||||||
|
- 目录结构:`logs/2024-01-01/app.log`
|
||||||
|
- 便于按日期查找和管理日志
|
||||||
|
|
||||||
|
### ✅ 按大小分包
|
||||||
|
- 单个日志文件最大大小限制(默认100MB)
|
||||||
|
- 超过大小限制时自动创建新文件
|
||||||
|
- 文件命名:`app.log`, `app.log.1`, `app.log.2` 等
|
||||||
|
|
||||||
|
### ✅ 自动轮转
|
||||||
|
- 支持压缩旧日志文件
|
||||||
|
- 自动删除超过保留期限的日志
|
||||||
|
- 限制备份文件数量
|
||||||
|
|
||||||
|
### ✅ 生产环境持久化
|
||||||
|
- 日志目录挂载到宿主机 `./logs`
|
||||||
|
- 容器重启后日志不丢失
|
||||||
|
- 便于日志收集和分析
|
||||||
|
|
||||||
|
## 配置说明
|
||||||
|
|
||||||
|
### 基础配置 (`config.yaml`)
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
logger:
|
||||||
|
level: "info" # 日志级别
|
||||||
|
format: "console" # 日志格式 (console/json)
|
||||||
|
output: "stdout" # 输出目标 (stdout/stderr/file)
|
||||||
|
log_dir: "logs" # 日志目录
|
||||||
|
max_size: 100 # 单个文件最大大小(MB)
|
||||||
|
max_backups: 3 # 最大备份文件数
|
||||||
|
max_age: 7 # 最大保留天数
|
||||||
|
compress: true # 是否压缩
|
||||||
|
use_color: true # 是否使用彩色输出
|
||||||
|
use_daily: false # 是否按日分包
|
||||||
|
```
|
||||||
|
|
||||||
|
### 生产环境配置 (`configs/env.production.yaml`)
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
logger:
|
||||||
|
level: warn # 生产环境只记录警告及以上级别
|
||||||
|
format: json # JSON格式便于日志分析
|
||||||
|
output: "file" # 输出到文件
|
||||||
|
log_dir: "/app/logs" # 容器内日志目录
|
||||||
|
max_size: 100 # 100MB
|
||||||
|
max_backups: 5 # 5个备份文件
|
||||||
|
max_age: 30 # 保留30天
|
||||||
|
compress: true # 启用压缩
|
||||||
|
use_daily: true # 启用按日分包
|
||||||
|
```
|
||||||
|
|
||||||
|
## 日志目录结构
|
||||||
|
|
||||||
|
### 按日分包模式
|
||||||
|
```
|
||||||
|
logs/
|
||||||
|
├── 2024-01-01/
|
||||||
|
│ ├── app.log # 当前日志文件
|
||||||
|
│ ├── app.log.1 # 第一个备份文件
|
||||||
|
│ ├── app.log.2 # 第二个备份文件
|
||||||
|
│ └── app.log.3.gz # 压缩的备份文件
|
||||||
|
├── 2024-01-02/
|
||||||
|
│ ├── app.log
|
||||||
|
│ └── app.log.1
|
||||||
|
└── 2024-01-03/
|
||||||
|
└── app.log
|
||||||
|
```
|
||||||
|
|
||||||
|
### 传统模式
|
||||||
|
```
|
||||||
|
logs/
|
||||||
|
├── app.log # 当前日志文件
|
||||||
|
├── app.log.1 # 第一个备份文件
|
||||||
|
├── app.log.2 # 第二个备份文件
|
||||||
|
└── app.log.3.gz # 压缩的备份文件
|
||||||
|
```
|
||||||
|
|
||||||
|
## 日志级别
|
||||||
|
|
||||||
|
| 级别 | 说明 | 使用场景 |
|
||||||
|
|------|------|----------|
|
||||||
|
| `debug` | 调试信息 | 开发环境详细调试 |
|
||||||
|
| `info` | 一般信息 | 业务流程关键节点 |
|
||||||
|
| `warn` | 警告信息 | 需要注意但不影响功能 |
|
||||||
|
| `error` | 错误信息 | 业务逻辑错误 |
|
||||||
|
| `fatal` | 致命错误 | 系统无法继续运行 |
|
||||||
|
| `panic` | 恐慌错误 | 程序崩溃 |
|
||||||
|
|
||||||
|
## 日志格式
|
||||||
|
|
||||||
|
### JSON格式(生产环境)
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"timestamp": "2024-01-01T12:00:00Z",
|
||||||
|
"level": "info",
|
||||||
|
"message": "用户注册成功",
|
||||||
|
"user_id": "12345",
|
||||||
|
"phone": "138****8888",
|
||||||
|
"request_id": "req-123456",
|
||||||
|
"caller": "user_handler.go:45"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 控制台格式(开发环境)
|
||||||
|
```
|
||||||
|
2024-01-01T12:00:00Z INFO 用户注册成功 {"user_id": "12345", "phone": "138****8888"}
|
||||||
|
```
|
||||||
|
|
||||||
|
## 使用方法
|
||||||
|
|
||||||
|
### 1. 查看日志
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# 查看实时日志
|
||||||
|
docker logs -f tyapi-app-prod
|
||||||
|
|
||||||
|
# 查看最近的日志
|
||||||
|
docker logs --tail 100 tyapi-app-prod
|
||||||
|
|
||||||
|
# 查看宿主机日志文件
|
||||||
|
tail -f logs/2024-01-01/app.log
|
||||||
|
|
||||||
|
# 查看错误日志
|
||||||
|
grep "ERROR" logs/2024-01-01/app.log
|
||||||
|
```
|
||||||
|
|
||||||
|
### 2. 日志管理
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# 查看日志统计信息
|
||||||
|
./scripts/log-manager.sh stats
|
||||||
|
|
||||||
|
# 查看日志目录大小
|
||||||
|
./scripts/log-manager.sh size
|
||||||
|
|
||||||
|
# 列出所有日志文件
|
||||||
|
./scripts/log-manager.sh list
|
||||||
|
|
||||||
|
# 清理旧日志文件
|
||||||
|
./scripts/log-manager.sh clean
|
||||||
|
```
|
||||||
|
|
||||||
|
### 3. 日志分析
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# 使用jq分析JSON日志
|
||||||
|
cat logs/2024-01-01/app.log | jq 'select(.level == "error")'
|
||||||
|
|
||||||
|
# 统计错误类型
|
||||||
|
cat logs/2024-01-01/app.log | jq -r '.level' | sort | uniq -c
|
||||||
|
|
||||||
|
# 查看特定用户的请求
|
||||||
|
cat logs/2024-01-01/app.log | jq 'select(.user_id == "12345")'
|
||||||
|
```
|
||||||
|
|
||||||
|
## 代码示例
|
||||||
|
|
||||||
|
### 基本日志记录
|
||||||
|
```go
|
||||||
|
import "tyapi-server/internal/shared/logger"
|
||||||
|
|
||||||
|
// 获取日志器
|
||||||
|
log := logger.GetLogger()
|
||||||
|
|
||||||
|
// 记录不同级别的日志
|
||||||
|
log.Info("用户登录成功", logger.String("user_id", "12345"))
|
||||||
|
log.Warn("用户多次登录失败", logger.String("phone", "138****8888"))
|
||||||
|
log.Error("数据库连接失败", logger.Error(err))
|
||||||
|
```
|
||||||
|
|
||||||
|
### 带上下文的日志
|
||||||
|
```go
|
||||||
|
// 从Gin上下文获取日志器
|
||||||
|
ctx := c.Request.Context()
|
||||||
|
log := logger.GetLogger().WithContext(ctx)
|
||||||
|
|
||||||
|
log.Info("处理用户请求",
|
||||||
|
logger.String("action", "user_login"),
|
||||||
|
logger.String("ip", c.ClientIP()),
|
||||||
|
)
|
||||||
|
```
|
||||||
|
|
||||||
|
### 结构化日志字段
|
||||||
|
```go
|
||||||
|
log.Info("业务操作",
|
||||||
|
logger.String("operation", "create_user"),
|
||||||
|
logger.String("user_id", user.ID),
|
||||||
|
logger.Int("age", user.Age),
|
||||||
|
logger.Float64("score", 95.5),
|
||||||
|
logger.Bool("is_active", true),
|
||||||
|
logger.Error(err),
|
||||||
|
)
|
||||||
|
```
|
||||||
|
|
||||||
|
## 监控和告警
|
||||||
|
|
||||||
|
### 1. 日志监控
|
||||||
|
- 使用 ELK Stack (Elasticsearch + Logstash + Kibana)
|
||||||
|
- 或使用 Grafana + Loki
|
||||||
|
- 实时监控错误日志和性能指标
|
||||||
|
|
||||||
|
### 2. 告警配置
|
||||||
|
- 错误日志数量告警
|
||||||
|
- 日志文件大小告警
|
||||||
|
- 磁盘空间告警
|
||||||
|
|
||||||
|
### 3. 性能监控
|
||||||
|
```bash
|
||||||
|
# 监控日志写入性能
|
||||||
|
iostat -x 1
|
||||||
|
|
||||||
|
# 监控磁盘使用情况
|
||||||
|
df -h logs/
|
||||||
|
|
||||||
|
# 监控日志文件增长
|
||||||
|
watch -n 1 'ls -lh logs/$(date +%Y-%m-%d)/app.log'
|
||||||
|
```
|
||||||
|
|
||||||
|
## 故障排除
|
||||||
|
|
||||||
|
### 常见问题
|
||||||
|
|
||||||
|
1. **日志文件权限问题**
|
||||||
|
```bash
|
||||||
|
# 修复权限
|
||||||
|
chmod -R 755 logs/
|
||||||
|
chown -R $(whoami) logs/
|
||||||
|
```
|
||||||
|
|
||||||
|
2. **磁盘空间不足**
|
||||||
|
```bash
|
||||||
|
# 清理旧日志
|
||||||
|
./scripts/log-manager.sh clean
|
||||||
|
|
||||||
|
# 检查磁盘使用情况
|
||||||
|
df -h
|
||||||
|
```
|
||||||
|
|
||||||
|
3. **日志轮转失败**
|
||||||
|
```bash
|
||||||
|
# 检查lumberjack配置
|
||||||
|
# 确保有足够的磁盘空间
|
||||||
|
# 检查文件权限
|
||||||
|
```
|
||||||
|
|
||||||
|
### 性能优化
|
||||||
|
|
||||||
|
1. **异步日志写入**
|
||||||
|
- 使用缓冲写入减少I/O操作
|
||||||
|
- 批量写入提高性能
|
||||||
|
|
||||||
|
2. **日志级别控制**
|
||||||
|
- 生产环境使用 `warn` 级别
|
||||||
|
- 减少不必要的日志输出
|
||||||
|
|
||||||
|
3. **定期清理**
|
||||||
|
- 设置合理的保留期限
|
||||||
|
- 定期清理旧日志文件
|
||||||
|
|
||||||
|
## 最佳实践
|
||||||
|
|
||||||
|
### 1. 日志内容
|
||||||
|
- ✅ 记录关键业务操作
|
||||||
|
- ✅ 包含足够的上下文信息
|
||||||
|
- ✅ 使用结构化的字段
|
||||||
|
- ❌ 避免记录敏感信息
|
||||||
|
- ❌ 避免过度详细的调试信息
|
||||||
|
|
||||||
|
### 2. 日志管理
|
||||||
|
- ✅ 定期清理旧日志
|
||||||
|
- ✅ 监控日志文件大小
|
||||||
|
- ✅ 设置合理的轮转策略
|
||||||
|
- ✅ 备份重要日志
|
||||||
|
|
||||||
|
### 3. 性能考虑
|
||||||
|
- ✅ 使用异步日志写入
|
||||||
|
- ✅ 合理设置日志级别
|
||||||
|
- ✅ 避免在循环中记录日志
|
||||||
|
- ✅ 使用结构化日志字段
|
||||||
|
|
||||||
|
## 相关文件
|
||||||
|
|
||||||
|
- `internal/shared/logger/logger.go` - 日志系统核心实现
|
||||||
|
- `internal/config/config.go` - 日志配置结构
|
||||||
|
- `config.yaml` - 基础日志配置
|
||||||
|
- `configs/env.production.yaml` - 生产环境日志配置
|
||||||
|
- `docker-compose.prod.yml` - Docker日志卷挂载配置
|
||||||
|
- `scripts/log-manager.sh` - 日志管理脚本
|
||||||
1
go.mod
1
go.mod
@@ -29,6 +29,7 @@ require (
|
|||||||
go.uber.org/fx v1.24.0
|
go.uber.org/fx v1.24.0
|
||||||
go.uber.org/zap v1.27.0
|
go.uber.org/zap v1.27.0
|
||||||
golang.org/x/time v0.12.0
|
golang.org/x/time v0.12.0
|
||||||
|
gopkg.in/natefinch/lumberjack.v2 v2.2.1
|
||||||
gorm.io/driver/postgres v1.6.0
|
gorm.io/driver/postgres v1.6.0
|
||||||
gorm.io/gorm v1.30.0
|
gorm.io/gorm v1.30.0
|
||||||
)
|
)
|
||||||
|
|||||||
2
go.sum
2
go.sum
@@ -369,6 +369,8 @@ gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EV
|
|||||||
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
|
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
|
||||||
gopkg.in/ini.v1 v1.67.0 h1:Dgnx+6+nfE+IfzjUEISNeydPJh9AXNNsWbGP9KzCsOA=
|
gopkg.in/ini.v1 v1.67.0 h1:Dgnx+6+nfE+IfzjUEISNeydPJh9AXNNsWbGP9KzCsOA=
|
||||||
gopkg.in/ini.v1 v1.67.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
|
gopkg.in/ini.v1 v1.67.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
|
||||||
|
gopkg.in/natefinch/lumberjack.v2 v2.2.1 h1:bBRl1b0OH9s/DuPhuXpNl+VtCaJXFZ5/uEFST95x9zc=
|
||||||
|
gopkg.in/natefinch/lumberjack.v2 v2.2.1/go.mod h1:YD8tP3GAjkrDg1eZH7EGmyESg/lsYskCTPBJVb9jqSc=
|
||||||
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||||
gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||||
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
|
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
|
||||||
|
|||||||
@@ -83,12 +83,13 @@ type LoggerConfig struct {
|
|||||||
Level string `mapstructure:"level"`
|
Level string `mapstructure:"level"`
|
||||||
Format string `mapstructure:"format"`
|
Format string `mapstructure:"format"`
|
||||||
Output string `mapstructure:"output"`
|
Output string `mapstructure:"output"`
|
||||||
FilePath string `mapstructure:"file_path"`
|
LogDir string `mapstructure:"log_dir"` // 日志目录
|
||||||
MaxSize int `mapstructure:"max_size"`
|
MaxSize int `mapstructure:"max_size"` // 单个文件最大大小(MB)
|
||||||
MaxBackups int `mapstructure:"max_backups"`
|
MaxBackups int `mapstructure:"max_backups"` // 最大备份文件数
|
||||||
MaxAge int `mapstructure:"max_age"`
|
MaxAge int `mapstructure:"max_age"` // 最大保留天数
|
||||||
Compress bool `mapstructure:"compress"`
|
Compress bool `mapstructure:"compress"` // 是否压缩
|
||||||
UseColor bool `mapstructure:"use_color"`
|
UseColor bool `mapstructure:"use_color"` // 是否使用彩色输出
|
||||||
|
UseDaily bool `mapstructure:"use_daily"` // 是否按日分包
|
||||||
}
|
}
|
||||||
|
|
||||||
// JWTConfig JWT配置
|
// JWTConfig JWT配置
|
||||||
|
|||||||
@@ -81,11 +81,12 @@ func NewContainer() *Container {
|
|||||||
Level: cfg.Logger.Level,
|
Level: cfg.Logger.Level,
|
||||||
Format: cfg.Logger.Format,
|
Format: cfg.Logger.Format,
|
||||||
Output: cfg.Logger.Output,
|
Output: cfg.Logger.Output,
|
||||||
FilePath: cfg.Logger.FilePath,
|
LogDir: cfg.Logger.LogDir,
|
||||||
MaxSize: cfg.Logger.MaxSize,
|
MaxSize: cfg.Logger.MaxSize,
|
||||||
MaxBackups: cfg.Logger.MaxBackups,
|
MaxBackups: cfg.Logger.MaxBackups,
|
||||||
MaxAge: cfg.Logger.MaxAge,
|
MaxAge: cfg.Logger.MaxAge,
|
||||||
Compress: cfg.Logger.Compress,
|
Compress: cfg.Logger.Compress,
|
||||||
|
UseDaily: cfg.Logger.UseDaily,
|
||||||
}
|
}
|
||||||
return logger.NewLogger(logCfg)
|
return logger.NewLogger(logCfg)
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -4,9 +4,12 @@ import (
|
|||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
|
"path/filepath"
|
||||||
|
"time"
|
||||||
|
|
||||||
"go.uber.org/zap"
|
"go.uber.org/zap"
|
||||||
"go.uber.org/zap/zapcore"
|
"go.uber.org/zap/zapcore"
|
||||||
|
"gopkg.in/natefinch/lumberjack.v2"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Logger 日志接口
|
// Logger 日志接口
|
||||||
@@ -33,11 +36,12 @@ type Config struct {
|
|||||||
Level string
|
Level string
|
||||||
Format string
|
Format string
|
||||||
Output string
|
Output string
|
||||||
FilePath string
|
LogDir string // 日志目录
|
||||||
MaxSize int
|
MaxSize int // 单个文件最大大小(MB)
|
||||||
MaxBackups int
|
MaxBackups int // 最大备份文件数
|
||||||
MaxAge int
|
MaxAge int // 最大保留天数
|
||||||
Compress bool
|
Compress bool // 是否压缩
|
||||||
|
UseDaily bool // 是否按日分包
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewLogger 创建新的日志实例
|
// NewLogger 创建新的日志实例
|
||||||
@@ -69,19 +73,10 @@ func NewLogger(config Config) (Logger, error) {
|
|||||||
case "stderr":
|
case "stderr":
|
||||||
writeSyncer = zapcore.AddSync(os.Stderr)
|
writeSyncer = zapcore.AddSync(os.Stderr)
|
||||||
case "file":
|
case "file":
|
||||||
if config.FilePath == "" {
|
writeSyncer, err = createFileWriteSyncer(config)
|
||||||
config.FilePath = "logs/app.log"
|
|
||||||
}
|
|
||||||
// 确保目录存在
|
|
||||||
if err := os.MkdirAll("logs", 0755); err != nil {
|
|
||||||
return nil, fmt.Errorf("创建日志目录失败: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
file, err := os.OpenFile(config.FilePath, os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0666)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("打开日志文件失败: %w", err)
|
return nil, fmt.Errorf("创建文件输出失败: %w", err)
|
||||||
}
|
}
|
||||||
writeSyncer = zapcore.AddSync(file)
|
|
||||||
default:
|
default:
|
||||||
writeSyncer = zapcore.AddSync(os.Stdout)
|
writeSyncer = zapcore.AddSync(os.Stdout)
|
||||||
}
|
}
|
||||||
@@ -97,6 +92,56 @@ func NewLogger(config Config) (Logger, error) {
|
|||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// createFileWriteSyncer 创建文件输出同步器
|
||||||
|
func createFileWriteSyncer(config Config) (zapcore.WriteSyncer, error) {
|
||||||
|
// 设置默认日志目录
|
||||||
|
if config.LogDir == "" {
|
||||||
|
config.LogDir = "logs"
|
||||||
|
}
|
||||||
|
|
||||||
|
// 确保日志目录存在
|
||||||
|
if err := os.MkdirAll(config.LogDir, 0755); err != nil {
|
||||||
|
return nil, fmt.Errorf("创建日志目录失败: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 设置默认值
|
||||||
|
if config.MaxSize == 0 {
|
||||||
|
config.MaxSize = 100 // 默认100MB
|
||||||
|
}
|
||||||
|
if config.MaxBackups == 0 {
|
||||||
|
config.MaxBackups = 3 // 默认3个备份
|
||||||
|
}
|
||||||
|
if config.MaxAge == 0 {
|
||||||
|
config.MaxAge = 7 // 默认7天
|
||||||
|
}
|
||||||
|
|
||||||
|
// 构建日志文件路径
|
||||||
|
var logFilePath string
|
||||||
|
if config.UseDaily {
|
||||||
|
// 按日分包:logs/2024-01-01/app.log
|
||||||
|
today := time.Now().Format("2006-01-02")
|
||||||
|
dailyDir := filepath.Join(config.LogDir, today)
|
||||||
|
if err := os.MkdirAll(dailyDir, 0755); err != nil {
|
||||||
|
return nil, fmt.Errorf("创建日期目录失败: %w", err)
|
||||||
|
}
|
||||||
|
logFilePath = filepath.Join(dailyDir, "app.log")
|
||||||
|
} else {
|
||||||
|
// 传统方式:logs/app.log
|
||||||
|
logFilePath = filepath.Join(config.LogDir, "app.log")
|
||||||
|
}
|
||||||
|
|
||||||
|
// 创建lumberjack日志轮转器
|
||||||
|
lumberJackLogger := &lumberjack.Logger{
|
||||||
|
Filename: logFilePath,
|
||||||
|
MaxSize: config.MaxSize, // 单个文件最大大小(MB)
|
||||||
|
MaxBackups: config.MaxBackups, // 最大备份文件数
|
||||||
|
MaxAge: config.MaxAge, // 最大保留天数
|
||||||
|
Compress: config.Compress, // 是否压缩
|
||||||
|
}
|
||||||
|
|
||||||
|
return zapcore.AddSync(lumberJackLogger), nil
|
||||||
|
}
|
||||||
|
|
||||||
// getEncoderConfig 获取编码器配置
|
// getEncoderConfig 获取编码器配置
|
||||||
func getEncoderConfig() zapcore.EncoderConfig {
|
func getEncoderConfig() zapcore.EncoderConfig {
|
||||||
return zapcore.EncoderConfig{
|
return zapcore.EncoderConfig{
|
||||||
|
|||||||
154
scripts/log-manager.sh
Normal file
154
scripts/log-manager.sh
Normal file
@@ -0,0 +1,154 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
# 日志管理脚本
|
||||||
|
# 用于清理旧日志文件和查看日志统计信息
|
||||||
|
|
||||||
|
LOG_DIR="./logs"
|
||||||
|
RETENTION_DAYS=30
|
||||||
|
|
||||||
|
# 颜色定义
|
||||||
|
RED='\033[0;31m'
|
||||||
|
GREEN='\033[0;32m'
|
||||||
|
YELLOW='\033[1;33m'
|
||||||
|
BLUE='\033[0;34m'
|
||||||
|
NC='\033[0m' # No Color
|
||||||
|
|
||||||
|
# 打印带颜色的消息
|
||||||
|
print_info() {
|
||||||
|
echo -e "${BLUE}[INFO]${NC} $1"
|
||||||
|
}
|
||||||
|
|
||||||
|
print_success() {
|
||||||
|
echo -e "${GREEN}[SUCCESS]${NC} $1"
|
||||||
|
}
|
||||||
|
|
||||||
|
print_warning() {
|
||||||
|
echo -e "${YELLOW}[WARNING]${NC} $1"
|
||||||
|
}
|
||||||
|
|
||||||
|
print_error() {
|
||||||
|
echo -e "${RED}[ERROR]${NC} $1"
|
||||||
|
}
|
||||||
|
|
||||||
|
# 显示帮助信息
|
||||||
|
show_help() {
|
||||||
|
echo "日志管理脚本"
|
||||||
|
echo ""
|
||||||
|
echo "用法: $0 [命令]"
|
||||||
|
echo ""
|
||||||
|
echo "命令:"
|
||||||
|
echo " clean - 清理超过 $RETENTION_DAYS 天的旧日志文件"
|
||||||
|
echo " stats - 显示日志统计信息"
|
||||||
|
echo " size - 显示日志目录大小"
|
||||||
|
echo " list - 列出所有日志文件"
|
||||||
|
echo " help - 显示此帮助信息"
|
||||||
|
echo ""
|
||||||
|
echo "示例:"
|
||||||
|
echo " $0 clean # 清理旧日志"
|
||||||
|
echo " $0 stats # 查看统计信息"
|
||||||
|
}
|
||||||
|
|
||||||
|
# 清理旧日志文件
|
||||||
|
clean_old_logs() {
|
||||||
|
print_info "开始清理超过 $RETENTION_DAYS 天的旧日志文件..."
|
||||||
|
|
||||||
|
if [ ! -d "$LOG_DIR" ]; then
|
||||||
|
print_error "日志目录 $LOG_DIR 不存在"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# 查找并删除超过指定天数的日志文件
|
||||||
|
find "$LOG_DIR" -name "*.log*" -type f -mtime +$RETENTION_DAYS -exec rm -f {} \;
|
||||||
|
|
||||||
|
# 删除空的日期目录
|
||||||
|
find "$LOG_DIR" -type d -empty -delete
|
||||||
|
|
||||||
|
print_success "旧日志文件清理完成"
|
||||||
|
}
|
||||||
|
|
||||||
|
# 显示日志统计信息
|
||||||
|
show_stats() {
|
||||||
|
print_info "日志统计信息:"
|
||||||
|
echo ""
|
||||||
|
|
||||||
|
if [ ! -d "$LOG_DIR" ]; then
|
||||||
|
print_error "日志目录 $LOG_DIR 不存在"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# 总文件数
|
||||||
|
total_files=$(find "$LOG_DIR" -name "*.log*" -type f | wc -l)
|
||||||
|
echo "总日志文件数: $total_files"
|
||||||
|
|
||||||
|
# 总大小
|
||||||
|
total_size=$(du -sh "$LOG_DIR" 2>/dev/null | cut -f1)
|
||||||
|
echo "日志目录总大小: $total_size"
|
||||||
|
|
||||||
|
# 按日期统计
|
||||||
|
echo ""
|
||||||
|
echo "按日期统计:"
|
||||||
|
for date_dir in "$LOG_DIR"/*/; do
|
||||||
|
if [ -d "$date_dir" ]; then
|
||||||
|
date_name=$(basename "$date_dir")
|
||||||
|
file_count=$(find "$date_dir" -name "*.log*" -type f | wc -l)
|
||||||
|
dir_size=$(du -sh "$date_dir" 2>/dev/null | cut -f1)
|
||||||
|
echo " $date_name: $file_count 个文件, $dir_size"
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
# 最近修改的文件
|
||||||
|
echo ""
|
||||||
|
echo "最近修改的日志文件:"
|
||||||
|
find "$LOG_DIR" -name "*.log*" -type f -exec ls -lh {} \; | head -5
|
||||||
|
}
|
||||||
|
|
||||||
|
# 显示日志目录大小
|
||||||
|
show_size() {
|
||||||
|
if [ ! -d "$LOG_DIR" ]; then
|
||||||
|
print_error "日志目录 $LOG_DIR 不存在"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
total_size=$(du -sh "$LOG_DIR" 2>/dev/null | cut -f1)
|
||||||
|
print_info "日志目录大小: $total_size"
|
||||||
|
}
|
||||||
|
|
||||||
|
# 列出所有日志文件
|
||||||
|
list_logs() {
|
||||||
|
if [ ! -d "$LOG_DIR" ]; then
|
||||||
|
print_error "日志目录 $LOG_DIR 不存在"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
print_info "所有日志文件:"
|
||||||
|
find "$LOG_DIR" -name "*.log*" -type f -exec ls -lh {} \;
|
||||||
|
}
|
||||||
|
|
||||||
|
# 主函数
|
||||||
|
main() {
|
||||||
|
case "$1" in
|
||||||
|
"clean")
|
||||||
|
clean_old_logs
|
||||||
|
;;
|
||||||
|
"stats")
|
||||||
|
show_stats
|
||||||
|
;;
|
||||||
|
"size")
|
||||||
|
show_size
|
||||||
|
;;
|
||||||
|
"list")
|
||||||
|
list_logs
|
||||||
|
;;
|
||||||
|
"help"|"-h"|"--help"|"")
|
||||||
|
show_help
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
print_error "未知命令: $1"
|
||||||
|
show_help
|
||||||
|
exit 1
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
}
|
||||||
|
|
||||||
|
# 执行主函数
|
||||||
|
main "$@"
|
||||||
Reference in New Issue
Block a user