Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to log the active configuration in a Spring Boot application?

I would really like to use YAML config for Spring Boot, as I find it quite readable and useful to have a single file showing what properties are active in my different profiles. Unfortunately, I'm finding that setting properties in application.yml can be rather fragile.

Things like using a tab instead of spaces will cause properties to not exist (without warnings as far as I can see), and all too often I find that my active profiles are not being set, due to some unknown issue with my YAML.

So I was wondering whether there are any hooks that would enable me to get hold of the currently active profiles and properties, so that I could log them.

Similarly, is there a way to cause start-up to fail if the application.yml contains errors? Either that or a means for me to validate the YAML myself, so that I could kill the start-up process.

like image 723
Steve Avatar asked Jun 27 '14 09:06

Steve


People also ask

How do I write logs in spring boot?

To make Spring Boot write its log to disk, set the path and filename. With this configuration, Spring Boot will write to the console and also to a log file called spring. log , at the path you specify.

Where can I find logs in spring boot application?

By default Spring Boot does not output logs to any file. If you want to have logs written in a file (in addition to the console output) then you should use either of logging. file or logging. path properties (not both).

How do I get a list of spring boot application properties?

To see all properties in your Spring Boot application, enable the Actuator endpoint called env . This enables an HTTP endpoint which shows all the properties of your application's environment. You can do this by setting the property management.

What are the ways in which spring boot can read configuration?

Spring Boot lets you externalize your configuration so that you can work with the same application code in different environments. You can use properties files, YAML files, environment variables, and command-line arguments to externalize configuration.


2 Answers

In addition to other answers: logging active properties on context refreshed event.

Java 8

package mypackage;  import lombok.extern.slf4j.Slf4j; import org.springframework.context.event.ContextRefreshedEvent; import org.springframework.context.event.EventListener; import org.springframework.core.env.ConfigurableEnvironment; import org.springframework.core.env.MapPropertySource; import org.springframework.stereotype.Component;  import java.util.ArrayList; import java.util.Collection; import java.util.List;  @Slf4j @Component public class AppContextEventListener {      @EventListener     public void handleContextRefreshed(ContextRefreshedEvent event) {         printActiveProperties((ConfigurableEnvironment) event.getApplicationContext().getEnvironment());     }      private void printActiveProperties(ConfigurableEnvironment env) {          System.out.println("************************* ACTIVE APP PROPERTIES ******************************");          List<MapPropertySource> propertySources = new ArrayList<>();          env.getPropertySources().forEach(it -> {             if (it instanceof MapPropertySource && it.getName().contains("applicationConfig")) {                 propertySources.add((MapPropertySource) it);             }         });          propertySources.stream()                 .map(propertySource -> propertySource.getSource().keySet())                 .flatMap(Collection::stream)                 .distinct()                 .sorted()                 .forEach(key -> {                     try {                         System.out.println(key + "=" + env.getProperty(key));                     } catch (Exception e) {                         log.warn("{} -> {}", key, e.getMessage());                     }                 });         System.out.println("******************************************************************************");     } } 

Kotlin

package mypackage  import mu.KLogging import org.springframework.context.event.ContextRefreshedEvent import org.springframework.context.event.EventListener import org.springframework.core.env.ConfigurableEnvironment import org.springframework.core.env.MapPropertySource import org.springframework.stereotype.Component  @Component class AppContextEventListener {      companion object : KLogging()      @EventListener     fun handleContextRefreshed(event: ContextRefreshedEvent) {         printActiveProperties(event.applicationContext.environment as ConfigurableEnvironment)     }      fun printActiveProperties(env: ConfigurableEnvironment) {         println("************************* ACTIVE APP PROPERTIES ******************************")         env.propertySources                 .filter { it.name.contains("applicationConfig") }                 .map { it as EnumerablePropertySource<*> }                 .map { it -> it.propertyNames.toList() }                 .flatMap { it }                 .distinctBy { it }                 .sortedBy { it }                 .forEach { it ->                     try {                         println("$it=${env.getProperty(it)}")                     } catch (e: Exception) {                         logger.warn("$it -> ${e.message}")                     }                 }         println("******************************************************************************")     } } 

Output like:

************************* ACTIVE APP PROPERTIES ****************************** server.port=3000 spring.application.name=my-app ... 2017-12-29 13:13:32.843  WARN 36252 --- [           main] m.AppContextEventListener        : spring.boot.admin.client.service-url -> Could not resolve placeholder 'management.address' in value "http://${management.address}:${server.port}" ... spring.datasource.password= spring.datasource.url=jdbc:postgresql://localhost/my_db?currentSchema=public spring.datasource.username=db_user ... ****************************************************************************** 
like image 174
fightlight Avatar answered Sep 27 '22 22:09

fightlight


I had the same problem, and wish there was a debug flag that would tell the profile processing system to spit out some useful logging. One possible way of doing it would be to register an event listener for your application context, and print out the profiles from the environment. I haven't tried doing it this way myself, so your mileage may vary. I think maybe something like what's outlined here:

How to add a hook to the application context initialization event?

Then you'd do something like this in your listener:

System.out.println("Active profiles: " + Arrays.toString(ctxt.getEnvironment().getActiveProfiles())); 

Might be worth a try. Another way you could probably do it would be to declare the Environment to be injected in the code where you need to print the profiles. I.e.:

@Component public class SomeClass {   @Autowired   private Environment env;   ...   private void dumpProfiles() {     // Print whatever needed from env here   } } 
like image 25
user2337270 Avatar answered Sep 27 '22 21:09

user2337270