Sinobu

Concept

Sinobu provides a minimalist, high-performance logging library designed with an emphasis on garbage-less operation and zero-boilerplate code. It is especially well-suited for high-throughput applications where every microsecond and memory allocation matters.

πŸš€ No Boilerplate

Logging is as simple as calling a static method like I#info(Object). Therefore, there’s no need to create logger instances per class. This approach dramatically reduces code clutter and eliminates repetitive logger setup.

void log() {
    I.info("Hello Logging");
}

♻️ Garbage Less

Many logging libraries create temporary objects (log events, strings, byte arrays, etc.) each time they output logs, causing GC latency; Sinobu tackles this problem head on and does not create new objects unless you explicitly request stack trace.

⚑ High Performance

Sinobu is engineered for speed. Its optimized encoding, buffer reuse, and minimal synchronization mean it can outperform many mainstream logging libraries. Even under heavy logging loads, it maintains consistent performance with minimal CPU and memory impact. Check benchmark.

Usage

Logging is performed via static methods such as I#info(Object) or I#info(String, Object). These methods support various input types:

  • Object - Use Object#toString() representation as message.
  • Supplier - Delaying the construction of message avoids extra processing when the log level prevents writing.
  • Throwable - A message and a stack trace back to the cause are written.
void basic() {
    I.trace("Write your message");
}
void lazyEvaluation() {
    I.debug(() -> "Delaying the construction of message.");
}
void throwable() {
    try {
        mayBeThrowError();
    } catch (Exception e) {
        I.error("Write message and stack trace");
        I.error(e);
    }
}

Most methods come in two forms:

  • Without category - logs to the default system category.
  • With category - the first argument specifies the log category, allowing fine-grained control.
void categorized() {
    I.debug("Write message in system category");
    I.warn("database", "Write message in database category");
}

Configuration

Logging behavior can be configured via environment variables (I#env(String) Configuration keys follow a specific pattern to allow both fine-grained and global control.

Resolution Order

When any environment variable is required, configuration values are resolved in the following order:

  1. Look for category.property (e.g. system.file)
  2. If not found, look for *.property (e.g. *.file)
  3. If still not found, use the built-in default (e.g. Level#WARNING)

Log Appender

Log messages can be routed to different output destinations. While logs may go to the console by default (depending on the underlying System#out implementation), Sinobu allows you to explicitly configure destinations. You can even configure multiple destinations for the same logger category.

Property Key Value Type Description
category.console Level Enables console logging for the specified category.
category.file Level Enables file logging for the specified category.
category.extra Level Enables extra logging for the specified category.
You must define I#Logger as extra logger.

File Logging Options

Options specific to file logging when category.file is enabled. Log files are typically named category<Date>.log (e.g. database2024-10-27.log).

Property Key Value Type Description
category.dir String Specifies the directory where log files for this category should be created. Default is .log
category.append boolean If true, appends to existing log files for this category. If false, overwrites. Default is true.
category.rotate int Number of past daily log files to keep for this category. Older files are deleted. 0 disables rotation. Default is 90.

Formatting Options

Options related to the formatting of log messages for a specific category.

Property Key Value Type Description
category.caller Level Includes caller info for messages in this category at or above the given level. Can impact performance.
SchedulingPersistence