🎯 TL;DR: Loggers are the entry point into the logging framework and determine what gets logged, where it gets logged, and at what level it gets logged. Most production logging problems are not caused by Log4j2 itself but by poorly designed logger hierarchies, incorrect log levels, and inconsistent logging strategies. The single most important thing senior engineers must understand is that every log statement is both an operational asset and a performance cost.
📘 Theory & Internals
What is a Logger?
🧠 Plain English: A logger is like a department manager in a large company. Every event generated by employees passes through the manager before being recorded in company records.
A Logger is the primary component responsible for creating log events.
Example:
private static final Logger logger =
LoggerFactory.getLogger(UserService.class);
Whenever application code executes:
logger.info("User created");
the logger creates a log event and sends it into the logging pipeline.
Internally a logger manages:
- Log level filtering
- Logger inheritance
- Event creation
- Appender delegation
- Context information
Why Logger Hierarchy Exists
Imagine a large enterprise application:
com.company
├── user
├── payment
├── notification
├── order
└── inventory
Creating independent configurations for thousands of classes would be impossible.
Logger hierarchy solves this problem.
Example:
com.company
│
├── com.company.user
│ │
│ └── UserService
│
├── com.company.order
│ │
│ └── OrderService
Children inherit configuration from parents.
Logger Naming Convention
Best practice:
LoggerFactory.getLogger(UserService.class);
Produces:
com.company.service.UserService
Bad practice:
LoggerFactory.getLogger("Logger");
This removes hierarchy benefits.
Logger Hierarchy Example
Root Logger (INFO)
│
▼
com.company (INFO)
│
▼
com.company.payment (DEBUG)
│
▼
PaymentService
Configuration:
<Logger name="com.company.payment"
level="DEBUG"/>
Only payment-related classes receive DEBUG logging.
Everything else remains INFO.
Effective Log Level Resolution
Log4j2 resolves levels using inheritance.
Example:
Root = INFO
com.company = INFO
com.company.payment = DEBUG
Class:
com.company.payment.PaymentService
Effective Level:
DEBUG
Class:
com.company.user.UserService
Effective Level:
INFO
Internal Log Level Evaluation
logger.debug("Payment Started")
│
▼
Current Level = INFO
│
▼
DEBUG < INFO
│
▼
Discard Event
No LogEvent object proceeds further.
This optimization saves CPU.
Understanding Log Levels
TRACE
Most detailed level.
Purpose:
- Method entry
- Method exit
- Internal framework diagnostics
Example:
logger.trace("Entering method processOrder()");
Production usage:
Rare.
DEBUG
Used during troubleshooting.
Example:
logger.debug("Fetched {} records", count);
Production usage:
Temporary debugging.
INFO
Most important level.
Used for:
- Business events
- Application startup
- Major workflow completion
Example:
logger.info("Order created id={}", orderId);
WARN
Used when something unexpected occurs but application continues.
Example:
logger.warn("Retry attempt {}", attempt);
ERROR
Used for failures.
Example:
logger.error("Payment failed", exception);
FATAL
Critical failure.
Example:
logger.fatal("Database unavailable");
In many modern systems ERROR and FATAL are treated similarly.
Recommended Logging Strategy
| Event | Level |
|---|---|
| Application Startup | INFO |
| Business Transaction | INFO |
| Validation Failure | WARN |
| External Service Failure | ERROR |
| Debugging Details | DEBUG |
| Framework Internal Diagnostics | TRACE |
What Should Be Logged?
Good candidates:
User Login
Order Creation
Payment Success
Payment Failure
Service Startup
Configuration Loading
Security Violations
Database Connectivity Issues
What Should NOT Be Logged?
Bad candidates:
Getter Calls
Setter Calls
Loop Iterations
Every SQL Query
Passwords
Credit Card Numbers
JWT Tokens
Logging Strategy in Microservices
🧠 Plain English: If every employee sends every email to the CEO, important information gets buried. Logging works the same way.
Bad Logging:
logger.info("Entering method");
logger.info("Loop started");
logger.info("Loop iteration");
logger.info("Loop completed");
Good Logging:
logger.info(
"Order processed id={} amount={}",
orderId,
amount);
Structured Event Thinking
Instead of:
logger.info("Order completed");
Use:
logger.info(
"Order completed id={} user={} amount={}",
orderId,
userId,
amount);
Future troubleshooting becomes dramatically easier.
Failure Modes
Log Flooding
Symptoms:
High CPU
Large Log Files
Slow Application
Disk Full
Cause:
Excessive INFO or DEBUG logging.
Missing Business Context
Bad:
logger.error("Payment Failed");
Good:
logger.error(
"Payment Failed paymentId={} userId={}",
paymentId,
userId);
Incorrect Log Levels
Bad:
logger.error("Application Started");
Startup is not an error.
Correct:
logger.info("Application Started");
Duplicate Logging
Bad:
logger.error("Payment failed");
throw exception;
Global exception handler logs again.
Result:
Duplicate entries.
Logger Additivity
One of the most misunderstood Log4j2 features.
Root Logger
│
▼
Payment Logger
If additivity=true:
Payment Logger Writes
+
Root Logger Writes
Result:
Duplicate logs.
Configuration:
<Logger name="com.company.payment"
additivity="false">
</Logger>
Observability Considerations
Monitor:
ERROR Rate
WARN Rate
INFO Volume
Logger Throughput
Duplicate Log Growth
Useful alerts:
ERROR logs > 200/min
WARN logs > 500/min
Disk > 80%
Performance Impact of Logging
Approximate costs:
| Operation | Relative Cost |
|---|---|
| TRACE | High |
| DEBUG | Medium |
| INFO | Medium |
| WARN | Medium |
| ERROR | High (Stack Trace) |
Stack traces are expensive.
Example:
logger.error("Failed", exception);
Generates large output.
⚠️ Warning: Excessive ERROR logging can become a production bottleneck because stack trace generation is expensive.
💡 Pro Tip: Log business events at INFO and technical details at DEBUG.
🚨 Critical: Never log authentication tokens, passwords, credit card data, session IDs, API keys, or encryption keys.
⚖️ Comparisons
Log Level Comparison
| Level | Use Case | Performance Impact | Production Usage |
|---|---|---|---|
| TRACE | Internal diagnostics | Highest | Rare |
| DEBUG | Troubleshooting | High | Temporary |
| INFO | Business events | Moderate | Common |
| WARN | Recoverable issues | Moderate | Common |
| ERROR | Failures | High | Common |
| FATAL | Critical failures | High | Rare |
⚠️ Common Mistake: Developers frequently log everything at INFO. This makes production logs noisy and hides important operational signals.
Good vs Bad Logging
| Approach | Example | Result |
|---|---|---|
| Generic | "Error occurred" | Useless |
| Contextual | "Payment failed id=123" | Actionable |
| Sensitive Data | Password logged | Security issue |
| Structured Logging | Key-value data | Searchable |
Recommendation: Use contextual INFO logs for business events and structured ERROR logs for failures.
💻 Code Examples
Example 1 — Basic Logger Usage
// ✅ Proper Logger Declaration
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class UserService {
private static final Logger logger =
LoggerFactory.getLogger(UserService.class);
public void createUser() {
// ✅ Correct
logger.info("User creation started");
// ❌ Wrong
System.out.println("User creation started");
}
}
Example 2 — Contextual Logging
// ✅ Business Context Logging
public void createOrder(Long orderId,
Long userId) {
logger.info(
"Order created orderId={} userId={}",
orderId,
userId);
// ❌ Bad
logger.info("Order created");
}
Example 3 — Production-Grade Logging
// ✅ Production Error Handling
public Payment processPayment(
Long paymentId) {
try {
logger.info(
"Payment started paymentId={}",
paymentId);
Payment payment =
paymentGateway.process(paymentId);
logger.info(
"Payment completed paymentId={}",
paymentId);
return payment;
} catch (Exception ex) {
logger.error(
"Payment failed paymentId={}",
paymentId,
ex);
throw ex;
}
}
Anti-Pattern Block
| Anti-Pattern | Code | What Goes Wrong |
|---|---|---|
| Generic Message | "Error occurred" | No debugging context |
| Password Logging | logger.info(password) | Security breach |
| INFO Everywhere | All logs INFO | Signal lost in noise |
| Duplicate Logging | Local + Global logging | Duplicate entries |
| Loop Logging | Log inside loops | Massive log volume |
🏗️ Real-World Scenarios
Scenario 1
Situation → A payment service generated 300 GB logs daily. Storage costs increased by 400%.
Root Cause → Developers logged every API request payload at INFO level.
Solution → Move payload logging to DEBUG and enable only during investigations.
Outcome → Daily log volume reduced from 300 GB to 28 GB.
💡 Lesson: Every log statement has a storage cost.
Scenario 2
Situation → Engineers received an alert for payment failures but could not identify affected customers.
Root Cause → Error logs lacked order IDs and user IDs.
Solution → Introduced contextual logging.
Outcome → Mean time to resolution reduced from 2 hours to 12 minutes.
💡 Lesson: Context is more valuable than verbosity.
Scenario 3
Situation → Engineers were paged at 2 AM because monitoring showed 95% CPU utilization.
Root Cause → TRACE logging accidentally enabled in production after troubleshooting.
Solution → Revert logging configuration and introduce deployment validation.
Outcome → CPU utilization dropped from 95% to 42%.
💡 Lesson: Log levels directly impact system performance.
🎯 Interview Q&A
Q1 [Easy] What is a logger?
A: A logger is the component responsible for creating log events and forwarding them through the logging framework. It acts as the entry point for application logging. Loggers also manage level filtering and hierarchy inheritance.
Q2 [Easy] Why should logger names match class names?
A: Class-based logger names automatically create meaningful hierarchies and simplify troubleshooting. They also allow package-level configuration.
Q3 [Medium] Explain logger hierarchy.
A: Loggers inherit configuration from parent loggers. This allows centralized configuration and reduces duplication. Child loggers may override inherited settings.
Q4 [Medium] What is effective log level?
A: Effective log level is the final level a logger uses after inheritance rules are applied. If no explicit level exists, the parent level is inherited.
Q5 [Medium] What is additivity?
A: Additivity determines whether log events propagate to parent loggers. If enabled, the same event may be written multiple times.
Q6 [Hard] Why are stack traces expensive?
A: Stack traces require object creation, stack walking, formatting, and large I/O operations. Excessive exception logging can significantly impact performance.
Q7 [Hard] How would you identify log flooding?
A: Analyze log volume trends, disk growth, CPU utilization, and logging throughput metrics. Large INFO spikes often indicate logging misuse.
Q8 [Hard] AI-generated code logs entire request objects. Why can this be dangerous?
A: Request objects often contain sensitive information, large payloads, and circular references. This can create security, performance, and storage issues.
Q9 [Hard] Should every exception be logged?
A: No. Exceptions should be logged at the handling boundary. Logging the same exception multiple times creates noise and duplicate stack traces.
Q10 [System Design] How would you define logging standards for 200 microservices?
A: Standardize logger naming, log levels, structured logging, correlation IDs, retention policies, and centralized monitoring.
Q11 [System Design] How would you reduce logging costs by 50%?
A: Eliminate unnecessary INFO logs, reduce payload logging, archive old logs, and introduce retention policies.
Q12 [Hard] When should WARN be used?
A: WARN should indicate unusual conditions that do not stop application execution but require visibility.
Q13 [Hard] Why are business events usually INFO level?
A: Business events represent normal application behavior and are useful for auditing and operational monitoring.
📋 Revision Cheat Sheet
- Logger is the entry point responsible for creating log events.
- Class-Based Logger Names provide automatic hierarchy and easier configuration.
- Logger Hierarchy allows child loggers to inherit parent settings.
- Effective Log Level is determined after inheritance rules are applied.
- TRACE should only be enabled during deep diagnostics.
- DEBUG is useful for troubleshooting but should not remain enabled permanently in production.
- INFO should capture meaningful business events.
- WARN indicates recoverable issues that deserve attention.
- ERROR represents failures requiring investigation.
- Additivity=true may cause duplicate log entries.
- Stack Traces are expensive due to formatting and I/O overhead.
- Contextual Logging with IDs dramatically improves troubleshooting speed.
- Never Log Sensitive Data such as passwords, tokens, or credit card numbers.
- Loop Logging can generate enormous log volumes and should be avoided.
- Structured Logging is more searchable and operationally useful than free-form text.