* Added Logging abstraction for base library

* Version incremented
This commit is contained in:
2025-08-03 03:29:15 +04:00
parent 34ac0231d5
commit a87a07d939
13 changed files with 374 additions and 128 deletions
-122
View File
@@ -1,122 +0,0 @@
using System.Diagnostics;
namespace Telegrator
{
/// <summary>
/// Telegrator's FUNNY debug logger helper
/// </summary>
public static class Alligator
{
/// <summary>
/// Gets or sets flags of what trace messages to write
/// </summary>
public static DebugLevel Allowed { get; set; } = DebugLevel.None;
/// <summary>
/// Writes trace message if Indent level has Router flag
/// </summary>
/// <param name="message"></param>
public static void RouterWriteLine(string message)
{
if (Allowed.HasFlag(DebugLevel.Router))
Trace.WriteLine(message);
}
/// <summary>
/// Writes debug message if Indent level has Router flag
/// </summary>
/// <param name="message"></param>
/// <param name="args"></param>
public static void RouterWriteLine(string message, params object[] args)
{
if (Allowed.HasFlag(DebugLevel.Router))
Trace.WriteLine(string.Format(message, args));
}
/// <summary>
/// Writes trace message if Indent level has Providers flag
/// </summary>
/// <param name="message"></param>
public static void ProviderWriteLine(string message)
{
if (Allowed.HasFlag(DebugLevel.Providers))
Trace.WriteLine(message);
}
/// <summary>
/// Writes trace message if Indent level has Providers flag
/// </summary>
/// <param name="message"></param>
/// <param name="args"></param>
public static void ProviderWriteLine(string message, params object[] args)
{
if (Allowed.HasFlag(DebugLevel.Providers))
Trace.WriteLine(string.Format(message, args));
}
/// <summary>
/// Writes trace message if Indent level has Filters flag
/// </summary>
/// <param name="message"></param>
public static void FilterWriteLine(string message)
{
if (Allowed.HasFlag(DebugLevel.Filters))
Trace.WriteLine(message);
}
/// <summary>
/// Writes trace message if Indent level has Filters flag
/// </summary>
/// <param name="message"></param>
/// <param name="args"></param>
public static void FilterWriteLine(string message, params object[] args)
{
if (Allowed.HasFlag(DebugLevel.Filters))
Trace.WriteLine(string.Format(message, args));
}
/// <summary>
/// Writes trace message if Indent level has Pool flag
/// </summary>
/// <param name="message"></param>
public static void PoolWriteLine(string message)
{
if (Allowed.HasFlag(DebugLevel.HandlersPool))
Trace.WriteLine(message);
}
/// <summary>
/// Writes trace message if Indent level has Pool flag
/// </summary>
/// <param name="message"></param>
/// <param name="args"></param>
public static void PoolWriteLine(string message, params object[] args)
{
if (Allowed.HasFlag(DebugLevel.HandlersPool))
Trace.WriteLine(string.Format(message, args));
}
/// <summary>
/// Writes trace message if flag was set
/// </summary>
/// <param name="level"></param>
/// <param name="message"></param>
public static void WriteLine(DebugLevel level, string message)
{
if (Allowed.HasFlag(level))
Trace.WriteLine(message);
}
/// <summary>
/// Writes trace message if flag was set
/// </summary>
/// <param name="level"></param>
/// <param name="message"></param>
/// <param name="args"></param>
public static void WriteLine(DebugLevel level, string message, params object[] args)
{
if (Allowed.HasFlag(level))
Trace.WriteLine(string.Format(message, args));
}
}
}
+145
View File
@@ -0,0 +1,145 @@
namespace Telegrator.Logging
{
/// <summary>
/// Centralized logging system for Telegrator.
/// Provides static access to logging functionality with adapter support.
/// </summary>
public static class Alligator
{
private static readonly List<ITelegratorLogger> _adapters = new();
private static readonly object _lock = new();
/// <summary>
/// Gets the current adapters count.
/// </summary>
public static int AdaptersCount => _adapters.Count;
/// <summary>
/// Adds a logger adapter to the centralized logging system.
/// </summary>
/// <param name="adapter">The logger adapter to add.</param>
public static void AddAdapter(ITelegratorLogger adapter)
{
if (adapter == null)
throw new ArgumentNullException(nameof(adapter));
lock (_lock)
{
if (!_adapters.Contains(adapter))
{
_adapters.Add(adapter);
}
}
}
/// <summary>
/// Removes a logger adapter from the centralized logging system.
/// </summary>
/// <param name="adapter">The logger adapter to remove.</param>
public static void RemoveAdapter(ITelegratorLogger adapter)
{
if (adapter == null)
return;
lock (_lock)
{
_adapters.Remove(adapter);
}
}
/// <summary>
/// Clears all logger adapters.
/// </summary>
public static void ClearAdapters()
{
lock (_lock)
{
_adapters.Clear();
}
}
/// <summary>
/// Logs a message to all registered adapters.
/// </summary>
/// <param name="level">The log level.</param>
/// <param name="message">The message to log.</param>
/// <param name="exception">Optional exception.</param>
public static void Log(LogLevel level, string message, Exception? exception = null)
{
// Fast path: if no adapters, do nothing
if (_adapters.Count == 0)
return;
// Lock only during enumeration to prevent collection modification during iteration
lock (_lock)
{
foreach (var adapter in _adapters)
{
try
{
adapter.Log(level, message, exception);
}
catch
{
_ = 0xBAD + 0xC0DE; // Ignore adapter errors to prevent logging failures
}
}
}
}
/// <summary>
/// Logs a trace message to all registered adapters.
/// </summary>
/// <param name="message">The message to log.</param>
public static void LogTrace(string message)
{
Log(LogLevel.Trace, message);
}
/// <summary>
/// Logs a debug message to all registered adapters.
/// </summary>
/// <param name="message">The message to log.</param>
public static void LogDebug(string message)
{
Log(LogLevel.Debug, message);
}
/// <summary>
/// Logs an information message to all registered adapters.
/// </summary>
/// <param name="message">The message to log.</param>
public static void LogInformation(string message)
{
Log(LogLevel.Information, message);
}
/// <summary>
/// Logs a warning message to all registered adapters.
/// </summary>
/// <param name="message">The message to log.</param>
public static void LogWarning(string message)
{
Log(LogLevel.Warning, message);
}
/// <summary>
/// Logs an error message to all registered adapters.
/// </summary>
/// <param name="message">The message to log.</param>
/// <param name="exception">Optional exception.</param>
public static void LogError(string message, Exception? exception = null)
{
Log(LogLevel.Error, message, exception);
}
/// <summary>
/// Logs an error message with exception only to all registered adapters.
/// </summary>
/// <param name="exception">The exception to log.</param>
public static void LogError(Exception exception)
{
Log(LogLevel.Error, exception.Message, exception);
}
}
}
+70
View File
@@ -0,0 +1,70 @@
using System;
namespace Telegrator.Logging
{
/// <summary>
/// Console logger implementation that writes to System.Console.
/// This logger is optional and can be used for simple console output.
/// </summary>
public class ConsoleLogger : ITelegratorLogger
{
private readonly LogLevel _minimumLevel;
private readonly bool _includeTimestamp;
/// <summary>
/// Initializes a new instance of ConsoleLogger.
/// </summary>
/// <param name="minimumLevel">Minimum log level to output. Default is Information.</param>
/// <param name="includeTimestamp">Whether to include timestamp in log messages. Default is true.</param>
public ConsoleLogger(LogLevel minimumLevel = LogLevel.Information, bool includeTimestamp = true)
{
_minimumLevel = minimumLevel;
_includeTimestamp = includeTimestamp;
}
/// <inheritdoc/>
public void Log(LogLevel level, string message, Exception? exception = null)
{
if (level < _minimumLevel)
return;
var timestamp = _includeTimestamp ? $"[{DateTime.Now:yyyy-MM-dd HH:mm:ss.fff}] " : "";
var levelStr = $"[{level.ToString().ToUpper()}] ";
var logMessage = $"{timestamp}{levelStr}{message}";
// Add exception if present
if (exception != null)
{
logMessage += $" | Exception: {exception.Message}";
}
// Write to console with appropriate color
var originalColor = Console.ForegroundColor;
try
{
Console.ForegroundColor = level switch
{
LogLevel.Trace => ConsoleColor.Gray,
LogLevel.Debug => ConsoleColor.Cyan,
LogLevel.Information => ConsoleColor.White,
LogLevel.Warning => ConsoleColor.Yellow,
LogLevel.Error => ConsoleColor.Red,
_ => ConsoleColor.White
};
Console.WriteLine(logMessage);
// Write exception details if present
if (exception != null)
{
Console.ForegroundColor = ConsoleColor.Red;
Console.WriteLine($"Exception Details: {exception}");
}
}
finally
{
Console.ForegroundColor = originalColor;
}
}
}
}
+50
View File
@@ -0,0 +1,50 @@
using System;
namespace Telegrator.Logging
{
/// <summary>
/// Interface for Telegrator logging system.
/// Provides abstraction for logging without external dependencies.
/// </summary>
public interface ITelegratorLogger
{
/// <summary>
/// Logs a message with specified level.
/// </summary>
/// <param name="level">The log level.</param>
/// <param name="message">The message to log.</param>
/// <param name="exception">Optional exception.</param>
void Log(LogLevel level, string message, Exception? exception = null);
}
/// <summary>
/// Log levels for Telegrator logging system.
/// </summary>
public enum LogLevel
{
/// <summary>
/// Trace level - most detailed logging.
/// </summary>
Trace = 0,
/// <summary>
/// Debug level - detailed debugging information.
/// </summary>
Debug = 1,
/// <summary>
/// Information level - general information.
/// </summary>
Information = 2,
/// <summary>
/// Warning level - warning messages.
/// </summary>
Warning = 3,
/// <summary>
/// Error level - error messages.
/// </summary>
Error = 4
}
}
+21
View File
@@ -0,0 +1,21 @@
using System;
namespace Telegrator.Logging
{
/// <summary>
/// Null logger implementation that does nothing.
/// Used when logging is not required or disabled.
/// </summary>
public class NullLogger : ITelegratorLogger
{
/// <summary>
/// Singleton instance of NullLogger.
/// </summary>
public static readonly NullLogger Instance = new();
private NullLogger() { }
/// <inheritdoc/>
public void Log(LogLevel level, string message, Exception? exception = null) { }
}
}
+1 -1
View File
@@ -17,7 +17,7 @@
<EnableNETAnalyzers>True</EnableNETAnalyzers>
<EnforceCodeStyleInBuild>True</EnforceCodeStyleInBuild>
<PackageLicenseFile>LICENSE</PackageLicenseFile>
<Version>1.0.9</Version>
<Version>1.0.10</Version>
</PropertyGroup>
<ItemGroup>
+21 -3
View File
@@ -1,6 +1,7 @@
using Telegram.Bot;
using Telegram.Bot.Polling;
using Telegrator.Configuration;
using Telegrator.Logging;
using Telegrator.MadiatorCore;
using Telegrator.Polling;
using Telegrator.Providers;
@@ -37,7 +38,7 @@ namespace Telegrator
/// <param name="httpClient">Optional HTTP client for making requests.</param>
/// <param name="cancellationToken">The cancellation token.</param>
public TelegratorClient(string token, HttpClient? httpClient = null, CancellationToken cancellationToken = default)
: this(new TelegramBotClientOptions(token), httpClient, cancellationToken) { }
: this(new TelegramBotClientOptions(token), null, httpClient, cancellationToken) { }
/// <summary>
/// Initializes a new instance of the <see cref="TelegratorClient"/> class with bot options.
@@ -45,9 +46,19 @@ namespace Telegrator
/// <param name="options">The Telegram bot client options.</param>
/// <param name="httpClient">Optional HTTP client for making requests.</param>
/// <param name="cancellationToken">The cancellation token.</param>
public TelegratorClient(TelegramBotClientOptions options, HttpClient? httpClient = null, CancellationToken cancellationToken = default) : base(options, httpClient, cancellationToken)
public TelegratorClient(TelegramBotClientOptions options, HttpClient? httpClient = null, CancellationToken cancellationToken = default)
: this(options, null, httpClient, cancellationToken) { }
/// <summary>
/// Initializes a new instance of the <see cref="TelegratorClient"/> class with bot options and Telegrator options.
/// </summary>
/// <param name="options">The Telegram bot client options.</param>
/// <param name="telegratorOptions">The Telegrator options.</param>
/// <param name="httpClient">Optional HTTP client for making requests.</param>
/// <param name="cancellationToken">The cancellation token.</param>
public TelegratorClient(TelegramBotClientOptions options, TelegratorOptions? telegratorOptions, HttpClient? httpClient = null, CancellationToken cancellationToken = default) : base(options, httpClient, cancellationToken)
{
Options = new TelegratorOptions();
Options = telegratorOptions ?? new TelegratorOptions();
Handlers = new HandlersCollection(default);
BotInfo = new TelegramBotInfo(this.GetMe(cancellationToken).Result);
}
@@ -67,6 +78,10 @@ namespace Telegrator
AwaitingProvider awaitingProvider = new AwaitingProvider(Options);
updateRouter = new UpdateRouter(handlerProvider, awaitingProvider, Options, BotInfo);
// Log startup
Alligator.LogInformation($"Telegrator bot starting up - BotId: {BotInfo.Id}, Username: {BotInfo.Username}, MaxParallelHandlers: {Options.MaximumParallelWorkingHandlers ?? -1}");
StartReceivingInternal(receiverOptions, cancellationToken);
}
@@ -96,7 +111,10 @@ namespace Telegrator
catch (OperationCanceledException)
{
// Cancelled
Alligator.LogInformation("Telegrator bot stopped (cancelled)");
}
}
}
}