diff --git a/X.Serilog.Sinks.Telegram.sln b/X.Serilog.Sinks.Telegram.sln
index 8396d0d..d4db7ff 100644
--- a/X.Serilog.Sinks.Telegram.sln
+++ b/X.Serilog.Sinks.Telegram.sln
@@ -8,6 +8,8 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "examples", "examples", "{4A
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WebApp", "examples\WebApp\WebApp.csproj", "{15736D36-94A1-4E3F-8A5F-EFEFE27F1995}"
EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ConsoleApp", "examples\ConsoleApp\ConsoleApp.csproj", "{D007F793-195D-448A-A34E-74EF0245F9D3}"
+EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@@ -22,9 +24,14 @@ Global
{15736D36-94A1-4E3F-8A5F-EFEFE27F1995}.Debug|Any CPU.Build.0 = Debug|Any CPU
{15736D36-94A1-4E3F-8A5F-EFEFE27F1995}.Release|Any CPU.ActiveCfg = Release|Any CPU
{15736D36-94A1-4E3F-8A5F-EFEFE27F1995}.Release|Any CPU.Build.0 = Release|Any CPU
+ {D007F793-195D-448A-A34E-74EF0245F9D3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {D007F793-195D-448A-A34E-74EF0245F9D3}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {D007F793-195D-448A-A34E-74EF0245F9D3}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {D007F793-195D-448A-A34E-74EF0245F9D3}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(NestedProjects) = preSolution
{807F309C-4CE3-4E68-8D46-9044A0A7BD6A} = {652C6F31-3E8C-400E-9716-ACF591E48E6F}
{15736D36-94A1-4E3F-8A5F-EFEFE27F1995} = {4A2DA76C-10DE-476D-A26E-16FAB3CBFC8C}
+ {D007F793-195D-448A-A34E-74EF0245F9D3} = {4A2DA76C-10DE-476D-A26E-16FAB3CBFC8C}
EndGlobalSection
EndGlobal
diff --git a/examples/ConsoleApp/ConsoleApp.csproj b/examples/ConsoleApp/ConsoleApp.csproj
new file mode 100644
index 0000000..b6ebeec
--- /dev/null
+++ b/examples/ConsoleApp/ConsoleApp.csproj
@@ -0,0 +1,19 @@
+
+
+
+ Exe
+ net8.0
+ enable
+ enable
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/examples/ConsoleApp/Program.cs b/examples/ConsoleApp/Program.cs
new file mode 100644
index 0000000..b72b8b7
--- /dev/null
+++ b/examples/ConsoleApp/Program.cs
@@ -0,0 +1,22 @@
+using Serilog;
+using Serilog.Events;
+using X.Serilog.Sinks.Telegram.Extensions;
+
+const string botToken = "TELEGRAM_BOT_TOKEN";
+const string loggingChatId = "CHANNEL_OR_CHAT_ID";
+
+Log.Logger = new LoggerConfiguration()
+ .WriteTo.TelegramCore(
+ token: botToken,
+ chatId: loggingChatId,
+ logLevel: LogEventLevel.Verbose)
+ .WriteTo.Console()
+ .CreateLogger();
+
+
+while (true)
+{
+ var level = Random.Shared.NextInt64(0, 6);
+ Log.Logger.Write((LogEventLevel)level, "Message");
+ await Task.Delay(500);
+}
\ No newline at end of file
diff --git a/examples/WebApp/Program.cs b/examples/WebApp/Program.cs
index 084e75d..e22ff1a 100644
--- a/examples/WebApp/Program.cs
+++ b/examples/WebApp/Program.cs
@@ -7,6 +7,7 @@
using X.Serilog.Sinks.Telegram;
using X.Serilog.Sinks.Telegram.Batch.Rules;
using X.Serilog.Sinks.Telegram.Configuration;
+using X.Serilog.Sinks.Telegram.Extensions;
using X.Serilog.Sinks.Telegram.Filters;
var builder = WebApplication.CreateBuilder(args);
diff --git a/examples/WebApp/WebApp.csproj b/examples/WebApp/WebApp.csproj
index 8d4a0ad..62db7f4 100644
--- a/examples/WebApp/WebApp.csproj
+++ b/examples/WebApp/WebApp.csproj
@@ -7,8 +7,9 @@
-
-
+
+
+
diff --git a/src/X.Serilog.Sinks.Telegram/Configuration/BatchEmittingRulesConfiguration.cs b/src/X.Serilog.Sinks.Telegram/Configuration/BatchEmittingRulesConfiguration.cs
index db5515d..d33f4bf 100644
--- a/src/X.Serilog.Sinks.Telegram/Configuration/BatchEmittingRulesConfiguration.cs
+++ b/src/X.Serilog.Sinks.Telegram/Configuration/BatchEmittingRulesConfiguration.cs
@@ -40,15 +40,7 @@ public TimeSpan RuleCheckPeriod
///
public IImmutableList BatchProcessingExecutionHooks
=> BatchProcessingRules
- .Select(rule =>
- {
- if (rule is IExecutionHook hook)
- {
- return hook;
- }
-
- return null;
- })
- .Where(hook => hook != null)
- .ToImmutableList()!;
+ .Where(rule => rule is IExecutionHook)
+ .Cast()
+ .ToImmutableList();
}
\ No newline at end of file
diff --git a/src/X.Serilog.Sinks.Telegram/Configuration/TelegramSinkDefaults.cs b/src/X.Serilog.Sinks.Telegram/Configuration/TelegramSinkDefaults.cs
index c6d987d..9bef296 100644
--- a/src/X.Serilog.Sinks.Telegram/Configuration/TelegramSinkDefaults.cs
+++ b/src/X.Serilog.Sinks.Telegram/Configuration/TelegramSinkDefaults.cs
@@ -7,6 +7,32 @@ namespace X.Serilog.Sinks.Telegram.Configuration;
///
public static class TelegramSinkDefaults
{
+ ///
+ /// Gets the logging mode for the application.
+ ///
+ ///
+ /// The logging mode determines how log messages are processed and formatted before being sent.
+ /// In this case, it is set to return , which indicates that log messages
+ /// will be published individually to the specified Telegram channel.
+ ///
+ ///
+ /// This property is read-only and returns the default logging mode of the system.
+ /// It is crucial for configuring the overall logging strategy of the application.
+ /// For example, when set to , each log message is sent as it occurs.
+ /// Other modes, like , could aggregate messages over a period
+ /// or until a certain condition is met before sending.
+ ///
+ public static LoggingMode DefaultFormatterMode => LoggingMode.AggregatedNotifications;
+
+ public static FormatterConfiguration DefaultFormatterConfiguration => new()
+ {
+ UseEmoji = true,
+ ReadableApplicationName = "X.Serilog.Telegram.Sink",
+ IncludeException = false,
+ IncludeProperties = false,
+ TimeZone = TimeZoneInfo.Utc
+ };
+
///
/// The limit on the number of log events to be included in a single batch.
///
diff --git a/src/X.Serilog.Sinks.Telegram/Extensions/DependencyInjectionExtensions.cs b/src/X.Serilog.Sinks.Telegram/Extensions/DependencyInjectionExtensions.cs
new file mode 100644
index 0000000..f0f6c35
--- /dev/null
+++ b/src/X.Serilog.Sinks.Telegram/Extensions/DependencyInjectionExtensions.cs
@@ -0,0 +1,58 @@
+using System.Collections.Immutable;
+using X.Serilog.Sinks.Telegram.Batch.Rules;
+using X.Serilog.Sinks.Telegram.Configuration;
+using X.Serilog.Sinks.Telegram.Filters;
+
+namespace X.Serilog.Sinks.Telegram.Extensions;
+
+public static class DependencyInjectionExtensions
+{
+ public static LoggerConfiguration TelegramCore(
+ this LoggerSinkConfiguration sinkConfig,
+ string token,
+ string chatId,
+ LogEventLevel logLevel
+ )
+ {
+ ArgumentNullException.ThrowIfNull(sinkConfig);
+ ArgumentNullException.ThrowIfNull(token);
+ ArgumentNullException.ThrowIfNull(chatId);
+
+ return TelegramCoreInternal(sinkConfig, token, chatId, logLevel);
+ }
+
+ private static LoggerConfiguration TelegramCoreInternal(
+ LoggerSinkConfiguration sinkConfig,
+ string token,
+ string chatId,
+ LogEventLevel logLevel)
+ {
+ return sinkConfig.Telegram(config =>
+ {
+ config.Token = token;
+ config.ChatId = chatId;
+
+ config.Mode = TelegramSinkDefaults.DefaultFormatterMode;
+
+ config.BatchPostingLimit = TelegramSinkDefaults.BatchPostingLimit;
+ config.BatchEmittingRulesConfiguration = new BatchEmittingRulesConfiguration
+ {
+ RuleCheckPeriod = TelegramSinkDefaults.RulesCheckPeriod,
+ BatchProcessingRules = new List
+ {
+ new BatchSizeRule(config.LogsAccessor, batchSize: config.BatchPostingLimit),
+ // send logs to the Telegram once per 250 seconds
+ new OncePerTimeRule(TelegramSinkDefaults.RulesCheckPeriod * 50)
+ }.ToImmutableList()
+ };
+ config.FormatterConfiguration = TelegramSinkDefaults.DefaultFormatterConfiguration;
+ config.LogFiltersConfiguration = new LogsFiltersConfiguration()
+ {
+ ApplyLogFilters = false,
+ Filters = new ImmutableArray()
+ };
+ },
+ messageFormatter: null!,
+ restrictedToMinimumLevel: logLevel);
+ }
+}
\ No newline at end of file
diff --git a/src/X.Serilog.Sinks.Telegram/Configuration/LoggerConfigurationTelegramExtensions.cs b/src/X.Serilog.Sinks.Telegram/Extensions/LoggerConfigurationTelegramExtensions.cs
similarity index 93%
rename from src/X.Serilog.Sinks.Telegram/Configuration/LoggerConfigurationTelegramExtensions.cs
rename to src/X.Serilog.Sinks.Telegram/Extensions/LoggerConfigurationTelegramExtensions.cs
index 06e88b2..db0fdbb 100644
--- a/src/X.Serilog.Sinks.Telegram/Configuration/LoggerConfigurationTelegramExtensions.cs
+++ b/src/X.Serilog.Sinks.Telegram/Extensions/LoggerConfigurationTelegramExtensions.cs
@@ -1,8 +1,9 @@
using System.Threading.Channels;
using X.Serilog.Sinks.Telegram.Batch;
+using X.Serilog.Sinks.Telegram.Configuration;
using X.Serilog.Sinks.Telegram.Formatters;
-namespace X.Serilog.Sinks.Telegram.Configuration;
+namespace X.Serilog.Sinks.Telegram.Extensions;
public static class LoggerConfigurationTelegramExtensions
{
diff --git a/src/X.Serilog.Sinks.Telegram/Formatters/DefaultAggregatedNotificationsFormatter.cs b/src/X.Serilog.Sinks.Telegram/Formatters/DefaultAggregatedNotificationsFormatter.cs
index 308ce6e..24c01b7 100644
--- a/src/X.Serilog.Sinks.Telegram/Formatters/DefaultAggregatedNotificationsFormatter.cs
+++ b/src/X.Serilog.Sinks.Telegram/Formatters/DefaultAggregatedNotificationsFormatter.cs
@@ -7,7 +7,7 @@ public class DefaultAggregatedNotificationsFormatter : MessageFormatterBase
public override List Format(
ICollection logEntries,
FormatterConfiguration config,
- Func, FormatterConfiguration, List> formatter = null)
+ Func, FormatterConfiguration, List>? formatter = null)
{
formatter ??= DefaultFormatter;
return base.Format(logEntries, config, formatter);
diff --git a/src/X.Serilog.Sinks.Telegram/Formatters/DefaultLogFormatter.cs b/src/X.Serilog.Sinks.Telegram/Formatters/DefaultLogFormatter.cs
index 0b155bd..d513967 100644
--- a/src/X.Serilog.Sinks.Telegram/Formatters/DefaultLogFormatter.cs
+++ b/src/X.Serilog.Sinks.Telegram/Formatters/DefaultLogFormatter.cs
@@ -9,7 +9,7 @@ internal class DefaultLogFormatter : MessageFormatterBase
/// Throws when, after using the formatter, the message is null, empty, or whitespace.
public override List Format(ICollection logEntries,
FormatterConfiguration config,
- Func, FormatterConfiguration, List> formatter = null)
+ Func, FormatterConfiguration, List>? formatter = null)
{
if (!NotEmpty(logEntries))
{
diff --git a/src/X.Serilog.Sinks.Telegram/Formatters/IMessageFormatter.cs b/src/X.Serilog.Sinks.Telegram/Formatters/IMessageFormatter.cs
index de80b8c..f15311e 100644
--- a/src/X.Serilog.Sinks.Telegram/Formatters/IMessageFormatter.cs
+++ b/src/X.Serilog.Sinks.Telegram/Formatters/IMessageFormatter.cs
@@ -13,5 +13,5 @@ public interface IMessageFormatter
/// Human-readable message.
List Format(ICollection logEntries,
FormatterConfiguration config,
- Func, FormatterConfiguration, List> formatter = null);
+ Func, FormatterConfiguration, List>? formatter = null);
}
\ No newline at end of file
diff --git a/src/X.Serilog.Sinks.Telegram/Formatters/MessageFormatterBase.cs b/src/X.Serilog.Sinks.Telegram/Formatters/MessageFormatterBase.cs
index e863569..a69df61 100644
--- a/src/X.Serilog.Sinks.Telegram/Formatters/MessageFormatterBase.cs
+++ b/src/X.Serilog.Sinks.Telegram/Formatters/MessageFormatterBase.cs
@@ -10,7 +10,7 @@ public abstract class MessageFormatterBase : IMessageFormatter
///
public virtual List Format(ICollection logEntries,
FormatterConfiguration config,
- Func, FormatterConfiguration, List> formatter = null)
+ Func, FormatterConfiguration, List>? formatter = null)
{
if (!NotEmpty(logEntries))
{
diff --git a/src/X.Serilog.Sinks.Telegram/TelegramSink.cs b/src/X.Serilog.Sinks.Telegram/TelegramSink.cs
index eeb2175..371d4a6 100644
--- a/src/X.Serilog.Sinks.Telegram/TelegramSink.cs
+++ b/src/X.Serilog.Sinks.Telegram/TelegramSink.cs
@@ -112,7 +112,8 @@ private async Task EmitBatchInternalAsync(int batchSize, CancellationToken cance
private async Task> GetMessagesFromQueueAsync(int amount)
{
var logsBatch = await _logsQueueAccessor.DequeueSeveralAsync(amount);
- var events = logsBatch.Where(log => log is not null)
+ var events = logsBatch
+ .Where(log => log is not null)
.Select(LogEntry.MapFrom)
.ToList();
diff --git a/src/X.Serilog.Sinks.Telegram/X.Serilog.Sinks.Telegram.csproj b/src/X.Serilog.Sinks.Telegram/X.Serilog.Sinks.Telegram.csproj
index d1fb817..159a61b 100644
--- a/src/X.Serilog.Sinks.Telegram/X.Serilog.Sinks.Telegram.csproj
+++ b/src/X.Serilog.Sinks.Telegram/X.Serilog.Sinks.Telegram.csproj
@@ -15,7 +15,7 @@
-
+