출처 : https://youtu.be/fkwb8coxBJM
※ 출시순서 : log4j -> logback -> log4j2
appender
- Log의 형태 및 어디에 출력할지 설정하기 위한 영역
- 대표적인 Appender형식은 다음과 같음
- ConsoleAppender : 콘솔에 로그를 출력
- FileAppender : 파일에 로그를 저장
- RollingFileAppender : 여러개의 파일을 순회하며 로그를 저장(로그 레벨 중심)
- SMTPAppender : 로그를 메일로 보냄
- DBAppender : 데이터베이스에 로그를 저장
Encoder
- Appender 내에 포함되는 항목이며, pattern을 사용하여 원하는 형식으로 출력
root
- 설정한 Appender를 참조하여 로그의 레벨을 설정할 수 있음
- root는 전역설정이며, 지역설정을 하기 위해서는 logger를 사용
TRACE > DEBUG > INFO > WARN > ERROR
1) ERROR : 로직 수행 중에 오류가 발생한 경우, 시스템적으로 심각한 문제가 발생하여 작동이 불가한 경우
2) WARN : 시스템 에러의 원인이 될 수 있는 경고 레벨, 처리가능한 사항
3) INFO : 상태 변경과 같은 정보성 메시지
4) DEBUG : 어플리케이션의 디버깅을 위한 메시지 레벨
5) TRACE : DEBUG 레벨보다 더 디테일한 메시지를 표현하기 위한 레벨
※예를 들어 로그 레벨을 INFO로 설정할 경우 TRACE, DEBUG 레벨은 출력되지 않음.
-- 실습
<?xml version="1.0" encoding="UTF-8"?>
<configuration scan="true" scanPeriod="30 seconds"> <!-- logback 구현체가 설정을 확인하는 주기 -->
<property name="moduleId" value="around_hub_spring_boot"/><!-- moduleId는 프로젝트가 설치된 폴더명 또는 구분할 수 있는 식별자이면 됨 -->
<property name="type" value="around_hub"/><!-- 로그파일명을 구성하는 인자 -->
<property name="logback" value="logback"/><!-- log를 저장할 최종 디렉토리명 -->
<property name="logdir" value="D:\Workspace\LogFiles"/>
<!-- Appenders -->
<appender name="console" class="ch.qos.logback.core.ConsoleAppender"> <!-- 콘솔에 출력 : class형식 콘솔에 출력되는 형식-->
<filter class="ch.qos.logback.classic.filter.ThresholdFilter">
<level>DEBUG</level> <!-- 디버그 이상의 출력값들을 보겠다는 이야기 -->
</filter>
<encoder>
<pattern>[%d{yyyy-MM-dd HH:mm:ss.SSS}] [%-5level] [%thread] %logger{30} %msg%n</pattern>
<!-- 로그 출력 패턴-->
</encoder>
</appender>
<!-- <appender name="DEBUG_LOG" class="ch.qos.logback.core.rolling.RollingFileAppender">-->
<!-- <filter class="ch.qos.logback.classic.filter.ThresholdFilter">-->
<!-- <level>DEBUG</level>-->
<!-- </filter>-->
<!-- <file>${logdir}/${moduleId}/${logback}/debug_${type}.log</file>-->
<!-- <append>true</append>-->
<!-- <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">-->
<!-- <fileNamePattern>${logdir}/${moduleId}/${logback}/debug_${type}.%d{yyyy-MM-dd}.gz</fileNamePattern>-->
<!-- <maxHistory>30</maxHistory>-->
<!-- </rollingPolicy>-->
<!-- <encoder>-->
<!-- <pattern>[%d{yyyy-MM-dd HH:mm:ss.SSS}] [%-5level] [%thread] %logger %msg%n</pattern>-->
<!-- </encoder>-->
<!-- </appender>-->
<!-- <appender name="INFO_LOG" class="ch.qos.logback.core.rolling.RollingFileAppender">-->
<!-- <filter class="ch.qos.logback.classic.filter.ThresholdFilter">-->
<!-- <level>INFO</level>-->
<!-- </filter>-->
<!-- <file>${logdir}/${moduleId}/${logback}/info_${type}.log</file>-->
<!-- <append>true</append>-->
<!-- <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">-->
<!-- <fileNamePattern>${logdir}/${moduleId}/${logback}/info_${type}.%d{yyyy-MM-dd}.gz</fileNamePattern>-->
<!-- <maxHistory>30</maxHistory>-->
<!-- </rollingPolicy>-->
<!-- <encoder>-->
<!-- <pattern>[%d{yyyy-MM-dd HH:mm:ss.SSS}] [%-5level] [%thread] %logger %msg%n</pattern>-->
<!-- </encoder>-->
<!-- </appender>-->
<!--
<appender name="WARN_LOG" class="ch.qos.logback.core.rolling.RollingFileAppender">
<filter class="ch.qos.logback.classic.filter.ThresholdFilter">
<level>WARN</level>
</filter>
<file>${logdir}/${moduleId}/${logback}/warn_${type}.log</file>
<append>true</append>
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<fileNamePattern>${logdir}/${moduleId}/${logback}/warn_${type}.%d{yyyy-MM-dd}.gz</fileNamePattern>
<maxHistory>30</maxHistory>
</rollingPolicy>
<encoder>
<pattern>[%d{yyyy-MM-dd HH:mm:ss.SSS}] [%-5level] [%thread] %logger %msg%n</pattern>
</encoder>
</appender>
<appender name="ERROR_LOG" class="ch.qos.logback.core.rolling.RollingFileAppender">
<filter class="ch.qos.logback.classic.filter.ThresholdFilter">
<level>WARN</level>
</filter>
<file>${logdir}/${moduleId}/${logback}/error_${type}.log</file>
<append>true</append>
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<fileNamePattern>${logdir}/${moduleId}/${logback}/error_${type}.%d{yyyy-MM-dd}.gz</fileNamePattern>
<maxHistory>30</maxHistory>
</rollingPolicy>
<encoder>
<pattern>[%d{yyyy-MM-dd HH:mm:ss.SSS}] [%-5level] [%thread] %logger %msg%n</pattern>
</encoder>
</appender>
-->
<!-- TRACE > DEBUG > INFO > WARN > ERROR > OFF -->
<!-- Root Logger -->
<!-- INFO 레벨에 맞게끔 출력해라 -->
<root level="INFO">
<!-- 윗부분의 appender의 이름과 매칭되어야한다. -->
<appender-ref ref="console" />
<!--
<appender-ref ref="DEBUG_LOG" />
<appender-ref ref="INFO_LOG" />
<appender-ref ref="WARN_LOG" />
<appender-ref ref="ERROR_LOG" />
-->
</root>
</configuration>
원래 spring에서 로그백 설정하기 위해서는 디펜던시를 추가해야함
스프링 부트같은 경우 starterweb이라는 dependency에서 의존성을 잡고 있기 때문에 자동으로 로그백 잡혀있음 -> 별도 라이브러리 세팅할 필요 없음
package com.example.testproject.controller;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class HelloController {
//
private final Logger LOGGER= LoggerFactory.getLogger(HelloController.class);
@RequestMapping("/hello")
public String hello(){
return "Hello World";
}
@PostMapping("log-test")
public void logTest(){
LOGGER.trace("trace log");
LOGGER.debug("debug log");
LOGGER.info("info log");
LOGGER.warn("warn log");
LOGGER.error("error log");
}
}
RUN했을때 콘솔의 모습
swaggerUI에 들어가서 execute해주었을때
-로그가 추가로 찍히는것을 볼 수 있다.
[%d{yyyy-MM-dd HH:mm:ss.SSS}][%-5level] [%thread] %logger{30} %msg%n
[INFO ] : 레벨
[%thread] : 쓰레드이름-번호
%logger : 로거의 항목 뒤에 {30}붙여도 됨 (간단하게 만들때)
%msg%n : 로거의 메세지 출력
로그에 info와 warning만 찍히게 된 이유는 logback설정 해줄때
<root level="INFO">
로 설정해놓았기 때문임
// http://localhost:8080/api/v1/product-api/product/{productId}
@GetMapping(value = "/product/{productId}")
public ProductDto getProduct(@PathVariable String productId) {
long startTime=System.currentTimeMillis();
LOGGER.info("[ProductController] perform {} of Around Hub API.", "getProduct");
ProductDto productDto=productService.getProduct(productId);
//중괄호를 사용해서 원하는 값들을 넣어준다
LOGGER.info("[ProductController] Response :: productId = {}, productName = {}, productPrice = {}, productStock = {}, Response Time = {}ms",
productDto.getProductId(),productDto.getProductName(),productDto.getProductPrice(),productDto.getProductStock(),
(System.currentTimeMillis()-startTime));
return productDto;
}
swagger로 이동후 일단 create를 excute시켜보기 (조회하기위해)
get 실행시 하단 로그 찍히는걸 볼 수 있음.
[2022-10-19 00:37:32.607] [INFO ] [http-nio-8081-exec-10] c.e.t.c.ProductController [ProductController] perform getProduct of Around Hub API.
Hibernate: select productent0_.product_id as product_1_0_0_, productent0_.product_name as product_2_0_0_, productent0_.product_price as product_3_0_0_, productent0_.product_stock as product_4_0_0_ from product productent0_ where productent0_.product_id=?
[2022-10-19 00:37:32.613] [INFO ] [http-nio-8081-exec-10] c.e.t.c.ProductController [ProductController] Response :: productId = string, productName = string, productPrice = 0, productStock = 0, Response Time = 6ms