Configure logging for Windows Service using log4net — Part 2

This blog post is part of the series How to: Create Windows Service that schedules jobs, logs and is configurable by means of dependency injection.

In previous blog post, we created a simple Windows Service with Topshelf which can be installed using simple command line. When we ran our Windows Service as a console application we saw the following output:

We can see there is some default logging going on here. In this blog post we will see how to configure our own logging using log4net, Apache library that is publicly available as a NuGet package. Before we show how to do just that, let’s first try to understand how logging is implemented in Topshelf.

If we decompile Topshelf’s HostFactory.New() and HostFactory.Run()methods, we can see calls to HostLogger.Get() method which returns LogWriter that does the actual logging. In HostLogger.Get() method, HostLogger uses LogWriterFactory to create LogWriter instance which is then returned. HostLogger provides default value for LogWriterFactoryproperty, which is why we see logging taking place when we run our console application. We can supply custom LogWriterFactory by calling HostLogger.UseLogger(HostLoggerConfigurator configurator). HostLoggerConfigurator is a factory for LogWriterFactory and contains a single method called CreateLogWriterFactory().

Types HostLoggerConfigurator, LogWriterFactory and LogWriter are interfaces. That means we can provide our custom implementations and supply them via HostLogger.UseLogger() method. By default, HostLoggeruses TraceHostLoggerConfigurator, TraceLogWriterFactory and TraceLogWriter implementations from Topshelf.Logging namespace. Together, they set up TraceSource with TraceListener that outputs to console — that is why we see logs in the console. TraceSource and TraceListener are types from System.Diagnostics and you can read more about them on Microsoft’s docs page.

Now that we know how logging in Topshelf works, it’s just a matter of providing our own log4net implementations for HostLoggerConfigurator, LogWriterFactory and LogWriter, or we can use NuGet package that does that for us — Topshelf.Log4Net.

After installing Topshelf.Log4Net, we can do the following:

XmlConfigurator.Configure() configures log4net from our app.config file.

hostConfigurator.UseLog4Net() provides log4net implementations for HostLoggerConfigurator, LogWriterFactory, LogWriter and supplies them to HostLogger via HostLogger.UseLogger().

Once this is done, we get the following output:

We see the logging pattern that is now configured in the provided app.configbelow.

If you are not familiar with log4net configuration API, you can learn more on https://logging.apache.org/log4net/release/manual/configuration.html.

In next post, we will configure dependency injection using Autofac.