-
Notifications
You must be signed in to change notification settings - Fork 125
Feature/initial attempt #72
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
f17cb52
fbeb47b
28a52d6
360de64
11f9662
834b1b8
6a2884f
1027296
1e27cd8
62aca49
814e17f
b2f32cf
67c1153
d58afda
99f27a1
9493330
c259969
636b9f2
fddd376
558fb65
64411b7
91053dc
0be2657
14f3440
2d83c64
7489f97
9a06121
4b5ee31
a76b65b
4ccea1d
1325fa3
07b897a
3b90756
5049097
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,35 @@ | ||
// Copyright 2017 Serilog Contributors | ||
// | ||
// Licensed under the Apache License, Version 2.0 (the "License"); | ||
// you may not use this file except in compliance with the License. | ||
// You may obtain a copy of the License at | ||
// | ||
// http://www.apache.org/licenses/LICENSE-2.0 | ||
// | ||
// Unless required by applicable law or agreed to in writing, software | ||
// distributed under the License is distributed on an "AS IS" BASIS, | ||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
// See the License for the specific language governing permissions and | ||
// limitations under the License. | ||
|
||
namespace Serilog | ||
{ | ||
/// <summary> | ||
/// Specifies the compression type | ||
/// </summary> | ||
public enum CompressionType | ||
{ | ||
/// <summary> | ||
/// Zip compression | ||
/// </summary> | ||
Zip, | ||
/// <summary> | ||
/// RGZip compression | ||
/// </summary> | ||
GZip, | ||
/// <summary> | ||
/// No compression | ||
/// </summary> | ||
None, | ||
}; | ||
} |
Large diffs are not rendered by default.
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -35,6 +35,7 @@ sealed class RollingFileSink : ILogEventSink, IFlushableFileSink, IDisposable | |
readonly bool _buffered; | ||
readonly bool _shared; | ||
readonly bool _rollOnFileSizeLimit; | ||
readonly CompressionType _compressionType; | ||
|
||
readonly object _syncRoot = new object(); | ||
bool _isDisposed; | ||
|
@@ -50,13 +51,16 @@ public RollingFileSink(string path, | |
bool buffered, | ||
bool shared, | ||
RollingInterval rollingInterval, | ||
bool rollOnFileSizeLimit) | ||
bool rollOnFileSizeLimit, | ||
CompressionType compressionType = CompressionType.None | ||
) | ||
{ | ||
if (path == null) throw new ArgumentNullException(nameof(path)); | ||
if (fileSizeLimitBytes.HasValue && fileSizeLimitBytes < 0) throw new ArgumentException("Negative value provided; file size limit must be non-negative"); | ||
if (retainedFileCountLimit.HasValue && retainedFileCountLimit < 1) throw new ArgumentException("Zero or negative value provided; retained file count limit must be at least 1"); | ||
|
||
_roller = new PathRoller(path, rollingInterval); | ||
_compressionType = compressionType; | ||
_textFormatter = textFormatter; | ||
_fileSizeLimitBytes = fileSizeLimitBytes; | ||
_retainedFileCountLimit = retainedFileCountLimit; | ||
|
@@ -66,6 +70,79 @@ public RollingFileSink(string path, | |
_rollOnFileSizeLimit = rollOnFileSizeLimit; | ||
} | ||
|
||
/// <summary> | ||
/// Chooses which compression algorithm to run on the log file passed in within the given directory. | ||
/// </summary> | ||
/// <param name="logFile"> The log file to be compressed </param> | ||
/// <param name="logDirectory"> The directory that holds logFile </param> | ||
/// <param name="compressionType"> The compression algorithm to be used. Is of type CompressionType </param> | ||
public void Compress(string logFile, string logDirectory, CompressionType compressionType) | ||
{ | ||
switch (compressionType) | ||
{ | ||
case CompressionType.Zip: | ||
ZipCompress(logFile, logDirectory); | ||
break; | ||
case CompressionType.GZip: | ||
GZipCompress(logFile, logDirectory); | ||
break; | ||
default: | ||
throw new Exception("Compression type entered incorrectly or not supported.\n"); | ||
} | ||
} | ||
|
||
/// <summary> | ||
/// Uses Zip compression to compress prevLog into a new, zipped directory. | ||
/// The Zip algorithm is from System.IO.Compression | ||
/// </summary> | ||
/// <param name="logFile"> The log file to be compressed </param> | ||
/// <param name="logDirectory"> The directory that holds logFile </param> | ||
public void ZipCompress(string logFile, string logDirectory) | ||
{ | ||
var readDirectory = Path.Combine(logDirectory, "new_dir"); | ||
Directory.CreateDirectory(readDirectory); | ||
System.IO.File.Move( | ||
Path.Combine(logDirectory, logFile), Path.Combine(readDirectory, logFile) | ||
); | ||
|
||
var zipName = Path.GetFileNameWithoutExtension(logFile); | ||
var zip_path = Path.Combine(logDirectory, $"{zipName}.zip"); | ||
System.IO.Compression.ZipFile.CreateFromDirectory(readDirectory, zip_path); | ||
|
||
Directory.Delete(readDirectory, true); | ||
} | ||
|
||
/// <summary> | ||
/// Uses GZip compression algorithm to compress logFile into a .gzip file | ||
/// The GZip algorithm is from System.IO.Compression | ||
/// </summary> | ||
/// <param name="logFile"> The log file to be compressed </param> | ||
/// <param name="logDirectory"> The directory that holds logFile </param> | ||
public void GZipCompress(string logFile, string logDirectory) | ||
{ | ||
|
||
var inFile = Path.Combine(logDirectory, logFile); | ||
|
||
var logName = Path.GetFileNameWithoutExtension(logFile); | ||
var outFile = Path.Combine(logDirectory, $"{logName}.gz"); | ||
|
||
using (var outputStream = System.IO.File.Create(outFile)) | ||
{ | ||
using (var inputStream = System.IO.File.OpenRead(inFile)) | ||
{ | ||
using (var gzipStream = new System.IO.Compression.GZipStream(outputStream, System.IO.Compression.CompressionMode.Compress)) | ||
{ | ||
int bufferSize = 1024; | ||
var buffer = new byte[bufferSize]; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I don't think |
||
|
||
inputStream.CopyTo(gzipStream, bufferSize); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Such a small buffer size is going to result in sub-par compression ratios - what's the purpose of overriding the default buffer size here? (I guess the default is 64K?) |
||
} | ||
} | ||
} | ||
|
||
System.IO.File.Delete(inFile); | ||
} | ||
|
||
public void Emit(LogEvent logEvent) | ||
{ | ||
if (logEvent == null) throw new ArgumentNullException(nameof(logEvent)); | ||
|
@@ -101,7 +178,31 @@ void AlignCurrentFileTo(DateTime now, bool nextSequence = false) | |
minSequence = _currentFileSequence.Value + 1; | ||
} | ||
|
||
var prevLog = Directory.GetFiles(_roller.LogFileDirectory, _roller.DirectorySearchPattern) | ||
.Select(Path.GetFileName).LastOrDefault(); | ||
var logDirectory = _roller.LogFileDirectory; | ||
|
||
CloseFile(); | ||
|
||
if (_compressionType != CompressionType.None) | ||
{ | ||
Compress(prevLog, logDirectory, _compressionType); | ||
|
||
var directoryFiles = Directory.GetFiles(_roller.LogFileDirectory, _roller.DirectorySearchPattern); | ||
|
||
foreach (var directoryFile in directoryFiles) | ||
{ | ||
var directoryFileName = Path.GetFileName(directoryFile); | ||
|
||
// Not sure if we can assume log files will always be .txt? | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Nope 😄 The filename (and extension) are configurable by the user |
||
if (System.IO.Path.GetExtension(directoryFileName) == ".txt") | ||
{ | ||
Compress(directoryFileName, logDirectory, _compressionType); | ||
} | ||
} | ||
|
||
} | ||
|
||
OpenFile(now, minSequence); | ||
} | ||
} | ||
|
@@ -110,8 +211,6 @@ void OpenFile(DateTime now, int? minSequence = null) | |
{ | ||
var currentCheckpoint = _roller.GetCurrentCheckpoint(now); | ||
|
||
// We only try periodically because repeated failures | ||
// to open log files REALLY slow an app down. | ||
_nextCheckpoint = _roller.GetNextCheckpoint(now) ?? now.AddMinutes(30); | ||
|
||
var existingFiles = Enumerable.Empty<string>(); | ||
|
@@ -213,6 +312,8 @@ public void Dispose() | |
|
||
void CloseFile() | ||
{ | ||
|
||
|
||
if (_currentFile != null) | ||
{ | ||
(_currentFile as IDisposable)?.Dispose(); | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,103 @@ | ||
using System.Linq; | ||
using Xunit; | ||
using Serilog.Sinks.File.Tests.Support; | ||
using System.IO; | ||
|
||
namespace Serilog.Sinks.File.Tests | ||
{ | ||
public class RollingCompressionTests | ||
{ | ||
[Fact] | ||
public void GZipCompressionCorrect() | ||
{ | ||
var fileName = Some.String() + "log.txt"; | ||
var temp = Some.TempFolderPath(); | ||
var pathFormat = Path.Combine(temp, fileName); | ||
|
||
using (var log = new LoggerConfiguration() | ||
.WriteTo.File(pathFormat, | ||
rollOnFileSizeLimit: true, fileSizeLimitBytes: 1, | ||
compressionType: CompressionType.GZip) | ||
.CreateLogger()) | ||
{ | ||
|
||
log.Information("test"); | ||
log.Information("test"); | ||
|
||
string[] compressedFiles = Directory.EnumerateFiles(temp).Where(name => name.Contains("-GZip")).ToArray(); | ||
|
||
foreach(var compressedFile in compressedFiles) | ||
{ | ||
using (FileStream compressedStream = new FileStream(compressedFile, FileMode.Open)) | ||
{ | ||
byte[] compressedBytes = new byte[2]; | ||
|
||
compressedStream.Read(compressedBytes, 0, compressedBytes.Length); | ||
|
||
// Magic Bytes for Zip | ||
Assert.Equal(compressedBytes[0], 0x1f); | ||
Assert.Equal(compressedBytes[1], 0x8b); | ||
// fileName is original .txt file name | ||
Assert.False(compressedFiles.Contains(fileName)); | ||
} | ||
} | ||
|
||
log.Dispose(); | ||
|
||
foreach (var loggedFile in Directory.GetFiles(temp)) | ||
{ | ||
System.IO.File.Delete(loggedFile); | ||
} | ||
Directory.Delete(temp); | ||
} | ||
|
||
} | ||
|
||
[Fact] | ||
public void ZipCompressionCorrect() | ||
{ | ||
|
||
var fileName = Some.String() + "log.txt"; | ||
var temp = Some.TempFolderPath(); | ||
var pathFormat = Path.Combine(temp, fileName); | ||
|
||
using (var log = new LoggerConfiguration() | ||
.WriteTo.File(pathFormat, | ||
rollOnFileSizeLimit: true, fileSizeLimitBytes: 1, | ||
compressionType: CompressionType.Zip) | ||
.CreateLogger()) | ||
{ | ||
|
||
log.Information("test"); | ||
log.Information("test"); | ||
|
||
string[] compressedFiles = Directory.EnumerateFiles(temp).Where(name => name.Contains("-Zip")).ToArray(); | ||
|
||
foreach (var compressedFile in compressedFiles) | ||
{ | ||
using (FileStream compressedStream = new FileStream(compressedFile, FileMode.Open)) | ||
{ | ||
|
||
byte[] compressedBytes = new byte[2]; | ||
|
||
compressedStream.Read(compressedBytes, 0, compressedBytes.Length); | ||
|
||
// Magic Bytes for Zip | ||
Assert.Equal(compressedBytes[0], 0x50); | ||
Assert.Equal(compressedBytes[1], 0x4B); | ||
// fileName is original .txt file name | ||
Assert.False(compressedFiles.Contains(fileName)); | ||
} | ||
} | ||
|
||
log.Dispose(); | ||
|
||
foreach (var loggedFile in Directory.GetFiles(temp)) | ||
{ | ||
System.IO.File.Delete(loggedFile); | ||
} | ||
Directory.Delete(temp); | ||
} | ||
} | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why
public
?