Unravel › Java concepts › 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
Different brands of the same dashboard camera: each records events with a time and a severity, but with different buttons and menus.
- 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).
- 2Log4j 2: LogManager.getLogger() with {} placeholders and ThreadContext for context valuesConfiguration is log4j2.xml (or YAML, properties).
- 3The facade (SLF4J, Commons Logging) lets a library log without choosing the backend; bridges route JUL and Log4j output into the chosen backend
- 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
- Log4j 2 versions before 2.17 had the "Log4Shell" vulnerability (message lookups could load remote code)
- 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
- JUL loggers form a tree by dotted names; a Logger has handlers (console, file) with formatters, and a Level
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()); }}- line 1 uses log, the core of Other logging APIs: JUL, Log4j, System.out
- line 3 uses getLogger, the core of Other logging APIs: JUL, Log4j, System.out
- line 5 uses log, the core of Other logging APIs: JUL, Log4j, System.out
- line 7 uses log, the core of Other logging APIs: JUL, Log4j, System.out
- 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.printlnin 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:
- Types:
LogManagerLevelConsoleHandlerFileHandlerLog4jHandlerFormatterThreadContextLogFactoryMarker - Method calls:
LogManager.getLogger()log()severe()warning()fine()
Part of a learning path
- Errors, logging and tests in depth · previous: Defensive checks: assert and preconditions · next: JUnit 5: parameterized tests and lifecycle
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.