To measure the cost of string concatenation in logging, compare eager concatenation, parameterized logging, and lazy or guarded argument computation under the same workload, with the log level both disabled and enabled. Keep message construction and formatting separate from appenders and output: otherwise a benchmark cannot tell you whether its result comes from concatenation, the logger, or I/O.
What changes when a log level is disabled?
With eager concatenation, Java constructs the message before calling the logger. For example, logger.debug("id=" + id) performs the concatenation even if DEBUG is disabled and the logger discards the event. If a value’s conversion or computation is expensive, that work may happen too.
A parameterized call such as logger.debug("id={}", id) gives the logging API the template and argument separately. SLF4J says its parameterized overloads avoid superfluous string concatenation when the relevant level is disabled. The logger can check whether to accept the event before formatting the message. Apache Log4j likewise recommends message parameters and suggests Suppliers for expensive arguments. Log4j performance guidance explains these patterns.
Parameterization does not automatically defer every expression used to obtain an argument. If computing an argument is costly, use a supported lazy form or guard the call so the computation occurs only when the level is enabled.
The Tool Desk
Outbyte Driver Updater FREEScan for outdated or missing drivers - takes under a minuteDriver Scan →Outbyte PC Repair FREERepair Windows errors before they cause bigger problemsFix Now →Which logging forms should you benchmark?
Use the same logger, level, values, message shape, and workload for each version. Include at least these cases:
- Eager concatenation:
logger.debug("Entry number: " + i + " is " + entry[i]); - Parameterized message:
logger.debug("Entry number: {} is {}", i, entry[i]); - Lazy expensive argument:
logger.debug("User role: {}", () -> lookupRole(userId));, using the Supplier form supported by your logging API. - Explicit guard: check
logger.isDebugEnabled()before computing an expensive value, then make the logging call inside the guard.
Run each relevant case with DEBUG disabled and enabled. The disabled case reveals work performed before the logger rejects an event. The enabled case also includes message formatting and whatever downstream processing your configuration performs.
Rank #2
How do you isolate concatenation from logging and I/O?
A logging call can include several distinct costs: evaluating arguments, constructing a message, formatting parameters, applying a layout or encoder, passing the event through an appender, and writing to a sink. Console, file, asynchronous, and structured logging configurations can behave differently. If the benchmark writes every event to a terminal or file, sink throughput may dominate the result and obscure the construction cost you meant to measure.
Design separate measurements for the question you want to answer:
- Disabled-level overhead: keep the level disabled and compare eager concatenation, parameterized calls, and guarded or lazy computation. Avoid output, since no event should be emitted.
- Message and formatting cost: enable the level but use a controlled appender or benchmark setup that avoids real console or disk I/O. Keep the layout or encoder consistent across variants.
- End-to-end logging cost: measure the actual appender, layout or encoder, and sink used in deployment. Report this separately from message-construction results.
State exactly what the benchmark includes. A number from a disabled logger is not comparable to one that includes formatting or output.
What benchmark details affect the result?
Use a Java microbenchmark harness such as JMH for controlled runs. Match the target JDK and logging implementation, and record the configuration rather than treating a result as a universal cost. At minimum, document:
Rank #4
- JDK version, logging framework and version, and relevant logger configuration.
- Whether the log level is enabled, plus the layout, encoder, appender, and sink.
- Message length, parameter count, value types, and whether any argument invokes expensive computation or
toString(). - Warm-up, measurement repetitions, and whether results are reported as latency, throughput, or both.
- Allocation rate and output volume, so a faster result is not mistaken for a lower-allocation one or for a run that emitted less data.
Vary message size and parameter count when they matter to your application. Log4j notes that formatting cost increases with the number of parameters. Keep the workload otherwise matched so that a difference between variants has an interpretable cause. Log4j’s performance documentation discusses these factors and notes that results can vary between runs.
How should published nanosecond figures be interpreted?
Apache Log4j’s performance documentation reports historical averages from a 2.53 GHz Intel Core 2 Duo MacBook Pro. In its disabled-level checks, it gives 4 ns for Log4j, 5 ns for Logback, and 3 ns for Log4j 2. Its concatenation-heavy comparison gives averages of 188 ns for Log4j, 183 ns for Logback, and 188 ns for Log4j 2. These are figures for the documented test environment, not constants that can be applied to a current machine, JDK, message, or logging configuration. The documentation also warns that results vary between runs.
Recommended Free Tools
Best Value
Use those values as historical examples of how strongly the measured operation and environment matter, not as a prediction of your service’s overhead. To make a useful decision, benchmark the deployment JDK, logger, message sizes, and output path that your code actually uses.
Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.Can parameterized logging still allocate?
It can. SLF4J documents fixed-arity parameterized overloads and a varargs form; calls with three or more arguments can create an Object[]. When allocation matters, prefer the available fixed-arity overloads where practical and measure allocation rate along with timing. The SLF4J Logger API documents the overloads and their behavior.
Also distinguish passing an existing value from calculating one. Parameterization can defer formatting, but it does not make arbitrary argument expressions lazy. For expensive work, use a Supplier supported by the framework or an explicit enabled-level guard.
How can you prevent eager concatenation?
JetBrains Inspectopedia documents an inspection for non-constant concatenations passed to SLF4J and Log4j 2 logging methods. It flags a pattern that can perform message construction even when the event is disabled and recommends parameterized messages. The inspection documentation can help teams enable the check in IDE review or CI.
For ordinary log messages, use placeholders. Reserve guards or Supplier forms for values whose computation or conversion is expensive, and verify that the chosen API actually defers that work.
Quick Recap
Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.

