mirror of
https://github.com/rwinkhart/go-winio.git
synced 2026-09-01 14:47:32 -04:00
Merge pull request #120 from kevpar/etw-smart-field
Move smart ETW field logging to base etw library
This commit is contained in:
@@ -1,7 +1,9 @@
|
||||
package etw
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"math"
|
||||
"reflect"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
@@ -377,3 +379,124 @@ func Struct(name string, opts ...FieldOpt) FieldOpt {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Currently, we support logging basic builtin types (int, string, etc), slices
|
||||
// of basic builtin types, error, types derived from the basic types (e.g. "type
|
||||
// foo int"), and structs (recursively logging their fields). We do not support
|
||||
// slices of derived types (e.g. "[]foo").
|
||||
//
|
||||
// For types that we don't support, the value is formatted via fmt.Sprint, and
|
||||
// we also log a message that the type is unsupported along with the formatted
|
||||
// type. The intent of this is to make it easier to see which types are not
|
||||
// supported in traces, so we can evaluate adding support for more types in the
|
||||
// future.
|
||||
func SmartField(name string, v interface{}) FieldOpt {
|
||||
switch v := v.(type) {
|
||||
case bool:
|
||||
return BoolField(name, v)
|
||||
case []bool:
|
||||
return BoolArray(name, v)
|
||||
case string:
|
||||
return StringField(name, v)
|
||||
case []string:
|
||||
return StringArray(name, v)
|
||||
case int:
|
||||
return IntField(name, v)
|
||||
case []int:
|
||||
return IntArray(name, v)
|
||||
case int8:
|
||||
return Int8Field(name, v)
|
||||
case []int8:
|
||||
return Int8Array(name, v)
|
||||
case int16:
|
||||
return Int16Field(name, v)
|
||||
case []int16:
|
||||
return Int16Array(name, v)
|
||||
case int32:
|
||||
return Int32Field(name, v)
|
||||
case []int32:
|
||||
return Int32Array(name, v)
|
||||
case int64:
|
||||
return Int64Field(name, v)
|
||||
case []int64:
|
||||
return Int64Array(name, v)
|
||||
case uint:
|
||||
return UintField(name, v)
|
||||
case []uint:
|
||||
return UintArray(name, v)
|
||||
case uint8:
|
||||
return Uint8Field(name, v)
|
||||
case []uint8:
|
||||
return Uint8Array(name, v)
|
||||
case uint16:
|
||||
return Uint16Field(name, v)
|
||||
case []uint16:
|
||||
return Uint16Array(name, v)
|
||||
case uint32:
|
||||
return Uint32Field(name, v)
|
||||
case []uint32:
|
||||
return Uint32Array(name, v)
|
||||
case uint64:
|
||||
return Uint64Field(name, v)
|
||||
case []uint64:
|
||||
return Uint64Array(name, v)
|
||||
case uintptr:
|
||||
return UintptrField(name, v)
|
||||
case []uintptr:
|
||||
return UintptrArray(name, v)
|
||||
case float32:
|
||||
return Float32Field(name, v)
|
||||
case []float32:
|
||||
return Float32Array(name, v)
|
||||
case float64:
|
||||
return Float64Field(name, v)
|
||||
case []float64:
|
||||
return Float64Array(name, v)
|
||||
case error:
|
||||
return StringField(name, v.Error())
|
||||
default:
|
||||
switch rv := reflect.ValueOf(v); rv.Kind() {
|
||||
case reflect.Bool:
|
||||
return SmartField(name, rv.Bool())
|
||||
case reflect.Int:
|
||||
return SmartField(name, int(rv.Int()))
|
||||
case reflect.Int8:
|
||||
return SmartField(name, int8(rv.Int()))
|
||||
case reflect.Int16:
|
||||
return SmartField(name, int16(rv.Int()))
|
||||
case reflect.Int32:
|
||||
return SmartField(name, int32(rv.Int()))
|
||||
case reflect.Int64:
|
||||
return SmartField(name, int64(rv.Int()))
|
||||
case reflect.Uint:
|
||||
return SmartField(name, uint(rv.Uint()))
|
||||
case reflect.Uint8:
|
||||
return SmartField(name, uint8(rv.Uint()))
|
||||
case reflect.Uint16:
|
||||
return SmartField(name, uint16(rv.Uint()))
|
||||
case reflect.Uint32:
|
||||
return SmartField(name, uint32(rv.Uint()))
|
||||
case reflect.Uint64:
|
||||
return SmartField(name, uint64(rv.Uint()))
|
||||
case reflect.Uintptr:
|
||||
return SmartField(name, uintptr(rv.Uint()))
|
||||
case reflect.Float32:
|
||||
return SmartField(name, float32(rv.Float()))
|
||||
case reflect.Float64:
|
||||
return SmartField(name, float64(rv.Float()))
|
||||
case reflect.String:
|
||||
return SmartField(name, rv.String())
|
||||
case reflect.Struct:
|
||||
fields := make([]FieldOpt, 0, rv.NumField())
|
||||
for i := 0; i < rv.NumField(); i++ {
|
||||
field := rv.Field(i)
|
||||
if field.CanInterface() {
|
||||
fields = append(fields, SmartField(name, field.Interface()))
|
||||
}
|
||||
}
|
||||
return Struct(name, fields...)
|
||||
}
|
||||
}
|
||||
|
||||
return StringField(name, fmt.Sprintf("(Unsupported: %T) %v", v, v))
|
||||
}
|
||||
|
||||
@@ -6,7 +6,7 @@ import (
|
||||
"fmt"
|
||||
"os"
|
||||
|
||||
"github.com/Microsoft/go-winio/internal/etw"
|
||||
"github.com/Microsoft/go-winio/pkg/etw"
|
||||
"github.com/sirupsen/logrus"
|
||||
|
||||
"golang.org/x/sys/windows"
|
||||
|
||||
+1
-125
@@ -1,9 +1,6 @@
|
||||
package etwlogrus
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"reflect"
|
||||
|
||||
"github.com/Microsoft/go-winio/pkg/etw"
|
||||
"github.com/sirupsen/logrus"
|
||||
)
|
||||
@@ -71,7 +68,7 @@ func (h *Hook) Fire(e *logrus.Entry) error {
|
||||
fields = append(fields, etw.StringField("Message", e.Message))
|
||||
|
||||
for k, v := range e.Data {
|
||||
fields = append(fields, getFieldOpt(k, v))
|
||||
fields = append(fields, etw.SmartField(k, v))
|
||||
}
|
||||
|
||||
return h.provider.WriteEvent(
|
||||
@@ -80,127 +77,6 @@ func (h *Hook) Fire(e *logrus.Entry) error {
|
||||
fields)
|
||||
}
|
||||
|
||||
// Currently, we support logging basic builtin types (int, string, etc), slices
|
||||
// of basic builtin types, error, types derived from the basic types (e.g. "type
|
||||
// foo int"), and structs (recursively logging their fields). We do not support
|
||||
// slices of derived types (e.g. "[]foo").
|
||||
//
|
||||
// For types that we don't support, the value is formatted via fmt.Sprint, and
|
||||
// we also log a message that the type is unsupported along with the formatted
|
||||
// type. The intent of this is to make it easier to see which types are not
|
||||
// supported in traces, so we can evaluate adding support for more types in the
|
||||
// future.
|
||||
func getFieldOpt(k string, v interface{}) etw.FieldOpt {
|
||||
switch v := v.(type) {
|
||||
case bool:
|
||||
return etw.BoolField(k, v)
|
||||
case []bool:
|
||||
return etw.BoolArray(k, v)
|
||||
case string:
|
||||
return etw.StringField(k, v)
|
||||
case []string:
|
||||
return etw.StringArray(k, v)
|
||||
case int:
|
||||
return etw.IntField(k, v)
|
||||
case []int:
|
||||
return etw.IntArray(k, v)
|
||||
case int8:
|
||||
return etw.Int8Field(k, v)
|
||||
case []int8:
|
||||
return etw.Int8Array(k, v)
|
||||
case int16:
|
||||
return etw.Int16Field(k, v)
|
||||
case []int16:
|
||||
return etw.Int16Array(k, v)
|
||||
case int32:
|
||||
return etw.Int32Field(k, v)
|
||||
case []int32:
|
||||
return etw.Int32Array(k, v)
|
||||
case int64:
|
||||
return etw.Int64Field(k, v)
|
||||
case []int64:
|
||||
return etw.Int64Array(k, v)
|
||||
case uint:
|
||||
return etw.UintField(k, v)
|
||||
case []uint:
|
||||
return etw.UintArray(k, v)
|
||||
case uint8:
|
||||
return etw.Uint8Field(k, v)
|
||||
case []uint8:
|
||||
return etw.Uint8Array(k, v)
|
||||
case uint16:
|
||||
return etw.Uint16Field(k, v)
|
||||
case []uint16:
|
||||
return etw.Uint16Array(k, v)
|
||||
case uint32:
|
||||
return etw.Uint32Field(k, v)
|
||||
case []uint32:
|
||||
return etw.Uint32Array(k, v)
|
||||
case uint64:
|
||||
return etw.Uint64Field(k, v)
|
||||
case []uint64:
|
||||
return etw.Uint64Array(k, v)
|
||||
case uintptr:
|
||||
return etw.UintptrField(k, v)
|
||||
case []uintptr:
|
||||
return etw.UintptrArray(k, v)
|
||||
case float32:
|
||||
return etw.Float32Field(k, v)
|
||||
case []float32:
|
||||
return etw.Float32Array(k, v)
|
||||
case float64:
|
||||
return etw.Float64Field(k, v)
|
||||
case []float64:
|
||||
return etw.Float64Array(k, v)
|
||||
case error:
|
||||
return etw.StringField(k, v.Error())
|
||||
default:
|
||||
switch rv := reflect.ValueOf(v); rv.Kind() {
|
||||
case reflect.Bool:
|
||||
return getFieldOpt(k, rv.Bool())
|
||||
case reflect.Int:
|
||||
return getFieldOpt(k, int(rv.Int()))
|
||||
case reflect.Int8:
|
||||
return getFieldOpt(k, int8(rv.Int()))
|
||||
case reflect.Int16:
|
||||
return getFieldOpt(k, int16(rv.Int()))
|
||||
case reflect.Int32:
|
||||
return getFieldOpt(k, int32(rv.Int()))
|
||||
case reflect.Int64:
|
||||
return getFieldOpt(k, int64(rv.Int()))
|
||||
case reflect.Uint:
|
||||
return getFieldOpt(k, uint(rv.Uint()))
|
||||
case reflect.Uint8:
|
||||
return getFieldOpt(k, uint8(rv.Uint()))
|
||||
case reflect.Uint16:
|
||||
return getFieldOpt(k, uint16(rv.Uint()))
|
||||
case reflect.Uint32:
|
||||
return getFieldOpt(k, uint32(rv.Uint()))
|
||||
case reflect.Uint64:
|
||||
return getFieldOpt(k, uint64(rv.Uint()))
|
||||
case reflect.Uintptr:
|
||||
return getFieldOpt(k, uintptr(rv.Uint()))
|
||||
case reflect.Float32:
|
||||
return getFieldOpt(k, float32(rv.Float()))
|
||||
case reflect.Float64:
|
||||
return getFieldOpt(k, float64(rv.Float()))
|
||||
case reflect.String:
|
||||
return getFieldOpt(k, rv.String())
|
||||
case reflect.Struct:
|
||||
fields := make([]etw.FieldOpt, 0, rv.NumField())
|
||||
for i := 0; i < rv.NumField(); i++ {
|
||||
field := rv.Field(i)
|
||||
if field.CanInterface() {
|
||||
fields = append(fields, getFieldOpt(k, field.Interface()))
|
||||
}
|
||||
}
|
||||
return etw.Struct(k, fields...)
|
||||
}
|
||||
}
|
||||
|
||||
return etw.StringField(k, fmt.Sprintf("(Unsupported: %T) %v", v, v))
|
||||
}
|
||||
|
||||
// Close cleans up the hook and closes the ETW provider. If the provder was
|
||||
// registered by etwlogrus, it will be closed as part of `Close`. If the
|
||||
// provider was passed in, it will not be closed.
|
||||
|
||||
Reference in New Issue
Block a user