Welcome to CuttingEdge.Logging

CuttingEdge.Logging is a library that helps programmers to output log statements to a variety of output targets in .NET applications. The design is based on the .NET 2.0 Provider Model. This means the library uses the same configuration and extensibility model.

Contents

 

Overview

CuttingEdge.Logging is a configurable logging system and can even be plugged into ASP.NET applications without a republish or recompile. The library is written in C# .NET 3.5 in Visual Studio 2008, but the library can also be used by .NET 2.0 applications. It can be used for several types of .NET applications, such as server and desktop applications. However, Compact Edition and Silverlight are not supported.

Comparing

CuttingEdge.Logging differentiates with other logging frameworks such as log4net and the Enterprise Library Logging Application Block (LAB) in it's simplicity. CuttingEdge.Logging does not allow you to configure layouts (log4net) or formatters (LAB) to control the way events are written. Neither does it support filters (log4net and LAB) to determine which event should be logged and where to. log4net even allows you to change configuration, without an application restart (dynamic configuration) and it's compatible with Mono, .NET CE and even SSCLI.

While those two frameworks are highly configurable and composable; they are complex to configure and use. CuttingEdge.Logging is designed with the KISS principle (keep it small, simple) in mind. You won't have to read large manuals and when you are familiar with the .NET provider model, you'll feel right at home.

Usage

C# example

The following example shows some code snippets of what code a C# developer could write using CuttingEdge.Logging.

// Log an information event to the default provider.
Logger.Log("Operation completed successfully.");
    
// Log a warning to the default provider.
Logger.Log(LoggingEventType.Warning, "Server is currently under high load");
    
// Log an error event with source location to the default provider.
Logger.Log(LoggingEventType.Error,
    "Something went wrong.", MethodBase.GetCurrentMethod());
    
try
{
    this.DoSomeAction();
}
catch (Exception ex)
{
    // Log an exception to the default provider.
    Logger.Log(ex);
    throw;
}
    
// Log an information event to the default provider.
// This is equivalent to calling 'Logger.Log'.
Logger.Provider.Log("Success!", MethodBase.GetCurrentMethod());
    
// Log to an alternative provider by name (note that name is case-insensitive).
LoggingProviderBase xmlLogger = Logger.Providers["XmlLogger"];
xmlLogger.Log("Success!");
    
// Display all configured providers
foreach (LoggingProviderBase loggingProvider in Logger.Providers)
{
    Console.WriteLine(loggingProvider.Name);
}
    
// Logging providers can be chained. Using fallback providers.
// This way you can ensure a event is being logged, even if the
// default provider fails.
LoggingProviderBase fallbackProvider = Logger.Provider.FallbackProvider;
if (fallbackProvider != null)
{
    fallbackProvider.Log(LoggingEventType.Warning, "This is a warning.");
}

VB.NET example

The following example shows some code snippets of what code a VB.NET developer could write using CuttingEdge.Logging.

' Log an information event to the default provider. 
Logger.Log("Operation completed successfully.")
    
' Log a warning to the default provider. 
Logger.Log(LoggingEventType.Warning, "Server is currently under high load")
    
' Log an error event with source location to the default provider. 
Logger.Log(LoggingEventType.[Error], _
	"Something went wrong.", MethodBase.GetCurrentMethod())
    
Try
	DoSomeAction()
Catch ex As Exception
	' Log an exception to the default provider. 
	Logger.Log(ex)
	Throw
End Try
    
' Log an information event to the default provider. 
' This is equivalent to calling 'Logger.Log'. 
Logger.Provider.Log("Success!", MethodBase.GetCurrentMethod())
    
' Log to an alternative provider by name (note that name is case-insensitive).
Dim xmlLogger As LoggingProviderBase = Logger.Providers("XmlLogger")
xmlLogger.Log("Success!")

' Display all configured providers 
For Each loggingProvider As LoggingProviderBase In Logger.Providers
	Console.WriteLine(loggingProvider.Name)
Next
    
' Logging providers can be chained. Using fallback providers. 
' This way you can ensure a event is being logged, even if the 
' default provider fails. 
Dim fallbackProvider As LoggingProviderBase = Logger.Provider.FallbackProvider
If fallbackProvider IsNot Nothing Then
	fallbackProvider.Log(LoggingEventType.Warning, "This is a warning.")
End If

Basic configuration

The following example shows an app.config of a typical application that uses CuttingEdge.Logging. The configuration in this example allows logging to the Windows event log by configuring a WindowsEventLogLoggingProvider.

<?xml version="1.0"?>
<configuration>
  <configSections>
    <!-- The following section should be added to the configSections. -->
    <section name="logging"
      type="CuttingEdge.Logging.LoggingSection, CuttingEdge.Logging" />
  </configSections>
  <!-- the logging section allows you to configure logging providers -->
  <logging defaultProvider="WindowsEventLogLoggingProvider">
    <providers>
      <!-- The WindowsEventLogLoggingProvider writes to the event log -->
      <add
        name="WindowsEventLogLoggingProvider"
        type="CuttingEdge.Logging.WindowsEventLogLoggingProvider, CuttingEdge.Logging"
        source="MyWebApplication"
        logName="MyWebApplication"
      />    
    </providers>
  </logging>
</configuration>
You can find more configuration examples on the configuration examples page.

More advanced configuration

The example below shows how to configure the Logging Provider model in a web environment to log to a SQL Server database and use the Windows event log as fallback logging store. The AspNetSqlLoggingProvider is configured with the threshold set to Information, which means that Debug events will not be logged. The WindowsEventLogLoggingProvider has its threshold set to Warning, which means that Debug and Information events will not be logged. By configuring the AspNetExceptionLoggingModule http module, the web application ensures that unhandled exceptions will get logged automatically. The configured LoggingWebEventProvider will route web events, raised by the ASP.NET health monitoring system, to the Logging infrastructure.

The AspNetSqlLoggingProvider is configured with initializeSchema="True". This means it will try to create the necessary tables and stored procedures needed for it to operate. This is the alternative for manually running the SQL scripts that are supplied with the release. For initialization to succeed, the supplied connection must have the proper rights on the database. The switch must be removed after initialization; the provider will throw an exception when the database schema already exists.

<?xml version="1.0"?>
<configuration>
  <configSections>
    <section name="logging" 
      type="CuttingEdge.Logging.LoggingSection, CuttingEdge.Logging" />
  </configSections>
  <connectionStrings>
    <add name="SqlLogging"
        connectionString="Data Source=.;Integrated Security=SSPI;Initial Catalog=Logging;" />
  </connectionStrings>
  <logging defaultProvider="AspNetSqlLoggingProvider">
    <providers>
      <add
        name="AspNetSqlLoggingProvider"
        type="CuttingEdge.Logging.Web.AspNetSqlLoggingProvider, CuttingEdge.Logging"
        fallbackProvider="WindowsEventLogLoggingProvider"
        description="ASP.NET SQL logging provider example"
        connectionStringName="SqlLogging"
        threshold="Information"
        initializeSchema="True"
        applicationName="[MyWebApplication]"
        userNameRetrievalType="Membership"
        logQueryString="True"
        logFormData="False"
      />
      <add
        name="WindowsEventLogLoggingProvider"
        type="CuttingEdge.Logging.WindowsEventLogLoggingProvider, CuttingEdge.Logging"
        threshold="Warning"
        source="MyWebApplication"
        logName="MyWebApplication"
      />
    </providers>
  </logging>
  <system.web>
    <httpModules>
      <!--
        We're defining the AspNetExceptionLoggingModule here.
        This http module will always log to the default logger.
      -->
      <add
        name="UnhandledExceptionLogger"
        type="CuttingEdge.Logging.Web.AspNetExceptionLoggingModule, CuttingEdge.Logging"
      />
    </httpModules>
    <healthMonitoring heartbeatInterval="0" enabled="true">
      <providers>
        <!-- We're configuring the web event provider here. -->
        <add
          name="LoggingWebEventProvider"
          type="CuttingEdge.Logging.Web.LoggingWebEventProvider, CuttingEdge.Logging"
          loggingProvider="AspNetSqlLoggingProvider"
        />
      </providers>
      <rules>
        <add
          name="Custom Event Provider"
          eventName="All Events"
          provider="LoggingWebEventProvider"
          profile="Default"
        />
      </rules>
    </healthMonitoring>
  </system.web>
</configuration>
You can find more configuration examples on the configuration examples page.

Extending CuttingEdge.Logging

The following example shows how to extend CuttingEdge.Logging by defining a logger that logs to the file system. Note however that this is an illustrative example. The library contains an XmlFileLoggingProvider for writing log information in an XML format to the file system, and it contains an FileLoggingProviderBase that can act as base class for providers that write to the file system.

using System;
using System.Collections.Specialized;
using System.Configuration.Provider;
using System.IO;
    
using CuttingEdge.Logging;
    
namespace MyLoggingProviders
{
    public class MyFileLoggingProvider : LoggingProviderBase
    {
        private string path;
        
        public override void Initialize(string name,
            NameValueCollection config)
        {
            if (config == null)
            {
                throw new ArgumentNullException("config");
            }
            
            // Call base initialize first.
            base.Initialize(name, config);
            
            // Performing provider specific initialization.
            this.InitializePath(name, config);
            
            // Always call this method last.
            this.CheckForUnrecognizedAttributes(name, config);
        }
        
        protected override object LogInternal(LogEntry entry)
        {
            DateTime now = DateTime.Now;
            
            string line = String.Format("{0} {1}\t{2}\t{3}\t{4}\n",
                now.ToShortDateString(), now.ToShortTimeString(),
                entry.Severity, entry.Message, entry.Exception);
            
            File.AppendAllText(this.path, line);
            return null;
        }
        
        private void InitializePath(string name,
            NameValueCollection config)
        {
            this.path = config["path"];
            
            if (String.IsNullOrEmpty(this.path))
            {
                throw new ProviderException(string.Format(
                    "Empty or missing 'path' attribute in " +
                    "provider '{0}' in config file.", name));
            }
            
            config.Remove("path");
        }
    }
}

The following example shows the configuration for the logging provider that we've defined above:

<?xml version="1.0"?>
<configuration>
  <configSections>
    <section name="logging"
      type="CuttingEdge.Logging.LoggingSection, CuttingEdge.Logging" />
  </configSections>
  <logging defaultProvider="MyFileLoggingProvider">
    <providers>
      <add
         name="MyFileLoggingProvider"
         type="MyLoggingProviders.MyFileLoggingProvider, MyLoggingProviders"
         path="c:\mylog.txt"
      />
    </providers>
  </logging>
</configuration>
Please note that this example expects the MyFileLoggingProvider to be placed in an assembly called MyLoggingProviders. Change this assembly name to the name of the assembly / project where you place the MyFileLoggingProvider. Also note that this example is a bit naive and will not work properly in a multi-threaded environment, such as ASP.NET. Again, please note that this example is illustrative. Please use the XmlFileLoggingProvider or it’s base class FileLoggingProviderBase to create a logger that writes to the file system.

More information

For more information about CuttingEdge.Logging, please visit the following links: For more information about the ASP.NET provider model, please visit the following links:

This project is supported by:

NCover NDepend

Last edited Aug 24, 2010 at 3:59 PM by dot_net_junkie, version 29