一,安装用到的库:
1,安装zap日志库:
liuhongdi@ku:/data/liuhongdi/zaplog$ go get -u go.uber.org/zap
2,安装go-file-rotatelogs库
liuhongdi@ku:/data/liuhongdi/zaplog2$ go get -u github.com/lestrrat/go-file-rotatelogs
说明:刘宏缔的go森林是一个专注golang的博客,
地址:https://blog.csdn.net/weixin_43881017
说明:作者:刘宏缔 邮箱: 371125307@qq.com
二,演示项目的相关信息:
1,项目地址:
https://github.com/liuhongdi/digv06
2,功能说明:记录http服务的访问日志access log
3,项目结构:如图:
三,go代码说明
1,config/config.yaml
-
Database:
-
DBType: mysql
-
UserName: root
-
Password: password
-
Host: 127.0.0.1:3306
-
DBName: dig
-
Charset: utf8
-
ParseTime: True
-
MaxIdleConns: 10
-
MaxOpenConns: 30
-
Server:
-
RunMode: debug
-
HttpPort: 8000
-
ReadTimeout: 60
-
WriteTimeout: 60
-
Log:
-
LogFilePath: /data/gologs/logs
-
LogInfoFileName: info
-
LogWarnFileName: warn
-
LogFileExt: log
-
AccessLog:
-
LogFilePath: /data/gologs/logs
-
LogFileName: access
-
LogFileExt: log
2,global/setting.go
-
package global
-
-
import (
-
"fmt"
-
"github.com/liuhongdi/digv06/pkg/setting"
-
"time"
-
)
-
//服务器配置
-
type ServerSettingS struct {
-
RunMode string
-
HttpPort string
-
ReadTimeout time.Duration
-
WriteTimeout time.Duration
-
}
-
//数据库配置
-
type DatabaseSettingS struct {
-
DBType string
-
UserName string
-
Password string
-
Host string
-
DBName string
-
Charset string
-
ParseTime bool
-
MaxIdleConns int
-
MaxOpenConns int
-
}
-
//日志配置
-
type LogSettingS struct {
-
LogFilePath string //保存到的目录
-
LogInfoFileName string //info级日志文件的名字
-
LogWarnFileName string //warn级日志文件的名字
-
LogAccessFileName string //Access日志文件的名字
-
LogFileExt string //文件的扩展名
-
}
-
//访问日志配置
-
type AccessLogSettingS struct {
-
LogFilePath string //保存到的目录
-
LogFileName string //Access日志文件的名字
-
LogFileExt string //文件的扩展名
-
}
-
//定义全局变量
-
var (
-
ServerSetting *ServerSettingS
-
DatabaseSetting *DatabaseSettingS
-
LogSetting *LogSettingS
-
AccessLogSetting *AccessLogSettingS
-
)
-
-
//读取配置到全局变量
-
func SetupSetting() error {
-
s, err := setting.NewSetting()
-
if err != nil {
-
return err
-
}
-
err = s.ReadSection("Database", &DatabaseSetting)
-
if err != nil {
-
return err
-
}
-
-
err = s.ReadSection("Server", &ServerSetting)
-
if err != nil {
-
return err
-
}
-
-
err = s.ReadSection("Log", &LogSetting)
-
if err != nil {
-
return err
-
}
-
-
err = s.ReadSection("AccessLog", &AccessLogSetting)
-
if err != nil {
-
return err
-
}
-
-
fmt.Println("setting:")
-
fmt.Println(ServerSetting)
-
fmt.Println(DatabaseSetting)
-
fmt.Println(LogSetting)
-
fmt.Println(AccessLogSetting)
-
return nil
-
}
3,global/accessLog.go
-
package global
-
-
import (
-
"fmt"
-
"github.com/liuhongdi/digv06/pkg/setting"
-
"time"
-
)
-
//服务器配置
-
type ServerSettingS struct {
-
RunMode string
-
HttpPort string
-
ReadTimeout time.Duration
-
WriteTimeout time.Duration
-
}
-
//数据库配置
-
type DatabaseSettingS struct {
-
DBType string
-
UserName string
-
Password string
-
Host string
-
DBName string
-
Charset string
-
ParseTime bool
-
MaxIdleConns int
-
MaxOpenConns int
-
}
-
//日志配置
-
type LogSettingS struct {
-
LogFilePath string //保存到的目录
-
LogInfoFileName string //info级日志文件的名字
-
LogWarnFileName string //warn级日志文件的名字
-
LogAccessFileName string //Access日志文件的名字
-
LogFileExt string //文件的扩展名
-
}
-
//访问日志配置
-
type AccessLogSettingS struct {
-
LogFilePath string //保存到的目录
-
LogFileName string //Access日志文件的名字
-
LogFileExt string //文件的扩展名
-
}
-
//定义全局变量
-
var (
-
ServerSetting *ServerSettingS
-
DatabaseSetting *DatabaseSettingS
-
LogSetting *LogSettingS
-
AccessLogSetting *AccessLogSettingS
-
)
-
-
//读取配置到全局变量
-
func SetupSetting() error {
-
s, err := setting.NewSetting()
-
if err != nil {
-
return err
-
}
-
err = s.ReadSection("Database", &DatabaseSetting)
-
if err != nil {
-
return err
-
}
-
-
err = s.ReadSection("Server", &ServerSetting)
-
if err != nil {
-
return err
-
}
-
-
err = s.ReadSection("Log", &LogSetting)
-
if err != nil {
-
return err
-
}
-
-
err = s.ReadSection("AccessLog", &AccessLogSetting)
-
if err != nil {
-
return err
-
}
-
-
fmt.Println("setting:")
-
fmt.Println(ServerSetting)
-
fmt.Println(DatabaseSetting)
-
fmt.Println(LogSetting)
-
fmt.Println(AccessLogSetting)
-
return nil
-
}
4,middelware/accesslog.go
-
package middleware
-
-
import (
-
"bytes"
-
"github.com/liuhongdi/digv06/global"
-
"github.com/liuhongdi/digv06/pkg/util"
-
"time"
-
"github.com/gin-gonic/gin"
-
)
-
-
type AccessLogWriter struct {
-
gin.ResponseWriter
-
body *bytes.Buffer
-
}
-
-
func (w AccessLogWriter) Write(p []byte) (int, error) {
-
if n, err := w.body.Write(p); err != nil {
-
return n, err
-
}
-
return w.ResponseWriter.Write(p)
-
}
-
-
func AccessLog() gin.HandlerFunc {
-
return func(c *gin.Context) {
-
bodyWriter := &AccessLogWriter{body: bytes.NewBufferString(""), ResponseWriter: c.Writer}
-
c.Writer = bodyWriter
-
-
beginTime := time.Now().UnixNano()
-
c.Next()
-
endTime := time.Now().UnixNano()
-
duration:=endTime-beginTime
-
-
s := "%s %s "%s %s" "+
-
"%s %d %d %dµs "+
-
""%s""
-
-
layout := "2006-01-02 15:04:05"
-
timeNow := time.Now().Format(layout)
-
-
global.AccessLogger.Infof(s,
-
util.GetRealIp(c),
-
timeNow,
-
c.Request.Method,
-
c.Request.RequestURI,
-
c.Request.Proto,
-
bodyWriter.Status(),
-
bodyWriter.body.Len(),
-
duration/1000,
-
c.Request.Header.Get("User-Agent"),
-
-
);
-
}
-
}
5,pkg/zaplog/zaplog.go
-
package zaplog
-
-
import (
-
rotatelogs "github.com/lestrrat/go-file-rotatelogs"
-
"go.uber.org/zap"
-
"go.uber.org/zap/zapcore"
-
"io"
-
"time"
-
)
-
-
//get logger
-
func GetInitLogger(filepath,infofilename,warnfilename,fileext string) (*zap.SugaredLogger,error) {
-
encoder := getEncoder()
-
//两个判断日志等级的interface
-
//warnlevel以下属于info
-
infoLevel := zap.LevelEnablerFunc(func(lvl zapcore.Level) bool {
-
return lvl < zapcore.WarnLevel
-
})
-
//warnlevel及以上属于warn
-
warnLevel := zap.LevelEnablerFunc(func(lvl zapcore.Level) bool {
-
return lvl >= zapcore.WarnLevel
-
})
-
-
infoWriter,err := getLogWriter(filepath+"/"+infofilename,fileext)
-
if (err != nil) {
-
return nil,err
-
}
-
warnWriter,err2 := getLogWriter(filepath+"/"+warnfilename,fileext)
-
if (err2 != nil) {
-
return nil,err2
-
}
-
-
//创建具体的Logger
-
core := zapcore.NewTee(
-
zapcore.NewCore(encoder, infoWriter, infoLevel),
-
zapcore.NewCore(encoder, warnWriter, warnLevel),
-
)
-
loggerres := zap.New(core, zap.AddCaller())
-
-
return loggerres.Sugar(),nil
-
}
-
-
//get logger
-
func GetInitAccessLogger(filepath,filename,fileext string) (*zap.SugaredLogger,error) {
-
-
warnWriter,err2 := getLogWriter(filepath+"/"+filename,fileext)
-
if (err2 != nil) {
-
return nil,err2
-
}
-
-
var cfg zap.Config
-
cfg =zap.Config{
-
Level: zap.NewAtomicLevelAt(zap.DebugLevel),
-
Development: true,
-
Encoding: "console",
-
EncoderConfig: zapcore.EncoderConfig{
-
MessageKey: "msg",
-
},
-
OutputPaths: []string{"stdout", "./log.txt"},
-
ErrorOutputPaths: []string{"stderr"},
-
}
-
-
l, err := cfg.Build(SetOutput(warnWriter, cfg))
-
if err != nil {
-
panic(err)
-
}
-
-
return l.Sugar(),nil
-
}
-
-
-
func SetOutput(ws zapcore.WriteSyncer, conf zap.Config) zap.Option {
-
var enc zapcore.Encoder
-
switch conf.Encoding {
-
case "json":
-
enc = zapcore.NewJSONEncoder(conf.EncoderConfig)
-
case "console":
-
enc = zapcore.NewConsoleEncoder(conf.EncoderConfig)
-
default:
-
panic("unknown encoding")
-
}
-
return zap.WrapCore(func(core zapcore.Core) zapcore.Core {
-
return zapcore.NewCore(enc, ws, conf.Level)
-
})
-
}
-
-
-
//Encoder
-
func getEncoder() zapcore.Encoder {
-
encoderConfig := zap.NewProductionEncoderConfig()
-
encoderConfig.EncodeTime = zapcore.ISO8601TimeEncoder
-
encoderConfig.EncodeLevel = zapcore.CapitalLevelEncoder
-
return zapcore.NewConsoleEncoder(encoderConfig)
-
}
-
-
//LogWriter
-
func getLogWriter(filePath,fileext string) (zapcore.WriteSyncer,error) {
-
warnIoWriter,err := getWriter(filePath,fileext)
-
if (err != nil) {
-
return nil,err
-
}
-
return zapcore.AddSync(warnIoWriter),nil
-
}
-
-
//日志文件切割,按天
-
func getWriter(filename,fileext string) (io.Writer,error) {
-
// 保存30天内的日志,每24小时(整点)分割一次日志
-
hook, err := rotatelogs.New(
-
filename+"_%Y%m%d."+fileext,
-
rotatelogs.WithLinkName(filename),
-
rotatelogs.WithMaxAge(time.Hour*24*30),
-
rotatelogs.WithRotationTime(time.Hour*24),
-
)
-
/*
-
//供测试用,保存30天内的日志,每1分钟(整点)分割一次日志
-
hook, err := rotatelogs.New(
-
filename+"_%Y%m%d%H%M.log",
-
rotatelogs.WithLinkName(filename),
-
rotatelogs.WithMaxAge(time.Hour*24*30),
-
rotatelogs.WithRotationTime(time.Minute*1),
-
)
-
*/
-
if err != nil {
-
//panic(err)
-
return nil,err
-
}
-
return hook,nil
-
}
6,router/router.go
-
package router
-
-
import (
-
"github.com/gin-gonic/gin"
-
"github.com/liuhongdi/digv06/controller"
-
"github.com/liuhongdi/digv06/global"
-
"github.com/liuhongdi/digv06/middleware"
-
"github.com/liuhongdi/digv06/pkg/result"
-
"runtime/debug"
-
)
-
-
func Router() *gin.Engine {
-
router := gin.Default()
-
//处理异常
-
router.NoRoute(HandleNotFound)
-
router.NoMethod(HandleNotFound)
-
router.Use(middleware.AccessLog())
-
router.Use(Recover)
-
-
// 路径映射
-
articlec:=controller.NewArticleController()
-
router.GET("/article/getone/:id", articlec.GetOne);
-
router.GET("/article/list", articlec.GetList);
-
return router
-
}
-
-
//404
-
func HandleNotFound(c *gin.Context) {
-
global.Logger.Errorf("handle not found: %v", c.Request.RequestURI)
-
//global.Logger.Errorf("stack: %v",string(debug.Stack()))
-
result.NewResult(c).Error(404,"资源未找到")
-
return
-
}
-
-
//500
-
func Recover(c *gin.Context) {
-
defer func() {
-
if r := recover(); r != nil {
-
//打印错误堆栈信息
-
//log.Printf("panic: %v ", r)
-
global.Logger.Errorf("panic: %v", r)
-
//log stack
-
global.Logger.Errorf("stack: %v",string(debug.Stack()))
-
//print stack
-
debug.PrintStack()
-
//return
-
result.NewResult(c).Error(500,"服务器内部错误")
-
}
-
}()
-
//继续后续接口调用
-
c.Next()
-
}
7,main.go
-
package main
-
-
import (
-
"github.com/gin-gonic/gin"
-
_ "github.com/jinzhu/gorm/dialects/mysql"
-
"github.com/liuhongdi/digv06/global"
-
"github.com/liuhongdi/digv06/router"
-
"log"
-
)
-
-
//init
-
func init() {
-
//setting
-
err := global.SetupSetting()
-
if err != nil {
-
log.Fatalf("init.setupSetting err: %v", err)
-
}
-
-
//logger
-
err = global.SetupLogger()
-
if err != nil {
-
log.Fatalf("init.SetupLogger err: %v", err)
-
}
-
-
//access logger
-
err = global.SetupAccessLogger()
-
if err != nil {
-
log.Fatalf("init.SetupAccessLogger err: %v", err)
-
}
-
-
//db
-
err = global.SetupDBLink()
-
if err != nil {
-
log.Fatalf("init.SetupLogger err: %v", err)
-
global.Logger.Fatalf("init.setupDBEngine err: %v", err)
-
}
-
-
global.Logger.Infof("------应用init结束")
-
//global.Logger.
-
}
-
-
func main() {
-
global.Logger.Infof("------应用main函数开始")
-
//设置运行模式
-
gin.SetMode(global.ServerSetting.RunMode)
-
//引入路由
-
r := router.Router()
-
//run
-
r.Run(":"+global.ServerSetting.HttpPort)
-
}
8,其他代码请参见github
四,测试效果
访问url:
http://127.0.0.1:8000/article/getone/1
然后查看日志:
-
root@ku:/data/gologs/logs# more access_20201216.log
-
127.0.0.1 2020-12-16 15:41:08 "GET /article/getone/1" HTTP/1.1 200 571 13710µs "Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:83.0) Gecko/20100101 Firefox/83.0"
-
127.0.0.1 2020-12-16 15:41:11 "GET /article/getone/1" HTTP/1.1 200 571 2162µs "Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:83.0) Gecko/20100101 Firefox/83.0"
-
127.0.0.1 2020-12-16 15:41:16 "GET /article/getone/100" HTTP/1.1 200 52 770µs "Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:83.0) Gecko/20100101 Firefox/83.0"
五,查看各个库的版本:
-
module github.com/liuhongdi/digv06
-
-
go 1.15
-
-
require (
-
github.com/gin-gonic/gin v1.6.3
-
github.com/go-playground/universal-translator v0.17.0
-
github.com/go-playground/validator/v10 v10.2.0
-
github.com/jinzhu/gorm v1.9.16
-
github.com/lestrrat/go-file-rotatelogs v0.0.0-20180223000712-d3151e2a480f
-
github.com/lestrrat/go-strftime v0.0.0-20180220042222-ba3bf9c1d042 // indirect
-
github.com/magiconair/properties v1.8.4 // indirect
-
github.com/mitchellh/mapstructure v1.3.3 // indirect
-
github.com/pelletier/go-toml v1.8.1 // indirect
-
github.com/pkg/errors v0.9.1 // indirect
-
github.com/spf13/afero v1.4.1 // indirect
-
github.com/spf13/cast v1.3.1 // indirect
-
github.com/spf13/jwalterweatherman v1.1.0 // indirect
-
github.com/spf13/pflag v1.0.5 // indirect
-
github.com/spf13/viper v1.7.1
-
go.uber.org/multierr v1.6.0 // indirect
-
go.uber.org/zap v1.16.0
-
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68 // indirect
-
golang.org/x/text v0.3.4 // indirect
-
gopkg.in/ini.v1 v1.62.0 // indirect
-
gopkg.in/yaml.v2 v2.3.0 // indirect
-
)