@@ -42,10 +42,12 @@ public static class FileLoggerConfigurationExtensions
42
42
/// <param name="formatProvider">Supplies culture-specific formatting information, or null.</param>
43
43
/// <param name="outputTemplate">A message template describing the format used to write to the sink.
44
44
/// 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>
47
48
/// <param name="buffered">Indicates if flushing to the output file can be buffered or not. The default
48
49
/// is false.</param>
50
+ /// <param name="shared">Allow the log file to be shared by multiple processes. The default is false.</param>
49
51
/// <returns>Configuration object allowing method chaining.</returns>
50
52
/// <remarks>The file will be written using the UTF-8 character set.</remarks>
51
53
public static LoggerConfiguration File (
@@ -56,14 +58,15 @@ public static LoggerConfiguration File(
56
58
IFormatProvider formatProvider = null ,
57
59
long ? fileSizeLimitBytes = DefaultFileSizeLimitBytes ,
58
60
LoggingLevelSwitch levelSwitch = null ,
59
- bool buffered = false )
61
+ bool buffered = false ,
62
+ bool shared = false )
60
63
{
61
64
if ( sinkConfiguration == null ) throw new ArgumentNullException ( nameof ( sinkConfiguration ) ) ;
62
65
if ( path == null ) throw new ArgumentNullException ( nameof ( path ) ) ;
63
66
if ( outputTemplate == null ) throw new ArgumentNullException ( nameof ( outputTemplate ) ) ;
64
67
65
68
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 ) ;
67
70
}
68
71
69
72
/// <summary>
@@ -72,18 +75,20 @@ public static LoggerConfiguration File(
72
75
/// <param name="sinkConfiguration">Logger sink configuration.</param>
73
76
/// <param name="formatter">A formatter, such as <see cref="JsonFormatter"/>, to convert the log events into
74
77
/// 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 )"/>
76
79
/// and specify the outputTemplate parameter instead.
77
80
/// </param>
78
81
/// <param name="path">Path to the file.</param>
79
82
/// <param name="restrictedToMinimumLevel">The minimum level for
80
83
/// events passed through the sink. Ignored when <paramref name="levelSwitch"/> is specified.</param>
81
84
/// <param name="levelSwitch">A switch allowing the pass-through minimum level
82
85
/// 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>
85
89
/// <param name="buffered">Indicates if flushing to the output file can be buffered or not. The default
86
90
/// is false.</param>
91
+ /// <param name="shared">Allow the log file to be shared by multiple processes. The default is false.</param>
87
92
/// <returns>Configuration object allowing method chaining.</returns>
88
93
/// <remarks>The file will be written using the UTF-8 character set.</remarks>
89
94
public static LoggerConfiguration File (
@@ -93,28 +98,121 @@ public static LoggerConfiguration File(
93
98
LogEventLevel restrictedToMinimumLevel = LevelAlias . Minimum ,
94
99
long ? fileSizeLimitBytes = DefaultFileSizeLimitBytes ,
95
100
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 )
97
128
{
98
129
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 ) ) ;
99
175
if ( formatter == null ) throw new ArgumentNullException ( nameof ( formatter ) ) ;
100
176
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" ) ;
101
178
102
- FileSink sink ;
103
- try
179
+ if ( shared )
104
180
{
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 ) ) ;
106
187
}
107
- catch ( ArgumentException )
188
+
189
+ ILogEventSink sink ;
190
+ try
108
191
{
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
110
204
}
111
205
catch ( Exception ex )
112
206
{
113
207
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 ) ;
115
213
}
116
214
117
- return sinkConfiguration . Sink ( sink , restrictedToMinimumLevel , levelSwitch ) ;
215
+ return addSink ( sink , restrictedToMinimumLevel , levelSwitch ) ;
118
216
}
119
217
}
120
218
}
0 commit comments