Topics log4j TOPIC 2: Loggers, Logger Hierarchy, Log Levels & Effective Logging Strategies
Back Sign up to track progress
log4j

TOPIC 2: Loggers, Logger Hierarchy, Log Levels & Effective Logging Strategies

Sign up free to track your views & progress

🎯 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.

EventLevel
Application StartupINFO
Business TransactionINFO
Validation FailureWARN
External Service FailureERROR
Debugging DetailsDEBUG
Framework Internal DiagnosticsTRACE

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:

OperationRelative Cost
TRACEHigh
DEBUGMedium
INFOMedium
WARNMedium
ERRORHigh (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

LevelUse CasePerformance ImpactProduction Usage
TRACEInternal diagnosticsHighestRare
DEBUGTroubleshootingHighTemporary
INFOBusiness eventsModerateCommon
WARNRecoverable issuesModerateCommon
ERRORFailuresHighCommon
FATALCritical failuresHighRare

⚠️ Common Mistake: Developers frequently log everything at INFO. This makes production logs noisy and hides important operational signals.

Good vs Bad Logging

ApproachExampleResult
Generic"Error occurred"Useless
Contextual"Payment failed id=123"Actionable
Sensitive DataPassword loggedSecurity issue
Structured LoggingKey-value dataSearchable

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-PatternCodeWhat Goes Wrong
Generic Message"Error occurred"No debugging context
Password Logginglogger.info(password)Security breach
INFO EverywhereAll logs INFOSignal lost in noise
Duplicate LoggingLocal + Global loggingDuplicate entries
Loop LoggingLog inside loopsMassive 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.
Done reading this topic? Sign up free to track your progress.
Sign Up to Track