package log import ( "context" "fmt" "time" ) const ( // DefaultErrorFieldName is the default field name used for errors DefaultErrorFieldName = "error" ) // FieldType is a type of data Field can represent type FieldType int const ( // FieldTypeNil is for a pure nil FieldTypeNil FieldType = iota // FieldTypeString is for a string FieldTypeString // FieldTypeBinary is for a binary array FieldTypeBinary // FieldTypeBoolean is for boolean FieldTypeBoolean // FieldTypeSigned is for signed integers FieldTypeSigned // FieldTypeUnsigned is for unsigned integers FieldTypeUnsigned // FieldTypeFloat is for float FieldTypeFloat // FieldTypeTime is for time.Time FieldTypeTime // FieldTypeDuration is for time.Duration FieldTypeDuration // FieldTypeError is for an error FieldTypeError // FieldTypeArray is for an array of any type FieldTypeArray // FieldTypeAny is for any type FieldTypeAny // FieldTypeReflect is for unknown types FieldTypeReflect // FieldTypeByteString is for a bytes that can be represented as UTF-8 string FieldTypeByteString // FieldTypeContext wraps context for lazy context fields evaluation if possible FieldTypeContext ) // Field stores one structured logging field type Field struct { key string ftype FieldType string string signed int64 unsigned uint64 float float64 iface interface{} } // Key returns field key func (f Field) Key() string { return f.key } // Type returns field type func (f Field) Type() FieldType { return f.ftype } // String returns field string func (f Field) String() string { return f.string } // Binary constructs field of []byte func (f Field) Binary() []byte { if f.iface == nil { return nil } return f.iface.([]byte) } // Bool returns field bool func (f Field) Bool() bool { return f.Signed() != 0 } // Signed returns field int64 func (f Field) Signed() int64 { return f.signed } // Unsigned returns field uint64 func (f Field) Unsigned() uint64 { return f.unsigned } // Float returns field float64 func (f Field) Float() float64 { return f.float } // Time returns field time.Time func (f Field) Time() time.Time { return time.Unix(0, f.signed) } // Duration returns field time.Duration func (f Field) Duration() time.Duration { return time.Nanosecond * time.Duration(f.signed) } // Error constructs field of error type func (f Field) Error() error { if f.iface == nil { return nil } return f.iface.(error) } // Interface returns field interface func (f Field) Interface() interface{} { return f.iface } // Any returns contained data as interface{} // nolint: gocyclo func (f Field) Any() interface{} { switch f.Type() { case FieldTypeNil: return nil case FieldTypeString: return f.String() case FieldTypeBinary: return f.Interface() case FieldTypeBoolean: return f.Bool() case FieldTypeSigned: return f.Signed() case FieldTypeUnsigned: return f.Unsigned() case FieldTypeFloat: return f.Float() case FieldTypeTime: return f.Time() case FieldTypeDuration: return f.Duration() case FieldTypeError: return f.Error() case FieldTypeArray: return f.Interface() case FieldTypeAny: return f.Interface() case FieldTypeReflect: return f.Interface() case FieldTypeByteString: return f.Interface() case FieldTypeContext: return f.Interface() default: // For when new field type is not added to this func panic(fmt.Sprintf("unknown field type: %d", f.Type())) } } // Nil constructs field of nil type func Nil(key string) Field { return Field{key: key, ftype: FieldTypeNil} } // String constructs field of string type func String(key, value string) Field { return Field{key: key, ftype: FieldTypeString, string: value} } // Sprintf constructs field of string type with formatting func Sprintf(key, format string, args ...interface{}) Field { return Field{key: key, ftype: FieldTypeString, string: fmt.Sprintf(format, args...)} } // Strings constructs Field from []string func Strings(key string, value []string) Field { return Array(key, value) } // Binary constructs field of []byte type func Binary(key string, value []byte) Field { return Field{key: key, ftype: FieldTypeBinary, iface: value} } // Bool constructs field of bool type func Bool(key string, value bool) Field { field := Field{key: key, ftype: FieldTypeBoolean} if value { field.signed = 1 } else { field.signed = 0 } return field } // Bools constructs Field from []bool func Bools(key string, value []bool) Field { return Array(key, value) } // Int constructs Field from int func Int(key string, value int) Field { return Int64(key, int64(value)) } // Ints constructs Field from []int func Ints(key string, value []int) Field { return Array(key, value) } // Int8 constructs Field from int8 func Int8(key string, value int8) Field { return Int64(key, int64(value)) } // Int8s constructs Field from []int8 func Int8s(key string, value []int8) Field { return Array(key, value) } // Int16 constructs Field from int16 func Int16(key string, value int16) Field { return Int64(key, int64(value)) } // Int16s constructs Field from []int16 func Int16s(key string, value []int16) Field { return Array(key, value) } // Int32 constructs Field from int32 func Int32(key string, value int32) Field { return Int64(key, int64(value)) } // Int32s constructs Field from []int32 func Int32s(key string, value []int32) Field { return Array(key, value) } // Int64 constructs Field from int64 func Int64(key string, value int64) Field { return Field{key: key, ftype: FieldTypeSigned, signed: value} } // Int64s constructs Field from []int64 func Int64s(key string, value []int64) Field { return Array(key, value) } // UInt constructs Field from uint func UInt(key string, value uint) Field { return UInt64(key, uint64(value)) } // UInts constructs Field from []uint func UInts(key string, value []uint) Field { return Array(key, value) } // UInt8 constructs Field from uint8 func UInt8(key string, value uint8) Field { return UInt64(key, uint64(value)) } // UInt8s constructs Field from []uint8 func UInt8s(key string, value []uint8) Field { return Array(key, value) } // UInt16 constructs Field from uint16 func UInt16(key string, value uint16) Field { return UInt64(key, uint64(value)) } // UInt16s constructs Field from []uint16 func UInt16s(key string, value []uint16) Field { return Array(key, value) } // UInt32 constructs Field from uint32 func UInt32(key string, value uint32) Field { return UInt64(key, uint64(value)) } // UInt32s constructs Field from []uint32 func UInt32s(key string, value []uint32) Field { return Array(key, value) } // UInt64 constructs Field from uint64 func UInt64(key string, value uint64) Field { return Field{key: key, ftype: FieldTypeUnsigned, unsigned: value} } // UInt64s constructs Field from []uint64 func UInt64s(key string, value []uint64) Field { return Array(key, value) } // Float32 constructs Field from float32 func Float32(key string, value float32) Field { return Float64(key, float64(value)) } // Float32s constructs Field from []float32 func Float32s(key string, value []float32) Field { return Array(key, value) } // Float64 constructs Field from float64 func Float64(key string, value float64) Field { return Field{key: key, ftype: FieldTypeFloat, float: value} } // Float64s constructs Field from []float64 func Float64s(key string, value []float64) Field { return Array(key, value) } // Time constructs field of time.Time type func Time(key string, value time.Time) Field { return Field{key: key, ftype: FieldTypeTime, signed: value.UnixNano()} } // Times constructs Field from []time.Time func Times(key string, value []time.Time) Field { return Array(key, value) } // Duration constructs field of time.Duration type func Duration(key string, value time.Duration) Field { return Field{key: key, ftype: FieldTypeDuration, signed: value.Nanoseconds()} } // Durations constructs Field from []time.Duration func Durations(key string, value []time.Duration) Field { return Array(key, value) } // NamedError constructs field of error type func NamedError(key string, value error) Field { return Field{key: key, ftype: FieldTypeError, iface: value} } // Error constructs field of error type with default field name func Error(value error) Field { return NamedError(DefaultErrorFieldName, value) } // Errors constructs Field from []error func Errors(key string, value []error) Field { return Array(key, value) } // Array constructs field of array type func Array(key string, value interface{}) Field { return Field{key: key, ftype: FieldTypeArray, iface: value} } // Reflect constructs field of unknown type func Reflect(key string, value interface{}) Field { return Field{key: key, ftype: FieldTypeReflect, iface: value} } // ByteString constructs field of bytes that could represent UTF-8 string func ByteString(key string, value []byte) Field { return Field{key: key, ftype: FieldTypeByteString, iface: value} } // Context constructs field for lazy context fields evaluation if possible func Context(ctx context.Context) Field { return Field{ftype: FieldTypeContext, iface: ctx} } // Any tries to deduce interface{} underlying type and constructs Field from it. // Use of this function is ok only for the sole purpose of not repeating its entire code // or parts of it in user's code (when you need to log interface{} types with unknown content). // Otherwise please use specialized functions. // nolint: gocyclo func Any(key string, value interface{}) Field { switch val := value.(type) { case bool: return Bool(key, val) case float64: return Float64(key, val) case float32: return Float32(key, val) case int: return Int(key, val) case []int: return Ints(key, val) case int64: return Int64(key, val) case []int64: return Int64s(key, val) case int32: return Int32(key, val) case []int32: return Int32s(key, val) case int16: return Int16(key, val) case []int16: return Int16s(key, val) case int8: return Int8(key, val) case []int8: return Int8s(key, val) case string: return String(key, val) case []string: return Strings(key, val) case uint: return UInt(key, val) case []uint: return UInts(key, val) case uint64: return UInt64(key, val) case []uint64: return UInt64s(key, val) case uint32: return UInt32(key, val) case []uint32: return UInt32s(key, val) case uint16: return UInt16(key, val) case []uint16: return UInt16s(key, val) case uint8: return UInt8(key, val) case []byte: return Binary(key, val) case time.Time: return Time(key, val) case []time.Time: return Times(key, val) case time.Duration: return Duration(key, val) case []time.Duration: return Durations(key, val) case error: return NamedError(key, val) case []error: return Errors(key, val) case context.Context: return Context(val) default: return Field{key: key, ftype: FieldTypeAny, iface: value} } }