分享
  1. 首页
  2. 文章

Go语言(十四)日志项目

wx5b285b48ed74e · · 1392 次点击 · · 开始浏览
这是一个创建于 的文章,其中的信息可能已经有所发展或是发生改变。

日志项目

日志库需求分析

  • 日志库产生的背景

    • 程序运行是个黑盒
    • 日志是程序之外的表现
    • 通过日志,可以知道程序的健康状态
  • 日志打印的级别

    • 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)
}

备注

  • 缺少的功能:
    • 异步写盘
    • 日志切分

有疑问加站长微信联系(非本文作者)

本文来自:51CTO博客

感谢作者:wx5b285b48ed74e

查看原文:Go语言(十四)日志项目

入群交流(和以上内容无关):加入Go大咖交流群,或添加微信:liuxiaoyan-s 备注:入群;或加QQ群:692541889

关注微信
1392 次点击
1 回复 | 直到 2020年04月22日 18:25:43
暂无回复
添加一条新回复 (您需要 后才能回复 没有账号 ?)
  • 请尽量让自己的回复能够对别人有帮助
  • 支持 Markdown 格式, **粗体**、~~删除线~~、`单行代码`
  • 支持 @ 本站用户;支持表情(输入 : 提示),见 Emoji cheat sheet
  • 图片支持拖拽、截图粘贴等方式上传

用户登录

没有账号?注册
(追記) (追記ここまで)

今日阅读排行

    加载中
(追記) (追記ここまで)

一周阅读排行

    加载中

关注我

  • 扫码关注领全套学习资料 关注微信公众号
  • 加入 QQ 群:
    • 192706294(已满)
    • 731990104(已满)
    • 798786647(已满)
    • 729884609(已满)
    • 977810755(已满)
    • 815126783(已满)
    • 812540095(已满)
    • 1006366459(已满)
    • 692541889

  • 关注微信公众号
  • 加入微信群:liuxiaoyan-s,备注入群
  • 也欢迎加入知识星球 Go粉丝们(免费)

给该专栏投稿 写篇新文章

每篇文章有总共有 5 次投稿机会

收入到我管理的专栏 新建专栏