1. 程式人生 > 其它 >自定義go語言日誌輸出

自定義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 }