gin学习之logger篇

Logger模块详解

Logger 模块最终以 HandlerFunc 函数对象的形式(Logger 处理中间件)提供给其他模块使用。

LoggerConfig类型

LoggerConfig 是创建 HandlerFunc 对象的重要参数类型。

类型定义

type LoggerConfig struct {
    // 默认为gin.defaultLogFormatter
    Formatter LogFormatter

    // 日志写到哪里去,默认为gin.DefaultWriter
    Output io.Writer

    // 哪些URL路径的日志不用记录
    SkipPaths []string
}

LogFormatter

LogFormatter 是一个函数类型,用于格式化日志,参数类型为 LogFormatterParams

函数原型

type LogFormatter func(params LogFormatterParams) string

LogFormatterParams

当使用 LogFormatter 格式化日志时,LogFormatterParams 作为参数传入。

defaultLogFormatter变量

defaultLogFormatter是一个默认的日志数据的格式化函数

var defaultLogFormatter = func(param LogFormatterParams) string {
    // 获取颜色码
    var statusColor, methodColor, resetColor string
    if param.IsOutputColor() {
        statusColor = param.StatusCodeColor()
        methodColor = param.MethodColor()
        resetColor = param.ResetColor()
    }
    // 处理请求超过一分钟,将处理请求时间对秒取整
    if param.Latency > time.Minute {
        // Truncate in a golang < 1.8 safe way
        param.Latency = param.Latency - param.Latency%time.Second
    }
    // 日志数据格式化
    return fmt.Sprintf("[GIN] %v |%s %3d %s| %13v | %15s |%s %-7s %s %s\n%s",
        param.TimeStamp.Format("2006/01/02 - 15:04:05"),
        statusColor, param.StatusCode, resetColor,
        param.Latency,
        param.ClientIP,
        methodColor, param.Method, resetColor,
        param.Path,
        param.ErrorMessage,
    )
}

DefaultWriter

DefaultWriter为默认的Logger Writer。

var DefaultWriter io.Writer = os.Stdout

DefaultErrorWriter

DefaultErrorWriter为默认的Error Writer。

// DefaultErrorWriter is the default io.Writer used by Gin to debug errors
var DefaultErrorWriter io.Writer = os.Stderr

创建HandlerFunc(Logger处理中间件)

gin提供几个函数:具有指定的日志格式函数的日志处理中间件。

类型定义

type HandlerFunc func(*Context)

Context类型见gin学习之Context篇

函数原型

// 基础函数定义
func LoggerWithConfig(conf LoggerConfig) HandlerFunc

// 封装函数定义
func LoggerWithWriter(out io.Writer, notlogged ...string) HandlerFunc
func LoggerWithFormatter(f LogFormatter) HandlerFunc
func Logger() HandlerFunc
func ErrorLoggerT(typ ErrorType) HandlerFunc
func ErrorLogger() HandlerFunc

详细代码分析

通过LoggerWithConfig()返回一个Logger处理中间件,传入自定义LoggerConfig参数。

func LoggerWithConfig(conf LoggerConfig) HandlerFunc {
    // 配置Logger的formatter
    formatter := conf.Formatter
    if formatter == nil {
        formatter = defaultLogFormatter
    }

    // 配置Logger的output
    out := conf.Output
    if out == nil {
        out = DefaultWriter
    }

    // 配置Logger的notlogged(忽略一些处理URL路径下请求的日志)
    notlogged := conf.SkipPaths

    // 先默认日志输出目的地为终端设备
    isTerm := true

    // 判断日志输出目的地是否为终端
    if w, ok := out.(*os.File); !ok || os.Getenv("TERM") == "dumb" ||
        (!isatty.IsTerminal(w.Fd()) && !isatty.IsCygwinTerminal(w.Fd())) {
        isTerm = false
    }

    var skip map[string]struct{}

    // 处理notlogged
    if length := len(notlogged); length > 0 {
        skip = make(map[string]struct{}, length)

        for _, path := range notlogged {
            skip[path] = struct{}{}
        }
    }

    // 基于gin.Context返回日志格式化的中间件处理函数
    // gin.Context详解见gin学习之context
    return func(c *Context) {
        // Start timer
        start := time.Now()
        path := c.Request.URL.Path
        raw := c.Request.URL.RawQuery

        // Process request
        c.Next()

        // 当前请求的path不跳过,才会记录日志
        if _, ok := skip[path]; !ok {
            // 填充LogFormatterParams结构
            param := LogFormatterParams{
                Request: c.Request,
                isTerm:  isTerm,
                Keys:    c.Keys,
            }

            // Stop timer
            param.TimeStamp = time.Now()
            param.Latency = param.TimeStamp.Sub(start)

            param.ClientIP = c.ClientIP()
            param.Method = c.Request.Method
            param.StatusCode = c.Writer.Status()
            // errors处理见gin学习之errors
            param.ErrorMessage = c.Errors.ByType(ErrorTypePrivate).String()

            param.BodySize = c.Writer.Size()

            if raw != "" {
                path = path + "?" + raw
            }

            param.Path = path

            // type LogFormatter func(params LogFormatterParams) string
            // 调用formatter函数(类型为LogFormatter),得到格式化日志,并输出到out
            fmt.Fprint(out, formatter(param))
        }
    }
}

通过Logger()返回一个Logger处理中间件,使用默认配置参数。

// writer=gin.DefaultWriter(os.Stdout), formatter=gin.defaultLogFormatter
func Logger() HandlerFunc {
    return LoggerWithConfig(LoggerConfig{})
}

通过LoggerWithFormatter()获得Logger处理中间件,传入LogFormatter参数。

func LoggerWithFormatter(f LogFormatter) HandlerFunc {
    return LoggerWithConfig(LoggerConfig{
        Formatter: f,
    })
}

通过LoggerWithWriter()获得Logger处理中间件,传入自定义writer和notlogged(忽略一些处理URL路径下请求的日志)。

func LoggerWithWriter(out io.Writer, notlogged ...string) HandlerFunc HandlerFunc {
    return LoggerWithConfig(LoggerConfig{
        Output:    out,
        SkipPaths: notlogged,
    })
}

通过ErrorLogger()返回一个Logger处理中间件。

func ErrorLogger() HandlerFunc {
    return ErrorLoggerT(ErrorTypeAny)
}

通过ErrorLoggerT()返回一个Logger处理中间件。

func ErrorLoggerT(typ ErrorType) HandlerFunc {
    return func(c *Context) {
        c.Next()
        errors := c.Errors.ByType(typ)
        if len(errors) > 0 {
            c.JSON(-1, errors)
        }
    }
}

Logger运行机制

所有 HandlerFunc 对象都会注册挂载到 Engine.RouterGroup.Handlers 上面。

func (engine *Engine) Use(middleware ...HandlerFunc) IRoutes {
    engine.RouterGroup.Use(middleware...)
    // ...... 
}

func (group *RouterGroup) Use(middleware ...HandlerFunc) IRoutes {
    group.Handlers = append(group.Handlers, middleware...)
    return group.returnObj()
}

Logger机制使用举例如下

// new一个io.Writer,作为日志的输出目的地
buffer := new(bytes.Buffer)

// 创建一个Engine对象(router)
router := New()

// 向router注册一个日志处理中间件
router.Use(LoggerWithConfig(LoggerConfig{Output: buffer}))

其他方法

// 禁止终端日志有色显示
func DisableConsoleColor() {
    consoleColorMode = disableColor
}

// 强制终端日志有色显示
func ForceConsoleColor() {
    consoleColorMode = forceColor
}
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容