feat: zap日志配置
This commit is contained in:
@@ -0,0 +1,161 @@
|
||||
package internal
|
||||
|
||||
import (
|
||||
"os"
|
||||
"path/filepath"
|
||||
"sync"
|
||||
"time"
|
||||
)
|
||||
|
||||
type Cutter struct {
|
||||
level string // 日志级别
|
||||
layout string //时间格式
|
||||
formats []string //自定义参数
|
||||
director string //日志文件夹
|
||||
retentionDay int //保留天数
|
||||
file *os.File //文件
|
||||
mutex *sync.RWMutex // 读写锁
|
||||
}
|
||||
|
||||
type CutterOption func(c *Cutter)
|
||||
|
||||
// 设置时间格式
|
||||
func CutterWithLayout(layout string) CutterOption {
|
||||
return func(c *Cutter) {
|
||||
c.layout = layout
|
||||
}
|
||||
}
|
||||
|
||||
// 格式化参数
|
||||
func CutterWithFormats(format ...string) CutterOption {
|
||||
return func(c *Cutter) {
|
||||
if len(format) > 0 {
|
||||
c.formats = format
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// NewCutter 创建一个新的 Cutter 实例,用于管理日志文件的切割和保留。
|
||||
//
|
||||
// 参数:
|
||||
// - directory: 日志文件存储的目录路径。
|
||||
// - level: 日志级别,用于标识日志的严重程度。
|
||||
// - retentionDay: 日志文件保留的天数,超过该天数的日志文件将被删除。
|
||||
// - options: 可选的 CutterOption 函数,用于对 Cutter 实例进行额外的配置。
|
||||
//
|
||||
// 返回值:
|
||||
// - *Cutter: 返回一个初始化后的 Cutter 实例。
|
||||
func NewCutter(directory string, level string, retentionDay int, options ...CutterOption) *Cutter {
|
||||
// 初始化 Cutter 实例,设置日志级别、目录、保留天数以及互斥锁
|
||||
rotate := &Cutter{
|
||||
level: level,
|
||||
director: directory,
|
||||
retentionDay: retentionDay,
|
||||
mutex: new(sync.RWMutex),
|
||||
}
|
||||
|
||||
// 应用所有传入的 CutterOption 配置函数
|
||||
for i := 0; i < len(options); i++ {
|
||||
options[i](rotate)
|
||||
}
|
||||
|
||||
return rotate
|
||||
}
|
||||
|
||||
// Write 方法将给定的字节数据写入到日志文件中。该方法会确保日志文件的目录存在,并根据配置的格式生成文件名。
|
||||
// 如果日志文件已经存在,数据将被追加到文件末尾。如果文件不存在,则会创建新文件。
|
||||
// 该方法还会定期清理超过保留天数的日志文件夹。
|
||||
//
|
||||
// 参数:
|
||||
// - bytes: 要写入的字节数据。
|
||||
//
|
||||
// 返回值:
|
||||
// - n: 成功写入的字节数。
|
||||
// - err: 如果发生错误,返回错误信息;否则返回 nil。
|
||||
func (c *Cutter) Write(bytes []byte) (n int, err error) {
|
||||
// 加锁以确保并发安全
|
||||
c.mutex.Lock()
|
||||
defer func() {
|
||||
// 在函数结束时关闭文件并释放锁
|
||||
if c.file != nil {
|
||||
_ = c.file.Close()
|
||||
c.file = nil
|
||||
}
|
||||
c.mutex.Unlock()
|
||||
}()
|
||||
|
||||
// 生成日志文件名
|
||||
length := len(c.formats)
|
||||
values := make([]string, 0, 3+length)
|
||||
values = append(values, c.director)
|
||||
if c.layout != "" {
|
||||
values = append(values, time.Now().Format(c.layout))
|
||||
}
|
||||
for i := 0; i < length; i++ {
|
||||
values = append(values, c.formats[i])
|
||||
}
|
||||
values = append(values, c.level+".log")
|
||||
filename := filepath.Join(values...)
|
||||
|
||||
// 确保日志文件所在的目录存在
|
||||
directory := filepath.Dir(filename)
|
||||
err = os.MkdirAll(directory, os.ModePerm)
|
||||
if err != nil {
|
||||
return 0, nil
|
||||
}
|
||||
|
||||
// 清理超过保留天数的日志文件夹
|
||||
err = removeNDaysFolders(c.director, c.retentionDay)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
// 打开或创建日志文件,并追加写入数据
|
||||
c.file, err = os.OpenFile(filename, os.O_CREATE|os.O_APPEND|os.O_WRONLY, 0644)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
// 将数据写入文件并返回写入的字节数
|
||||
return c.file.Write(bytes)
|
||||
}
|
||||
|
||||
// Sync 方法用于将当前文件的内容同步到磁盘,确保所有缓冲区的数据都写入磁盘。
|
||||
// 该方法在调用时会先获取互斥锁,以确保在同步过程中不会有其他操作干扰。
|
||||
// 如果当前 Cutter 实例中的文件对象不为 nil,则调用文件对象的 Sync 方法进行同步操作。
|
||||
// 如果文件对象为 nil,则直接返回 nil,表示无需同步。
|
||||
//
|
||||
// 返回值:
|
||||
// - error: 如果同步过程中发生错误,则返回该错误;否则返回 nil。
|
||||
func (c *Cutter) Sync() error {
|
||||
c.mutex.Lock()
|
||||
defer c.mutex.Unlock()
|
||||
|
||||
// 如果文件对象存在,则调用其 Sync 方法进行同步
|
||||
if c.file != nil {
|
||||
return c.file.Sync()
|
||||
}
|
||||
|
||||
// 文件对象不存在,直接返回 nil
|
||||
return nil
|
||||
}
|
||||
|
||||
// removeNDaysFolders 删除指定目录下,指定天数前的文件夹
|
||||
func removeNDaysFolders(dir string, days int) error {
|
||||
if days <= 0 {
|
||||
return nil
|
||||
}
|
||||
cutoff := time.Now().AddDate(0, 0, -days)
|
||||
return filepath.Walk(dir, func(path string, info os.FileInfo, err error) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if info.IsDir() && info.ModTime().Before(cutoff) && path != dir {
|
||||
err = os.RemoveAll(path)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
})
|
||||
}
|
||||
Reference in New Issue
Block a user