Serilog.Sinks.SCU.Telegram 1.0.8

There is a newer version of this package available.
See the version list below for details.
dotnet add package Serilog.Sinks.SCU.Telegram --version 1.0.8
                    
NuGet\Install-Package Serilog.Sinks.SCU.Telegram -Version 1.0.8
                    
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="Serilog.Sinks.SCU.Telegram" Version="1.0.8" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="Serilog.Sinks.SCU.Telegram" Version="1.0.8" />
                    
Directory.Packages.props
<PackageReference Include="Serilog.Sinks.SCU.Telegram" />
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add Serilog.Sinks.SCU.Telegram --version 1.0.8
                    
#r "nuget: Serilog.Sinks.SCU.Telegram, 1.0.8"
                    
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package Serilog.Sinks.SCU.Telegram@1.0.8
                    
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=Serilog.Sinks.SCU.Telegram&version=1.0.8
                    
Install as a Cake Addin
#tool nuget:?package=Serilog.Sinks.SCU.Telegram&version=1.0.8
                    
Install as a Cake Tool

SCU.Serilog.Sinks.Telegram

Repo - https://github.com/sapozhnikovv/SCU.Serilog.Sinks.Telegram

Minimal, Effective, Safe and Fully Async Serilog Sink that allows sending messages to pre-defined list of users in Telegram chat. It uses HttpClient singleton, Channel as queue and StringBuilder pool to optimize memory using (no mem leaks) and performance. Also uses SCU.MemoryChunks extenstion (split strings by size into chunks, without allocation redundant intermediate arrays like in LINQ version) https://github.com/sapozhnikovv/SCU.MemoryChunks (very small, 3 lines of code)

This Sink designed to be simple, fast, safe and stable.

Works without issues in docker container's too.

Logging in Telegram chat is a simple task. You don't need to have many dependencies, dozens of code files, a huge wiki on how to configure it. If you hate monstrous projects, this Serilog extension is your choice. Sources of this project - 4 files. Low cognitive complexity.

If the functionality of this solution does not meet your needs, you can always make your own version of this extension.

Example of using

Note: Nuget not passing name SCU.Serilog.Sinks.Telegram, so in Nuget this extension has name Serilog.Sinks.SCU.Telegram, but in C# code name of lib is SCU.Serilog.Sinks.Telegram.

using SCU.Serilog.Sinks.Telegram;

Basic

using Serilog;
using Serilog.Events;
using SCU.Serilog.Sinks.Telegram;

Log.Logger = new LoggerConfiguration()
            .WriteTo.TelegramSerilog(
                apiKey: "12345:AAAAAAAAAAAA",
                chatIds: ["12345", "12346"],
                restrictedToMinimumLevel: LogEventLevel.Warning)
            .CreateLogger();

with Serilog.AspNetCore

using Serilog;
using Serilog.Events;
using SCU.Serilog.Sinks.Telegram;

builder.Services.AddSerilog(logger => logger.WriteTo.TelegramSerilog(
        apiKey: "12345:AAAAAAA",
        chatIds: ["12345", "12346"],
        restrictedToMinimumLevel: LogEventLevel.Warning));

with Serilog.AspNetCore and Serilog.Settings.Configuration

Loading from appsettings.json

using Serilog;
using Serilog.Events;
using SCU.Serilog.Sinks.Telegram;

builder.Services.AddSerilog(logger => logger.ReadFrom.Configuration(builder.Configuration));

appsettings.json

{
  "Serilog": {
    "WriteTo": [
      {
        "Name": "TelegramSerilog",
        "Args": {
          "apiKey": "12345:AAAAAAAAAAAA",
          "chatIds": [ "12345", "12346" ],
          "restrictedToMinimumLevel": "Warning",
          "batchTextLength": 1500,
          "batchInterval": 5,
          "maxCapacity": 1000000,
          "excludedByContains": [
            "Failed to determine the https port for redirect"
          ]
        }
      }
    ]
  }
}

  • apiKey - telegram channel key
  • chatIds - array of 'string's with chat IDs
  • restrictedToMinimumLevel - log level
  • batchTextLength - value is 'int'. This is the number of characters in logged messages. Sink will trigger the sending if reached. If value ⇐ 0 then 1500 will be used.
  • batchInterval - value is 'int'. It is time in seconds. Sink will trigger the sending if reached. If value ⇐ 0 then 5s will be used.
  • maxCapacity - value is 'int'. It is the limit of messages in queue. If value ⇐ 0 then int.MaxValue will be used.
  • excludedByContains - array of 'string's. If a logged message contains any of these values - message will not be logged.

you can skip and not use all parameters except the first 2. apiKey and chatIds are required.

Fatal/Critical log messages will be logged immediately.

If you need to print error from TelegramSender - you can enable SelfLoggig in Serilog

Serilog.Debugging.SelfLog.Enable(msg => Console.WriteLine(msg));

If you need to re-configure Telegram Sender - you can use static fields in TelegramSender.Settings and change them on the fly

// These values ​​are default values ​​and are suitable for most (small business) projects.
TelegramSender.Settings.DefaultWaitTimeAfterSendMs = 750;
TelegramSender.Settings.ChunkSize = 3000;
TelegramSender.Settings.RetryWaitTimeWhenTooManyRequestsSeconds = 40;
TelegramSender.Settings.RetryCountWhenTooManyRequests = 2;
If you have question about Disposing Sink:

In many projects with Sinks you can see the implementation of IDisposable, but in this project it is not and here is why: Serilog Sinks are singletons - They are created once and live until the application terminates. Serilog does NOT call Dispose - Even if the sink implements IDisposable.

If you have question about HttpClient as singleton:

https://learn.microsoft.com/en-us/dotnet/fundamentals/networking/http/httpclient-guidelines#recommended-use HttpClient should be singleton.

Why PeriodicTimer not used?
About logic:

PeriodicTimer logic is fixed interval, but Logic of this Sink is 'wait X seconds after the sending message (even if sending is very long running)'. Logic of this Sink use 'time drift'.

About stability:

Task.Delay creates one-time timer (Infinite time for repeat) and 'Dispose'/collect/release it automatically. OS deactivate one-time timers automatically, it is not on the .net side. PeriodicTimer create long-lived timer, it should be disposed manually. Without Dispose (Disposal may not be caused), PeriodicTimer can leak system resources (Windows WaitableTimer/Linux timerfd) and block app shutdown for its full interval. Task.Delay only leaves orphaned Task objects that GC cleans, while unfinished PeriodicTimer calls actively prevent process termination. Though both delay shutdown without cancellation, PeriodicTimer risks hung timers and descriptor leaks on Linux. Even if timer in linux cannot do executions (it will be closed) when app process is closed, this still can cause some issues with containers where may be checking how and when app/container will terminate. Task.Delay lightweight approach avoids these OS dependencies. For reliability without strict disposal, Task.Delay is preferable.

About memory:

PeriodicTimer is memory efficient, but in current implementation of this Sink - Task.Delay used on seconds-based intervals, so memory allocation of DelayPromises is acceptable. (Example: ~28Kb memory will be allocated and then collected in one hour for 5 seconds interval. 40 bytes / interval. It is small numbers of memory for GC.)

So, this construct consists of explicit and implicit singletons.

Memory Profiling

Memory profiling was done via JetBrains dotMem and using the old-school method of marking objects in RAM.

License

Free MIT license (https://github.com/sapozhnikovv/SCU.Serilog.Sinks.Telegram/blob/main/LICENSE)

P.S:

This Serilog extension was designed for Color Disco platform and proven to work well. As the founder and developer of the platform, I decided to make this extension available on GitHub.

Product Compatible and additional computed target framework versions.
.NET net8.0 is compatible.  net8.0-android was computed.  net8.0-browser was computed.  net8.0-ios was computed.  net8.0-maccatalyst was computed.  net8.0-macos was computed.  net8.0-tvos was computed.  net8.0-windows was computed.  net9.0 was computed.  net9.0-android was computed.  net9.0-browser was computed.  net9.0-ios was computed.  net9.0-maccatalyst was computed.  net9.0-macos was computed.  net9.0-tvos was computed.  net9.0-windows was computed.  net10.0 was computed.  net10.0-android was computed.  net10.0-browser was computed.  net10.0-ios was computed.  net10.0-maccatalyst was computed.  net10.0-macos was computed.  net10.0-tvos was computed.  net10.0-windows was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

NuGet packages

This package is not used by any NuGet packages.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
1.2.3.2 211 8/7/2025
1.2.3 208 8/6/2025
1.2.2 192 7/19/2025
1.1.0 161 3/27/2025
1.0.8 153 3/27/2025