The goal of this document is to summarize the differences between various structured logging libraries, in order to encourage a discussion so that a consensus can be reached for a common format.
Please use the GitHub issues for discussion, and submit GitHub Pull requests to add/fix the information in the tables.
Behold the following logging command that you might find in an application. There is a "message" string, and a "payload" object:
logger.info("Hello World", {"animal": "cat", "numLegs": 4})
^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Message Payload object
Some libraries merge the payload object with the root object, so the event will look like this:
{
"timestamp": "2018-06-18T23:16:45.000Z",
"message": "Hello World",
"animal": "cat",
"numLegs": 4
}
While other libraries nest the payload object beneath some key, with a result like this:
{
"timestamp": "2018-06-18T23:16:45.000Z",
"message": "Hello World",
"data": {
"animal": "cat",
"numLegs": 4
}
}
Library | Message JSON Key | Payload Object JSON Key |
---|---|---|
bunyan (JavaScript) | msg |
Merged with root |
katip (Haskell) | msg |
data |
logrus (Go) | msg |
Merged with root |
logstash | message |
Merged with root |
ougai (Ruby) | msg |
Merged with root |
pygogo (Python) | message |
Merged with root |
roarr (JavaScript) | message |
context |
semantic logger (Ruby) | message |
payload |
serilog (C#) | @m / @mt |
Merged with root |
slog (Rust) | msg |
Merged with root |
structlog (Python) | msg |
HELP NEEDED |
All libraries automatically add a timestamp to all events.
Library | Timestamp JSON Key | Timestamp format |
---|---|---|
bunyan (JavaScript) | time |
ISO 8601 |
katip (Haskell) | at |
ISO 8601 |
logrus (Go) | time |
ISO 8601 |
logstash | timestamp / @timestamp |
ISO 8601 / varies |
ougai (Ruby) | time |
ISO 8601 |
pygogo (Python) | time |
ISO 8601 |
roarr (JavaScript) | time |
Epoch milliseconds |
semantic logger (Ruby) | timestamp |
ISO 8601 |
serilog (C#) | Timestamp / @t |
ISO 8601 |
slog (Rust) | ts |
ISO 8601 |
structlog (Python) | timestamp |
ISO 8601 |
All libraries require that that all events are tagged with a level, chosen from a pre-defined list of available levels.
Library | Log Level JSON Key |
---|---|
bunyan (JavaScript) | level |
katip (Haskell) | sev |
logrus (Go) | level |
logstash | HELP NEEDED |
ougai (Ruby) | level |
pygogo (Python) | level |
roarr (JavaScript) | context.logLevel |
semantic logger (Ruby) | level |
serilog (C#) | Level / @l |
slog (Rust) | level |
structlog (Python) | level |
Library | VERBOSE | TRACE | DEBUG | INFO | NOTICE | WARNING | ERROR | CRITICAL | ALERT | FATAL | PANIC | EMERGENCY |
---|---|---|---|---|---|---|---|---|---|---|---|---|
bunyan (JavaScript) | N/A | 10 |
20 |
30 |
N/A | 40 |
50 |
N/A | N/A | 60 |
N/A | N/A |
katip (Haskell) | N/A | N/A | Debug |
Info |
Notice |
Warning |
Error |
Critical |
Alert |
N/A | N/A | Emergency |
logrus (Go) | N/A | N/A | debug |
info |
N/A | warning |
error |
N/A | N/A | fatal |
panic |
N/A |
logstash | HELP NEEDED | HELP NEEDED | HELP NEEDED | HELP NEEDED | HELP NEEDED | HELP NEEDED | HELP NEEDED | HELP NEEDED | HELP NEEDED | HELP NEEDED | HELP NEEDED | HELP NEEDED |
ougai (Ruby) | N/A | 10 |
20 |
30 |
N/A | 40 |
50 |
N/A | N/A | 60 |
N/A | N/A |
pygogo (Python) | N/A | N/A | DEBUG |
INFO |
N/A | WARNING |
ERROR |
CRITICAL |
N/A | N/A | N/A | N/A |
roarr (JavaScript) | N/A | 10 |
20 |
30 |
N/A | 40 |
50 |
N/A | N/A | 60 |
N/A | N/A |
semantic logger (Ruby) | N/A | trace |
debug |
info |
N/A | warn |
error |
N/A | N/A | fatal |
N/A | N/A |
serilog (C#) | Verbose |
N/A | Debug |
Information |
N/A | Warning |
Error |
N/A | N/A | Fatal |
N/A | N/A |
slog (Rust) | N/A | TRACE |
DEBUG |
INFO |
N/A | WARN |
ERROR |
CRITICAL |
N/A | N/A | N/A | N/A |
structlog (Python) | N/A | N/A | debug |
info |
N/A | warning |
error |
critical |
N/A | N/A | N/A | N/A |
Some libraries automatically add additional fields to all events (such as process ID and thread ID) and/or allow you to configure a few pre-determined global fields suchs the current environment and application.
Library | Environment | Application | Namespace | Package | Machine Hostname | Process ID | Thread ID |
---|---|---|---|---|---|---|---|
bunyan (JavaScript) | N/A | N/A | N/A | N/A | hostname |
pid |
N/A |
katip (Haskell) | env |
app (Array of strings) |
ns (Array of strings) |
N/A | host |
pid |
thread |
logrus (Go) | N/A | N/A | N/A | N/A | N/A | N/A | N/A |
logstash | HELP NEEDED | HELP NEEDED | HELP NEEDED | HELP NEEDED | HELP NEEDED | HELP NEEDED | HELP NEEDED |
ougai (Ruby) | N/A | app |
N/A | N/A | hostname |
pid |
N/A |
pygogo (Python) | N/A | N/A | N/A | N/A | N/A | N/A | N/A |
roarr (JavaScript) | N/A | context.application |
context.namespace |
context.package |
context.hostname |
N/A | N/A |
semantic logger (Ruby) | environment |
application |
N/A | N/A | host |
pid |
thread |
serilog (C#) | N/A | N/A | N/A | N/A | N/A | N/A | N/A |
slog (Rust) | N/A | N/A | N/A | N/A | N/A | N/A | N/A |
structlog (Python) | N/A | N/A | N/A | N/A | N/A | N/A | N/A |
Logging of HTTP requests is very common. Let's figure out a common format for HTTP method, host, url, headers, remote IP, remote IP geo-lookup, response status code, response size, etc...
!!! TODO !!!