You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

234 lines
5.4 KiB

2 years ago
package logm
import (
"fmt"
toolm2 "github.com/han-joker/moo-layout/api/moo/toolm"
"github.com/sirupsen/logrus"
"io"
"os"
"path"
"time"
)
//常量
//日志文件后缀
const fileExt = ".log"
//日志格式
const (
Text = iota
Json
)
// OutMode 预设值
const (
Console = iota // 控制台
File // 文件,单文件模式
FilePerDay // 每天一个文件
FilePerWeek // 每周一个文件
FilePerMonth // 每月一个文件
FilePerHour // 每小时一个文件
FilePerSize // 文件固定大小
User
)
//变量
//池
var pool = map[string]*log{}
//格式集合
var fmtContainer = []int{Text, Json}
//输出模式
var outModeContainer = []int{Console, File, FilePerDay, FilePerWeek, FilePerMonth, FilePerHour, FilePerSize, User}
//默认选项
var optionDefault = Option{
Fmt: Text,
Caller: false,
OutMode: Console,
Path: "./logs/",
FilePrefix: "moo",
SizeMax: 100 * 1024 * 1024, // 100 M Bytes
Output: os.Stdout,
}
//类型
//日志
type log struct {
*logrus.Logger
option Option
// cache
writers map[string]*os.File
}
// Option 选项
type Option struct {
Name string
Fmt int // Text, Json
Caller bool // true, false
OutMode int // Console, FILE, User
Path string // some path
FilePrefix string //
SizeMax int64
Output io.Writer
}
type Fields = logrus.Fields
// New 创建对象
func New(option ...Option) *log {
verifiedOption := optionVerify(option...)
l := create(verifiedOption)
l.refreshOutMode()
return l
}
// Get 存在直接返回,否则创建、存储再返回
func Get(option ...Option) *log {
verifiedOption := optionVerify(option...)
if !Has(verifiedOption.Name) {
pool[verifiedOption.Name] = create(verifiedOption)
}
pool[verifiedOption.Name].refreshOutMode()
return pool[verifiedOption.Name]
}
// Has 存在返回 true否则返回 false
func Has(name string) bool {
_, has := pool[name]
return has
}
func (l *log) syncLoggerOption() *log {
switch l.option.Fmt {
case Json:
l.Logger.SetFormatter(&logrus.JSONFormatter{})
case Text:
l.Logger.SetFormatter(&logrus.TextFormatter{})
default:
l.Logger.SetFormatter(&logrus.TextFormatter{})
}
l.Logger.SetReportCaller(l.option.Caller)
l.Logger.SetOutput(l.option.Output)
return l
}
func (l *log) refreshOutMode() *log {
// 初始默认值
l.Logger.SetOutput(optionDefault.Output)
filename := ""
switch l.option.OutMode {
case File:
filename = l.option.Path + "/" + l.option.FilePrefix + fileExt
case FilePerHour:
now := time.Now()
filename = l.option.Path + "/" +
l.option.FilePrefix +
fmt.Sprintf("%04d-%02d-%02d-%02d", now.Year(), now.Month(), now.Day(), now.Hour()) +
fileExt
case FilePerDay:
now := time.Now()
filename = l.option.Path + "/" +
l.option.FilePrefix +
fmt.Sprintf("%04d-%02d-%02d", now.Year(), now.Month(), now.Day()) +
fileExt
case FilePerMonth:
now := time.Now()
filename = l.option.Path + "/" +
l.option.FilePrefix +
fmt.Sprintf("%04d-%02d", now.Year(), now.Month()) +
fileExt
case FilePerWeek:
now := time.Now()
year, week := now.ISOWeek()
filename = l.option.Path + "/" +
l.option.FilePrefix +
fmt.Sprintf("%04d-%02d", year, week) +
fileExt
case FilePerSize:
filename = l.option.Path + "/" + l.option.FilePrefix + fileExt
if fileinfo, err := os.Stat(filename); err == nil {
if fileinfo.Size() >= l.option.SizeMax {
basename := path.Base(filename)
if file, exists := l.writers[basename]; exists {
if err := file.Close(); err != nil {
l.Info("can not close file")
} else {
delete(l.writers, basename)
}
}
now := time.Now()
newFilename := l.option.Path + "/" +
l.option.FilePrefix +
fmt.Sprintf("%s", now.Format("2006-01-02-15-04-05")) +
fileExt
if err := os.Rename(filename, newFilename); err != nil {
l.Info("can not rename log file")
}
}
}
case User:
l.Logger.SetOutput(l.option.Output)
default:
l.Logger.SetOutput(optionDefault.Output)
}
if filename != "" {
filepath := path.Dir(filename)
if err := os.MkdirAll(filepath, 0644); err == nil || os.IsExist(err) {
basename := path.Base(filename)
file, exists := l.writers[basename]
if !exists {
if file, err = os.OpenFile(filename, os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0666); err != nil {
l.Info("can not create log file")
}
}
if file != nil {
l.Logger.SetOutput(file)
l.writers[basename] = file
} else {
l.Info("can not open log file")
}
} else {
l.Info("can not make log path")
}
}
return l
}
func create(option Option) *log {
return (&log{
Logger: logrus.New(),
option: option,
writers: map[string]*os.File{},
}).syncLoggerOption()
}
func optionVerify(option ...Option) Option {
opt := optionDefault
if len(option) > 0 {
//设置选项
opt.Name = option[0].Name
if toolm2.IntSliceContains(option[0].Fmt, fmtContainer) {
opt.Fmt = option[0].Fmt
}
opt.Caller = option[0].Caller
if toolm2.IntSliceContains(option[0].OutMode, outModeContainer) {
opt.OutMode = option[0].OutMode
}
opt.Path = option[0].Path
opt.FilePrefix = toolm2.StringDefault(option[0].FilePrefix, opt.Name, optionDefault.FilePrefix)
opt.SizeMax = toolm2.Int64Default(option[0].SizeMax, optionDefault.SizeMax)
if _, ok := option[0].Output.(io.Writer); ok {
opt.Output = option[0].Output
}
}
return opt
}