[Spring Boot] Event Tracking
Spring BootEvent
The interaction that occurs between the user and the content, such as clicking, scrolling the screen, etc.
Event Tracking
The process of tracking and recording what the user is doing.
Logging
Debugging errors that occur during development or operation, or recording information (logs) necessary to monitor program status.
You can analyze logs to produce statistics.
Failure to properly set log criteria may result in bloated log files or only meaningless logs.
The Spring Framework basically uses a Spring-JCL module that implements Commons Logging (link), and is changed to SLF4J (Logback) or Log4j based on the dependence on the time of compilation.
@RestController
@RequestMapping("/tracker/api")
class TrackerController {
companion object {
private val logger = LoggerFactory.getLogger(this::class.java)
}
@GetMapping
fun tracking(request: HttpServletRequest): ResponseEntity<Any> {
logger.debug("tracker message")
return ResponseEntity(HttpStatus.OK)
}
}
[2023-08-22 14:36:44:28859] DEBUG 39592 --- [nio-8080-exec-1] c.e.t.c.TrackerController$Companion : tracker message
JCL(Jakarta Commons Logging, Apache Commons Loggundefinedng)
Log interface that was primarily used before SLF4J appeared
It works at runtime and is a logging method that is rarely used at the moment.
It is said that there is a class loader problem and a memory leak problem.
SLF4J(Simple Logging Facade for Java)
Library that serves as an abstraction (Interface, Facade Pattern) for various logging implementations (Logging Framework), such as java.util.logging, logback, and reload4j
Select and use the logging implementation at the time of compilation, not at runtime.
Delivery Module
1. SLF4J API
It provides an interface for using SLF4J for logging implementations.(SLF4J Interface)
2. SLF4J Binding (Supplier)
Library (as an adapter) that links the SLF4J API to the logging implementation.
Only one SLF4J binding should be used for the logging implementation to be used.(one and only one)Only one SLF4J binding should be used for the logging implementation to be used.(one and only one)
If multiple bindings are used, it is not possible to predict which bindings will be used.
3. SLF4J Bridging Modules
A library that connects (Redirects) the SLF4J interface when calling Logger to a logging API other than SLF4J so that the SLF4J API can handle it instead.
The logging implementation that SLF4J binds will be used.
Binding and Bridge cannot be used as jar associated with the same logging implementation.(Infinite Loop Occurred)
the course of action
Other logging API(log4j, jul, jcl) > SLF4J Bridge > SLF4J API > SLF4J Binding > Logging Framework
Logback
Logging Framework Created by Log4J Developers
Three modules provided by SLF4J are connected.
Log Level
Log level severity level: Trace < Debug < Info < Warn < Error
Depending on the console log level setting, the higher level is not output.
- Trace: Records all levels and uses them for route tracking.
- Debug: Use in the development phase and record query details.
- Info: Record operational reference, informational messages.
- Warn: Records areas where there is no immediate impact on the service but needs attention.
- Error: Record serious problems that require immediate action.
Setting the recording format differently depending on the deployment environment (link)
1. application-dev.yml
log:
config:
path: ./logs
filename: dev
max-history: 7
total-size-cap: 1GB
2. application-prod.yml
log:
config:
path: ./logs
filename: prod
max-history: 7
total-size-cap: 1GB
3. logback-spring.xml
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<springProfile name="dev">
<property resource="application-dev.yml"/>
</springProfile>
<springProfile name="prod">
<property resource="application-prod.yml"/>
</springProfile>
<springProperty name="LOG_DIR_PATH" source="log.config.path"/>
<springProperty name="LOG_FILE_NAME" source="log.config.filename"/>
<springProperty name="LOG_MAX_HISTORY" source="log.config.max-history"/>
<springProperty name="LOG_TOTAL_SIZE_CAP" source="log.config.total-size-cap"/>
<property name="CONSOLE_LOG_PATTERN"
value="[%d{yyyy-MM-dd HH:mm:ss}:%-3relative] %highlight(%-5level) %magenta(${PID:-}) --- [%15.15thread] %cyan(%-40.40logger{36}) : %msg%n"/>
<property name="FILE_LOG_PATTERN"
value="[%d{yyyy-MM-dd HH:mm:ss.SSS,Asia/Tokyo}:%-3relative] %-5level ${PID:-} --- [%15.15thread] %-40.40logger{36} : %msg%n"/>
<property name="FILE_LOG_PATTERN_CLASS_NUMBER"
value="[%d{yyyy-MM-dd HH:mm:ss.SSS,Asia/Tokyo}:%-3relative] %-5level ${PID:-} --- [%15.15thread] %logger{36} [%file:%line] - %msg ##%n"/>
<!-- Log to Console (STDOUT) -->
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
<pattern>${CONSOLE_LOG_PATTERN}</pattern>
</encoder>
</appender>
<!-- Log to File -->
<appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
<!-- Logs accumulated during application operation -->
<file>${LOG_DIR_PATH}/${LOG_FILE_NAME}.log</file>
<encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
<pattern>${FILE_LOG_PATTERN_CLASS_NUMBER}</pattern>
</encoder>
<!-- Log File Archive Rules -->
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<!-- Specify the name of the archived log file -->
<fileNamePattern>${LOG_DIR_PATH}/%d{yyyy-MM,aux}/${LOG_FILE_NAME}.%d.log</fileNamePattern>
<!-- Maximum number of months to archive, delete old files in order -->
<maxHistory>${LOG_MAX_HISTORY}</maxHistory>
<!-- Limit total archive size. Default byte unit -->
<totalSizeCap>${LOG_TOTAL_SIZE_CAP}</totalSizeCap>
</rollingPolicy>
</appender>
<!-- Asynchronous File -->
<appender name="FILE-ASYNC" class="ch.qos.logback.classic.AsyncAppender">
<appender-ref ref="FILE"/>
<!-- Whether to record code information (class:line number) associated with the event. When used, performance degradation occurs.-->
<includeCallerData>false</includeCallerData>
<!-- ERROR, Warn, and other logs are deleted if the queue capacity remains at the set value of %. Keep all logs when set to zero -->
<discardingThreshold>0</discardingThreshold>
<!-- Queue size -->
<queueSize>1024</queueSize>
<!-- Default false. If there is no space left in the queue, the thread is blocked and waits for space to be empty. If true, discard the log instead of falling into a blocking state -->
<neverBlock>true</neverBlock>
</appender>
<springProfile name="dev">
<root level="DEBUG">
<appender-ref ref="STDOUT"/>
<appender-ref ref="FILE-ASYNC"/>
</root>
</springProfile>
<springProfile name="prod">
<root level="INFO">
<appender-ref ref="STDOUT"/>
</root>
<logger name="my_logger" level="DEBUG">
<appender-ref ref="FILE"/>
</logger>
</springProfile>
</configuration>
4. controller
@RestController
@RequestMapping("/tracker/api")
class TrackerController {
companion object {
private val logger = LoggerFactory.getLogger(this::class.java)
private val myLogger = LoggerFactory.getLogger("my_logger")
}
@GetMapping
fun tracking(request: HttpServletRequest): ResponseEntity<Any> {
logger.debug("tracker message debug")
logger.info("tracker message info")
myLogger.debug("tracker message mylogger debug")
myLogger.info("tracker message mylogger info")
return ResponseEntity(HttpStatus.OK)
}
}
1. Console Log when running as profile dev
[2023-08-22 15:23:49:13390] DEBUG 41788 --- [nio-8080-exec-1] c.e.t.c.TrackerController$Companion : tracker message debug
[2023-08-22 15:23:49:13390] INFO 41788 --- [nio-8080-exec-1] c.e.t.c.TrackerController$Companion : tracker message info
[2023-08-22 15:23:49:13390] DEBUG 41788 --- [nio-8080-exec-1] my_logger : tracker message mylogger debug
[2023-08-22 15:23:49:13390] INFO 41788 --- [nio-8080-exec-1] my_logger : tracker message mylogger info
2. Console Log (when my_logger debug annotated) when running as profile profile
[2023-08-22 15:23:08:17824] INFO 24896 --- [nio-8080-exec-2] c.e.t.c.TrackerController$Companion : tracker message info
[2023-08-22 15:23:08:17824] INFO 24896 --- [nio-8080-exec-2] my_logger : tracker message mylogger info
3. Console Log when running as profile profile (without my_logger debug annotation)
[2023-08-22 15:27:10:11846] INFO 420 --- [nio-8080-exec-1] c.e.t.c.TrackerController$Companion : tracker message info
[2023-08-22 15:27:10:11846] DEBUG 420 --- [nio-8080-exec-1] my_logger : tracker message mylogger debug
[2023-08-22 15:27:10:11847] INFO 420 --- [nio-8080-exec-1] my_logger : tracker message mylogger info
File generation needs more research
Log4j
Apache's Java-based Logging Framework is the oldest framework.
A fatal vulnerability was discovered in 2021 and became an issue.
It is recommended that you use version 2.17.1 or later or replace it with a different logging module.
Reference
https://www.slf4j.org/manual.html
https://loosie.tistory.com/829
https://livenow14.tistory.com/63
https://gmlwjd9405.github.io/2019/01/04/logging-with-slf4j.html
https://velog.io/@mindfulness_22/slf4j-slf4j-logback-3
https://velog.io/@codemcd/Spring-Boot-and-Logging-1.-SLF4J
https://rlawls1991.tistory.com/entry/스프링-부트-기본-로거-설정
https://velog.io/@mindfulness_22/slf4j-facade-pattern-1
https://tecoble.techcourse.co.kr/post/2021-08-07-logback-tutorial
https://ckddn9496.tistory.com/82
https://velog.io/@cho876/Springboot-LogBack-설정하기