Jonathan Hart | f86817b | 2018-08-17 10:35:54 -0700 | [diff] [blame] | 1 | package logrus |
| 2 | |
| 3 | import "time" |
| 4 | |
Matteo Scandolo | 1f49bf5 | 2018-11-20 13:56:45 -0800 | [diff] [blame] | 5 | // Default key names for the default fields |
| 6 | const ( |
| 7 | defaultTimestampFormat = time.RFC3339 |
| 8 | FieldKeyMsg = "msg" |
| 9 | FieldKeyLevel = "level" |
| 10 | FieldKeyTime = "time" |
| 11 | FieldKeyLogrusError = "logrus_error" |
| 12 | FieldKeyFunc = "func" |
| 13 | FieldKeyFile = "file" |
| 14 | ) |
Jonathan Hart | f86817b | 2018-08-17 10:35:54 -0700 | [diff] [blame] | 15 | |
| 16 | // The Formatter interface is used to implement a custom Formatter. It takes an |
| 17 | // `Entry`. It exposes all the fields, including the default ones: |
| 18 | // |
| 19 | // * `entry.Data["msg"]`. The message passed from Info, Warn, Error .. |
| 20 | // * `entry.Data["time"]`. The timestamp. |
| 21 | // * `entry.Data["level"]. The level the entry was logged at. |
| 22 | // |
| 23 | // Any additional fields added with `WithField` or `WithFields` are also in |
| 24 | // `entry.Data`. Format is expected to return an array of bytes which are then |
| 25 | // logged to `logger.Out`. |
| 26 | type Formatter interface { |
| 27 | Format(*Entry) ([]byte, error) |
| 28 | } |
| 29 | |
Matteo Scandolo | 1f49bf5 | 2018-11-20 13:56:45 -0800 | [diff] [blame] | 30 | // This is to not silently overwrite `time`, `msg`, `func` and `level` fields when |
Jonathan Hart | f86817b | 2018-08-17 10:35:54 -0700 | [diff] [blame] | 31 | // dumping it. If this code wasn't there doing: |
| 32 | // |
| 33 | // logrus.WithField("level", 1).Info("hello") |
| 34 | // |
| 35 | // Would just silently drop the user provided level. Instead with this code |
| 36 | // it'll logged as: |
| 37 | // |
| 38 | // {"level": "info", "fields.level": 1, "msg": "hello", "time": "..."} |
| 39 | // |
| 40 | // It's not exported because it's still using Data in an opinionated way. It's to |
| 41 | // avoid code duplication between the two default formatters. |
Matteo Scandolo | 1f49bf5 | 2018-11-20 13:56:45 -0800 | [diff] [blame] | 42 | func prefixFieldClashes(data Fields, fieldMap FieldMap, reportCaller bool) { |
| 43 | timeKey := fieldMap.resolve(FieldKeyTime) |
| 44 | if t, ok := data[timeKey]; ok { |
| 45 | data["fields."+timeKey] = t |
| 46 | delete(data, timeKey) |
Jonathan Hart | f86817b | 2018-08-17 10:35:54 -0700 | [diff] [blame] | 47 | } |
| 48 | |
Matteo Scandolo | 1f49bf5 | 2018-11-20 13:56:45 -0800 | [diff] [blame] | 49 | msgKey := fieldMap.resolve(FieldKeyMsg) |
| 50 | if m, ok := data[msgKey]; ok { |
| 51 | data["fields."+msgKey] = m |
| 52 | delete(data, msgKey) |
Jonathan Hart | f86817b | 2018-08-17 10:35:54 -0700 | [diff] [blame] | 53 | } |
| 54 | |
Matteo Scandolo | 1f49bf5 | 2018-11-20 13:56:45 -0800 | [diff] [blame] | 55 | levelKey := fieldMap.resolve(FieldKeyLevel) |
| 56 | if l, ok := data[levelKey]; ok { |
| 57 | data["fields."+levelKey] = l |
| 58 | delete(data, levelKey) |
| 59 | } |
| 60 | |
| 61 | logrusErrKey := fieldMap.resolve(FieldKeyLogrusError) |
| 62 | if l, ok := data[logrusErrKey]; ok { |
| 63 | data["fields."+logrusErrKey] = l |
| 64 | delete(data, logrusErrKey) |
| 65 | } |
| 66 | |
| 67 | // If reportCaller is not set, 'func' will not conflict. |
| 68 | if reportCaller { |
| 69 | funcKey := fieldMap.resolve(FieldKeyFunc) |
| 70 | if l, ok := data[funcKey]; ok { |
| 71 | data["fields."+funcKey] = l |
| 72 | } |
| 73 | fileKey := fieldMap.resolve(FieldKeyFile) |
| 74 | if l, ok := data[fileKey]; ok { |
| 75 | data["fields."+fileKey] = l |
| 76 | } |
Jonathan Hart | f86817b | 2018-08-17 10:35:54 -0700 | [diff] [blame] | 77 | } |
| 78 | } |