summaryrefslogtreecommitdiffstats
path: root/vendor/github.com/mattermost/logr/v2/field.go
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/github.com/mattermost/logr/v2/field.go')
-rw-r--r--vendor/github.com/mattermost/logr/v2/field.go403
1 files changed, 403 insertions, 0 deletions
diff --git a/vendor/github.com/mattermost/logr/v2/field.go b/vendor/github.com/mattermost/logr/v2/field.go
new file mode 100644
index 00000000..5725d0a1
--- /dev/null
+++ b/vendor/github.com/mattermost/logr/v2/field.go
@@ -0,0 +1,403 @@
+package logr
+
+import (
+ "errors"
+ "fmt"
+ "io"
+ "reflect"
+ "strconv"
+ "time"
+)
+
+var (
+ Comma = []byte{','}
+ Equals = []byte{'='}
+ Space = []byte{' '}
+ Newline = []byte{'\n'}
+ Quote = []byte{'"'}
+ Colon = []byte{'"'}
+)
+
+// LogCloner is implemented by `Any` types that require a clone to be provided
+// to the logger because the original may mutate.
+type LogCloner interface {
+ LogClone() interface{}
+}
+
+// LogWriter is implemented by `Any` types that provide custom formatting for
+// log output. A string representation of the type should be written directly to
+// the `io.Writer`.
+type LogWriter interface {
+ LogWrite(w io.Writer) error
+}
+
+type FieldType uint8
+
+const (
+ UnknownType FieldType = iota
+ StringType
+ StringerType
+ StructType
+ ErrorType
+ BoolType
+ TimestampMillisType
+ TimeType
+ DurationType
+ Int64Type
+ Int32Type
+ IntType
+ Uint64Type
+ Uint32Type
+ UintType
+ Float64Type
+ Float32Type
+ BinaryType
+ ArrayType
+ MapType
+)
+
+type Field struct {
+ Key string
+ Type FieldType
+ Integer int64
+ Float float64
+ String string
+ Interface interface{}
+}
+
+func quoteString(w io.Writer, s string, shouldQuote func(s string) bool) error {
+ b := shouldQuote(s)
+ if b {
+ if _, err := w.Write(Quote); err != nil {
+ return err
+ }
+ }
+
+ if _, err := w.Write([]byte(s)); err != nil {
+ return err
+ }
+
+ if b {
+ if _, err := w.Write(Quote); err != nil {
+ return err
+ }
+ }
+ return nil
+}
+
+// ValueString converts a known type to a string using default formatting.
+// This is called lazily by a formatter.
+// Formatters can provide custom formatting or types passed via `Any` can implement
+// the `LogString` interface to generate output for logging.
+// If the optional shouldQuote callback is provided, then it will be called for any
+// string output that could potentially need to be quoted.
+func (f Field) ValueString(w io.Writer, shouldQuote func(s string) bool) error {
+ if shouldQuote == nil {
+ shouldQuote = func(s string) bool { return false }
+ }
+ var err error
+ switch f.Type {
+ case StringType:
+ err = quoteString(w, f.String, shouldQuote)
+
+ case StringerType:
+ s, ok := f.Interface.(fmt.Stringer)
+ if ok {
+ err = quoteString(w, s.String(), shouldQuote)
+ } else if f.Interface == nil {
+ err = quoteString(w, "", shouldQuote)
+ } else {
+ err = fmt.Errorf("invalid fmt.Stringer for key %s", f.Key)
+ }
+
+ case StructType:
+ s, ok := f.Interface.(LogWriter)
+ if ok {
+ err = s.LogWrite(w)
+ break
+ }
+ // structs that do not implement LogWriter fall back to reflection via Printf.
+ // TODO: create custom reflection-based encoder.
+ _, err = fmt.Fprintf(w, "%v", f.Interface)
+
+ case ErrorType:
+ // TODO: create custom error encoder.
+ err = quoteString(w, fmt.Sprintf("%v", f.Interface), shouldQuote)
+
+ case BoolType:
+ var b bool
+ if f.Integer != 0 {
+ b = true
+ }
+ _, err = io.WriteString(w, strconv.FormatBool(b))
+
+ case TimestampMillisType:
+ ts := time.Unix(f.Integer/1000, (f.Integer%1000)*int64(time.Millisecond))
+ err = quoteString(w, ts.UTC().Format(TimestampMillisFormat), shouldQuote)
+
+ case TimeType:
+ t, ok := f.Interface.(time.Time)
+ if !ok {
+ err = errors.New("invalid time")
+ break
+ }
+ err = quoteString(w, t.Format(DefTimestampFormat), shouldQuote)
+
+ case DurationType:
+ _, err = fmt.Fprintf(w, "%s", time.Duration(f.Integer))
+
+ case Int64Type, Int32Type, IntType:
+ _, err = io.WriteString(w, strconv.FormatInt(f.Integer, 10))
+
+ case Uint64Type, Uint32Type, UintType:
+ _, err = io.WriteString(w, strconv.FormatUint(uint64(f.Integer), 10))
+
+ case Float64Type, Float32Type:
+ size := 64
+ if f.Type == Float32Type {
+ size = 32
+ }
+ err = quoteString(w, strconv.FormatFloat(f.Float, 'f', -1, size), shouldQuote)
+
+ case BinaryType:
+ b, ok := f.Interface.([]byte)
+ if ok {
+ _, err = fmt.Fprintf(w, "[%X]", b)
+ break
+ }
+ _, err = fmt.Fprintf(w, "[%v]", f.Interface)
+
+ case ArrayType:
+ a := reflect.ValueOf(f.Interface)
+ arr:
+ for i := 0; i < a.Len(); i++ {
+ item := a.Index(i)
+ switch v := item.Interface().(type) {
+ case LogWriter:
+ if err = v.LogWrite(w); err != nil {
+ break arr
+ }
+ case fmt.Stringer:
+ if err = quoteString(w, v.String(), shouldQuote); err != nil {
+ break arr
+ }
+ default:
+ s := fmt.Sprintf("%v", v)
+ if err = quoteString(w, s, shouldQuote); err != nil {
+ break arr
+ }
+ }
+ if _, err = w.Write(Comma); err != nil {
+ break arr
+ }
+ }
+
+ case MapType:
+ a := reflect.ValueOf(f.Interface)
+ iter := a.MapRange()
+ it:
+ for iter.Next() {
+ if _, err = io.WriteString(w, iter.Key().String()); err != nil {
+ break it
+ }
+ if _, err = w.Write(Equals); err != nil {
+ break it
+ }
+ val := iter.Value().Interface()
+ switch v := val.(type) {
+ case LogWriter:
+ if err = v.LogWrite(w); err != nil {
+ break it
+ }
+ case fmt.Stringer:
+ if err = quoteString(w, v.String(), shouldQuote); err != nil {
+ break it
+ }
+ default:
+ s := fmt.Sprintf("%v", v)
+ if err = quoteString(w, s, shouldQuote); err != nil {
+ break it
+ }
+ }
+ if _, err = w.Write(Comma); err != nil {
+ break it
+ }
+ }
+
+ case UnknownType:
+ _, err = fmt.Fprintf(w, "%v", f.Interface)
+
+ default:
+ err = fmt.Errorf("invalid type %d", f.Type)
+ }
+ return err
+}
+
+func nilField(key string) Field {
+ return String(key, "")
+}
+
+func fieldForAny(key string, val interface{}) Field {
+ switch v := val.(type) {
+ case LogCloner:
+ if v == nil {
+ return nilField(key)
+ }
+ c := v.LogClone()
+ return Field{Key: key, Type: StructType, Interface: c}
+ case *LogCloner:
+ if v == nil {
+ return nilField(key)
+ }
+ c := (*v).LogClone()
+ return Field{Key: key, Type: StructType, Interface: c}
+ case LogWriter:
+ if v == nil {
+ return nilField(key)
+ }
+ return Field{Key: key, Type: StructType, Interface: v}
+ case *LogWriter:
+ if v == nil {
+ return nilField(key)
+ }
+ return Field{Key: key, Type: StructType, Interface: *v}
+ case bool:
+ return Bool(key, v)
+ case *bool:
+ if v == nil {
+ return nilField(key)
+ }
+ return Bool(key, *v)
+ case float64:
+ return Float64(key, v)
+ case *float64:
+ if v == nil {
+ return nilField(key)
+ }
+ return Float64(key, *v)
+ case float32:
+ return Float32(key, v)
+ case *float32:
+ if v == nil {
+ return nilField(key)
+ }
+ return Float32(key, *v)
+ case int:
+ return Int(key, v)
+ case *int:
+ if v == nil {
+ return nilField(key)
+ }
+ return Int(key, *v)
+ case int64:
+ return Int64(key, v)
+ case *int64:
+ if v == nil {
+ return nilField(key)
+ }
+ return Int64(key, *v)
+ case int32:
+ return Int32(key, v)
+ case *int32:
+ if v == nil {
+ return nilField(key)
+ }
+ return Int32(key, *v)
+ case int16:
+ return Int32(key, int32(v))
+ case *int16:
+ if v == nil {
+ return nilField(key)
+ }
+ return Int32(key, int32(*v))
+ case int8:
+ return Int32(key, int32(v))
+ case *int8:
+ if v == nil {
+ return nilField(key)
+ }
+ return Int32(key, int32(*v))
+ case string:
+ return String(key, v)
+ case *string:
+ if v == nil {
+ return nilField(key)
+ }
+ return String(key, *v)
+ case uint:
+ return Uint(key, v)
+ case *uint:
+ if v == nil {
+ return nilField(key)
+ }
+ return Uint(key, *v)
+ case uint64:
+ return Uint64(key, v)
+ case *uint64:
+ if v == nil {
+ return nilField(key)
+ }
+ return Uint64(key, *v)
+ case uint32:
+ return Uint32(key, v)
+ case *uint32:
+ if v == nil {
+ return nilField(key)
+ }
+ return Uint32(key, *v)
+ case uint16:
+ return Uint32(key, uint32(v))
+ case *uint16:
+ if v == nil {
+ return nilField(key)
+ }
+ return Uint32(key, uint32(*v))
+ case uint8:
+ return Uint32(key, uint32(v))
+ case *uint8:
+ if v == nil {
+ return nilField(key)
+ }
+ return Uint32(key, uint32(*v))
+ case []byte:
+ if v == nil {
+ return nilField(key)
+ }
+ return Field{Key: key, Type: BinaryType, Interface: v}
+ case time.Time:
+ return Time(key, v)
+ case *time.Time:
+ if v == nil {
+ return nilField(key)
+ }
+ return Time(key, *v)
+ case time.Duration:
+ return Duration(key, v)
+ case *time.Duration:
+ if v == nil {
+ return nilField(key)
+ }
+ return Duration(key, *v)
+ case error:
+ return NamedErr(key, v)
+ case fmt.Stringer:
+ if v == nil {
+ return nilField(key)
+ }
+ return Field{Key: key, Type: StringerType, Interface: v}
+ case *fmt.Stringer:
+ if v == nil {
+ return nilField(key)
+ }
+ return Field{Key: key, Type: StringerType, Interface: *v}
+ default:
+ return Field{Key: key, Type: UnknownType, Interface: val}
+ }
+}
+
+// FieldSorter provides sorting of an array of fields by key.
+type FieldSorter []Field
+
+func (fs FieldSorter) Len() int { return len(fs) }
+func (fs FieldSorter) Less(i, j int) bool { return fs[i].Key < fs[j].Key }
+func (fs FieldSorter) Swap(i, j int) { fs[i], fs[j] = fs[j], fs[i] }