Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -33,13 +33,33 @@ public class RollingFileTraceListener : TraceListenerBase
private const string _defaultFilePathTemplate = "{ApplicationName}-{DateTime:yyyy-MM-dd}.log";
// Default format matches Microsoft.VisualBasic.Logging.FileLogTraceListener
private const string _defaultTemplate = "{DateTime:u} [{Thread}] {EventType} {Source} {Id}: {Message}{Data}";
private readonly string _filePathTemplate;
private static string[] _supportedAttributes = new string[]
{
"template", "Template",
"convertWriteToEvent", "ConvertWriteToEvent",
"newStreamOnError", "NewStreamOnError"
};
TraceFormatter traceFormatter = new TraceFormatter();
private RollingTextWriter rollingTextWriter;
private object _rollingTextWriterLock = new object();
private RollingTextWriter _rollingTextWriter = null;
private RollingTextWriter RollingTextWriter
{
get
{
if (_rollingTextWriter == null)
{
lock (_rollingTextWriterLock)
{
if (_rollingTextWriter == null)
{
_rollingTextWriter = RollingTextWriter.Create(_filePathTemplate, NewStreamOnError);
}
}
}
return _rollingTextWriter;
}
}

/// <summary>
/// Constructor. Writes to a rolling text file using the default name.
Expand Down Expand Up @@ -78,11 +98,11 @@ public RollingFileTraceListener(string filePathTemplate)
{
if (string.IsNullOrEmpty(filePathTemplate))
{
rollingTextWriter = new RollingTextWriter(_defaultFilePathTemplate);
_filePathTemplate = _defaultFilePathTemplate;
}
else
{
rollingTextWriter = RollingTextWriter.Create(filePathTemplate);
_filePathTemplate = filePathTemplate;
}
}

Expand Down Expand Up @@ -111,13 +131,47 @@ public bool ConvertWriteToEvent
}
}

private bool? _newStreamOnError = null;
Comment thread
alex-grigoras marked this conversation as resolved.
/// <summary>
/// Gets or sets whether errors writing to the file should cause a new file stream to be instantiated.
/// Useful when the drive containing the file has a transient fault (usb stick removed and reinserted, network outage of mapped drive, etc.)
/// </summary>
[SuppressMessage("Microsoft.Usage", "CA1806:DoNotIgnoreMethodResults", MessageId = "System.Boolean.TryParse(System.String,System.Boolean@)", Justification = "Default value is acceptable if conversion fails.")]
public bool NewStreamOnError
{
get
{
if (_newStreamOnError.HasValue)
{
return _newStreamOnError.Value;
}

// Default behaviour is to create a new stream on error
var newStreamOnError = true;
if (Attributes.ContainsKey("newStreamOnError"))
{
if(bool.TryParse(Attributes["newStreamOnError"], out newStreamOnError) == false)
Comment thread
alex-grigoras marked this conversation as resolved.
{
newStreamOnError = true;
}
}
_newStreamOnError = newStreamOnError;
return newStreamOnError;
}
set
{
Attributes["newStreamOnError"] = value.ToString(CultureInfo.InvariantCulture);
Comment thread
alex-grigoras marked this conversation as resolved.
_newStreamOnError = value;
}
}

/// <summary>
/// Gets or sets the file system to use; this defaults to an adapter for System.IO.File.
/// </summary>
public IFileSystem FileSystem
{
get { return rollingTextWriter.FileSystem; }
set { rollingTextWriter.FileSystem = value; }
get { return RollingTextWriter.FileSystem; }
set { RollingTextWriter.FileSystem = value; }
}

/// <summary>
Expand Down Expand Up @@ -186,15 +240,15 @@ public string Template
/// </remarks>
public string FilePathTemplate
{
get { return rollingTextWriter.FilePathTemplate; }
get { return RollingTextWriter.FilePathTemplate; }
}

/// <summary>
/// Flushes the output buffer.
/// </summary>
public override void Flush()
{
rollingTextWriter.Flush();
RollingTextWriter.Flush();
}

/// <summary>
Expand All @@ -218,7 +272,7 @@ protected override void Write(string category, string message, object data)
}
else
{
rollingTextWriter.Write(null, message);
RollingTextWriter.Write(null, message);
}
}

Expand All @@ -235,7 +289,7 @@ protected override void WriteLine(string category, string message, object data)
}
else
{
rollingTextWriter.WriteLine(null, message);
RollingTextWriter.WriteLine(null, message);
}
}

Expand Down Expand Up @@ -266,16 +320,16 @@ protected override void WriteTrace(TraceEventCache eventCache, string source, Tr
relatedActivityId,
data
);
rollingTextWriter.WriteLine(eventCache, output);
RollingTextWriter.WriteLine(eventCache, output);
}

protected override void Dispose(bool disposing)
{
if (disposing)
{
if (rollingTextWriter != null)
if (RollingTextWriter != null)
{
rollingTextWriter.Dispose();
RollingTextWriter.Dispose();
}
}
base.Dispose(disposing);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,18 +16,20 @@ class RollingTextWriter : IDisposable
private string _filePathTemplate;
private IFileSystem _fileSystem = new FileSystem();
TraceFormatter traceFormatter = new TraceFormatter();
private bool _newStreamOnError;

public RollingTextWriter(string filePathTemplate)
public RollingTextWriter(string filePathTemplate, bool newStreamOnError)
{
_filePathTemplate = filePathTemplate;
_newStreamOnError = newStreamOnError;
}

/// <summary>
/// Create RollingTextWriter with filePathTemplate which might contain 1 environment variable in front.
/// </summary>
/// <param name="filePathTemplate"></param>
/// <returns></returns>
public static RollingTextWriter Create(string filePathTemplate)
public static RollingTextWriter Create(string filePathTemplate, bool newStreamOnError)
{
var segments = filePathTemplate.Split('%');
if (segments.Length > 3)
Expand All @@ -50,10 +52,10 @@ public static RollingTextWriter Create(string filePathTemplate)
}
}
var filePath = rootFolder + segments[2];
return new RollingTextWriter(filePath);
return new RollingTextWriter(filePath, newStreamOnError);
}

return new RollingTextWriter(filePathTemplate);
return new RollingTextWriter(filePathTemplate, newStreamOnError);

}

Expand All @@ -80,7 +82,18 @@ public void Flush()
{
if (_currentWriter != null)
{
_currentWriter.Flush();
try
{
_currentWriter.Flush();
}
catch
{
if (_newStreamOnError)
{
DestroyCurrentWriter();
}
throw;
}
}
}
}
Expand All @@ -91,7 +104,18 @@ public void Write(TraceEventCache eventCache, string value)
lock (_fileLock)
{
EnsureCurrentWriter(filePath);
_currentWriter.Write(value);
try
{
_currentWriter.Write(value);
}
catch
{
if(_newStreamOnError)
{
DestroyCurrentWriter();
}
throw;
}
}
}

Expand All @@ -101,7 +125,18 @@ public void WriteLine(TraceEventCache eventCache, string value)
lock (_fileLock)
{
EnsureCurrentWriter(filePath);
_currentWriter.WriteLine(value);
try
{
_currentWriter.WriteLine(value);
}
catch
{
if (_newStreamOnError)
{
DestroyCurrentWriter();
}
throw;
}
}
}

Expand Down Expand Up @@ -148,6 +183,18 @@ private void EnsureCurrentWriter(string path)
}
}

private void DestroyCurrentWriter()
{
// NOTE: This is called inside lock(_fileLock)
if (_currentWriter != null)
{
_currentWriter.Close();
_currentWriter.Dispose();
_currentWriter = null;
_currentPath = null;
}
}

static string getFullPath(string path, int num)
{
var extension = Path.GetExtension(path);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
using System;
using System.Collections;
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System.Globalization;
using System.IO;
using System.Text;
Expand Down Expand Up @@ -40,13 +41,32 @@ public class RollingXmlTraceListener : TraceListenerBase
private readonly string machineName = Environment.MachineName;
// Default format matches Microsoft.VisualBasic.Logging.FileLogTraceListener
private const string _defaultFilePathTemplate = "{ApplicationName}-{DateTime:yyyy-MM-dd}.svclog";
private readonly string _filePathTemplate;
private static string[] _supportedAttributes = new string[]
{
{
"newStreamOnError", "NewStreamOnError"
};
TraceFormatter traceFormatter = new TraceFormatter();

private RollingTextWriter rollingTextWriter;

private object _rollingTextWriterLock = new object();
private RollingTextWriter _rollingTextWriter = null;
private RollingTextWriter RollingTextWriter
{
get
{
if (_rollingTextWriter == null)
{
lock (_rollingTextWriterLock)
{
if (_rollingTextWriter == null)
{
_rollingTextWriter = RollingTextWriter.Create(_filePathTemplate, NewStreamOnError);
}
}
}
return _rollingTextWriter;
}
}
/// <summary>
/// Constructor. Writes to a rolling text file using the default name.
/// </summary>
Expand Down Expand Up @@ -84,11 +104,11 @@ public RollingXmlTraceListener(string filePathTemplate)
{
if (string.IsNullOrEmpty(filePathTemplate))
{
rollingTextWriter = new RollingTextWriter(_defaultFilePathTemplate);
_filePathTemplate = _defaultFilePathTemplate;
}
else
{
rollingTextWriter = RollingTextWriter.Create(filePathTemplate);
_filePathTemplate = filePathTemplate;
}
}

Expand All @@ -97,8 +117,8 @@ public RollingXmlTraceListener(string filePathTemplate)
/// </summary>
public IFileSystem FileSystem
{
get { return rollingTextWriter.FileSystem; }
set { rollingTextWriter.FileSystem = value; }
get { return RollingTextWriter.FileSystem; }
set { RollingTextWriter.FileSystem = value; }
}

/// <summary>
Expand All @@ -122,15 +142,48 @@ public override bool IsThreadSafe
/// </remarks>
public string FilePathTemplate
{
get { return rollingTextWriter.FilePathTemplate; }
get { return RollingTextWriter.FilePathTemplate; }
}

private bool? _newStreamOnError = null;
/// <summary>
/// Gets or sets whether errors writing to the file should cause a new file stream to be instantiated.
/// Useful when the drive containing the file has a transient fault (usb stick removed and reinserted, network outage of mapped drive, etc.)
/// </summary>
[SuppressMessage("Microsoft.Usage", "CA1806:DoNotIgnoreMethodResults", MessageId = "System.Boolean.TryParse(System.String,System.Boolean@)", Justification = "Default value is acceptable if conversion fails.")]
public bool NewStreamOnError
{
get
{
if(_newStreamOnError.HasValue)
{
return _newStreamOnError.Value;
}

// Default behaviour is to create a new stream on error
var newStreamOnError = true;
if (Attributes.ContainsKey("newStreamOnError"))
{
if (bool.TryParse(Attributes["newStreamOnError"], out newStreamOnError) == false)
{
newStreamOnError = true;
}
}
_newStreamOnError = newStreamOnError;
return newStreamOnError;
}
set
{
Attributes["newStreamOnError"] = value.ToString(CultureInfo.InvariantCulture);
}
}

/// <summary>
/// Flushes the output buffer.
/// </summary>
public override void Flush()
{
rollingTextWriter.Flush();
RollingTextWriter.Flush();
}

/// <summary>
Expand Down Expand Up @@ -170,7 +223,7 @@ protected override void WriteTrace(TraceEventCache eventCache, string source, Tr

AppendFooter(output, eventCache);

rollingTextWriter.WriteLine(eventCache, output.ToString());
RollingTextWriter.WriteLine(eventCache, output.ToString());
}

private static void AppendData(StringBuilder output, object data)
Expand Down