Enhance ScopedLoggerFactory to support log file compression with rolling, include LogZipService for managing zipped archives, and update CliRunner configuration accordingly.
This commit is contained in:
parent
e57c6a6a02
commit
9863b54bc8
@ -54,7 +54,13 @@ namespace TBF.Rig.RegisterReaders.PoseidonCmdStartStop
|
||||
if (isCliLogging)
|
||||
{
|
||||
log = new ScopedLoggerFactory().CreateLogger<CliRunner>(
|
||||
@"C:\TBF\Logs\CliRunner.txt"
|
||||
@"C:\TBF\Logs\CliRunner.txt",
|
||||
10, // maxFileSizeMB
|
||||
7, // maxBackups
|
||||
log4net.Core.Level.Debug,
|
||||
true, // zipRolledFiles
|
||||
true, // singleZipPerDay
|
||||
TimeSpan.FromMinutes(2) // zipScanInterval
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,14 +1,31 @@
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.IO;
|
||||
using System.IO.Compression;
|
||||
using System.Linq;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Threading;
|
||||
using log4net;
|
||||
using log4net.Appender;
|
||||
using log4net.Core;
|
||||
using log4net.Layout;
|
||||
using log4net.Repository.Hierarchy;
|
||||
|
||||
|
||||
namespace TBF.Rig.RegisterReaders.PoseidonCmdStartStop
|
||||
{
|
||||
public class ScopedLoggerFactory
|
||||
public sealed class ScopedLoggerFactory
|
||||
{
|
||||
public ILog CreateLogger<T>(string logFile, Level level = null)
|
||||
private static readonly LogZipService ZipService = new LogZipService();
|
||||
|
||||
public ILog CreateLogger<T>(
|
||||
string logFile,
|
||||
int maxFileSizeMB,
|
||||
int maxBackups,
|
||||
Level level,
|
||||
bool zipRolledFiles,
|
||||
bool singleZipPerDay,
|
||||
TimeSpan zipScanInterval)
|
||||
{
|
||||
var layout = new PatternLayout("%date %-5level %logger - %message%newline");
|
||||
layout.ActivateOptions();
|
||||
@ -18,8 +35,15 @@ namespace TBF.Rig.RegisterReaders.PoseidonCmdStartStop
|
||||
Name = typeof(T).Name + "Appender",
|
||||
File = logFile,
|
||||
AppendToFile = true,
|
||||
RollingStyle = RollingFileAppender.RollingMode.Date,
|
||||
RollingStyle = RollingFileAppender.RollingMode.Composite,
|
||||
DatePattern = "'.'yyyyMMdd",
|
||||
StaticLogFileName = true,
|
||||
PreserveLogFileNameExtension = true,
|
||||
MaxSizeRollBackups = maxBackups,
|
||||
MaximumFileSize = maxFileSizeMB + "MB",
|
||||
CountDirection = 1,
|
||||
LockingModel = new FileAppender.MinimalLock(),
|
||||
ImmediateFlush = true,
|
||||
Layout = layout
|
||||
};
|
||||
appender.ActivateOptions();
|
||||
@ -27,12 +51,122 @@ namespace TBF.Rig.RegisterReaders.PoseidonCmdStartStop
|
||||
var hierarchy = (Hierarchy)LogManager.GetRepository();
|
||||
var logger = (log4net.Repository.Hierarchy.Logger)hierarchy.GetLogger(typeof(T).FullName);
|
||||
|
||||
logger.RemoveAllAppenders(); // isolate this logger
|
||||
logger.RemoveAllAppenders();
|
||||
logger.AddAppender(appender);
|
||||
logger.Level = level ?? Level.Debug;
|
||||
logger.Hierarchy.Configured = true;
|
||||
logger.Additivity = false;
|
||||
hierarchy.Configured = true;
|
||||
|
||||
if (zipRolledFiles)
|
||||
{
|
||||
ZipService.StartFor(logFile, singleZipPerDay, zipScanInterval);
|
||||
}
|
||||
|
||||
return LogManager.GetLogger(typeof(T));
|
||||
}
|
||||
}
|
||||
|
||||
internal sealed class LogZipService : IDisposable
|
||||
{
|
||||
private readonly ConcurrentDictionary<string, Timer> _timers =
|
||||
new ConcurrentDictionary<string, Timer>();
|
||||
|
||||
public void StartFor(string baseLogFile, bool singleZipPerDay, TimeSpan interval)
|
||||
{
|
||||
_timers.GetOrAdd(baseLogFile, delegate (string key)
|
||||
{
|
||||
// .NET Framework Timer ctor: Timer(Callback, state, dueTimeMs, periodMs)
|
||||
return new Timer(
|
||||
new TimerCallback(delegate (object state) { CompressRolledFiles(key, singleZipPerDay); }),
|
||||
null,
|
||||
(int)TimeSpan.FromSeconds(20).TotalMilliseconds,
|
||||
(int)interval.TotalMilliseconds
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
private static void CompressRolledFiles(string baseLogFile, bool singleZipPerDay)
|
||||
{
|
||||
try
|
||||
{
|
||||
var dir = Path.GetDirectoryName(baseLogFile);
|
||||
var fileName = Path.GetFileName(baseLogFile);
|
||||
var nameNoExt = Path.GetFileNameWithoutExtension(fileName);
|
||||
var ext = Path.GetExtension(fileName);
|
||||
|
||||
var candidates = Directory.EnumerateFiles(dir)
|
||||
.Where(f =>
|
||||
!f.EndsWith(".zip", StringComparison.OrdinalIgnoreCase) &&
|
||||
!StringComparer.OrdinalIgnoreCase.Equals(f, baseLogFile) &&
|
||||
Regex.IsMatch(Path.GetFileName(f),
|
||||
"^" + Regex.Escape(nameNoExt) + "\\.\\d{8}(\\.\\d+)?" + Regex.Escape(ext) + "$"));
|
||||
|
||||
foreach (var f in candidates)
|
||||
{
|
||||
if ((DateTime.UtcNow - File.GetLastWriteTimeUtc(f)).TotalSeconds < 15)
|
||||
continue;
|
||||
|
||||
if (!CanOpenExclusive(f)) continue;
|
||||
|
||||
string zipPath = singleZipPerDay
|
||||
? Path.Combine(dir, nameNoExt + "-" + ExtractDatePart(f) + ".zip")
|
||||
: f + ".zip";
|
||||
|
||||
AddFileToZip(zipPath, f);
|
||||
File.Delete(f);
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
// ignore errors
|
||||
}
|
||||
}
|
||||
|
||||
private static void AddFileToZip(string zipPath, string fileToAdd)
|
||||
{
|
||||
var entryName = Path.GetFileName(fileToAdd);
|
||||
if (!File.Exists(zipPath))
|
||||
{
|
||||
using (var archive = ZipFile.Open(zipPath, ZipArchiveMode.Create))
|
||||
{
|
||||
archive.CreateEntryFromFile(fileToAdd, entryName, CompressionLevel.Optimal);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
using (var archive = ZipFile.Open(zipPath, ZipArchiveMode.Update))
|
||||
{
|
||||
var existing = archive.GetEntry(entryName);
|
||||
if (existing != null) existing.Delete();
|
||||
archive.CreateEntryFromFile(fileToAdd, entryName, CompressionLevel.Optimal);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static bool CanOpenExclusive(string path)
|
||||
{
|
||||
try
|
||||
{
|
||||
using (FileStream fs = File.Open(path, FileMode.Open, FileAccess.Read, FileShare.None))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
catch { return false; }
|
||||
}
|
||||
|
||||
private static string ExtractDatePart(string rolledFilePath)
|
||||
{
|
||||
var name = Path.GetFileName(rolledFilePath);
|
||||
var m = Regex.Match(name, @"\.(\d{8})(?:\.\d+)?(\.[^.]+)$");
|
||||
if (m.Success) return m.Groups[1].Value;
|
||||
return DateTime.UtcNow.ToString("yyyyMMdd");
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
foreach (var t in _timers.Values) t.Dispose();
|
||||
_timers.Clear();
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -139,6 +139,8 @@
|
||||
<Reference Include="System.Data" />
|
||||
<Reference Include="System.Deployment" />
|
||||
<Reference Include="System.Drawing" />
|
||||
<Reference Include="System.IO.Compression" />
|
||||
<Reference Include="System.IO.Compression.FileSystem" />
|
||||
<Reference Include="System.Management" />
|
||||
<Reference Include="System.Net.Http" />
|
||||
<Reference Include="System.Numerics" />
|
||||
|
||||
Loading…
Reference in New Issue
Block a user