Canonical logs are single log lines that you add at the end of every request. Each canonical log line includes all the key vitals of the request, from the request method to the status code of the response, including the request ID, user ID and details of the database calls.
For example, let's say you're building an API and you want to easily and quickly answer the following questions:
- Which routes are failing the most?
- Is a specific experiencing more failures than others?
- Is there a correlation between database latency and errors?
You can add a single log at the end of the execution that summarizes the key telemetry data about the request. These log lines are still human-readable, provide the full picture of a single request, and are easy to aggregate by your logs processor. For example:
{
"message": "Canonical POST /users",
"id": "f8ddb912-3da6-4050-82bd-6bb7a8587cd9",
"durationMS": 326,
"request": {
"http": {
"method": "POST",
"path": "/users",
"user": "5703383e-c2d8-4f72-b7d2-ab7e3d9d4e00"
}
},
"response": {
"status": "200"
},
"database": {
"numCalls": 6,
"numFailures": 1
}
}
With this single event, you can answer all the questions about the execution of this requests, or aggregated data across all requests.
There's a single step between canonical logs and distributed tracing: accurate measures of time and latencies. You can implement OpenTelemetry to further extend your observability instrumentation.