我需要为log15记录器添加属性,但如果我无意中添加了两次,它将出现两次。所以,我想添加逻辑以查看属性是否已填充,如果是,则跳过操作。
这是我输出日志对象时得到的结果:
log="&{ctx:[field1 val1 field2 val2 field3 val3 field2 val2] h:0xc82052c1e0}"
如何访问该“ctx”字段并验证我的值何时已存在?我尝试了一些反射技巧并且可以获得数据类型,但我无法弄清楚如何获得该值。
答案 0 :(得分:1)
我将首先完成您所要求的内容,即访问存储在记录器上下文中的属性。
Go中的反思基于Type
和Value
。您无法使用Type
访问任何数据,您只需拥有该类型的信息(惊喜!)。所以,在这里你必须使用反射的Value
方。
但是,问题是记录器的ctx
字段未导出,因此无法直接访问它。但是,使用一些不安全的操作可以使它成为可能。
以下是代码:
package main
import (
"fmt"
"reflect"
"unsafe"
)
type logger struct {
ctx []interface{}
}
type Logger interface {
Populate(ctx ...interface{})
}
func NewLogger() Logger {
return &logger{}
}
func (l *logger) Populate(ctx ...interface{}) {
l.ctx = ctx
}
func main() {
log := NewLogger()
log.Populate(42, "42", 84, "84")
fmt.Println(log)
// &{[42 42 84 84]}
v := reflect.ValueOf(log).Elem()
field := v.FieldByName("ctx")
ar := *(*[]interface{})(unsafe.Pointer(field.UnsafeAddr()))
for _, i := range ar {
fmt.Println(i)
}
// 42 42 84 84
}
永远不要这样做
代码有效,并产生您的期望。但是,您正在使用反射和不安全操作从第三方库的未导出结构中获取值。我的英语不够好,无法正确表达糟糕这是怎么回事。
如果您不希望在记录器中具有两倍相同的属性,请不要将它放在第一位,这比维护上面的代码要好得多,容易得多。
如果您仍然不相信自己,请将记录器包装在存储记录器中包含的属性的结构中。至少它会是你掌握的东西,并做同样的工作。
因此,您可以自由使用此代码。但是如果你想帮自己一个忙,那么你就不会在那种情况下使用它。