using System;
using System.Collections.Concurrent;
using System.IO;
using System.Threading;
using System.Threading.Tasks;
using Swan.Lite.Logging;
using Swan.Threading;
namespace Swan.Logging
{
///
/// A helper class to write into files the messages sent by the .
///
///
public class FileLogger : TextLogger, ILogger
{
private readonly ManualResetEventSlim _doneEvent = new ManualResetEventSlim(true);
private readonly ConcurrentQueue _logQueue = new ConcurrentQueue();
private readonly ExclusiveTimer _timer;
private readonly string _filePath;
private bool _disposedValue; // To detect redundant calls
///
/// Initializes a new instance of the class.
///
public FileLogger()
: this(SwanRuntime.EntryAssemblyDirectory, true)
{
}
///
/// Initializes a new instance of the class.
///
/// The filePath.
/// if set to true [daily file].
public FileLogger(string filePath, bool dailyFile)
{
_filePath = filePath;
DailyFile = dailyFile;
_timer = new ExclusiveTimer(
async () => await WriteLogEntries().ConfigureAwait(false),
TimeSpan.Zero,
TimeSpan.FromSeconds(5));
}
///
public LogLevel LogLevel { get; set; }
///
/// Gets the file path.
///
///
/// The file path.
///
public string FilePath => DailyFile
? Path.Combine(Path.GetDirectoryName(_filePath), Path.GetFileNameWithoutExtension(_filePath) + $"_{DateTime.UtcNow:yyyyMMdd}" + Path.GetExtension(_filePath))
: _filePath;
///
/// Gets a value indicating whether [daily file].
///
///
/// true if [daily file]; otherwise, false.
///
public bool DailyFile { get; }
///
public void Log(LogMessageReceivedEventArgs logEvent)
{
var (outputMessage, _) = GetOutputAndColor(logEvent);
_logQueue.Enqueue(outputMessage);
}
///
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
///
/// Releases unmanaged and - optionally - managed resources.
///
/// true to release both managed and unmanaged resources; false to release only unmanaged resources.
protected virtual void Dispose(bool disposing)
{
if (_disposedValue) return;
if (disposing)
{
_timer.Pause();
_timer.Dispose();
_doneEvent.Wait();
_doneEvent.Reset();
WriteLogEntries(true).Await();
_doneEvent.Dispose();
}
_disposedValue = true;
}
private async Task WriteLogEntries(bool finalCall = false)
{
if (_logQueue.IsEmpty)
return;
if (!finalCall && !_doneEvent.IsSet)
return;
_doneEvent.Reset();
try
{
using (var file = File.AppendText(FilePath))
{
while (!_logQueue.IsEmpty)
{
if (_logQueue.TryDequeue(out var entry))
await file.WriteAsync(entry).ConfigureAwait(false);
}
}
}
finally
{
if (!finalCall)
_doneEvent.Set();
}
}
}
}