diff --git a/src/Serilog.Sinks.RollingFile/RollingFileLoggerConfigurationExtensions.cs b/src/Serilog.Sinks.RollingFile/RollingFileLoggerConfigurationExtensions.cs index 672e4ef..41975e9 100644 --- a/src/Serilog.Sinks.RollingFile/RollingFileLoggerConfigurationExtensions.cs +++ b/src/Serilog.Sinks.RollingFile/RollingFileLoggerConfigurationExtensions.cs @@ -53,8 +53,9 @@ public static class RollingFileLoggerConfigurationExtensions /// including the current log file. For unlimited retention, pass null. The default is 31. /// Indicates if flushing to the output file can be buffered or not. The default /// is false. + /// Allow the log files to be shared by multiple processes. The default is false. /// Configuration object allowing method chaining. - /// The file will be written using the UTF-8 character set. + /// The file will be written using the UTF-8 encoding without a byte-order mark. public static LoggerConfiguration RollingFile( this LoggerSinkConfiguration sinkConfiguration, string pathFormat, @@ -64,11 +65,12 @@ public static LoggerConfiguration RollingFile( long? fileSizeLimitBytes = DefaultFileSizeLimitBytes, int? retainedFileCountLimit = DefaultRetainedFileCountLimit, LoggingLevelSwitch levelSwitch = null, - bool buffered = false) + bool buffered = false, + bool shared = false) { var formatter = new MessageTemplateTextFormatter(outputTemplate, formatProvider); return RollingFile(sinkConfiguration, formatter, pathFormat, restrictedToMinimumLevel, fileSizeLimitBytes, - retainedFileCountLimit, levelSwitch, buffered); + retainedFileCountLimit, levelSwitch, buffered, shared); } /// @@ -92,8 +94,9 @@ public static LoggerConfiguration RollingFile( /// including the current log file. For unlimited retention, pass null. The default is 31. /// Indicates if flushing to the output file can be buffered or not. The default /// is false. + /// Allow the log files to be shared by multiple processes. The default is false. /// Configuration object allowing method chaining. - /// The file will be written using the UTF-8 character set. + /// The file will be written using the UTF-8 encoding without a byte-order mark. public static LoggerConfiguration RollingFile( this LoggerSinkConfiguration sinkConfiguration, ITextFormatter formatter, @@ -102,11 +105,16 @@ public static LoggerConfiguration RollingFile( long? fileSizeLimitBytes = DefaultFileSizeLimitBytes, int? retainedFileCountLimit = DefaultRetainedFileCountLimit, LoggingLevelSwitch levelSwitch = null, - bool buffered = false) + bool buffered = false, + bool shared = false) { if (sinkConfiguration == null) throw new ArgumentNullException(nameof(sinkConfiguration)); if (formatter == null) throw new ArgumentNullException(nameof(formatter)); - var sink = new RollingFileSink(pathFormat, formatter, fileSizeLimitBytes, retainedFileCountLimit, buffered: buffered); + + if (shared && buffered) + throw new ArgumentException("Buffered writes are not available when file sharing is enabled.", nameof(buffered)); + + var sink = new RollingFileSink(pathFormat, formatter, fileSizeLimitBytes, retainedFileCountLimit, buffered: buffered, shared: shared); return sinkConfiguration.Sink(sink, restrictedToMinimumLevel, levelSwitch); } } diff --git a/src/Serilog.Sinks.RollingFile/Sinks/RollingFile/RollingFileSink.cs b/src/Serilog.Sinks.RollingFile/Sinks/RollingFile/RollingFileSink.cs index 0644672..9e5d745 100644 --- a/src/Serilog.Sinks.RollingFile/Sinks/RollingFile/RollingFileSink.cs +++ b/src/Serilog.Sinks.RollingFile/Sinks/RollingFile/RollingFileSink.cs @@ -39,11 +39,12 @@ public sealed class RollingFileSink : ILogEventSink, IDisposable readonly int? _retainedFileCountLimit; readonly Encoding _encoding; readonly bool _buffered; + readonly bool _shared; readonly object _syncRoot = new object(); bool _isDisposed; DateTime? _nextCheckpoint; - FileSink _currentFile; + ILogEventSink _currentFile; /// Construct a . /// String describing the location of the log files, @@ -54,9 +55,10 @@ public sealed class RollingFileSink : ILogEventSink, IDisposable /// For unrestricted growth, pass null. The default is 1 GB. /// The maximum number of log files that will be retained, /// including the current log file. For unlimited retention, pass null. The default is 31. - /// Character encoding used to write the text file. The default is UTF-8. + /// Character encoding used to write the text file. The default is UTF-8 without BOM. /// Indicates if flushing to the output file can be buffered or not. The default /// is false. + /// Allow the log files to be shared by multiple processes. The default is false. /// Configuration object allowing method chaining. /// The file will be written using the UTF-8 character set. public RollingFileSink(string pathFormat, @@ -64,18 +66,25 @@ public RollingFileSink(string pathFormat, long? fileSizeLimitBytes, int? retainedFileCountLimit, Encoding encoding = null, - bool buffered = false) + bool buffered = false, + bool shared = false) { if (pathFormat == null) throw new ArgumentNullException(nameof(pathFormat)); if (fileSizeLimitBytes.HasValue && fileSizeLimitBytes < 0) throw new ArgumentException("Negative value provided; file size limit must be non-negative"); if (retainedFileCountLimit.HasValue && retainedFileCountLimit < 1) throw new ArgumentException("Zero or negative value provided; retained file count limit must be at least 1"); +#if !SHARING + if (shared) + throw new NotSupportedException("File sharing is not supported on this platform."); +#endif + _roller = new TemplatedPathRoller(pathFormat); _textFormatter = textFormatter; _fileSizeLimitBytes = fileSizeLimitBytes; _retainedFileCountLimit = retainedFileCountLimit; - _encoding = encoding ?? new UTF8Encoding(encoderShouldEmitUTF8Identifier: false); + _encoding = encoding; _buffered = buffered; + _shared = shared; } /// @@ -98,8 +107,7 @@ public void Emit(LogEvent logEvent) // If the file was unable to be opened on the last attempt, it will remain // null until the next checkpoint passes, at which time another attempt will be made to // open it. - if (_currentFile != null) - _currentFile.Emit(logEvent); + _currentFile?.Emit(logEvent); } } @@ -148,7 +156,13 @@ void OpenFile(DateTime now) try { +#if SHARING + _currentFile = _shared ? + (ILogEventSink)new SharedFileSink(path, _textFormatter, _fileSizeLimitBytes, _encoding) : + new FileSink(path, _textFormatter, _fileSizeLimitBytes, _encoding, _buffered); +#else _currentFile = new FileSink(path, _textFormatter, _fileSizeLimitBytes, _encoding, _buffered); +#endif } catch (IOException ex) { @@ -223,7 +237,7 @@ void CloseFile() { if (_currentFile != null) { - _currentFile.Dispose(); + (_currentFile as IDisposable)?.Dispose(); _currentFile = null; } diff --git a/src/Serilog.Sinks.RollingFile/project.json b/src/Serilog.Sinks.RollingFile/project.json index b1fc93c..2651010 100644 --- a/src/Serilog.Sinks.RollingFile/project.json +++ b/src/Serilog.Sinks.RollingFile/project.json @@ -1,5 +1,5 @@ { - "version": "2.3.0-*", + "version": "3.0.0-*", "description": "The rolling file sink for Serilog - Simple .NET logging with fully-structured events", "authors": [ "Serilog Contributors" ], "packOptions": { @@ -9,8 +9,7 @@ "iconUrl": "http://serilog.net/images/serilog-sink-nuget.png" }, "dependencies": { - "Serilog": "2.0.0", - "Serilog.Sinks.File": "2.0.0" + "Serilog.Sinks.File": "3.0.0-dev-00735" }, "buildOptions": { "keyFile": "../../assets/Serilog.snk", @@ -18,7 +17,9 @@ "warningsAsErrors": true }, "frameworks": { - "net4.5": {}, + "net4.5": { + "buildOptions": {"define": ["SHARING"]} + }, "netstandard1.3": { "dependencies": { "System.IO": "4.1.0", diff --git a/test/Serilog.Sinks.RollingFile.Tests/RollingFileLoggerConfigurationExtensionsTests.cs b/test/Serilog.Sinks.RollingFile.Tests/RollingFileLoggerConfigurationExtensionsTests.cs new file mode 100644 index 0000000..e5ac302 --- /dev/null +++ b/test/Serilog.Sinks.RollingFile.Tests/RollingFileLoggerConfigurationExtensionsTests.cs @@ -0,0 +1,16 @@ +using System; +using Xunit; + +namespace Serilog.Tests +{ + public class RollingFileLoggerConfigurationExtensionsTests + { + [Fact] + public void BuffferingIsNotAvailableWhenSharingEnabled() + { + Assert.Throws(() => + new LoggerConfiguration() + .WriteTo.RollingFile("logs", buffered: true, shared: true)); + } + } +} diff --git a/test/Serilog.Sinks.RollingFile.Tests/project.json b/test/Serilog.Sinks.RollingFile.Tests/project.json index 1f84c3e..2e868cc 100644 --- a/test/Serilog.Sinks.RollingFile.Tests/project.json +++ b/test/Serilog.Sinks.RollingFile.Tests/project.json @@ -1,11 +1,9 @@ { - "version": "2.0.0", "testRunner": "xunit", "dependencies": { "Serilog.Sinks.RollingFile": { "target": "project" }, "xunit": "2.1.0", - "dotnet-test-xunit": "1.0.0-rc2-build10025", - "Serilog.Sinks.File": "2.0.0" + "dotnet-test-xunit": "1.0.0-rc2-build10025" }, "buildOptions": { "keyFile": "../../assets/Serilog.snk",