David K. Bainbridge | 528b318 | 2017-01-23 08:51:59 -0800 | [diff] [blame^] | 1 | package logrus |
| 2 | |
| 3 | import "time" |
| 4 | |
| 5 | const DefaultTimestampFormat = time.RFC3339 |
| 6 | |
| 7 | // The Formatter interface is used to implement a custom Formatter. It takes an |
| 8 | // `Entry`. It exposes all the fields, including the default ones: |
| 9 | // |
| 10 | // * `entry.Data["msg"]`. The message passed from Info, Warn, Error .. |
| 11 | // * `entry.Data["time"]`. The timestamp. |
| 12 | // * `entry.Data["level"]. The level the entry was logged at. |
| 13 | // |
| 14 | // Any additional fields added with `WithField` or `WithFields` are also in |
| 15 | // `entry.Data`. Format is expected to return an array of bytes which are then |
| 16 | // logged to `logger.Out`. |
| 17 | type Formatter interface { |
| 18 | Format(*Entry) ([]byte, error) |
| 19 | } |
| 20 | |
| 21 | // This is to not silently overwrite `time`, `msg` and `level` fields when |
| 22 | // dumping it. If this code wasn't there doing: |
| 23 | // |
| 24 | // logrus.WithField("level", 1).Info("hello") |
| 25 | // |
| 26 | // Would just silently drop the user provided level. Instead with this code |
| 27 | // it'll logged as: |
| 28 | // |
| 29 | // {"level": "info", "fields.level": 1, "msg": "hello", "time": "..."} |
| 30 | // |
| 31 | // It's not exported because it's still using Data in an opinionated way. It's to |
| 32 | // avoid code duplication between the two default formatters. |
| 33 | func prefixFieldClashes(data Fields) { |
| 34 | if t, ok := data["time"]; ok { |
| 35 | data["fields.time"] = t |
| 36 | } |
| 37 | |
| 38 | if m, ok := data["msg"]; ok { |
| 39 | data["fields.msg"] = m |
| 40 | } |
| 41 | |
| 42 | if l, ok := data["level"]; ok { |
| 43 | data["fields.level"] = l |
| 44 | } |
| 45 | } |