diff --git a/DarkRift.Server/Plugins/LogWriters/FileWriter.cs b/DarkRift.Server/Plugins/LogWriters/FileWriter.cs index 37bae64..918e0a4 100644 --- a/DarkRift.Server/Plugins/LogWriters/FileWriter.cs +++ b/DarkRift.Server/Plugins/LogWriters/FileWriter.cs @@ -23,38 +23,138 @@ public sealed class FileWriter : LogWriter /// /// The stream to the log file to write to. /// - private StreamWriter LogFileStream { get; } + private StreamWriter LogFileStream { get; set; } + + private readonly object streamLock = new object(); /// /// The directory we are writing to. /// public string LogFilePath { get; private set; } + /// + /// The format of the path (used for rotation). + /// + public string LogFilePathFormat { get; private set; } + + /// + /// The time this file started (for rotation). + /// + public DateTime LogCreated { get; private set; } + + /// + /// Number of bytes written. + /// + public int LogBytesWritten { get; private set; } + + /// + /// Maximum number of bytes (before rotating). 0 to disable. + /// + public int LogMaxBytes { get; private set; } + + /// + /// Maximum number of seconds per log file (before rotating). 0 to disable. + /// + public int LogMaxTimeSeconds { get; private set; } + /// /// Creates a new file writer with the given plugin load data. /// /// The data for this plugin. public FileWriter(LogWriterLoadData logWriterLoadData) : base(logWriterLoadData) { - //Get the log directory concatenated with the date - LogFilePath = string.Format(logWriterLoadData.Settings["file"], DateTime.Now); - //Create the actual log directory (will do nothing if it already exists) - Directory.CreateDirectory(Path.GetDirectoryName(LogFilePath)); + // Sore the format for creating the filename + LogFilePathFormat = logWriterLoadData.Settings["file"] ?? "Logs/{0:yyyy-MM-dd}/{0:HH-mm-ss}.txt"; + + // Get the maximum size (in MB, convert to bytes) + try + { + int logMaxSizeMB = int.Parse(logWriterLoadData.Settings["maxSize"] ?? "100"); + LogMaxBytes = Math.Max(0, logMaxSizeMB * 1000000); + } + catch (FormatException) + { + LogMaxBytes = 0; + } + + // Get the maximum time before rotation (in seconds) + try + { + LogMaxTimeSeconds = int.Parse(logWriterLoadData.Settings["maxTime"] ?? "86400"); + } + catch (FormatException) + { + LogMaxTimeSeconds = 0; + } + + CreateStream(); + } + + private void CreateStream() + { + // Only create a new stream if the file name is different from existing. + string newFilePath = string.Format(LogFilePathFormat, DateTime.Now); + if (LogFilePath is null || newFilePath != LogFilePath) + { + // Close the old stream, if open + if (!(LogFilePath is null)) + { + LogFileStream.WriteLine($"Log File Continues in {newFilePath}"); + CloseStream(); + } + + //Get the log directory concatenated with the date + LogFilePath = string.Format(LogFilePathFormat, DateTime.Now); - //Create the log file and stream for it - LogFileStream = new StreamWriter(LogFilePath); + //Create the actual log directory (will do nothing if it already exists) + Directory.CreateDirectory(Path.GetDirectoryName(LogFilePath)); + + //Create the log file and stream for it + LogFileStream = new StreamWriter(LogFilePath); + + // Write + if (!(LogFilePath is null)) + { + LogFileStream.WriteLine($"Log File Continued from {LogFilePath}"); + LogFileStream.Flush(); + } + + + // Reset the counters + LogFilePath = newFilePath; + LogBytesWritten = 0; + LogCreated = DateTime.Now; + } + } + + private void CloseStream() + { + LogFileStream.Flush(); + LogFileStream.Close(); + LogFileStream.Dispose(); } /// public override void WriteEvent(WriteEventArgs args) { //Write to file - lock (LogFileStream) + lock (streamLock) { LogFileStream.WriteLine(args.FormattedMessage); LogFileStream.Flush(); + + // Remember number of btyes written + LogBytesWritten += args.FormattedMessage.Length + 2; + + // If limits exceeded, then rotate while lock still in place + // Will only rotate is log file older than a second (to avoid naming clashes) + if ((LogMaxBytes > 0 && LogBytesWritten >= LogMaxBytes) + || (LogMaxTimeSeconds > 0 && (int)DateTime.Now.Subtract(LogCreated).TotalSeconds >= LogMaxTimeSeconds) + ) { + CreateStream(); + } } } @@ -63,8 +163,8 @@ protected override void Dispose(bool disposing) { if (disposing) { - lock (LogFileStream) - LogFileStream.Dispose(); + lock (streamLock) + CloseStream(); } base.Dispose(disposing); }