mirror of https://github.com/winsw/winsw
Backport redirection updates (#770)
parent
c49d50381e
commit
ad5f78b3c5
|
@ -47,12 +47,11 @@ namespace WinSW
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Convenience method to copy stuff from StreamReader to StreamWriter
|
/// Convenience method to copy stuff from StreamReader to StreamWriter
|
||||||
/// </summary>
|
/// </summary>
|
||||||
protected void CopyStream(StreamReader reader, StreamWriter writer)
|
protected void CopyStream(Stream reader, Stream writer)
|
||||||
{
|
{
|
||||||
string? line;
|
var copy = new StreamCopyOperation(reader, writer);
|
||||||
while ((line = reader.ReadLine()) != null)
|
while (copy.CopyLine() != 0)
|
||||||
{
|
{
|
||||||
writer.WriteLine(line);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
reader.Dispose();
|
reader.Dispose();
|
||||||
|
@ -107,8 +106,6 @@ namespace WinSW
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected StreamWriter CreateWriter(FileStream stream) => new(stream) { AutoFlush = true };
|
|
||||||
|
|
||||||
protected abstract void LogOutput(StreamReader outputReader);
|
protected abstract void LogOutput(StreamReader outputReader);
|
||||||
|
|
||||||
protected abstract void LogError(StreamReader errorReader);
|
protected abstract void LogError(StreamReader errorReader);
|
||||||
|
@ -132,12 +129,12 @@ namespace WinSW
|
||||||
|
|
||||||
protected override void LogOutput(StreamReader outputReader)
|
protected override void LogOutput(StreamReader outputReader)
|
||||||
{
|
{
|
||||||
new Thread(() => this.CopyStream(outputReader, this.CreateWriter(new FileStream(this.OutputLogFileName, this.FileMode)))).Start();
|
new Thread(() => this.CopyStream(outputReader.BaseStream, new FileStream(this.OutputLogFileName, this.FileMode))).Start();
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void LogError(StreamReader errorReader)
|
protected override void LogError(StreamReader errorReader)
|
||||||
{
|
{
|
||||||
new Thread(() => this.CopyStream(errorReader, this.CreateWriter(new FileStream(this.ErrorLogFileName, this.FileMode)))).Start();
|
new Thread(() => this.CopyStream(errorReader.BaseStream, new FileStream(this.ErrorLogFileName, this.FileMode))).Start();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -203,17 +200,15 @@ namespace WinSW
|
||||||
var periodicRollingCalendar = new PeriodicRollingCalendar(this.Pattern, this.Period);
|
var periodicRollingCalendar = new PeriodicRollingCalendar(this.Pattern, this.Period);
|
||||||
periodicRollingCalendar.Init();
|
periodicRollingCalendar.Init();
|
||||||
|
|
||||||
var writer = this.CreateWriter(new FileStream(this.BaseLogFileName + "_" + periodicRollingCalendar.Format + ext, FileMode.Append));
|
var writer = new FileStream(this.BaseLogFileName + "_" + periodicRollingCalendar.Format + ext, FileMode.Append);
|
||||||
string? line;
|
var copy = new StreamCopyOperation(reader.BaseStream, writer);
|
||||||
while ((line = reader.ReadLine()) != null)
|
while (copy.CopyLine() != 0)
|
||||||
{
|
{
|
||||||
if (periodicRollingCalendar.ShouldRoll)
|
if (periodicRollingCalendar.ShouldRoll)
|
||||||
{
|
{
|
||||||
writer.Dispose();
|
writer.Dispose();
|
||||||
writer = this.CreateWriter(new FileStream(this.BaseLogFileName + "_" + periodicRollingCalendar.Format + ext, FileMode.Create));
|
copy.Writer = writer = new FileStream(this.BaseLogFileName + "_" + periodicRollingCalendar.Format + ext, FileMode.Create);
|
||||||
}
|
}
|
||||||
|
|
||||||
writer.WriteLine(line);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
reader.Dispose();
|
reader.Dispose();
|
||||||
|
@ -228,14 +223,14 @@ namespace WinSW
|
||||||
public static int DefaultSizeThreshold = 10 * BytesPerMB; // roll every 10MB.
|
public static int DefaultSizeThreshold = 10 * BytesPerMB; // roll every 10MB.
|
||||||
public static int DefaultFilesToKeep = 8;
|
public static int DefaultFilesToKeep = 8;
|
||||||
|
|
||||||
public int SizeTheshold { get; private set; }
|
public int SizeThreshold { get; private set; }
|
||||||
|
|
||||||
public int FilesToKeep { get; private set; }
|
public int FilesToKeep { get; private set; }
|
||||||
|
|
||||||
public SizeBasedRollingLogAppender(string logDirectory, string baseName, bool outFileDisabled, bool errFileDisabled, string outFilePattern, string errFilePattern, int sizeThreshold, int filesToKeep)
|
public SizeBasedRollingLogAppender(string logDirectory, string baseName, bool outFileDisabled, bool errFileDisabled, string outFilePattern, string errFilePattern, int sizeThreshold, int filesToKeep)
|
||||||
: base(logDirectory, baseName, outFileDisabled, errFileDisabled, outFilePattern, errFilePattern)
|
: base(logDirectory, baseName, outFileDisabled, errFileDisabled, outFilePattern, errFilePattern)
|
||||||
{
|
{
|
||||||
this.SizeTheshold = sizeThreshold;
|
this.SizeThreshold = sizeThreshold;
|
||||||
this.FilesToKeep = filesToKeep;
|
this.FilesToKeep = filesToKeep;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -259,20 +254,21 @@ namespace WinSW
|
||||||
/// </summary>
|
/// </summary>
|
||||||
private void CopyStreamWithRotation(StreamReader reader, string ext)
|
private void CopyStreamWithRotation(StreamReader reader, string ext)
|
||||||
{
|
{
|
||||||
var writer = this.CreateWriter(new FileStream(this.BaseLogFileName + ext, FileMode.Append));
|
var writer = new FileStream(this.BaseLogFileName + ext, FileMode.Append);
|
||||||
|
var copy = new StreamCopyOperation(reader.BaseStream, writer);
|
||||||
long fileLength = new FileInfo(this.BaseLogFileName + ext).Length;
|
long fileLength = new FileInfo(this.BaseLogFileName + ext).Length;
|
||||||
|
|
||||||
string? line;
|
int written;
|
||||||
while ((line = reader.ReadLine()) != null)
|
while ((written = copy.CopyLine()) != 0)
|
||||||
{
|
{
|
||||||
int lengthToWrite = Encoding.UTF8.GetByteCount(line) + 2; // CRLF
|
fileLength += written;
|
||||||
if (fileLength + lengthToWrite > this.SizeTheshold)
|
if (fileLength > this.SizeThreshold)
|
||||||
{
|
{
|
||||||
writer.Dispose();
|
writer.Dispose();
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
for (int j = this.FilesToKeep; j >= 1; j--)
|
for (int j = this.FilesToKeep; j >= 2; j--)
|
||||||
{
|
{
|
||||||
string dst = this.BaseLogFileName + "." + (j - 1) + ext;
|
string dst = this.BaseLogFileName + "." + (j - 1) + ext;
|
||||||
string src = this.BaseLogFileName + "." + (j - 2) + ext;
|
string src = this.BaseLogFileName + "." + (j - 2) + ext;
|
||||||
|
@ -296,12 +292,9 @@ namespace WinSW
|
||||||
|
|
||||||
// even if the log rotation fails, create a new one, or else
|
// even if the log rotation fails, create a new one, or else
|
||||||
// we'll infinitely try to roll.
|
// we'll infinitely try to roll.
|
||||||
writer = this.CreateWriter(new FileStream(this.BaseLogFileName + ext, FileMode.Create));
|
copy.Writer = writer = new FileStream(this.BaseLogFileName + ext, FileMode.Create);
|
||||||
fileLength = new FileInfo(this.BaseLogFileName + ext).Length;
|
fileLength = new FileInfo(this.BaseLogFileName + ext).Length;
|
||||||
}
|
}
|
||||||
|
|
||||||
writer.WriteLine(line);
|
|
||||||
fileLength += lengthToWrite;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
reader.Dispose();
|
reader.Dispose();
|
||||||
|
@ -339,7 +332,7 @@ namespace WinSW
|
||||||
{
|
{
|
||||||
public static int BytesPerKB = 1024;
|
public static int BytesPerKB = 1024;
|
||||||
|
|
||||||
public int SizeTheshold { get; private set; }
|
public int SizeThreshold { get; private set; }
|
||||||
|
|
||||||
public string FilePattern { get; private set; }
|
public string FilePattern { get; private set; }
|
||||||
|
|
||||||
|
@ -363,7 +356,7 @@ namespace WinSW
|
||||||
string zipdateformat)
|
string zipdateformat)
|
||||||
: base(logDirectory, baseName, outFileDisabled, errFileDisabled, outFilePattern, errFilePattern)
|
: base(logDirectory, baseName, outFileDisabled, errFileDisabled, outFilePattern, errFilePattern)
|
||||||
{
|
{
|
||||||
this.SizeTheshold = sizeThreshold;
|
this.SizeThreshold = sizeThreshold;
|
||||||
this.FilePattern = filePattern;
|
this.FilePattern = filePattern;
|
||||||
this.AutoRollAtTime = autoRollAtTime;
|
this.AutoRollAtTime = autoRollAtTime;
|
||||||
this.ZipOlderThanNumDays = zipolderthannumdays;
|
this.ZipOlderThanNumDays = zipolderthannumdays;
|
||||||
|
@ -383,13 +376,14 @@ namespace WinSW
|
||||||
private void CopyStreamWithRotation(StreamReader reader, string extension)
|
private void CopyStreamWithRotation(StreamReader reader, string extension)
|
||||||
{
|
{
|
||||||
// lock required as the timer thread and the thread that will write to the stream could try and access the file stream at the same time
|
// lock required as the timer thread and the thread that will write to the stream could try and access the file stream at the same time
|
||||||
object fileLock = new object();
|
object fileLock = new();
|
||||||
|
|
||||||
string baseDirectory = Path.GetDirectoryName(this.BaseLogFileName)!;
|
string baseDirectory = Path.GetDirectoryName(this.BaseLogFileName)!;
|
||||||
string baseFileName = Path.GetFileName(this.BaseLogFileName);
|
string baseFileName = Path.GetFileName(this.BaseLogFileName);
|
||||||
string logFile = this.BaseLogFileName + extension;
|
string logFile = this.BaseLogFileName + extension;
|
||||||
|
|
||||||
var writer = this.CreateWriter(new FileStream(logFile, FileMode.Append));
|
var writer = new FileStream(logFile, FileMode.Append);
|
||||||
|
var copy = new StreamCopyOperation(reader.BaseStream, writer);
|
||||||
long fileLength = new FileInfo(logFile).Length;
|
long fileLength = new FileInfo(logFile).Length;
|
||||||
|
|
||||||
// We auto roll at time is configured then we need to create a timer and wait until time is elasped and roll the file over
|
// We auto roll at time is configured then we need to create a timer and wait until time is elasped and roll the file over
|
||||||
|
@ -412,7 +406,7 @@ namespace WinSW
|
||||||
string nextFileName = Path.Combine(baseDirectory, string.Format("{0}.{1}.#{2:D4}{3}", baseFileName, now.ToString(this.FilePattern), nextFileNumber, extension));
|
string nextFileName = Path.Combine(baseDirectory, string.Format("{0}.{1}.#{2:D4}{3}", baseFileName, now.ToString(this.FilePattern), nextFileNumber, extension));
|
||||||
File.Move(logFile, nextFileName);
|
File.Move(logFile, nextFileName);
|
||||||
|
|
||||||
writer = this.CreateWriter(new FileStream(logFile, FileMode.Create));
|
copy.Writer = writer = new FileStream(logFile, FileMode.Create);
|
||||||
fileLength = new FileInfo(logFile).Length;
|
fileLength = new FileInfo(logFile).Length;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -433,13 +427,13 @@ namespace WinSW
|
||||||
timer.Start();
|
timer.Start();
|
||||||
}
|
}
|
||||||
|
|
||||||
string? line;
|
int written;
|
||||||
while ((line = reader.ReadLine()) != null)
|
while ((written = copy.CopyLine()) != 0)
|
||||||
{
|
{
|
||||||
lock (fileLock)
|
lock (fileLock)
|
||||||
{
|
{
|
||||||
int lengthToWrite = Encoding.UTF8.GetByteCount(line) + 2; // CRLF
|
fileLength += written;
|
||||||
if (fileLength + lengthToWrite > this.SizeTheshold)
|
if (fileLength > this.SizeThreshold)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
@ -453,7 +447,7 @@ namespace WinSW
|
||||||
|
|
||||||
// even if the log rotation fails, create a new one, or else
|
// even if the log rotation fails, create a new one, or else
|
||||||
// we'll infinitely try to roll.
|
// we'll infinitely try to roll.
|
||||||
writer = this.CreateWriter(new FileStream(logFile, FileMode.Create));
|
copy.Writer = writer = new FileStream(logFile, FileMode.Create);
|
||||||
fileLength = new FileInfo(logFile).Length;
|
fileLength = new FileInfo(logFile).Length;
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
|
@ -461,9 +455,6 @@ namespace WinSW
|
||||||
this.EventLogger.LogEvent($"Failed to roll size time log: {e.Message}");
|
this.EventLogger.LogEvent($"Failed to roll size time log: {e.Message}");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
writer.WriteLine(line);
|
|
||||||
fileLength += lengthToWrite;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -618,4 +609,70 @@ namespace WinSW
|
||||||
return nextFileNumber;
|
return nextFileNumber;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
internal sealed class StreamCopyOperation
|
||||||
|
{
|
||||||
|
private const int BufferSize = 1024;
|
||||||
|
|
||||||
|
private readonly byte[] buffer;
|
||||||
|
private readonly Stream reader;
|
||||||
|
|
||||||
|
private int startIndex;
|
||||||
|
private int endIndex;
|
||||||
|
|
||||||
|
internal Stream Writer;
|
||||||
|
|
||||||
|
internal StreamCopyOperation(Stream reader, Stream writer)
|
||||||
|
{
|
||||||
|
this.buffer = new byte[BufferSize];
|
||||||
|
this.reader = reader;
|
||||||
|
this.startIndex = 0;
|
||||||
|
this.endIndex = 0;
|
||||||
|
this.Writer = writer;
|
||||||
|
}
|
||||||
|
|
||||||
|
internal int CopyLine()
|
||||||
|
{
|
||||||
|
byte[] buffer = this.buffer;
|
||||||
|
var source = this.reader;
|
||||||
|
int startIndex = this.startIndex;
|
||||||
|
int endIndex = this.endIndex;
|
||||||
|
var destination = this.Writer;
|
||||||
|
|
||||||
|
int total = 0;
|
||||||
|
while (true)
|
||||||
|
{
|
||||||
|
if (startIndex == 0)
|
||||||
|
{
|
||||||
|
if ((endIndex = source.Read(buffer, 0, BufferSize)) == 0)
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int buffered = endIndex - startIndex;
|
||||||
|
|
||||||
|
int newLineIndex = Array.IndexOf(buffer, (byte)'\n', startIndex, buffered);
|
||||||
|
if (newLineIndex >= 0)
|
||||||
|
{
|
||||||
|
int count = newLineIndex - startIndex + 1;
|
||||||
|
total += count;
|
||||||
|
destination.Write(buffer, startIndex, count);
|
||||||
|
destination.Flush();
|
||||||
|
startIndex = (newLineIndex + 1) % BufferSize;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
total += buffered;
|
||||||
|
destination.Write(buffer, startIndex, buffered);
|
||||||
|
destination.Flush();
|
||||||
|
startIndex = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.startIndex = startIndex;
|
||||||
|
this.endIndex = endIndex;
|
||||||
|
|
||||||
|
return total;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -246,7 +246,7 @@ $@"<service>
|
||||||
|
|
||||||
var logHandler = serviceDescriptor.Log.CreateLogHandler() as SizeBasedRollingLogAppender;
|
var logHandler = serviceDescriptor.Log.CreateLogHandler() as SizeBasedRollingLogAppender;
|
||||||
Assert.That(logHandler, Is.Not.Null);
|
Assert.That(logHandler, Is.Not.Null);
|
||||||
Assert.That(logHandler.SizeTheshold, Is.EqualTo(112 * 1024));
|
Assert.That(logHandler.SizeThreshold, Is.EqualTo(112 * 1024));
|
||||||
Assert.That(logHandler.FilesToKeep, Is.EqualTo(113));
|
Assert.That(logHandler.FilesToKeep, Is.EqualTo(113));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -287,7 +287,7 @@ $@"<service>
|
||||||
|
|
||||||
var logHandler = serviceDescriptor.Log.CreateLogHandler() as RollingSizeTimeLogAppender;
|
var logHandler = serviceDescriptor.Log.CreateLogHandler() as RollingSizeTimeLogAppender;
|
||||||
Assert.That(logHandler, Is.Not.Null);
|
Assert.That(logHandler, Is.Not.Null);
|
||||||
Assert.That(logHandler.SizeTheshold, Is.EqualTo(10240 * 1024));
|
Assert.That(logHandler.SizeThreshold, Is.EqualTo(10240 * 1024));
|
||||||
Assert.That(logHandler.FilePattern, Is.EqualTo("yyyy-MM-dd"));
|
Assert.That(logHandler.FilePattern, Is.EqualTo("yyyy-MM-dd"));
|
||||||
Assert.That(logHandler.AutoRollAtTime, Is.EqualTo((TimeSpan?)new TimeSpan(0, 0, 0)));
|
Assert.That(logHandler.AutoRollAtTime, Is.EqualTo((TimeSpan?)new TimeSpan(0, 0, 0)));
|
||||||
}
|
}
|
||||||
|
|
|
@ -276,7 +276,7 @@ log:
|
||||||
|
|
||||||
var logHandler = serviceDescriptor.Log.CreateLogHandler() as SizeBasedRollingLogAppender;
|
var logHandler = serviceDescriptor.Log.CreateLogHandler() as SizeBasedRollingLogAppender;
|
||||||
Assert.That(logHandler, Is.Not.Null);
|
Assert.That(logHandler, Is.Not.Null);
|
||||||
Assert.That(logHandler.SizeTheshold, Is.EqualTo(112 * 1024));
|
Assert.That(logHandler.SizeThreshold, Is.EqualTo(112 * 1024));
|
||||||
Assert.That(logHandler.FilesToKeep, Is.EqualTo(113));
|
Assert.That(logHandler.FilesToKeep, Is.EqualTo(113));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -325,7 +325,7 @@ log:
|
||||||
|
|
||||||
var logHandler = serviceDescriptor.Log.CreateLogHandler() as RollingSizeTimeLogAppender;
|
var logHandler = serviceDescriptor.Log.CreateLogHandler() as RollingSizeTimeLogAppender;
|
||||||
Assert.That(logHandler, Is.Not.Null);
|
Assert.That(logHandler, Is.Not.Null);
|
||||||
Assert.That(logHandler.SizeTheshold, Is.EqualTo(10240 * 1024));
|
Assert.That(logHandler.SizeThreshold, Is.EqualTo(10240 * 1024));
|
||||||
Assert.That(logHandler.FilePattern, Is.EqualTo("yyyy-MM-dd"));
|
Assert.That(logHandler.FilePattern, Is.EqualTo("yyyy-MM-dd"));
|
||||||
Assert.That(logHandler.AutoRollAtTime, Is.EqualTo((TimeSpan?)new TimeSpan(0, 0, 0)));
|
Assert.That(logHandler.AutoRollAtTime, Is.EqualTo((TimeSpan?)new TimeSpan(0, 0, 0)));
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue