4
4
using Serilog . Sinks . File . Tests . Support ;
5
5
using Serilog . Configuration ;
6
6
using Serilog . Core ;
7
+ using Serilog . Debugging ;
8
+ using Xunit . Abstractions ;
7
9
8
10
namespace Serilog . Sinks . File . Tests ;
9
11
10
- public class RollingFileSinkTests
12
+ public class RollingFileSinkTests : IDisposable
11
13
{
14
+ private readonly ITestOutputHelper _testOutputHelper ;
15
+
16
+ public RollingFileSinkTests ( ITestOutputHelper testOutputHelper )
17
+ {
18
+ _testOutputHelper = testOutputHelper ;
19
+ }
20
+
21
+ public void Dispose ( )
22
+ {
23
+ SelfLog . Disable ( ) ;
24
+ }
25
+
12
26
[ Fact ]
13
27
public void LogEventsAreEmittedToTheFileNamedAccordingToTheEventTimestamp ( )
14
28
{
@@ -145,6 +159,116 @@ public void WhenRetentionCountAndArchivingHookIsSetOldFilesAreCopiedAndOriginalD
145
159
} ) ;
146
160
}
147
161
162
+ [ Fact ]
163
+ public void WhenFirstOpeningFailedWithLockRetryDelayedUntilNextCheckpoint ( )
164
+ {
165
+ var fileName = Some . String ( ) + ".txt" ;
166
+ using var temp = new TempFolder ( ) ;
167
+ using var log = new LoggerConfiguration ( )
168
+ . WriteTo . File ( Path . Combine ( temp . Path , fileName ) , rollOnFileSizeLimit : true , fileSizeLimitBytes : 1 , rollingInterval : RollingInterval . Minute , hooks : new FailOpeningHook ( true , 2 , 3 , 4 ) )
169
+ . CreateLogger ( ) ;
170
+ LogEvent e1 = Some . InformationEvent ( new DateTime ( 2012 , 10 , 28 ) ) ,
171
+ e2 = Some . InformationEvent ( e1 . Timestamp . AddSeconds ( 1 ) ) ,
172
+ e3 = Some . InformationEvent ( e1 . Timestamp . AddMinutes ( 5 ) ) ,
173
+ e4 = Some . InformationEvent ( e1 . Timestamp . AddMinutes ( 31 ) ) ;
174
+ LogEvent [ ] logEvents = new [ ] { e1 , e2 , e3 , e4 } ;
175
+
176
+ foreach ( var logEvent in logEvents )
177
+ {
178
+ Clock . SetTestDateTimeNow ( logEvent . Timestamp . DateTime ) ;
179
+ log . Write ( logEvent ) ;
180
+ }
181
+
182
+ var files = Directory . GetFiles ( temp . Path )
183
+ . OrderBy ( p => p , StringComparer . OrdinalIgnoreCase )
184
+ . ToArray ( ) ;
185
+ var pattern = "yyyyMMddHHmm" ;
186
+
187
+ Assert . Equal ( 6 , files . Length ) ;
188
+ // Successful write of e1:
189
+ Assert . True ( files [ 0 ] . EndsWith ( ExpectedFileName ( fileName , e1 . Timestamp , pattern ) ) , files [ 0 ] ) ;
190
+ // Failing writes for e2, will be dropped and logged to SelfLog:
191
+ Assert . True ( files [ 1 ] . EndsWith ( "_001.txt" ) , files [ 1 ] ) ;
192
+ Assert . True ( files [ 2 ] . EndsWith ( "_002.txt" ) , files [ 2 ] ) ;
193
+ Assert . True ( files [ 3 ] . EndsWith ( "_003.txt" ) , files [ 3 ] ) ;
194
+ // Successful write of e3:
195
+ Assert . True ( files [ 4 ] . EndsWith ( ExpectedFileName ( fileName , e3 . Timestamp , pattern ) ) , files [ 4 ] ) ;
196
+ // Successful write of e4:
197
+ Assert . True ( files [ 5 ] . EndsWith ( ExpectedFileName ( fileName , e4 . Timestamp , pattern ) ) , files [ 5 ] ) ;
198
+ }
199
+
200
+ [ Fact ]
201
+ public void WhenFirstOpeningFailedWithLockRetryDelayed30Minutes ( )
202
+ {
203
+ var fileName = Some . String ( ) + ".txt" ;
204
+ using var temp = new TempFolder ( ) ;
205
+ using var log = new LoggerConfiguration ( )
206
+ . WriteTo . File ( Path . Combine ( temp . Path , fileName ) , rollOnFileSizeLimit : true , fileSizeLimitBytes : 1 , rollingInterval : RollingInterval . Hour , hooks : new FailOpeningHook ( true , 2 , 3 , 4 ) )
207
+ . CreateLogger ( ) ;
208
+ LogEvent e1 = Some . InformationEvent ( new DateTime ( 2012 , 10 , 28 ) ) ,
209
+ e2 = Some . InformationEvent ( e1 . Timestamp . AddSeconds ( 1 ) ) ,
210
+ e3 = Some . InformationEvent ( e1 . Timestamp . AddMinutes ( 5 ) ) ,
211
+ e4 = Some . InformationEvent ( e1 . Timestamp . AddMinutes ( 31 ) ) ;
212
+ LogEvent [ ] logEvents = new [ ] { e1 , e2 , e3 , e4 } ;
213
+
214
+ SelfLog . Enable ( _testOutputHelper . WriteLine ) ;
215
+ foreach ( var logEvent in logEvents )
216
+ {
217
+ Clock . SetTestDateTimeNow ( logEvent . Timestamp . DateTime ) ;
218
+ log . Write ( logEvent ) ;
219
+ }
220
+
221
+ var files = Directory . GetFiles ( temp . Path )
222
+ . OrderBy ( p => p , StringComparer . OrdinalIgnoreCase )
223
+ . ToArray ( ) ;
224
+ var pattern = "yyyyMMddHH" ;
225
+
226
+ Assert . Equal ( 4 , 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
+ /* 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! */
233
+ // Successful write of e4, the third file will be retried after failing initially:
234
+ Assert . True ( files [ 3 ] . EndsWith ( "_003.txt" ) , files [ 3 ] ) ;
235
+ }
236
+
237
+ [ Fact ]
238
+ public void WhenFirstOpeningFailedWithoutLockRetryDelayed30Minutes ( )
239
+ {
240
+ var fileName = Some . String ( ) + ".txt" ;
241
+ using var temp = new TempFolder ( ) ;
242
+ using var log = new LoggerConfiguration ( )
243
+ . WriteTo . File ( Path . Combine ( temp . Path , fileName ) , rollOnFileSizeLimit : true , fileSizeLimitBytes : 1 , rollingInterval : RollingInterval . Hour , hooks : new FailOpeningHook ( false , 2 ) )
244
+ . CreateLogger ( ) ;
245
+ LogEvent e1 = Some . InformationEvent ( new DateTime ( 2012 , 10 , 28 ) ) ,
246
+ e2 = Some . InformationEvent ( e1 . Timestamp . AddSeconds ( 1 ) ) ,
247
+ e3 = Some . InformationEvent ( e1 . Timestamp . AddMinutes ( 5 ) ) ,
248
+ e4 = Some . InformationEvent ( e1 . Timestamp . AddMinutes ( 31 ) ) ;
249
+ LogEvent [ ] logEvents = new [ ] { e1 , e2 , e3 , e4 } ;
250
+
251
+ SelfLog . Enable ( _testOutputHelper . WriteLine ) ;
252
+ foreach ( var logEvent in logEvents )
253
+ {
254
+ Clock . SetTestDateTimeNow ( logEvent . Timestamp . DateTime ) ;
255
+ log . Write ( logEvent ) ;
256
+ }
257
+
258
+ var files = Directory . GetFiles ( temp . Path )
259
+ . OrderBy ( p => p , StringComparer . OrdinalIgnoreCase )
260
+ . ToArray ( ) ;
261
+ var pattern = "yyyyMMddHH" ;
262
+
263
+ Assert . Equal ( 2 , files . Length ) ;
264
+ // Successful write of e1:
265
+ Assert . True ( files [ 0 ] . EndsWith ( ExpectedFileName ( fileName , e1 . Timestamp , pattern ) ) , files [ 0 ] ) ;
266
+ /* Failing writes for e2, will be dropped and logged to SelfLog; on non-lock it will try it once */
267
+ /* 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! */
268
+ // Successful write of e4, the file will be retried after failing initially:
269
+ Assert . True ( files [ 1 ] . EndsWith ( "_001.txt" ) , files [ 1 ] ) ;
270
+ }
271
+
148
272
[ Fact ]
149
273
public void WhenSizeLimitIsBreachedNewFilesCreated ( )
150
274
{
@@ -279,7 +403,7 @@ static void TestRollingEventSequence(
279
403
Clock . SetTestDateTimeNow ( @event . Timestamp . DateTime ) ;
280
404
log . Write ( @event ) ;
281
405
282
- var expected = pathFormat . Replace ( ".txt" , @event . Timestamp . ToString ( "yyyyMMdd" ) + ".txt ") ;
406
+ var expected = ExpectedFileName ( pathFormat , @event . Timestamp , "yyyyMMdd ") ;
283
407
Assert . True ( System . IO . File . Exists ( expected ) ) ;
284
408
285
409
verified . Add ( expected ) ;
@@ -292,4 +416,9 @@ static void TestRollingEventSequence(
292
416
Directory . Delete ( folder , true ) ;
293
417
}
294
418
}
419
+
420
+ static string ExpectedFileName ( string fileName , DateTimeOffset timestamp , string pattern )
421
+ {
422
+ return fileName . Replace ( ".txt" , timestamp . ToString ( pattern ) + ".txt" ) ;
423
+ }
295
424
}
0 commit comments