Imports System Imports System.Configuration Imports System.Diagnostics Imports System.Globalization Imports System.IO Imports System.Security.Permissions Imports System.Text.RegularExpressions Public Class RollingXmlWriterTraceListener Inherits XmlWriterTraceListener Private Shared ReadOnly LogFileNumberCaptureName As String = "LogFileNumber" Private attributesLoaded As Boolean = False Private logfileSuffixExpression As Regex = New Regex("_(?<" & LogFileNumberCaptureName & ">\d*)\.", RegexOptions.Compiled) Private currentFileSuffixNumber As Integer = 0 Private _maxTraceFileSize As Long = 128 * 1024 * 1024 Private basicTraceFileName As String = String.Empty Public Sub New(ByVal filename As String) MyBase.New(filename) Me.basicTraceFileName = filename Me.currentFileSuffixNumber = Me.GetTraceFileNumber() Me.StartNewTraceFile() End Sub Public Sub New(ByVal filename As String, ByVal name As String) MyBase.New(filename, name) Me.basicTraceFileName = filename Me.StartNewTraceFile() End Sub Public ReadOnly Property CurrentTraceFileName As String Get Return Path.Combine(Path.GetDirectoryName(Me.basicTraceFileName), Path.GetFileNameWithoutExtension(Me.basicTraceFileName) & "_" & Me.currentFileSuffixNumber.ToString().PadLeft(4, "0"c) & Path.GetExtension(Me.basicTraceFileName)) End Get End Property Public Property MaxTraceFileSize As Long Get If Not Me.attributesLoaded Then Me.LoadAttributes() End If Return Me._maxTraceFileSize End Get Set(ByVal value As Long) If Not Me.attributesLoaded Then Me.LoadAttributes() End If Me._maxTraceFileSize = value End Set End Property Protected ReadOnly Property IsRollingConditionReached As Boolean Get Dim streamWriter As StreamWriter = CType(Me.Writer, StreamWriter) Dim fileStream As FileStream = CType(streamWriter.BaseStream, FileStream) Dim traceFileName As String = fileStream.Name Dim traceFileInfo As FileInfo = New FileInfo(traceFileName) If traceFileInfo.Length > Me._maxTraceFileSize Then Return True Else Return False End If End Get End Property Public Overrides Sub Fail(ByVal message As String) If Me.IsRollingConditionReached Then Me.StartNewTraceFile() End If MyBase.Fail(message) End Sub Public Overrides Sub Fail(ByVal message As String, ByVal detailMessage As String) If Me.IsRollingConditionReached Then Me.StartNewTraceFile() End If MyBase.Fail(message, detailMessage) End Sub Public Overrides Sub TraceData(ByVal eventCache As TraceEventCache, ByVal source As String, ByVal eventType As TraceEventType, ByVal id As Integer, ByVal data As Object) If Me.IsRollingConditionReached Then Me.StartNewTraceFile() End If MyBase.TraceData(eventCache, source, eventType, id, data) End Sub Public Overrides Sub TraceData(ByVal eventCache As TraceEventCache, ByVal source As String, ByVal eventType As TraceEventType, ByVal id As Integer, ParamArray data As Object()) If Me.IsRollingConditionReached Then Me.StartNewTraceFile() End If MyBase.TraceData(eventCache, source, eventType, id, data) End Sub Public Overrides Sub TraceEvent(ByVal eventCache As TraceEventCache, ByVal source As String, ByVal eventType As TraceEventType, ByVal id As Integer) If Me.IsRollingConditionReached Then Me.StartNewTraceFile() End If MyBase.TraceEvent(eventCache, source, eventType, id) End Sub Public Overrides Sub TraceEvent(ByVal eventCache As TraceEventCache, ByVal source As String, ByVal eventType As TraceEventType, ByVal id As Integer, ByVal message As String) If Me.IsRollingConditionReached Then Me.StartNewTraceFile() End If MyBase.TraceEvent(eventCache, source, eventType, id, message) End Sub Public Overrides Sub TraceEvent(ByVal eventCache As TraceEventCache, ByVal source As String, ByVal eventType As TraceEventType, ByVal id As Integer, ByVal format As String, ParamArray args As Object()) If Me.IsRollingConditionReached Then Me.StartNewTraceFile() End If MyBase.TraceEvent(eventCache, source, eventType, id, format, args) End Sub Public Overrides Sub TraceTransfer(ByVal eventCache As TraceEventCache, ByVal source As String, ByVal id As Integer, ByVal message As String, ByVal relatedActivityId As Guid) If Me.IsRollingConditionReached Then Me.StartNewTraceFile() End If MyBase.TraceTransfer(eventCache, source, id, message, relatedActivityId) End Sub Public Overrides Sub Write(ByVal o As Object) If Me.IsRollingConditionReached Then Me.StartNewTraceFile() End If MyBase.Write(o) End Sub Public Overrides Sub Write(ByVal o As Object, ByVal category As String) If Me.IsRollingConditionReached Then Me.StartNewTraceFile() End If MyBase.Write(o, category) End Sub Public Overrides Sub Write(ByVal message As String) If Me.IsRollingConditionReached Then Me.StartNewTraceFile() End If MyBase.Write(message) End Sub Public Overrides Sub Write(ByVal message As String, ByVal category As String) If Me.IsRollingConditionReached Then Me.StartNewTraceFile() End If MyBase.Write(message, category) End Sub Public Overrides Sub WriteLine(ByVal o As Object) If Me.IsRollingConditionReached Then Me.StartNewTraceFile() End If MyBase.WriteLine(o) End Sub Public Overrides Sub WriteLine(ByVal o As Object, ByVal category As String) If Me.IsRollingConditionReached Then Me.StartNewTraceFile() End If MyBase.WriteLine(o, category) End Sub Public Overrides Sub WriteLine(ByVal message As String) If Me.IsRollingConditionReached Then Me.StartNewTraceFile() End If MyBase.WriteLine(message) End Sub Public Overrides Sub WriteLine(ByVal message As String, ByVal category As String) If Me.IsRollingConditionReached Then Me.StartNewTraceFile() End If MyBase.WriteLine(message, category) End Sub Protected Overrides Function GetSupportedAttributes() As String() Return New String(0) {"MaxTraceFileSize"} End Function Private Sub StartNewTraceFile() Dim streamWriter As StreamWriter = CType(Me.Writer, StreamWriter) Dim fileStream As FileStream = CType(streamWriter.BaseStream, FileStream) fileStream.Close() Me.currentFileSuffixNumber += 1 Me.Writer = New StreamWriter(New FileStream(Me.CurrentTraceFileName, FileMode.Create)) End Sub Private Function GetTraceFileNumber() As Integer Dim directoryName As String = Path.GetDirectoryName(Me.basicTraceFileName) Dim basicTraceFileNameWithoutExtension As String = Path.GetFileNameWithoutExtension(Me.basicTraceFileName) Dim basicTraceFileNameExtension As String = Path.GetExtension(Me.basicTraceFileName) Dim existingLogFiles As String() = Directory.GetFiles(directoryName, basicTraceFileNameWithoutExtension & "*") Dim highestNumber As Integer = -1 For Each existingLogFile As String In existingLogFiles Dim match As Match = Me.logfileSuffixExpression.Match(existingLogFile) If match IsNot Nothing Then Dim tempInt As Integer If match.Groups.Count >= 1 AndAlso Integer.TryParse(match.Groups(LogFileNumberCaptureName).Value, tempInt) AndAlso tempInt >= highestNumber Then highestNumber = tempInt End If End If Next Return highestNumber End Function Private Sub LoadAttributes() If Attributes.ContainsKey("MaxTraceFileSize") AndAlso Not String.IsNullOrEmpty(Attributes("MaxTraceFileSize")) Then Dim tempLong As Long = 0 Dim attributeValue As String = Attributes("MaxTraceFileSize") If Long.TryParse(attributeValue, tempLong) Then Me._maxTraceFileSize = Long.Parse(Attributes("MaxTraceFileSize"), NumberFormatInfo.InvariantInfo) Else Throw New ConfigurationErrorsException(String.Format("Trace listener {0} has an unparseable configuration attribute ""MaxTraceFileSize"". The value ""{1}"" cannot be parsed to a long value.", Me.Name, attributeValue)) End If End If Me.attributesLoaded = True End Sub End Class