自定义go语言日志输出

自定义输出符合下列需求:

  1.含两类日志输出方式:调试模式下输出到控制台;生产环境输出到日志文件

  2.调用不同的函数/方法构造不同的输出方式,后续只需调用日志级别对应的函数即可输出该级别日志

工具构造:

  - / mylogger

    - mylogger.go  类似python的init.py,怎么叫不知道

    - console.go   定义日志输出到控制台方式

    - writeFile.go  定义日志写入文件方式

 

mylogger.go:

 1 package mylogger
 2 
 3 import (
 4     "errors"
 5     "fmt"
 6     "path"
 7     "runtime"
 8     "strings"
 9 )
10 
11 // log level variable
12 type logLevel uint16
13 
14 // 对外接口
15 type Logger interface {
16     Debug(format string, a ...interface{})
17     Trace(format string, a ...interface{})
18     Info(format string, a ...interface{})
19     Warning(format string, a ...interface{})
20     Error(format string, a ...interface{})
21     Fatal(format string, a ...interface{})
22 }
23 
24 // level
25 const (
26     UNKNOWN logLevel = iota
27     DEBUG
28     TRACE
29     INFO
30     WARNING
31     ERROR
32     FATAL
33 )
34 
35 // 将等级字符串转换成整形 string -> uint16
36 func parseLogLevel(s string) (logLevel, error){
37     s = strings.ToLower(s)
38     switch s {
39     case "trace":
40         return TRACE, nil
41     case "debug":
42         return DEBUG, nil
43     case "info":
44         return INFO, nil
45     case "warning":
46         return WARNING, nil
47     case "error":
48         return ERROR, nil
49     case "fatal":
50         return FATAL, nil
51     default:
52         err := errors.New("无效的日志级别")
53         return UNKNOWN, err
54     }
55 }
56 
57 // 将整形转换成等级字符串 uint16 -> string
58 func unparseLogLevel(level logLevel) string {
59     switch level {
60     case DEBUG:
61         return "DEBUG"
62     case TRACE:
63         return "TRACE"
64     case INFO:
65         return "INFO"
66     case WARNING:
67         return "WARNING"
68     case ERROR:
69         return "ERROR"
70     case FATAL:
71         return "FATAl"
72     default:
73         return "DEBUG"
74     }
75 }
76 
77 // 调用runtime.Caller获取调用log打印的具体代码位置
78 func getInfo(skip int) (funcName, fileName string, lineNo int) {
79     pc, file, lineNo, ok := runtime.Caller(skip)
80     if !ok {
81         fmt.Println("runtime.Caller() failed")
82         return
83     }
84     funcName = runtime.FuncForPC(pc).Name()
85     funcName = strings.Split(funcName, ".")[1]
86     fileName = path.Base(file)
87     return funcName, fileName, lineNo
88 }

console.go:

 1 package mylogger
 2 
 3 import (
 4     "fmt"
 5     "time"
 6 )
 7 
 8 // console log 结构体
 9 type consoleLogger struct {
10     level logLevel
11 }
12 
13 // 控制台输出log对象构造函数
14 func NewConsoleLogger(levelStr string) consoleLogger {
15     level, err := parseLogLevel(levelStr)
16     if err != nil {
17         panic(err)
18     }
19     return consoleLogger{level:level}
20 }
21 
22 // log输出公共函数
23 func (l consoleLogger) enable (level logLevel, format string, a ...interface{}) {
24     if l.level <= level {
25         // 拼接格式化字符串,格式化可有可无
26         msg := fmt.Sprintf(format, a...)
27         now := time.Now()
28         levelStr := unparseLogLevel(level)
29         funcName, fileName, lineNo := getInfo(3)
30         fmt.Printf("[%s] [%s] [%s:%s:%d] %s\n",now.Format("2006-01-02 15:04:05"), levelStr, fileName, funcName, lineNo, msg)
31     }
32 }
33 
34 // Debug输出
35 func (l consoleLogger) Debug (format string, a ...interface{}) {
36     l.enable(DEBUG, format, a...)
37 }
38 
39 // Trace
40 func (l consoleLogger) Trace (format string, a ...interface{}) {
41     l.enable(TRACE, format, a...)
42 }
43 
44 // Info
45 func (l consoleLogger) Info (format string, a ...interface{}) {
46     l.enable(INFO, format, a...)
47 }
48 
49 // Warning
50 func (l consoleLogger) Warning (format string, a ...interface{}) {
51     l.enable(WARNING, format, a...)
52 }
53 
54 // Error
55 func (l consoleLogger) Error (format string, a ...interface{}) {
56     l.enable(ERROR, format, a...)
57 }
58 
59 // Fatal
60 func (l consoleLogger) Fatal (format string, a ...interface{}) {
61     l.enable(FATAL, format, a...)
62 }

writeFile.go:

  1 package mylogger
  2 
  3 import (
  4     "fmt"
  5     "os"
  6     "path"
  7     "time"
  8 )
  9 
 10 // file log结构体
 11 type fileLogger struct {
 12     level          logLevel
 13     filePath     string
 14     fileName     string
 15     fileObj        *os.File
 16     errfileObj  *os.File
 17     maxFileSize int64
 18 }
 19 
 20 // 文件日志对象构造函数
 21 func NewFileLogger(levelStr, fp, fn string, maxsize int64) *fileLogger {
 22     level, err := parseLogLevel(levelStr)
 23     if err != nil {
 24         panic(err)
 25     }
 26     f1 := &fileLogger{level:level, filePath:fp, fileName:fn, maxFileSize:maxsize}
 27     err = f1.initFile()
 28     if err != nil {
 29         panic(err)
 30     }
 31     return f1
 32 }
 33 
 34 // 初始化打开日志文件并赋值给file log结构体
 35 func (f *fileLogger) initFile() error {
 36     fileObj, err1 := os.OpenFile(path.Join(f.filePath, f.fileName), os.O_WRONLY | os.O_CREATE | os.O_APPEND, 0644)
 37     if err1 != nil {
 38         fmt.Printf("open log file failed, err:%v\n", err1)
 39         return err1
 40     }
 41     f.fileObj = fileObj
 42 
 43     errfileObj, err2 := os.OpenFile(path.Join(f.filePath, fmt.Sprintf("%s.error", f.fileName)), os.O_WRONLY | os.O_CREATE | os.O_APPEND, 0644)
 44     //errfileObj, err2 := os.OpenFile(path.Join(f.filePath, "error", f.fileName), os.O_WRONLY | os.O_CREATE | os.O_APPEND, 0644)
 45     if err2 != nil {
 46         fmt.Printf("open error log file failed, err:%v\n", err2)
 47         return err2
 48     }
 49     f.errfileObj = errfileObj
 50     return nil
 51 }
 52 
 53 // 关闭文件
 54 func (f *fileLogger) Close() {
 55     f.fileObj.Close()
 56     f.errfileObj.Close()
 57 }
 58 
 59 // 切割文件函数
 60 func (l *fileLogger) isCuttingFile(f *os.File) (*os.File, error) {
 61     fileInfo, err := f.Stat()
 62     if err != nil {
 63         fmt.Printf("get file info failed, err:%v\n", err)
 64         return f, nil
 65     }
 66     if fileInfo.Size() >= l.maxFileSize {
 67         LogName := path.Join(l.filePath, fileInfo.Name())
 68         newLogName := fmt.Sprintf("%s.bak%s", LogName, time.Now().Format("20060102150405"))
 69         // 关闭文件
 70         f.Close()
 71         // 给原文件重命名
 72         os.Rename(LogName, newLogName)
 73         // 设置为新的文件操作符
 74         fileObj, err := os.OpenFile(LogName, os.O_WRONLY | os.O_CREATE | os.O_APPEND, 0644)
 75         if err != nil {
 76             fmt.Printf("open new file failed, err:%v", err)
 77             return nil, err
 78         }
 79         return fileObj, nil
 80     }
 81     return f, nil
 82 }
 83 
 84 // log输出公共函数
 85 func (l *fileLogger) enable (level logLevel, format string, a ...interface{}) {
 86     if l.level <= level {
 87         // 拼接格式化字符串,格式化可有可无
 88         msg := fmt.Sprintf(format, a...)
 89         now := time.Now()
 90         levelStr := unparseLogLevel(level)
 91         funcName, fileName, lineNo := getInfo(3)
 92         // 切割文件
 93         fileObj, err := l.isCuttingFile(l.fileObj)
 94         if err != nil {
 95             panic(err)
 96         }
 97         l.fileObj = fileObj
 98         fmt.Fprintf(l.fileObj, "[%s] [%s] [%s:%s:%d] %s\n",now.Format("2006-01-02 15:04:05"), levelStr, fileName, funcName, lineNo, msg)
 99         //如果等级 >= Warning,写入日志到errFile
100         if level >= WARNING {
101             fileObj, err := l.isCuttingFile(l.errfileObj)
102             if err != nil {
103                 panic(err)
104             }
105             l.errfileObj = fileObj
106             fmt.Fprintf(l.errfileObj, "[%s] [%s] [%s:%s:%d] %s\n",now.Format("2006-01-02 15:04:05"), levelStr, fileName, funcName, lineNo, msg)
107         }
108     }
109 }
110 
111 // Debug输出
112 func (l *fileLogger) Debug (format string, a ...interface{}) {
113     l.enable(DEBUG, format, a...)
114 }
115 
116 // Trace
117 func (l *fileLogger) Trace (format string, a ...interface{}) {
118     l.enable(TRACE, format, a...)
119 }
120 
121 // Info
122 func (l *fileLogger) Info (format string, a ...interface{}) {
123     l.enable(INFO, format, a...)
124 }
125 
126 // Warning
127 func (l *fileLogger) Warning (format string, a ...interface{}) {
128     l.enable(WARNING, format, a...)
129 }
130 
131 // Error
132 func (l *fileLogger) Error (format string, a ...interface{}) {
133     l.enable(ERROR, format, a...)
134 }
135 
136 // Fatal
137 func (l *fileLogger) Fatal (format string, a ...interface{}) {
138     l.enable(FATAL, format, a...)
139 }

简单使用:

 1 package main
 2 
 3 import (
 4     mylogger "utils/mylogger"
 5     "time"
 6 )
 7 
 8 var logger mylogger.Logger
 9 
10 func main() {
11     // console
12     logger = mylogger.NewConsoleLogger("info")
13     // file
14     //logger := mylogger.NewFileLogger("Info", "/home/xxx/logs/gologs", "2021-11-11.log", 500*1024*1024)
15     for {
16         logger.Trace("这是一条trace记录")
17         logger.Debug("这是一条debug记录")
18         logger.Info("这是一条info记录")
19         // format string
20         name := "唐僧"
21         logger.Warning("%s说:这是一条warning记录", name)
22         logger.Error("这是一条error记录")
23         logger.Fatal("这是一条fatal记录")
24         time.Sleep(time.Second)
25     }
26 }

 


  • 作者:合十
  • 发表时间:2021年11月25日 16:09
  • 更新时间:2024年4月20日 08:04
  • 所属分类:GO语言

Comments

该文章还未收到评论,点击下方评论框开始评论吧~