using EonaCat.Logger.Syslog; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; using System; using System.Collections.Generic; using System.IO; using System.Threading; using System.Threading.Tasks; using EonaCat.Logger.EonaCatCoreLogger; using EonaCat.Logger.EonaCatCoreLogger.Extensions; using EonaCat.Logger.EonaCatCoreLogger.Models; using EonaCat.Logger.Extensions; 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; } public ILogger Logger { get; private set; } public string CurrentLogFile => LoggerProvider is FileLoggerProvider fileLoggerProvider ? fileLoggerProvider.LogFile : string.Empty; public bool IsRunning { get; private set; } private static LogManager _instance; private readonly CancellationTokenSource _tokenSource = new CancellationTokenSource(); public static LogManager Instance => InstanceInit(); public LoggerSettings Settings { get; set; } = CreateDefaultSettings(); private static LogManager InstanceInit() { if (_instance == null) { _instance = new LogManager(CreateDefaultSettings()); } return _instance; } private static LoggerSettings CreateDefaultSettings() { var settings = new LoggerSettings(); settings.Id = "EonaCatLogger"; settings.MaxLogType = ELogType.TRACE; return settings; } protected virtual async Task DisposeAsync(bool disposing) { if (disposing) { await StopLoggingAsync().ConfigureAwait(false); } } public async Task StartNewLogAsync() { if (_tokenSource.IsCancellationRequested) return; if (IsRunning && CurrentDateTme.Date > _logDate.Date) await StopLoggingAsync().ConfigureAwait(false); IsRunning = true; CreateLogger(); Directory.CreateDirectory(Settings.FileLoggerOptions.LogDirectory); _logDate = CurrentDateTme; } private void CreateLogger() { IServiceCollection serviceCollection = new ServiceCollection(); serviceCollection.AddLogging(builder => builder.SetMinimumLevel(Settings.MaxLogType.ToLogLevel()).AddEonaCatFileLogger(configuration => { var fileLoggerOptions = Settings.FileLoggerOptions; configuration.MaxWriteTries = fileLoggerOptions.MaxWriteTries; configuration.RetainedFileCountLimit = fileLoggerOptions.RetainedFileCountLimit; configuration.FlushPeriod = fileLoggerOptions.FlushPeriod; configuration.IsEnabled = fileLoggerOptions.IsEnabled; configuration.BatchSize = fileLoggerOptions.BatchSize; configuration.FileSizeLimit = fileLoggerOptions.FileSizeLimit; configuration.LogDirectory = fileLoggerOptions.LogDirectory; configuration.FileNamePrefix = fileLoggerOptions.FileNamePrefix; configuration.MaxRolloverFiles = fileLoggerOptions.MaxRolloverFiles; configuration.UseLocalTime = Settings.UseLocalTime; })); var serviceProvider = serviceCollection.BuildServiceProvider(); LoggerProvider = serviceProvider.GetService(); LoggerFactory = serviceProvider.GetService(); Logger = LoggerFactory.CreateLogger(Settings.Id); } private void InternalWriteAsync(DateTime dateTime, string message, ELogType logType = ELogType.INFO, bool? writeToConsole = null) { if (string.IsNullOrEmpty(message) || logType == ELogType.NONE || (int)logType >= (int)Settings.MaxLogType) return; var messageWithHeader = LogHelper.FormatMessageWithHeader(Settings, logType, message, dateTime); writeToConsole ??= Settings.EnableConsole; if (writeToConsole.Value) { LogHelper.SendToConsole(Settings, logType, messageWithHeader, true); } Task.Run(() => { LogHelper.SendToFile(Logger, Settings, logType, message); }); Task.Run(() => { LogHelper.SendToSysLogServers(Settings, messageWithHeader); }); var logMessage = new EonaCatLogMessage { DateTime = dateTime, Message = message, LogType = logType, Origin = string.IsNullOrWhiteSpace(Settings.LogOrigin) ? "LogManager" : Settings.LogOrigin }; Settings.OnLogEvent(logMessage); } public void Reset() => Settings.ResetLogEvent(); public LogManager(LoggerSettings settings, string serverIp, int serverPort) { if (string.IsNullOrEmpty(serverIp)) throw new ArgumentNullException(nameof(serverIp)); if (serverPort < 0) throw new ArgumentException("Server port must be zero or greater."); settings.SysLogServers = new List { new SyslogServer(serverIp, serverPort) }; Settings = settings; SetupLogManager(); } public LogManager(LoggerSettings settings) { Settings = settings; SetupFileLogger(settings, null, true); SetupLogManager(); } private void SetupFileLogger(LoggerSettings settings = null, string logFolder = null, bool defaultPrefix = true) { if (settings == null) settings = Settings; if (!settings.EnableFileLogging) return; if (logFolder != null) settings.FileLoggerOptions.LogDirectory = logFolder; if (string.IsNullOrWhiteSpace(settings.FileLoggerOptions.FileNamePrefix)) settings.FileLoggerOptions.FileNamePrefix = defaultPrefix ? "EonaCat" : string.Empty; } private void SetupLogManager() { AppDomain.CurrentDomain.ProcessExit += ProcessExit; Console.CancelKeyPress += Console_CancelKeyPress; _logDate = CurrentDateTme; } private void Console_CancelKeyPress(object sender, ConsoleCancelEventArgs e) { Dispose(); } private void ProcessExit(object sender, EventArgs e) { Dispose(); } private Task StopLoggingAsync() { IsRunning = false; InternalWriteAsync(CurrentDateTme, $"{DllInfo.ApplicationName} stopped."); return Task.Delay(500); } public void DeleteCurrentLogFile() { if (CurrentLogFile != null) File.Delete(CurrentLogFile); } public void Dispose() { DisposeAsync(true).GetAwaiter().GetResult(); GC.SuppressFinalize(this); } public void Write(Exception exception, string module = null, string method = null, bool criticalException = false, bool? writeToConsole = null) { if (exception == null) return; Write(exception.FormatExceptionToMessage(module, method), criticalException ? ELogType.CRITICAL : ELogType.ERROR, writeToConsole); } public void Write(string message, ELogType logType = ELogType.INFO, bool? writeToConsole = null) { if (logType == ELogType.NONE) return; if (!IsRunning) StartNewLogAsync().ConfigureAwait(false); InternalWriteAsync(CurrentDateTme, message, logType, writeToConsole); } } }