github.com/hellobchain/third_party@v0.0.0-20230331131523-deb0478a2e52/go-kit/kit/log/json_logger.go (about)

     1  package log
     2  
     3  import (
     4  	"encoding"
     5  	"encoding/json"
     6  	"fmt"
     7  	"io"
     8  	"reflect"
     9  )
    10  
    11  type jsonLogger struct {
    12  	io.Writer
    13  }
    14  
    15  // NewJSONLogger returns a Logger that encodes keyvals to the Writer as a
    16  // single JSON object. Each log event produces no more than one call to
    17  // w.Write. The passed Writer must be safe for concurrent use by multiple
    18  // goroutines if the returned Logger will be used concurrently.
    19  func NewJSONLogger(w io.Writer) Logger {
    20  	return &jsonLogger{w}
    21  }
    22  
    23  func (l *jsonLogger) Log(keyvals ...interface{}) error {
    24  	n := (len(keyvals) + 1) / 2 // +1 to handle case when len is odd
    25  	m := make(map[string]interface{}, n)
    26  	for i := 0; i < len(keyvals); i += 2 {
    27  		k := keyvals[i]
    28  		var v interface{} = ErrMissingValue
    29  		if i+1 < len(keyvals) {
    30  			v = keyvals[i+1]
    31  		}
    32  		merge(m, k, v)
    33  	}
    34  	return json.NewEncoder(l.Writer).Encode(m)
    35  }
    36  
    37  func merge(dst map[string]interface{}, k, v interface{}) {
    38  	var key string
    39  	switch x := k.(type) {
    40  	case string:
    41  		key = x
    42  	case fmt.Stringer:
    43  		key = safeString(x)
    44  	default:
    45  		key = fmt.Sprint(x)
    46  	}
    47  
    48  	// We want json.Marshaler and encoding.TextMarshaller to take priority over
    49  	// err.Error() and v.String(). But json.Marshall (called later) does that by
    50  	// default so we force a no-op if it's one of those 2 case.
    51  	switch x := v.(type) {
    52  	case json.Marshaler:
    53  	case encoding.TextMarshaler:
    54  	case error:
    55  		v = safeError(x)
    56  	case fmt.Stringer:
    57  		v = safeString(x)
    58  	}
    59  
    60  	dst[key] = v
    61  }
    62  
    63  func safeString(str fmt.Stringer) (s string) {
    64  	defer func() {
    65  		if panicVal := recover(); panicVal != nil {
    66  			if v := reflect.ValueOf(str); v.Kind() == reflect.Ptr && v.IsNil() {
    67  				s = "NULL"
    68  			} else {
    69  				panic(panicVal)
    70  			}
    71  		}
    72  	}()
    73  	s = str.String()
    74  	return
    75  }
    76  
    77  func safeError(err error) (s interface{}) {
    78  	defer func() {
    79  		if panicVal := recover(); panicVal != nil {
    80  			if v := reflect.ValueOf(err); v.Kind() == reflect.Ptr && v.IsNil() {
    81  				s = nil
    82  			} else {
    83  				panic(panicVal)
    84  			}
    85  		}
    86  	}()
    87  	s = err.Error()
    88  	return
    89  }