You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Go项目logrus日志使用struct替代map传递字段的实现方法

实现方案

原生logrus的WithFields方法仅支持logrus.Fields类型参数,要实现直接传入结构体携带日志字段,只需通过反射做一层结构体到logrus.Fields的转换即可,具体实现如下:

步骤1:实现结构体转Fields工具函数

通过反射读取结构体的json标签作为日志键名,字段值作为日志值:

import (
    "reflect"
    "github.com/sirupsen/logrus"
)

// StructToFields 将带json标签的结构体转换为logrus可用的Fields
func StructToFields(obj interface{}) logrus.Fields {
    fields := logrus.Fields{}
    val := reflect.ValueOf(obj)
    // 兼容结构体指针
    if val.Kind() == reflect.Ptr {
        val = val.Elem()
    }
    // 非结构体类型直接返回空
    if val.Kind() != reflect.Struct {
        return fields
    }
    typ := val.Type()
    for i := 0; i < val.NumField(); i++ {
        field := typ.Field(i)
        tag := field.Tag.Get("json")
        // 跳过无json标签、标记为忽略的字段
        if tag == "" || tag == "-" {
            continue
        }
        // 处理带omitempty等后缀的json标签,只取逗号前的键名
        if commaIdx := findComma(tag); commaIdx != -1 {
            tag = tag[:commaIdx]
        }
        fields[tag] = val.Field(i).Interface()
    }
    return fields
}

func findComma(s string) int {
    for idx, char := range s {
        if char == ',' {
            return idx
        }
    }
    return -1
}

步骤2:基础使用方式

直接调用转换函数传入WithFields即可:

type LogMessage struct {
    Status  bool        `json:"status"`
    Message string      `json:"message"`
}

func main() {
    logrus.WithFields(StructToFields(&LogMessage{
        Status:  false,
        Message: "Error User Already Exists",
    })).Info("User Creation Failed.")
}

步骤3:进一步封装实现你期望的写法

如果不想每次都手动调用StructToFields,可以对logrus做一层薄封装:

// 全局logger实例
var logger *logrus.Logger

func init() {
    logger = logrus.New()
    // 可在这里统一配置logger的格式、日志级别、输出路径等
    logger.SetFormatter(&logrus.TextFormatter{
        FullTimestamp: true,
    })
}

// 自定义WithFields方法,支持直接传入结构体
func WithFields(obj interface{}) *logrus.Entry {
    // 兼容原生logrus.Fields类型传参
    if nativeFields, ok := obj.(logrus.Fields); ok {
        return logger.WithFields(nativeFields)
    }
    // 结构体类型自动转换
    return logger.WithFields(StructToFields(obj))
}

封装完成后就可以直接使用你期望的用法:

WithFields(&LogMessage {Status: false, Message: "Error User Already Exists"}).Info("User Creation Failed.")

输出结果与你预期完全一致:

time="2024-05-20T14:30:00+08:00" level=info msg="User Creation Failed." status=false message="Error User Already Exists"

注意事项

  • 结构体字段必须首字母大写(可导出),否则反射无法读取字段值
  • 如果需要支持嵌套结构体,只需在StructToFields方法中添加递归处理逻辑即可

内容的提问来源于stack exchange,提问作者Sagar Agarwal

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.03 18:27:03