Easy configuration with minor dependencies
- manual user log with default name trace.log
- auto gin middleware log with default name access.log
- auto gorm middleware log with default name db.log
- enabled color for screen
- disabled in log file
- 7 files for trace.log/access.log/db.log by default
- Centralized warn/error/fatal level to error.log
- Seperated logs for user/gin/gorm to trace.log/access.log/db.log
- link log point to alive log files, it's handy when using tail command
go get -u github.com/justin-ren/xlogrus
//log engine
"github.com/sirupsen/logrus"
//loop log
"github.com/lestrrat-go/file-rotatelogs"
//hook for log file
"github.com/rifflock/lfshook"
//log format
"github.com/x-cray/logrus-prefixed-formatter"
- example code
package main
import (
"fmt"
uLog "github.com/justin-ren/xlogrus/user"
"github.com/pkg/errors"
)
func main() {
opt := uLog.GetOpt()
//path must end with '/', default path is './logs/'
opt.LogPath = "/tmp/logs/"
//below log full name is user.log.20230212, default is trace.log
opt.FileNamePrefix = "user.log"
lg, err := uLog.New(opt)
if err != nil {
fmt.Printf("%+v\n", errors.Cause(err))
panic(err)
}
//below log would be saved in user.log with timestamp %Y%m and keep 7 files by default
//so automatically keep 7 days logs
//To modify count of loop files by opt.KeepCount
lg.Debugln("debug msg")
lg.Infoln("info msg")
//below log level would be saved in error.log with timestamp %Y%m and keep 7 files by default`
//so automatically keep 7 months logs
lg.Warnln("warn msg")
lg.Errorln("error msg")
lg.Fatalf("%+v", errors.New("error stack")) //save error stack to log files
}
$ cat /tmp/logs/user.log
[2023-02-14 08:09:58.682854] DEBUG debug msg
[2023-02-14 08:09:58.683414] INFO info msg
[2023-02-14 08:09:58.683469] WARN warn msg
[2023-02-14 08:09:58.683670] ERROR error msg
[2023-02-14 08:09:58.683842] FATAL error stack
main.main
/home/renxiong/projects/goTest/xlogrus-example/user.go:32
runtime.main
/usr/local/go/src/runtime/proc.go:250
runtime.goexit
/usr/local/go/src/runtime/asm_amd64.s:1598
$ cat /tmp/logs/error.log
[2023-02-13 23:35:15.254703] ERROR Error Log
[2023-02-14 08:09:58.683469] WARN warn msg
[2023-02-14 08:09:58.683670] ERROR error msg
[2023-02-14 08:09:58.683842] FATAL error stack
main.main
/home/renxiong/projects/goTest/xlogrus-example/user.go:32
runtime.main
/usr/local/go/src/runtime/proc.go:250
runtime.goexit
/usr/local/go/src/runtime/asm_amd64.s:1598
- example code
func main() {
opt := GinLog.GetOpt()
//path must end with '/',default is ./logs/
opt.OptLogrus.LogPath = "/tmp/logs/"
//full name of loop logs will be gin.log.202302013,default is access.log
opt.OptLogrus.FileNamePrefix = "gin.log"
//timestamp of log file is defined as following
//"%Y%m%d" is default
//opt.OptLogrus.FileNameSuffixTimeFormat = "%Y%m%d"
//will not log info for route /skip
opt.SkipRoute = map[string]struct{}{
"/skip": {},
}
//keep cut of loop log is defined here
//7 is default
//opt.OptLogrus.KeepCount = 7
_, gLog, err := GinLog.New(opt)
r := gin.New()
r.Use(gLog, gin.Recovery())
rLog := r.Group("log")
rLog.GET("/hello", func(ctx *gin.Context) {
ctx.JSON(http.StatusOK, gin.H{"msg": "hello"})
})
rLog.GET("/skip", func(ctx *gin.Context) {
ctx.JSON(http.StatusOK, gin.H{"msg": "ignored"})
})
err = r.Run(":8080")
if err != nil {
panic(errors.Cause(err))
return
}
}
$ curl localhost:8080/hello
404 page not found$ curl localhost:8080/log/hello
{"msg":"hello"}$ curl localhost:8080/log/skip
{"msg":"ignored"}$ ls -lrt /tmp/logs/
total 12
-rw-r--r-- 1 renxiong renxiong 405 Feb 14 08:09 user.log.20230214
lrwxrwxrwx 1 renxiong renxiong 17 Feb 14 08:09 user.log -> user.log.20230214
lrwxrwxrwx 1 renxiong renxiong 16 Feb 14 09:13 gin.log -> gin.log.20230214
-rw-r--r-- 1 renxiong renxiong 482 Feb 14 09:13 error.log.202302
lrwxrwxrwx 1 renxiong renxiong 16 Feb 14 09:13 error.log -> error.log.202302
-rw-r--r-- 1 renxiong renxiong 379 Feb 14 09:15 gin.log.20230214
$ cat /tmp/logs/gin.log
[2023-02-14 09:13:21.370334] WARN clientIP=127.0.0.1 dataLength=-1 latency=264ns method=GET path=/hello statusCode=404
[2023-02-14 09:14:59.056411] INFO clientIP=127.0.0.1 dataLength=15 latency=1.070547ms method=GET path=/log/hello statusCode=200
[2023-02-14 09:15:26.864735] INFO clientIP=127.0.0.1 dataLength=17 latency=32.015µs method=GET path=/log/skip statusCode=200
$ cat /tmp/logs/error.log | grep clientIP
[2023-02-14 09:13:21.370334] WARN clientIP=127.0.0.1 dataLength=-1 latency=264ns method=GET path=/hello statusCode=404
$ cat /tmp/logs/error.log | tail -1
[2023-02-14 09:13:21.370334] WARN clientIP=127.0.0.1 dataLength=-1 latency=264ns method=GET path=/hello statusCode=404
$
- example code
package main
import (
"github.com/gin-gonic/gin"
"github.com/pkg/errors"
"net/http"
// GinLog gin middleware auto log
GinLog "github.com/justin-ren/xlogrus/gin"
)
func main() {
opt := GinLog.GetOpt()
//path must end with '/',default is ./logs/
opt.OptLogrus.LogPath = "/tmp/logs/"
//full name of loop logs will be gin.log.202302013,default is access.log
opt.OptLogrus.FileNamePrefix = "gin.log"
//timestamp of log file is defined as following
//"%Y%m%d" is default
opt.OptLogrus.FileNameSuffixTimeFormat = "%Y%m%d"
//will not log info for route /skip
opt.SkipRoute = map[string]struct{}{
"/skip": {},
}
//keep cut of loop log is defined here
//7 is default
opt.OptLogrus.KeepCount = 7
_, gLog, err := GinLog.New(opt)
r := gin.New()
r.Use(gLog, gin.Recovery())
rLog := r.Group("log")
rLog.GET("/hello", func(ctx *gin.Context) {
ctx.JSON(http.StatusOK, gin.H{"msg": "hello"})
})
rLog.GET("/skip", func(ctx *gin.Context) {
ctx.JSON(http.StatusOK, gin.H{"msg": "ignored"})
})
err = r.Run(":8080")
if err != nil {
panic(errors.Cause(err))
return
}
}
$ cat /tmp/logs/gorm.log
[2023-02-14 09:45:43.169051] ERROR elapsed=0.150981 err=no such table: not_existing_tables from=/home/renxiong/projects/goTest/xlogrus-example/gorm.go:56 rows=0 sql=INSERT INTO `not_existing_tables` DEFAULT VALUES
$ cat /tmp/logs/error.log | tail -1
[2023-02-14 09:45:43.169051] ERROR elapsed=0.150981 err=no such table: not_existing_tables from=/home/renxiong/projects/goTest/xlogrus-example/gorm.go:56 rows=0 sql=INSERT INTO `not_existing_tables` DEFAULT VALUES