I have been told to add “logging” to my code using log4net, the problem is no one can travel in time and see what real world problems the logging will need to be used to solve.<
What kinds of logging should one add to an application that would be useful later?
If you throw exceptions from your own exception classes, or even better, all your exception classes derive from a base class, add ERROR level logging in the (base) exception constructor; saves you having to remember on each catch/throw. Useful if you have a large code base.
For CLR or 3rd party exceptions, log Exception.ToString() not just the message, otherwise you miss the full stack trace (assuming programmers are not swallowing exceptions or re-throwing sans inner exception)
Focus on DEBUG detail in areas where you either know or suspect you will have issues (just ask QA or Tech Support where to look;-)
If you follow the robustness principle, then you may want INFO or WARN logging when you ignore or change inputs, or expected behaviour. This could be useful if your WCF service starts receiving unexpected (but parseable) input.
To ensure your application performs well, don't ship/install it with DEBUG level logging enabled by default, ERROR or WARN is probably the way to go.
I disagree with the last part of the accepted answer, because log4net has awesome filtering capabilities; on the condition that your programmers understand that logging comes at a cost (as per CK's answer) and they (and QA and Tech Support) know about the filters, and that configuring everything at DEBUG is a bad idea. If you are logging at DEBUG level a large object graph, xml document, db result, et cetera, wrap it in some code that reduces the expense:
if (log.IsDebugEnabled)
{
log.DebugFormat("Loaded in {0} ms {1}", timer.ElapsedMilliseconds, dataSet.GetXml());
}
I would suggest you follow the recommended static logger-per-class approach, simply because it should make logging more useful when you have to actually use it and narrow down on a problem using filters, e.g. LoggerMatchFilter.
If you follow this approach and are willing take a (fairly small) performance hit, here's one way which uses a stack trace to create ILog objects for any class and ensure the config file is wired up to monitor for changes:
public static class LogFactory
{
///
/// Create log whose name is the calling methods class name.
///
///
///
/// Configures the log repository if it hasn't been configured before.
///
///
/// Creates a debug log message right after getting the logger, this follows
/// the log4net recommendation to log first message as early as possible.
///
///
/// Log ready for work.
public static log4net.ILog Create()
{
var method = new StackTrace().GetFrame(1).GetMethod();
var log = log4net.LogManager.GetLogger(method.DeclaringType);
if (log4net.LogManager.GetRepository().Configured == false)
{
try
{
new FileIOPermission(FileIOPermissionAccess.Read,
AppDomain.CurrentDomain.SetupInformation.ConfigurationFile)
.Demand();
var configFile = new FileInfo(AppDomain.CurrentDomain.SetupInformation.ConfigurationFile);
log4net.Config.XmlConfigurator.ConfigureAndWatch(configFile);
log.DebugFormat("Log4net configured and watching {0}", configFile.FullName);
}
catch (System.Security.SecurityException e)
{
log.DebugFormat("Unable to watch config file due to security permissions. {0}", e.ToString());
}
}
log.DebugFormat("Logging {0}", log.Logger.Name);
return log;
}
}