Design a Logger with Independent Handlers
Company: Rippling
Role: Software Engineer
Category: Software Engineering Fundamentals
Difficulty: medium
Interview Round: Technical Screen
# Design a Logger with Independent Handlers
Design a logging library in which each handler is independent. A logger may dispatch one record to console, file, remote, or future handlers, but a handler owns its own filtering, formatting, buffering, failures, and lifecycle. Adding or removing one handler must not require changes to the others.
### Constraints & Assumptions
- A log record contains timestamp, severity, message, logger name, and structured fields.
- Handlers may be synchronous or asynchronous.
- A slow or failed remote handler must not corrupt another handler's output.
- Configuration can change while the process is running.
- Recursive logging from inside a handler must be controlled.
### Clarifying Questions to Ask
- Is ordering required globally, per logger, or per handler?
- May a handler drop records under pressure?
- What flush and shutdown guarantees are required?
- How should handler failures be surfaced to the application?
### Part 1 - Interfaces and ownership
Define logger, record, filter, formatter, and handler contracts. State which component owns mutable state and lifecycle.
#### What This Part Should Cover
- Immutable records at the dispatch boundary
- Handler-local filter, formatter, and sink
- Open extension without logger type checks
- Explicit start, flush, close, and error behavior
### Part 2 - Isolation and concurrency
Explain dispatch, asynchronous queues, backpressure, ordering, exception isolation, and recursion protection.
#### What This Part Should Cover
- One handler cannot mutate another's view
- Bounded queues and documented overflow policy
- Per-handler ordering semantics
- Failure reporting outside the normal logging path
### Part 3 - Configuration and testing
Describe safe handler replacement and tests for independent behavior, overload, shutdown, and partial failure.
#### What This Part Should Cover
- Atomic configuration snapshots
- Graceful drain and resource ownership
- Fault-injection and concurrency tests
- Metrics for drops, lag, and sink errors
```hint Dispatch an immutable record
Independence is much easier when handlers receive the same immutable value and cannot modify shared formatting or sink state.
```
### What a Strong Answer Covers
- Narrow handler interfaces with clear ownership and lifecycle
- Isolation of state, failures, formatting, and backpressure
- Deterministic ordering and shutdown guarantees
- Runtime configuration plus tests that force one handler to fail or stall
### Follow-up Questions
1. How would you prevent an error reported by a handler from recursively entering that handler?
2. What does `flush` mean for an asynchronous remote handler?
3. How can configuration be replaced without losing records or using a closed sink?
Quick Answer: Design a logging library with independent handlers, immutable records, isolated failures, bounded backpressure, and safe runtime reconfiguration.