| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125 | package logrusimport (	"bytes"	"encoding/json"	"fmt"	"runtime")type fieldKey string// FieldMap allows customization of the key names for default fields.type FieldMap map[fieldKey]stringfunc (f FieldMap) resolve(key fieldKey) string {	if k, ok := f[key]; ok {		return k	}	return string(key)}// JSONFormatter formats logs into parsable jsontype JSONFormatter struct {	// TimestampFormat sets the format used for marshaling timestamps.	TimestampFormat string	// DisableTimestamp allows disabling automatic timestamps in output	DisableTimestamp bool	// DisableHTMLEscape allows disabling html escaping in output	DisableHTMLEscape bool	// DataKey allows users to put all the log entry parameters into a nested dictionary at a given key.	DataKey string	// FieldMap allows users to customize the names of keys for default fields.	// As an example:	// formatter := &JSONFormatter{	//   	FieldMap: FieldMap{	// 		 FieldKeyTime:  "@timestamp",	// 		 FieldKeyLevel: "@level",	// 		 FieldKeyMsg:   "@message",	// 		 FieldKeyFunc:  "@caller",	//    },	// }	FieldMap FieldMap	// CallerPrettyfier can be set by the user to modify the content	// of the function and file keys in the json data when ReportCaller is	// activated. If any of the returned value is the empty string the	// corresponding key will be removed from json fields.	CallerPrettyfier func(*runtime.Frame) (function string, file string)	// PrettyPrint will indent all json logs	PrettyPrint bool}// Format renders a single log entryfunc (f *JSONFormatter) Format(entry *Entry) ([]byte, error) {	data := make(Fields, len(entry.Data)+4)	for k, v := range entry.Data {		switch v := v.(type) {		case error:			// Otherwise errors are ignored by `encoding/json`			// https://github.com/sirupsen/logrus/issues/137			data[k] = v.Error()		default:			data[k] = v		}	}	if f.DataKey != "" {		newData := make(Fields, 4)		newData[f.DataKey] = data		data = newData	}	prefixFieldClashes(data, f.FieldMap, entry.HasCaller())	timestampFormat := f.TimestampFormat	if timestampFormat == "" {		timestampFormat = defaultTimestampFormat	}	if entry.err != "" {		data[f.FieldMap.resolve(FieldKeyLogrusError)] = entry.err	}	if !f.DisableTimestamp {		data[f.FieldMap.resolve(FieldKeyTime)] = entry.Time.Format(timestampFormat)	}	data[f.FieldMap.resolve(FieldKeyMsg)] = entry.Message	data[f.FieldMap.resolve(FieldKeyLevel)] = entry.Level.String()	if entry.HasCaller() {		funcVal := entry.Caller.Function		fileVal := fmt.Sprintf("%s:%d", entry.Caller.File, entry.Caller.Line)		if f.CallerPrettyfier != nil {			funcVal, fileVal = f.CallerPrettyfier(entry.Caller)		}		if funcVal != "" {			data[f.FieldMap.resolve(FieldKeyFunc)] = funcVal		}		if fileVal != "" {			data[f.FieldMap.resolve(FieldKeyFile)] = fileVal		}	}	var b *bytes.Buffer	if entry.Buffer != nil {		b = entry.Buffer	} else {		b = &bytes.Buffer{}	}	encoder := json.NewEncoder(b)	encoder.SetEscapeHTML(!f.DisableHTMLEscape)	if f.PrettyPrint {		encoder.SetIndent("", "  ")	}	if err := encoder.Encode(data); err != nil {		return nil, fmt.Errorf("failed to marshal fields to JSON, %v", err)	}	return b.Bytes(), nil}
 |