Logging is an important part of all applications and benefits not only us, the developers, but also the users and maintainers of the system. Spring Boot applications should collect relevant log data to help us diagnose and fix problems and measure business performance.
The Spring Boot framework is preconfigured with Logback as the default implementation in its "competent" approach to the Spring Framework. This article explores various ways to configure logging in Spring Boot.
Sample code
This article is accompanied by a sample working code on GitHub .
Why journaling is important
Decisions about what and where to log are often strategic and are made with the assumption that an application might not function correctly in real-world environments. Logs play a key role in helping the application quickly recover from any such crashes and resume normal operation.
Making mistakes at integration points visible
The distributed nature of today's applications built using a microservice architecture introduces many work pieces. Thus, naturally, you can run into problems due to temporary failures in any of the infrastructure systems.
Exception logs recorded at integration points allow us to identify the root cause of an interruption and allow us to take appropriate action to recover with minimal impact on the end-user experience.
Diagnosis of functional errors in the production system
There may be customer complaints about the wrong transaction amount. To diagnose this, we need to drill down into our logs to find the sequence of operations from the request data when the API is called to the response data at the end of the processing API.
Event history analysis
. , .
, , , .
, , , , . CI / CD.
Spring Boot
Spring Boot - Logback .
, Spring Boot. -, start.spring.io . :
@SpringBootApplication
public class SpringLoggerApplication {
static final Logger log =
LoggerFactory.getLogger(SpringLoggerApplication.class);
public static void main(String[] args) {
log.info("Before Starting application");
SpringApplication.run(SpringLoggerApplication.class, args);
log.debug("Starting my application in debug with {} args", args.length);
log.info("Starting my application with {} args.", args.length);
}
}
Maven Gradle jar , :
13:21:45.673 [main] INFO io.pratik.springLogger.SpringLoggerApplication - Before Starting application
. ____ _ __ _ _
/\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
\\/ ___)| |_)| | | | | || (_| | ) ) ) )
' |____| .__|_| |_|_| |_\__, | / / / /
=========|_|==============|___/=/_/_/_/
:: Spring Boot :: (v2.3.2.RELEASE)
.
.
.
... : Started SpringLoggerApplication in 3.054 seconds (JVM running for 3.726)
... : Starting my application 0
, Spring, . .
application.properties
( application.yml
), .
. .
java -jar target/springLogger-0.0.1-SNAPSHOT.jar --trace
, , , .
, , Spring. , log.level.<package-name>
:
java \\
-jar target/springLogger-0.0.1-SNAPSHOT.jar \\
-Dlogging.level.org.springframework=ERROR \\
-Dlogging.level.io.pratik=TRACE
application.properties
:
logging.level.org.springframework=ERROR
logging.level.io.app=TRACE
, logging.file.name
logging.file.path
application.properties
. info.
# Output to a file named application.log.
logging.file.name=application.log
# Output to a file named spring.log in path /Users
logging.file.path=/Users
, logging.file.name
.
, Spring 2.2 , . 2.3.2.RELEASE.
, logging.pattern.file
:
# Logging pattern for file
logging.pattern.file= %d{yyyy-MM-dd HH:mm:ss} [%thread] %-5level %logger{36} - %msg%
, :
| , | |
---|---|---|
|
| 10 Mb |
|
| 7 |
| . , . |
|
|
|
, .
Spring . , off application.properties
:
spring.main.banner-mode=off
ANSI, spring.output.ansi.enabled
. : , .
spring.output.ansi.enabled=ALWAYS
spring.output.ansi.enabled
DETECT
. , ANSI.
Logback Spring Boot . log4j java util, spring-boot-starter-loging pom.xml
:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<exclusions>
<exclusion>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-logging</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-log4j2</artifactId>
</dependency>
logback-spring.xml
, logback.xml
logback-spring.xml
XML . Spring logback-spring.xml
, logback-spring.groovy
.
appender
configuration
. encoder
:
<configuration >
<include
resource="/org/springframework/boot/logging/logback/base.xml" />
<appender name="STDOUT"
class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n
</pattern>
</encoder>
</appender>
</configuration>
Logback
debug
configuration
true
, .
<configuration debug="true">
, Logback, :
...- About to instantiate appender of type [...ConsoleAppender]
...- About to instantiate appender of type [...RollingFileAppender]
..SizeAndTimeBasedRollingPolicy.. - setting totalSizeCap to 0 Bytes
..SizeAndTimeBasedRollingPolicy.. - ..limited to [10 MB] each.
..SizeAndTimeBasedRollingPolicy.. Will use gz compression
..SizeAndTimeBasedRollingPolicy..use the pattern /var/folders/
..RootLoggerAction - Setting level of ROOT logger to INFO
, , .
, logback-spring.xml
. , .
. Spring Boot , . , Logstash:
<appender name="LOGSTASH"
class="net.logstash.logback.appender.LogstashTcpSocketAppender">
<destination>localhost:4560</destination>
<encoder charset="UTF-8"
class="net.logstash.logback.encoder.LogstashEncoder" />
</appender>
LogstashEncoder
JSON localhost:4560
. .
Lombok
, : Lombok, Slf4j
:
@Service
@Slf4j
public class UserService {
public String getUser(final String userID) {
log.info("Service: Fetching user with id {}", userID);
}
}
In this article, we have seen how to use logging in Spring Boot and how to configure it according to our requirements. But to take full advantage of the benefits, the framework's logging capabilities need to be complemented by robust and standardized logging practices across your development teams.
These techniques will also need to be implemented through a combination of peer review and automated code quality control tools. Taken together, this ensures that when production errors occur, we have as much information as possible to diagnose.
You can find all the source code used in the article on Github .