본문 바로가기

개발

자바 스프링부트 앱- 로그 레벨별로 여러 로그 파일 남기기

자바를 배워본적도 없는 내게 자바 스프링부트 앱으로 로그 파일을 3개나 만들라는 지시가 떨어졌다.... 두둥...

처음엔 멘붕이 와서 어버버버했는데, 인도인 유투버 아저씨들의 도움을 받아 개략적인 틀은 완성했지만 계속 뭔가 쫌 부족했다.
로그는 어떻게 찍어야 할지 감도 안 잡혔는데, 
로그 레벨별로 debug, info, error 3개의 경우를 나눠 로그 파일을 만들어야 한다니... 정말 막막했다.

그래도 끊임없는 구글링과 다른 개발자분들의 조언 덕에 구현할 수 있었다.

 

기본적인 스프링부트 앱을 만드는 방법은 여기를 참조했다.
https://donghoon-khan.github.io/2020/08/10/deploy-spring-boot-application-on-kubernetes/

 

Spring Boot 애플리케이션 쿠버네티스로 배포하기 - Donghoon Kang | DH Blog

스프링 프레임워크는 자바 플랫폼을 위한 오픈소스 애플리케이션 프레임워크로, 따로 설명하지 않아도 웹개발자라면 한번씩은 경험해본 프레임워크일 것이다. Spring은 MSA를 위해 Spring-Cloud라는

donghoon-khan.github.io

 

간단하게 헬로월드 파일을 5초마다 찍는 자바 파일을 만든다.

src/main/java/com/example/demo.SpringBootLoggerApplication.java

package com.example.demo;

import java.util.Timer;
import java.util.TimerTask;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.web.bind.annotation.RestController;

@RestController
@SpringBootApplication
public class SpringBootLoggerApplication {

    public static void main (String [] args)
    {
            SpringApplication.run(SpringBootLoggerApplication.class, args);
            new Timer().schedule(new Task(), 1000, 5000);
    }
    
}

class Task extends TimerTask {

    private static final Logger LOGGER = LoggerFactory.getLogger(SpringBootLoggerApplication.class);
        private int i = 1;

    @Override
    public void run() {
        LOGGER.info("Hello World ::: "+(i));
        i++;
    	if (i%5==0)
	        try {
	            throw new Exception("Error message");
	        } catch (Exception e) {
	                LOGGER.error("This is Logger Error message " + e);
	        }
    
    }
}

 

src/main/resources/logback.yml 파일을 만들고 다음과 같은 내용을 붙여넣는다.

<configuration>

    <property name="LOG_PATTERN" value="(%date [%thread]) %-5level %marker|%logger{36}: %msg%n" />
    <property name="LOG_BASEDIR" value="logfile"/>

    <appender name="console" class="ch.qos.logback.core.ConsoleAppender">
        <encoder>
            <pattern>${LOG_PATTERN}</pattern>
        </encoder>
    </appender>

    <appender name="appLog" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <file>${LOG_BASEDIR}/app.log</file>
        <encoder>
            <pattern>${LOG_PATTERN}</pattern>
        </encoder>
        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
            <fileNamePattern>${LOG_BASEDIR}/app-%d{yyyy-MM-dd}.log</fileNamePattern>
            <maxHistory>30</maxHistory>
            <totalSizeCap>1GB</totalSizeCap>
        </rollingPolicy>
    </appender>

    <appender name="exceptionLog" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <file>${LOG_BASEDIR}/exception.log</file>
        <encoder>
            <pattern>${LOG_PATTERN}</pattern>
        </encoder>
        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
            <fileNamePattern>${LOG_BASEDIR}/exception-%d{yyyy-MM-dd}.log</fileNamePattern>
            <maxHistory>30</maxHistory>
            <totalSizeCap>1GB</totalSizeCap>
        </rollingPolicy>
        <filter class="ch.qos.logback.classic.filter.LevelFilter">
            <level>ERROR</level>
            <onMatch>ACCEPT</onMatch>
            <onMismatch>DENY</onMismatch>
        </filter>
    </appender>

    <appender name="etcLog" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <file>${LOG_BASEDIR}/etc.log</file>
        <encoder>
            <pattern>${LOG_PATTERN}</pattern>
        </encoder>
        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
            <fileNamePattern>${LOG_BASEDIR}/etc-%d{yyyy-MM-dd}.log</fileNamePattern>
            <maxHistory>30</maxHistory>
            <totalSizeCap>1GB</totalSizeCap>
        </rollingPolicy>
        <filter class="ch.qos.logback.classic.filter.LevelFilter">
            <level>DEBUG</level>
            <onMatch>ACCEPT</onMatch>
            <onMismatch>DENY</onMismatch>
        </filter>
    </appender>

    <logger name="com.example.demo.SpringBootLoggerApplication" level="INFO">
        <appender-ref ref="appLog" />
    </logger> 
     
    <logger name="com.example.demo" level="ERROR">
        <appender-ref ref="exceptionLog" />
    </logger>

    <root level="DEBUG">
    <appender-ref ref="console" />
    <appender-ref ref="etcLog" />
    </root>
    
</configuration>

 

info level -> app.log
debug level -> etc.log
error level -> exception.log
와 같이 로그가 남는다. 

 

app.log

* 2022-01-23 22:04:04,616 [Timer-0] INFO  |c.i.app.SpringBootLoggerApplication: Hello World ::: 1, pod_name_IS_UNDEFINED, pod_namespace_IS_UNDEFINED, cluster_name_IS_UNDEFINED
* 2022-01-23 22:04:09,617 [Timer-0] INFO  |c.i.app.SpringBootLoggerApplication: Hello World ::: 2, pod_name_IS_UNDEFINED, pod_namespace_IS_UNDEFINED, cluster_name_IS_UNDEFINED
* 2022-01-23 22:04:14,617 [Timer-0] INFO  |c.i.app.SpringBootLoggerApplication: Hello World ::: 3, pod_name_IS_UNDEFINED, pod_namespace_IS_UNDEFINED, cluster_name_IS_UNDEFINED
* 2022-01-23 22:04:19,618 [Timer-0] INFO  |c.i.app.SpringBootLoggerApplication: Hello World ::: 4, pod_name_IS_UNDEFINED, pod_namespace_IS_UNDEFINED, cluster_name_IS_UNDEFINED
* 2022-01-23 22:04:19,618 [Timer-0] ERROR |c.i.app.SpringBootLoggerApplication: This is Logger Error message java.lang.Exception: Error message, pod_name_IS_UNDEFINED, pod_namespace_IS_UNDEFINED, cluster_name_IS_UNDEFINED
* 2022-01-23 22:04:24,620 [Timer-0] INFO  |c.i.app.SpringBootLoggerApplication: Hello World ::: 5, pod_name_IS_UNDEFINED, pod_namespace_IS_UNDEFINED, cluster_name_IS_UNDEFINED
* 2022-01-23 22:04:29,621 [Timer-0] INFO  |c.i.app.SpringBootLoggerApplication: Hello World ::: 6, pod_name_IS_UNDEFINED, pod_namespace_IS_UNDEFINED, cluster_name_IS_UNDEFINED
* 2022-01-23 22:04:34,621 [Timer-0] INFO  |c.i.app.SpringBootLoggerApplication: Hello World ::: 7, pod_name_IS_UNDEFINED, pod_namespace_IS_UNDEFINED, cluster_name_IS_UNDEFINED
* 2022-01-23 22:04:39,622 [Timer-0] INFO  |c.i.app.SpringBootLoggerApplication: Hello World ::: 8, pod_name_IS_UNDEFINED, pod_namespace_IS_UNDEFINED, cluster_name_IS_UNDEFINED
* 2022-01-23 22:04:44,622 [Timer-0] INFO  |c.i.app.SpringBootLoggerApplication: Hello World ::: 9, pod_name_IS_UNDEFINED, pod_namespace_IS_UNDEFINED, cluster_name_IS_UNDEFINED
* 2022-01-23 22:04:44,623 [Timer-0] ERROR |c.i.app.SpringBootLoggerApplication: This is Logger Error message java.lang.Exception: Error message, pod_name_IS_UNDEFINED, pod_namespace_IS_UNDEFINED, cluster_name_IS_UNDEFINED
* 2022-01-23 22:04:49,626 [Timer-0] INFO  |c.i.app.SpringBootLoggerApplication: Hello World ::: 10, pod_name_IS_UNDEFINED, pod_namespace_IS_UNDEFINED, cluster_name_IS_UNDEFINED

 

etc.log

* 2022-01-23 22:04:03,606 [restartedMain] DEBUG |o.s.b.a.ApplicationAvailabilityBean: Application availability state LivenessState changed to CORRECT, pod_name_IS_UNDEFINED, pod_namespace_IS_UNDEFINED, cluster_name_IS_UNDEFINED
* 2022-01-23 22:04:03,608 [restartedMain] DEBUG |o.s.boot.devtools.restart.Restarter: Creating new Restarter for thread Thread[main,5,main], pod_name_IS_UNDEFINED, pod_namespace_IS_UNDEFINED, cluster_name_IS_UNDEFINED
* 2022-01-23 22:04:03,608 [restartedMain] DEBUG |o.s.boot.devtools.restart.Restarter: Immediately restarting application, pod_name_IS_UNDEFINED, pod_namespace_IS_UNDEFINED, cluster_name_IS_UNDEFINED
* 2022-01-23 22:04:03,608 [restartedMain] DEBUG |o.s.boot.devtools.restart.Restarter: Starting application com.infotech.app.SpringBootLoggerApplication with URLs [file:/Users/ru/code/springboot/SpringBootLogger/target/classes/], pod_name_IS_UNDEFINED, pod_namespace_IS_UNDEFINED, cluster_name_IS_UNDEFINED
* 2022-01-23 22:04:03,609 [restartedMain] DEBUG |o.s.b.a.ApplicationAvailabilityBean: Application availability state ReadinessState changed to ACCEPTING_TRAFFIC, pod_name_IS_UNDEFINED, pod_namespace_IS_UNDEFINED, cluster_name_IS_UNDEFINED
* 2022-01-23 22:04:59,958 [RMI TCP Connection(8)-127.0.0.1] DEBUG |o.s.b.a.ApplicationAvailabilityBean: Application availability state ReadinessState changed from ACCEPTING_TRAFFIC to REFUSING_TRAFFIC, pod_name_IS_UNDEFINED, pod_namespace_IS_UNDEFINED, cluster_name_IS_UNDEFINED
* 2022-01-23 22:04:59,958 [RMI TCP Connection(8)-127.0.0.1] DEBUG |o.s.b.w.s.c.AnnotationConfigServletWebServerApplicationContext: Closing org.springframework.boot.web.servlet.context.AnnotationConfigServletWebServerApplicationContext@412f8456, started on Sun Jan 23 22:04:00 KST 2022, pod_name_IS_UNDEFINED, pod_namespace_IS_UNDEFINED, cluster_name_IS_UNDEFINED
* 2022-01-23 22:04:59,960 [RMI TCP Connection(8)-127.0.0.1] DEBUG |o.s.c.s.DefaultLifecycleProcessor: Stopping beans in phase 2147483647, pod_name_IS_UNDEFINED, pod_namespace_IS_UNDEFINED, cluster_name_IS_UNDEFINED
* 2022-01-23 22:04:59,961 [RMI TCP Connection(8)-127.0.0.1] DEBUG |o.s.c.s.DefaultLifecycleProcessor: Bean 'webServerGracefulShutdown' completed its stop procedure, pod_name_IS_UNDEFINED, pod_namespace_IS_UNDEFINED, cluster_name_IS_UNDEFINED
* 2022-01-23 22:04:59,961 [RMI TCP Connection(8)-127.0.0.1] DEBUG |o.s.c.s.DefaultLifecycleProcessor: Stopping beans in phase 2147483646, pod_name_IS_UNDEFINED, pod_namespace_IS_UNDEFINED, cluster_name_IS_UNDEFINED
* 2022-01-23 22:04:59,980 [RMI TCP Connection(8)-127.0.0.1] DEBUG |o.s.c.s.DefaultLifecycleProcessor: Bean 'webServerStartStop' completed its stop procedure, pod_name_IS_UNDEFINED, pod_namespace_IS_UNDEFINED, cluster_name_IS_UNDEFINED
* 2022-01-23 22:04:59,981 [RMI TCP Connection(8)-127.0.0.1] DEBUG |o.s.j.e.a.AnnotationMBeanExporter: Unregistering JMX-exposed beans on shutdown, pod_name_IS_UNDEFINED, pod_namespace_IS_UNDEFINED, cluster_name_IS_UNDEFINED
* 2022-01-23 22:04:59,982 [RMI TCP Connection(8)-127.0.0.1] DEBUG |o.s.s.c.ThreadPoolTaskExecutor: Shutting down ExecutorService 'applicationTaskExecutor', pod_name_IS_UNDEFINED, pod_namespace_IS_UNDEFINED, cluster_name_IS_UNDEFINED

 

exception.log

* 2022-01-23 20:59:01,510 [Timer-0] ERROR |c.i.app.SpringBootLoggerApplication: This is Logger Error message java.lang.Exception: Error message, pod_name_IS_UNDEFINED, pod_namespace_IS_UNDEFINED, cluster_name_IS_UNDEFINED
* 2022-01-23 20:59:26,514 [Timer-0] ERROR |c.i.app.SpringBootLoggerApplication: This is Logger Error message java.lang.Exception: Error message, pod_name_IS_UNDEFINED, pod_namespace_IS_UNDEFINED, cluster_name_IS_UNDEFINED
* 2022-01-23 20:59:51,527 [Timer-0] ERROR |c.i.app.SpringBootLoggerApplication: This is Logger Error message java.lang.Exception: Error message, pod_name_IS_UNDEFINED, pod_namespace_IS_UNDEFINED, cluster_name_IS_UNDEFINED
* 2022-01-23 21:00:06,899 [Timer-1] ERROR |c.i.app.SpringBootLoggerApplication: This is Logger Error message java.lang.Exception: Error message, pod_name_IS_UNDEFINED, pod_namespace_IS_UNDEFINED, cluster_name_IS_UNDEFINED
* 2022-01-23 21:00:51,652 [Timer-0] ERROR |c.i.app.SpringBootLoggerApplication: This is Logger Error message java.lang.Exception: Error message, pod_name_IS_UNDEFINED, pod_namespace_IS_UNDEFINED, cluster_name_IS_UNDEFINED
* 2022-01-23 22:01:33,669 [Timer-0] ERROR |c.i.app.SpringBootLoggerApplication: This is Logger Error message java.lang.Exception: Error message, pod_name_IS_UNDEFINED, pod_namespace_IS_UNDEFINED, cluster_name_IS_UNDEFINED
* 2022-01-23 22:04:19,618 [Timer-0] ERROR |c.i.app.SpringBootLoggerApplication: This is Logger Error message java.lang.Exception: Error message, pod_name_IS_UNDEFINED, pod_namespace_IS_UNDEFINED, cluster_name_IS_UNDEFINED
* 2022-01-23 22:04:44,623 [Timer-0] ERROR |c.i.app.SpringBootLoggerApplication: This is Logger Error message java.lang.Exception: Error message, pod_name_IS_UNDEFINED, pod_namespace_IS_UNDEFINED, cluster_name_IS_UNDEFINED