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
相关产品推荐
相关产品推荐

