Go語言(十四)日誌項目

日誌項目

日誌庫需求分析

  • 日誌庫產生的背景

    • 程序運行是個黑盒
    • 日誌是程序之外的表現
    • 通過日誌,可以知道程序的健康狀態
  • 日誌打印的級別

    • Debug:日誌最詳細,對程序的影響比較大
    • Trace: 用來追蹤問題
    • Info: 比較重要的信息,比如訪問日誌
    • Warn:警告日誌,表明程序存在問題
    • Error: 錯誤日誌,運行程序時發生的錯誤
    • Fatal: 嚴重錯誤日誌
  • 日誌存儲的位置

    • 直接輸出到控制檯
    • 打印到文件裏
    • 直接打印到網絡中,比如kafka
  • 爲什麼使用接口

    • 定義日誌庫的標準或者規範
    • 易於擴展
    • 利於程序維護
  • 日誌庫的設計
    • 打印各個level的日誌
    • 設置級別
    • 構造函數

日誌庫接口設計

log_base.go 基類

package xlog

import (
   "fmt"
   "os"
   "path/filepath"
   "time"
)

type LogData struct {
   timeStr  string
   levelStr string
   module   string
   filename string
   funcName string
   lineNo   int
   data     string
}

type XLogBase struct {
   level   int
   module  string
}

func (l *XLogBase) writeLog(file *os.File,logData *LogData) {
   fmt.Fprintf(file,"%s %s %s (%s:%s:%d) %s\n",
      logData.timeStr, logData.levelStr, logData.module,
      logData.filename, logData.funcName, logData.lineNo, logData.data)
}

func (l *XLogBase) formatLogger(level int, module, format string, args ...interface{}) *LogData {
   now := time.Now()
   timeStr := now.Format("2006-01-02 15:04:05.000")
   levelStr := getLevelStr(level)
   filename, funcName, lineNo := GetLineInfo(3)
   filename = filepath.Base(filename)
   data := fmt.Sprintf(format, args...)
   //fmt.Printf("%s %s %s (%s:%s:%d) %s\n",timeStr,leveStr,module,filename,funcName,lineNo,data)
   return &LogData{
      timeStr:  timeStr,
      levelStr: levelStr,
      module:   module,
      filename: filename,
      funcName: funcName,
      lineNo:   lineNo,
      data:     data,
   }
}

log.go

package xlog

type XLog interface {
   Init() error   //文件初始化
   LogDebug(format string, args ...interface{})
   LogTrace(format string, args ...interface{})
   LogInfo(format string, args ...interface{})
   LogWarn(format string, args ...interface{})
   LogError(format string, args ...interface{})
   LogFatal(format string, args ...interface{})
   Close()
   SetLevel(level int)
}

func NewXLog(logType, level int, filename, module string) XLog {
   //定義接口
   var logger XLog
   switch logType {
   case XLogTypeFile:
      logger = NewXFile(level,filename, module)
   case XLogTypeConsole:
      logger = NewXConsole(level, module)
   default:
      logger = NewXFile(level,filename, module)
   }
   return logger
}

level.go

package xlog

const (
   XLogLevelDebug = iota
   XLogLevelTrace
   XLogLevelInfo
   XLogLevelWarn
   XLogLevelError
   XLogLevelFatal
)

const (
   XLogTypeFile = iota
   XLogTypeConsole
)

func getLevelStr(level int) string {
   switch level {
   case XLogLevelDebug:
      return "DEBUG"
   case XLogLevelTrace:
      return "TRACE"
   case XLogLevelInfo:
      return "INFO"
   case XLogLevelWarn:
      return "WARN"
   case XLogLevelError:
      return "ERROR"
   case XLogLevelFatal:
      return "FATAL"
   default:
      return "UNKNOWN"
   }
}

tool.go: 獲取程序運行所在行以及函數名

package xlog

import "runtime"

func GetLineInfo(skip int) (filename, funcName string, lineNo int) {
   pc, file, line, ok := runtime.Caller(skip)
   if ok {
      fun := runtime.FuncForPC(pc)
      funcName = fun.Name()
   }
   filename = file
   lineNo = line
   return
}

文件日誌庫開發

package xlog

import (
   "os"
)

type XFile struct {
   *XLogBase
   filename string
   file     *os.File
}

func (c *XFile) Init() (err error) {
   c.file,err = os.OpenFile(c.filename, os.O_APPEND|os.O_CREATE|os.O_WRONLY,0755)
   if err != nil {
      return
   }
   return
}

func NewXFile(level int, filename, module string) XLog {
   logger := &XFile{
      filename: filename,
   }
   logger.XLogBase = &XLogBase{
      module: module,
      level: level,
   }
   return logger
}

func (c *XFile) LogDebug(format string, args ...interface{}) {
   if c.level > XLogLevelDebug {
      return
   }
   logData := c.formatLogger(XLogLevelDebug, c.module, format, args...)
   c.writeLog(c.file,logData)
}
func (c *XFile) LogTrace(format string, args ...interface{}) {
   if c.level > XLogLevelTrace {
      return
   }
   logData := c.formatLogger(XLogLevelTrace, c.module, format, args...)
   c.writeLog(c.file,logData)
}
func (c *XFile) LogInfo(format string, args ...interface{}) {
   if c.level > XLogLevelInfo {
      return
   }
   logData := c.formatLogger(XLogLevelInfo, c.module, format, args...)
   c.writeLog(c.file,logData)
}
func (c *XFile) LogWarn(format string, args ...interface{}) {
   if c.level > XLogLevelWarn {
      return
   }
   logData := c.formatLogger(XLogLevelWarn, c.module, format, args...)
   c.writeLog(c.file,logData)
}
func (c *XFile) LogError(format string, args ...interface{}) {
   if c.level > XLogLevelError {
      return
   }
   logData := c.formatLogger(XLogLevelError, c.module, format, args...)
   c.writeLog(c.file,logData)
}
func (c *XFile) LogFatal(format string, args ...interface{}) {
   if c.level > XLogLevelFatal {
      return
   }
   logData := c.formatLogger(XLogLevelFatal, c.module, format, args...)
   c.writeLog(c.file,logData)
}

func (c *XFile) SetLevel(level int) {
   c.level = level
}

func (c *XFile)Close()  {
   if c.file != nil {
      c.file.Close()
   }
}

Console日誌開發

package xlog

import (
   "os"
)

type XConsole struct {
   *XLogBase   //指針實現
}

func NewXConsole(level int, module string) XLog {
   logger := &XConsole{}
   //初始化指針,防止panic
   logger.XLogBase = &XLogBase{
      level: level,
      module: module,
   }
   return logger
}

//不需要初始化文件寫入
func (c *XConsole)Init() error {
   return nil
}

func (c *XConsole) LogDebug(format string, args ...interface{}) {
   if c.level > XLogLevelDebug {
      return
   }
   logData := c.formatLogger(XLogLevelDebug, c.module, format, args...)
   c.writeLog(os.Stdout,logData)
}

func (c *XConsole) LogTrace(format string, args ...interface{}) {
   if c.level > XLogLevelTrace {
      return
   }
   logData := c.formatLogger(XLogLevelTrace, c.module, format, args...)
   c.writeLog(os.Stdout,logData)
}

func (c *XConsole) LogInfo(format string, args ...interface{}) {
   if c.level > XLogLevelInfo {
      return
   }
   logData := c.formatLogger(XLogLevelInfo, c.module, format, args...)
   c.writeLog(os.Stdout,logData)
}

func (c *XConsole) LogWarn(format string, args ...interface{}) {
   if c.level > XLogLevelWarn {
      return
   }
   logData := c.formatLogger(XLogLevelWarn, c.module, format, args...)
   c.writeLog(os.Stdout,logData)
}

func (c *XConsole) LogError(format string, args ...interface{}) {
   if c.level > XLogLevelError {
      return
   }
   logData := c.formatLogger(XLogLevelError, c.module, format, args...)
   c.writeLog(os.Stdout,logData)
}

func (c *XConsole) LogFatal(format string, args ...interface{}) {
   if c.level > XLogLevelFatal {
      return
   }
   logData := c.formatLogger(XLogLevelFatal, c.module, format, args...)
   c.writeLog(os.Stdout,logData)
}
func (c *XConsole) SetLevel(level int) {
   c.level = level
}

func (c *XConsole) Close() {}

日誌使用以及測試

xlog_example/main.go

package main

import (
   "flag"
   "fmt"
   _"fmt"
   "oldBoy/day9/xlog"
)

func logic(logger xlog.XLog) {
   logger.LogDebug("dads1,user_id:%d,username:%s",12331,"sadsaf")
   logger.LogTrace("dads2")
   logger.LogInfo("dads3")
   logger.LogWarn("dads4")
   logger.LogError("sss")
   logger.LogFatal("sss")
}
/*
func testGetLine() {
   //skip =2 深度爲2的調用位置,也就是main下的22行
   filename,funcName,lineNo := xlog.GetLineInfo(2)
   fmt.Printf("filename=%s,funcname=%s,linenum=%d\n",filename,funcName,lineNo)
}
 */
func main() {
   //testGetLine()
   var logTypeStr string
   flag.StringVar(&logTypeStr,"type","file","please input a logger type")
   flag.Parse()

   var logType int
   if (logTypeStr == "file") {
      logType = xlog.XLogTypeFile
   }else {
      logType = xlog.XLogTypeConsole
   }
   logger := xlog.NewXLog(logType,xlog.XLogLevelDebug,"./xlog.log","xlog_example")
   err := logger.Init()
   if err != nil {
      fmt.Printf("init error:%v\n",err)
      return
   }
   logic(logger)
}

備註

  • 缺少的功能:
    • 異步寫盤
    • 日誌切分
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章