[Spring Boot] Event Tracking

Spring Boot

Language :

Event

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.

spring_dependency_complie.png

spring_dependency_complie.png

@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-설정하기

민갤

Back-End Developer

백엔드 개발자입니다.