Logging is a tool that has long been used to enable ex post facto debugging of apps. Unlike tracing, it is just a record of an event at a point in time. It doesn’t span a particular event. It might not give you as much information for free like tracing does but, commonly, it is much cheaper (both in terms of cost and performance) so you’re able record all logs where you might only be able to record a small proporation of traces. Structured logging means your log record is made up of key-value pairs, allowing your logs to have more consistency and for them to be easier to search (e.g. you can index by particular fields). Often by contention there is a special field for the log message (e.g. message). Whilst using string interpolation can make the message look nice in your log viewer. It makes the log message a pain to look up. This goes both ways:

  1. If you’ve found a problematic log in your log viewer, finding the source is as simple as searching your codebase for that literal string. With string interpolation you have to find the longest literal part of the string.
  2. If you want to search for specific instances of a log message all you need to do is query for that string (e.g. message: "I want to find this log message"). Rather than finding an untemplated suffix (or substring) and searching for that.

Tooling can help you a bit with (1), you could include the log source location but often that’s custom or tooling specific. I’ve found that (2) is the most frustrating if there is any templating in the log message.

Rather than including the fields in the log message, instead, include the fields of interest using your log aggregation tool. For example, in an OpenSearch based log viewer, you can add fields to the summary line for a log. If this is something you use often you can turn it into a saved search.