SpringBoot 에서 Logging을 사용해보자 Using Logging in SpringBoot
What is a Log?
- Simply put, a log is a continuous record of data
- When first learning programming, most people frequently use System.out.print
- During program execution, something gets printed to the console - these outputs can serve as logs
Logging Framework
- While you can use System.out.print for debugging, this approach becomes very inefficient as your application grows larger
- Planning ahead for convenient log viewing after development is one way to create and maintain good programs
Slf4j
- As requirements for logging and tracing increased, logging frameworks emerged to address these needs
- Among Spring’s logging frameworks, Slf4j is the most popular library
- Using Slf4j, you can easily swap and use implementations like
logback,log4j, andlog4j2
Let’s Apply Logging
- The development environment is as follows:
- SpringBoot
- Kotlin
- Gradle
Dependency Configuration (build.gradle.kts)
import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
plugins {
id("org.springframework.boot") version "2.7.1"
id("io.spring.dependency-management") version "1.0.11.RELEASE"
kotlin("jvm") version "1.6.21"
kotlin("plugin.spring") version "1.6.21"
}
group = "com.example"
version = "0.0.1-SNAPSHOT"
java.sourceCompatibility = JavaVersion.VERSION_11
configurations {
compileOnly {
extendsFrom(configurations.annotationProcessor.get())
}
}
repositories {
mavenCentral()
}
dependencies {
implementation("org.springframework.boot:spring-boot-starter-web")
implementation("com.fasterxml.jackson.module:jackson-module-kotlin")
implementation("org.springframework.boot:spring-boot-starter-log4j2")
implementation("org.jetbrains.kotlin:kotlin-reflect")
implementation("org.jetbrains.kotlin:kotlin-stdlib-jdk8")
compileOnly("org.projectlombok:lombok")
annotationProcessor("org.projectlombok:lombok")
testImplementation("org.springframework.boot:spring-boot-starter-test")
}
configurations.forEach {
it.exclude(group = "org.springframework.boot", module = "spring-boot-starter-logging")
it.exclude(group = "org.apache.logging.log4j", module = "log4j-to-slf4j")
}
tasks.withType<KotlinCompile> {
kotlinOptions {
freeCompilerArgs = listOf("-Xjsr305=strict")
jvmTarget = "11"
}
}
tasks.withType<Test> {
useJUnitPlatform()
}
log4j2 Configuration
- You can configure log4j2 using XML configuration or Jackson-based configuration
- Create an
xmlfile under SpringBoot’sresourcefolder - Save the created
xmlfile aslog4j2.xmland add the following content:
<?xml version="1.0" encoding="UTF-8" ?>
<Configuration status="INFO">
<Properties>
<Property name="LOG_PATTERN">%d{HH:mm:ss.SSSZ} [%t] %-5level %logger{36} - %msg%n</Property>
</Properties>
<Appenders>
<Console name="ConsoleLog" target="SYSTEM_OUT">
<PatternLayout pattern="${LOG_PATTERN}" charset="UTF-8"/>
</Console>
</Appenders>
<Loggers>
<Root level="info">
<AppenderRef ref="ConsoleLog"/>
<AppenderRef ref="FileLog"/>
</Root>
</Loggers>
</Configuration>
- Configuration: The top-level element for log configuration
- status attribute: Sets the logging level for Log4j2’s internal operations (used when logging is needed to resolve internal log4j issues)
- Properties: Defines variables to be used in the configuration below
- name: In the example above, name=”LOG_PATTERN” defines a variable called LOG_PATTERN
- Appenders: Where logs are output
- Console: Settings for logs output to the console
- name: Name of the appender
- target: Log target (default: SYSTEM_OUT)
- PatternLayout: Sets the log pattern
- Loggers: The entity responsible for logging operations, allowing various settings per package
- Root: General log policy settings for logging across all packages (only one can be set)
- AppenderRef: References the Appender configured above
- Root: General log policy settings for logging across all packages (only one can be set)
Writing TestController
- Let’s write a TestController and output logs from that controller
- In Java, you can use log directly after importing Slf4j, but in Kotlin, you need to declare it as shown below
- There are various ways to configure Logger in Kotlin, so I’ve included a helpful reference link below
package com.example.springkotlinloggingsample
import lombok.extern.slf4j.Slf4j
import org.slf4j.Logger
import org.slf4j.LoggerFactory
import org.springframework.stereotype.Controller
import org.springframework.web.bind.annotation.GetMapping
@Slf4j
@Controller
class TestController {
val logger: Logger = LoggerFactory.getLogger(TestController::class.java)
@GetMapping("/")
fun index(): String {
logger.info("Hello, This is INFO Message")
logger.debug("Hello, This is DEBUG Message")
logger.trace("Hello, This is TRACE Message")
logger.warn("Hello, This is WARN Message")
logger.error("Hello, This is ERROR Message")
return "index"
}
}
- Now when you output logs through an API call, you’ll see logs like this:
[http-nio-8080-exec-2] INFO com.example.springkotlinloggingsample.TestController - Hello, This is INFO Message [http-nio-8080-exec-2] WARN com.example.springkotlinloggingsample.TestController - Hello, This is WARN Message [http-nio-8080-exec-2] ERROR com.example.springkotlinloggingsample.TestController - Hello, This is ERROR Message- TRACE and DEBUG are not displayed
- Logging has levels, and TRACE and DEBUG require additional configuration to lower the log level to be visible
- The log levels are as follows:
TRACE > DEBUG > INFO > WARN > ERROR
Save Logs to Files (Modify log4j2.xml)
- You can see that logs are being output in the format configured in log4j2.xml
- Since logs should be retrievable even if the server goes down, many people use methods to send logs to other platforms
- In this example, we’ll simply save logs to “files”
-
Modify log4j2.xml as follows:
<?xml version="1.0" encoding="UTF-8" ?> <Configuration status="INFO"> <Properties> <Property name="LOG_PATTERN">%d{HH:mm:ss.SSSZ} [%t] %-5level %logger{36} - %msg%n</Property> </Properties> <Appenders> <Console name="ConsoleLog" target="SYSTEM_OUT"> <PatternLayout pattern="${LOG_PATTERN}" charset="UTF-8"/> </Console> <RollingFile name="FileLog" fileName="./logs/spring.log" filePattern="./logs/spring-%d{yyyy-MM-dd}-%i.log"> <PatternLayout pattern="${LOG_PATTERN}" charset="UTF-8" /> <Policies> <TimeBasedTriggeringPolicy interval="1" /> <SizeBasedTriggeringPolicy size="10000KB" /> </Policies> <DefaultRolloverStrategy max="20" fileIndex="min" /> </RollingFile> </Appenders> <Loggers> <Root level="info"> <AppenderRef ref="ConsoleLog" /> <AppenderRef ref="FileLog" /> </Root> </Loggers> </Configuration>-
RollingFile: Configure log output to files based on conditions
- name: Name of the appender
- fileName: File name including path
- filePattern: File name pattern including path based on rolling conditions
- Policies: File rolling policies
- TimeBasedTriggeringPolicy: Records logs to a new file on a daily basis (interval=1)
- SizeBasedTriggeringPolicy: Creates a new file when the file size exceeds the limit
- DefaultRolloverStrategy: Sets the maximum number of files that can be created when file capacity is exceeded
-
After configuring as above, a logs folder will be created under springboot and log files will accumulate there
-
댓글남기기