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

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

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
}