Logging in NServiceBus
Like many other open-source frameworks on the .NET platform
NServiceBus makes use of Log4Net for its logging capabilities.
Familiar to developers and administrators alike,
Log4Net has years of production use under its belt.
NServiceBus extends the Log4Net APIs with a much simplified
model that prevents administrators from accidentally
changing behaviors set by developers at design time.
Logging Basics
Starting logging with NServiceBus is as simple as calling:
NServiceBus.Configure.With().Log4Net();
This makes use of the ConsoleAppender setting the logging threshold to Debug.
This means that all logging statements performed by NServiceBus or the application
at a level at, or above Debug (like Warn, Error, and Fatal) will be sent to the
console for output.
Calling Log4Net from your code is very straightforward. Often you'll set up a single static
readonly reference to a logger in your classes, and then use it in all your methods like this:
using log4net;
namespace YourNamespace
{
public class YourClass
{
public void SomeMethod()
{
//your code
Logger.Debug("Something interesting happened.");
}
private static readonly ILog Logger = LogManager.GetLogger("Name");
}
}
In order to make use of the standard Log4Net configuration found in the application
configuration file, the following call needs to be made before the call to 'NServiceBus.Configure.With()':
NServiceBus.SetLoggingLibrary.Log4Net(log4net.Config.XmlConfigurator.Configure);
The reason that this isn't supported in the fluent initialization API is that NServiceBus frowns on the log4net
model of mixing developer settings (like the type of appender - console, file, etc) and administrator
settings (like the logging level) in the same place. In its place, NServiceBus suggests more operations-friendly
approaches as described further down this page.
The Log4Net configuration section that would be included in the application configuration file
that results in the Debug threshold with the ConsoleAppender is shown here:
<log4net debug="false">
<appender name="console" type="log4net.Appender.ConsoleAppender">
<layout type="log4net.Layout.PatternLayout">
<param name="ConversionPattern" value="%d [%t] %-5p %c [%x] <%X{auth}> - %m%n"/>
</layout>
</appender>
<root>
<level value="DEBUG"/>
<appender-ref ref="console"/>
</root>
</log4net>
For more information about standard Log4Net functionality, see the Log4Net home page.
Logging message contents
When NServiceBus receives a message, it writes the result of the "ToString()" method of
the message class to the log. By default, this will write the name of the message type only.
If you want the full message contents to be written to the log, override the "ToString()"
method of the relevant message class. Here's an example:
public class MyMessage : IMessage
{
public Guid EventId { get; set; }
public DateTime? Time { get; set; }
public TimeSpan Duration { get; set; }
public override string ToString()
{
return string.Format(
"MyMessage: EventId={0}, Time={1}, Duration={2}",
EventId, Time, Duration
);
}
}
Note that NServiceBus will only make this calls at a log threshold of DEBUG or lower.
Customized Logging
You can tell NServiceBus to use any of the built-in Log4Net appenders and specifying
additional properties of the chosen appender by using the following API:
NServiceBus.Configure.With().Log4Net<SmtpAppender>(a => a.From = "no-reply@YourApp.YourCompany.com");
This example will have all logging calls sent using SMTP from the email address 'no-reply@YourApp.YourCompany.com'.
If there isn't a built-in appender for the technology you want to use for logging,
write a class which inherits from AppenderSkeleton as follows:
public class YourAppender : log4net.Appender.AppenderSkeleton
{
public string YourProperty { get; set; }
protected override void Append(LoggingEvent loggingEvent)
{
//call your logging technology here
}
}
Then plug your appender into NServiceBus like this:
NServiceBus.Configure.With().Log4Net<YourAppender>(a => a.YourProperty = "value");
As you can see, there isn't very much effort involved in plugging in your own logging technology.
That being said, with the number of appenders available out of the box with Log4Net,
you should be able to find something to suit your needs. Here's a taste:
- ADO.NET
- ASP.NET Trace
- System.Diagnostics.Debug
- System.Diagnostics.Trace
- System Event Log
- Rolling File
- SMTP
- UDP
Administrative Configuration
As you saw before, most of the logging configuration done with NServiceBus is done in code.
This prevents administrators from accidentally changing values set by developers. It also
provides developers with compile-time checking, intellisense, and the other
productivity-enhancing capabilities of Visual Studio.
Yet there are certain parameters that need to be under administrative control. The main
parameter is the logging resolution - how much information is logged. Logging only errors
is usually desirable in production scenarios as it gives the best performance. Yet, when
a system behaves erratically, having more information logged can give greater insight into
what is causing the problems.
This is controlled by the application configuration file by including the following entries:
<configSections>
<section name="Logging" type="NServiceBus.Config.Logging, NServiceBus.Core" />
</configSections>
<Logging Threshold="WARN" />
The value of the 'Threshold' attribute of the 'Logging' element can be any of the standard
Log4Net entries: ALERT, ALL, CRITICAL, DEBUG, EMERGENCY, ERROR, FATAL, FINE, FINER, FINEST,
INFO, NOTICE, OFF, SEVERE, TRACE, VERBOSE, and WARN. Make sure you use all caps for these entries.
Note that if the developer set this value in code, the configuration value will be ignored.
Next Steps
In order to avoid abusing the logging capabilities, see how auditing is handled.