logging.level

Sets log levels per logger or package (logging.level.<name>=DEBUG), with groups such as web and sql to switch related loggers together.

Signature
logging.level.com.example.orders=DEBUG
  • Added in Spring Boot Spring Boot 4.1 (verified present)

Parameters

ParameterTypeDescription
$<logger-name>String keyA package or class name such as com.example.orders or org.hibernate.SQL, or root for the root logger.
$valueLogLevelTRACE, DEBUG, INFO, WARN, ERROR, FATAL or OFF.
$logging.group.<name>optionalList<String>Defines a group of loggers that can be set with one logging.level.<name> entry. Boot predefines web and sql.

Return value

n/aA map from logger name (or log group name) to level. Each entry sets the threshold for that logger and everything under it in the name hierarchy.

Errors

An unknown level value fails property binding at startup.

Every logger has a name, usually the class that owns it, and names form a hierarchy by package. logging.level.<name> sets the threshold for a logger and everything below it. root covers the lot.

logging.level.root=INFO
logging.level.com.example.orders=DEBUG
logging.level.org.springframework.web=DEBUG

The default is INFO for everything. Raise the level for your own packages when investigating, and lower noisy libraries rather than the root.

Groups

A log group names several loggers at once. Boot defines two: web (Spring's org.springframework.web, org.springframework.http and codec packages) and sql (Spring JDBC, Hibernate's SQL output and jOOQ). logging.level.sql=DEBUG shows the SQL Hibernate sends, without hunting for the exact logger names. Add your own with logging.group.payments=com.example.payments,com.acme.gatewayclient.

The environment variable catch

Relaxed binding turns LOGGING_LEVEL_COM_EXAMPLE_ORDERS=DEBUG into logging.level.com.example.orders. Environment variables are lower-cased on the way in, so the trick works for packages but not for a class name or any logger with capitals: LOGGING_LEVEL_ORG_HIBERNATE_SQL targets org.hibernate.sql, which is not org.hibernate.SQL. Use a group (LOGGING_LEVEL_SQL=DEBUG) or a command-line argument instead.

Changing levels without a restart

With Actuator's loggers endpoint exposed, a POST to /actuator/loggers/com.example.orders changes the level of a running instance, and posting an empty level resets it. It is the fastest way to get detail during an incident, and the change is lost on restart, which is usually what you want. Protect the endpoint: it accepts writes.

Production consequences

  • DEBUG on root in production floods log storage and slows request handling, because some libraries log every byte they read.
  • TRACE on Hibernate's parameter binding (org.hibernate.orm.jdbc.bind) prints the values of every query, including personal data. Do not leave it on.
  • Use parameterised messages (log.debug("Order {} saved", id)) so disabled levels cost almost nothing.

Example

Example · properties
# Quiet by default, detailed for our own code.
logging.level.root=WARN
logging.level.com.example=INFO
logging.level.com.example.orders.pricing=DEBUG

# Hibernate SQL, Spring JDBC and jOOQ in one switch.
logging.level.sql=DEBUG

# Our own group: the payments code and the client library it uses.
logging.group.payments=com.example.payments,com.acme.gatewayclient
logging.level.payments=DEBUG

When to use it

  • Seeing the SQL Hibernate generates while tuning a slow endpoint
  • Turning on DEBUG for one package on one production instance during an incident, without a redeploy
  • Silencing a chatty third-party library while keeping the rest at INFO

Frequently asked questions

How do I log SQL statements in Spring Boot?

Set logging.level.sql=DEBUG, which covers Hibernate's org.hibernate.SQL logger and Spring JDBC. Prefer it to spring.jpa.show-sql, which writes to standard output and bypasses the logging system.

Why does LOGGING_LEVEL_ORG_HIBERNATE_SQL not work?

Environment variable names are lower-cased during binding, so the key becomes org.hibernate.sql, and logger names are case-sensitive. Use LOGGING_LEVEL_SQL or a custom group instead.

More examples

Loggers named after the class

logging.level.com.example.orders.pricing=DEBUG reaches this logger because its name sits under that package. The {} placeholders mean the message is only built when DEBUG is enabled, so the call is cheap when it is not.

Example · java
import java.math.BigDecimal;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;

@Service
public class PricingService {

    // Logger name: the fully qualified class name, so package settings apply to it.
    private static final Logger log = LoggerFactory.getLogger(PricingService.class);

    public BigDecimal priceFor(String sku, int quantity, BigDecimal unitPrice) {
        BigDecimal total = unitPrice.multiply(BigDecimal.valueOf(quantity));
        log.debug("Priced {} x {} at {}", quantity, sku, total);
        if (quantity > 1_000) {
            log.warn("Unusually large order line: {} x {}", quantity, sku);
        }
        return total;
    }
}

Raising a level on a running instance

This needs the loggers endpoint in management.endpoints.web.exposure.include. Because it accepts writes, put it behind authentication or on a management port that only operators can reach.

Example · http
### Current level of one logger
GET http://localhost:9090/actuator/loggers/com.example.orders

### Turn on DEBUG until the next restart
POST http://localhost:9090/actuator/loggers/com.example.orders
Content-Type: application/json

{ "configuredLevel": "DEBUG" }

### Put it back to whatever the configuration says
POST http://localhost:9090/actuator/loggers/com.example.orders
Content-Type: application/json

{ "configuredLevel": null }

Setting levels from the environment

The second line is the mistake people make in container manifests. Groups solve it neatly, and a group of your own can wrap any class name that has capitals in it.

Example · bash
# Works: package names are already lower case
LOGGING_LEVEL_COM_EXAMPLE_ORDERS=DEBUG java -jar orders.jar

# Does not reach org.hibernate.SQL (becomes org.hibernate.sql)
LOGGING_LEVEL_ORG_HIBERNATE_SQL=DEBUG java -jar orders.jar

# Works: the built-in sql group includes org.hibernate.SQL
LOGGING_LEVEL_SQL=DEBUG java -jar orders.jar

# Works: arguments keep their case
java -jar orders.jar --logging.level.org.hibernate.SQL=DEBUG

Discussion

  • Be the first to comment on this lesson.