Enterprise Library Logging With No Configuration
While you can use Log4net with no configuration (it just doesn't log), you can't do it with Enterprise Library Logging. If you try to write to the logger, you get (in EntLib4) a ConfigurationErrorsException or (in EntLib5) an ActivationException.
This is some code which traps a missing configuration error and builds it manually. This is the EntLib 5 version; to use it with EntLib 4 it just uses the other error trap, and you new up a LogWriter instead of a LogWriterImpl. This is adapted from this code (EntLib 2!).
It's a singleton so just use it like LogLoader.Instance.LogWriter.Write("Error!") (see useage).
LogLoader
using System.Collections.Generic;
using System.Configuration;
using System.Diagnostics;
using Microsoft.Practices.EnterpriseLibrary.Common.Configuration;
using Microsoft.Practices.EnterpriseLibrary.Logging;
using Microsoft.Practices.EnterpriseLibrary.Logging.Filters;
using Microsoft.Practices.EnterpriseLibrary.Logging.Formatters;
using Microsoft.Practices.EnterpriseLibrary.Logging.TraceListeners;
using Microsoft.Practices.ServiceLocation;
namespace EntLib5NoConfig
{
/// <summary>
/// Singleton that gets the logWriter
/// </summary>
sealed class LogLoader
{
private const string GeneralCategory = "General";
private const string ErrorCategory = "Errors";
//Singleton pattern is Skeet #4 thread-safe without locks
private static readonly LogLoader Loader = new LogLoader();
static LogLoader()
{
// Explicit static constructor to tell C# compiler
// not to mark type as beforefieldinit
}
/// <summary>
/// Initializes a new instance of the <see cref="LogLoader"/> class.
/// </summary>
LogLoader()
{
try
{
var factory = new LogWriterFactory(ConfigurationSourceFactory.Create());
LogWriter = factory.Create();
}
catch (ConfigurationErrorsException)
{
// in EntLib4
CreateManualWriter();
}
catch (ActivationException)
{
// in EntLib5
CreateManualWriter();
}
}
/// <summary>
/// Access the singleton
/// </summary>
/// <value>The instance.</value>
public static LogLoader Instance
{
get { return Loader; }
}
/// <summary>
/// Gets the log writer.
/// </summary>
/// <value>The log writer.</value>
public LogWriter LogWriter { get; private set; }
/// <summary>
/// Creates a manual writer.
/// </summary>
public void CreateManualWriter()
{
//from http://davidhayden.com/blog/dave/archive/2006/02/18/2805.aspx
var formatter = new TextFormatter(
"Timestamp: {timestamp}{newline}" +
"Category: {category}{newline}" +
"Message: {message}{newline}" +
"Extended Properties: {dictionary({key} - {value}{newline})}");
// Log messages to event log
var logListener = new FormattedEventLogTraceListener("Enterprise Library Logging", formatter);
// var logListener = new FlatFileTraceListener("D:\\messages.log", string.Empty, string.Empty, formatter);
//this source has our listener
var mainLogSource = new LogSource(ErrorCategory, SourceLevels.All);
mainLogSource.Listeners.Add(logListener);
// Don't log to this source
var emptyLogSource = new LogSource("Empty");
// "Error" category goes to main log source
var traceSources = new Dictionary<string, LogSource> { { ErrorCategory, mainLogSource } };
// filter "Error" category
var categoryFilter = new CategoryFilter("Only Errors", new List<string> { ErrorCategory }, CategoryFilterMode.DenyAllExceptAllowed);
var filters = new List<ILogFilter> { categoryFilter };
// in EntLib5 can't use LogWriter (it's abstract) or LogWriterFactory (which uses IServiceLocator)
LogWriter = new LogWriterImpl(
//The collection of filters to use when processing an entry
filters,
//The trace sources to dispatch entries to
traceSources,
//The special LogSource to which all log entries should be logged.
mainLogSource,
//The special LogSource to which log entries with at least one non-matching category should be logged
emptyLogSource,
//The special LogSource to which internal errors must be logged
emptyLogSource,
//The default category to set when entry categories list of a log entry is empty
GeneralCategory,
//The tracing status
false,
//true if warnings should be logged when a non-matching category is found
false
);
}
}
}
Useage
I'd typically write a simpler facade over EntLib's own static Logger facade (so I can Log.Info() or Log.Error() like in Log4net).
var entry = new LogEntry
{
Severity = TraceEventType.Error,
Message = message
};
entry.Categories.Add("Error");
var frame = new StackFrame(1);
var src = frame.GetMethod().ReflectedType + "." + frame.GetMethod().Name;
entry.ExtendedProperties.Add("Stack", src);
LogLoader.Instance.LogWriter.Write(entry);