A modular, dependency-free, type-safe logging library powering the Slate Engine
- Dependency-free
- Custom sinks
- Custom formatters
{}formatting- Async logging
- Exception logging
- Context-aware logging
- ANSI color support
- Thread capture
- File logging
- Custom categories
- 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.
git clone https://github.com/breadcat-dev/slate-logger.git
cd slate-logger
./gradlew publishToMavenLocalgit clone https://github.com/breadcat-dev/slate-logger.git
cd slate-logger
./gradlew.bat publishToMavenLocalOnce installed, add the dependency:
implementation "cat.breadcat.slate:logger:<version>"implementation("cat.breadcat.slate:logger:<version>")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);
}
}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;
}
}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
- Performance optimization
- Log rotation
none
PolyForm Noncommercial License 1.0.0