Keeping Your Code Clean while Logging
Editorial Note: I originally wrote this post for the LogEntries blog. You can check out the original here, at their site. While you’re there, take a look at their product offering that handles your log aggregation, search, and alerting needs.
In my consultancy practice, one of the things that I do most frequently is help teams write so-called “clean code.” Usually, this orients around test-driven development (TDD) and writing code that is easily maintained via regression tests and risk-free refactoring. Teams want to understand how to do this, and how to do it in their production code (as opposed to in some kind of toy “let’s build a calculator” exercise).
One of the most prominent, early sticking points that rears its head tends to be application logging. Why? Unit testing is all about isolating objects, instantiating them, and rapidly verifying their behavior in memory. Logging is all about dumping as much information as possible to a file (or database, service, etc with appenders) from as many places as possible. Unstoppable force, meet immovable object.
For instance, consider the following C# code from a “let’s build a calculator” exercise.
[TestMethod] public void Adding_Numbers_Works() { var target = new Calculator(); var result = target.Add(2, 2); Assert.AreEqual<int>(4, result); } public class Calculator { public int Add(int x, int y) { return x + y; } }
Life here is good. The calculator’s add method returns the sum of the integers, and we have a test method that supplies 2 and 2, and confirms a result of 4. That’s a screaming fast, very clear test. But, consider what happens if we amend our calculator to take advantage of logging.
public class Calculator { public int Add(int x, int y) { Logger.Log($"Entering add method with parameters {x} and {y}."); Logger.Log($"Returning result of {x + y}"); return x + y; } }
Now, with that same test, everything goes wrong. Instead of passing, it throws an exception about not having write access to some weird directory on your machine that you’ve never even heard of. After digging a bit, you see that it’s the directory in which the test runner executes when running your solution’s tests. Hmmm.