new --> compare  ...and what he said.
tweet tweet tweet tweet tweet

Samples

 

Logging Tasks

 

  • Still have questions? Get answers.

 


Instantiating various kinds of Loggers

Back to Top

There are numerous types of Loggers provided in the framework. Here are just a few examples.

  • A logger that writes to the console

Logger logger = TextWriterLogger.NewConsoleLogger();

  • A logger that writes to a file

Logger logger = new FileLogger("c:\\mylogfiles\\mylog.log");

  • A logger that writes Serialized log entries to a socket

Logger logger = new SerialSocketLogger("SomeHost.com", portNumber);

  • A logger that writes to numerous other loggers

This type of logger, the CompositeLogger, will probably be the main logger for your application. You can then put other, more specific loggers inside this one.

/* first instantiate some basic loggers */
Logger consoleLogger = TextWriterLogger.NewConsoleLogger();
Logger fileLogger = new FileLogger("c:\\mylogfiles\\mylog.log");
Logger socketLogger = new SerialSocketLogger("SomeHost.com", 12345);

/* now instantiate a CompositeLogger */
CompositeLogger logger = new CompositeLogger();

/* add the basic loggers to the CompositeLogger */
logger.AddLogger("console", consoleLogger);
logger.AddLogger("file", fileLogger);
logger.AddLogger("socket", socketLogger);

/* now all logs to logger will automatically be sent
    to the contained loggers as well */

  • Using the InsistentLogger

The InsistentLogger provides the functionality of retrying to log when a logger fails. For example, if a SerialSocketLogger was unable to connect to a server socket, then an InsistentLogger would automatically provide the retrying capability. Using it is simple:

/* create my basic logger */
Logger logger = new SerialSocketLogger( "SomeHost.com", 12345 );

/* - wrap in an InsistentLogger
   - have a backup of 200 LogEntries
   - retry logging every 60 seconds */
logger = new InsistentLogger( logger, 200, 60 );

/* now I can log to logger just like any other logger */

 


Logging in an application

Back to Top

  • Various sample logging methods

 

logger.LogDebug("x = " + x);

logger.LogInfo("User " + aUser + "has visited page " + page);

logger.LogStatus("Active");

logger.LogWarning("Database is inaccessible");

logger.LogError(anException);

logger.LogCritical("Database is down");

logger.LogFatal("Application is exitting because " + reason);

Debug, Info, Status, Warning, Error, Critical, and Fatal are all severities. A logger can be set to only log items that are of a specified severity or higher, while ignoring items of lower importance.

If you prefer, you can specify the severity as a parameter such as

logger.Log( LogSeverity.Info, "This is some information" );

logger.Log( LogSeverity.Error, anException );

  • Using "categories"

Categories are simply an optional way of organizing log entries. A category can be an instance of any class you wish, but most likely would simply be a String. You might like to categorize log entries based on their respective sub-system, or by their general meaning for the application.

logger.LogWarning("Database", "Database is non-responsive");

logger.Log( LogSeverity.Warning, "Database", "Database is non-responsive");

 


Formatting Log Entries

Back to Top

  • Simple Date/Time formatting

Every logger has a formatter. Each formatter has a FormatString used for formatting its timestamp. You can customize the way the timestamp appears by doing something such as

/* this is the long format for both date and time */
logger.Formatter.FormatString = "F";

  • Advanced formatting

The way a LogEntry looks in a log can be completely customized. By default every logger uses an instance of LogEntryStandardFormatter. However, you can create your own subclasses of the abstract class LogEntryFormatter. Simply override the AsString(LogEntry) method to provide a completely custom look in the log.

LogEntryFormatter myFormatter = new MyCustomLogEntryFormatter();

logger.Formatter = myFormatter;

You can also change the default formatter for all your logger instances by doing something like:

Logger.DefaultFormatterClass = typeof( MyCustomLogEntryFormatter );

 


Filtering Log Entries

Back to Top

Filtering log entries is the process of ignoring some entries and actually logging others. Basic filtering is done by setting the severity threshold of a logger.

logger.SeverityThreshold = LogSeverity.Warning;

In the above example, all log requests that are of a severity lower than Warning will be ignored. The default severity threshold for loggers is Debug, which is the lowest severity.

You may wish to have more sophisticated filtering, however. For example, one logger might be specifically for database related log entries, whereas another might be for recording the general state of the application. You can use the provided LogEntryCategoryFilter class to accomplish this filtering. The following example shows how you might use it.

/* create and setup the filter */
LogEntryCategoryFilter myDbFilter = new LogEntryCategoryFilter(true);
myFilter.AddCategory("Database");

/* now set the logger's filter */
logger.Filter = myDbFilter;

Using the logger above, only entries with the "Database" category will get logged. For example:

logger.LogInfo( "This has no category, and won't get logged" );
logger.LogInfo( "Network", "This won't get logged either" );
logger.LogInfo( "Database", "This will get logged" );

You can easily create a CompositeLogger which contains other loggers, each with its own filter.

Also, you can create your own custom filter by simply sublassing LogEntryFilter, overriding the method CanPass(LogEntry).

By default, if you don't specify a filter for a logger, it will use a LogEntryPassFilter, which allows all log entries to get logged. You can set your own default filter class by doing something such as:

Logger.DefaultFilterClass = typeof( MyCustomLogEntryFilter );


Creating a Custom Logger

Back to Top

The framework provides a very easy way for you to log to anything you choose. It starts by subclassing Logger. From there you have two basic choices.

If your needs are to simply write the LogEntry as a String to some device, then you can just override the method WriteToLog(String). If your needs are more sophisticated, then you can override the method DoLog(LogEntry). In either case, the methods should return true if they were successful, and false otherwise.

Suppose you wanted to make a logger that simply displayed a message box to the user. Your code might look something like the following.

using System;
using System.Windows.Forms;
using BitFactory.Logging;

namespace My_Application
 {
  public class MessageBoxLogger : Logger
   {
    protected override bool WriteToLog(String aString)
     {
      MessageBox.Show(aString);
      return true;
     }
   }
}

If you wanted something a little fancier, instead of overriding WriteToLog, you could instead override DoLog as in the following.

protected override bool DoLog(LogEntry aLogEntry)
 {
  MessageBoxIcon icon = MessageBoxIcon.Warning;
  if (aLogEntry.Severity < LogSeverity.Warning)
     icon = MessageBoxIcon.Information;
  else if (aLogEntry.Severity > LogSeverity.Warning)
     icon = MessageBoxIcon.Error;

  MessageBox.Show(
     aLogEntry.Message,
     aLogEntry.SeverityString,
     MessageBoxButtons.OK,
     icon);

  return true;
 }

 

Using loggers in an ASP.NET Application

Back to Top

ASP.NET applications are a great place to utilize the logging framework.Here is just one way in which you can implement logging in your application.

Let's suppose you want to log various events throughout your application to

  • a file,
  • a socket,
  • and Email

Suppose you want to log Status (and greater) events to the file and to your email. And suppose that you want to send Debug (and greater) events to the socket.

First, declare the logger variable and property in the Global.asax.cs file.

private static CompositeLogger logger = new CompositeLogger();
public static CompositeLogger Logger
 {
   get { return logger; }
 }

In the following code, the logger is initialized, and a status log entry is made indicating that the application has started.

private void InitLogger()
 {
  //  create the email logger
  Logger emailLogger = new EmailLogger(
       "smtp.MyHost.com",
       "website@MyDomain.com",
       "webmaster@MyDomain.com" );
  emailLogger.SeverityThreshold = LogSeverity.Status;

  // create the file logger
  Logger fileLogger = new FileLogger(
       Server.MapPath("\\myroot\\mylogs\\logfile.log") );
  fileLogger.SeverityThreshold = LogSeverity.Status;

  // create a socket logger - wrapped in an insistent logger
  Logger socketLogger = new SerialSocketLogger(
       "<IP address of my home machine>",
       12345 /* pick a port number */ );
  socketLogger = new InsistentLogger(
       socketLogger,
       200, /* retain 200 log entries in memory */
       3600 /* retry a failed socket every hour */ );

  // add the loggers to the main composite logger
  Logger.AddLogger("Email",emailLogger);
  Logger.AddLogger("File",fileLogger);
  Logger.AddLogger("Socket",socketLogger);
 }

protected void Application_Start(Object sender, EventArgs e)
 {
  InitLogger();
  Logger.LogStatus("Application Started");
 }

You might want to be informed when the application ends. The following would do the trick.

protected void Application_End(Object sender, EventArgs e)
 {
  Logger.LogWarning("Application Ending");
 }

To log errors, simply add the following code (Note that there are really only two lines of code here, but a lot of exception information is written to the log.):

protected void Application_Error(Object sender, EventArgs e)
 {
  Exception ex = Server.GetLastError();
  Logger.LogError(" -- Exception --> " + Environment.NewLine +
     ex.ToString() + Environment.NewLine + Environment.NewLine +
     " -- message --> " + Environment.NewLine +
     ex.Message + Environment.NewLine + Environment.NewLine +
     " -- stack --> " + Environment.NewLine + ex.StackTrace);
 }

Now, anywhere else in the application you can make log entries by doing something like the following.

Global.Logger.LogInfo( "This is information" );

Automatically, emails will be sent when appropriate, the socket will get log entries sent to it, and the log file will have entries appended to it.

 

 

 

 

 

 

 

 

 

 

 

 

 

 


Other .NET tools you may find interesting:
Role-based security made easy

 

© Copyright 2005 - 2010 - Lorne Brinkman - All Rights Reserved
www.TheObjectGuy.com