Command Palette

Search for a command to run...

PHASE 4Intermediate ~8 min· topic 17 of 18Level 3

Problem 4.17 — Logging Framework

In one line

Design a mini SLF4J/Logback: log levels, multiple appenders (console, file, remote), formatters, per-logger configuration, and asynchronous writing that never blocks the application.

0/18 · 0%

Think of it like this

A newsroom. Reporters (application code) write stories with an urgency label (log level); editors (filters) drop the unimportant ones; formatters lay them out; and the paper is printed, posted online, and archived (appenders), all without reporters waiting for the printing press.

Key ideas

  1. 01

    Requirements: levels DEBUG < INFO < WARN < ERROR with a configurable threshold per logger; messages go to one or more APPENDERS; each appender has a FORMATTER; loggers are hierarchical by name (com.shop configures com.shop.orders); logging must be thread-safe and cheap when disabled.

  2. 02

    Patterns: SINGLETON/registry for the logger factory; STRATEGY for formatters; OBSERVER-like fan-out to appenders; CHAIN OF RESPONSIBILITY for filters; DECORATOR for an async appender that wraps any appender with a queue and a background thread (Phase 2).

  3. 03

    Performance: check the level BEFORE building the message (parameterised messages log.info("order {}", id) avoid string building when disabled); async appenders use a bounded queue and a policy when full (drop DEBUG, block, or discard) (Phase 13B, backpressure).

  4. 04

    Production reality: structured JSON output with context (MDC: request ID, trace ID) that log pipelines can parse (Stateful Systems course, log pipeline).

Code & diagrams

core typesjava

Levels, a logger that filters by level, pluggable formatters, and an async decorator.

enum Level { DEBUG, INFO, WARN, ERROR }

record LogEvent(Instant time, Level level, String logger, String message, Map<String, String> context) {}

interface Formatter { String format(LogEvent e); }
interface Appender { void append(LogEvent e); }

final class Logger {
  private final String name;
  private volatile Level threshold;
  private final List<Appender> appenders;
  Logger(String name, Level threshold, List<Appender> appenders) { this.name = name; this.threshold = threshold; this.appenders = appenders; }

  void info(String pattern, Object... args) { log(Level.INFO, pattern, args); }
  void error(String pattern, Object... args) { log(Level.ERROR, pattern, args); }

  private void log(Level level, String pattern, Object... args) {
    if (level.ordinal() < threshold.ordinal()) return;            // cheap exit when disabled
    String msg = MessageFormatter.format(pattern, args);          // "{}" substitution
    LogEvent e = new LogEvent(Instant.now(), level, name, msg, Mdc.copy());
    for (Appender a : appenders) a.append(e);
  }
}

final class AsyncAppender implements Appender {                     // Decorator
  private final BlockingQueue<LogEvent> queue = new ArrayBlockingQueue<>(10_000);
  AsyncAppender(Appender delegate) {
    Thread t = new Thread(() -> { try { while (true) delegate.append(queue.take()); } catch (InterruptedException ignored) { } });
    t.setDaemon(true); t.start();
  }
  public void append(LogEvent e) {
    if (!queue.offer(e) && e.level().ordinal() >= Level.WARN.ordinal()) {
      try { queue.put(e); } catch (InterruptedException ex) { Thread.currentThread().interrupt(); }  // never drop WARN/ERROR
    }                                                                // DEBUG/INFO dropped when full
  }
}

Explain without notes

01

Why use parameterised messages instead of string concatenation in log calls?

Practice

01

Add a rolling file appender that starts a new file at 100 MB and keeps the last 7 files.

Trade-offs

  • ↔

    Async logging protects latency but can lose buffered events on a crash; synchronous logging is safer for audit logs.

Run it in production

You've designed it. Now build, operate, and break the same idea hands-on in the DevOps courses:

Completion checklist

  • I can map logging concerns to Singleton, Strategy, Chain of Responsibility, and Decorator

Back to phase