Logging records runtime events and diagnostic information so an application can expose what it is doing without coupling business logic to a particular output mechanism. A useful subsystem accepts a message and level, selects a destination, and supports interchangeable implementations. section 10.1 section 10.1.1
A practical logging design separates policy from implementation:
- Expose an interface containing message and level rather than filenames or other destination-specific details. section 10.1.1
- Allow file, console, or external aggregation destinations through multiple implementations. section 10.1
- Choose synchronous or asynchronous delivery and structured or unstructured formatting according to application needs. section 10.1
- Represent logging as a free-monadic language when business actions need logging without directly performing effects. section 10.1.1
Logging inside transactional state
Logging directly from STM can repeat messages when a transaction restarts. A safer design interprets transactional logging into a concurrent log buffer, commits the state action, then flushes the entries through the real logger. This keeps logging out of business return values and preserves levels without requiring callers to remember ad hoc flushing. section 10.2.2
Listing 10.1 Logger in C#
public interface ILogger { #1
void logMessage(int logLevel, string message);
};
public class FileLogger : ILogger { #2
private int _logLevel;
private string _file;
public FileLogger(int logLevel, string file) {
_logLevel = logLevel;
_file = file;
}
public void logMessage(int logLevel, string message) {
if (logLevel <= _logLevel) #3
using (StreamWriter log = File.AppendText(_file)) { #4
log.WriteLine(message);
}
}
};
The annotated C# listing contrasts a small implementation-neutral logger interface with a file logger that filters by level and appends messages to a file. section 10.1.1







































