Added LocalTime or UTC time display
This commit is contained in:
@@ -7,7 +7,7 @@
|
|||||||
net7.0;
|
net7.0;
|
||||||
</TargetFrameworks>
|
</TargetFrameworks>
|
||||||
<ApplicationIcon>icon.ico</ApplicationIcon>
|
<ApplicationIcon>icon.ico</ApplicationIcon>
|
||||||
<Version>1.1.5</Version>
|
<Version>1.1.6</Version>
|
||||||
<Authors>EonaCat (Jeroen Saey)</Authors>
|
<Authors>EonaCat (Jeroen Saey)</Authors>
|
||||||
<GeneratePackageOnBuild>true</GeneratePackageOnBuild>
|
<GeneratePackageOnBuild>true</GeneratePackageOnBuild>
|
||||||
<Company>EonaCat (Jeroen Saey)</Company>
|
<Company>EonaCat (Jeroen Saey)</Company>
|
||||||
@@ -43,6 +43,7 @@
|
|||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
<PackageReference Include="Microsoft.AspNetCore.Http.Abstractions" Version="2.2.0" />
|
||||||
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="7.0.0" />
|
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="7.0.0" />
|
||||||
<PackageReference Include="Microsoft.Extensions.Logging" Version="7.0.0" />
|
<PackageReference Include="Microsoft.Extensions.Logging" Version="7.0.0" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|||||||
2
EonaCat.Logger/EonaCat.Logger.csproj.DotSettings
Normal file
2
EonaCat.Logger/EonaCat.Logger.csproj.DotSettings
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
<wpf:ResourceDictionary xml:space="preserve" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:s="clr-namespace:System;assembly=mscorlib" xmlns:ss="urn:shemas-jetbrains-com:settings-storage-xaml" xmlns:wpf="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
|
||||||
|
<s:String x:Key="/Default/CodeInspection/CSharpLanguageProject/LanguageLevel/@EntryValue">CSharp110</s:String></wpf:ResourceDictionary>
|
||||||
@@ -47,6 +47,7 @@ namespace EonaCat.Logger.EonaCatCoreLogger.Extensions
|
|||||||
options.FileSizeLimit = fileLoggerOptions.FileSizeLimit;
|
options.FileSizeLimit = fileLoggerOptions.FileSizeLimit;
|
||||||
options.IsEnabled = fileLoggerOptions.IsEnabled;
|
options.IsEnabled = fileLoggerOptions.IsEnabled;
|
||||||
options.MaxRolloverFiles = fileLoggerOptions.MaxRolloverFiles;
|
options.MaxRolloverFiles = fileLoggerOptions.MaxRolloverFiles;
|
||||||
|
options.UseLocalTime = fileLoggerOptions.UseLocalTime;
|
||||||
}
|
}
|
||||||
|
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -70,6 +70,11 @@ namespace EonaCat.Logger.EonaCatCoreLogger
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Determines if we need to use the local time in the logging or UTC (default:false)
|
||||||
|
/// </summary>
|
||||||
|
public bool UseLocalTime { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets or sets a strictly positive value representing the maximum retained file rollovers or null for no limit.
|
/// Gets or sets a strictly positive value representing the maximum retained file rollovers or null for no limit.
|
||||||
/// Defaults to <c>10</c>.
|
/// Defaults to <c>10</c>.
|
||||||
|
|||||||
@@ -14,8 +14,10 @@ namespace EonaCat.Logger.EonaCatCoreLogger.Internal
|
|||||||
private LoggerSettings _loggerSettings;
|
private LoggerSettings _loggerSettings;
|
||||||
private readonly BatchingLoggerProvider _provider;
|
private readonly BatchingLoggerProvider _provider;
|
||||||
private readonly string _category;
|
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;
|
_loggerSettings = loggerSettings;
|
||||||
_provider = loggerProvider;
|
_provider = loggerProvider;
|
||||||
@@ -41,7 +43,7 @@ namespace EonaCat.Logger.EonaCatCoreLogger.Internal
|
|||||||
_loggerSettings = new LoggerSettings();
|
_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)
|
if (exception != null)
|
||||||
{
|
{
|
||||||
message = exception.FormatExceptionToMessage() + Environment.NewLine;
|
message = exception.FormatExceptionToMessage() + Environment.NewLine;
|
||||||
@@ -63,7 +65,7 @@ namespace EonaCat.Logger.EonaCatCoreLogger.Internal
|
|||||||
|
|
||||||
public void Log<TState>(LogLevel logLevel, EventId eventId, TState state, Exception exception, Func<TState, Exception, string> formatter)
|
public void Log<TState>(LogLevel logLevel, EventId eventId, TState state, Exception exception, Func<TState, Exception, string> formatter)
|
||||||
{
|
{
|
||||||
Log(DateTimeOffset.Now, logLevel, eventId, state, exception, formatter);
|
Log(CurrentDateTimeOffset, logLevel, eventId, state, exception, formatter);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -14,6 +14,9 @@ namespace EonaCat.Logger.EonaCatCoreLogger.Internal
|
|||||||
|
|
||||||
public abstract class BatchingLoggerProvider : ILoggerProvider
|
public abstract class BatchingLoggerProvider : ILoggerProvider
|
||||||
{
|
{
|
||||||
|
protected DateTimeOffset CurrentDateTimeOffset => UseLocalTime ? DateTimeOffset.Now : DateTimeOffset.UtcNow;
|
||||||
|
protected DateTime CurrentDateTme => UseLocalTime ? DateTime.Now : DateTime.UtcNow;
|
||||||
|
|
||||||
private readonly List<LogMessage> _currentBatch = new List<LogMessage>();
|
private readonly List<LogMessage> _currentBatch = new List<LogMessage>();
|
||||||
private readonly TimeSpan _interval;
|
private readonly TimeSpan _interval;
|
||||||
private readonly int _batchSize;
|
private readonly int _batchSize;
|
||||||
@@ -21,6 +24,9 @@ namespace EonaCat.Logger.EonaCatCoreLogger.Internal
|
|||||||
private ConcurrentQueue<LogMessage> _messageQueue;
|
private ConcurrentQueue<LogMessage> _messageQueue;
|
||||||
private Task _outputTask;
|
private Task _outputTask;
|
||||||
private CancellationTokenSource _cancellationTokenSource;
|
private CancellationTokenSource _cancellationTokenSource;
|
||||||
|
private LoggerSettings _loggerSettings;
|
||||||
|
|
||||||
|
protected bool UseLocalTime { get; set; }
|
||||||
|
|
||||||
protected BatchingLoggerProvider(IOptions<BatchingLoggerOptions> options)
|
protected BatchingLoggerProvider(IOptions<BatchingLoggerOptions> options)
|
||||||
{
|
{
|
||||||
@@ -31,18 +37,37 @@ namespace EonaCat.Logger.EonaCatCoreLogger.Internal
|
|||||||
throw new ArgumentOutOfRangeException(nameof(loggerOptions.FlushPeriod), $"{nameof(loggerOptions.FlushPeriod)} must be longer than zero.");
|
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;
|
_interval = loggerOptions.FlushPeriod;
|
||||||
_batchSize = loggerOptions.BatchSize;
|
_batchSize = loggerOptions.BatchSize;
|
||||||
|
|
||||||
Start();
|
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<LogMessage> messages, CancellationToken token);
|
protected abstract Task WriteMessagesAsync(IEnumerable<LogMessage> messages, CancellationToken token);
|
||||||
|
|
||||||
private async Task ProcessLogQueueAsync(object state)
|
private async Task ProcessLogQueueAsync(object state)
|
||||||
{
|
{
|
||||||
var startupMessage = $"{DllInfo.ApplicationName} started.{Environment.NewLine}";
|
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);
|
AddMessage(DateTimeOffset.Now, startupMessage);
|
||||||
|
|
||||||
@@ -77,7 +102,7 @@ namespace EonaCat.Logger.EonaCatCoreLogger.Internal
|
|||||||
|
|
||||||
await IntervalAsync(_interval, _cancellationTokenSource.Token).ConfigureAwait(false);
|
await IntervalAsync(_interval, _cancellationTokenSource.Token).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
await WriteMessagesAsync(new List<LogMessage> { new LogMessage { Message = $"[{DllInfo.ApplicationName}] {DllInfo.ApplicationName} stopped.{Environment.NewLine}", Timestamp = DateTimeOffset.Now } }, _cancellationTokenSource.Token).ConfigureAwait(false);
|
await WriteMessagesAsync(new List<LogMessage> { new LogMessage { Message = $"[{DllInfo.ApplicationName}] {DllInfo.ApplicationName} stopped.{Environment.NewLine}", Timestamp = CurrentDateTimeOffset } }, _cancellationTokenSource.Token).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected virtual Task IntervalAsync(TimeSpan interval, CancellationToken cancellationToken)
|
protected virtual Task IntervalAsync(TimeSpan interval, CancellationToken cancellationToken)
|
||||||
@@ -132,7 +157,7 @@ namespace EonaCat.Logger.EonaCatCoreLogger.Internal
|
|||||||
|
|
||||||
public ILogger CreateLogger(string categoryName)
|
public ILogger CreateLogger(string categoryName)
|
||||||
{
|
{
|
||||||
return new BatchingLogger(this, categoryName);
|
return new BatchingLogger(this, categoryName, LoggerSettings);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -22,7 +22,7 @@ namespace EonaCat.Logger.Managers
|
|||||||
if (settings != null)
|
if (settings != null)
|
||||||
{
|
{
|
||||||
if (sb.ToString().Contains("{ts}"))
|
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}"))
|
if (sb.ToString().Contains("{host}"))
|
||||||
sb.Replace("{host}", $"[Host:{Dns.GetHostName()}]");
|
sb.Replace("{host}", $"[Host:{Dns.GetHostName()}]");
|
||||||
|
|||||||
@@ -4,7 +4,6 @@ using Microsoft.Extensions.Logging;
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Runtime.CompilerServices;
|
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using EonaCat.Logger.EonaCatCoreLogger;
|
using EonaCat.Logger.EonaCatCoreLogger;
|
||||||
@@ -16,6 +15,7 @@ namespace EonaCat.Logger.Managers
|
|||||||
{
|
{
|
||||||
public partial class LogManager : ILogManager, IDisposable
|
public partial class LogManager : ILogManager, IDisposable
|
||||||
{
|
{
|
||||||
|
private DateTime CurrentDateTme => Settings.UseLocalTime ? DateTime.Now : DateTime.UtcNow;
|
||||||
private DateTime _logDate;
|
private DateTime _logDate;
|
||||||
public ILoggerProvider LoggerProvider { get; private set; }
|
public ILoggerProvider LoggerProvider { get; private set; }
|
||||||
public ILoggerFactory LoggerFactory { get; private set; }
|
public ILoggerFactory LoggerFactory { get; private set; }
|
||||||
@@ -30,7 +30,7 @@ namespace EonaCat.Logger.Managers
|
|||||||
|
|
||||||
public static LogManager Instance => InstanceInit();
|
public static LogManager Instance => InstanceInit();
|
||||||
|
|
||||||
public LoggerSettings Settings { get; } = CreateDefaultSettings();
|
public LoggerSettings Settings { get; set; } = CreateDefaultSettings();
|
||||||
|
|
||||||
private static LogManager InstanceInit()
|
private static LogManager InstanceInit()
|
||||||
{
|
{
|
||||||
@@ -62,9 +62,7 @@ namespace EonaCat.Logger.Managers
|
|||||||
if (_tokenSource.IsCancellationRequested)
|
if (_tokenSource.IsCancellationRequested)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
DateTime now = DateTime.UtcNow;
|
if (IsRunning && CurrentDateTme.Date > _logDate.Date)
|
||||||
|
|
||||||
if (IsRunning && now.Date > _logDate.Date)
|
|
||||||
await StopLoggingAsync().ConfigureAwait(false);
|
await StopLoggingAsync().ConfigureAwait(false);
|
||||||
|
|
||||||
IsRunning = true;
|
IsRunning = true;
|
||||||
@@ -73,7 +71,7 @@ namespace EonaCat.Logger.Managers
|
|||||||
|
|
||||||
Directory.CreateDirectory(Settings.FileLoggerOptions.LogDirectory);
|
Directory.CreateDirectory(Settings.FileLoggerOptions.LogDirectory);
|
||||||
|
|
||||||
_logDate = now;
|
_logDate = CurrentDateTme;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void CreateLogger()
|
private void CreateLogger()
|
||||||
@@ -91,6 +89,7 @@ namespace EonaCat.Logger.Managers
|
|||||||
configuration.LogDirectory = fileLoggerOptions.LogDirectory;
|
configuration.LogDirectory = fileLoggerOptions.LogDirectory;
|
||||||
configuration.FileNamePrefix = fileLoggerOptions.FileNamePrefix;
|
configuration.FileNamePrefix = fileLoggerOptions.FileNamePrefix;
|
||||||
configuration.MaxRolloverFiles = fileLoggerOptions.MaxRolloverFiles;
|
configuration.MaxRolloverFiles = fileLoggerOptions.MaxRolloverFiles;
|
||||||
|
configuration.UseLocalTime = Settings.UseLocalTime;
|
||||||
}));
|
}));
|
||||||
|
|
||||||
var serviceProvider = serviceCollection.BuildServiceProvider();
|
var serviceProvider = serviceCollection.BuildServiceProvider();
|
||||||
@@ -172,7 +171,7 @@ namespace EonaCat.Logger.Managers
|
|||||||
{
|
{
|
||||||
AppDomain.CurrentDomain.ProcessExit += ProcessExit;
|
AppDomain.CurrentDomain.ProcessExit += ProcessExit;
|
||||||
Console.CancelKeyPress += Console_CancelKeyPress;
|
Console.CancelKeyPress += Console_CancelKeyPress;
|
||||||
_logDate = DateTime.UtcNow;
|
_logDate = CurrentDateTme;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void Console_CancelKeyPress(object sender, ConsoleCancelEventArgs e)
|
private void Console_CancelKeyPress(object sender, ConsoleCancelEventArgs e)
|
||||||
@@ -188,7 +187,7 @@ namespace EonaCat.Logger.Managers
|
|||||||
private Task StopLoggingAsync()
|
private Task StopLoggingAsync()
|
||||||
{
|
{
|
||||||
IsRunning = false;
|
IsRunning = false;
|
||||||
InternalWriteAsync(DateTime.UtcNow, $"{DllInfo.ApplicationName} stopped.");
|
InternalWriteAsync(CurrentDateTme, $"{DllInfo.ApplicationName} stopped.");
|
||||||
return Task.Delay(500);
|
return Task.Delay(500);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -217,12 +216,10 @@ namespace EonaCat.Logger.Managers
|
|||||||
if (logType == ELogType.NONE)
|
if (logType == ELogType.NONE)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
var now = DateTime.UtcNow;
|
|
||||||
|
|
||||||
if (!IsRunning)
|
if (!IsRunning)
|
||||||
StartNewLogAsync().ConfigureAwait(false);
|
StartNewLogAsync().ConfigureAwait(false);
|
||||||
|
|
||||||
InternalWriteAsync(now, message, logType, writeToConsole);
|
InternalWriteAsync(CurrentDateTme, message, logType, writeToConsole);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,6 +14,11 @@ namespace EonaCat.Logger.Managers
|
|||||||
public event LogDelegate OnLog;
|
public event LogDelegate OnLog;
|
||||||
public delegate void LogDelegate(EonaCatLogMessage message);
|
public delegate void LogDelegate(EonaCatLogMessage message);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Determines if we need to use the local time in the logging or UTC (default:false)
|
||||||
|
/// </summary>
|
||||||
|
public bool UseLocalTime { get; set; }
|
||||||
|
|
||||||
public string Id { get; set; } = "EonaCatLogger";
|
public string Id { get; set; } = "EonaCatLogger";
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -135,7 +140,7 @@ namespace EonaCat.Logger.Managers
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private FileLoggerOptions CreateDefaultFileLoggerOptions()
|
private static FileLoggerOptions CreateDefaultFileLoggerOptions()
|
||||||
{
|
{
|
||||||
return new FileLoggerOptions();
|
return new FileLoggerOptions();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
using EonaCat.Logger.Managers;
|
using EonaCat.Logger.Managers;
|
||||||
using Microsoft.AspNetCore.Http.Features;
|
using System.IO.Compression;
|
||||||
using Microsoft.AspNetCore.Mvc;
|
using EonaCat.Logger.Extensions;
|
||||||
using System.Net;
|
|
||||||
|
|
||||||
namespace EonaCat.Logger.Test.Web
|
namespace EonaCat.Logger.Test.Web
|
||||||
{
|
{
|
||||||
@@ -30,114 +29,64 @@ namespace EonaCat.Logger.Test.Web
|
|||||||
LogManager.DeleteCurrentLogFile();
|
LogManager.DeleteCurrentLogFile();
|
||||||
}
|
}
|
||||||
|
|
||||||
internal static IActionResult DownloadLogAsync(HttpResponse response, string logFile)
|
private static string ConvertToAbsolutePath(string path)
|
||||||
{
|
{
|
||||||
if (IsDisabled)
|
return Path.IsPathRooted(path) ? path : Path.Combine(LogFolder, path);
|
||||||
{
|
|
||||||
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();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void DisableResponseBuffering(HttpResponse response)
|
public static async Task DownloadLogAsync(HttpContext context, string logName, long limit)
|
||||||
{
|
{
|
||||||
var httpContext = response.HttpContext;
|
var logFileName = logName + ".log";
|
||||||
var responseBodyFeature = httpContext.Features.Get<IHttpResponseBodyFeature>();
|
|
||||||
if (responseBodyFeature != null)
|
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;
|
||||||
}
|
}
|
||||||
}
|
else
|
||||||
|
|
||||||
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))
|
|
||||||
{
|
{
|
||||||
try
|
string[] acceptEncodingParts = acceptEncoding.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries);
|
||||||
|
|
||||||
|
if (acceptEncodingParts.Contains("br"))
|
||||||
{
|
{
|
||||||
// Clear the response first
|
response.Headers.ContentEncoding = "br";
|
||||||
response.Clear();
|
s = new BrotliStream(response.Body, CompressionMode.Compress);
|
||||||
|
|
||||||
// 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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
catch (OperationCanceledException)
|
else if (acceptEncodingParts.Contains("gzip"))
|
||||||
{
|
{
|
||||||
// The operation was canceled, clean up if necessary
|
response.Headers.ContentEncoding = "gzip";
|
||||||
fileStream.Close();
|
s = new GZipStream(response.Body, CompressionMode.Compress);
|
||||||
}
|
}
|
||||||
finally
|
else if (acceptEncodingParts.Contains("deflate"))
|
||||||
{
|
{
|
||||||
|
response.Headers.ContentEncoding = "deflate";
|
||||||
try
|
s = new DeflateStream(response.Body, CompressionMode.Compress);
|
||||||
{
|
|
||||||
// Flush and close the output stream
|
|
||||||
await outputStream.FlushAsync(cancellationToken).ConfigureAwait(false);
|
|
||||||
}
|
|
||||||
catch (ObjectDisposedException e)
|
|
||||||
{
|
|
||||||
Log(e, "StreamFileContentAsync");
|
|
||||||
}
|
|
||||||
finally
|
|
||||||
{
|
|
||||||
outputStream?.Close();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user