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) }
备注
- 缺少的功能:
- 异步写盘
- 日志切分