自定义log输出信息,时间戳
一、改写 log.Printf和log.Println
1、简介
(1)go 源码中支持格式化输出信息的包名称有 fmt 、log 两种包类型;
(2)两种包类型,均包含 Printf() 接口和 Println() 接口;
(3)两者的区别:
(a)fmt包适合通用的格式化输出,如打印普通消息、调试输出等;
(b)log包适合用于正式的日志记录,提供时间戳、日志级别、日志标记和自定义输出等特性,能够更好地记录和
追踪程序的运行状态。
(4)log 包虽然能输出时间戳,但默认输出的时间戳是 0 时区的时间,在显示上面感觉不是那么的习惯,比如北京时
间是上午八点,则 log 输出的时间为 0 点,正好相差八个小时。
2、自定义 Printf 和 Println
若想直观输出时间戳信息,则需要通过自定义接口的形式来解决此问题,此时需要涉及到 time 包,来实现时区设置,如北京地区则为东八区,这样的一个转换。
代码示例如下:
(1)东八区设置(两种写法都可以):
// var now = time.Now().In(time.FixedZone("CST", 8*3600))
now := time.Now().In(time.FixedZone("Asia/Shanghai", 8*3600))
(2)自定义 Printf() 接口:
func Printf(format string, v ...interface{}) {
now := time.Now().In(time.FixedZone("Asia/Shanghai", 8*3600))
message := now.Format("2006-01-02 15:04:05") + " " + format
fmt.Printf(message, v...)
}
(3)自定义 Println() 接口:
func Println(values ...interface{}) {
now := time.Now().In(time.FixedZone("Asia/Shanghai", 8*3600))
message := now.Format("2006-01-02 15:04:05") + " "
fmt.Printf("%s", message)
fmt.Println(values...)
}
二、Gin web 默认输出 log 改写
默认模式下,gin web 输出log信息包含信息有:时间戳、状态码、相应时间、客户端IP、HTTP 请求方法、路由信息,其中时间戳输出默认也为 0 时区时间,则改写时间戳代码如下:
(1)输出信息颜色标识,在终端显示HTTP状态码相应的颜色,此时需要 ASNI 编码:
const (
green = "\033[97;42m"
white = "\033[90;47m"
yellow = "\033[90;43m"
red = "\033[97;41m"
blue = "\033[97;44m"
magenta = "\033[97;45m"
cyan = "\033[97;46m"
reset = "\033[0m"
)
(2)区分 HTTP 状态码颜色标识:
func StatusCodeColor(code int) string {
switch {
case code >= http.StatusContinue && code < http.StatusOK:
return white
case code >= http.StatusOK && code < http.StatusMultipleChoices:
return green
case code >= http.StatusMultipleChoices && code < http.StatusBadRequest:
return white
case code >= http.StatusBadRequest && code < http.StatusInternalServerError:
return yellow
default:
return red
}
}
(3)区分 HTTP 请求方法颜色标识:
func MethodColor(method string) string {
switch method {
case http.MethodGet:
return blue
case http.MethodPost:
return cyan
case http.MethodPut:
return yellow
case http.MethodDelete:
return red
case http.MethodPatch:
return green
case http.MethodHead:
return magenta
case http.MethodOptions:
return white
default:
return reset
}
}
(4)终止颜色标识:
func ResetColor() string {
return reset
}
(5)自定义log中间件,此处是使用的 logrus 组件,源码包位置:
"github.com/sirupsen/logrus"
(6)demo:
package main
import (
"fmt"
"io/ioutil"
"net/http"
"os"
"time"
"github.com/sirupsen/logrus"
"github.com/gin-gonic/gin"
)
func main() {
// 创建一个新的引擎实例
r := gin.New()
// 创建一个新的logrus Logger实例
log := logrus.New()
// 自定义logrus中间件
r.Use(logrusMiddleware(log))
// 定义路由
r.GET("/", func(c *gin.Context) {
c.JSON(200, gin.H{
"message": "hello world",
})
})
// 启动Gin服务器
r.Run(":8080")
}
// 自定义中间件
func logrusMiddleware(log *logrus.Logger) gin.HandlerFunc {
return func(c *gin.Context) {
startTime := time.Now().In(time.FixedZone("Asia/Shanghai", 8*3600))
// 处理请求
c.Next()
fmt.Printf("[GIN] %v |%s %3d %s| %13v | %15s |%s %-7s %s %#v\n",
startTime.Format("2006/01/02 - 15:04:05"),
StatusCodeColor(c.Writer.Status()), c.Writer.Status(), ResetColor(),
time.Since(startTime),
c.ClientIP(),
MethodColor(c.Request.Method), c.Request.Method, ResetColor(),
c.Request.URL.Path,
)
}
}
三、实现 c语言 “FUNCTION”, “LINE”
log模块自带的日志功能,同样能够显示代码路径,行号,日期等信息,但其显示的路径是文件的绝对路径,打印日志显得太繁琐不够简练,当代码运行出错时,若只想打印文件的相对路径且只保留上一级目录,函数名和行号,因此改写示例代码如下:
// 输出信息如下: 2024-11-28 16:35:15 [error][xxx/xxx.go:23 - function]
func PrintfErr(format string, v ...interface{}) {
var pcs [32]uintptr
n := runtime.Callers(2, pcs[:]) // 跳过两层调用栈
frames := runtime.CallersFrames(pcs[:n])
frame, _ := frames.Next()
// 解析函数名和文件路径
funcName := frame.Function
filePath := frame.File
line := frame.Line
// 提取函数名(去除包路径和文件名)
funcNameParts := strings.Split(funcName, ".")
funcName = funcNameParts[len(funcNameParts)-1]
// 处理文件路径,只保留到上一级目录
dir, fileName := filepath.Split(filePath)
parentDir := filepath.Dir(dir)
relativePath := filepath.Join(filepath.Base(parentDir), fileName)
logMessage := fmt.Sprintf("[error][%s:%d - %s] ", relativePath, line, funcName)
now := time.Now().In(time.FixedZone("Asia/Shanghai", 8*3600))
message := now.Format("2006-01-02 15:04:05") + " " + logMessage + format
fmt.Printf(message, v...)
fmt.Println()
}

被折叠的 条评论
为什么被折叠?



