spring boot
application properties
bean instantiation
logging
java development

How to log all active properties of a spring boot application before the beans instantiation?

Master System Design with Codemia

Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.

Introduction

If you need to inspect configuration before any Spring beans are created, logging from a CommandLineRunner or ApplicationRunner is too late. The right place is earlier in startup, after the environment has been prepared but before the application context begins instantiating beans.

Use an EnvironmentPostProcessor

EnvironmentPostProcessor runs early enough to inspect property sources before bean creation. It receives the ConfigurableEnvironment, so you can enumerate sources, read active profiles, and log resolved properties while the application is still bootstrapping.

java
1package com.example.demo;
2
3import org.slf4j.Logger;
4import org.slf4j.LoggerFactory;
5import org.springframework.boot.SpringApplication;
6import org.springframework.boot.env.EnvironmentPostProcessor;
7import org.springframework.core.Ordered;
8import org.springframework.core.env.ConfigurableEnvironment;
9import org.springframework.core.env.EnumerablePropertySource;
10import org.springframework.core.env.PropertySource;
11
12import java.util.Arrays;
13import java.util.Set;
14import java.util.TreeSet;
15
16public class PropertyLoggingPostProcessor implements EnvironmentPostProcessor, Ordered {
17    private static final Logger log = LoggerFactory.getLogger(PropertyLoggingPostProcessor.class);
18
19    @Override
20    public void postProcessEnvironment(ConfigurableEnvironment environment, SpringApplication application) {
21        Set<String> propertyNames = new TreeSet<>();
22
23        for (PropertySource<?> source : environment.getPropertySources()) {
24            if (source instanceof EnumerablePropertySource<?> enumerable) {
25                propertyNames.addAll(Arrays.asList(enumerable.getPropertyNames()));
26            }
27        }
28
29        log.info("Active profiles: {}", Arrays.toString(environment.getActiveProfiles()));
30
31        for (String name : propertyNames) {
32            if (isSensitive(name)) {
33                continue;
34            }
35            log.info("{}={}", name, environment.getProperty(name));
36        }
37    }
38
39    private boolean isSensitive(String name) {
40        String lower = name.toLowerCase();
41        return lower.contains("password") || lower.contains("secret") || lower.contains("token") || lower.contains("key");
42    }
43
44    @Override
45    public int getOrder() {
46        return Ordered.LOWEST_PRECEDENCE;
47    }
48}

Register it in META-INF/spring.factories:

properties
org.springframework.boot.env.EnvironmentPostProcessor=\
com.example.demo.PropertyLoggingPostProcessor

That registration causes Spring Boot to load the post-processor during environment preparation.

Why This Runs Before Beans

Spring Boot starts by building the environment, loading property sources, and resolving profiles. Only after that does it move on to creating the application context and instantiating beans. Because EnvironmentPostProcessor hooks into the environment phase, it sees the effective configuration early enough for diagnostics.

That makes it useful for debugging profile activation, missing environment variables, externalized configuration, and property precedence issues.

Logging Only What Matters

Dumping every property can create noisy logs and accidental credential exposure. In practice, it is better to filter aggressively.

You can restrict logging to your own prefixes:

java
if (name.startsWith("app.") || name.startsWith("spring.datasource.")) {
    log.info("{}={}", name, environment.getProperty(name));
}

You should also mask sensitive values instead of only skipping them when those keys are important for troubleshooting.

java
private String safeValue(String name, String value) {
    return isSensitive(name) ? "******" : value;
}

Alternative Hook: ApplicationEnvironmentPreparedEvent

Another early hook is an ApplicationListener<ApplicationEnvironmentPreparedEvent>. It fires at a similar stage and is a good fit when you want event-driven startup logic rather than a dedicated environment post-processor class.

For most property inspection tasks, EnvironmentPostProcessor is the cleaner choice because the intent is explicit and the API is focused on environment mutation and inspection.

Property Source Order Matters

Spring may load the same key from several places, including default properties, application.yml, environment variables, command line arguments, and container-level configuration. Calling environment.getProperty(name) returns the winning value after precedence rules are applied.

That is usually what you want in logs. If you also need to know where a value came from, inspect property sources individually instead of only the resolved environment.

Common Pitfalls

A common mistake is trying to log properties from a bean constructor or @PostConstruct. By that point, bean creation is already underway, so you have missed the requested lifecycle stage.

Another issue is logging secrets. Database passwords, API tokens, and signing keys should never be emitted in plaintext startup logs.

Developers also sometimes assume every property source is enumerable. That is not true, which is why the code checks for EnumerablePropertySource before calling getPropertyNames().

Summary

  • Use EnvironmentPostProcessor to inspect active properties before bean instantiation.
  • Register the post-processor through META-INF/spring.factories.
  • Filter or mask sensitive values before logging.
  • 'environment.getProperty(name) gives the effective resolved value after precedence rules.'
  • Avoid later hooks like runners or bean lifecycle callbacks when you need pre-instantiation visibility.

Course illustration
Course illustration