Skip to content

Commit

Permalink
handle struct, slices, maps and pointers
Browse files Browse the repository at this point in the history
  • Loading branch information
dmathieu committed Apr 10, 2024
1 parent 4cdf838 commit 93db706
Show file tree
Hide file tree
Showing 2 changed files with 95 additions and 22 deletions.
61 changes: 51 additions & 10 deletions bridges/otellogrus/hook.go
Expand Up @@ -40,6 +40,7 @@ package otellogrus // import "go.opentelemetry.io/contrib/bridges/otellogrus"

import (
"fmt"
"reflect"

"github.com/sirupsen/logrus"

Expand Down Expand Up @@ -188,27 +189,67 @@ func convertFields(fields logrus.Fields) []log.KeyValue {

i := 0
for k, v := range fields {
kvs[i] = convertKeyValue(k, v)
kvs[i] = log.KeyValue{
Key: k,
Value: convertValue(v),
}
i++
}
return kvs
}

func convertKeyValue(k string, v interface{}) log.KeyValue {
func convertValue(v interface{}) log.Value {
switch v := v.(type) {
case bool:
return log.Bool(k, v)
return log.BoolValue(v)
case []byte:
return log.Bytes(k, v)
return log.BytesValue(v)
case float64:
return log.Float64(k, v)
return log.Float64Value(v)
case int:
return log.Int(k, v)
return log.IntValue(v)
case int64:
return log.Int64(k, v)
return log.Int64Value(v)
case string:
return log.String(k, v)
default:
return log.String(k, fmt.Sprintf("%s", v))
return log.StringValue(v)
}

t := reflect.TypeOf(v)
if t == nil {
return log.Value{}
}
val := reflect.ValueOf(v)
switch t.Kind() {
case reflect.Struct:
return log.StringValue(fmt.Sprintf("%+v", v))
case reflect.Slice, reflect.Array:
items := make([]log.Value, 0, val.Len())
for i := 0; i < val.Len(); i++ {
items = append(items, convertValue(val.Index(i).Interface()))
}
return log.SliceValue(items...)
case reflect.Map:
kvs := make([]log.KeyValue, 0, val.Len())
for _, k := range val.MapKeys() {
var key string
// If the key is a struct, use %+v to print the struct fields.
if k.Kind() == reflect.Struct {
key = fmt.Sprintf("%+v", k.Interface())
} else {
key = fmt.Sprintf("%v", k.Interface())
}
kvs = append(kvs, log.KeyValue{
Key: key,
Value: convertValue(val.MapIndex(k).Interface()),
})
}
return log.MapValue(kvs...)
case reflect.Ptr, reflect.Interface:
if val.IsNil() {
return log.Value{}
}
return convertValue(val.Elem().Interface())
}

return log.StringValue(fmt.Sprintf("unhandled attribute type: (%s) %+v", t, v))
}
56 changes: 44 additions & 12 deletions bridges/otellogrus/hook_test.go
Expand Up @@ -133,53 +133,85 @@ func TestConvertFields(t *testing.T) {
wantKeyValue []log.KeyValue
}{
{
name: "with a boolean",

name: "with a boolean",
fields: logrus.Fields{"hello": true},
wantKeyValue: []log.KeyValue{
log.Bool("hello", true),
},
},
{
name: "with a bytes array",

name: "with a bytes array",
fields: logrus.Fields{"hello": []byte("world")},
wantKeyValue: []log.KeyValue{
log.Bytes("hello", []byte("world")),
},
},
{
name: "with a float64",

name: "with a float64",
fields: logrus.Fields{"hello": 6.5},
wantKeyValue: []log.KeyValue{
log.Float64("hello", 6.5),
},
},
{
name: "with an int",

name: "with an int",
fields: logrus.Fields{"hello": 42},
wantKeyValue: []log.KeyValue{
log.Int("hello", 42),
},
},
{
name: "with an int64",

name: "with an int64",
fields: logrus.Fields{"hello": int64(42)},
wantKeyValue: []log.KeyValue{
log.Int64("hello", 42),
},
},
{
name: "with a string",

name: "with a string",
fields: logrus.Fields{"hello": "world"},
wantKeyValue: []log.KeyValue{
log.String("hello", "world"),
},
},
{
name: "with nil",
fields: logrus.Fields{"hello": nil},
wantKeyValue: []log.KeyValue{
log.KeyValue{Key: "hello", Value: log.Value{}},
},
},
{
name: "with a struct",
fields: logrus.Fields{"hello": struct{ Name string }{Name: "foobar"}},
wantKeyValue: []log.KeyValue{
log.String("hello", "{Name:foobar}"),
},
},
{
name: "with a slice",
fields: logrus.Fields{"hello": []string{"foo", "bar"}},
wantKeyValue: []log.KeyValue{
log.Slice("hello",
log.StringValue("foo"),
log.StringValue("bar"),
),
},
},
{
name: "with a map",
fields: logrus.Fields{"hello": map[string]int{"answer": 42}},
wantKeyValue: []log.KeyValue{
log.Map("hello", log.Int("answer", 42)),
},
},
{
name: "with a pointer to struct",
fields: logrus.Fields{"hello": &struct{ Name string }{Name: "foobar"}},
wantKeyValue: []log.KeyValue{
log.String("hello", "{Name:foobar}"),
},
},
} {
t.Run(tt.name, func(t *testing.T) {
assert.Equal(t, convertFields(tt.fields), tt.wantKeyValue)
Expand Down

0 comments on commit 93db706

Please sign in to comment.