Spring Boot编程日志配置

14

如何在Spring Boot应用程序中以编程方式配置日志记录?

使用XML或属性文件对我的需求不够灵活。

更新:我想实现这样的效果:

@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());
}

我在每个环境中拥有的仅是:

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

不会出现XML、Groovy或其他格式的重复,我真的不想处理这些。

到最后,这实际上就跟Spring JavaConfig为bean所做的事情一样,只不过是为了日志记录。 XML或其他文件格式太过静态,需要进行太多的重复操作,并且与应用程序的其余配置集成得不够好。

为什么日志记录的配置应该与任何其他bean或服务不同呢?这毫无意义。


1
@M.Deinum 不行,你不能这么做;Spring Boot(实际上,我认为是Spring自动配置)会覆盖Groovy配置的。 - chrylis -cautiouslyoptimistic-
我还需要针对每个环境不同的配置,具有不同的appender类型,...因此,XML并不能满足我的需求。 - Axel Fontaine
1
@chrylis,logback.groovy应该在Spring Boot中得到明确支持(至少从M6开始,也许更早我忘了)。如果它不能正常工作,我建议您在GitHub上提出问题并进行解释。 - Dave Syer
1
@AxelFontaine,您可以通过更改每个Spring配置文件的logging.config(或仅在启动时作为系统属性)来为每个环境提供不同的XML(或Groovy或其他)配置。这样不够灵活吗? - Dave Syer
@DaveSyer 作为一条注释,对于logback.groovy的支持以及测试配置的添加是在修订版本9db55a3b7166b4794fde3beb44d9f30c4eb52348之后才加入的,该修订版本是在M6之后但包含在M7中。 - chrylis -cautiouslyoptimistic-
显示剩余6条评论
1个回答

19

我不确定您是否需要禁用日志系统的默认XML配置,但您确实希望在进行该操作之后执行自定义调用。幸运的是,这很容易,因为它是在SpringApplication的初始化程序链中尽可能早地完成的。最简单的放置代码的位置可能是SpringApplicationInitializer(它还必须实现ApplicationContextInitializer,以便可以将其添加到SpringApplication)。例如:

SpringApplication application = new SpringApplication(MySources.class);
application.addInitializers(new LoggingInitializer());
application.run(args);
你无法在初始化器中进行依赖注入,但这样可以确保在生命周期的尽可能早的阶段调用它。如果你的初始化器实现了 EnvironmentAware 接口,那么在调用 SpringApplicationInitializer.initialize() 之前,你将被传递一个 Environment 实例 - 使用它你可以解析你的示例中与环境相关的部分。
String loggingLevelRoot = environment.getProperty("logging.level.root");

一旦您使其正常工作后,为避免在所有应用程序上执行相同的操作,您可以通过添加一个包含您的初始化器类的META-INF/spring.factories来将其声明式化:

org.springframework.context.ApplicationContextInitializer=\
my.pkg.for.LoggingInitializer
如果你真的需要依赖注入和@Value解析,我认为你必须接受在你有机会配置任何东西之前ApplicationContext已经完全刷新的事实。如果这是可以接受的妥协,我建议只需向上下文添加一个LoggingInitializer并使其实现CommandLineRunner

一个自定义的 LoggingSystem 实现同样可以完成这个工作,不是吗?但是它不会被自动检测到,所以你应该添加 -Dorg.springframework.boot.logging.LoggingSystem=<class name>(或设置系统属性)。 - Bertrand Renuart
@DaveSyer 在这种情况下 EnvironmentAware 是不起作用的。如果你需要 Environment 实例,那么最好在 initialize() 方法内从应用程序上下文实例中获取它。 - ydrozhdzhal
我发现这篇关于替代策略的解释非常有帮助。我确实需要参考这个问题,以了解如何执行一些建议中推荐的操作示例:https://stackoverflow.com/questions/46636599/how-do-i-set-the-logging-properties-in-a-spring-java-configuration?noredirect=1&lq=1 - user1445967

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接