一,官方文档:
地址
https://gorm.io/zh_CN/docs/logger.html
参考的gorm logger代码实现:
https://github.com/go-gorm/gorm/blob/master/logger/logger.go
自定义日志需要实现的接口:
type Interface interface {
LogMode(LogLevel) Interface
Info(context.Context, string, ...interface{})
Warn(context.Context, string, ...interface{})
Error(context.Context, string, ...interface{})
Trace(ctx context.Context, begin time.Time, fc func() (sql string, rowsAffected int64), err error)
}
二,代码例子:
1,自定义日志类:
package gormfilelogger
import (
"bytes"
"context"
"errors"
"fmt"
gormlogger "gorm.io/gorm/logger"
"gorm.io/gorm/utils"
"log"
"os"
"runtime"
"strings"
"time"
)
const (
Reset = "\033[0m"
Red = "\033[31m"
Green = "\033[32m"
Yellow = "\033[33m"
Blue = "\033[34m"
Magenta = "\033[35m"
Cyan = "\033[36m"
White = "\033[37m"
BlueBold = "\033[34;1m"
MagentaBold = "\033[35;1m"
RedBold = "\033[31;1m"
YellowBold = "\033[33;1m"
)
const (
// Silent silent log level
Silent gormlogger.LogLevel = iota + 1
// Error error log level
Error
// Warn warn log level
Warn
// Info info log level
Info
)
//gorm原日志的配置
type FileLogConfig struct {
gormlogger.Config
}
//定义日志类
type StdFileLogger struct {
FileLogConfig
infoStr, warnStr, errStr string
traceStr, traceErrStr, traceWarnStr string
path,name string
}
//初始化,区分有颜色和无颜色
func NewStdFileLogger(config FileLogConfig,path,name string) *StdFileLogger {
var (
infoStr = "%s\n[info] "
warnStr = "%s\n[warn] "
errStr = "%s\n[error] "
traceStr = "%s\n[%.3fms] [rows:%v] %s"
traceWarnStr = "%s %s\n[%.3fms] [rows:%v] %s"
traceErrStr = "%s %s\n[%.3fms] [rows:%v] %s"
)
if config.Colorful {
infoStr = Green + "%s\n" + Reset + Green + "[info] " + Reset
warnStr = BlueBold + "%s\n" + Reset + Magenta + "[warn] " + Reset
errStr = Magenta + "%s\n" + Reset + Red + "[error] " + Reset
traceStr = Green + "%s\n" + Reset + Yellow + "[%.3fms] " + BlueBold + "[rows:%v]" + Reset + " %s"
traceWarnStr = Green + "%s " + Yellow + "%s\n" + Reset + RedBold + "[%.3fms] " + Yellow + "[rows:%v]" + Magenta + " %s" + Reset
traceErrStr = RedBold + "%s " + MagentaBold + "%s\n" + Reset + Yellow + "[%.3fms] " + BlueBold + "[rows:%v]" + Reset + " %s"
}
return &StdFileLogger{
FileLogConfig: config,
path:path,
name:name,
//Loggers: loggers,
infoStr: infoStr,
warnStr: warnStr,
errStr: errStr,
traceStr: traceStr,
traceWarnStr: traceWarnStr,
traceErrStr: traceErrStr,
}
}
func (logger *StdFileLogger) printf(msg string, data ...interface{}) {
//得到要打印的内容
content:=fmt.Sprintf(msg, data...)
//打印到控制台
log.Printf(content)
//得到文件名:
now := time.Now()
dateStr:=now.Format("2006-01-02")
filePath := logger.path+"/"+logger.name+"_"+dateStr+".log"
// 替换掉彩色打印符号
content = strings.ReplaceAll(content, Reset, "")
content = strings.ReplaceAll(content, Red, "")
content = strings.ReplaceAll(content, Green, "")
content = strings.ReplaceAll(content, Yellow, "")
content = strings.ReplaceAll(content, Blue, "")
content = strings.ReplaceAll(content, Magenta, "")
content = strings.ReplaceAll(content, Cyan, "")
content = strings.ReplaceAll(content, White, "")
content = strings.ReplaceAll(content, BlueBold, "")
content = strings.ReplaceAll(content, MagentaBold, "")
content = strings.ReplaceAll(content, RedBold, "")
content = strings.ReplaceAll(content, YellowBold, "")
// 格式化时间
formatted := now.Format("2006-01-02 15:04:05")
content = formatted+" "+content
//保存到文件
logger.LogToFile(filePath,content+"\n")
}
//日志的级别
func (logger *StdFileLogger) LogMode(lv gormlogger.LogLevel) gormlogger.Interface {
logger.LogLevel = lv
return logger
}
//info
func (logger *StdFileLogger) Info(ctx context.Context, msg string, data ...interface{}) {
if logger.LogLevel >= Info {
logger.printf(logger.infoStr+msg, append([]interface{}{utils.FileWithLineNum()}, data...)...)
}
}
//warn
func (logger *StdFileLogger) Warn(ctx context.Context, msg string, data ...interface{}) {
if logger.LogLevel >= Warn {
logger.printf(logger.infoStr+msg, append([]interface{}{utils.FileWithLineNum()}, data...)...)
}
}
//error
func (logger *StdFileLogger) Error(ctx context.Context, msg string, data ...interface{}) {
if logger.LogLevel >= Error {
//fmt.Println("当前是错误日志:")
logger.printf("当前是错误日志:\n")
logger.printf(logger.infoStr+msg, append([]interface{}{utils.FileWithLineNum()}, data...)...)
}
}
// Trace 打印sql语句
func (logger *StdFileLogger) Trace(ctx context.Context, begin time.Time, fc func() (sql string, rowsAffected int64), err error) {
if logger.LogLevel <= Silent {
return
}
elapsed := time.Since(begin)
switch {
case err != nil && logger.LogLevel >= Error && (!errors.Is(err, gormlogger.ErrRecordNotFound) || !logger.IgnoreRecordNotFoundError):
sql, rows := fc()
//得到stack
stack:= logger.PrintStackTrace(err)
if rows == -1 {
logger.printf(logger.traceErrStr+"\n"+stack, utils.FileWithLineNum(), err, float64(elapsed.Nanoseconds())/1e6, "-", sql)
} else {
logger.printf(logger.traceErrStr+"\n"+stack, utils.FileWithLineNum(), err, float64(elapsed.Nanoseconds())/1e6, rows, sql)
}
case elapsed > logger.SlowThreshold && logger.SlowThreshold != 0 && logger.LogLevel >= Warn:
sql, rows := fc()
slowLog := fmt.Sprintf("SLOW SQL >= %v", logger.SlowThreshold)
if rows == -1 {
logger.printf(logger.traceWarnStr, utils.FileWithLineNum(), slowLog, float64(elapsed.Nanoseconds())/1e6, "-", sql)
} else {
logger.printf(logger.traceWarnStr, utils.FileWithLineNum(), slowLog, float64(elapsed.Nanoseconds())/1e6, rows, sql)
}
case logger.LogLevel == Info:
sql, rows := fc()
if rows == -1 {
logger.printf(logger.traceStr, utils.FileWithLineNum(), float64(elapsed.Nanoseconds())/1e6, "-", sql)
} else {
logger.printf(logger.traceStr, utils.FileWithLineNum(), float64(elapsed.Nanoseconds())/1e6, rows, sql)
}
}
}
//出错时打印错误的堆栈信息
func (logger *StdFileLogger) PrintStackTrace(err error) string {
// 创建一个缓冲区用于存储堆栈信息
buf := bytes.NewBuffer(nil)
// 获取当前goroutine的堆栈信息
for i := 0; ; i++ {
pc, file, line, ok := runtime.Caller(i)
if !ok {
break
}
fmt.Fprintf(buf, "%d: %s:%d (0x%x)\n", i, file, line, pc)
}
// 打印堆栈信息
//fmt.Println(buf.String())
return buf.String()
}
//写内容到文件
func (logger *StdFileLogger) LogToFile(filename,msg string) {
// 输出到文件
file, err := os.OpenFile(filename, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644)
if err != nil {
fmt.Println("日志文件的打开错误 :", err)
}
defer file.Close()
if _, err := file.WriteString(msg); err != nil {
fmt.Println("写入日志文件错误 :", err)
}
}
2,在创建到数据的连接时调用自定义的日志类:
func SetupDBLink() (error) {
var err error
//创建日志类
path:="/data/goapp/logs/" //日志保存目录
name:="gormfile" //日志名字前缀
mylogger := gormfilelogger.NewStdFileLogger(gormfilelogger.FileLogConfig{
Config: logger.Config{ // gorm日志原始配置项
SlowThreshold: 200 * time.Millisecond,
IgnoreRecordNotFoundError: false,
Colorful: true,
},
},path,name).LogMode(gormfilelogger.Info)
//生成dsn
dsn := fmt.Sprintf("%s:%s@tcp(%s)/%s?charset=%s&parseTime=%t&loc=Local",
"username",
"password",
"127.0.0.1:3306",
"databasename",
"utf8",
true, )
//标准输出,替换掉
//DBLink, err = gorm.Open(mysql.Open(dsn), &gorm.Config{Logger: logger.Default.LogMode(logger.Info),})
DBLink, err = gorm.Open(mysql.Open(dsn), &gorm.Config{Logger: mylogger,})
//DBLink.Logger.LogMode(logger.Info)
if err != nil {
return err
}
sqlDB, _ := DBLink.DB()
// SetMaxIdleConns 设置空闲连接池中连接的最大数量
sqlDB.SetMaxIdleConns(10)
// SetMaxOpenConns 设置打开数据库连接的最大数量
sqlDB.SetMaxOpenConns(30)
// SetConnMaxLifetime 设置了连接可复用的最大时间
sqlDB.SetConnMaxLifetime(time.Hour)
return nil
}
三,测试效果:
日志内容例子:
2024-12-09 20:39:47 /data/test/service/userService.go:91 Error 1054 (42S22): Unknown column 'test' in 'field list'
[0.522ms] [rows:-] SELECT id,title,test FROM `image` WHERE uid=1851 and status in (0,1) LIMIT 20
0: /data/test/pkg/gormfilelogger/gormlogger2.go:221 (0x86340b)
1: /data/goapp/industry/pkg/gormfilelogger/gormlogger2.go:191 (0x862f57)
2: /data/gopath/pkg/mod/gorm.io/gorm@v1.25.12/callbacks.go:134 (0x7fd72a)
3: /data/gopath/pkg/mod/gorm.io/gorm@v1.25.12/finisher_api.go:516 (0x8082b1)
4: /data/test/service/userService.go:91 (0x9f0656)
5: /data/test/controller/userController.go:457 (0xa825fa)
6: /data/gopath/pkg/mod/github.com/gofiber/fiber/v2@v2.52.5/router.go:145 (0x9ae1fd)
7: /data/gopath/pkg/mod/github.com/gofiber/fiber/v2@v2.52.5/ctx.go:1034 (0x997e8c)
8: /data/gopath/pkg/mod/github.com/gofiber/fiber/v2@v2.52.5/router.go:425 (0x9afe30)
9: /data/gopath/pkg/mod/github.com/gofiber/fiber/v2@v2.52.5/ctx.go:1031 (0x997e7c)
10: /data/gopath/pkg/mod/github.com/gofiber/fiber/v2@v2.52.5/middleware/recover/recover.go:43 (0xa8681a)
11: /data/gopath/pkg/mod/github.com/gofiber/fiber/v2@v2.52.5/router.go:145 (0x9ae1fd)
12: /data/gopath/pkg/mod/github.com/gofiber/fiber/v2@v2.52.5/router.go:172 (0x9ae428)
13: /data/gopath/pkg/mod/github.com/valyala/fasthttp@v1.57.0/server.go:2385 (0x968c30)
14: /data/gopath/pkg/mod/github.com/valyala/fasthttp@v1.57.0/workerpool.go:225 (0x974851)
15: /data/gopath/pkg/mod/github.com/valyala/fasthttp@v1.57.0/workerpool.go:197 (0x9745f1)
16: /usr/local/soft/go/src/runtime/asm_amd64.s:1700 (0x478160)
标签:err,自定义,gorm,content,go,日志,data,logger From: https://www.cnblogs.com/architectforest/p/18591993