Skip to content

Repository files navigation

Slate Engine - Logger

License Java Status Latest Release Downloads Stars

A modular, dependency-free, type-safe logging library powering the Slate Engine


Features

  • Dependency-free
  • Custom sinks
  • Custom formatters
  • {} formatting
  • Async logging
  • Exception logging
  • Context-aware logging
  • ANSI color support
  • Thread capture
  • File logging
  • Custom categories

Installation

Requirements

  • Java JDK 21+
  • Gradle 9.3.0+ (included)
  • Git

Currently, Slate Logger is not on Maven Central. To use it, clone the repository and publish it to your local Maven repository.

Linux / MacOS

git clone https://github.com/breadcat-dev/slate-logger.git
cd slate-logger
./gradlew publishToMavenLocal

Windows

git clone https://github.com/breadcat-dev/slate-logger.git
cd slate-logger
./gradlew.bat publishToMavenLocal

Once installed, add the dependency:

Groovy

implementation "cat.breadcat.slate:logger:<version>"

Kotlin

implementation("cat.breadcat.slate:logger:<version>")

Usage

import cat.breadcat.logger.LogLevel;
import cat.breadcat.logger.Logger;
import cat.breadcat.logger.formatter.ColorFormatter;
import cat.breadcat.logger.formatter.PlainFormatter;
import cat.breadcat.logger.sink.ConsoleSink;
import cat.breadcat.logger.sink.FileSink;

import java.io.IOException;
import java.nio.file.Path;


public class Main
{
    public static void main(String[] args) throws InterruptedException
    {
        // final Logger LOGGER = LoggerFactory.console(Main.class);

        final Logger LOGGER = Logger.builder()
                .source(Main.class)
                .addSink(new ConsoleSink(ColorFormatter.instance()))
                .addSink(new FileSink(PlainFormatter.instance(), Path.of("./debug.log")))
                .setMinimum(LogLevel.INFO)
                .captureThread()
                .build();

        // Simple logging
        LOGGER.debug("hello");
        LOGGER.info("hello");
        LOGGER.warn("hello");
        LOGGER.error("hello");
        LOGGER.critical("hello");

        // Exception logging + message formatting
        final IOException exception = new IOException("test exception");

        LOGGER.atDebug()
                .category("category")
                .exception(exception)
                .log("{} was here {} ago", "BreadCat", null);
        LOGGER.atInfo()
                .category("category")
                .exception(exception)
                .log("{} was here {} ago", "BreadCat", null);
        LOGGER.atWarn()
                .category("category")
                .exception(exception)
                .log("{} was here {} ago", "BreadCat", null);
        LOGGER.atError()
                .category("category")
                .exception(exception)
                .log("{} was here {} ago", "BreadCat", null);

        // Different thread
        Thread.startVirtualThread(() ->
        {
            LOGGER.atCritical()
                    .category("crash")
                    .exception(exception)
                    .log("something crash related idk");
        });

        Thread.sleep(250);
    }
}

Examples

Custom Formatter

public final class NetworkFormatter implements LogFormatter
{
    // ===== Constants =====

    private static final NetworkFormatter INSTANCE = new NetworkFormatter();

    // ===== Constructors =====

    private NetworkFormatter()
    {
    }

    // ===== Factories =====

    public static NetworkFormatter instance()
    {
        return INSTANCE;
    }

    // ===== Formatting =====

    @Override
    public String format(LogEvent event)
    {
        Objects.requireNonNull(event.context(), "context");
        Objects.requireNonNull(event.timestamp(), "timestamp");
        Objects.requireNonNull(event.clazz(), "clazz");
        Objects.requireNonNull(event.level(), "level");
        Objects.requireNonNull(event.message(), "message");

        LogContext context = event.context();
        LogThread thread = event.thread();
        LogException exception = event.exception();
        Object category = context.get(LogContextKeys.CATEGORY);
        Object user = context.get("user");
        Object address = context.get("address");
        LogTimestamp timestamp = event.timestamp();
        String className = event.clazz().getSimpleName();
        LogLevel level = event.level();
        String message = event.message();

        String formattedThread =
                (thread != null) ?
                        "-" + (thread.name().isBlank() ? "thread" + thread.id() : thread.name()) :
                        "";
        String formattedException =
                (exception != null) ?
                        "\n" + exception.stackTrace() :
                        "";
        String formattedCategory =
                (category != null) ?
                        "-" + category :
                        "";
        String formattedUser = user + "-" + address;
        String formattedTimestamp = timestamp.format();
        String formattedClassName = className + formattedThread;
        String formattedLevel = level + formattedCategory;

        String coloredException = Ansi.color(formattedException, level.color());
        String coloredUser = Ansi.color(formattedUser, AnsiColor.YELLOW);
        String coloredTimestamp = Ansi.color(formattedTimestamp, AnsiColor.CYAN);
        String coloredClassName = Ansi.color(formattedClassName, AnsiColor.MAGENTA);
        String coloredLevel = Ansi.color(formattedLevel, level.color());

        return "(" + coloredTimestamp + ") [" + coloredClassName + "] {" + coloredUser + "} <" + coloredLevel + "> " + message + coloredException;
    }
}

Custom Context

final Logger LOGGER = Logger.builder()
        .source(Main.class)
        .addSink(new ConsoleSink(NetworkFormatter.instance()))
        .captureThread()
        .build();

LOGGER.atInfo()
        .with("user", "BreadCat")
        .with("address", "127.0.0.1")
        .category("connection")
        .log("A new user has connected to the server");

Console:

(2026-08-07 14:13:41.706) [Main-main] {BreadCat-127.0.0.1} <INFO-connection> A new user has connected to the server

Roadmap

  • Performance optimization
  • Log rotation

Dependencies

none

License

PolyForm Noncommercial License 1.0.0

About

A modular, dependency-free, type-safe logging library powering the Slate Engine

Topics

Resources

Stars

2 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages