4
4
using Serilog . Sinks . File . Tests . Support ;
5
5
using Serilog . Configuration ;
6
6
using Serilog . Core ;
7
+ using Xunit . Abstractions ;
7
8
8
9
namespace Serilog . Sinks . File . Tests ;
9
10
10
11
public class RollingFileSinkTests
11
12
{
13
+ private readonly ITestOutputHelper _testOutputHelper ;
14
+
15
+ public RollingFileSinkTests ( ITestOutputHelper testOutputHelper )
16
+ {
17
+ _testOutputHelper = testOutputHelper ;
18
+ }
19
+
12
20
[ Fact ]
13
21
public void LogEventsAreEmittedToTheFileNamedAccordingToTheEventTimestamp ( )
14
22
{
@@ -145,6 +153,130 @@ public void WhenRetentionCountAndArchivingHookIsSetOldFilesAreCopiedAndOriginalD
145
153
} ) ;
146
154
}
147
155
156
+ [ Fact ]
157
+ public void WhenFirstOpeningFailedWithLockRetryDelayedUntilNextCheckpoint ( )
158
+ {
159
+ var fileName = Some . String ( ) + ".txt" ;
160
+ using var temp = new TempFolder ( ) ;
161
+ using var log = new LoggerConfiguration ( )
162
+ . WriteTo . File ( Path . Combine ( temp . Path , fileName ) , rollOnFileSizeLimit : true , fileSizeLimitBytes : 1 , rollingInterval : RollingInterval . Minute , hooks : new FailOpeningHook ( true , 2 , 3 , 4 ) )
163
+ . CreateLogger ( ) ;
164
+ LogEvent e1 = Some . InformationEvent ( new DateTime ( 2012 , 10 , 28 ) ) ,
165
+ e2 = Some . InformationEvent ( e1 . Timestamp . AddSeconds ( 1 ) ) ,
166
+ e3 = Some . InformationEvent ( e1 . Timestamp . AddMinutes ( 5 ) ) ,
167
+ e4 = Some . InformationEvent ( e1 . Timestamp . AddMinutes ( 31 ) ) ;
168
+ LogEvent [ ] logEvents = new [ ] { e1 , e2 , e3 , e4 } ;
169
+
170
+ foreach ( var logEvent in logEvents )
171
+ {
172
+ Clock . SetTestDateTimeNow ( logEvent . Timestamp . DateTime ) ;
173
+ log . Write ( logEvent ) ;
174
+ }
175
+
176
+ var files = Directory . GetFiles ( temp . Path )
177
+ . OrderBy ( p => p , StringComparer . OrdinalIgnoreCase )
178
+ . ToArray ( ) ;
179
+ var pattern = "yyyyMMddHHmm" ;
180
+
181
+ Assert . Equal ( 6 , files . Length ) ;
182
+ // Successful write of e1:
183
+ Assert . True ( files [ 0 ] . EndsWith ( ExpectedFileName ( fileName , e1 . Timestamp , pattern ) ) , files [ 0 ] ) ;
184
+ // Failing writes for e2, will be dropped and logged to SelfLog:
185
+ Assert . True ( files [ 1 ] . EndsWith ( "_001.txt" ) , files [ 1 ] ) ;
186
+ Assert . True ( files [ 2 ] . EndsWith ( "_002.txt" ) , files [ 2 ] ) ;
187
+ Assert . True ( files [ 3 ] . EndsWith ( "_003.txt" ) , files [ 3 ] ) ;
188
+ // Successful write of e3:
189
+ Assert . True ( files [ 4 ] . EndsWith ( ExpectedFileName ( fileName , e3 . Timestamp , pattern ) ) , files [ 4 ] ) ;
190
+ // Successful write of e4:
191
+ Assert . True ( files [ 5 ] . EndsWith ( ExpectedFileName ( fileName , e4 . Timestamp , pattern ) ) , files [ 5 ] ) ;
192
+ }
193
+
194
+ [ Fact ]
195
+ public void WhenFirstOpeningFailedWithLockRetryDelayed30Minutes ( )
196
+ {
197
+ var fileName = Some . String ( ) + ".txt" ;
198
+ using var temp = new TempFolder ( ) ;
199
+ LogEvent e1 = Some . InformationEvent ( new DateTime ( 2012 , 10 , 28 ) ) ,
200
+ e2 = Some . InformationEvent ( e1 . Timestamp . AddSeconds ( 1 ) ) ,
201
+ e3 = Some . InformationEvent ( e1 . Timestamp . AddMinutes ( 5 ) ) ,
202
+ e4 = Some . InformationEvent ( e1 . Timestamp . AddMinutes ( 31 ) ) ;
203
+ LogEvent [ ] logEvents = new [ ] { e1 , e2 , e3 , e4 } ;
204
+
205
+ using ( var log = new LoggerConfiguration ( )
206
+ . WriteTo . File ( Path . Combine ( temp . Path , fileName ) , rollOnFileSizeLimit : true , fileSizeLimitBytes : 1 ,
207
+ rollingInterval : RollingInterval . Hour , hooks : new FailOpeningHook ( true , 2 , 3 , 4 ) )
208
+ . CreateLogger ( ) )
209
+ {
210
+ foreach ( var logEvent in logEvents )
211
+ {
212
+ Clock . SetTestDateTimeNow ( logEvent . Timestamp . DateTime ) ;
213
+ log . Write ( logEvent ) ;
214
+ }
215
+ }
216
+
217
+ var files = Directory . GetFiles ( temp . Path )
218
+ . OrderBy ( p => p , StringComparer . OrdinalIgnoreCase )
219
+ . ToArray ( ) ;
220
+ var pattern = "yyyyMMddHH" ;
221
+
222
+ foreach ( var file in files )
223
+ {
224
+ _testOutputHelper . WriteLine ( file + ": " + System . IO . File . ReadAllText ( file ) ) ;
225
+ }
226
+ Assert . Equal ( 5 , files . Length ) ;
227
+ // Successful write of e1:
228
+ Assert . True ( files [ 0 ] . EndsWith ( ExpectedFileName ( fileName , e1 . Timestamp , pattern ) ) , files [ 0 ] ) ;
229
+ // Failing writes for e2, will be dropped and logged to SelfLog; on lock it will try it three times:
230
+ Assert . True ( files [ 1 ] . EndsWith ( "_001.txt" ) , files [ 1 ] ) ;
231
+ Assert . True ( files [ 2 ] . EndsWith ( "_002.txt" ) , files [ 2 ] ) ;
232
+ Assert . True ( files [ 3 ] . EndsWith ( "_003.txt" ) , files [ 3 ] ) ;
233
+ /* e3 will be dropped and logged to SelfLog without new file as it's in the 30 minutes cooldown and roller only starts on next hour! */
234
+ // Successful write of e4:
235
+ Assert . True ( files [ 4 ] . EndsWith ( "_004.txt" ) , files [ 4 ] ) ;
236
+ }
237
+
238
+ [ Fact ]
239
+ public void WhenFirstOpeningFailedWithoutLockRetryDelayed30Minutes ( )
240
+ {
241
+ var fileName = Some . String ( ) + ".txt" ;
242
+ using var temp = new TempFolder ( ) ;
243
+ LogEvent e1 = Some . InformationEvent ( new DateTime ( 2012 , 10 , 28 ) ) ,
244
+ e2 = Some . InformationEvent ( e1 . Timestamp . AddSeconds ( 1 ) ) ,
245
+ e3 = Some . InformationEvent ( e1 . Timestamp . AddMinutes ( 5 ) ) ,
246
+ e4 = Some . InformationEvent ( e1 . Timestamp . AddMinutes ( 31 ) ) ;
247
+ LogEvent [ ] logEvents = new [ ] { e1 , e2 , e3 , e4 } ;
248
+
249
+ using ( var log = new LoggerConfiguration ( )
250
+ . WriteTo . File ( Path . Combine ( temp . Path , fileName ) , rollOnFileSizeLimit : true , fileSizeLimitBytes : 1 ,
251
+ rollingInterval : RollingInterval . Hour , hooks : new FailOpeningHook ( false , 2 ) )
252
+ . CreateLogger ( ) )
253
+ {
254
+ foreach ( var logEvent in logEvents )
255
+ {
256
+ Clock . SetTestDateTimeNow ( logEvent . Timestamp . DateTime ) ;
257
+ log . Write ( logEvent ) ;
258
+ }
259
+ }
260
+
261
+ var files = Directory . GetFiles ( temp . Path )
262
+ . OrderBy ( p => p , StringComparer . OrdinalIgnoreCase )
263
+ . ToArray ( ) ;
264
+ var pattern = "yyyyMMddHH" ;
265
+
266
+ foreach ( var file in files )
267
+ {
268
+ _testOutputHelper . WriteLine ( file + ": " + System . IO . File . ReadAllText ( file ) ) ;
269
+ }
270
+ Assert . Equal ( 3 , files . Length ) ;
271
+ // Successful write of e1:
272
+ Assert . True ( files [ 0 ] . EndsWith ( ExpectedFileName ( fileName , e1 . Timestamp , pattern ) ) , files [ 0 ] ) ;
273
+ // Failing writes for e2, will be dropped and logged to SelfLog; on non-lock it will try it once:
274
+ Assert . True ( files [ 1 ] . EndsWith ( "_001.txt" ) , files [ 1 ] ) ;
275
+ /* e3 will be dropped and logged to SelfLog without new file as it's in the 30 minutes cooldown and roller only starts on next hour! */
276
+ // Successful write of e4:
277
+ Assert . True ( files [ 2 ] . EndsWith ( "_002.txt" ) , files [ 2 ] ) ;
278
+ }
279
+
148
280
[ Fact ]
149
281
public void WhenSizeLimitIsBreachedNewFilesCreated ( )
150
282
{
@@ -279,7 +411,7 @@ static void TestRollingEventSequence(
279
411
Clock . SetTestDateTimeNow ( @event . Timestamp . DateTime ) ;
280
412
log . Write ( @event ) ;
281
413
282
- var expected = pathFormat . Replace ( ".txt" , @event . Timestamp . ToString ( "yyyyMMdd" ) + ".txt ") ;
414
+ var expected = ExpectedFileName ( pathFormat , @event . Timestamp , "yyyyMMdd ") ;
283
415
Assert . True ( System . IO . File . Exists ( expected ) ) ;
284
416
285
417
verified . Add ( expected ) ;
@@ -292,4 +424,9 @@ static void TestRollingEventSequence(
292
424
Directory . Delete ( folder , true ) ;
293
425
}
294
426
}
427
+
428
+ static string ExpectedFileName ( string fileName , DateTimeOffset timestamp , string pattern )
429
+ {
430
+ return fileName . Replace ( ".txt" , timestamp . ToString ( pattern ) + ".txt" ) ;
431
+ }
295
432
}
0 commit comments