golang 标准库log的封装并实现日志切分

都知道golang的log库可以拿来就用,但对于生产来说还不够,需要基于log库做点封装。除了这些还有其他问题,比如打印字段定制化,性能问题。本文不讨论太多,只对log进行简单封装,实现log的持久化、loglevel、日志切分等功能。

参考:

代码结构

具体代码

main入口

package main
import (
lu "go-stdLog/log_utils"
)
func main() {
lgfile, err := lu.MustOpen("log.txt", "logs")
if err != nil {
lu.Error("Failed to open log file:" + err.Error())
}
// output to file
lu.Config(lu.DEBUG, lgfile)
// with rotate
// lu.ConfigWithLumberjack(lu.DEBUG, "log.txt")
// balabala
lu.Debug("msg")
lu.Info("msg")
lu.Warning("msg")
lu.Error("msg")
}

log_utils.log

package log_utils
import (
"fmt"
"io/ioutil"
"log"
"mime/multipart"
"os"
"path"
"runtime"
"strings"
)
/*
* reference: go原生log模块的简易封装 https://cloud.tencent.com/developer/article/1673063
*/
type Level int
const (
DEBUG Level = iota
INFO
WARNING
ERROR
FATAL
)
var (
logPrefix = ""
levelFlags = []string{"DEBG", "INFO", "WARN", "ERRO", "FATL"}
logger *log.Logger
loggerf *log.Logger
curLevel Level
logfile *os.File
)
func init() {
curLevel = DEBUG
logger = log.New(os.Stdout, "[Default] ", log.LstdFlags)
logger.SetFlags(log.Ldate | log.Lmicroseconds | log.Llongfile)
}
func Println(l *log.Logger, v ...interface{}) {
if l != nil {
l.Output(3, fmt.Sprintln(v...))
}
}
func Fatalln(l *log.Logger, v ...interface{}) {
if l != nil {
l.Output(3, fmt.Sprintln(v...))
os.Exit(1)
}
}
func setPrefix(level Level) {
// stdout
logPrefix = fmt.Sprintf("[%s] ", levelFlags[level])
logger.SetPrefix(logPrefix)
// log file
if loggerf != nil {
loggerf.SetPrefix(logPrefix)
}
}
func Debug(v ...interface{}) {
setPrefix(DEBUG)
if DEBUG >= curLevel {
Println(logger, v)
Println(loggerf, v)
}
}
func Info(v ...interface{}) {
setPrefix(INFO)
if INFO >= curLevel {
Println(logger, v)
Println(loggerf, v)
}
}
func Warning(v ...interface{}) {
setPrefix(WARNING)
if WARNING >= curLevel {
Println(logger, v)
Println(loggerf, v)
}
}
func Error(v ...interface{}) {
setPrefix(ERROR)
if ERROR >= curLevel {
Println(logger, v)
Println(loggerf, v)
}
}
func Fatal(v ...interface{}) {
setPrefix(FATAL)
if FATAL >= curLevel {
Println(logger, v)
Println(loggerf, v)
}
}
// output to file
func Config(level Level, lfile *os.File) {
curLevel = level
loggerf = log.New(lfile, "[default] ", log.LstdFlags)
loggerf.SetFlags(log.Ldate | log.Lmicroseconds | log.Llongfile)
}
// output log && rotate
func ConfigWithLumberjack(level Level, filename string) {
curLevel = level
loggerf = log.New(getLumberjackLogger(filename), "[default] ", log.LstdFlags)
loggerf.SetFlags(log.Ldate | log.Lmicroseconds | log.Llongfile)
}
func getLumberjackLogger(fielname string) *lumberjack.Logger {
lumLogger := &lumberjack.Logger{
Filename: fielname,
MaxSize: 1, // MB
MaxBackups: 7, // backup cnt
MaxAge: 7, // days
Compress: true,
}
return lumLogger
}
// support file log
func getSize(f multipart.File) (int, error) {
content, err := ioutil.ReadAll(f)
return len(content), err
}
func getExt(filename string) string {
return path.Ext(filename)
}
func checkIsExist(src string) bool {
_, err := os.Stat(src)
return os.IsNotExist(err)
}
func checkPermission(src string) bool {
_, err := os.Stat(src)
return os.IsPermission(err)
}
func mkdir(src string) error {
err := os.MkdirAll(src, os.ModePerm)
if err != nil {
return err
}
return nil
}
func NotExistMkDir(src string) error {
if exist := checkIsExist(src); exist {
if err := mkdir(src); err != nil {
return err
}
}
return nil
}
func lastDir(dir string) string {
return ""
}
func compareString(s1, s2 string) bool {
if len(s1) != len(s2) {
return false
}
for i, _ := range s1 {
if s1[i] != s2[i] {
return false
}
}
return true
}
func Open(name string, flag int, perm os.FileMode) (*os.File, error) {
f, err := os.OpenFile(name, flag, perm)
if err != nil {
return nil, err
}
return f, nil
}
func MustOpen(filename, filepath string) (*os.File, error) {
dir, err := os.Getwd()
if err != nil {
return nil, fmt.Errorf("os.Getwd err: %v", err)
}
osTyp := runtime.GOOS
if compareString(osTyp, "windows") {
dirs := strings.Split(dir, "\\")
dir = strings.Join(dirs[:], "\\")
}
var src string
var perm bool
if compareString(osTyp, "windows") {
src = dir + "\\" + filepath
perm = checkPermission(src)
} else {
src = path.Join(dir, filepath)
perm = checkPermission(src)
}
if perm {
return nil, fmt.Errorf("file.CheckPermission Permission denied src: %s", src)
}
err = NotExistMkDir(src)
if err != nil {
return nil, fmt.Errorf("file.IsNotExistMkDir src: %s, err: %v", src, err)
}
// default windows system
f, err := Open(src + "\\" + filename, os.O_APPEND | os.O_CREATE | os.O_RDWR, 0644)
if err != nil {
return nil, fmt.Errorf("Fail to OpenFile :%v", err)
}
return f, nil
}

日志切分用到lumberjack,以下是go.mod:

module go-stdLog
go 1.19
require (
gopkg.in/natefinch/lumberjack.v2 v2.0.0
)
require (
github.com/BurntSushi/toml v1.2.1 // indirect
gopkg.in/yaml.v2 v2.4.0 // indirect
)

测试结果

console

log文件

以上就是基于标准库log的简单实践,一般应用或不考虑性能情况下,可以试试上log库。

posted on   进击的davis  阅读(685)  评论(0编辑  收藏  举报

相关博文:
阅读排行:
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· Manus的开源复刻OpenManus初探
· AI 智能体引爆开源社区「GitHub 热点速览」
· 三行代码完成国际化适配,妙~啊~
· .NET Core 中如何实现缓存的预热?
历史上的今天:
2021-12-01 0139-单词拆分
2021-12-01 0279-完全平方数
2021-12-01 0322-零钱兑换

导航

< 2025年3月 >
23 24 25 26 27 28 1
2 3 4 5 6 7 8
9 10 11 12 13 14 15
16 17 18 19 20 21 22
23 24 25 26 27 28 29
30 31 1 2 3 4 5
点击右上角即可分享
微信分享提示