diff --git a/src/Serilog.Sinks.File/FileLoggerConfigurationExtensions.cs b/src/Serilog.Sinks.File/FileLoggerConfigurationExtensions.cs index d31acb4..9e77cbb 100644 --- a/src/Serilog.Sinks.File/FileLoggerConfigurationExtensions.cs +++ b/src/Serilog.Sinks.File/FileLoggerConfigurationExtensions.cs @@ -94,27 +94,97 @@ public static LoggerConfiguration File( long? fileSizeLimitBytes = DefaultFileSizeLimitBytes, LoggingLevelSwitch levelSwitch = null, bool buffered = false) + { + return ConfigureFile(sinkConfiguration.Sink, formatter, path, restrictedToMinimumLevel, fileSizeLimitBytes, levelSwitch, buffered); + } + + /// + /// Write log events to the specified file. + /// + /// Logger sink configuration. + /// Path to the file. + /// The minimum level for + /// events passed through the sink. Ignored when is specified. + /// A switch allowing the pass-through minimum level + /// to be changed at runtime. + /// Supplies culture-specific formatting information, or null. + /// A message template describing the format used to write to the sink. + /// the default is "{Timestamp} [{Level}] {Message}{NewLine}{Exception}". + /// Configuration object allowing method chaining. + /// The file will be written using the UTF-8 character set. + public static LoggerConfiguration File( + this LoggerAuditSinkConfiguration sinkConfiguration, + string path, + LogEventLevel restrictedToMinimumLevel = LevelAlias.Minimum, + string outputTemplate = DefaultOutputTemplate, + IFormatProvider formatProvider = null, + LoggingLevelSwitch levelSwitch = null) { if (sinkConfiguration == null) throw new ArgumentNullException(nameof(sinkConfiguration)); + if (path == null) throw new ArgumentNullException(nameof(path)); + if (outputTemplate == null) throw new ArgumentNullException(nameof(outputTemplate)); + + var formatter = new MessageTemplateTextFormatter(outputTemplate, formatProvider); + return File(sinkConfiguration, formatter, path, restrictedToMinimumLevel, levelSwitch); + } + + /// + /// Write log events to the specified file. + /// + /// Logger sink configuration. + /// A formatter, such as , to convert the log events into + /// text for the file. If control of regular text formatting is required, use the other + /// overload of + /// and specify the outputTemplate parameter instead. + /// + /// Path to the file. + /// The minimum level for + /// events passed through the sink. Ignored when is specified. + /// A switch allowing the pass-through minimum level + /// to be changed at runtime. + /// Configuration object allowing method chaining. + /// The file will be written using the UTF-8 character set. + public static LoggerConfiguration File( + this LoggerAuditSinkConfiguration sinkConfiguration, + ITextFormatter formatter, + string path, + LogEventLevel restrictedToMinimumLevel = LevelAlias.Minimum, + LoggingLevelSwitch levelSwitch = null) + { + return ConfigureFile(sinkConfiguration.Sink, formatter, path, restrictedToMinimumLevel, null, levelSwitch, false, true); + } + + static LoggerConfiguration ConfigureFile( + this Func addSink, + ITextFormatter formatter, + string path, + LogEventLevel restrictedToMinimumLevel = LevelAlias.Minimum, + long? fileSizeLimitBytes = DefaultFileSizeLimitBytes, + LoggingLevelSwitch levelSwitch = null, + bool buffered = false, + bool propagateExceptions = false) + { + if (addSink == null) throw new ArgumentNullException(nameof(addSink)); if (formatter == null) throw new ArgumentNullException(nameof(formatter)); if (path == null) throw new ArgumentNullException(nameof(path)); + if (fileSizeLimitBytes.HasValue && fileSizeLimitBytes < 0) throw new ArgumentException("Negative value provided; file size limit must be non-negative"); FileSink sink; try { sink = new FileSink(path, formatter, fileSizeLimitBytes, buffered: buffered); } - catch (ArgumentException) - { - throw; - } catch (Exception ex) { SelfLog.WriteLine("Unable to open file sink for {0}: {1}", path, ex); - return sinkConfiguration.Sink(new NullSink()); + + if (propagateExceptions) + throw; + + return addSink(new NullSink(), LevelAlias.Maximum, null); } - return sinkConfiguration.Sink(sink, restrictedToMinimumLevel, levelSwitch); + return addSink(sink, restrictedToMinimumLevel, levelSwitch); } } } \ No newline at end of file diff --git a/src/Serilog.Sinks.File/Sinks/File/FileSink.cs b/src/Serilog.Sinks.File/Sinks/File/FileSink.cs index 8268654..088b5bd 100644 --- a/src/Serilog.Sinks.File/Sinks/File/FileSink.cs +++ b/src/Serilog.Sinks.File/Sinks/File/FileSink.cs @@ -16,7 +16,6 @@ using System.IO; using System.Text; using Serilog.Core; -using Serilog.Debugging; using Serilog.Events; using Serilog.Formatting; @@ -53,7 +52,11 @@ public FileSink(string path, ITextFormatter textFormatter, long? fileSizeLimitBy _textFormatter = textFormatter; _buffered = buffered; - TryCreateDirectory(path); + var directory = Path.GetDirectoryName(path); + if (!string.IsNullOrWhiteSpace(directory) && !Directory.Exists(directory)) + { + Directory.CreateDirectory(directory); + } var file = System.IO.File.Open(path, FileMode.Append, FileAccess.Write, FileShare.Read); var outputWriter = new StreamWriter(file, encoding ?? new UTF8Encoding(encoderShouldEmitUTF8Identifier: false)); @@ -69,22 +72,6 @@ public FileSink(string path, ITextFormatter textFormatter, long? fileSizeLimitBy } } - static void TryCreateDirectory(string path) - { - try - { - var directory = Path.GetDirectoryName(path); - if (!string.IsNullOrWhiteSpace(directory) && !Directory.Exists(directory)) - { - Directory.CreateDirectory(directory); - } - } - catch (Exception ex) - { - SelfLog.WriteLine("Failed to create directory {0}: {1}", path, ex); - } - } - /// /// Emit the provided log event to the sink. /// diff --git a/src/Serilog.Sinks.File/project.json b/src/Serilog.Sinks.File/project.json index 6acdfb7..bb17847 100644 --- a/src/Serilog.Sinks.File/project.json +++ b/src/Serilog.Sinks.File/project.json @@ -9,7 +9,7 @@ "iconUrl": "http://serilog.net/images/serilog-sink-nuget.png" }, "dependencies": { - "Serilog": "2.0.0" + "Serilog": "2.2.0-dev-00688" }, "buildOptions": { "keyFile": "../../assets/Serilog.snk", diff --git a/test/Serilog.Sinks.File.Tests/FileLoggerConfigurationExtensionsTests.cs b/test/Serilog.Sinks.File.Tests/FileLoggerConfigurationExtensionsTests.cs new file mode 100644 index 0000000..8dbbdbc --- /dev/null +++ b/test/Serilog.Sinks.File.Tests/FileLoggerConfigurationExtensionsTests.cs @@ -0,0 +1,55 @@ +using System; +using Serilog; +using Serilog.Sinks.File.Tests.Support; +using Serilog.Tests.Support; +using Xunit; + +namespace Serilog.Tests +{ + public class FileLoggerConfigurationExtensionsTests + { + const string InvalidPath = "/\\"; + + [Fact] + public void WhenWritingCreationExceptionsAreSuppressed() + { + new LoggerConfiguration() + .WriteTo.File(InvalidPath) + .CreateLogger(); + } + + [Fact] + public void WhenAuditingCreationExceptionsPropagate() + { + Assert.Throws(() => + new LoggerConfiguration() + .AuditTo.File(InvalidPath) + .CreateLogger()); + } + + [Fact] + public void WhenWritingLoggingExceptionsAreSuppressed() + { + using (var tmp = TempFolder.ForCaller()) + using (var log = new LoggerConfiguration() + .WriteTo.File(new ThrowingLogEventFormatter(), tmp.AllocateFilename()) + .CreateLogger()) + { + log.Information("Hello"); + } + } + + [Fact] + public void WhenAuditingLoggingExceptionsPropagate() + { + using (var tmp = TempFolder.ForCaller()) + using (var log = new LoggerConfiguration() + .AuditTo.File(new ThrowingLogEventFormatter(), tmp.AllocateFilename()) + .CreateLogger()) + { + var ex = Assert.Throws(() => log.Information("Hello")); + Assert.IsType(ex.GetBaseException()); + } + } + } +} diff --git a/test/Serilog.Sinks.File.Tests/Sinks/File/FileSinkTests.cs b/test/Serilog.Sinks.File.Tests/FileSinkTests.cs similarity index 98% rename from test/Serilog.Sinks.File.Tests/Sinks/File/FileSinkTests.cs rename to test/Serilog.Sinks.File.Tests/FileSinkTests.cs index e71cac3..f553494 100644 --- a/test/Serilog.Sinks.File.Tests/Sinks/File/FileSinkTests.cs +++ b/test/Serilog.Sinks.File.Tests/FileSinkTests.cs @@ -1,4 +1,5 @@ -using System.IO; +using System; +using System.IO; using Xunit; using Serilog.Formatting.Json; using Serilog.Sinks.File.Tests.Support; diff --git a/test/Serilog.Sinks.File.Tests/Support/ThrowingLogEventFormatter.cs b/test/Serilog.Sinks.File.Tests/Support/ThrowingLogEventFormatter.cs new file mode 100644 index 0000000..9170ef5 --- /dev/null +++ b/test/Serilog.Sinks.File.Tests/Support/ThrowingLogEventFormatter.cs @@ -0,0 +1,15 @@ +using System; +using System.IO; +using Serilog.Events; +using Serilog.Formatting; + +namespace Serilog.Tests.Support +{ + public class ThrowingLogEventFormatter : ITextFormatter + { + public void Format(LogEvent logEvent, TextWriter output) + { + throw new NotImplementedException(); + } + } +}