diff --git a/src/Essential.Diagnostics.RollingFileTraceListener/Diagnostics/RollingFileTraceListener.cs b/src/Essential.Diagnostics.RollingFileTraceListener/Diagnostics/RollingFileTraceListener.cs index 1417dd8..f69d72d 100644 --- a/src/Essential.Diagnostics.RollingFileTraceListener/Diagnostics/RollingFileTraceListener.cs +++ b/src/Essential.Diagnostics.RollingFileTraceListener/Diagnostics/RollingFileTraceListener.cs @@ -37,10 +37,16 @@ public class RollingFileTraceListener : TraceListenerBase { "template", "Template", "convertWriteToEvent", "ConvertWriteToEvent", + "createSubdirectories", "CreateSubdirectories" }; TraceFormatter traceFormatter = new TraceFormatter(); private RollingTextWriter rollingTextWriter; + // Indicate whether all subdirectories in full file path + // should be checked for existence and re-created if missed + // before opening the file + private bool? createSubdirectories; + /// /// Constructor. Writes to a rolling text file using the default name. /// @@ -111,6 +117,42 @@ public bool ConvertWriteToEvent } } + /// + /// Gets or sets the value indicating whether all subdirectories in full file path + /// should be checked for existence and re-created if missed + /// before opening the file. Default value is False. + /// + [SuppressMessage("Microsoft.Usage", "CA1806:DoNotIgnoreMethodResults", MessageId = "System.Boolean.TryParse(System.String,System.Boolean@)", Justification = "Default value is acceptable if conversion fails.")] + public bool CreateSubdirectories + { + get + { + if (createSubdirectories.HasValue) + { + return createSubdirectories.Value; + } + + if (Attributes.ContainsKey("createSubdirectories")) + { + bool parsed; + if (bool.TryParse(Attributes["createSubdirectories"], out parsed)) + { + createSubdirectories = parsed; + return createSubdirectories.Value; + } + } + + // Default behaviour is do NOT check and fail if any of + // the subdirectories in log file path are not exists. + return false; + } + set + { + createSubdirectories = value; + Attributes["createSubdirectories"] = value.ToString(CultureInfo.InvariantCulture); + } + } + /// /// Gets or sets the file system to use; this defaults to an adapter for System.IO.File. /// @@ -218,6 +260,7 @@ protected override void Write(string category, string message, object data) } else { + rollingTextWriter.FileSystem.CreateSubdirectories = CreateSubdirectories; rollingTextWriter.Write(null, message); } } @@ -235,6 +278,7 @@ protected override void WriteLine(string category, string message, object data) } else { + rollingTextWriter.FileSystem.CreateSubdirectories = CreateSubdirectories; rollingTextWriter.WriteLine(null, message); } } @@ -266,6 +310,7 @@ protected override void WriteTrace(TraceEventCache eventCache, string source, Tr relatedActivityId, data ); + rollingTextWriter.FileSystem.CreateSubdirectories = CreateSubdirectories; rollingTextWriter.WriteLine(eventCache, output); } diff --git a/src/Essential.Diagnostics.RollingFileTraceListener/IO/FileSystem.cs b/src/Essential.Diagnostics.RollingFileTraceListener/IO/FileSystem.cs index c1deb7b..46a59e9 100644 --- a/src/Essential.Diagnostics.RollingFileTraceListener/IO/FileSystem.cs +++ b/src/Essential.Diagnostics.RollingFileTraceListener/IO/FileSystem.cs @@ -7,6 +7,13 @@ namespace Essential.IO /// public class FileSystem : IFileSystem { + /// + /// Gets or sets the value indicating whether all subdirectories in full file path + /// should be checked for existence and re-created if missed + /// before opening the file. Default value is False. + /// + public bool CreateSubdirectories { get; set; } + /// /// Opens a System.IO.FileStream on the specified path, /// having the specified mode with read, write, or read/write access @@ -19,6 +26,13 @@ public class FileSystem : IFileSystem /// public Stream Open(string path, FileMode mode, FileAccess access, FileShare share) { + if (CreateSubdirectories) + { + // Making sure that all subdirectories in file path exists + var directory = Path.GetDirectoryName(path); + Directory.CreateDirectory(directory); + } + return File.Open(path, mode, access, share); } } diff --git a/src/Essential.Diagnostics.RollingFileTraceListener/IO/IFileSystem.cs b/src/Essential.Diagnostics.RollingFileTraceListener/IO/IFileSystem.cs index 7459f9f..f0d1a0b 100644 --- a/src/Essential.Diagnostics.RollingFileTraceListener/IO/IFileSystem.cs +++ b/src/Essential.Diagnostics.RollingFileTraceListener/IO/IFileSystem.cs @@ -7,6 +7,13 @@ namespace Essential.IO /// public interface IFileSystem { + /// + /// Gets or sets the value indicating whether all subdirectories in full file path + /// should be checked for existence and re-created if missed + /// before opening the file. Default value is False. + /// + bool CreateSubdirectories { get; set; } + /// /// Opens a System.IO.FileStream on the specified path, /// having the specified mode with read, write, or read/write access diff --git a/src/Tests/Essential.Diagnostics.RollingFileTraceListener.Tests/Utility/MockFileSystem.cs b/src/Tests/Essential.Diagnostics.RollingFileTraceListener.Tests/Utility/MockFileSystem.cs index 96cb8e2..44081c9 100644 --- a/src/Tests/Essential.Diagnostics.RollingFileTraceListener.Tests/Utility/MockFileSystem.cs +++ b/src/Tests/Essential.Diagnostics.RollingFileTraceListener.Tests/Utility/MockFileSystem.cs @@ -7,6 +7,8 @@ namespace Essential.Diagnostics.Tests.Utility { public class MockFileSystem : IFileSystem { + public bool CreateSubdirectories { get; set; } + public IList> OpenedItems = new List>(); public Stream Open(string path, FileMode mode, FileAccess access, FileShare share)