Spring Boot 程序化日志配置

Posted

技术标签:

【中文标题】Spring Boot 程序化日志配置【英文标题】:Spring Boot programmatic logging configuration 【发布时间】:2013-12-28 17:30:47 【问题描述】:

如何在 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=[信息,调试,..] logging.level.myApp=[INFO, DEBUG, ..] logging.file=[真 |假]

没有重复我真的不想处理的 XML、Groovy 和其他格式。

归根结底,这实际上是为了实现与 Spring JavaConfig 为 bean 所做的相同的日志记录灵活性。 XML 或其他文件格式太静态了,需要太多重复,并且与应用程序的其余配置集成得不够好。

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

【问题讨论】:

什么是使用xml不够灵活?如果你使用 Logback,你可以使用 Groovy 来配置 logback。 @M.Deinum 不,你不能; Spring Boot(实际上,我认为是 Spring Autoconfig)踩踏了 Groovy 配置。 我还需要对每个环境进行不同的配置,使用不同的 appender 类型,......所以不,XML 不会削减它。 @chrylis logback.groovy 应该在 Spring Boot 中得到明确支持(至少从 M6 开始,也许在那之前我忘记了)。如果它不起作用我建议你在 github 中提出一个问题并解释一下。 @AxelFontaine 您可以为每个环境提供不同的 XML(或 groovy 或其他)配置,只需更改每个 Spring 配置文件的 logging.config(或仅作为启动时的系统属性)。这还不够灵活吗? 【参考方案1】:

我不确定您是否想要或需要禁用日志系统的默认 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>(或设置系统属性)。 @DaveSyer EnvironmentAware 在这种情况下不起作用。如果您需要 Environment 实例,那么最好从 initialize() 方法内的应用程序上下文实例中获取它。 我发现这种对替代策略的解释非常有帮助。我确实需要参考这个问题,以获取如何执行此处推荐的一些操作的示例:***.com/questions/46636599/…

以上是关于Spring Boot 程序化日志配置的主要内容,如果未能解决你的问题,请参考以下文章

Spring Boot配置保存日志文件

Spring Boot 日志配置

spring-boot中如何配置tomcat访问日志的位置和名称?

Spring Boot 日志配置方法(超详细)

Spring Boot 日志记录模式

Spring Boot 日志详解