Study guide

16.2 Java Logging API Basics: Logger, Levels, Handlers, and Configuration

Oracle Java SE 17 Developer Certified Professional 1Z0-829

Track your progress as you read

Finished sections get a check mark.

1 Introduction: The 1Z0-829 Exam

About the Java SE 17 Developer (1Z0-829) Exam

2 Chapter 1: Java Fundamentals & Language Basics

1.1 Primitive Types, Literals, Wrapper Classes, and Type Promotion/Casting 1.2 Local Variable Type Inference (`var`) Rules and Scoping 1.3 Operators, Precedence, Evaluation Order, and Short-Circuit Evaluation 1.4 Text Blocks, String Immutability, and StringBuilder APIs

3 Chapter 2: Program Flow & Decision Constructs

2.1 Conditional Branching with if/else and the Ternary Operator 2.2 Switch Statements and Switch Expressions 2.3 Iteration Constructs, Loop Control, and Branching Labels

4 Chapter 3: Object-Oriented Design & Class Mechanics

3.1 Class Declarations, Field/Method Signatures, and Access Modifiers 3.2 Constructors, Overloading, Initialization Order, and Garbage Collection 3.3 Inheritance, Method Overriding, Polymorphism, and `super`/`this` 3.4 Abstract Classes, Static Members, and Object Methods (`equals`, `hashCode`, `toString`)

5 Chapter 4: Advanced OOP: Interfaces, Records & Sealed Types

4.1 Interface Architecture: Default, Static, and Private Methods 4.2 Enumerations: Constants, Constructors, Methods, and Custom Bodies 4.3 Records: Canonical/Compact Constructors, Components, and Immutability 4.4 Sealed Classes and Interfaces: `permits`, Hierarchy Constraints, and Modifiers

6 Chapter 5: Pattern Matching & Nested Types

5.1 Pattern Matching for `instanceof` and Flow Scoping Mechanics 5.2 Nested Types: Member Inner, Static Nested, Local, and Anonymous Classes 5.3 Defensive Programming, Immutability Patterns, and Validation

7 Chapter 6: Generics, Collections & Arrays

6.1 Generic Classes, Interfaces, Methods, and Type Erasure 6.2 Bounded Type Parameters and Wildcards (PECS Rule) 6.3 Collections Framework: List, Set, Queue, and Deque APIs 6.4 The Map Interface, Sorting, Comparable, and Comparator 6.5 Arrays: Declaration, Initialization, Multidimensional Arrays, and the Arrays Utility Class

8 Chapter 7: Functional Programming & Lambda Expressions

7.1 Functional Interfaces and Lambda Syntax Rules 7.2 Standard Functional Interfaces in `java.util.function` 7.3 Method References: Static, Bound, Unbound, and Constructor References

9 Chapter 8: The Stream API

8.1 Stream Lifecycle: Creation, Pipeline Architecture, and Lazy Evaluation 8.2 Intermediate Stream Operations: Filtering, Mapping, Sorting, and Slicing 8.3 Terminal Stream Operations: Reduction, Matching, Finding, and Collecting 8.4 Primitive Streams (`IntStream`, `LongStream`, `DoubleStream`) and Numeric Statistics

10 Chapter 9: Advanced Streams & Collectors

9.1 The Optional Class: Safe Null Handling, Transformation, and Chaining 9.2 The Collectors API: Downstream Reductions, Grouping, and Partitioning 9.3 Parallel Streams: Fork/Join Pool, Spliterators, and Concurrency Pitfalls

11 Chapter 10: Exception Handling

10.1 The Java Exception Hierarchy: Checked vs. Unchecked Exceptions and Errors 10.2 Exception Constructs: `try-catch-finally`, Multi-Catch, and Rethrowing 10.3 Try-With-Resources, `AutoCloseable`, Suppressed Exceptions, and Custom Exceptions

12 Chapter 11: Date/Time API & Localization

11.1 Date and Time Core Types: `LocalDate`, `LocalTime`, `LocalDateTime` 11.2 Timestamps, Intervals, and Durations: `Instant`, `Period`, and `Duration` 11.3 Time Zones, Daylight Saving Time (DST) Offsets, and `ZonedDateTime` 11.4 Internationalization and Localization: `Locale`, `ResourceBundle`, and Formatters 11.5 Formatting and Parsing Messages, Numbers, Percentages, and Localized Dates

13 Chapter 12: Java Platform Module System (JPMS)

12.1 Module Architecture, `module-info.java`, and Module Paths 12.2 Module Directives: `requires`, `requires transitive`, `exports`, and Qualified Exports 12.3 Reflection, Deep Encapsulation, `opens`, and Open Modules 12.4 Services in JPMS (`uses`, `provides...with`), Migration Paths, and Tooling (`jlink`, `jdeps`) 12.5 Compiling and Packaging Code: Non-Modular JARs, Modular JARs, and Migration Strategies

14 Chapter 13: Concurrency & Multithreading

13.1 Thread Fundamentals, `Runnable`, `Callable`, and Thread Lifecycle 13.2 Memory Visibility, `volatile`, Intrinsic Locks, and Synchronization 13.3 The Concurrency Framework: `ExecutorService`, Thread Pools, and `Future` 13.4 Concurrent Collections, Atomic Variables, Explicit Locks, and `CompletableFuture`

15 Chapter 14: Java I/O and NIO.2

14.1 Classical I/O: Byte and Character Streams, Readers, Writers, and Buffering 14.2 Object Serialization, `Serializable`, `transient`, and `serialVersionUID` 14.3 NIO.2 Architecture: `Path`, `Paths`, and Basic `Files` Operations 14.4 Advanced NIO.2: Directory Walking, Streams (`Files.lines`, `walk`), and `WatchService`

16 Chapter 15: Accessing Databases with JDBC

15.1 JDBC Architecture, Drivers, `DriverManager`, and `DataSource` Connections 15.2 SQL Execution: `Statement`, `PreparedStatement`, and `CallableStatement` 15.3 `ResultSet` Navigation, Data Types, and Transaction Management (Commit, Rollback, Savepoints)

17 Chapter 16: Annotations & the Java Logging API

16.1 Standard Annotations: @Override, @FunctionalInterface, @Deprecated, @SuppressWarnings, and @SafeVarargs 16.2 Java Logging API Basics: Logger, Levels, Handlers, and Configuration

16.2 Java Logging API Basics: Logger, Levels, Handlers, and Configuration

Key Takeaways Explain This Topic AI

java.util.logging defines seven standard levels from SEVERE (1000) down to FINEST (300), plus OFF and ALL.

With the default JDK configuration the root logger and its ConsoleHandler use INFO, so fine() messages are not printed.

A log record must pass the logger's level and then each handler's level, so lowering only the logger level to FINE still hides FINE output.

Records also go to parent handlers unless setUseParentHandlers(false) is called, which is why an added handler can print duplicate lines.

The java.util.logging.config.file system property loads a logging.properties file with entries such as .level=INFO and com.shop.level=FINE.

Last updated: October 2026

16.2 Java Logging API Basics: Logger , Levels, Handlers, and Configuration

Oracle also expects candidates to "understand the basics of Java Logging API." The standard API is java.util.logging in the java.logging module, so a modular application needs requires java.logging; . The exam-level skills are obtaining a logger, choosing levels, predicting which messages print, and reading a basic configuration.

  • Obtaining and Using a Logger import java.util.logging.Level;
  • import java.util.logging.Logger;
  • public class OrderService {
  • private static final Logger LOG = Logger.getLogger(OrderService.class.getName());
  • void place(int id, int tries) {
  • LOG.info("Placing order " + id);
  • LOG.log(Level.WARNING, "Order {0} failed after {1} tries", new Object[] {id, tries});
  • LOG.fine(() -> "Expensive debug text " + id); // Supplier: built only if FINE is enabled
  • try {
  • throw new IllegalStateException("payment declined");
  • } catch (IllegalStateException e) {
  • LOG.log(Level.SEVERE, "Order failed", e); // prints the message plus the stack trace
  • }
  • }
  • }

Logger.getLogger(name) returns the logger for a dot-separated name, usually the class name. Calling it again with the same name returns the same instance ( log == Logger.getLogger("com.shop.Orders") is true while the logger is in use).

Loggers form a hierarchy by name: com.shop.Orders is a child of com.shop , and the root logger has the empty name "" .

Convenience methods exist for each level ( severe , warning , info , config , fine , finer , finest ), plus log(Level, String) , log(Level, String, Object[]) with {0} -style parameters, and log(Level, String, Throwable) .

isLoggable(Level) tells you whether a message at that level would pass the logger's level check.

The Seven Standard Levels

  • Level intValue() Typical use
  • SEVERE 1000 Serious failures
  • WARNING 900 Potential problems
  • INFO 800 Informational messages (the default threshold)
  • CONFIG 700 Configuration details
  • FINE 500 Tracing information
  • FINER 400 Detailed tracing
  • FINEST 300 Most detailed tracing

Level.OFF ( Integer.MAX_VALUE ) disables logging, and Level.ALL ( Integer.MIN_VALUE ) enables everything. A message is published when its level value is greater than or equal to the threshold.

Why fine() Prints Nothing by Default

With the JDK's default configuration, the root logger's level is INFO and it has one ConsoleHandler , also at level INFO , that writes to System.err . A new named logger has a null level, so it inherits the effective level INFO from its parent. As a result, info , warning , and severe messages appear, while config , fine , finer , and finest messages do not.

Every message must pass two filters :

The logger's level (its own or the inherited one).

The handler's level for each handler that receives the record. Logger log = Logger.getLogger("com.shop.Orders");

  • log.setLevel(Level.FINE);
  • log.fine("A"); // still NOT shown: the root ConsoleHandler is INFO
  • ConsoleHandler handler = new ConsoleHandler();
  • handler.setLevel(Level.FINE);
  • log.addHandler(handler);
  • log.info("B"); // printed TWICE: by this handler and by the root handler
  • log.setUseParentHandlers(false);
  • log.fine("C"); // printed once, by this handler only

Records travel up the hierarchy to the parent's handlers unless setUseParentHandlers(false) is called. Forgetting that step is the usual cause of duplicate log lines.

Configuring Logging Without Code

The default settings come from the JDK's logging.properties file. You can point the JVM at your own file with a system property: java -Djava.util.logging.config.file=logging.properties -cp app.jar com.shop.Main handlers=java.util.logging.ConsoleHandler, java.util.logging.FileHandler

  • .level=INFO
  • com.shop.level=FINE
  • java.util.logging.ConsoleHandler.level=FINE
  • java.util.logging.FileHandler.pattern=%h/shop%u.log

.level sets the root logger level; com.shop.level sets the level for the com.shop logger and its children.

Each handler has its own level property, which is the second filter described above.

FileHandler writes to files (its pattern can use %h for the user's home directory and %u for a unique number), and ConsoleHandler writes to System.err .

System.Logger : The Platform Logging Facade

Java 9 added System.getLogger(name) , which returns a System.Logger with its own levels ( ALL , TRACE , DEBUG , INFO , WARNING , ERROR , OFF ). By default it is backed by java.util.logging , so System.getLogger("sys").log(System.Logger.Level.INFO, "started") prints through the same console handler. Libraries use it to log without choosing a framework for the application.

How a Log Record Flows

  • Step Component What can stop the record
  • 1 Logger The record's level is below the logger's effective level
  • 2 Logger Filter (optional) setFilter(...) rejects the record

3 Each Handler on this logger, then on each parent (unless setUseParentHandlers(false) ) The record's level is below that handler's level, or the handler's own filter rejects it

4 The handler's Formatter Nothing; it only turns the record into text ( SimpleFormatter by default, XMLFormatter for FileHandler )

The default SimpleFormatter prints two lines per record: a timestamp with the source class and method, then LEVEL: message . Its layout comes from the java.util.logging.SimpleFormatter.format property; for example, the pattern %4$s: %5$s%n prints only the level and the message, such as INFO: formatted .

Logging Best Practices the Exam Rewards

Avoid building text that is never logged. LOG.fine("Order " + id) builds the string even when FINE is disabled; prefer LOG.fine(() -> "Order " + id) , a {0} parameter, or an if (LOG.isLoggable(Level.FINE)) guard.

Log the exception object, not just its message. LOG.log(Level.SEVERE, "Order failed", e) keeps the stack trace; logging e.getMessage() loses it.

Do not log and rethrow at every layer. Logging the same exception in each method as it propagates produces duplicate noise; log it once where it is handled.

Never log secrets. Passwords read with Console.readPassword() (see 14.1) or tokens must not reach log files.

Use named loggers. Logger.getLogger(MyClass.class.getName()) lets configuration target a package. Logger.getGlobal() returns the logger named global , and Logger.getAnonymousLogger() returns an unregistered logger whose name is null .