0Pricing
Java Academy · Lesson

Parameterized Logging

Efficient message formatting.

Parameterized Logging is a free Java Academy lesson on CoddyKit — lesson 3 of 4. You can read the complete lesson below for free — then practise it hands-on in the browser with a built-in code editor and a 24/7 AI tutor. It is part of the Java Academy learning path, one of 4 lessons in the course, and your progress syncs across the web and the CoddyKit app.

The Problem With String Concatenation

Concatenating a log message builds the full string before the call, even if the level is disabled.

log.debug("id=" + id + " name=" + name) wastes CPU when DEBUG is off, because the string is built regardless.

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class Main {
    private static final Logger log = LoggerFactory.getLogger(Main.class);
    public static void main(String[] args) {
        String name = "Ada"; int id = 7;
        // Bad: string is built even if DEBUG is disabled
        log.debug("id=" + id + " name=" + name);
    }
}

Placeholders With {}

SLF4J uses {} as a placeholder. Pass the values as extra arguments.

The message is only assembled if the level is enabled, so disabled logs cost almost nothing.

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class Main {
    private static final Logger log = LoggerFactory.getLogger(Main.class);
    public static void main(String[] args) {
        String name = "Ada"; int id = 7;
        // Good: no string built unless DEBUG is on
        log.debug("id={} name={}", id, name);
    }
}

Multiple Placeholders

Placeholders are filled in order. The first {} takes the first argument, the second takes the second, and so on.

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class Main {
    private static final Logger log = LoggerFactory.getLogger(Main.class);
    public static void main(String[] args) {
        log.info("order {} for user {} totaling {} cents", "A-1", 42, 1599);
    }
}

Why It Is Efficient

The framework first checks the level. If disabled, it returns immediately without calling toString() on any argument.

The expensive part, formatting, happens lazily only when the message will actually be emitted.

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class Main {
    private static final Logger log = LoggerFactory.getLogger(Main.class);
    static String describe(Object o) { System.out.println("toString called"); return o.toString(); }
    public static void main(String[] args) {
        // Note: passing describe(...) still evaluates eagerly; pass the raw object instead
        log.trace("value={}", new int[]{1, 2, 3});
    }
}

Pass Raw Objects, Not Pre-formatted Strings

To get the laziness benefit, pass the raw object, not a method call that formats it.

If you write log.debug("{}", buildReport()), buildReport() still runs eagerly. Pass arguments the logger can format itself.

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class Main {
    private static final Logger log = LoggerFactory.getLogger(Main.class);
    public static void main(String[] args) {
        Object user = new Object();
        // Logger calls user.toString() only if DEBUG is enabled
        log.debug("current user: {}", user);
    }
}

Lazy Suppliers for Heavy Work

When formatting is genuinely expensive, use the SLF4J 2.x fluent API with a Supplier so the work is deferred.

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class Main {
    private static final Logger log = LoggerFactory.getLogger(Main.class);
    static String heavyReport() { return "...expensive..."; }
    public static void main(String[] args) {
        log.atDebug()
           .setMessage("report: {}")
           .addArgument(() -> heavyReport())
           .log();
    }
}

Escaping a Literal Brace

If you need a literal {} in the message, escape it with a backslash: \\{}.

This is rare, but useful when logging JSON-like text.

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class Main {
    private static final Logger log = LoggerFactory.getLogger(Main.class);
    public static void main(String[] args) {
        // Logs a literal {} then the value
        log.info("empty object is \\{} and id is {}", 7);
    }
}

Exception Plus Placeholders

You can combine placeholders with a trailing exception. SLF4J detects that the last argument is a Throwable and prints its stack trace.

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class Main {
    private static final Logger log = LoggerFactory.getLogger(Main.class);
    public static void main(String[] args) {
        int id = 99;
        try {
            throw new RuntimeException("db down");
        } catch (Exception e) {
            log.error("failed processing record {}", id, e);
        }
    }
}

Avoid Too Many Arguments

If the placeholder count and argument count mismatch, SLF4J does its best but the output may look wrong.

Keep them in sync. For more than a couple of values, consider structured context (MDC) instead.

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class Main {
    private static final Logger log = LoggerFactory.getLogger(Main.class);
    public static void main(String[] args) {
        // Two placeholders, two arguments: correct
        log.info("user {} did {}", "ada", "login");
    }
}

Adding Context With MDC

For values shared across many lines (like a request id), put them in the MDC rather than every message.

The pattern layout can then print the MDC value on every line automatically.

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.slf4j.MDC;

public class Main {
    private static final Logger log = LoggerFactory.getLogger(Main.class);
    public static void main(String[] args) {
        MDC.put("requestId", "req-1234");
        try {
            log.info("handling request");
            log.info("request done");
        } finally {
            MDC.clear();
        }
    }
}

Best Practices Summary

Rules for efficient logging:

  • Always use {} placeholders, never + concatenation.
  • Pass raw objects, not pre-built strings.
  • Use suppliers or isXEnabled() for truly heavy work.
  • Use MDC for cross-cutting context.
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class Main {
    private static final Logger log = LoggerFactory.getLogger(Main.class);
    public static void main(String[] args) {
        log.info("processed {} items in {} ms", 1000, 42);
    }
}

Quick Check

Test your parameterized logging knowledge.

Recap

You learned parameterized logging:

  • Use {} placeholders with extra arguments.
  • Messages build lazily, only when the level is on.
  • Pass raw objects; use suppliers for heavy work.
  • Use MDC for shared contextual values.

Next, configuring the Logback backend.

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class Main {
    private static final Logger log = LoggerFactory.getLogger(Main.class);
    public static void main(String[] args) {
        log.info("Parameterized logging recap: {}", "done");
    }
}

Frequently asked questions

Is the “Parameterized Logging” lesson free?

Yes — the full text of “Parameterized Logging” is free to read here on the web, and the Java Academy course includes 4 lessons in total. To practise it interactively (a built-in code editor and a 24/7 AI tutor) and unlock the rest of the Java Academy course, upgrade to CoddyKit PRO.

What will I learn in “Parameterized Logging”?

Efficient message formatting. You practise Java Academy with hands-on code you run directly in the browser, and a 24/7 AI tutor answers your questions as you work through the lesson.

Do I need any experience to start Java Academy?

No prior experience is required. Java Academy on CoddyKit is structured for beginners through advanced learners; this is — lesson 3 of 4, so you can start here or from the beginning and move at your own pace.

How long does the “Parameterized Logging” lesson take?

Most CoddyKit lessons take about 5–10 minutes. Each one is bite-sized and interactive, so you make steady progress and pick up exactly where you left off across the web and the app.

Can I write and run code in this Java Academy lesson?

Yes. Every Java Academy lesson includes a built-in code editor, so you write and run real code right in your browser and get instant AI feedback — no local setup required.

All lessons in this course

  1. Why Structured Logging
  2. SLF4J Facade and Loggers
  3. Parameterized Logging
  4. Configuring Logback
← Back to Java Academy