...

Source file src/github.com/go-kit/log/json_logger.go

Documentation: github.com/go-kit/log

     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  	enc := json.NewEncoder(l.Writer)
    35  	enc.SetEscapeHTML(false)
    36  	return enc.Encode(m)
    37  }
    38  
    39  func merge(dst map[string]interface{}, k, v interface{}) {
    40  	var key string
    41  	switch x := k.(type) {
    42  	case string:
    43  		key = x
    44  	case fmt.Stringer:
    45  		key = safeString(x)
    46  	default:
    47  		key = fmt.Sprint(x)
    48  	}
    49  
    50  	// We want json.Marshaler and encoding.TextMarshaller to take priority over
    51  	// err.Error() and v.String(). But json.Marshall (called later) does that by
    52  	// default so we force a no-op if it's one of those 2 case.
    53  	switch x := v.(type) {
    54  	case json.Marshaler:
    55  	case encoding.TextMarshaler:
    56  	case error:
    57  		v = safeError(x)
    58  	case fmt.Stringer:
    59  		v = safeString(x)
    60  	}
    61  
    62  	dst[key] = v
    63  }
    64  
    65  func safeString(str fmt.Stringer) (s string) {
    66  	defer func() {
    67  		if panicVal := recover(); panicVal != nil {
    68  			if v := reflect.ValueOf(str); v.Kind() == reflect.Ptr && v.IsNil() {
    69  				s = "NULL"
    70  			} else {
    71  				s = fmt.Sprintf("PANIC in String method: %v", panicVal)
    72  			}
    73  		}
    74  	}()
    75  	s = str.String()
    76  	return
    77  }
    78  
    79  func safeError(err error) (s interface{}) {
    80  	defer func() {
    81  		if panicVal := recover(); panicVal != nil {
    82  			if v := reflect.ValueOf(err); v.Kind() == reflect.Ptr && v.IsNil() {
    83  				s = nil
    84  			} else {
    85  				s = fmt.Sprintf("PANIC in Error method: %v", panicVal)
    86  			}
    87  		}
    88  	}()
    89  	s = err.Error()
    90  	return
    91  }
    92  

View as plain text