diff --git a/SfeduSchedule/Controllers/ScheduleController.cs b/SfeduSchedule/Controllers/ScheduleController.cs index 40e97ec..25a5141 100644 --- a/SfeduSchedule/Controllers/ScheduleController.cs +++ b/SfeduSchedule/Controllers/ScheduleController.cs @@ -1,10 +1,7 @@ -using System.Net; using System.Text; -using System.Text.Json; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.RateLimiting; -using ModeusSchedule.Abstractions; using ModeusSchedule.Abstractions.DTO; using SfeduSchedule.Services; diff --git a/SfeduSchedule/Logging/ConsoleFormatter.cs b/SfeduSchedule/Logging/ConsoleFormatter.cs new file mode 100644 index 0000000..00452e1 --- /dev/null +++ b/SfeduSchedule/Logging/ConsoleFormatter.cs @@ -0,0 +1,124 @@ +using Microsoft.Extensions.Logging.Abstractions; +using Microsoft.Extensions.Logging.Console; +using Microsoft.Extensions.Options; + +namespace SfeduSchedule.Logging; + +public sealed class ConsoleFormatter : Microsoft.Extensions.Logging.Console.ConsoleFormatter, IDisposable +{ + private readonly IDisposable? _optionsReloadToken; + private ConsoleFormatterOptions _formatterOptions; + + public ConsoleFormatter(IOptionsMonitor options) + : base("CustomConsoleFormatter") + { + _optionsReloadToken = options.OnChange(ReloadLoggerOptions); + _formatterOptions = options.CurrentValue; + } + + private void ReloadLoggerOptions(ConsoleFormatterOptions options) + { + _formatterOptions = options; + } + + public override void Write(in LogEntry logEntry, IExternalScopeProvider? scopeProvider, TextWriter textWriter) + { + var message = logEntry.Formatter(logEntry.State, logEntry.Exception); + if (logEntry.Exception == null && message == null) + { + return; + } + + // Timestamp + if (!string.IsNullOrEmpty(_formatterOptions.TimestampFormat)) + { + textWriter.Write(DateTime.Now.ToString(_formatterOptions.TimestampFormat)); + } + + // Level + + // Нужно для удаления цвета в логах при перенаправлении вывода + var useColor = _formatterOptions.ColorBehavior == LoggerColorBehavior.Enabled || + (_formatterOptions.ColorBehavior == LoggerColorBehavior.Default && !System.Console.IsOutputRedirected); + + textWriter.Write(GetLogLevelString(logEntry.LogLevel, useColor)); + + // Write : + textWriter.Write(":"); + + // TraceId + var traceIdHolder = new TraceIdHolder(); + scopeProvider?.ForEachScope((scope, state) => + { + if (scope is not IEnumerable> props) return; + foreach (var pair in props) + { + if (pair.Key == "TraceId") + state.TraceId = pair.Value?.ToString(); + } + }, traceIdHolder); + + if (!string.IsNullOrEmpty(traceIdHolder.TraceId)) + { + textWriter.Write($" [{traceIdHolder.TraceId}]"); + } + + // Category + textWriter.Write($" {logEntry.Category}: "); + + // Message + textWriter.WriteLine(message); + + if (logEntry.Exception != null) + { + textWriter.WriteLine(logEntry.Exception.ToString()); + } + } + + private static string GetLogLevelString(LogLevel logLevel, bool useColor) + { + var logLevelString = logLevel switch + { + LogLevel.Trace => "trce", + LogLevel.Debug => "dbug", + LogLevel.Information => "info", + LogLevel.Warning => "warn", + LogLevel.Error => "fail", + LogLevel.Critical => "crit", + _ => "unknown" + }; + + if (!useColor) + { + return logLevelString; + } + + var color = logLevel switch + { + LogLevel.Trace => "\x1B[90m", + LogLevel.Debug => "\x1B[37m", + LogLevel.Information => "\x1B[32m", + LogLevel.Warning => "\x1B[33m", + LogLevel.Error => "\x1B[31m", + LogLevel.Critical => "\x1B[41m\x1B[37m", + _ => "\x1B[39m" + }; + + return $"{color}{logLevelString}\x1B[0m"; + } + + public void Dispose() + { + _optionsReloadToken?.Dispose(); + } +} + +public class ConsoleFormatterOptions : Microsoft.Extensions.Logging.Console.ConsoleFormatterOptions +{ + public LoggerColorBehavior ColorBehavior { get; set; } +} + +internal class TraceIdHolder +{ + public string? TraceId { get; set; } +} diff --git a/SfeduSchedule/Program.cs b/SfeduSchedule/Program.cs index ecf9c74..74f3f49 100644 --- a/SfeduSchedule/Program.cs +++ b/SfeduSchedule/Program.cs @@ -1,5 +1,4 @@ using System.Net; -using System.Diagnostics; using System.Reflection; using System.Threading.RateLimiting; using Microsoft.AspNetCore.Authentication; @@ -14,11 +13,10 @@ using Quartz; using SfeduSchedule; using SfeduSchedule.Auth; using SfeduSchedule.Jobs; +using SfeduSchedule.Logging; using SfeduSchedule.Middleware; using SfeduSchedule.Services; -using SfeduSchedule.Logging; using X.Extensions.Logging.Telegram.Extensions; -using Microsoft.Extensions.Logging.Console; using IPNetwork = Microsoft.AspNetCore.HttpOverrides.IPNetwork; var builder = WebApplication.CreateBuilder(args); @@ -53,12 +51,9 @@ var pluginsPath = Path.Combine(dataDirectory, "Plugins"); #region Работа с логированием builder.Logging.ClearProviders(); -// Configure the console logger to include logging scopes so TraceId from the CorrelationIdMiddleware is visible -builder.Logging.AddSimpleConsole(options => -{ - options.SingleLine = true; - options.TimestampFormat = "yyyy-MM-dd HH:mm:ss.fff "; -}); +builder.Logging.AddConsole(options => options.FormatterName = "CustomConsoleFormatter") + .AddConsoleFormatter(); + builder.Logging.AddFilter("Quartz", LogLevel.Warning); if (!string.IsNullOrEmpty(tgChatId) && !string.IsNullOrEmpty(tgToken)) builder.Logging.AddTelegram(options =>