Skip to content

Commit a3cd930

Browse files
committed
Fix issue with FileSink not closing the stream on hook errors
1 parent 7c44444 commit a3cd930

File tree

3 files changed

+37
-42
lines changed

3 files changed

+37
-42
lines changed

src/Serilog.Sinks.File/Sinks/File/FileSink.cs

+10-2
Original file line numberDiff line numberDiff line change
@@ -91,8 +91,16 @@ internal FileSink(
9191

9292
if (hooks != null)
9393
{
94-
outputStream = hooks.OnFileOpened(path, outputStream, encoding) ??
95-
throw new InvalidOperationException($"The file lifecycle hook `{nameof(FileLifecycleHooks.OnFileOpened)}(...)` returned `null`.");
94+
try
95+
{
96+
outputStream = hooks.OnFileOpened(path, outputStream, encoding) ??
97+
throw new InvalidOperationException($"The file lifecycle hook `{nameof(FileLifecycleHooks.OnFileOpened)}(...)` returned `null`.");
98+
}
99+
catch
100+
{
101+
outputStream?.Dispose();
102+
throw;
103+
}
96104
}
97105

98106
_output = new StreamWriter(outputStream, encoding);

test/Serilog.Sinks.File.Tests/RollingFileSinkTests.cs

+24-37
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
using Serilog.Sinks.File.Tests.Support;
55
using Serilog.Configuration;
66
using Serilog.Core;
7+
using Serilog.Debugging;
78
using Xunit.Abstractions;
89

910
namespace Serilog.Sinks.File.Tests;
@@ -196,85 +197,71 @@ public void WhenFirstOpeningFailedWithLockRetryDelayed30Minutes()
196197
{
197198
var fileName = Some.String() + ".txt";
198199
using var temp = new TempFolder();
200+
using var log = new LoggerConfiguration()
201+
.WriteTo.File(Path.Combine(temp.Path, fileName), rollOnFileSizeLimit: true, fileSizeLimitBytes: 1, rollingInterval: RollingInterval.Hour, hooks: new FailOpeningHook(true, 2, 3, 4))
202+
.CreateLogger();
199203
LogEvent e1 = Some.InformationEvent(new DateTime(2012, 10, 28)),
200204
e2 = Some.InformationEvent(e1.Timestamp.AddSeconds(1)),
201205
e3 = Some.InformationEvent(e1.Timestamp.AddMinutes(5)),
202206
e4 = Some.InformationEvent(e1.Timestamp.AddMinutes(31));
203207
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())
208+
209+
SelfLog.Enable(_testOutputHelper.WriteLine);
210+
foreach (var logEvent in logEvents)
209211
{
210-
foreach (var logEvent in logEvents)
211-
{
212-
Clock.SetTestDateTimeNow(logEvent.Timestamp.DateTime);
213-
log.Write(logEvent);
214-
}
212+
Clock.SetTestDateTimeNow(logEvent.Timestamp.DateTime);
213+
log.Write(logEvent);
215214
}
216215

217216
var files = Directory.GetFiles(temp.Path)
218217
.OrderBy(p => p, StringComparer.OrdinalIgnoreCase)
219218
.ToArray();
220219
var pattern = "yyyyMMddHH";
221220

222-
foreach (var file in files)
223-
{
224-
_testOutputHelper.WriteLine(file + ": " + System.IO.File.ReadAllText(file));
225-
}
226-
Assert.Equal(5, files.Length);
221+
Assert.Equal(4, files.Length);
227222
// Successful write of e1:
228223
Assert.True(files[0].EndsWith(ExpectedFileName(fileName, e1.Timestamp, pattern)), files[0]);
229224
// Failing writes for e2, will be dropped and logged to SelfLog; on lock it will try it three times:
230225
Assert.True(files[1].EndsWith("_001.txt"), files[1]);
231226
Assert.True(files[2].EndsWith("_002.txt"), files[2]);
232-
Assert.True(files[3].EndsWith("_003.txt"), files[3]);
233227
/* 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]);
228+
// Successful write of e4, the third file will be retried after failing initially:
229+
Assert.True(files[3].EndsWith("_003.txt"), files[3]);
236230
}
237231

238232
[Fact]
239233
public void WhenFirstOpeningFailedWithoutLockRetryDelayed30Minutes()
240234
{
241235
var fileName = Some.String() + ".txt";
242236
using var temp = new TempFolder();
237+
using var log = new LoggerConfiguration()
238+
.WriteTo.File(Path.Combine(temp.Path, fileName), rollOnFileSizeLimit: true, fileSizeLimitBytes: 1, rollingInterval: RollingInterval.Hour, hooks: new FailOpeningHook(false, 2))
239+
.CreateLogger();
243240
LogEvent e1 = Some.InformationEvent(new DateTime(2012, 10, 28)),
244241
e2 = Some.InformationEvent(e1.Timestamp.AddSeconds(1)),
245242
e3 = Some.InformationEvent(e1.Timestamp.AddMinutes(5)),
246243
e4 = Some.InformationEvent(e1.Timestamp.AddMinutes(31));
247244
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())
245+
246+
SelfLog.Enable(_testOutputHelper.WriteLine);
247+
foreach (var logEvent in logEvents)
253248
{
254-
foreach (var logEvent in logEvents)
255-
{
256-
Clock.SetTestDateTimeNow(logEvent.Timestamp.DateTime);
257-
log.Write(logEvent);
258-
}
249+
Clock.SetTestDateTimeNow(logEvent.Timestamp.DateTime);
250+
log.Write(logEvent);
259251
}
260252

261253
var files = Directory.GetFiles(temp.Path)
262254
.OrderBy(p => p, StringComparer.OrdinalIgnoreCase)
263255
.ToArray();
264256
var pattern = "yyyyMMddHH";
265257

266-
foreach (var file in files)
267-
{
268-
_testOutputHelper.WriteLine(file + ": " + System.IO.File.ReadAllText(file));
269-
}
270-
Assert.Equal(3, files.Length);
258+
Assert.Equal(2, files.Length);
271259
// Successful write of e1:
272260
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]);
261+
/* Failing writes for e2, will be dropped and logged to SelfLog; on non-lock it will try it once */
275262
/* 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]);
263+
// Successful write of e4, the file will be retried after failing initially:
264+
Assert.True(files[1].EndsWith("_001.txt"), files[1]);
278265
}
279266

280267
[Fact]

test/Serilog.Sinks.File.Tests/Support/FailOpeningHook.cs

+3-3
Original file line numberDiff line numberDiff line change
@@ -19,18 +19,18 @@ public FailOpeningHook(bool asFileLocked, params int[] failingInstances)
1919
_failingInstances = failingInstances;
2020
}
2121

22-
public override Stream OnFileOpened(string path, Stream _, Encoding __)
22+
public override Stream OnFileOpened(string path, Stream stream, Encoding encoding)
2323
{
2424
TimesOpened++;
2525
if (_failingInstances.Contains(TimesOpened))
2626
{
2727
var message = $"We failed on try {TimesOpened}, the file was locked: {_asFileLocked}";
28-
28+
2929
throw _asFileLocked
3030
? new IOException(message)
3131
: new Exception(message);
3232
}
3333

34-
return base.OnFileOpened(path, _, __);
34+
return base.OnFileOpened(path, stream, encoding);
3535
}
3636
}

0 commit comments

Comments
 (0)