網站首頁 編程語言 正文
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
}
}
}
原文鏈接:https://blog.csdn.net/Json_Marz/article/details/129047913
- 上一篇:沒有了
- 下一篇:沒有了
相關推薦
- 2022-09-07 Python的flask常用函數route()_python
- 2022-05-31 Python學習之日志模塊詳解_python
- 2022-05-12 Android textAppearance 使用
- 2022-07-31 Android中View.post和Handler.post的關系_Android
- 2022-04-28 sql?server?累計求和實現代碼_MsSql
- 2023-06-03 C++11學習之右值引用和移動語義詳解_C 語言
- 2022-11-10 golang?常用定時任務匯總_Golang
- 2022-09-02 Python常用編碼的區別介紹_python
- 欄目分類
-
- 最近更新
-
- window11 系統安裝 yarn
- 超詳細win安裝深度學習環境2025年最新版(
- Linux 中運行的top命令 怎么退出?
- MySQL 中decimal 的用法? 存儲小
- get 、set 、toString 方法的使
- @Resource和 @Autowired注解
- Java基礎操作-- 運算符,流程控制 Flo
- 1. Int 和Integer 的區別,Jav
- spring @retryable不生效的一種
- Spring Security之認證信息的處理
- Spring Security之認證過濾器
- Spring Security概述快速入門
- Spring Security之配置體系
- 【SpringBoot】SpringCache
- Spring Security之基于方法配置權
- redisson分布式鎖中waittime的設
- maven:解決release錯誤:Artif
- restTemplate使用總結
- Spring Security之安全異常處理
- MybatisPlus優雅實現加密?
- Spring ioc容器與Bean的生命周期。
- 【探索SpringCloud】服務發現-Nac
- Spring Security之基于HttpR
- Redis 底層數據結構-簡單動態字符串(SD
- arthas操作spring被代理目標對象命令
- Spring中的單例模式應用詳解
- 聊聊消息隊列,發送消息的4種方式
- bootspring第三方資源配置管理
- GIT同步修改后的遠程分支