diff --git a/EonaCat.Logger/EonaCat.Logger.csproj b/EonaCat.Logger/EonaCat.Logger.csproj
index 90777fd..490031b 100644
--- a/EonaCat.Logger/EonaCat.Logger.csproj
+++ b/EonaCat.Logger/EonaCat.Logger.csproj
@@ -7,7 +7,7 @@
net7.0;
icon.ico
- 1.1.5
+ 1.1.6
EonaCat (Jeroen Saey)
true
EonaCat (Jeroen Saey)
@@ -43,6 +43,7 @@
+
diff --git a/EonaCat.Logger/EonaCat.Logger.csproj.DotSettings b/EonaCat.Logger/EonaCat.Logger.csproj.DotSettings
new file mode 100644
index 0000000..16c7a3d
--- /dev/null
+++ b/EonaCat.Logger/EonaCat.Logger.csproj.DotSettings
@@ -0,0 +1,2 @@
+
+ CSharp110
\ No newline at end of file
diff --git a/EonaCat.Logger/EonaCatCoreLogger/Extensions/FileLoggerFactoryExtensions.cs b/EonaCat.Logger/EonaCatCoreLogger/Extensions/FileLoggerFactoryExtensions.cs
index 87191d9..baf295e 100644
--- a/EonaCat.Logger/EonaCatCoreLogger/Extensions/FileLoggerFactoryExtensions.cs
+++ b/EonaCat.Logger/EonaCatCoreLogger/Extensions/FileLoggerFactoryExtensions.cs
@@ -47,6 +47,7 @@ namespace EonaCat.Logger.EonaCatCoreLogger.Extensions
options.FileSizeLimit = fileLoggerOptions.FileSizeLimit;
options.IsEnabled = fileLoggerOptions.IsEnabled;
options.MaxRolloverFiles = fileLoggerOptions.MaxRolloverFiles;
+ options.UseLocalTime = fileLoggerOptions.UseLocalTime;
}
);
diff --git a/EonaCat.Logger/EonaCatCoreLogger/FileLoggerOptions.cs b/EonaCat.Logger/EonaCatCoreLogger/FileLoggerOptions.cs
index 11e80f8..862fb5b 100644
--- a/EonaCat.Logger/EonaCatCoreLogger/FileLoggerOptions.cs
+++ b/EonaCat.Logger/EonaCatCoreLogger/FileLoggerOptions.cs
@@ -70,6 +70,11 @@ namespace EonaCat.Logger.EonaCatCoreLogger
}
}
+ ///
+ /// Determines if we need to use the local time in the logging or UTC (default:false)
+ ///
+ public bool UseLocalTime { get; set; }
+
///
/// Gets or sets a strictly positive value representing the maximum retained file rollovers or null for no limit.
/// Defaults to 10.
diff --git a/EonaCat.Logger/EonaCatCoreLogger/Internal/BatchingLogger.cs b/EonaCat.Logger/EonaCatCoreLogger/Internal/BatchingLogger.cs
index 2291646..184962d 100644
--- a/EonaCat.Logger/EonaCatCoreLogger/Internal/BatchingLogger.cs
+++ b/EonaCat.Logger/EonaCatCoreLogger/Internal/BatchingLogger.cs
@@ -14,8 +14,10 @@ namespace EonaCat.Logger.EonaCatCoreLogger.Internal
private LoggerSettings _loggerSettings;
private readonly BatchingLoggerProvider _provider;
private readonly string _category;
+ private DateTimeOffset CurrentDateTimeOffset => _loggerSettings.UseLocalTime ? DateTimeOffset.Now : DateTimeOffset.UtcNow;
+ private DateTime CurrentDateTme => _loggerSettings.UseLocalTime ? DateTime.Now : DateTime.UtcNow;
- public BatchingLogger(BatchingLoggerProvider loggerProvider, string categoryName, LoggerSettings loggerSettings = null)
+ public BatchingLogger(BatchingLoggerProvider loggerProvider, string categoryName, LoggerSettings loggerSettings)
{
_loggerSettings = loggerSettings;
_provider = loggerProvider;
@@ -41,7 +43,7 @@ namespace EonaCat.Logger.EonaCatCoreLogger.Internal
_loggerSettings = new LoggerSettings();
}
- var message = LogHelper.FormatMessageWithHeader(_loggerSettings, logLevel.FromLogLevel(), formatter(state, exception), DateTime.Now) + Environment.NewLine;
+ var message = LogHelper.FormatMessageWithHeader(_loggerSettings, logLevel.FromLogLevel(), formatter(state, exception), timestamp.DateTime) + Environment.NewLine;
if (exception != null)
{
message = exception.FormatExceptionToMessage() + Environment.NewLine;
@@ -63,7 +65,7 @@ namespace EonaCat.Logger.EonaCatCoreLogger.Internal
public void Log(LogLevel logLevel, EventId eventId, TState state, Exception exception, Func formatter)
{
- Log(DateTimeOffset.Now, logLevel, eventId, state, exception, formatter);
+ Log(CurrentDateTimeOffset, logLevel, eventId, state, exception, formatter);
}
}
}
\ No newline at end of file
diff --git a/EonaCat.Logger/EonaCatCoreLogger/Internal/BatchingLoggerProvider.cs b/EonaCat.Logger/EonaCatCoreLogger/Internal/BatchingLoggerProvider.cs
index 142de19..6c2d677 100644
--- a/EonaCat.Logger/EonaCatCoreLogger/Internal/BatchingLoggerProvider.cs
+++ b/EonaCat.Logger/EonaCatCoreLogger/Internal/BatchingLoggerProvider.cs
@@ -14,6 +14,9 @@ namespace EonaCat.Logger.EonaCatCoreLogger.Internal
public abstract class BatchingLoggerProvider : ILoggerProvider
{
+ protected DateTimeOffset CurrentDateTimeOffset => UseLocalTime ? DateTimeOffset.Now : DateTimeOffset.UtcNow;
+ protected DateTime CurrentDateTme => UseLocalTime ? DateTime.Now : DateTime.UtcNow;
+
private readonly List _currentBatch = new List();
private readonly TimeSpan _interval;
private readonly int _batchSize;
@@ -21,6 +24,9 @@ namespace EonaCat.Logger.EonaCatCoreLogger.Internal
private ConcurrentQueue _messageQueue;
private Task _outputTask;
private CancellationTokenSource _cancellationTokenSource;
+ private LoggerSettings _loggerSettings;
+
+ protected bool UseLocalTime { get; set; }
protected BatchingLoggerProvider(IOptions options)
{
@@ -31,18 +37,37 @@ namespace EonaCat.Logger.EonaCatCoreLogger.Internal
throw new ArgumentOutOfRangeException(nameof(loggerOptions.FlushPeriod), $"{nameof(loggerOptions.FlushPeriod)} must be longer than zero.");
}
+ if (options is FileLoggerOptions fileLoggerOptions)
+ {
+ UseLocalTime = fileLoggerOptions.UseLocalTime;
+ }
+
_interval = loggerOptions.FlushPeriod;
_batchSize = loggerOptions.BatchSize;
Start();
}
+ protected LoggerSettings LoggerSettings
+ {
+ get
+ {
+ if (_loggerSettings != null) return _loggerSettings;
+
+ _loggerSettings = new LoggerSettings();
+ _loggerSettings.UseLocalTime = UseLocalTime;
+ return _loggerSettings;
+ }
+
+ set => _loggerSettings = value;
+ }
+
protected abstract Task WriteMessagesAsync(IEnumerable messages, CancellationToken token);
private async Task ProcessLogQueueAsync(object state)
{
var startupMessage = $"{DllInfo.ApplicationName} started.{Environment.NewLine}";
- startupMessage = LogHelper.FormatMessageWithHeader(new LoggerSettings(), ELogType.INFO, startupMessage, DateTime.Now);
+ startupMessage = LogHelper.FormatMessageWithHeader(LoggerSettings, ELogType.INFO, startupMessage, CurrentDateTme);
AddMessage(DateTimeOffset.Now, startupMessage);
@@ -77,7 +102,7 @@ namespace EonaCat.Logger.EonaCatCoreLogger.Internal
await IntervalAsync(_interval, _cancellationTokenSource.Token).ConfigureAwait(false);
}
- await WriteMessagesAsync(new List { new LogMessage { Message = $"[{DllInfo.ApplicationName}] {DllInfo.ApplicationName} stopped.{Environment.NewLine}", Timestamp = DateTimeOffset.Now } }, _cancellationTokenSource.Token).ConfigureAwait(false);
+ await WriteMessagesAsync(new List { new LogMessage { Message = $"[{DllInfo.ApplicationName}] {DllInfo.ApplicationName} stopped.{Environment.NewLine}", Timestamp = CurrentDateTimeOffset } }, _cancellationTokenSource.Token).ConfigureAwait(false);
}
protected virtual Task IntervalAsync(TimeSpan interval, CancellationToken cancellationToken)
@@ -132,7 +157,7 @@ namespace EonaCat.Logger.EonaCatCoreLogger.Internal
public ILogger CreateLogger(string categoryName)
{
- return new BatchingLogger(this, categoryName);
+ return new BatchingLogger(this, categoryName, LoggerSettings);
}
}
}
\ No newline at end of file
diff --git a/EonaCat.Logger/Managers/LogHelper.cs b/EonaCat.Logger/Managers/LogHelper.cs
index e6992c6..59f60c9 100644
--- a/EonaCat.Logger/Managers/LogHelper.cs
+++ b/EonaCat.Logger/Managers/LogHelper.cs
@@ -22,7 +22,7 @@ namespace EonaCat.Logger.Managers
if (settings != null)
{
if (sb.ToString().Contains("{ts}"))
- sb.Replace("{ts}", dateTime.ToString(settings.TimestampFormat));
+ sb.Replace("{ts}", dateTime.ToString(settings.TimestampFormat) + " " + (settings.UseLocalTime ? "[LOCAL]" : "[UTC]"));
if (sb.ToString().Contains("{host}"))
sb.Replace("{host}", $"[Host:{Dns.GetHostName()}]");
diff --git a/EonaCat.Logger/Managers/LogManager.cs b/EonaCat.Logger/Managers/LogManager.cs
index b15dcad..c614b95 100644
--- a/EonaCat.Logger/Managers/LogManager.cs
+++ b/EonaCat.Logger/Managers/LogManager.cs
@@ -4,7 +4,6 @@ using Microsoft.Extensions.Logging;
using System;
using System.Collections.Generic;
using System.IO;
-using System.Runtime.CompilerServices;
using System.Threading;
using System.Threading.Tasks;
using EonaCat.Logger.EonaCatCoreLogger;
@@ -16,6 +15,7 @@ namespace EonaCat.Logger.Managers
{
public partial class LogManager : ILogManager, IDisposable
{
+ private DateTime CurrentDateTme => Settings.UseLocalTime ? DateTime.Now : DateTime.UtcNow;
private DateTime _logDate;
public ILoggerProvider LoggerProvider { get; private set; }
public ILoggerFactory LoggerFactory { get; private set; }
@@ -30,7 +30,7 @@ namespace EonaCat.Logger.Managers
public static LogManager Instance => InstanceInit();
- public LoggerSettings Settings { get; } = CreateDefaultSettings();
+ public LoggerSettings Settings { get; set; } = CreateDefaultSettings();
private static LogManager InstanceInit()
{
@@ -62,9 +62,7 @@ namespace EonaCat.Logger.Managers
if (_tokenSource.IsCancellationRequested)
return;
- DateTime now = DateTime.UtcNow;
-
- if (IsRunning && now.Date > _logDate.Date)
+ if (IsRunning && CurrentDateTme.Date > _logDate.Date)
await StopLoggingAsync().ConfigureAwait(false);
IsRunning = true;
@@ -73,7 +71,7 @@ namespace EonaCat.Logger.Managers
Directory.CreateDirectory(Settings.FileLoggerOptions.LogDirectory);
- _logDate = now;
+ _logDate = CurrentDateTme;
}
private void CreateLogger()
@@ -91,6 +89,7 @@ namespace EonaCat.Logger.Managers
configuration.LogDirectory = fileLoggerOptions.LogDirectory;
configuration.FileNamePrefix = fileLoggerOptions.FileNamePrefix;
configuration.MaxRolloverFiles = fileLoggerOptions.MaxRolloverFiles;
+ configuration.UseLocalTime = Settings.UseLocalTime;
}));
var serviceProvider = serviceCollection.BuildServiceProvider();
@@ -172,7 +171,7 @@ namespace EonaCat.Logger.Managers
{
AppDomain.CurrentDomain.ProcessExit += ProcessExit;
Console.CancelKeyPress += Console_CancelKeyPress;
- _logDate = DateTime.UtcNow;
+ _logDate = CurrentDateTme;
}
private void Console_CancelKeyPress(object sender, ConsoleCancelEventArgs e)
@@ -188,7 +187,7 @@ namespace EonaCat.Logger.Managers
private Task StopLoggingAsync()
{
IsRunning = false;
- InternalWriteAsync(DateTime.UtcNow, $"{DllInfo.ApplicationName} stopped.");
+ InternalWriteAsync(CurrentDateTme, $"{DllInfo.ApplicationName} stopped.");
return Task.Delay(500);
}
@@ -217,12 +216,10 @@ namespace EonaCat.Logger.Managers
if (logType == ELogType.NONE)
return;
- var now = DateTime.UtcNow;
-
if (!IsRunning)
StartNewLogAsync().ConfigureAwait(false);
- InternalWriteAsync(now, message, logType, writeToConsole);
+ InternalWriteAsync(CurrentDateTme, message, logType, writeToConsole);
}
}
}
diff --git a/EonaCat.Logger/Managers/LoggerSettings.cs b/EonaCat.Logger/Managers/LoggerSettings.cs
index 2d43dc5..ce36a74 100644
--- a/EonaCat.Logger/Managers/LoggerSettings.cs
+++ b/EonaCat.Logger/Managers/LoggerSettings.cs
@@ -14,6 +14,11 @@ namespace EonaCat.Logger.Managers
public event LogDelegate OnLog;
public delegate void LogDelegate(EonaCatLogMessage message);
+ ///
+ /// Determines if we need to use the local time in the logging or UTC (default:false)
+ ///
+ public bool UseLocalTime { get; set; }
+
public string Id { get; set; } = "EonaCatLogger";
///
@@ -135,7 +140,7 @@ namespace EonaCat.Logger.Managers
}
}
- private FileLoggerOptions CreateDefaultFileLoggerOptions()
+ private static FileLoggerOptions CreateDefaultFileLoggerOptions()
{
return new FileLoggerOptions();
}
diff --git a/Testers/EonaCat.Logger.Test.Web/Logger.cs b/Testers/EonaCat.Logger.Test.Web/Logger.cs
index d527a26..dedaa7c 100644
--- a/Testers/EonaCat.Logger.Test.Web/Logger.cs
+++ b/Testers/EonaCat.Logger.Test.Web/Logger.cs
@@ -1,7 +1,6 @@
using EonaCat.Logger.Managers;
-using Microsoft.AspNetCore.Http.Features;
-using Microsoft.AspNetCore.Mvc;
-using System.Net;
+using System.IO.Compression;
+using EonaCat.Logger.Extensions;
namespace EonaCat.Logger.Test.Web
{
@@ -30,114 +29,64 @@ namespace EonaCat.Logger.Test.Web
LogManager.DeleteCurrentLogFile();
}
- internal static IActionResult DownloadLogAsync(HttpResponse response, string logFile)
+ private static string ConvertToAbsolutePath(string path)
{
- if (IsDisabled)
- {
- response.StatusCode = (int)HttpStatusCode.BadRequest;
- return null;
- }
-
- // Check if the file exists
- if (!File.Exists(logFile))
- {
- response.StatusCode = (int)HttpStatusCode.BadRequest;
- return null;
- }
-
- // Create a cancellation token source to handle cancellation
- var cancellationTokenSource = new CancellationTokenSource();
-
- // Start streaming the file content to the response
- Task.Run(() => StreamFileContentAsync(response, logFile, response.Body, cancellationTokenSource.Token), cancellationTokenSource.Token);
-
- // Return an empty result to indicate that streaming has started
- return new EmptyResult();
+ return Path.IsPathRooted(path) ? path : Path.Combine(LogFolder, path);
}
- private static void DisableResponseBuffering(HttpResponse response)
+ public static async Task DownloadLogAsync(HttpContext context, string logName, long limit)
{
- var httpContext = response.HttpContext;
- var responseBodyFeature = httpContext.Features.Get();
- if (responseBodyFeature != null)
+ var logFileName = logName + ".log";
+
+ await using var fS = new FileStream(Path.Combine(ConvertToAbsolutePath(LogFolder), logFileName), FileMode.Open, FileAccess.Read, FileShare.ReadWrite, 64 * 1024, true);
+ var response = context.Response;
+
+ response.ContentType = "text/plain";
+ response.Headers.ContentDisposition = "attachment;filename=" + logFileName;
+
+ if ((limit > fS.Length) || (limit < 1))
+ limit = fS.Length;
+
+ var oFS = new OffsetStream(fS, 0, limit);
+ var request = context.Request;
+ Stream s;
+
+ string acceptEncoding = request.Headers["Accept-Encoding"];
+ if (string.IsNullOrEmpty(acceptEncoding))
{
- responseBodyFeature.DisableBuffering();
+ s = response.Body;
}
- }
-
- private static async Task StreamFileContentAsync(HttpResponse response, string filePath, Stream outputStream, CancellationToken cancellationToken)
- {
- using (var fileStream = new FileStream(filePath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite, 4096, FileOptions.Asynchronous | FileOptions.SequentialScan))
+ else
{
- try
+ string[] acceptEncodingParts = acceptEncoding.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries);
+
+ if (acceptEncodingParts.Contains("br"))
{
- // Clear the response first
- response.Clear();
-
- // Disable response buffering
- DisableResponseBuffering(response);
-
- // Set the response headers
- response.Headers.Add("Content-Disposition", $"attachment; filename={Path.GetFileName(filePath)}");
- response.Headers.Add("Content-Type", "application/octet-stream");
-
- byte[] buffer = new byte[4096];
- int bytesRead;
- while ((bytesRead = await fileStream.ReadAsync(buffer, 0, buffer.Length, cancellationToken).ConfigureAwait(false)) > 0)
- {
- if (cancellationToken.IsCancellationRequested)
- {
- break;
- }
-
- // Check if the response is completed
- if (response.HasStarted)
- {
- // The response is already completed, so we can't write further
- break;
- }
-
- try
- {
- await outputStream.WriteAsync(buffer, 0, bytesRead, cancellationToken).ConfigureAwait(false);
- }
- catch (Exception)
- {
- // Do nothing, handle any specific error if needed
- }
-
- // Check if the file has been modified
- if (File.GetLastWriteTimeUtc(filePath) > File.GetLastWriteTimeUtc(fileStream.Name))
- {
- // Close the existing stream and reopen the file with updated contents
- fileStream.Close();
- await StreamFileContentAsync(response, filePath, outputStream, cancellationToken).ConfigureAwait(false);
- return;
- }
- }
+ response.Headers.ContentEncoding = "br";
+ s = new BrotliStream(response.Body, CompressionMode.Compress);
}
- catch (OperationCanceledException)
+ else if (acceptEncodingParts.Contains("gzip"))
{
- // The operation was canceled, clean up if necessary
- fileStream.Close();
+ response.Headers.ContentEncoding = "gzip";
+ s = new GZipStream(response.Body, CompressionMode.Compress);
}
- finally
+ else if (acceptEncodingParts.Contains("deflate"))
{
-
- try
- {
- // Flush and close the output stream
- await outputStream.FlushAsync(cancellationToken).ConfigureAwait(false);
- }
- catch (ObjectDisposedException e)
- {
- Log(e, "StreamFileContentAsync");
- }
- finally
- {
- outputStream?.Close();
- }
+ response.Headers.ContentEncoding = "deflate";
+ s = new DeflateStream(response.Body, CompressionMode.Compress);
}
+ else
+ {
+ s = response.Body;
+ }
+ }
+
+ await using (s)
+ {
+ await oFS.CopyToAsync(s).ConfigureAwait(false);
+
+ if (fS.Length > limit)
+ await s.WriteAsync("\r\n####__EONACATLOGGER_TRUNCATED___####"u8.ToArray()).ConfigureAwait(false);
}
}