当您使用 Spring Boot 启动器依赖项之一时,Logback 是开箱即用的,因为它们包括 — 提供日志记录,而无需任何配置,如果需要,可以更改这些配置以区别工作。有两种方法可以提供您自己的配置。如果只需要更简单的更改,则可以将它们添加到属性文件中,例如,对于更复杂的需求,可以使用 XML 或 Groovy 来指定设置。在本教程中,我们将重点介绍如何使用 XML 来定义自定义日志记录配置,并了解执行此操作的一些基础知识,并简要介绍如何使用属性文件来指定对 Spring Boot 提供的标准设置的简单更改。 spring-boot-starter-loggingapplication.properties
在这篇文章中,我使用依赖关系来拉入,这可以在下面找到。 spring-boot-starterspring-boot-starter-logging
<dependency>br <groupId>org.springframework.boot</groupId>br <artifactId>spring-boot-starter</artifactId>br</dependency>
这将利用 ,而 后者又具有依赖关系。 spring-boot-starter-logging
<dependencies>br <dependency>br <groupId>ch.qos.logback</groupId>br <artifactId>logback-classic</artifactId>br </dependency>br <dependency>br <groupId>org.slf4j</groupId>br <artifactId>jul-to-slf4j</artifactId>br </dependency>br <dependency>br <groupId>org.slf4j</groupId>br <artifactId>log4j-over-slf4j</artifactId>br </dependency>br</dependencies>
logback-classic包含依赖关系,它们之间包含我们入门所需的一切。上面显示的库的版本适用于Spring Boot的版本。这些依赖项在Spring Boot版本之间保持不变,但它们自己的版本可能略有不同。自从最初针对版本编写本文以来,不需要对任何示例进行任何更改(针对 和 进行测试)。 logback-core2.7.12.0.0.RELEASE2.0.0.RELEASE2.3.1.RELEASE2.7.1
在我们开始配置 Logback 之前,值得快速浏览一下如何从类中向日志发送消息。
@Service public class MyServiceImpl implements MyService {br private static final Logger LOGGER = LoggerFactory.getLogger(MyServiceImpl.class);br @Override public void doStuff(final String value) {br LOGGER.trace("doStuff needed more information - {}", value);br LOGGER.debug("doStuff needed to debug - {}", value);br LOGGER.info("doStuff took input - {}", value);br LOGGER.warn("doStuff needed to warn - {}", value);br LOGGER.error("doStuff encountered an error with value - {}", value);br }br}
允许使用表示每个日志记录级别、、、后跟消息的方法将消息写入日志。大括号/大括号将替换为作为方法参数传入的值。 LOGGERtracedebuginfowarnerror
现在,我们可以从一个相对简单的示例开始查看配置 Logback 本身。下面是 logback.xml 文件,它是 Logback 将搜索以配置其设置的文件之一。
<?xml version="1.0" encoding="UTF-8"?>br<configuration>br <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">br <encoder>br <pattern>%d{dd-MM-yyyy HH:mm:ss.SSS} %magenta([%thread]) %highlight(%-5level) %logger{36}.%M - %msg%n</pattern>br </encoder>br </appender>br <root level="info">br <appender-ref ref="STDOUT" />br </root>br</configuration>
它创建了一个类的追加器,它将像往常一样将日志消息输出到控制台。设置了日志消息将遵循的模式,这些模式附带了一些表示法,这些表示法将根据已发送到记录器的消息替换为生成的值。示例中包含了一些表示法。以下是对每个功能的解释: ConsoleAppenderSystem.out.print
- %d– 以允许的格式输出日志消息发生的时间。SimpleDateFormat
- %thread– 输出发生日志消息的线程的名称。
- $-5level– 输出日志消息的日志记录级别。
- %logger{36}– 输出日志消息所在的包 + 类名。括号内的数字表示包 + 类名的最大长度。如果输出长于指定的长度,则从根包开始,到输出低于最大长度之前,它将采用每个单独包的第一个字符的子字符串。类名永远不会减少。可以在转换Word文档中找到一个很好的图表。
- %M– 输出发生日志消息的方法的名称(显然,这使用起来很慢,除非您不担心性能,或者方法名称对您特别重要,否则不建议这样做)。
- %msg– 输出实际的日志消息。
- %n– 换行符。
- %magenta()– 将括号中包含的输出的颜色设置为洋红色(其他颜色可用)。
- highlight()– 根据日志记录级别设置括号中包含的输出的颜色(例如 ERROR = red)。
然后,在根记录器中引用创建的追加器。在上面的示例中,日志记录级别已设置为 INFO(可以使用小写或大写)。使其仅输出在日志级别 INFO 或更高级别(INFO、警告、错误)定义的消息。
Logback 中可用的日志记录级别包括:
返回到上面显示的具有 INFO 日志记录级别的代码段,只有级别 INFO 或更高级别的消息(WARN 和 ERROR)才会输出到日志中。因此,如果我们调用它将生成以下内容(与Spring相关的日志已从此和所有以下输出示例中删除)。MyService.doStuff("value")
8-08-2017 13:32:18.549 [main] INFO com.lankydan.service.MyServiceImpl.doStuff - doStuff took input - valuebr28-08-2017 13:32:18.549 [main] WARN com.lankydan.service.MyServiceImpl.doStuff - doStuff needed to warn - valuebr28-08-2017 13:32:18.549 [main] ERROR com.lankydan.service.MyServiceImpl.doStuff - doStuff encountered an error with value - value
请注意,即使将 TRACE 和 DEBUG 级别消息发送到记录器,它们也不会显示,因为它们低于 INFO 的级别。
如果要从 内部编写与前面的代码示例等效的代码示例,可以按如下方式进行操作。application.properties
logging.level.root=infobrlogging.pattern.console=%d{dd-MM-yyyy HH:mm:ss.SSS} %magenta([%thread]) %highlight(%-5level) %logger.%M - %msg%n
以这种形式完成时,不需要 logback.xml 文件,并且如您所见,配置相当短,对于更简单的设置很有用。
使用 Spring Boot 时,会提供 Logback 的默认配置,当您添加自己的 logback.xml时,该配置将被覆盖。如果您希望包含Spring Boot的配置,可以在标签中添加以下内容。
<include resource="org/springframework/boot/logging/logback/base.xml"/>
有关此内容的详细信息,请参阅 Spring Boot 文档 – 配置 Logback 以进行日志记录。
如果要记录与根级别不同的类的消息,则可以为该类定义自己的记录器。这将允许您设置该特定类的日志记录级别,以及指定该类独有的其他属性。下面介绍如何为单个类定义记录器。
<logger name="com.lankydan.service.MyServiceImpl" level="debug">br <appender-ref ref="STDOUT" />br</logger>
如果您继续运行这段代码,并且仍然定义了根记录器,它将生成以下输出:
27-08-2017 17:02:10.248 [main] DEBUG com.lankydan.service.MyServiceImpl.doStuff - doStuff needed to debug - valuebr27-08-2017 17:02:10.248 [main] DEBUG com.lankydan.service.MyServiceImpl.doStuff - doStuff needed to debug - valuebr27-08-2017 17:02:10.248 [main] INFO com.lankydan.service.MyServiceImpl.doStuff - doStuff took input - valuebr27-08-2017 17:02:10.248 [main] INFO com.lankydan.service.MyServiceImpl.doStuff - doStuff took input - valuebr27-08-2017 17:02:10.248 [main] WARN com.lankydan.service.MyServiceImpl.doStuff - doStuff needed to warn - valuebr27-08-2017 17:02:10.248 [main] WARN com.lankydan.service.MyServiceImpl.doStuff - doStuff needed to warn - valuebr27-08-2017 17:02:10.248 [main] ERROR com.lankydan.service.MyServiceImpl.doStuff - doStuff encountered an error with value - valuebr27-08-2017 17:02:10.248 [main] ERROR com.lankydan.service.MyServiceImpl.doStuff - doStuff encountered an error with value - value
如您所见,每条日志消息都生成了两次,这可能不是您想要的。要解决此问题,需要使用。如果不使用将导致消息被打印出来两次,因为根日志追加器和类级追加器都写入日志。即使根级别是 ,通过将类级别设置为 ,它也会在全局覆盖它,并将导致根追加器也写入类的级别。下面是包含此属性的代码应如下所示。additivity="false"additivity="false" ERRORDEBUGDEBUGMyServiceImpl
<logger name="com.lankydan.service.MyServiceImpl" additivity="false" level="debug">br <appender-ref ref="STDOUT" />br</logger>
另一种可能的解决方案是仅设置类的日志级别而不写入日志(由于未定义追加器)。这等效于上面的版本,但假设另一个日志追加器(在本例中为根追加器)正在写入日志以使其工作:
<logger name="com.lankydan.service.MyServiceImpl" level="debug"/>
如果使用这些解决方案中的任何一个,则输出将返回到预期值。
27-08-2017 16:30:47.818 [main] DEBUG com.lankydan.service.MyServiceImpl.doStuff - doStuff needed to debug - valuebr27-08-2017 16:30:47.834 [main] INFO com.lankydan.service.MyServiceImpl.doStuff - doStuff took input - valuebr27-08-2017 16:30:47.834 [main] WARN com.lankydan.service.MyServiceImpl.doStuff - doStuff needed to warn - valuebr27-08-2017 16:30:47.834 [main] ERROR com.lankydan.service.MyServiceImpl.doStuff - doStuff encountered an error with value - value
可以通过添加以下内容来编写类级日志记录。application.properties
logging.level.com.lankydan.service.MyServiceImpl=debug
还可以通过使用包名称而不是记录器标记中的类名来定义包级别日志记录。
<logger name="com.lankydan.service" additivity="false" level="debug">br <appender-ref ref="STDOUT" />br</logger>
通过将日志记录添加到其中一个弹簧框架包中,然后移动到其中一个类上,可以找到更多证据。例如:
<logger name="org.springframework.boot" level="debug">br <appender-ref ref="STDOUT" />br</logger>
与:
<logger name="org.springframework.boot.SpringApplication" level="debug">br <appender-ref ref="STDOUT" />br</logger>
它打印出完全不同数量的日志行。也许是数百行,而不是一两行,日志包含在日志中。 SpringApplicationorg.springframework.boot
包级别日志记录遵循与使用包而不是类名相同的格式。application.properties
logging.level.com.lankydan.service=debug
可以定义属性,允许通过配置文件重用它们,这在需要标记输出文件夹以供日志转到时非常方便。
<property name="LOG_PATH" value="logs"/>
此 named 属性将在其他示例中使用,并将使用项目根目录所在的目录(至少我的情况是这样)。这可能不是将日志保存到现实中的最佳位置,但对于本教程的需求,它是合适的。 是一个对默认 Spring Boot 日志记录设置很重要的属性,但可以创建任何名称的属性。然后,可以通过添加 在整个配置的其余部分访问 的值。 LOG_PATHDEV_HOME/logsDEV_HOMELOG_PATHLOG_PATH${LOG_PATH}
这种配置可以通过在Spring Boot中的重要性来实现。 application.propertiesLOG_PATH
logging.path=logs
当您定义自己的属性/变量时,这也有效,允许您从代码的其余部分引用它。例如:
propertyA=valuebrpropertyB=${propertyA} # extra configuration if required
${propertyA}将被 替换为 的值,允许使用它。propertyApropertyB
要将日志保存到文件中,可以使用。这是一个简单的文件追加器,会将所有日志保存到一个单一的文件,该文件可能会变得非常大,因此您更有可能使用我们稍后将介绍的。 FileAppenderRollingFileAppender
<appender name="SAVE-TO-FILE" class="ch.qos.logback.core.FileAppender">br <file>${LOG_PATH}/log.log</file>br <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">br <Pattern>br %d{dd-MM-yyyy HH:mm:ss.SSS} [%thread] %-5level %logger{36}.%M - %msg%nbr </Pattern>br </encoder>br</appender>
没有太多的东西。它遵循与 相同的结构类型,并添加了命名日志消息保存到的文件。值得注意的是,我已经删除了保存到文件时添加到编码器模式的颜色,因为它将包含不打算显示的字符,并且会使日志文件混乱。然后,可以像前面显示的附加器一样引用此追加器,从而可以实际使用它。这将如下所示,下面的代码片段将使用相同的代码。ConsoleAppenderSTDOUT
<logger name="com.lankydan.service.MyServiceImpl" additivity="false" level="debug">br <appender-ref ref="SAVE-TO-FILE" />br</logger>
从前面的代码段(设置的位置)继续,如果其他设置没有被玩太多,这实际上会导致日志输出到文件(以及控制台)。因此,您可以就此打住,但是如果以这种方式完成,则写入文件的模式和文件名不受您的控制。下面的示例将演示与上面显示的追加器类似的配置。 application.propertieslogging.pathSAVE-TO-FILE
logging.pattern.console=brlogging.path=logsbrlogging.file=${logging.path}/log.logbrlogging.pattern.file=%d{dd-MM-yyyy HH:mm:ss.SSS} [%thread] %-5level %logger{36}.%M - %msg%n
这与 XML 配置的不同之处在于,该示例显示了在记录器中引用的追加器,但上面的代码段还将包括根记录器,因此将所有日志消息输出到文件。添加了 以阻止它输出到控制台,以使其与上面的 XML 代码保持一致(这似乎不是执行此操作的好方法,但我还没有看到其他解决方案)。 MyServiceImplapplication.propertieslogging.pattern.console
RollingFileAppender会将日志保存到不同的文件,具体取决于其滚动策略。这很方便,因为它允许将日志输出拆分为您可以控制的各种形式。例如,您可以根据日期分隔日志文件,以便查看过去在特定日期发生的错误。您可以根据文件大小进行分离,这样您就不需要搜索一个无休止的大量文件, 或者同时执行这两项操作并按日期和大小进行分离。
TimeBasedRollingPolicy将根据日期创建一个新文件。下面的代码将每天创建一个新文件,并使用表示法将日期追加到日志文件的名称。符号的格式很重要,因为从中推断出翻转时间段。下面的示例将每天翻转,但要每月滚动,可以使用不同的模式,其中不包括日期的日部分。可以使用不同的展期周期 - 而不仅仅是每天或每月 - 因为周期是推断的,只要符号内的格式符合允许的格式。%d%d%d{MM-yyyy}%dSimpleDateFormat
<appender name="SAVE-TO-FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">br <file>${LOG_PATH}/log.log</file>br <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">br <Pattern>%d{dd-MM-yyyy HH:mm:ss.SSS} [%thread] %-5level %logger{36}.%M - %msg%n</Pattern>br </encoder>br <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">br <fileNamePattern>${LOG_PATH}/archived/log_%d{dd-MM-yyyy}.log</fileNamePattern>br <maxHistory>10</maxHistory>br <totalSizeCap>100MB</totalSizeCap>br </rollingPolicy>br</appender>
我已经包含了在上面的示例中可用的一些属性。 指定在自动删除存档的日志文件之前将保留多长时间。它们的保留时间取决于文件名中指定的滚动更新时间段,因此在上面的示例中,滚动更新周期是每天,允许在删除日志之前最多存储 10 天的存档日志。 限制所有已归档日志文件的最大大小。它要求将属性设置为 ,优先于删除存档文件时的属性。 TimeBasedRollingPolicymaxHistorytotalSizeCapmaxHistorymaxHistorytotalSizeCap
此配置超出了在文件内可以执行的操作范围。对于以下示例也可以这样说,尽管默认配置将允许日志文件在达到 10MB 时滚动更新,并允许最多 7 个存档的日志文件。application.properties
若要仅对文件大小进行滚动更新,需要使用 滚动策略 和 触发策略 。在前面的示例中,日志在滚动更新时被保存到存档文件夹中,但对于此策略,我没有保存它们,因为由于文件大小较小,日志的分离主要是为了帮助使它们更容易遍历。 FixedWindowRollingPolicySizeBasedTriggeringPolicy
<appender name="SAVE-TO-FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">br <file>${LOG_PATH}/log.log</file>br <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">br <Pattern>%d{dd-MM-yyyy HH:mm:ss.SSS} [%thread] %-5level %logger{36}.%M - %msg%n</Pattern>br </encoder>br <rollingPolicy class="ch.qos.logback.core.rolling.FixedWindowRollingPolicy">br <fileNamePattern>${LOG_PATH}/log_%i.log</fileNamePattern>br <minIndex>2</minIndex>br <maxIndex>3</maxIndex>br </rollingPolicy>br <triggeringPolicy class="ch.qos.logback.core.rolling.SizeBasedTriggeringPolicy">br <maxFileSize>1KB</maxFileSize>br </triggeringPolicy>br</appender>
的可选属性和 在 中找到的指定日志文件名中可以采用的最小值和最大值。因此,在上面的示例中,当日志滚动更新时,它们可以采用名称和(尽管从2开始很奇怪,并且只是为了清楚起见而包含的。通常从1开始)。生成日志文件的过程如下(以上面的代码片段为例): minIndexmaxIndexFixedWindowRollingPolicy%ilog_2.loglog_3.log
- log.log最大文件大小已达到 ->重命名为并创建新的log.loglog_2.loglog.log
- log_2.log最大文件大小达到 -> ,命名为 和 newlog_2.log renamed to log_3.loglog.loglog_2.loglog.log
- log_3.log最大文件大小达到 ->被删除、重命名为 、重命名为并创建新的log_3.loglog_2.loglog_3.loglog.loglog_2.loglog.log
如果我仍然在向您解释此过程方面做得很糟糕,那么请查看FixedWindowRollingPolicy文档,如果我失败了,它有望让您到达那里。
SizeAndTimeBasedRollingPolicy采用上述两个示例的一部分,允许它在大小和时间上滚动。请注意,它同时使用 和 表示法分别在文件名中包含日期和日志号。%d%i
<appender name="SAVE-TO-FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">br <file>${LOG_PATH}/log.log</file>br <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">br <Pattern>%d{dd-MM-yyyy HH:mm:ss.SSS} [%thread] %-5level %logger{36}.%M - %msg%n</Pattern>br </encoder>br <rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">br <fileNamePattern>${LOG_PATH}/archived/log_%d{dd-MM-yyyy}_%i.log</fileNamePattern>br <maxFileSize>10MB</maxFileSize>br <maxHistory>10</maxHistory>br <totalSizeCap>100MB</totalSizeCap>br </rollingPolicy>br</appender>
如您所见,它包含 、 和 ,使其能够控制单个文件的大小以及文件的集合。因此,上面的示例会将10天的历史记录拆分为10MB的文件,当所有文件的总大小达到100MB时,将删除最旧的文件。 maxFileSizemaxHistorytotalSizeCap
现在我们已经了解了如何定义可以输出到控制台或文件的多个追加器,我们可以将它们组合在一起,一次输出到两种形式,只需在记录器中引用多个追加器:
<logger name="com.lankydan.service" additivity="false" level="debug">br <appender-ref ref="STDOUT" />br <appender-ref ref="SAVE-TO-FILE" />br</logger>
因此,现在此记录器将输出到控制台,这要归功于以及使用附加器的文件。STDOUTSAVE-TO-FILE
类似的配置可以通过 来实现。如果您返回页面,您可能能够弄清楚如何自己执行此操作,因为前面的示例添加了一行额外的行,以防止它打印到控制台和文件。同样,这将包含来自根记录器的日志消息,而不仅仅是上面的代码段。 application.propertiesMyServiceImpl
logging.path=logsbrlogging.file=${logging.path}/log.logbrlogging.pattern.file=%d{dd-MM-yyyy HH:mm:ss.SSS} [%thread] %-5level %logger{36}.%M - %msg%n
Spring Boot 在使用 Logback 时提供的一个有用功能是能够在环境之间分离配置。因此,如果您想在开发环境中保存到文件并打印到控制台,但在生产环境中只打印到文件,那么这可以轻松实现。
<?xml version="1.0" encoding="UTF-8"?>br<configuration>br <!-- config for STDOUT and SAVE-TO-FILE -->br <springProfile name="dev">br <root level="info">br <appender-ref ref="STDOUT" />br <appender-ref ref="SAVE-TO-FILE" />br </root>br <logger name="com.lankydan.service" additivity="false" level="debug">br <appender-ref ref="STDOUT" />br <appender-ref ref="SAVE-TO-FILE" />br </logger>br </springProfile>br <springProfile name="prod">br <root level="info">br <appender-ref ref="SAVE-TO-FILE" />br </root>br <logger name="com.lankydan.service" additivity="false" level="error">br <appender-ref ref="SAVE-TO-FILE" />br </logger>br </springProfile>br</configuration>
使其工作的第一步是将 logback.xml 文件重命名为 logback-spring.xml,从而允许使用标记。请注意,您不能同时拥有 logback.xml 和 logback-spring.xml 文件,如果您这样做,则 spring 版本将被忽略为 logback.xml将始终优先。springProfile
在 tag 中,可以提供可通过属性、环境变量或 VM 选项设置的名称。下面介绍如何将名称设置为 ,该名称已用于表示开发环境。 springProfilespringProfiledev
在 application.properties 中设置或作为环境变量进行设置:
spring.profiles.active=dev
或作为 VM 选项:
-Dspring.profiles.active=dev
现在,当应用程序运行时,将使用 for,从而导致日志输出到控制台和文件。如果然后将其推送到生产环境,则需要将属性设置为 ,这会将配置更改为认为合适的配置,例如仅将日志写入文件,并可能更改所有或某些类/包的日志记录级别。springProfiledevprod
也可以通过 提供类似的配置。好吧,实际上不是,而是来自 和 - 为每个环境单独创建属性文件。遵循将 where 替换为环境名称的命名约定。根据您的 VM 选项或环境变量,可以选择其中之一,就像在 logback-spring.xml 中完成一样。以下是上述代码片段的等效配置。 application.propertiesapplication.propertiesapplication-dev.propertiesapplication-prod.propertiesapplication-{environment}.properties{environment}springProfile
application-dev.properties:
logging.level.root=infobrlogging.level.com.lankydan.service=debugbrlogging.path=logsbrlogging.file=${logging.path}/log.logbrlogging.pattern.file=%d{dd-MM-yyyy HH:mm:ss.SSS} [%thread] %-5level %logger{36}.%M - %msg%nbrlogging.pattern.console=%d{dd-MM-yyyy HH:mm:ss.SSS} %magenta([%thread]) %highlight(%-5level) %logger.%M - %msg%n
application-prod.properties:
logging.level.root=infobrlogging.level.com.lankydan.service=errorbrlogging.path=logsbrlogging.file=${logging.path}/log.logbrlogging.pattern.file=%d{dd-MM-yyyy HH:mm:ss.SSS} [%thread] %-5level %logger{36}.%M - %msg%nbrlogging.pattern.console=
我认为我应该在这一点上结束这篇文章,因为它比我原先预期的要长得多。话虽如此,Logback和Spring Boot还有很多我可以做的,我在这里没有介绍。从本教程中总结出来,您应该已经掌握了如何使用Spring Boot的Logback,包括如何使用属性文件来更改Spring Boot提供的默认设置,以及如何更进一步,并通过logback.xml和logback-spring.xml使用Logback创建自己的自定义配置。您还应该了解属性文件中的配置可以提供的限制,以便您知道何时可以切换到直接使用 Logback 来帮助您到达终点线。
来源: https://dzone.com/articles/configuring-logback-with-spring-boot
|