日誌項目
日誌庫需求分析
-
日誌庫產生的背景
- 程序運行是個黑盒
- 日誌是程序之外的表現
- 通過日誌,可以知道程序的健康狀態
-
日誌打印的級別
- 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)
}
備註
- 缺少的功能:
- 異步寫盤
- 日誌切分