golang中log包自定义输出日志格式与写入到文件
作者:Json_Marz
这篇文章主要给大家介绍了关于golang中log包自定义输出日志格式与写入到文件的相关资料,日志输出在任何项目中都极其重要,是有助于后续我们排查解决程序BUG,需要的朋友可以参考下
1.背景:
平时开发项目时打印日志用到logrus包,但是觉得logrus配置比较麻烦,于是想着直接使用go自带的log包输出日志,其提供了一些配置,比如SetPrefix(), 可以让我们自己二次封装,让自己的日志内容更鲜明些。
2.代码:
package log import ( "fmt" "github.com/robfig/cron/v3" "io" "log" "os" "my_log/config" "runtime" "strconv" "strings" "sync" "time" ) var ( debug *log.Logger info *log.Logger warn *log.Logger error *log.Logger dayChangeLock sync.RWMutex ) const ( debugLevel = iota //iota=0 infoLevel warnLevel errorLevel ) func init() { dayChangeLock = sync.RWMutex{} createLogFile() go logJob() } func createLogFile() { dayChangeLock.Lock() defer dayChangeLock.Unlock() now := time.Now() postFix := now.Format("20060102") logFile := "plume_log_" + postFix + ".log" logOut, err := os.OpenFile(logFile, os.O_RDWR|os.O_CREATE|os.O_APPEND, os.ModePerm) if err != nil { panic(err) } else { multiWriter := io.MultiWriter(os.Stdout, logOut) debug = log.New(multiWriter, "[DEBUG] ", log.Ldate|log.Ltime) info = log.New(multiWriter, "[INFO] ", log.Ldate|log.Ltime) warn = log.New(multiWriter, "[WARN] ", log.Ldate|log.Ltime) error = log.New(multiWriter, "[ERROR] ", log.Ldate|log.Ltime) } } func Debug(format string, v ...any) { if config.Conf.Level <= debugLevel { debug.Printf(getLineNo()+format, v...) } } func Info(format string, v ...any) { if config.Conf.Level <= infoLevel { info.Printf(getLineNo()+format, v...) } } func Warn(format string, v ...any) { if config.Conf.Level <= warnLevel { warn.Printf(getLineNo()+format, v...) } } func Error(format string, v ...any) { if config.Conf.Level <= errorLevel { error.Printf(getLineNo()+format, v...) } } func getLineNo() string { _, file, line, ok := runtime.Caller(2) if ok { split := strings.Split(file, "/") file = split[len(split)-1] fileLine := file + ":" + strconv.Itoa(line) + " " return fileLine } return "" } // logJob 定时操作日志 func logJob() { c := cron.New(cron.WithSeconds()) c.AddFunc("@daily", func() { Info("执行log定时任务。。。") now := time.Now() createLogFile() closeYesterdayLogFile := fmt.Sprintf("plume_log_%s.log", now.Add(-24*time.Hour).Format("20060102")) file, _ := os.Open(closeYesterdayLogFile) file.Sync() file.Close() // 删除n天前的日志 removeLogFile := fmt.Sprintf("plume_log_%s.log", time.Now().Add(time.Duration(config.Conf.Log.KeepDays)*-24*time.Hour).Format("20060102")) open, err := os.Open(removeLogFile) if err != nil { Error(err.Error()) return } go func () { // 设置for select 的原因是文件虽然被关闭了,但文件所占的process还在进行中,每10秒轮询一次,执行删除操作,确保文件有被删除 loop: for { select { case <-time.After(10 * time.Second): removeErr := os.Remove(removeLogFile) if removeErr != nil { Error(removeErr.Error()) } else { Info("删除日志成功:%s", removeLogFile) break loop } } } }() }) c.Start() } //var ( // kernel32 = syscall.NewLazyDLL(`kernel32.dll`) // proc = kernel32.NewProc(`SetConsoleTextAttribute`) // CloseHandle = kernel32.NewProc(`CloseHandle`) // // 给字体颜色对象赋值 // FontColor = Color{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15} //) //type Color struct { // black int // 黑色 // blue int // 蓝色 // green int // 绿色 // cyan int // 青色 // red int // 红色 // purple int // 紫色 // yellow int // 黄色 // light_gray int // 淡灰色(系统默认值) // gray int // 灰色 // light_blue int // 亮蓝色 // light_green int // 亮绿色 // light_cyan int // 亮青色 // light_red int // 亮红色 // light_purple int // 亮紫色 // light_yellow int // 亮黄色 // white int // 白色 //} // 输出有颜色的字体 //func ColorPrint4Window(s, t string) { // switch t { // case "DEBUG": // proc.Call(uintptr(syscall.Stdout), uintptr(FontColor.light_cyan)) // Debug(s) // case "INFO": // proc.Call(uintptr(syscall.Stdout), uintptr(FontColor.green)) // Info(s) // case "WARN": // proc.Call(uintptr(syscall.Stdout), uintptr(FontColor.light_yellow)) // Warn(s) // case "ERROR": // proc.Call(uintptr(syscall.Stdout), uintptr(FontColor.red)) // Error(s) // default: // proc.Call(uintptr(syscall.Stdout), uintptr(FontColor.black)) // Info(s) // } //}
使用viper读取配置:
package config import ( "github.com/spf13/viper" "os" ) var Conf *Config type Config struct { Log } type Log struct { Level int KeepDays int Prefix string } func init() { Conf = &Config{} config := viper.New() path, _ := os.Getwd() config.SetConfigName("config") // 配置文件名字,注意没有扩展名 config.SetConfigType("toml") config.AddConfigPath(path) if err := config.ReadInConfig(); err != nil { panic(err) } Conf.Level = config.GetInt("log.level") Conf.Log.KeepDays = config.GetInt("log.keep-days") Conf.Log.Prefix = config.GetString("log.prefix") }
package main import ( "my_log/log" ) func main() { log.Debug("我是debug日志") log.Info("我是info日志") log.Warn("我是warn日志") log.Error("我是error日志") }
日志配置文件(config.toml):
[log] level = 0 keep-days = 7 prefix = "test_"
控制台输出:
生成的日志文件内容:
碰到的问题:
The process cannot access the file because it is being used by another process.
// 问题的产生: file := "test_log.log" os.Open(file) file.Close() os.Remove(file) // 因为程序还在运行中,该日志文件所占的process还未停止 // 解决办法: // 延迟删除文件,比如time.Sleep() // 推荐使用:label:for + select 轮询删除,删除完毕 break:label // 示例代码: loop: for { select { case <-time.After(10 * time.Second): removeErr := os.Remove(file) if removeErr != nil { Error(removeErr.Error()) } else { Info("删除日志成功:%s", file) break loop } } }
总结
到此这篇关于golang中log包自定义输出日志格式与写入到文件的文章就介绍到这了,更多相关go log包自定义输出日志格式内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!