Skip to content

Commit 9a0257e

Browse files
authored
Merge pull request #107 from nogard111/OnFileRemovingHook
Add OnFileRemoving life cycle hook #106
2 parents 9f8bfc3 + f6d1cff commit 9a0257e

File tree

4 files changed

+67
-1
lines changed

4 files changed

+67
-1
lines changed

src/Serilog.Sinks.File/Sinks/File/FileLifecycleHooks.cs

+8
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ namespace Serilog.Sinks.File
1919
{
2020
/// <summary>
2121
/// Enables hooking into log file lifecycle events.
22+
/// Hooks run synchronously and therefore may affect responsiveness of the application if long operations are performed.
2223
/// </summary>
2324
public abstract class FileLifecycleHooks
2425
{
@@ -35,5 +36,12 @@ public abstract class FileLifecycleHooks
3536
/// <param name="encoding">The encoding to use when reading/writing to the stream.</param>
3637
/// <returns>The <see cref="Stream"/> Serilog should use when writing events to the log file.</returns>
3738
public virtual Stream OnFileOpened(Stream underlyingStream, Encoding encoding) => underlyingStream;
39+
40+
/// <summary>
41+
/// Called before an obsolete (rolling) log file is deleted.
42+
/// This can be used to copy old logs to an archive location or send to a backup server.
43+
/// </summary>
44+
/// <param name="path">The full path to the file being deleted.</param>
45+
public virtual void OnFileDeleting(string path) {}
3846
}
3947
}

src/Serilog.Sinks.File/Sinks/File/RollingFileSink.cs

+2-1
Original file line numberDiff line numberDiff line change
@@ -199,11 +199,12 @@ void ApplyRetentionPolicy(string currentFilePath)
199199
var fullPath = Path.Combine(_roller.LogFileDirectory, obsolete);
200200
try
201201
{
202+
_hooks?.OnFileDeleting(fullPath);
202203
System.IO.File.Delete(fullPath);
203204
}
204205
catch (Exception ex)
205206
{
206-
SelfLog.WriteLine("Error {0} while removing obsolete log file {1}", ex, fullPath);
207+
SelfLog.WriteLine("Error {0} while processing obsolete log file {1}", ex, fullPath);
207208
}
208209
}
209210
}

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

+22
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,28 @@ public void WhenRetentionCountIsSetOldFilesAreDeleted()
7171
});
7272
}
7373

74+
[Fact]
75+
public void WhenRetentionCountAndArchivingHookIsSetOldFilesAreCopiedAndOriginalDeleted()
76+
{
77+
const string archiveDirectory = "OldLogs";
78+
LogEvent e1 = Some.InformationEvent(),
79+
e2 = Some.InformationEvent(e1.Timestamp.AddDays(1)),
80+
e3 = Some.InformationEvent(e2.Timestamp.AddDays(5));
81+
82+
TestRollingEventSequence(
83+
(pf, wt) => wt.File(pf, retainedFileCountLimit: 2, rollingInterval: RollingInterval.Day, hooks: new ArchiveOldLogsHook(archiveDirectory)),
84+
new[] {e1, e2, e3},
85+
files =>
86+
{
87+
Assert.Equal(3, files.Count);
88+
Assert.True(!System.IO.File.Exists(files[0]));
89+
Assert.True(System.IO.File.Exists(files[1]));
90+
Assert.True(System.IO.File.Exists(files[2]));
91+
92+
Assert.True(System.IO.File.Exists(ArchiveOldLogsHook.AddTopDirectory(files[0], archiveDirectory)));
93+
});
94+
}
95+
7496
[Fact]
7597
public void WhenSizeLimitIsBreachedNewFilesCreated()
7698
{
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
using System;
2+
using System.IO;
3+
using System.Text;
4+
5+
namespace Serilog.Sinks.File.Tests.Support
6+
{
7+
internal class ArchiveOldLogsHook : FileLifecycleHooks
8+
{
9+
private readonly string _relativeArchiveDir;
10+
11+
public ArchiveOldLogsHook(string relativeArchiveDir)
12+
{
13+
_relativeArchiveDir = relativeArchiveDir;
14+
}
15+
16+
public override void OnFileDeleting(string path)
17+
{
18+
base.OnFileDeleting(path);
19+
var newFile = AddTopDirectory(path, _relativeArchiveDir, true);
20+
System.IO.File.Copy(path, newFile, false);
21+
}
22+
23+
public static string AddTopDirectory(string path, string directoryToAdd, bool createOnNonExist = false)
24+
{
25+
string file = Path.GetFileName(path);
26+
string directory = Path.Combine(Path.GetDirectoryName(path) ?? throw new InvalidOperationException(), directoryToAdd);
27+
28+
if (createOnNonExist && !Directory.Exists(directory))
29+
{
30+
Directory.CreateDirectory(directory);
31+
}
32+
return Path.Combine(directory, file);
33+
}
34+
}
35+
}

0 commit comments

Comments
 (0)