435c0d9fc8
This PR switches the Nomad repository from using govendor to Go modules for managing dependencies. Aspects of the Nomad workflow remain pretty much the same. The usual Makefile targets should continue to work as they always did. The API submodule simply defers to the parent Nomad version on the repository, keeping the semantics of API versioning that currently exists.
126 lines
3.1 KiB
Go
126 lines
3.1 KiB
Go
package logrus
|
|
|
|
import (
|
|
"bytes"
|
|
"encoding/json"
|
|
"fmt"
|
|
"runtime"
|
|
)
|
|
|
|
type fieldKey string
|
|
|
|
// FieldMap allows customization of the key names for default fields.
|
|
type FieldMap map[fieldKey]string
|
|
|
|
func (f FieldMap) resolve(key fieldKey) string {
|
|
if k, ok := f[key]; ok {
|
|
return k
|
|
}
|
|
|
|
return string(key)
|
|
}
|
|
|
|
// JSONFormatter formats logs into parsable json
|
|
type 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 entry
|
|
func (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
|
|
}
|