zoukankan      html  css  js  c++  java
  • 自定义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 }
  • 相关阅读:
    0x00 Java 研习录
    0x00 Linux From Scratch 实战
    第一章:Java编程入门
    陈洋总结
    pthread_detach
    explicit用法
    Java动态加载DLL方法
    ToolHelp32 函数
    android根据子view里面的数量自动排版的一个ViewGroup
    安装CocoaPods学习
  • 原文地址:https://www.cnblogs.com/zzmx0/p/15603156.html
Copyright © 2011-2022 走看看