BackendBench
Coffee

Unravel › Java concepts › Errors and logging

Errors and logging

Other logging APIs: JUL, Log4j, System.out

SLF4J is the usual facade, but code also uses java.util.logging (JUL, built into the JDK, with levels SEVERE to FINEST), Log4j 2 (LogManager.getLogger), Commons Logging, or plain System.out.

Learn these first

At a glance

Mental model

Different brands of the same dashboard camera: each records events with a time and a severity, but with different buttons and menus.

What happens, in order
  1. 1JUL: private static final Logger LOG = Logger.getLogger(Foo.class.getName()); LOG.log(Level.SEVERE, "failed " + id, e);Levels: SEVERE, WARNING, INFO, CONFIG, FINE, FINER, FINEST (INFO is the default threshold).
  2. 2Log4j 2: LogManager.getLogger() with {} placeholders and ThreadContext for context valuesConfiguration is log4j2.xml (or YAML, properties).
  3. 3The facade (SLF4J, Commons Logging) lets a library log without choosing the backend; bridges route JUL and Log4j output into the chosen backend
  4. 4System.out.println has no level, no timestamp, no file rotation and cannot be switched off without editing code: fine for scripts, wrong for services
Remember
Watch out
System.out.println in server codeLogging at SEVERE for expected situationsConcatenating strings for disabled levelsHaving two logging backends fight
Example (highlighted lines explain it)
import java.util.logging.*;public class Jobs {  private static final Logger LOG = Logger.getLogger(Jobs.class.getName());  static void run(int id) {    LOG.log(Level.INFO, "starting job {0}", id);    try { work(id); }    catch (RuntimeException e) { LOG.log(Level.SEVERE, "job " + id + " failed", e); }  }  static void work(int id) { if (id < 0) throw new IllegalArgumentException("id"); }  static void quiet() { LOG.setLevel(Level.WARNING); LOG.addHandler(new ConsoleHandler()); }}
  1. line 1 uses log, the core of Other logging APIs: JUL, Log4j, System.out
  2. line 3 uses getLogger, the core of Other logging APIs: JUL, Log4j, System.out
  3. line 5 uses log, the core of Other logging APIs: JUL, Log4j, System.out
  4. line 7 uses log, the core of Other logging APIs: JUL, Log4j, System.out
  5. line 10 uses Level, the core of Other logging APIs: JUL, Log4j, System.out
Read the full explanation (about 1 min)

SLF4J is the usual facade, but code also uses java.util.logging (JUL, built into the JDK, with levels SEVERE to FINEST), Log4j 2 (LogManager.getLogger), Commons Logging, or plain System.out. They all do the same job with different names.

A mental model

Different brands of the same dashboard camera: each records events with a time and a severity, but with different buttons and menus.

How it works

JUL: private static final Logger LOG = Logger.getLogger(Foo.class.getName()); LOG.log(Level.SEVERE, "failed " + id, e);. Levels: SEVERE, WARNING, INFO, CONFIG, FINE, FINER, FINEST (INFO is the default threshold).

Log4j 2: LogManager.getLogger() with {} placeholders and ThreadContext for context values. Configuration is log4j2.xml (or YAML, properties).

The facade (SLF4J, Commons Logging) lets a library log without choosing the backend; bridges route JUL and Log4j output into the chosen backend.

System.out.println has no level, no timestamp, no file rotation and cannot be switched off without editing code: fine for scripts, wrong for services.

Going deeper

Log4j 2 versions before 2.17 had the "Log4Shell" vulnerability (message lookups could load remote code). Keep it patched, and never log unescaped user input as a format string.

Check the level before building an expensive message (if (LOG.isLoggable(Level.FINE))), or use the lambda or placeholder forms so the work is skipped.

Mixing several backends on the class path produces missing or duplicate logs: choose one backend and bridge the rest.

Under the hood

JUL loggers form a tree by dotted names; a Logger has handlers (console, file) with formatters, and a Level. LogManager reads logging.properties once at startup, which is also how the JDK itself logs.

Common mistakes

  • System.out.println in server code.
  • Logging at SEVERE for expected situations.
  • Concatenating strings for disabled levels.
  • Having two logging backends fight.

How Unravel recognises it

When you paste code, Unravel looks for these signs of other logging apis: jul, log4j, system.out. Spotting them yourself is a good habit when you read unfamiliar code:

Part of a learning path

Related concepts

Frequently asked questions

What is Other logging APIs: JUL, Log4j, System.out?

SLF4J is the usual facade, but code also uses java.util.logging (JUL, built into the JDK, with levels SEVERE to FINEST), Log4j 2 (LogManager.getLogger), Commons Logging, or plain System.out. They all do the same job with different names.

What are the most common mistakes with Other logging APIs: JUL, Log4j, System.out?

System.out.println in server code. Logging at SEVERE for expected situations. Concatenating strings for disabled levels. Having two logging backends fight.

How can I see Other logging APIs: JUL, Log4j, System.out in real code?

Paste your own Java into Unravel and it will point out where other logging apis: jul, log4j, system.out appears, explain how it works at the detail level you choose, and draw the flow of the code around it.