Chaturmind
LearnDSASystem DesignDevOpsEngineering GrowthBlog
Start learning
Chaturmind

Structured learning paths for engineers who want to go deep. Written by practitioners.

Learn

  • Java
  • DSA
  • System Design
  • Spring Boot
  • AI / ML
  • DevOps
  • Engineering Growth

Company

  • Blog
  • Contact

Legal

  • Privacy Policy
  • Terms of Service

© 2026 Chaturmind. All rights reserved.

Built for engineers who want to go deep.


← Low-Level Design & Design Patterns

OOP Fundamentals & SOLID Principles

  • Object-Oriented Design Refresher
  • Single Responsibility & Open/Closed
  • Liskov Substitution & Interface Segregation
  • Dependency Inversion

Creational Design Patterns

  • Singleton Pattern
  • Factory & Abstract Factory
  • Builder Pattern
  • Prototype Pattern

Structural Design Patterns

  • Adapter & Facade
  • Decorator Pattern
  • Composite & Proxy
  • Bridge & Flyweight

Behavioral Design Patterns

  • Strategy Pattern
  • Observer Pattern
  • Command Pattern
  • Template Method
  • State Pattern
  • Chain of Responsibility
  • Iterator & Mediator
  • Visitor Pattern

Machine Coding Exercises

  • Parking Lot — Requirements & Class Design
  • Parking Lot — Implementation
  • Elevator System — Requirements & Class Design
  • Elevator System — Implementation & Scheduling
  • Library Management System
  • Tic-Tac-Toe / Board Game Design
  • Chess Engine Design
  • Vending Machine Design
  • ATM System Design
  • In-Memory Rate Limiter
  • Thread-Safe LRU Cache
  • Connection Pool Design
  • Producer-Consumer Class Design
  • Movie Ticket Booking System
  • Hotel Reservation System
  • Airline Booking / Seat Selection System
  • Splitwise / Expense Sharing System
  • Design a Logging Framework
  • Design a Notification/Observer-Based Pub-Sub
  • Design a Cache with Pluggable Eviction Policy
  • Design Snake and Ladder
  • Design a Card Game Framework
  • Design an Inventory Management System
  • Restaurant Management System
  • Food Delivery Order Matching
  • Design a Shopping Cart & Checkout Flow
  • Design a Recommendation Engine
  • Design a Job Scheduler
  • Design a Circuit Breaker
  • Design a Distributed ID Generator
  • Design a Pub-Sub Message Broker
  • Design Twitter/X
  • Multi-Pattern Problem: Design a Ride Booking Class Model
  • Multi-Pattern Problem: Design a Food Ordering Class Model
  • Design an Authentication/Authorization Module
  • Design a Form/Survey Builder
  • Design a Meeting Room / Calendar Booking System
  • Design a Search/Filter Engine for an E-Commerce Catalog
  • Design a Voting/Polling System
  • Design a Retry Mechanism with Backoff
  • Design a Health Check Aggregator
  • Design a Feature Flag System
  • Design a Config Management Client
  • Design a Leader Election Algorithm
  • Design a Distributed Counter
  • Design a Bloom Filter
  • Design a Consistent Hashing Ring
  • Design a Distributed Tracing Library
  • Design a Metrics Collection Library
  • Design an Audit Logging Framework
  • Design a Plugin/Extension System
  • Design a Workflow Engine
  • Multi-Pattern Capstone: Design a Food Delivery App
Chaturmind
← Low-Level Design & Design Patterns

OOP Fundamentals & SOLID Principles

  • Object-Oriented Design Refresher
  • Single Responsibility & Open/Closed
  • Liskov Substitution & Interface Segregation
  • Dependency Inversion

Creational Design Patterns

  • Singleton Pattern
  • Factory & Abstract Factory
  • Builder Pattern
  • Prototype Pattern

Structural Design Patterns

  • Adapter & Facade
  • Decorator Pattern
  • Composite & Proxy
  • Bridge & Flyweight

Behavioral Design Patterns

  • Strategy Pattern
  • Observer Pattern
  • Command Pattern
  • Template Method
  • State Pattern
  • Chain of Responsibility
  • Iterator & Mediator
  • Visitor Pattern

Machine Coding Exercises

  • Parking Lot — Requirements & Class Design
  • Parking Lot — Implementation
  • Elevator System — Requirements & Class Design
  • Elevator System — Implementation & Scheduling
  • Library Management System
  • Tic-Tac-Toe / Board Game Design
  • Chess Engine Design
  • Vending Machine Design
  • ATM System Design
  • In-Memory Rate Limiter
  • Thread-Safe LRU Cache
  • Connection Pool Design
  • Producer-Consumer Class Design
  • Movie Ticket Booking System
  • Hotel Reservation System
  • Airline Booking / Seat Selection System
  • Splitwise / Expense Sharing System
  • Design a Logging Framework
  • Design a Notification/Observer-Based Pub-Sub
  • Design a Cache with Pluggable Eviction Policy
  • Design Snake and Ladder
  • Design a Card Game Framework
  • Design an Inventory Management System
  • Restaurant Management System
  • Food Delivery Order Matching
  • Design a Shopping Cart & Checkout Flow
  • Design a Recommendation Engine
  • Design a Job Scheduler
  • Design a Circuit Breaker
  • Design a Distributed ID Generator
  • Design a Pub-Sub Message Broker
  • Design Twitter/X
  • Multi-Pattern Problem: Design a Ride Booking Class Model
  • Multi-Pattern Problem: Design a Food Ordering Class Model
  • Design an Authentication/Authorization Module
  • Design a Form/Survey Builder
  • Design a Meeting Room / Calendar Booking System
  • Design a Search/Filter Engine for an E-Commerce Catalog
  • Design a Voting/Polling System
  • Design a Retry Mechanism with Backoff
  • Design a Health Check Aggregator
  • Design a Feature Flag System
  • Design a Config Management Client
  • Design a Leader Election Algorithm
  • Design a Distributed Counter
  • Design a Bloom Filter
  • Design a Consistent Hashing Ring
  • Design a Distributed Tracing Library
  • Design a Metrics Collection Library
  • Design an Audit Logging Framework
  • Design a Plugin/Extension System
  • Design a Workflow Engine
  • Multi-Pattern Capstone: Design a Food Delivery App
HomeLearnSystem DesignLow-Level Design & Design PatternsMachine Coding Exercises
✓ FreeIntermediate· 6 min read

Design a Logging Framework

Logger/LogLevel/Appender/Formatter classes, Chain of Responsibility for level filtering across multiple appenders, and thread safety for concurrent writes.

Published September 23, 2026


Design a Logging Framework

Core classes

enum LogLevel { DEBUG(0), INFO(1), WARN(2), ERROR(3); final int severity; LogLevel(int s) { severity = s; } }

interface Appender { void write(LogLevel level, String message); LogLevel getMinLevel(); }
interface Formatter { String format(LogLevel level, String message, Instant timestamp); }

class ConsoleAppender implements Appender {
    private final LogLevel minLevel;
    private final Formatter formatter;
    public void write(LogLevel level, String message) { System.out.println(formatter.format(level, message, Instant.now())); }
    public LogLevel getMinLevel() { return minLevel; }
}
class FileAppender implements Appender { /* similar, writes to a file */ }
class NetworkAppender implements Appender { /* similar, ships to a log aggregator */ }

Level filtering via Chain of Responsibility

class Logger {
    private final List<Appender> appenders;

    void log(LogLevel level, String message) {
        for (Appender appender : appenders) {
            if (level.severity >= appender.getMinLevel().severity) { // each appender independently decides to handle or pass
                appender.write(level, message);
            }
        }
    }
}

Each Appender independently decides whether a given log call meets its own minimum severity — a ConsoleAppender configured for INFO and a FileAppender configured for ERROR can both be registered on the same Logger, each filtering independently. This is Chain of Responsibility's core idea (see Chain of Responsibility) applied without an explicit "pass to next" call — every appender in the list gets a chance to handle the same log event, rather than one handler claiming it exclusively, which fits logging's actual requirement (multiple destinations, not a single winner).

Thread safety for concurrent writes

class FileAppender implements Appender {
    private final BufferedWriter writer; // NOT thread-safe by default

    public synchronized void write(LogLevel level, String message) { // synchronize the actual I/O
        try { writer.write(formatter.format(level, message, Instant.now())); writer.newLine(); }
        catch (IOException e) { /* handle */ }
    }
}

Multiple application threads logging concurrently to the same file (or console) need the actual write operation synchronized — without it, two threads' output can interleave mid-line, producing garbled, unreadable log output (not a crash, just corrupted data). A synchronized method on the appender is the simplest correct fix; a production logging framework typically also buffers writes and flushes asynchronously on a dedicated thread, to avoid every application thread blocking on I/O directly for every single log call.

Follow-up questions this topic invites — and their answers

Q: Why does each Appender hold its own minLevel rather than the Logger filtering once globally? A: Different destinations often need different verbosity — you might want DEBUG-level detail in a local file for troubleshooting but only ERROR-level alerts sent over the network, which requires per-destination filtering, not one global level applied uniformly everywhere.

Q: How would you avoid the console/file write blocking the calling thread on every log call? A: Route log messages through an internal queue (a BlockingQueue, see Concurrent Utilities & Coordination) that a dedicated background thread drains and writes — the calling application thread just enqueues and returns immediately, decoupling application throughput from I/O latency, at the cost of a small risk of losing buffered-but-unflushed messages on a crash.

Q: Is synchronized the right choice long-term, or would a lock-free approach be better under high log volume? A: For genuinely high-throughput logging, a lock-free ring buffer (the approach libraries like Log4j2's async appender use) avoids the contention a single synchronized method creates under many concurrent logging threads — worth naming as the production-grade evolution of this design, while synchronized remains a correct, simple starting point.

Q: How does this design relate to Distributed Tracing's correlation ID propagation? A: A production Logger implementation typically includes the current correlation/trace ID (from thread-local or reactive context, see Distributed Tracing) automatically in every formatted log line — extending this design's Formatter to pull that context in is the natural connection point between structured logging and distributed tracing.

Previous

Splitwise / Expense Sharing System

Next

Design a Notification/Observer-Based Pub-Sub

AI Tutor

Lesson: Design a Logging Framework

Quick actions

AI responses can be inaccurate. Verify critical information.