Skip to content

grovegs/Logger

Repository files navigation

GroveGames.Logger

A high-performance, zero-allocation logging library for .NET, Unity, and Godot with Native AOT support. Built for game development scenarios where performance is critical.

Build Status Tests Latest Release NuGet


Features

  • Zero-Allocation Logging: Uses interpolated string handlers and Span<char> to eliminate heap allocations
  • Native AOT Compatible: Fully supports ahead-of-time compilation for maximum performance
  • Asynchronous File Writing: Non-blocking log writes using channels and background processing
  • Automatic File Rotation: Manages log files with configurable limits and automatic cleanup
  • Flexible Log Processing: Extensible processor system for custom log handling
  • Custom Formatting: Full control over log output format via ILogFormatter interface
  • Unity Integration: Available as a Unity package
  • Godot Integration: Available as a Godot addon

.NET

Install via NuGet:

dotnet add package GroveGames.Logger

Basic Console Logging

using GroveGames.Logger;

var logger = LoggerFactory.CreateLogger(builder =>
{
    builder.SetMinimumLevel(LogLevel.Information)
           .AddLogProcessor(new ConsoleLogProcessor(new ConsoleLogFormatter()));
});

logger.LogInformation("App", $"Application started at {DateTime.UtcNow}");
logger.LogWarning("App", $"Memory usage: {GC.GetTotalMemory(false) / 1024 / 1024}MB");
logger.LogError("App", $"Failed to load configuration");

File Logging

var logger = LoggerFactory.CreateLogger(builder =>
{
    var logFileFactory = new LogFileFactory(
        root: "logs",
        folderName: "app",
        maxFileCount: 10,
        bufferSize: 8192
    );

    var fileStream = logFileFactory.CreateFile();
    var streamWriter = new StreamWriter(fileStream, bufferSize: 8192, channelCapacity: 1000);
    var fileProcessor = new FileLogProcessor(streamWriter, new FileLogFormatter());

    builder.SetMinimumLevel(LogLevel.Debug)
           .AddLogProcessor(fileProcessor);
});

Custom Log Formatters

Implement ILogFormatter to create custom formats:

public sealed class JsonLogFormatter : ILogFormatter
{
    public int GetBufferSize(LogLevel level, ReadOnlySpan<char> tag, ReadOnlySpan<char> message)
    {
        return 100 + tag.Length + message.Length;
    }

    public void Format(Span<char> buffer, LogLevel level, ReadOnlySpan<char> tag, ReadOnlySpan<char> message)
    {
        var timestamp = DateTime.UtcNow;
        var position = 0;

        "{\"time\":\"".AsSpan().CopyTo(buffer[position..]);
        position += 10;

        timestamp.TryFormat(buffer[position..], out var written, "O");
        position += written;

        // ... continue building JSON
    }
}

var logger = LoggerFactory.CreateLogger(builder =>
{
    builder.AddLogProcessor(new FileLogProcessor(streamWriter, new JsonLogFormatter()));
});

Performance-Critical Scenarios

The logger uses interpolated string handlers that only allocate when the log level is active:

for (int i = 0; i < 1000000; i++)
{
    logger.LogDebug("Loop", $"Iteration {i} of {1000000}");
}

Core Components

  • ILogger: Core logging interface with minimal API surface
  • Logger: Main implementation with processor management
  • LoggerFactory: Primary entry point for creating loggers with builder configuration
  • LoggerBuilder: Fluent API for logger configuration
  • ILogProcessor: Interface for processing log entries
  • ILogFormatter: Interface for controlling log entry formatting
  • StreamWriter: High-performance async file writer with batching
  • LogFileFactory: Manages log file creation and rotation

Unity

There are two installation steps required to use it in Unity.

  1. Install GroveGames.Logger from NuGet using NuGetForUnity. Open Window from NuGet → Manage NuGet Packages, search "GroveGames.Logger" and press Install.

  2. Install the GroveGames.Logger.Unity package by referencing the git URL:

    https://github.com/grovegs/Logger.git?path=src/GroveGames.Logger.Unity/Packages/com.grovegames.logger
    
  3. Create a csc.rsp file in your Assets/ directory with the following content to enable C# 10 features:

    -langversion:10
    -nullable:enable
    

With the Unity package, Unity-specific formatters and processors become available for logging in Unity projects.

Setting Up Unity Logger

using GroveGames.Logger.Unity;
using UnityEngine;

public class GameManager : MonoBehaviour
{
    private Logger _logger;

    private void Awake()
    {
        _logger = UnityLoggerFactory.CreateLogger(builder =>
        {
            builder.AddUnityConsoleLogProcessor();
            builder.AddUnityFileLogProcessor();
        });

        _logger.LogInformation("Game", $"Unity {Application.unityVersion} initialized");
    }

    private void OnDestroy()
    {
        _logger?.Dispose();
    }
}

Project Settings Configuration

Configure logger settings via Edit → Project Settings → GroveGames → Logger. Settings are stored as a ScriptableObject in Assets/Settings/GroveGamesLoggerSettings.asset and automatically included in builds via EditorBuildSettings.

Setting Type Default Description
Min Log Level LogLevel Information Minimum level for log output
Max File Count int 10 Maximum number of log files to retain
File Folder Name string "logs" Folder name for log files
File Buffer Size int 8192 Buffer size in bytes for file operations
File Channel Capacity int 1000 Channel capacity for async log processing

For custom configurations or DI scenarios, pass settings directly:

var settings = UnityLoggerSettings.GetOrCreate();
var logger = UnityLoggerFactory.CreateLogger(settings, builder => { ... });

Unity Components

  • UnityLoggerFactory: Factory with GetOrCreate() pattern for DI-friendly architecture
  • UnityLoggerSettings: ScriptableObject with EditorBuildSettings integration
  • UnityLoggerSettingsProvider: Project Settings UI using UI Toolkit
  • UnityConsoleLogFormatter: Formatter for Unity console output (format: [Tag] Message)
  • UnityConsoleLogProcessor: Routes logs to Debug.Log, Debug.LogWarning, Debug.LogError
  • UnityLogFileFactory: File factory using Application.persistentDataPath
  • UnityLogHandler: Captures Unity's internal logs and forwards them to file logging

Godot

Install via NuGet:

dotnet add package GroveGames.Logger.Godot

Download the Godot addon from the latest release and extract it to your project's addons folder. Enable the addon in Project Settings → Plugins.

res://
├── addons/
│   └── GroveGames.Logger/
│       ├── plugin.cfg
│       └── ...
└── ...

Setting Up Godot Logger

using GroveGames.Logger;
using Godot;

public partial class Main : Node
{
    private Logger _logger;

    public override void _Ready()
    {
        _logger = GodotLoggerFactory.CreateLogger(builder =>
        {
            builder.AddGodotConsoleLogProcessor();
            builder.AddGodotFileLogProcessor();
        });

        _logger.LogInformation("Game", $"Godot {Engine.GetVersionInfo()} initialized");
    }

    public override void _ExitTree()
    {
        _logger?.Dispose();
    }
}

Godot Console Formatter

The GodotConsoleLogFormatter provides rich formatting for the Godot editor console:

  • Warning messages are highlighted with yellow color
  • Timestamps in HH:mm:ss format for easy debugging
  • Clean tag presentation with brackets

Project Settings Configuration

Configure logger settings via a Resource stored at res://addons/GroveGames.Logger/LoggerSettings.tres. The resource path is registered in project settings and automatically included in builds.

Setting Type Default Description
Min Log Level LogLevel Information Minimum level for log output
Max File Count int 10 Maximum number of log files to retain
File Folder Name string "logs" Folder name for log files
File Buffer Size int 8192 Buffer size in bytes for file operations
File Channel Capacity int 1000 Channel capacity for async log processing

For custom configurations or DI scenarios, reference the settings resource:

public partial class GameManager : Node
{
    [Export] private GodotLoggerSettingsResource _loggerSettings;

    public override void _Ready()
    {
        var logger = GodotLoggerFactory.CreateLogger(_loggerSettings, builder => { ... });
    }
}

Godot Components

  • GodotLoggerFactory: Factory with GetOrCreate() pattern for DI-friendly architecture
  • GodotLoggerSettingsResource: Resource with ProjectSettings integration
  • GodotConsoleLogFormatter: Rich formatting for Godot's editor console
  • GodotConsoleLogProcessor: Processor optimized for Godot's output methods
  • GodotLogFileFactory: File factory using OS.GetUserDataDir()

Architecture

Performance Optimizations

  1. Zero-Allocation String Handling: Uses Span<char> and stackalloc throughout
  2. Interpolated String Handlers: Compile-time optimization for string formatting
  3. Channel-Based Async I/O: Lock-free producer-consumer pattern for file writes
  4. Batched Writing: Reduces I/O operations by batching multiple log entries
  5. Native AOT: Full compatibility with ahead-of-time compilation

Testing

Run tests:

dotnet test

Contributing

Contributions are welcome! Please:

  1. Fork the repository
  2. Create a feature branch
  3. Write tests for new functionality
  4. Submit a pull request

License

This project is licensed under the MIT License - see the LICENSE file for details.

About

File logger for Godot C# projects

Resources

License

Stars

Watchers

Forks

Contributors