Ultimate Guide to Logging

Your open-source resource for understanding, analyzing, and troubleshooting system logs

.NET Logging Libraries

Microsoft provides you with an excellent source for logging errors into the event viewer, but it’s sometimes too difficult to analyze issues when using the default library source. Let’s say you have 10 web servers hosting a web application. If you write errors to each server’s event viewer, it can be extremely time-consuming to find out which server is having issues. In many cases, one server could have a hardware issue, or synchronization between software versions isn’t executed properly. If you write to the event viewer, administrators need to go back into each web server and review individual event viewer information. This can get tedious for large web farm administrators. The option is to log errors to files. If you wanted to write logs to files, you’d need to create your own layer that logs errors to a specific repository. Instead of relying on file I/O classes, you can incorporate a free logging library. These logging libraries support multiple outputs like syslog and HTTP, and can show you the time the event happened, the type of error (DEBUG vs. ERROR vs. WARNING), the exception message, and the location of the error. You can even log to a central location off the production server to reduce overhead, improve security, and aggregate all your logs in one place (or feed them to a dedicated log management solution) to allow for cohesive analytics and central archiving. There are several available on the market, but only a few are considered reliable and truly convenient for the coder.

In this section, we’ll cover three common logging libraries that make logging .NET information much more convenient. We benchmarked the Microsoft Enterprise Library along with others and found that Enterprise was much slower and more difficult to use than the libraries we mention here. In most .NET teams, the two main choices for external libraries are NLog and log4net. You can decide for yourself which logging libraries to use, but the following ones we discuss are the most convenient to get started.

Log4net

Log4net is one of the most common external logging services available to .NET developers. The developers for log4net promise you can have logging integrated with your application within minutes, and it’s true—setup is easy. Log4net is available in NuGet, so it’s just as easy to install as it is to code. Open NuGet Packages in Visual Studio, type “log4net” in the search bar, and select the package. Click “Install” and NuGet installs the appropriate DLLs into your project.

The following code is an example of logging an error in log4net.

private static readonly log4net.ILog log = log4net.LogManager.GetLogger("tests");
        public ActionResult Index()
        {
            log.Error("Event Test");
            return View();
        }

In the code above, we declare the log4net variable as a static private variable that the entire class can access. We could declare it in the Index method, but then it would be local, and we’d have to declare a variable in every method. You want to perform logging in every method to help ensure each part of your code traps errors.

The above code logs to a log4net file, but it doesn’t do you any good to just log an error without an actual error triggering. We can incorporate the log4net code with the error trapping that we discussed in the .NET Logging Basics section.

try
 {
    result = num1 / num2;
 }
catch (DivideByZeroException e)
{
    log.Error("Event Test");
    return View();
}

If you recall from the event viewer code in the .NET Logging Basics article, the above example greatly reduces the amount of code you need to create compared to using the event viewer. Of course, you’d want to get more detailed in your logged error. The above code just adds “Event Test” to the log file. You can get as detailed as needed. For instance, you could write the server name, application name, time of the event, and the error message. By identifying the server in your log files, administrators and developers know exactly which server is causing the error. Typically, you would define these variables in your web.config or app.config file.

Each exception class has its own properties you can use to print direct errors triggered from your code. When you print full reports of your errors, just remember it can be more difficult to parse and read, especially when you have several servers to review. A log management solution can make analyzing these logs easier.

NLog

NLog is just as easy—if not easier—than log4net. NLog is also available from NuGet. From the NuGet console, type the following to install the package to your solution:

Install-Package NLog.Config

Just like log4net, you can create a static global class variable for the NLog logger. This means you don’t need to create a new variable for each of your class methods if you choose to create your log variables at the class level.

private static Logger logger = LogManager.GetCurrentClassLogger();
 
        public ActionResult Index()
        {
            logger.Trace("Sample trace message");
            logger.Debug("Sample debug message");
            logger.Info("Sample informational message");
            logger.Warn("Sample warning message");
            logger.Error("Sample error message");
            logger.Fatal("Sample fatal error message");
            return View();
        }

With the logger NLog class variable defined, you can now write content to the log. As discussed in the log4net section, you probably will want to put NLog logging events in a try-catch block. The following code moves the event into a try-catch block.

try
{
    result = num1 / num2;
}
catch (DivideByZeroException e)
{
    logger.Fatal("The application crashed!");
    return View();
} 

Note that in this example, we assume that instantiation of the class is performed in the method. However, the best way to declare the logger variable would be through dependency injection by passing it to the constructor of the class.