如何在Golang中使用log.Logger自定义日志格式

来源:站长查询作者:下班再修头衔:程序员
导读:本期聚焦于小伙伴创作的《如何在Golang中使用log.Logger自定义日志格式》,敬请观看详情,探索知识的价值。以下视频、文章将为您系统阐述其核心内容与价值。如果您觉得《如何在Golang中使用log.Logger自定义日志格式》有用,将其分享出去将是对创作者最好的鼓励。

在Golang的标准库中,log包提供了基础的日志功能,其中log.Logger结构体是日志输出的核心载体,默认情况下输出的日志仅包含时间戳和日志内容,缺少日志级别、调用上下文等关键信息。通过自定义log.Logger的输出格式,可以按需添加各类辅助信息,让日志更便于排查问题。

如何在Golang中使用log.Logger自定义日志格式

log.Logger的核心结构

log.Logger的定义位于log包中,核心字段包括输出目标、前缀字符串和日志标志位三个部分,理解这些字段是自定义格式的基础。

type Logger struct {
    mu     sync.Mutex // 保证日志输出并发安全
    prefix string     // 日志前缀,每次输出都会先打印该内容
    flag   int        // 日志标志位,控制输出哪些额外信息
    out    io.Writer  // 日志输出目标,默认是os.Stderr
    buf    []byte     // 日志输出的临时缓冲区
}

其中flag字段是控制默认格式的关键,log包预定义了多个标志位常量,可以通过位或运算组合使用:

  • log.Ldate:输出本地日期,格式为2009/01/23
  • log.Ltime:输出本地时间,格式为01:23:23
  • log.Lmicroseconds:输出微秒级时间,需要在Ltime基础上使用
  • log.Llongfile:输出完整文件名和行号
  • log.Lshortfile:输出文件名和行号,会覆盖Llongfile
  • log.LUTC:使用UTC时间而非本地时间
  • log.Lmsgprefix:将前缀放在日志内容之后,而非开头
  • log.LstdFlags:默认值,等价于Ldate | Ltime

自定义日志格式的基础实现

如果仅需要基于现有标志位调整格式,可以直接创建log.Logger实例并指定对应的flag和prefix参数。比如需要输出日期、时间、短文件名和日志级别前缀,可以这样实现:

package main

import (
    "log"
    "os"
)

func main() {
    // 创建自定义Logger,输出到标准输出,前缀为[INFO],标志位包含日期、时间、短文件名
    logger := log.New(os.Stdout, "[INFO] ", log.Ldate|log.Ltime|log.Lshortfile)
    logger.Println("这是一条自定义格式的日志")
}

上述代码运行后会输出类似2024/05/20 14:30:00 main.go:12: [INFO] 这是一条自定义格式的日志的内容,已经比默认格式多了文件名和行号信息。

完全自定义日志格式的实现

如果预定义的标志位无法满足需求,比如需要添加日志级别、进程ID、自定义时间戳格式等信息,就需要自定义log.Logger的输出逻辑。核心思路是自定义一个实现了io.Writer接口的结构体,在写入日志内容时先按照自定义格式拼接完整内容,再输出到目标位置。

步骤1:定义自定义Writer结构体

我们创建一个customLoggerWriter结构体,内部包含输出目标和日志级别字段,实现Write方法来自定义格式:

package main

import (
    "fmt"
    "io"
    "log"
    "os"
    "time"
)

// 自定义Writer结构体
type customLoggerWriter struct {
    output io.Writer // 实际输出目标
    level  string    // 日志级别
}

// 实现Write方法,自定义日志格式
func (w *customLoggerWriter) Write(p []byte) (n int, err error) {
    // 拼接自定义格式:时间[级别] 日志内容
    // 时间格式设置为2006-01-02 15:04:05.000
    timestamp := time.Now().Format("2006-01-02 15:04:05.000")
    // 拼接完整日志内容,注意p已经包含换行符,不需要额外添加
    fullLog := fmt.Sprintf("%s [%s] %s", timestamp, w.level, p)
    // 写入实际输出目标
    return w.output.Write([]byte(fullLog))
}

步骤2:创建自定义Logger实例

使用自定义的Writer创建log.Logger实例,就可以输出完全自定义格式的日志:

func main() {
    // 创建自定义Writer,输出到标准输出,日志级别为INFO
    writer := &customLoggerWriter{
        output: os.Stdout,
        level:  "INFO",
    }
    // 创建Logger,prefix设为空,flag设为0,因为格式已经在Writer中处理
    logger := log.New(writer, "", 0)
    logger.Println("这是一条完全自定义格式的日志")
    logger.Println("这是另一条自定义格式的日志")
}

运行上述代码后,输出内容如下:

2024-05-20 14:35:00.123 [INFO] 这是一条完全自定义格式的日志
2024-05-20 14:35:00.124 [INFO] 这是另一条自定义格式的日志

步骤3:扩展支持多日志级别

实际项目中通常需要区分INFO、WARN、ERROR等不同日志级别,我们可以进一步封装,创建不同级别的日志输出方法:

// 封装多级别日志的Logger
type CustomLogger struct {
    infoLogger *log.Logger
    warnLogger *log.Logger
    errorLogger *log.Logger
}

// 创建CustomLogger实例
func NewCustomLogger(output io.Writer) *CustomLogger {
    return &CustomLogger{
        infoLogger:  log.New(&customLoggerWriter{output: output, level: "INFO"}, "", 0),
        warnLogger:  log.New(&customLoggerWriter{output: output, level: "WARN"}, "", 0),
        errorLogger: log.New(&customLoggerWriter{output: output, level: "ERROR"}, "", 0),
    }
}

// Info级别日志输出
func (c *CustomLogger) Info(format string, v ...interface{}) {
    c.infoLogger.Printf(format, v...)
}

// Warn级别日志输出
func (c *CustomLogger) Warn(format string, v ...interface{}) {
    c.warnLogger.Printf(format, v...)
}

// Error级别日志输出
func (c *CustomLogger) Error(format string, v ...interface{}) {
    c.errorLogger.Printf(format, v...)
}

func main() {
    logger := NewCustomLogger(os.Stdout)
    logger.Info("这是Info级别的日志,用户ID:%d", 1001)
    logger.Warn("这是Warn级别的日志,请求耗时:%dms", 300)
    logger.Error("这是Error级别的日志,错误原因:%s", "数据库连接失败")
}

上述封装后,调用不同方法就可以输出对应级别的日志,格式统一且易于扩展。

注意事项

在自定义log.Logger格式时,需要注意以下几点:

  • log.Logger的Write方法是并发安全的,内部通过mu字段加锁,自定义Writer如果是多协程使用,也需要保证自身的并发安全
  • 自定义Writer的Write方法接收的字节切片已经包含log.Logger添加的前缀和标志位内容,如果设置了prefix或flag,需要和自定义格式做好区分,避免重复输出
  • 如果日志需要输出到文件,只需要将output设置为对应的文件实例即可,不需要修改自定义格式的逻辑,扩展性较好

通过以上方法,就可以灵活实现Golang中log.Logger的自定义日志格式,满足不同项目的日志需求。

Golanglog.Logger自定义日志格式日志输出修改时间:2026-06-18 06:03:37

免责声明:​ 已尽一切努力确保本网站所含信息的准确性。网站内容多为原创整理与精心编撰,观点力求客观中立。本站旨在免费分享,内容仅供个人学习、研究或参考使用。若引用了第三方作品,版权归原作者所有。如内容涉及您的权益,请联系我们处理。
内容垂直聚焦
专注技术核心技术栏目,确保每篇文章深度聚焦于实用技能。从代码技巧到架构设计,为用户提供无干扰的纯技术知识沉淀,精准满足专业提升需求。
知识结构清晰
覆盖从开发到部署的全链路。AI、前端、编程、数据库、服务器、建站、系统层层递进,构建清晰学习路径,帮助用户系统化掌握开发与运维所需的核心技术。
深度技术解析
拒绝泛泛而谈,深入技术细节与实践难点。无论是数据库优化还是服务器配置,均结合真实场景与代码示例进行剖析,致力于提供可直接应用于工作的解决方案。
专业领域覆盖
精准对应开发生命周期。从前端界面到后端编程,从数据库操作到服务器运维,形成完整闭环,一站式满足全栈工程师和运维人员的技术需求。
即学即用高效
内容强调实操性,步骤清晰、代码完整。用户可根据教程直接复现和应用于自身项目,显著缩短从学习到实践的距离,快速解决开发中的具体问题。
持续更新保障
专注既定技术方向进行长期、稳定的内容输出。确保各栏目技术文章持续更新迭代,紧跟主流技术发展趋势,为用户提供经久不衰的学习价值。