gin
gin框架是款高性能的GoWeb框架,可以快速开发部署api服务。在使用过程中我们需要记录各种各样的日志,下面介绍下我们怎么自定义日志记录格式或扩展日志。
gin简单剖析
api服务创建
package main
import "github.com/gin-gonic/gin"
func main() {
r := gin.Default()
r.GET("/ping", func(c *gin.context) {
c.JSON(200, gin.H{
"message": "pong",
})
})
r.Run() // listen and serve on 0.0.0.0:8080
}
以上是github中官方介绍的一个简单的demo,三步创建了一个api服务
gin.Default 获取到一个Engine实例
engine.GET() 添加一个Get请求的路由逻辑
engine.Run() 启动服务
gin.Default 剖析
func New() *Engine {
debugprintWARNINGNew()
engine := &Engine{
RouterGroup: RouterGroup{
handlers: nil,
basePath: "/",
root: true,
},
FuncMap: template.FuncMap{},
RedirectTrailingSlash: true,
RedirectFixedPath: false,
HandleMethodNotAllowed: false,
ForwardedByClientIP: true,
APPEngine: defaultAppEngine,
UseRawPath: false,
UnescapePathValues: true,
trees: make(methodTrees, 0, 9),
delims: render.Delims{"{{", "}}"},
}
engine.RouterGroup.engine = engine
engine.pool.New = func() interface{} {
return engine.allocateContext()
}
return engine
}
// Default returns an Engine instance with the Logger and Recovery middleware already attached.
func Default() *Engine {
engine := New()
engine.Use(Logger(), Recovery())
return engine
}
gin.Default 通过New创建了Engine实例, 并Use了 Logger Recovery两个HandlerFunc中间件。注释也介绍了
默认返回一个引擎实例,其中包含日志记录器和崩溃恢复中间件。
那么我们是不是可以通过自己的Logger中间件来记录日志? 写到这里发现官方文档其实是有介绍的,少走弯路还是先看文档额~~不过直接看源码也没坏处,哈哈
日志中间件
func (c *Context) Next() {
c.index++
s := int8(len(c.handlers))
for ; c.index < s; c.index++ {
c.handlers[c.index](c)
}
}
gin通过循环当前的中间件处理链Handler,逐个调用中间件。
自定义日志中间件
日志记录(logrus)
logrus是第三方包,github上比较活跃,已经实现了很多常用功能,日常开发中用到的较多。
日志分割(rotatelogs)
logrus没有提供日志切分,go-file-rotatelogs可以实现linux logratate的大多数功能。
使用logrus的hook来加载github.com/lestrrat/go-file-rotatelogs 模块.每次当我们写入日志的时候,logrus都会调用go-file-rotatelogs 来判断日志是否要进行切分…
package api
import (
"github.com/gin-gonic/gin"
"os"
"fmt"
"github.com/sirupsen/logrus"
"github.com/lestrrat/go-file-rotatelogs"
"time"
"github.com/rifflock/lfshook"
)
func Logger() gin.HandlerFunc {
logClient := logrus.New()
//禁止logrus的输出
src, err := os.OpenFile(os.DevNull, os.O_append|os.O_WRONLY, os.ModeAppend)
if err!= nil{
fmt.Println("err", err)
}
logClient.Out = src
logClient.SetLevel(logrus.DebugLevel)
apiLogPath := "api.log"
logWriter, err := rotatelogs.New(
apiLogPath+".%Y-%m-%d-%H-%M.log",
rotatelogs.WithLinkName(apiLogPath), // 生成软链,指向最新日志文件
rotatelogs.WithMaxAge(7*24*time.Hour), // 文件最大保存时间
rotatelogs.WithRotationTime(24*time.Hour), // 日志切割时间间隔
)
writeMap := lfshook.WriterMap{
logrus.InfoLevel: logWriter,
logrus.FatalLevel: logWriter,
}
lfHook := lfshook.NewHook(writeMap, &logrus.JSONformatter{})
logClient.AddHook(lfHook)
return func (c *gin.Context) {
// 开始时间
start := time.Now()
// 处理请求
c.Next()
// 结束时间
end := time.Now()
//执行时间
latency := end.Sub(start)
path := c.request.URL.Path
clientIP := c.ClientIP()
method := c.Request.Method
statusCode := c.Writer.Status()
logClient.Infof("| %3d | %13v | %15s | %s %s |",
statusCode,
latency,
clientIP,
method, path,
)
}
}
注:
// Next should be used only inside middleware.
// It executes the pending handlers in the chain inside the calling handler.
// See example in GitHub.
func (c *Context) Next() {
c.index++
s := int8(len(c.handlers))
for ; c.index < s; c.index++ {
c.handlers[c.index](c)
}
}
这里面为了计算程序的执行时长, 我们又调用了一次c.Next(),让后面的中间件执行,这样日志中间件拿到了程序其它所有中间件执行的总时长,认为是程序的处理时间。
c.Next循环的时候都是同一个Context指针上下文,index下标为共享的数据,我们可以通过调用一次c.Next让log中间件插一脚。
相关阅读
originpro 2017也就是OriginLab OriginPro 2017,是一款非常专业的函数绘图软件,是各科学科的研究人员最好的帮手。它既可以根据数据
CREATE模型可以告诉你产品需要满足什么样的需求或者用户放弃使用的原因在哪里,通过不断的分析提炼,教你诊断和修复产品中的问题。用
SSM框架SpringMVC@Scheduled注解简单实现定时任务
第一步: 在Springmvc的xml中加入如下:xmlns:task="http://www.springframework.org/schema/task"http://www.springfr
nginx是什么? nginx是俄罗斯人 Igor Sysoev为俄罗斯访问量第二的Rambler.ru站点开发的一个十分轻量级的HTTP服务器。它是一个高性
MVC模式(三层架构模式)三层作用:1.视图:视图是用户看到并与之交互的界面。对老式的Web应用程序来说,视图就是由HTML元素组成的界面,在新