Welcome to ShenZhenJia Knowledge Sharing Community for programmer and developer-Open, Learning and Share
menu search
person
Welcome To Ask or Share your Answers For Others

Categories

How can I configure logging programmatically in a spring boot application?

Using an xml or properties file is not flexible enough for my needs.

Update: I want to achieve something like this:

@Value("${logging.level.root}")
private String loggingLevelRoot;

@Value("${logging.level.myApp}")
private String loggingLevelMyApp;

@Value("${logging.file}")
private boolean fileAppenderEnabled;

....

setLevel(Logger.ROOT_LOGGER_NAME, Level.toLevel(loggingLevelRoot)));
setLevel("com.myapp", Level.toLevel(loggingLevelMyApp)));
setLevel("org.springframework", Level.WARN);
setLevel("org.apache.coyote", Level.INFO);
setLevel("org.apache.catalina", Level.INFO);
setLevel("org.apache.catalina.startup.DigesterFactory", Level.ERROR);
setLevel("org.apache.catalina.util.LifecycleMBeanBase", Level.ERROR);

Logger logger = (Logger) LoggerFactory.getLogger(Logger.ROOT_LOGGER_NAME);
logger.addAppender(createConsoleAppender());
if (fileAppenderEnabled) {
    logger.addAppender(createFileAppender());
}

All I have per environment is:

  • logging.level.root=[INFO, DEBUG, ..]
  • logging.level.myApp=[INFO, DEBUG, ..]
  • logging.file=[true | false]

No duplication of XML, Groovy and other formats I really don't want to deal with.

At the end of the day, this is really about achieving the same flexibility for logging as Spring JavaConfig did for beans. XML or other file formats are simply too static, require too much duplication and not integrated well enough with the rest of the configuration of the application.

Why should logging be configured differently than any other bean or service? It makes no sense.

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
thumb_up_alt 0 like thumb_down_alt 0 dislike
298 views
Welcome To Ask or Share your Answers For Others

1 Answer

I'm not sure you want or need to disable the default XML configuration of the logging system, but you do want to execute your customization calls after that was done. Fortunately that's pretty easy as it's done as early as possible in the initializer chain for a SpringApplication. The easiest place to put your code is probably a SpringApplicationInitializer (it has to implement ApplicationContextInitializer as well so it can be added to the SpringApplication). E.g.

SpringApplication application = new SpringApplication(MySources.class);
application.addInitializers(new LoggingInitializer());
application.run(args);

You won't be able to do dependency injection into the initializer if you do it that way, but it will ensure that it gets called as early as possible in the lifecycle. If your initializer implements EnvironmentAware then you will also be passed an instance of Environment before the call to SpringApplicationInitializer.initialize() - using that you can resolve the environment dependent pieces in your sample, e.g.

String loggingLevelRoot = environment.getProperty("logging.level.root");

Once you have it working, to avoid having to do the same thing for all apps you can make it declarative by adding a META-INF/spring.factories containing your initializer class:

org.springframework.context.ApplicationContextInitializer=
my.pkg.for.LoggingInitializer

If you really need dependency injection and @Value resolution I think you are going to have to accept that the ApplicationContext will have fully refreshed before you get a chance to configure anything. If that's an acceptable compromise I recommend just adding a LoggingInitializer to your context and have it implement CommandLineRunner.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
thumb_up_alt 0 like thumb_down_alt 0 dislike
Welcome to ShenZhenJia Knowledge Sharing Community for programmer and developer-Open, Learning and Share
...