RSS Feed
Download our iPhone app
Browse DevX
Sign up for e-mail newsletters from DevX


Fast and Flexible Logging with Vista's Common Log File System : Page 5

Microsoft's Common Log File System is an OS-supported logging framework that provides all the logging capabilities you need—and it's available via managed code and your favorite .NET language.

Creating Log Record Relationships
You could use the Subsystem property on the custom LogEntry class to create relationships between log records. For example, suppose you decide that all the log entries in the "Transactions" subsystem are related to each other. You could find them all by iterating through the log, locating the log records that fit into this category. Unfortunately you would have to iterate through every record in the log, which could be an expensive and lengthy operation for large logs.

A better solution is to create log record relationships. CLFS has a built-in mechanism for creating such relationships between log records, and it's probably faster than any custom solution. Here's how it works. Every log record in a CLFS log has a unique sequence number. A LogRecordSequence doesn't have to iterate through log records to locate one with a given sequence number; it can advance directly to it.

The sequence numbers are similar to pointers or references. CLFS uses the sequence numbers to provide support for two logical record sequences that you're free to use as you wish: the Previous sequence and the User sequence. These sequences are similar to linked lists.

Figure 3. Record Relationships: The figure shows the physical, "Previous," and "User," record sequences for this set of records.
For example, Figure 3 shows a set of relationally-linked log records. There are two arbitrary sequences in the diagram. The Previous sequence consists of log records 03, 02, and 01. The User sequence consists of log records 03 and 01. You establish record sequences using the LogRecordSequence.Append method. For example, to add a new record, you would write:

   SequenceNumber LogRecordSequence.Append(
       ArraySegment<byte> serializedLogRecord,
       SequenceNumber userSequenceNumber,
       SequenceNumber previousSequenceNumber,
       RecordAppendOptions recordAppendOptions);
The Append method uses the second parameter to establish User sequences and the third parameter to establish Previous sequences. For example, to build the User and Previous sequences for the three records shown in Figure 3, you would write:

   SequenceNumber sn01 = sequence.Append(entry01, 
      SequenceNumber.Invalid, SequenceNumber.Invalid, 
   SequenceNumber sn02 = sequence.Append(entry02, 
      SequenceNumber.Invalid, sn01, RecordAppendOptions.None);
   SequenceNumber sn03 = sequence.Append(entry03, 
      sn01, sn02, RecordAppendOptions.None);
To read sequences from the log use the LogRecordSequence.ReadLogRecords method, passing in a LogRecordEnumeratorType value to control the read sequence:

   IEnumerable<LogRecord> LogRecordSequence.ReadLogRecords(
      SequenceNumber start, LogRecordEnumeratorType logRecordEnum);
The possible LogRecordEnumeratorType values are:

  • LogRecordEnumeratorType.Next—enumerates through log records according to their physical ordering in the extents.
  • LogRecordEnumeratorType.Previous—enumerates over the Previous sequence.
  • LogRecordEnumeratorType.User—enumerates over the User sequence.
The trick is to locate the correct starting sequence number. There are six places in the CLFS API where you can get a sequence number.

  • LogRecordSequence.BaseSequenceNumber is the sequence number of the first physical record in the log.
  • LogRecrodSequence.LastSequenceNumber will be the sequence number of the next appended record.
  • LogRecordSequence.Append returns the sequence number of the appended record, which you can save for future use.
  • LogRecord.SequenceNumber returns the log record's sequence number. This is the same sequence number returned from LogRecordSequence.Append.
  • LogRecord.Previous returns the next log record in the Previous sequence.
  • LogRecord.User returns the next log record in the User sequence.
If you don't wish to specify a sequence number, use SequenceNumber.Invalid. If you don't specify a sequence number for a log record's Previous or User sequence, the default value is SequenceNumber.Invalid.

Managing a Growing Log
LogRecordSequence.Append throws a SequenceFullException if your log runs out of space. You can trap this exception and take the appropriate steps to make room in your log or on your hard drive. How you handle this exception is up to you.

  • Call LogRecordSequence.AdvanceBaseSequenceNumber to move the base of the log forward and effectively mark older log records as no longer needed. The CLFS will overwrite the log records with older sequence numbers and thus increase the available space in your log.
  • Add additional extents.
  • Perform other actions appropriate for your application.
For some applications, it's important to group multiple log records together in a transaction. In this case, you need the CLFS to either write all the related log records or none of them—writing a portion of them would constitute data corruption. The CLFS doesn't directly support transactions, but you can reserve space for any number of log records before writing to the log.

   ReservationCollection reservedSpace = 
   SequenceNumber sn01 = sequence.Append(
      entry01, SequenceNumber.Invalid, SequenceNumber.Invalid, 
      RecordAppendOptions.None, reservedSpace);
   SequenceNumber sn02 = sequence.Append(
      entry02, SequenceNumber.Invalid, sn02, 
      RecordAppendOptions.None, reservedSpace);
      entry03, SequenceNumber.Invalid, sn03, 
      RecordAppendOptions.ForceFlush, reservedSpace);
The ReservationCollection.Add method throws a SequenceFullException if your log runs out of space. Catching the exception lets you avoid writing fewer than all three related entries to the log.

Sharing a CLFS Log
If you have more than one enterprise class application writing information to a log, maintaining completely separate logs for each application might be more trouble than it's worth. If the applications are writing a high volume of information to each log, there could be a performance hit associated with the high cost of file operations.

The CLFS addresses this problem with multiplexing, letting two or more applications share the same log file and container files. Multiplexing happens behind the scenes—your applications don't have to do anything special to share the physical log files with other applications.

Establish a multiplexed log by scoping the log file name with the "::" operator, for example:

   LogRecordSequence sequence01 = new LogRecordSequence(
      "DevX.CLFS.Log::Sequence01", FileMode.OpenOrCreate, 
   LogRecordSequence sequence02 = new LogRecordSequence(
      "DevX.CLFS.Log::Sequence02", FileMode.OpenOrCreate, 
The log file of a multiplexed log itself is the same—DevX.CLFS.Log in this case—but has more than one log record sequence written to it. You can read from the log using any of the sequences; the separate log record sequences are independent of each other even though the CLFS persists them in the same files.

Before Microsoft created the CLFS, developers' logging options included using the Windows Event Log, the Enterprise Library's Logging Application Block, buying third-party logging framework, or rolling their own solutions. The first two options are often adequate, but lack the robustness and control offered by the CLFS API. In short, Windows Vista and Windows Server 2003 R2 now provide an operating-system based logging solution that allows you to focus on what you want your application to log, rather than on how to accomplish the logging.

Seth Livingston is the CTO of Adventos, LLC, a training, mentoring, and delivery partner for Microsoft solutions and software development best practices. Seth splits his time among seminars, classes, mentoring, and guiding Adventos' technical direction. He lives in McKinney, Texas.
Email AuthorEmail Author
Close Icon
Thanks for your registration, follow us on our social networks to keep up-to-date