Monthly Archives: October 2006

1 Comment

Rolling File Trace Listener

Note: Archived version of the article about the 0.5.2.0 version. This is no longer the latest version.

Erwyn van der Meer, LogicaCMG
Based on Rolling File Sink by Hisham Baz, Avanade

Download v0.5.2.0 source code + documentation. The source code and documentation are provided "AS-IS". Feel free to change and/or extend them. Please contact me or leave a comment if you find an issue.

Last updated: April 18, 2006

Overview

This article describes the RollingFileTraceListener extension of the
Logging block of version 2.0 of the Microsoft Enterprise Library.  This
is a custom trace listener that can be plugged into the Enterprise
Library Logging block like the standard trace listeners that are
included. The FlatFileTraceListener shipped with EntLib 2.0 may not be
adequate for enterprise systems since log files by default will
continue to grow unchecked.  This new trace listener provides support for rolling over log files based on age of the log file or file size.

Usage

The ZIP file contains a Visual Studio 2005 solution and projects
with C# sources that are fully documented with XML comments. Extract
the ZIP file, open the EnterpriseLibraryExtensions.sln
solution in Visual Studio 2005 and build the solution. This will create
the assemblies for the RollingFileTraceListener and a test application.

In Windows the maximum path + filename length for a file is 260
characters. Please ensure you extract the ZIP file into a directory
with a path that is less than 82 characters in length. Otherwise you
will get a compilation error because during compilation Visual Studio
will create an intermediate file with a really long name for which the
path exceeds the limit of 260 characters.

In order to use the new trace listener from the Enterprise Library
Configuration tool, you must copy the assemblies into the same
directory as the configuration tool. There are two files that need to be copied - LogicaCMG.EnterpriseLibraryExtensions.Logging.dll and LogicaCMG.EnterpriseLibraryExtensions.Logging.Configuration.Design.dll.  When these files are in the same directory, they will be registered during the startup of the tool. This
will allow you to add a new Rolling File Trace Listener from the
right-click context menu on the Trace Listeners collection node.

Screenshot of how you can add a RollingFileTraceListener to an application configuration file using the Enterprise Library Configuration Console.

Configuration

The trace listener creates a new log file when the current file exceeds defined thresholds.  The
RollingFileTraceListener provides file age and file size thresholds
that can be configured using the Enterprise Library Configuration tool
like any other trace listener.

Screenshot of the configuration properties that can be set for a RollingFileTraceListener.

 The RollingFileTraceListener has the following properties

  • Filename – filename with optional relative or full path
  • Header – string (optional)
  • Footer – string (optional)
  • MaximumLogFilesBeforePurge – integer
  • Timestamp Format – string, e.g., yyyy-MM-dd [HH:mm:ss]  (optional)
  • Age Threshold - integer
  • Age Unit – None, Minutes, Hours, Days, Weeks, Months
  • Size Threshold – integer
  • Size Unit – None, KB, MB, GB

Design

The RollingFileTraceListener uses a database-style log roll-over process.  All new log entries are written to the file defined in the FileName property.  Before a log entry is written, the trace listener checks to see if the file has grown too big or the age limit has expired.  If
the current log file exceeds the size or age threshold, then the log
file is renamed with the current timestamp or an incremental counter.  The new file is created with the same name defined in FileName. So the current log file always has the same name.

Age Threshold

The age threshold allows you to limit the growth of your log files according to age.  The threshold is compared by evaluating the current date/time against the log file creation date/time.  For
example, if the log file was created on 1/1/2006 at 3PM and the age
threshold was set to 2 days, a new log file will be created for the
first log entry written after 1/3/2006 at 3PM.

There are two properties that control the age threshold behavior – AgeThreshold and AgeUnit.  Select the appropriate unit size first – None, Minutes, Hours, Days, Weeks or Months - by setting the AgeUnit property.  Set the AgeThreshold property to 0 or the AgeUnit to None to disable the age threshold check.

Size Threshold

In addition to age threshold, you can limit log file growth based on file size

There are two properties that control the age threshold behavior – SizeThreshold and SizeUnit.  Select the appropriate unit size first – None, Kilobytes, Megabytes or Gigabytes - by setting the SizeUnit property.  Set the SizeThreshold property to 0 or the SizeUnit to None to disable the file size threshold check. 

Combination Thresholds

Both the age and size thresholds can be applied at the same time.  For
example, logs can be configured to roll-over every week or earlier if
the file grows over 10MB. To accomplish this, set the AgeUnit to Weeks, AgeThreshold to 1, SizeUnit to Megabytes and SizeThreshold to 10.

Filename Formatting

When log file exceeds the defined thresholds, it is given a new unique name.

The TimestampFormat property can be used to define a date-time format string used for generating new file names.  This
allows overgrown or overaged log files to be renamed and stamped with
the current timestamp. The timestamp is appended to the end of the new
filename, before the extension.  For example, if TimestampFormat is set to yyyy-MM-dd and FileName is set to app.log, then when rolling over on February 15, 2006 the current log file is renamed to app2006-02-15.log.

If the new filename already exists, then an incremental counter is added until a unique combination is found.  If the TimestampFormat property is left blank, the counter will always be appended to the end of the FileName.  The counter is formatted to 7 digits (e.g., app[0000123].log) and counting begins from 1.

Purging

Log files can be automatically deleted after a certain maximum
number of log files are present by setting the
MaximumLogFilesBeforePurge property.  Set this property to 0 to disable automatic purging.  Purging
occurs before the current log file is renamed. The log files are
deleted in reverse order of their last modification time.

Change log

Version 0.5.2.0 – Fixed a bug that occurred when the
application configuration file is changed while an application using
the RollingFileTraceListener is running. In that case a GUID was
prepended to the filename of the log file, because the log file was
still locked by another RollingFileTraceListener instance.

Version 0.5.1.0 – Fixed a bug that prevented the
formatter name from being saved correctly when using the Enterprise
Library Configuration tool.

Version 0.5.0.0 – First public release.

Known problems

A GUID might be prepended to the filename of the log file

A RollingFileTraceListener instance "owns" the log file it is
writing to and locks it for exclusive write access when it writes the
first log entry. It keeps the file locked until the instance is
disposed. If another RollingFileTraceListener  instance
is created that points to the same file, before the first instance is
disposed, the second instance cannot open this file for writing and
will write to a new file with a GUID prepended to its name.

The RollingFileTraceListener indirectly derives from
System.Diagnostics.TextWriterTraceListener. This class changes the
filename to include a GUID when the file with the specified filename
cannot be written to. This is because RollingFileTraceListener
indirectly calls the EnsureWriter method on its base class
TextWriterTraceListener. .NET Reflector shows this code for
System.Diagnostics.TextWriterTraceListener.EnsureWriter() in System.dll
(slightly rewritten to improve clarity):

    try
    {
        this.writer = new StreamWriter(fileNameWithPath, true, encoding1, 0x1000);
        break;
    }
    catch (IOException)
    {
        Guid guid1 = Guid.NewGuid();
        fileName = guid1.ToString() + fileName;
        fileNameWithPath = Path.Combine(folderPath, fileName );
    }

Terms and conditions for the "Enterprise Library 2.0 Extensions including the Rolling File Trace Listener"

Copyright (c) 2006 Erwyn van der Meer

Permission is hereby granted, free of charge, to any
person obtaining a copy of this software and associated documentation files
(the "Software"), to deal in the Software without restriction,
including without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to permit
persons to whom the Software is furnished to do so, subject to the following
conditions:

The above copyright notice and this permission notice
shall be included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT
WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
THE USE OR OTHER DEALINGS IN THE SOFTWARE.

1 Comment

Today I started using the September 2006 CTP of Visual Studio Codename "Orcas".

Microsoft has started to distribute the "Orcas" CTPs as Virtual PC images which are based on a common Windows Server 2003 base image. The downloads are pretty large: 1.13 GB for the self-extracting EXE of the base image and 3.6 GB for the self-extracting EXE for the Orcas differencing disk. After extraction the numbers are 2.72 GB for the base image VHD and 9.27 GB for the Orcas VHD.

I extracted these files at home to a portable LaCie Ethernet Disk Mini hard-disk and transported them to work. My portable hard-disk is formatted as an EXT2 partition. The LaCie drive supports the NTFS format only as readonly when it is connected through Ethernet instead of through USB. I still want to able to use the drive as network-attached storage, so NTFS is not suitable for my drive. The drive does fully support FAT32, but FAT32 cannot store files bigger than 4GB. So FAT32 is not suitable either.

Windows XP does not natively support external drives formatted as EXT2 because it is a Linux format. Thankfully this can be fixed by the free-ware Ext2 Installable File System For Windows (Ext2fs).

Virtual PC 2004 SP1 doesn't seem to like accessing large files on an external EXT2 partition. I got some weird errors in the past when I tried booting a Virtual PC stored in that way. However, Virtual Server 2005 R2 (also available for free) works fine so I am using that instead.

If you look at the about box of Visual Studio Codename "Orcas" you can notice some things having the potential of causing incredible version confusion:

The "Orcas" Virtual PC has the following .NET Framework versions installed: 1.1, 2.0, 3.0 and 3.5.

Notice the inconsistency in the version numbering scheme. Why is it "v3.0" and "v3.5.60905"?! Previous feedback about naming inconsistencies hasn't had much effect. Also note:

Why is it Windows Workflow Foundation and just the acronym WPF?!

There is no support for .NET 3.0 in this "Orcas" CTP: there are no templates and designers for .NET 3.0 components like WPF, WCF and WF. Even though Microsoft has released these as the Microsoft Visual Studio Code Name “Orcas” Community Technology Preview – Development Tools for .NET Framework 3.0 ("Fidalgo").

The "Orcas" image is very large, but there is no Windows SDK installed. I think you are out of luck if you would try installing the Windows SDK for .NET 3.0 development and "Fidalgo": the build number for the RC1 of the .NET Framework 3.0 is 4324. This "Orcas" CTP contains the older build 4310.

"Orcas" is meant to target .NET 3.5, yet the about box says it is for .NET 2.0. "Orcas" still has the same major and minor version number 8.0 as Visual Studio 2005. It has the new C# 3.0 and VB 9.0 compilers and IntelliSense, but the installed products are still listed as Visual C# 2005 and Visual Basic 2005.

A version of LINQ is included in the System.Core DLL in the GAC. The file version number is 2.0.60905.0 and the assembly version number is 2.0.0.0. This makes it seem as though LINQ is part of .NET 2.0 instead of .NET 3.5. Fortunately it is placed in the Microsoft.NETFrameworkv3.5.60905 folder. Here is the content of that folder:

I couldn't find an other way to add a reference to the System.Core assembly to a Visual Studio project other than by manually adding a reference this DLL by browsing to this directory. These are the main namespaces in the System.Core assembly:

.NET 3.5 as released in this "Orcas" CTP is far from complete. Things that have been released as CTPs like LINQ designers, LINQ to XML, LINQ to SQL, ASP.NET AJAX (fka "Atlas"), BLINQ and ADO.NET "vNext" will eventually be integrated into the .NET Framework and Visual Studio, but they are nowhere to be found in this CTP.

Which begs the question: Microsoft, what's the point of releasing this "Orcas" CTP when there are so many things missing?