@@ -42,10 +42,12 @@ public static class FileLoggerConfigurationExtensions
4242 /// <param name="formatProvider">Supplies culture-specific formatting information, or null.</param>
4343 /// <param name="outputTemplate">A message template describing the format used to write to the sink.
4444 /// the default is "{Timestamp} [{Level}] {Message}{NewLine}{Exception}".</param>
45- /// <param name="fileSizeLimitBytes">The maximum size, in bytes, to which a log file will be allowed to grow.
46- /// For unrestricted growth, pass null. The default is 1 GB.</param>
45+ /// <param name="fileSizeLimitBytes">The approximate maximum size, in bytes, to which a log file will be allowed to grow.
46+ /// For unrestricted growth, pass null. The default is 1 GB. To avoid writing partial events, the last event within the limit
47+ /// will be written in full even if it exceeds the limit.</param>
4748 /// <param name="buffered">Indicates if flushing to the output file can be buffered or not. The default
4849 /// is false.</param>
50+ /// <param name="shared">Allow the log file to be shared by multiple processes. The default is false.</param>
4951 /// <returns>Configuration object allowing method chaining.</returns>
5052 /// <remarks>The file will be written using the UTF-8 character set.</remarks>
5153 public static LoggerConfiguration File (
@@ -56,14 +58,15 @@ public static LoggerConfiguration File(
5658 IFormatProvider formatProvider = null ,
5759 long ? fileSizeLimitBytes = DefaultFileSizeLimitBytes ,
5860 LoggingLevelSwitch levelSwitch = null ,
59- bool buffered = false )
61+ bool buffered = false ,
62+ bool shared = false )
6063 {
6164 if ( sinkConfiguration == null ) throw new ArgumentNullException ( nameof ( sinkConfiguration ) ) ;
6265 if ( path == null ) throw new ArgumentNullException ( nameof ( path ) ) ;
6366 if ( outputTemplate == null ) throw new ArgumentNullException ( nameof ( outputTemplate ) ) ;
6467
6568 var formatter = new MessageTemplateTextFormatter ( outputTemplate , formatProvider ) ;
66- return File ( sinkConfiguration , formatter , path , restrictedToMinimumLevel , fileSizeLimitBytes , levelSwitch , buffered ) ;
69+ return File ( sinkConfiguration , formatter , path , restrictedToMinimumLevel , fileSizeLimitBytes , levelSwitch , buffered : buffered , shared : shared ) ;
6770 }
6871
6972 /// <summary>
@@ -72,18 +75,20 @@ public static LoggerConfiguration File(
7275 /// <param name="sinkConfiguration">Logger sink configuration.</param>
7376 /// <param name="formatter">A formatter, such as <see cref="JsonFormatter"/>, to convert the log events into
7477 /// text for the file. If control of regular text formatting is required, use the other
75- /// overload of <see cref="File(LoggerSinkConfiguration, string, LogEventLevel, string, IFormatProvider, long?, LoggingLevelSwitch, bool)"/>
78+ /// overload of <see cref="File(LoggerSinkConfiguration, string, LogEventLevel, string, IFormatProvider, long?, LoggingLevelSwitch, bool, bool )"/>
7679 /// and specify the outputTemplate parameter instead.
7780 /// </param>
7881 /// <param name="path">Path to the file.</param>
7982 /// <param name="restrictedToMinimumLevel">The minimum level for
8083 /// events passed through the sink. Ignored when <paramref name="levelSwitch"/> is specified.</param>
8184 /// <param name="levelSwitch">A switch allowing the pass-through minimum level
8285 /// to be changed at runtime.</param>
83- /// <param name="fileSizeLimitBytes">The maximum size, in bytes, to which a log file will be allowed to grow.
84- /// For unrestricted growth, pass null. The default is 1 GB.</param>
86+ /// <param name="fileSizeLimitBytes">The approximate maximum size, in bytes, to which a log file will be allowed to grow.
87+ /// For unrestricted growth, pass null. The default is 1 GB. To avoid writing partial events, the last event within the limit
88+ /// will be written in full even if it exceeds the limit.</param>
8589 /// <param name="buffered">Indicates if flushing to the output file can be buffered or not. The default
8690 /// is false.</param>
91+ /// <param name="shared">Allow the log file to be shared by multiple processes. The default is false.</param>
8792 /// <returns>Configuration object allowing method chaining.</returns>
8893 /// <remarks>The file will be written using the UTF-8 character set.</remarks>
8994 public static LoggerConfiguration File (
@@ -93,28 +98,121 @@ public static LoggerConfiguration File(
9398 LogEventLevel restrictedToMinimumLevel = LevelAlias . Minimum ,
9499 long ? fileSizeLimitBytes = DefaultFileSizeLimitBytes ,
95100 LoggingLevelSwitch levelSwitch = null ,
96- bool buffered = false )
101+ bool buffered = false ,
102+ bool shared = false )
103+ {
104+ return ConfigureFile ( sinkConfiguration . Sink , formatter , path , restrictedToMinimumLevel , fileSizeLimitBytes , levelSwitch , buffered : buffered , shared : shared ) ;
105+ }
106+
107+ /// <summary>
108+ /// Write log events to the specified file.
109+ /// </summary>
110+ /// <param name="sinkConfiguration">Logger sink configuration.</param>
111+ /// <param name="path">Path to the file.</param>
112+ /// <param name="restrictedToMinimumLevel">The minimum level for
113+ /// events passed through the sink. Ignored when <paramref name="levelSwitch"/> is specified.</param>
114+ /// <param name="levelSwitch">A switch allowing the pass-through minimum level
115+ /// to be changed at runtime.</param>
116+ /// <param name="formatProvider">Supplies culture-specific formatting information, or null.</param>
117+ /// <param name="outputTemplate">A message template describing the format used to write to the sink.
118+ /// the default is "{Timestamp} [{Level}] {Message}{NewLine}{Exception}".</param>
119+ /// <returns>Configuration object allowing method chaining.</returns>
120+ /// <remarks>The file will be written using the UTF-8 character set.</remarks>
121+ public static LoggerConfiguration File (
122+ this LoggerAuditSinkConfiguration sinkConfiguration ,
123+ string path ,
124+ LogEventLevel restrictedToMinimumLevel = LevelAlias . Minimum ,
125+ string outputTemplate = DefaultOutputTemplate ,
126+ IFormatProvider formatProvider = null ,
127+ LoggingLevelSwitch levelSwitch = null )
97128 {
98129 if ( sinkConfiguration == null ) throw new ArgumentNullException ( nameof ( sinkConfiguration ) ) ;
130+ if ( path == null ) throw new ArgumentNullException ( nameof ( path ) ) ;
131+ if ( outputTemplate == null ) throw new ArgumentNullException ( nameof ( outputTemplate ) ) ;
132+
133+ var formatter = new MessageTemplateTextFormatter ( outputTemplate , formatProvider ) ;
134+ return File ( sinkConfiguration , formatter , path , restrictedToMinimumLevel , levelSwitch ) ;
135+ }
136+
137+ /// <summary>
138+ /// Write log events to the specified file.
139+ /// </summary>
140+ /// <param name="sinkConfiguration">Logger sink configuration.</param>
141+ /// <param name="formatter">A formatter, such as <see cref="JsonFormatter"/>, to convert the log events into
142+ /// text for the file. If control of regular text formatting is required, use the other
143+ /// overload of <see cref="File(LoggerAuditSinkConfiguration, string, LogEventLevel, string, IFormatProvider, LoggingLevelSwitch)"/>
144+ /// and specify the outputTemplate parameter instead.
145+ /// </param>
146+ /// <param name="path">Path to the file.</param>
147+ /// <param name="restrictedToMinimumLevel">The minimum level for
148+ /// events passed through the sink. Ignored when <paramref name="levelSwitch"/> is specified.</param>
149+ /// <param name="levelSwitch">A switch allowing the pass-through minimum level
150+ /// to be changed at runtime.</param>
151+ /// <returns>Configuration object allowing method chaining.</returns>
152+ /// <remarks>The file will be written using the UTF-8 character set.</remarks>
153+ public static LoggerConfiguration File (
154+ this LoggerAuditSinkConfiguration sinkConfiguration ,
155+ ITextFormatter formatter ,
156+ string path ,
157+ LogEventLevel restrictedToMinimumLevel = LevelAlias . Minimum ,
158+ LoggingLevelSwitch levelSwitch = null )
159+ {
160+ return ConfigureFile ( sinkConfiguration . Sink , formatter , path , restrictedToMinimumLevel , null , levelSwitch , false , true ) ;
161+ }
162+
163+ static LoggerConfiguration ConfigureFile (
164+ this Func < ILogEventSink , LogEventLevel , LoggingLevelSwitch , LoggerConfiguration > addSink ,
165+ ITextFormatter formatter ,
166+ string path ,
167+ LogEventLevel restrictedToMinimumLevel = LevelAlias . Minimum ,
168+ long ? fileSizeLimitBytes = DefaultFileSizeLimitBytes ,
169+ LoggingLevelSwitch levelSwitch = null ,
170+ bool buffered = false ,
171+ bool propagateExceptions = false ,
172+ bool shared = false )
173+ {
174+ if ( addSink == null ) throw new ArgumentNullException ( nameof ( addSink ) ) ;
99175 if ( formatter == null ) throw new ArgumentNullException ( nameof ( formatter ) ) ;
100176 if ( path == null ) throw new ArgumentNullException ( nameof ( path ) ) ;
177+ if ( fileSizeLimitBytes . HasValue && fileSizeLimitBytes < 0 ) throw new ArgumentException ( "Negative value provided; file size limit must be non-negative" ) ;
101178
102- FileSink sink ;
103- try
179+ if ( shared )
104180 {
105- sink = new FileSink ( path , formatter , fileSizeLimitBytes , buffered : buffered ) ;
181+ #if ! ATOMIC_APPEND
182+ throw new NotSupportedException ( "File sharing is not supported on this platform." ) ;
183+ #endif
184+
185+ if ( buffered )
186+ throw new ArgumentException ( "Buffered writes are not available when file sharing is enabled." , nameof ( buffered ) ) ;
106187 }
107- catch ( ArgumentException )
188+
189+ ILogEventSink sink ;
190+ try
108191 {
109- throw ;
192+ #if ATOMIC_APPEND
193+ if ( shared )
194+ {
195+ sink = new SharedFileSink ( path , formatter , fileSizeLimitBytes ) ;
196+ }
197+ else
198+ {
199+ #endif
200+ sink = new FileSink ( path , formatter , fileSizeLimitBytes , buffered : buffered ) ;
201+ #if ATOMIC_APPEND
202+ }
203+ #endif
110204 }
111205 catch ( Exception ex )
112206 {
113207 SelfLog . WriteLine ( "Unable to open file sink for {0}: {1}" , path , ex ) ;
114- return sinkConfiguration . Sink ( new NullSink ( ) ) ;
208+
209+ if ( propagateExceptions )
210+ throw ;
211+
212+ return addSink ( new NullSink ( ) , LevelAlias . Maximum , null ) ;
115213 }
116214
117- return sinkConfiguration . Sink ( sink , restrictedToMinimumLevel , levelSwitch ) ;
215+ return addSink ( sink , restrictedToMinimumLevel , levelSwitch ) ;
118216 }
119217 }
120218}
0 commit comments