代码拉取完成,页面将自动刷新
package logger
import (
"bytes"
"fmt"
"os"
"path/filepath"
"runtime"
"sync"
"time"
"gitee.com/night-tc/gobige/threads"
)
type option func(mgr *LoggerMgr)
func LoggerSetConfig(v *LogFileConfig) option {
return func(mgr *LoggerMgr) {
mgr.config = v
}
}
// LoggerMgr 日志管理器,负责日志的生成、写入和管理。
type LoggerMgr struct {
thgo *threads.ThreadGo //协程 管理
config *LogFileConfig //日志文件配置
logFileNowNumber int //当前日志文件编号(同一天日志超过FileLogMaxLine则会生成新的文件日志)
logFileNowLine int //当前正在写入的日志文件行数
writeChan chan *logData //写日志到文件的通道
consoleChan chan *logData //写日志到控制台通道
lk sync.RWMutex
tmpKeyList []LogKeyEnum //Debug时可以输入日志的Key
file *os.File //普通日志文件
errorFile *os.File //错误日志文件
fileUpdateTime *time.Time //普通日志文件更新时间
errorFileUpdateTime *time.Time //错误日志文件更新时间
}
// newLoggerMgr 创建一个新的日志管理器实例。
// 参数:
//
// thgo: 协程管理器实例。
// opts: 可选配置项。
//
// 返回值:
//
// *LoggerMgr: 日志管理器实例。
func newLoggerMgr(thgo *threads.ThreadGo, opts ...option) (result *LoggerMgr) {
result = new(LoggerMgr)
if thgo == nil {
result.thgo = threads.NewThreadGo()
} else {
result.thgo = thgo
}
result.config = defaultLogConfig
result.logFileNowNumber = LOGFILE_INIT_NUMBER
result.logFileNowLine = 0
result.writeChan = make(chan *logData, 1000)
result.consoleChan = make(chan *logData, 1000)
n := time.Now()
result.fileUpdateTime = &n
result.errorFileUpdateTime = &n
// result.tmpLogLevel = LogLevelDefualt
for i := range opts {
opts[i](result)
}
result.tmpKeyList = result.config.Keys
if thgo == nil {
istest = true
//如果为nil,表示Test逻辑
result.writeChan = nil
result.Start()
} else {
result.Start()
}
return
}
// Start 启动日志管理器,开启日志写入和控制台输出的协程。
func (this *LoggerMgr) Start() {
this.thgo.Go(this.run)
this.thgo.Go(this.runByconsole)
}
// Stop 停止日志管理器,关闭日志写入和控制台输出的通道。
func (this *LoggerMgr) Stop() {
if this.writeChan != nil {
close(this.writeChan)
}
close(this.consoleChan)
this.thgo.CloseWait()
}
// 是否有指定日志Key
// 参数:
//
// key: 日志Key。
//
// 返回值:
//
// bool: 是否包含指定Key。
func (this *LoggerMgr) checkKey(key LogKeyEnum) bool {
this.lk.RLock()
defer this.lk.RUnlock()
for i := range this.tmpKeyList {
if this.tmpKeyList[i] == key {
return true
}
}
return false
}
// 写日志到文件
// 参数:
//
// key: 日志Key。
// logLevel: 日志等级。
// format: 日志内容的格式化字符串。
func (this *LoggerMgr) writeLog(key LogKeyEnum, logLevel logLevel, format string) {
//生成日志数据
logData := this.genLogData(key, logLevel, format)
//通知写入控制台日志的通道
select {
case this.consoleChan <- logData:
default:
}
//通知写入日志文件的通道
select {
case this.writeChan <- logData:
default:
}
}
func getFileNameLineFunc(skipN int) (fName string, line int, funcName string) {
pc, _, _, ok := runtime.Caller(skipN)
if !ok {
fmt.Println("[fatal]cannot get caller info")
return
}
fun := runtime.FuncForPC(pc)
if fun == nil {
return
}
fName, line = fun.FileLine(pc)
funcName = fun.Name()
return
}
// 生成日志数据
// 参数:
//
// key: 日志Key。
// logLevel: 日志等级。
// format: 日志内容的格式化字符串。
//
// 返回值:
//
// *logData: 日志数据结构。
func (this *LoggerMgr) genLogData(key LogKeyEnum, logLevel logLevel, format string) *logData {
trace := ""
if logLevel <= LogLevelError {
trace = loggerTrace(5)
}
ffullpath := "" //长文件名
fpath := "" //短文件名
logTitle := ""
switch logLevel {
case LogLevelFatal:
logTitle = "[FATAL]"
case LogLevelError:
logTitle = "[ERROR]"
case LogLevelWarn:
logTitle = "[WARN]"
f, n, _ := getFileNameLineFunc(5)
ffullpath = fmt.Sprintf(" %v:%v \n", f, n)
case LogLevelInfo:
logTitle = "[INFO]"
case LogLevelDebug:
logTitle = "[DEBUG]"
}
logTime := time.Now().Format("2006-01-02 15:04:05.000")
var buf bytes.Buffer
buf.WriteString(logTime)
buf.WriteString(" ")
buf.WriteString(logTitle)
if key != "" {
buf.WriteString("[")
buf.WriteString(key)
buf.WriteString("]")
}
//文件行号和函数信息
if trace != "" {
//不打印路径,因为有堆栈
} else if this.config.AppendFileInfo {
f, n, _ := getFileNameLineFunc(5)
if f != "" {
if this.config.TrimFilePath {
fpath = fmt.Sprintf(" %v:%v ", filepath.Base(f), n)
} else {
ffullpath = fmt.Sprintf(" %v:%v \n", f, n)
}
}
}
buf.WriteString(fpath)
buf.WriteString(": ")
buf.WriteString(format)
buf.WriteString(trace)
buf.WriteString("\n")
buf.WriteString(ffullpath)
return &logData{
level: logLevel,
data: buf.String(),
}
}
// 打印错误日志到控制台。
// 参数:
//
// format: 错误信息的格式化字符串。
// a: 格式化参数。
func (this *LoggerMgr) printError(format string, a ...interface{}) {
//生成堆栈信息
trace := loggerTrace(0)
//格式化错误信息
err := fmt.Sprintf(format, a...)
//格式化完整错误信息
msg := fmt.Sprintf("\n%s [logFile Error]: logFile %s %s error: %s \n %s \n\n",
time.Now().Format("2006-01-02 15:04:05"), this.config.LogFilePath, this.config.LogFileName, err, trace)
//普通打印
fmt.Print(msg)
}
// fatal 记录致命错误日志。
// 参数:
//
// format: 日志内容的格式化字符串。
func (this *LoggerMgr) fatal(format string) {
this.writeLog("", LogLevelFatal, format)
}
// error 记录错误日志。
// 参数:
//
// format: 日志内容的格式化字符串。
func (this *LoggerMgr) error(format string) {
this.writeLog("", LogLevelError, format)
}
// warn 记录警告日志。
// 参数:
//
// format: 日志内容的格式化字符串。
func (this *LoggerMgr) warn(format string) {
this.writeLog("", LogLevelWarn, format)
}
// info 记录信息日志。
// 参数:
//
// format: 日志内容的格式化字符串。
func (this *LoggerMgr) info(format string) {
this.writeLog("", LogLevelInfo, format)
}
// debug 记录调试日志。
// 参数:
//
// key: 日志的关键字,用于标识日志类别。
// format: 日志内容的格式化字符串。
func (this *LoggerMgr) debug(key LogKeyEnum, format string) {
this.writeLog(key, LogLevelDebug, format)
}
此处可能存在不合适展示的内容,页面不予展示。您可通过相关编辑功能自查并修改。
如您确认内容无涉及 不当用语 / 纯广告导流 / 暴力 / 低俗色情 / 侵权 / 盗版 / 虚假 / 无价值内容或违法国家有关法律法规的内容,可点击提交进行申诉,我们将尽快为您处理。