True story: I once got an unusually excellent response from Microsoft technical support. I e-mailed them a thank you note saying their service had been prompt, helpful, and courteous. The next day I got an automated reply:
"We are looking into the problem you reported and will correct the issue as soon as possible."
Do you remember something called printf debugging? Years ago, before debuggers were as common as they are now, the only way to see a program's execution flow was to make your code print a debugging output file listing information like, "About to enter function so-and-so". That way, when your program crashed, you could look at the last line in the output file to tell how far your program had gotten before dying. The line that crashed your code had to be somewhere between that point and the next print statement, so you could use the output file to zero in on the bug.
These days, debuggers have advanced to the point where we take them for granted, and printf debugging via an output text file now seems quaint. But it's still useful. Debuggers have replaced printf debugging for tracing down run-of-the- mill bugs on your own computer, but there are some areas where debuggers still can't be used very effectively. Today, we usually call printf debugging logging or instrumentation or tracing. Yet the basic idea is still the same—a debugging output file will cleanly handle many scenarios that a debugger can't.
In this chapter, we'll examine what sort of situations logging is useful for. We'll discuss what information should go in a program log, and some techniques for structuring your log optimally. Finally, we'll also talk about the classes.NET provides for logging, and we'll see the .NET recommended method for turning logging on or off without even recompiling your application.