SkillAgentSearch skills...

ZeroLog

A high-performance, zero-allocation .NET logging library.

Install / Use

/learn @Abc-Arbitrage/ZeroLog
About this skill

Quality Score

0/100

Supported Platforms

Universal

README

ZeroLog <a href="#"><img src="icon.png" align="right" alt="Logo" /></a>

Build NuGet

ZeroLog is a high-performance, zero-allocation .NET logging library.

It provides logging capabilities to be used in latency-sensitive applications, where garbage collections are undesirable. ZeroLog can be used in a complete zero-allocation manner, meaning that after the initialization phase, it will not allocate any managed object on the heap, thus preventing any GC from being triggered.

Since ZeroLog does not aim to replace any existing logging libraries in any kind of application, it won't try to compete on feature set level with more pre-eminent projects like log4net or NLog for example. The focus will remain on performance and allocation free aspects.

The project is production ready and you can get it via NuGet if you want to give it a try.

ZeroLog v2 requires .NET 6 and C# 10 or later. If your application targets an earlier .NET version, you can use ZeroLog v1. Note that a .NET Standard 2.0 target is provided with a limited API surface for use by libraries, but it still requires the main application to target .NET 6 or later.

Internal Design

ZeroLog was designed to meet two main objectives:

  • Being a zero allocation library.
  • Doing as little work as possible in calling threads.

The second goal implies a major design choice: the actual logging is completely asynchronous. It means that writing messages to the appenders occurs in a background thread, and all formatting operations are delayed to be performed just before the appending. No formatting occurs in the calling thread, the log data is merely marshalled to the background logging thread in the most efficient way possible.

Internally, each logging call data (context, log messages, arguments, etc.) will be serialized to a pooled log message, before being enqueued in a concurrent data structure the background logging thread consumes. The logging thread will then format the log messages and append them to the configured appenders.

Getting Started

Before using ZeroLog, you need to initialize the LogManager by calling LogManager.Initialize and providing a configuration.

<!-- snippet: Initialize -->

<a id='snippet-Initialize'></a>

LogManager.Initialize(new ZeroLogConfiguration
{
    RootLogger =
    {
        Appenders =
        {
            new ConsoleAppender()
        }
    }
});

<sup><a href='/src/ZeroLog.Tests/Snippets.cs#L21-L34' title='Snippet source file'>snippet source</a> | <a href='#snippet-Initialize' title='Start of snippet'>anchor</a></sup>

<!-- endSnippet -->

The LogManager needs to be shut down by calling LogManager.Shutdown() when your application needs to exit.

You can retrieve a logger that will be the logging API entry point. Store this logger in a field.

<!-- snippet: GetLogger -->

<a id='snippet-GetLogger'></a>

private static readonly Log _log = LogManager.GetLogger(typeof(YourClass));

<sup><a href='/src/ZeroLog.Tests/Snippets.cs#L12-L16' title='Snippet source file'>snippet source</a> | <a href='#snippet-GetLogger' title='Start of snippet'>anchor</a></sup>

<!-- endSnippet -->

Logging APIs

Two logging APIs are provided:

A string interpolation API:

<!-- snippet: StringInterpolationApi -->

<a id='snippet-StringInterpolationApi'></a>

var date = DateTime.Today.AddDays(1);
_log.Info($"Tomorrow ({date:yyyy-MM-dd}) will be in {GetNumberOfSecondsUntilTomorrow():N0} seconds.");

<sup><a href='/src/ZeroLog.Tests/Snippets.cs#L40-L45' title='Snippet source file'>snippet source</a> | <a href='#snippet-StringInterpolationApi' title='Start of snippet'>anchor</a></sup>

<!-- endSnippet -->

This API uses C# 10 string interpolation handlers to implement custom interpolation support without allocations.

Note that if the log level is disabled (Info in this example), method calls such as GetNumberOfSecondsUntilTomorrow() will not be executed.

A StringBuilder-like API:

<!-- snippet: StringBuilderApi -->

<a id='snippet-StringBuilderApi'></a>

_log.Info()
    .Append("Tomorrow (")
    .Append(DateTime.Today.AddDays(1), "yyyy-MM-dd")
    .Append(") will be in ")
    .Append(GetNumberOfSecondsUntilTomorrow(), "N0")
    .Append(" seconds.")
    .Log();

<sup><a href='/src/ZeroLog.Tests/Snippets.cs#L51-L61' title='Snippet source file'>snippet source</a> | <a href='#snippet-StringBuilderApi' title='Start of snippet'>anchor</a></sup>

<!-- endSnippet -->

This API supports more features, but is less convenient to use. You need to call Log at the end of the chain. Note that an Append overload with a string interpolation handler is provided though.

The library provides Roslyn analyzers that check for incorrect usages of these APIs.

Structured Data

ZeroLog supports appending structured data (formatted as JSON) to log messages.

Structured data can be appended by calling AppendKeyValue, like so:

<!-- snippet: StructuredData -->

<a id='snippet-StructuredData'></a>

_log.Info()
    .Append("Tomorrow is another day.")
    .AppendKeyValue("NumSecondsUntilTomorrow", GetNumberOfSecondsUntilTomorrow())
    .Log();

<sup><a href='/src/ZeroLog.Tests/Snippets.cs#L67-L74' title='Snippet source file'>snippet source</a> | <a href='#snippet-StructuredData' title='Start of snippet'>anchor</a></sup>

<!-- endSnippet -->

Configuration

Appenders

You need to instantiate a set of appenders (output channels) that can be used by loggers, and pass them to the logger configurations.

Several appenders are provided by default, such as ConsoleAppener or DateAndSizeRollingFileAppender, but you can also write your own.

Formatters

The output format of the built-in appenders may be customized through the Formatter property, which controls how the message metadata is formatted. A DefaultFormatter is provided, which uses a customizable pattern to control how the message should be displayed, and suffixes it with the structured data as JSON.

The pattern is a string with the following placeholders:

| Placeholder | Effect | Format | |---------------------|------------------------------------------------------------------|------------------------------------------------------------| | %date | The message date in UTC (recommended, also contains time of day) | A DateTime format string, default: yyyy-MM-dd | | %localDate | The message date converted to the local time zone | A DateTime format string, default: yyyy-MM-dd | | %time | The message time of day (in UTC) | A TimeSpan format string, default: hh\:mm\:ss\.fffffff | | %localTime | The message time of day (converted to the local time zone) | A TimeSpan format string, default: hh\:mm\:ss\.fffffff | | %thread | The thread name (or ID) which logged the message | | | %threadId | The thread ID which logged the message | | | %threadName | The thread name which logged the message, or an empty string | | | %level | The log level (default: a short uppercase label) | pad makes eack level the same length | | %levelColor | The ANSI color code associated to the log level | | | %logger | The logger name | | | %loggerCompact | The logger name, with the namespace shortened to its initials | | | %message | The logged message | | | %exceptionMessage | The exception message, if any | | | %exceptionType | The exception type, if any | | | %newline | Equivalent to Environment.NewLine | | | %column | Inserts padding spaces until a given column index | The column index to reach | | %color | An ANSI SGR color code | See below for more information | | %resetColor | The reset ANSI color code | Equivalent to \e[0m | | %% | Inserts a single % character (escaping) | |

Patterns can be written in the form %{field} or %{field:format} to define a format string. String placeholders accept an integer format string which defines their minimum length. For instance, %{logger:20} will always be at least 20 characters wide.

The %{color:...} placeholder can be used to set the colo

View on GitHub
GitHub Stars434
CategoryDevelopment
Updated2d ago
Forks32

Languages

C#

Security Score

100/100

Audited on Mar 25, 2026

No findings