Samples
Logging Tasks
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();
|
Logger logger = new
FileLogger("c:\\mylogfiles\\mylog.log");
|
Logger logger = new
SerialSocketLogger("SomeHost.com", portNumber);
|
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 */
|
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 );
|
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";
|
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.
|
|
|