inhereting from XmlTraceListener to create rolling XML trace listener

Topics: Logging Application Block
May 12, 2009 at 7:23 PM

We need a rolling XML trace listener.  I have a simple class RollingXMLTracelistener that inherets from XMLTraceListener.  It uses two files. LogFileA and LogFileB.  It starts off writing to LogFileA and when LogFileA gets to large it flips over to write to LogFileB.  When LogFileB gets to large we flip back to LogFileA. 

My TraceData() just needs to do this

TraceData()

{

RollOver();       // check to see if the file is at max size and if so will point to the "other" file (A or B)

Write to that file

}

Questions

1. How do I specify the name of the file the trace listener is writing to on the fly ( toggling between A and B) in by RollOver()

2. How do I just write to the file - Logger.Write( message) does not seam to be working?

 

May 13, 2009 at 7:34 AM

Hi,

I'm not quite sure about this, do you create a trace listener programmatically within your RollingXMLTracelistener? or do you use a trace listener that was configured in the config? 

In case you are using a configured trace listener, you can try this:

 

            ExeConfigurationFileMap fileMap = new ExeConfigurationFileMap();

            fileMap.ExeConfigFilename = "configPath";

            Configuration entLibConfig = ConfigurationManager.OpenMappedExeConfiguration(fileMap, ConfigurationUserLevel.None);

            LoggingSettings loggingSettings = (LoggingSettings)entLibConfig.GetSection(LoggingSettings.SectionName);

            FlatFileTraceListenerData data = loggingSettings.TraceListeners.Get("FlatFile TraceListener") as FlatFileTraceListenerData;

            data.FileName = @"ThisIsTheNewFileName";

            entLibConfig.Save();

 

Valiant Dudan
Global Technology & Solutions
Avanade, Inc.
entlib.support@Avanade.com

 

 

 

May 13, 2009 at 1:02 PM

Thanks - I have this code in place and looks good until I get to the below line which is returning null

FlatFileTraceListenerData data = loggingSettings.TraceListeners.Get("FlatFile TraceListener") as FlatFileTraceListenerData;

1. I am not using a FlatFileTraceListener, my class derives from XMLTraceListener.  Does XMLTraceListener have it's own TraceListenerData class I should use instead of FlatFileTraceListenerData?

2. Do I pass .Get() the name of the trace listener or the type?

This is what my config file looks like for this listener

<font size="2" color="#0000ff"><font size="2" color="#0000ff">

<

</font></font><font size="2" color="#0000ff">

 

</font>

add listenerDataType="Microsoft.Practices.EnterpriseLibrary.Logging.Configuration.CustomTraceListenerData, Microsoft.Practices.EnterpriseLibrary.Logging, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"

<font size="2"><font size="2">

 

</font></font>
<font size="2">

 

</font>

traceOutputOptions="Callstack" filter="All" type="ASC.TechnicalArchitectureServiceAgent.RollingXMLTraceListener, ASC.TechnicalArchitectureServiceAgent, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null"

<font size="2"><font size="2">

 

</font></font>
<font size="2">

 

</font>

name="RollingXML" initializeData="c:\logs\testA.svclog" />

I can't imagine other developers would not use this solution if we can get it to work!

Thanks Valiant,

Jess

May 13, 2009 at 2:48 PM

Hi, Sorry about that, I overlook that one. Although that's the idea on how to change the settings of a tracelistener on the fly. :-) Anyways, would you mind sending us you RollingXmlTraceListener class or rather post your code?

Valiant Dudan
Global Technology & Solutions
Avanade, Inc.
entlib.support@Avanade.com

May 13, 2009 at 3:36 PM
Edited May 13, 2009 at 5:02 PM

Hi Valiant, I got it working using CustomTraceListenerData instead of FlatFileTraceListenerDataFlatFileTraceListenerData 

I think I have the trace listener writing to a new file (file B) but surprisingly, file A is not being release so I can't flush it's contents or delete it.

I think this would be a very elegant solution to get a rolling XML trace listener for Enterprise Library and it's almost there.

How can I paste the class in here - the formatting gets all messed up if I just cut and paste from VS?

Thanks

Jess 

 

May 13, 2009 at 5:08 PM

Here is the class - but not so easy to read.  Why is file A not getting released?

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

<font size="2" color="#0000ff"><font size="2" color="#0000ff">

using

</font></font><font size="2" color="#0000ff">

 

</font>

 

System;

<font size="2" color="#0000ff"><font size="2" color="#0000ff">

using

</font></font>
<font size="2" color="#0000ff">

 

</font>

 

System.Configuration;

<font size="2" color="#0000ff"><font size="2" color="#0000ff">

using

</font></font>
<font size="2" color="#0000ff">

 

</font>

 

System.Collections.Generic;

<font size="2" color="#0000ff"><font size="2" color="#0000ff">

using

</font></font>
<font size="2" color="#0000ff">

 

</font>

 

System.Diagnostics;

<font size="2" color="#0000ff"><font size="2" color="#0000ff">

using

</font></font>
<font size="2" color="#0000ff">

 

</font>

 

System.Linq;

<font size="2" color="#0000ff"><font size="2" color="#0000ff">

using

</font></font>
<font size="2" color="#0000ff">

 

</font>

 

System.Text;

<font size="2" color="#0000ff"><font size="2" color="#0000ff">

using

</font></font>
<font size="2" color="#0000ff">

 

</font>

 

Microsoft.Practices.EnterpriseLibrary.Logging.TraceListeners;

<font size="2" color="#0000ff"><font size="2" color="#0000ff">

using

</font></font>
<font size="2" color="#0000ff">

 

</font>

 

Microsoft.Practices.EnterpriseLibrary.Common.Configuration;

<font size="2" color="#0000ff"><font size="2" color="#0000ff">

using

</font></font>
<font size="2" color="#0000ff">

 

</font>

 

Microsoft.Practices.EnterpriseLibrary.Logging.Configuration;

<font size="2" color="#0000ff"><font size="2" color="#0000ff">

using

</font></font>
<font size="2" color="#0000ff">

 

</font>

 

Microsoft.Practices.EnterpriseLibrary.Logging;

<font size="2" color="#0000ff"><font size="2" color="#0000ff">

using

</font></font>
<font size="2" color="#0000ff">

 

</font>

 

ASC.TechnicalArchitecture;

<font size="2" color="#0000ff"><font size="2" color="#0000ff">

using

</font></font>
<font size="2" color="#0000ff">

 

</font>

 

System.IO;

<font size="2" color="#0000ff"><font size="2" color="#0000ff">

namespace

</font></font>
<font size="2" color="#0000ff">

 

</font>

 

ASC.TechnicalArchitectureServiceAgent

{

<font size="2">

[

</font>

 

ConfigurationElementType(typeof(CustomTraceListenerData

))]<font size="2">

 

</font>

 

public class RollingXMLTraceListener :

XmlTraceListener

{

<font size="2">

 

</font>

 

string

_fileName;<font size="2">

System.

</font>

 

DateTime

_currentDate;<font size="2">

System.IO.

</font>

 

StreamWriter _traceWriter = null

;<font size="2">

 

</font>

 

public RollingXMLTraceListener(string

name)<font size="2">

:

</font>

 

base

(name)

{

_fileName = name;

}

<font size="2">

 

</font>

 

private void

checkRollover()

{

<font size="2">

 

</font>

 

if (File.Exists("c:\\logs\\testA.svclog"

))

{

<font size="2">

 

</font>

 

FileInfo finfo = new FileInfo

(_fileName);<font size="2">

 

</font>

 

long

FileInBytes = finfo.Length;<font size="2">

 

</font>

 

long

FileInKB = finfo.Length / 1024;<font size="2">

 

</font>

 

byte[] byt = new byte

[1];<font size="2">

 

</font>

 

if

(FileInKB > 40)<font size="2">

{

</font>

 

// File A is full, move it's contents into file B archive

<font size="2">

 

</font>

 

if (File.Exists("c:\\logs\\testb.svclog"

))<font size="2">

 

</font>

 

File.Delete("c:\\logs\\testb.svclog"

);<font size="2">

 

</font>

 

File.Copy("c:\\logs\\testA.svclog", "c:\\logs\\testb.svclog"

); <font size="2">

 

</font>

 

// now we need to purge contents of file A difficult becuase EntLib is using it Idea: changes the file the trace l

<font size="2">

 

</font>

 

// listener writes to so we can 1. delete it, 2. Recreate it, have the trace listner write to this empty new copy

<font size="2">

 

</font>

 

// until it gets full again, at which time we copy into file B overwrit

<font size="2">

 

</font>

 

ExeConfigurationFileMap fileMap = new ExeConfigurationFileMap

();<font size="2">

fileMap.ExeConfigFilename =

</font>

 

"EnterpriseLibraryClient.config"

;<font size="2">

 

</font>

 

Configuration entLibConfig = ConfigurationManager.OpenMappedExeConfiguration(fileMap, ConfigurationUserLevel

.None);<font size="2">

 

</font>

 

LoggingSettings loggingSettings = (LoggingSettings)entLibConfig.GetSection(LoggingSettings

.SectionName);<font size="2">

 

</font>

 

CustomTraceListenerData data = loggingSettings.TraceListeners.Get("RollingXML") as CustomTraceListenerData

;<font size="2">

data.InitData =

</font>

 

@"c:\logs\testB.svclog"

;

entLibConfig.Save();

<font size="2">

 

</font>

 

// Logger.Writer.Dispose();

<font size="2">

 

</font>

 

// This does not "release" file A, can't delete it or empty it's contents

<font size="2">

 

</font>

 

File.Delete("c:\\logs\\testA.svclog"

);<font size="2">

 

</font>

 

File.Create("c:\\logs\\testA.svclog"

);<font size="2">

fileMap =

</font>

 

new ExeConfigurationFileMap

();<font size="2">

fileMap.ExeConfigFilename =

</font>

 

"EnterpriseLibraryClient.config"

;<font size="2">

entLibConfig =

</font>

 

ConfigurationManager.OpenMappedExeConfiguration(fileMap, ConfigurationUserLevel

.None);<font size="2">

loggingSettings = (

</font>

 

LoggingSettings)entLibConfig.GetSection(LoggingSettings

.SectionName);<font size="2">

data = loggingSettings.TraceListeners.Get(

</font>

 

"RollingXML") as CustomTraceListenerData

;<font size="2">

data.InitData =

</font>

 

@"c:\logs\testA.svclog"

;

entLibConfig.Save();

 

}

}

}

<font size="2">

 

</font>

 

public override void TraceData(TraceEventCache eventCache, string source, TraceEventType eventType, int id, object

data)

{

checkRollover();

<font size="2">

 

</font>

 

base

.TraceData(eventCache, source, eventType, id, data);

}

 

<font size="2">

 

</font>

 

public override void WriteLine(string

message)

{

<font size="2">

 

</font>

 

Logger

.Write(message);

May 14, 2009 at 5:06 AM

See if changing File.Copy to File.Move helps.   Sorry, it's difficult to read the code and this is what I can suggest of at the moment.

 

Sarah Urmeneta
Global Technology & Solutions
Avanade, Inc.
entlib.support@Avanade.com

 

 

May 14, 2009 at 12:47 PM
Edited May 14, 2009 at 12:58 PM

The probelms is I can't delete file A, even though I have changed the trace listener to no longer point to it. 

How can I post the code so it is more readable?

 

I'm going to email it to entlib.support@avanade.com

Subject will be ROLLINGXMLTRACELISENER

Jess

 

May 14, 2009 at 2:03 PM

Hi Valiant,

I've emailed the class thank you for helping with this

Jess