From aa911ace917181294680c8cf68ce89ef7b26fb3a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=B2=9C=20=EC=A7=84=EA=B0=95?= <jjjjjk12@ajou.ac.kr> Date: Sat, 29 Mar 2025 11:56:18 +0900 Subject: [PATCH] =?UTF-8?q?fix:=20enum=20type=20=EC=86=8C=EB=AC=B8?= =?UTF-8?q?=EC=9E=90=20=EC=A7=81=EB=A0=AC=ED=99=94=EB=A1=9C=20=EB=B3=80?= =?UTF-8?q?=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/aolda/itda/config/LoggingFilter.java | 96 +++++----- .../itda/controller/main/MainController.java | 66 +++---- .../com/aolda/itda/dto/main/MainInfoDTO.java | 40 ++-- .../itda/entity/certificate/Challenge.java | 12 +- .../com/aolda/itda/entity/log/Action.java | 12 +- .../com/aolda/itda/entity/log/ObjectType.java | 12 +- .../aolda/itda/service/main/MainService.java | 122 ++++++------ src/main/resources/logback-spring.xml | 178 +++++++++--------- 8 files changed, 284 insertions(+), 254 deletions(-) diff --git a/src/main/java/com/aolda/itda/config/LoggingFilter.java b/src/main/java/com/aolda/itda/config/LoggingFilter.java index 49264ec..f2330bf 100644 --- a/src/main/java/com/aolda/itda/config/LoggingFilter.java +++ b/src/main/java/com/aolda/itda/config/LoggingFilter.java @@ -1,48 +1,48 @@ -package com.aolda.itda.config; - -import jakarta.servlet.FilterChain; -import jakarta.servlet.ServletException; -import jakarta.servlet.http.HttpServletRequest; -import jakarta.servlet.http.HttpServletResponse; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.stereotype.Component; -import org.springframework.web.filter.OncePerRequestFilter; -import org.springframework.web.util.ContentCachingRequestWrapper; - -import java.io.IOException; - -@Component -public class LoggingFilter extends OncePerRequestFilter { - - private static final Logger logger = LoggerFactory.getLogger(LoggingFilter.class); - - @Override - protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) - throws ServletException, IOException { - - // Request Body를 읽을 수 있도록 래핑 - ContentCachingRequestWrapper cachingRequest = new ContentCachingRequestWrapper(request); - filterChain.doFilter(cachingRequest, response); - - // 로그 기록 - logRequest(cachingRequest); - } - - private void logRequest(ContentCachingRequestWrapper request) { - String ip = request.getRemoteAddr(); - String method = request.getMethod(); - String uri = request.getRequestURI(); - String queryString = request.getQueryString(); - String body = getRequestBody(request); - - logger.info("IP: {}, Method: {}, URI: {}, Query Params: {}, Request Body: {}", - ip, method, uri, (queryString != null ? queryString : "None"), - (!body.isEmpty() ? body : "None")); - } - - private String getRequestBody(ContentCachingRequestWrapper request) { - byte[] buf = request.getContentAsByteArray(); - return (buf.length > 0) ? new String(buf) : ""; - } -} +package com.aolda.itda.config; + +import jakarta.servlet.FilterChain; +import jakarta.servlet.ServletException; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.stereotype.Component; +import org.springframework.web.filter.OncePerRequestFilter; +import org.springframework.web.util.ContentCachingRequestWrapper; + +import java.io.IOException; + +@Component +public class LoggingFilter extends OncePerRequestFilter { + + private static final Logger logger = LoggerFactory.getLogger(LoggingFilter.class); + + @Override + protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) + throws ServletException, IOException { + + // Request Body를 읽을 수 있도록 래핑 + ContentCachingRequestWrapper cachingRequest = new ContentCachingRequestWrapper(request); + filterChain.doFilter(cachingRequest, response); + + // 로그 기록 + logRequest(cachingRequest); + } + + private void logRequest(ContentCachingRequestWrapper request) { + String ip = request.getRemoteAddr(); + String method = request.getMethod(); + String uri = request.getRequestURI(); + String queryString = request.getQueryString(); + String body = getRequestBody(request); + + logger.info("IP: {}, Method: {}, URI: {}, Query Params: {}, Request Body: {}", + ip, method, uri, (queryString != null ? queryString : "None"), + (!body.isEmpty() ? body : "None")); + } + + private String getRequestBody(ContentCachingRequestWrapper request) { + byte[] buf = request.getContentAsByteArray(); + return (buf.length > 0) ? new String(buf) : ""; + } +} diff --git a/src/main/java/com/aolda/itda/controller/main/MainController.java b/src/main/java/com/aolda/itda/controller/main/MainController.java index 7b22923..371cce5 100644 --- a/src/main/java/com/aolda/itda/controller/main/MainController.java +++ b/src/main/java/com/aolda/itda/controller/main/MainController.java @@ -1,33 +1,33 @@ -package com.aolda.itda.controller.main; - -import com.aolda.itda.service.main.MainService; -import com.fasterxml.jackson.core.JsonProcessingException; -import jakarta.servlet.http.HttpServletRequest; -import lombok.RequiredArgsConstructor; -import org.springframework.http.ResponseEntity; -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RequestParam; -import org.springframework.web.bind.annotation.RestController; - -import java.util.List; -import java.util.Map; - -@RestController -@RequestMapping("/api") -@RequiredArgsConstructor -public class MainController { - - private final MainService mainService; - - @GetMapping("/projects") - public ResponseEntity<Object> projects(HttpServletRequest request) throws JsonProcessingException { - return ResponseEntity.ok(mainService.getAllProjects((Map<String, String>) request.getSession().getAttribute("user"))); - } - - @GetMapping("/main") - public ResponseEntity<Object> mainInfo(@RequestParam String projectId, HttpServletRequest request) { - return ResponseEntity.ok(mainService.getMainInfo(projectId, (List<String>) request.getAttribute("projects"))); - } - -} +package com.aolda.itda.controller.main; + +import com.aolda.itda.service.main.MainService; +import com.fasterxml.jackson.core.JsonProcessingException; +import jakarta.servlet.http.HttpServletRequest; +import lombok.RequiredArgsConstructor; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.RestController; + +import java.util.List; +import java.util.Map; + +@RestController +@RequestMapping("/api") +@RequiredArgsConstructor +public class MainController { + + private final MainService mainService; + + @GetMapping("/projects") + public ResponseEntity<Object> projects(HttpServletRequest request) throws JsonProcessingException { + return ResponseEntity.ok(mainService.getAllProjects((Map<String, String>) request.getSession().getAttribute("user"))); + } + + @GetMapping("/main") + public ResponseEntity<Object> mainInfo(@RequestParam String projectId, HttpServletRequest request) { + return ResponseEntity.ok(mainService.getMainInfo(projectId, (List<String>) request.getAttribute("projects"))); + } + +} diff --git a/src/main/java/com/aolda/itda/dto/main/MainInfoDTO.java b/src/main/java/com/aolda/itda/dto/main/MainInfoDTO.java index 6de5fdf..cbcdcd5 100644 --- a/src/main/java/com/aolda/itda/dto/main/MainInfoDTO.java +++ b/src/main/java/com/aolda/itda/dto/main/MainInfoDTO.java @@ -1,20 +1,20 @@ -package com.aolda.itda.dto.main; - -import com.fasterxml.jackson.annotation.JsonInclude; -import lombok.AllArgsConstructor; -import lombok.Builder; -import lombok.Data; -import lombok.NoArgsConstructor; - -@Data -@NoArgsConstructor -@AllArgsConstructor -@Builder -@JsonInclude(JsonInclude.Include.NON_NULL) -public class MainInfoDTO { - - private Long routing; - private Long forwarding; - private Long certificate; - -} +package com.aolda.itda.dto.main; + +import com.fasterxml.jackson.annotation.JsonInclude; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Data +@NoArgsConstructor +@AllArgsConstructor +@Builder +@JsonInclude(JsonInclude.Include.NON_NULL) +public class MainInfoDTO { + + private Long routing; + private Long forwarding; + private Long certificate; + +} diff --git a/src/main/java/com/aolda/itda/entity/certificate/Challenge.java b/src/main/java/com/aolda/itda/entity/certificate/Challenge.java index 14713bf..41f607e 100644 --- a/src/main/java/com/aolda/itda/entity/certificate/Challenge.java +++ b/src/main/java/com/aolda/itda/entity/certificate/Challenge.java @@ -1,5 +1,15 @@ package com.aolda.itda.entity.certificate; +import com.fasterxml.jackson.annotation.JsonFormat; +import com.fasterxml.jackson.annotation.JsonValue; + +@JsonFormat(shape = JsonFormat.Shape.STRING) public enum Challenge { - HTTP, DNS_CLOUDFLARE + HTTP, DNS_CLOUDFLARE; + + @JsonValue + @Override + public String toString() { + return name().toLowerCase(); + } } diff --git a/src/main/java/com/aolda/itda/entity/log/Action.java b/src/main/java/com/aolda/itda/entity/log/Action.java index a620f87..448a65e 100644 --- a/src/main/java/com/aolda/itda/entity/log/Action.java +++ b/src/main/java/com/aolda/itda/entity/log/Action.java @@ -1,5 +1,15 @@ package com.aolda.itda.entity.log; +import com.fasterxml.jackson.annotation.JsonFormat; +import com.fasterxml.jackson.annotation.JsonValue; + +@JsonFormat(shape = JsonFormat.Shape.STRING) public enum Action { - CREATE, UPDATE, DELETE + CREATE, UPDATE, DELETE; + + @JsonValue + @Override + public String toString() { + return name().toLowerCase(); + } } diff --git a/src/main/java/com/aolda/itda/entity/log/ObjectType.java b/src/main/java/com/aolda/itda/entity/log/ObjectType.java index 5310315..c91f279 100644 --- a/src/main/java/com/aolda/itda/entity/log/ObjectType.java +++ b/src/main/java/com/aolda/itda/entity/log/ObjectType.java @@ -1,5 +1,15 @@ package com.aolda.itda.entity.log; +import com.fasterxml.jackson.annotation.JsonFormat; +import com.fasterxml.jackson.annotation.JsonValue; + +@JsonFormat(shape = JsonFormat.Shape.STRING) public enum ObjectType { - ROUTING, CERTIFICATE, FORWARDING + ROUTING, CERTIFICATE, FORWARDING; + + @JsonValue + @Override + public String toString() { + return name().toLowerCase(); + } } diff --git a/src/main/java/com/aolda/itda/service/main/MainService.java b/src/main/java/com/aolda/itda/service/main/MainService.java index 2c36ac8..8a4345e 100644 --- a/src/main/java/com/aolda/itda/service/main/MainService.java +++ b/src/main/java/com/aolda/itda/service/main/MainService.java @@ -1,61 +1,61 @@ -package com.aolda.itda.service.main; - -import com.aolda.itda.dto.PageResp; -import com.aolda.itda.dto.auth.IdAndNameDTO; -import com.aolda.itda.dto.main.MainInfoDTO; -import com.aolda.itda.repository.certificate.CertificateRepository; -import com.aolda.itda.repository.forwarding.ForwardingRepository; -import com.aolda.itda.repository.routing.RoutingRepository; -import com.aolda.itda.service.AuthService; -import com.fasterxml.jackson.core.JsonProcessingException; -import lombok.RequiredArgsConstructor; -import org.springframework.stereotype.Service; -import org.springframework.transaction.annotation.Transactional; - -import java.util.List; -import java.util.Map; - -@Service -@Transactional -@RequiredArgsConstructor -public class MainService { - - private final AuthService authService; - private final RoutingRepository routingRepository; - private final ForwardingRepository forwardingRepository; - private final CertificateRepository certificateRepository; - - /* 메인 페이지에 필요한 정보 반환 */ - public MainInfoDTO getMainInfo(String projectId, List<String> projects) { - - /* 프로젝트 권한 검증 */ - authService.validateProjectAuth(projects, projectId); - - /* 카운팅 */ - Long routing = (long) routingRepository.findByProjectIdAndIsDeleted(projectId, false).size(); - Long forwarding = (long) forwardingRepository.findByProjectIdAndIsDeleted(projectId, false).size(); - Long certificate = 0L; - - return MainInfoDTO.builder() - .routing(routing) - .forwarding(forwarding) - .certificate(certificate) - .build(); - } - - /* 접근 가능한 프로젝트 조회 */ - public PageResp<IdAndNameDTO> getAllProjects(Map<String, String> user) throws JsonProcessingException { - - List<IdAndNameDTO> projects; - if (authService.isAdmin(user)) { - projects = authService.getAllProjects(user.get("token")); - } - - else { - projects = authService.getProjectsWithUser(user); - } - - return PageResp.<IdAndNameDTO>builder() - .contents(projects).build(); - } -} +package com.aolda.itda.service.main; + +import com.aolda.itda.dto.PageResp; +import com.aolda.itda.dto.auth.IdAndNameDTO; +import com.aolda.itda.dto.main.MainInfoDTO; +import com.aolda.itda.repository.certificate.CertificateRepository; +import com.aolda.itda.repository.forwarding.ForwardingRepository; +import com.aolda.itda.repository.routing.RoutingRepository; +import com.aolda.itda.service.AuthService; +import com.fasterxml.jackson.core.JsonProcessingException; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.util.List; +import java.util.Map; + +@Service +@Transactional +@RequiredArgsConstructor +public class MainService { + + private final AuthService authService; + private final RoutingRepository routingRepository; + private final ForwardingRepository forwardingRepository; + private final CertificateRepository certificateRepository; + + /* 메인 페이지에 필요한 정보 반환 */ + public MainInfoDTO getMainInfo(String projectId, List<String> projects) { + + /* 프로젝트 권한 검증 */ + authService.validateProjectAuth(projects, projectId); + + /* 카운팅 */ + Long routing = (long) routingRepository.findByProjectIdAndIsDeleted(projectId, false).size(); + Long forwarding = (long) forwardingRepository.findByProjectIdAndIsDeleted(projectId, false).size(); + Long certificate = 0L; + + return MainInfoDTO.builder() + .routing(routing) + .forwarding(forwarding) + .certificate(certificate) + .build(); + } + + /* 접근 가능한 프로젝트 조회 */ + public PageResp<IdAndNameDTO> getAllProjects(Map<String, String> user) throws JsonProcessingException { + + List<IdAndNameDTO> projects; + if (authService.isAdmin(user)) { + projects = authService.getAllProjects(user.get("token")); + } + + else { + projects = authService.getProjectsWithUser(user); + } + + return PageResp.<IdAndNameDTO>builder() + .contents(projects).build(); + } +} diff --git a/src/main/resources/logback-spring.xml b/src/main/resources/logback-spring.xml index a8acbee..39e9337 100644 --- a/src/main/resources/logback-spring.xml +++ b/src/main/resources/logback-spring.xml @@ -1,90 +1,90 @@ -<?xml version="1.0" encoding="UTF-8"?> -<configuration> - - <property name="MAX_FILE_SIZE" value="10MB" /> - <property name="TOTAL_SIZE" value="1GB" /> - <property name="MAX_HISTORY" value="30" /> - - <!-- 콘솔에 출력할 로그 형식 --> - <appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender"> - <encoder> - <pattern>[%d{yyyy-MM-dd HH:mm:ss}] [%thread] %-5level %logger{36} - %msg%n</pattern> - </encoder> - </appender> - - <!-- INFO 로그 파일 저장 (1개당 10MB, 5개까지 유지, 이후 압축) --> - <appender name="INFO_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender"> - <file>/data/logs/info.log</file> - <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy"> - <fileNamePattern>/data/logs/info.%d{yyyy-MM-dd}.%i.log.gz</fileNamePattern> - <maxHistory>${MAX_HISTORY}</maxHistory> - <totalSizeCap>${TOTAL_SIZE}</totalSizeCap> - <timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP"> - <maxFileSize>${MAX_FILE_SIZE}</maxFileSize> - </timeBasedFileNamingAndTriggeringPolicy> - </rollingPolicy> - <encoder> - <pattern>[%d{yyyy-MM-dd HH:mm:ss}] [%thread] %-5level %logger{36} - %msg%n</pattern> - </encoder> - <!-- INFO 레벨만 허용 --> - <filter class="ch.qos.logback.classic.filter.LevelFilter"> - <level>INFO</level> - <onMatch>ACCEPT</onMatch> - <onMismatch>DENY</onMismatch> - </filter> - </appender> - - <!-- WARN 로그 파일 저장 --> - <appender name="WARN_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender"> - <file>/data/logs/warn.log</file> - <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy"> - <fileNamePattern>/data/logs/warn.%d{yyyy-MM-dd}.%i.log.gz</fileNamePattern> - <maxHistory>${MAX_HISTORY}</maxHistory> - <totalSizeCap>${TOTAL_SIZE}</totalSizeCap> - <timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP"> - <maxFileSize>${MAX_FILE_SIZE}</maxFileSize> - </timeBasedFileNamingAndTriggeringPolicy> - </rollingPolicy> - <encoder> - <pattern>[%d{yyyy-MM-dd HH:mm:ss}] [%thread] %-5level %logger{36} - %msg%n</pattern> - </encoder> - <!-- WARN 레벨만 허용 --> - <filter class="ch.qos.logback.classic.filter.LevelFilter"> - <level>WARN</level> - <onMatch>ACCEPT</onMatch> - <onMismatch>DENY</onMismatch> - </filter> - </appender> - - <!-- ERROR 로그 파일 저장 --> - <appender name="ERROR_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender"> - <file>/data/logs/error.log</file> - <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy"> - <fileNamePattern>/data/logs/error.%d{yyyy-MM-dd}.%i.log.gz</fileNamePattern> - <maxHistory>${MAX_HISTORY}</maxHistory> - <totalSizeCap>${TOTAL_SIZE}</totalSizeCap> - <timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP"> - <maxFileSize>${MAX_FILE_SIZE}</maxFileSize> - </timeBasedFileNamingAndTriggeringPolicy> - </rollingPolicy> - <encoder> - <pattern>[%d{yyyy-MM-dd HH:mm:ss}] [%thread] %-5level %logger{36} - %msg%n</pattern> - </encoder> - <!-- ERROR 레벨만 허용 --> - <filter class="ch.qos.logback.classic.filter.LevelFilter"> - <level>ERROR</level> - <onMatch>ACCEPT</onMatch> - <onMismatch>DENY</onMismatch> - </filter> - </appender> - - <logger name="com.aolda.itda" additivity="false"> - <!-- 각 Appender 참조 (필터는 Appender 내부에 정의됨) --> - <appender-ref ref="INFO_FILE"/> - <appender-ref ref="WARN_FILE"/> - <appender-ref ref="ERROR_FILE"/> - <!-- 콘솔 출력 --> - <appender-ref ref="CONSOLE"/> - </logger> - +<?xml version="1.0" encoding="UTF-8"?> +<configuration> + + <property name="MAX_FILE_SIZE" value="10MB" /> + <property name="TOTAL_SIZE" value="1GB" /> + <property name="MAX_HISTORY" value="30" /> + + <!-- 콘솔에 출력할 로그 형식 --> + <appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender"> + <encoder> + <pattern>[%d{yyyy-MM-dd HH:mm:ss}] [%thread] %-5level %logger{36} - %msg%n</pattern> + </encoder> + </appender> + + <!-- INFO 로그 파일 저장 (1개당 10MB, 5개까지 유지, 이후 압축) --> + <appender name="INFO_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender"> + <file>/data/logs/info.log</file> + <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy"> + <fileNamePattern>/data/logs/info.%d{yyyy-MM-dd}.%i.log.gz</fileNamePattern> + <maxHistory>${MAX_HISTORY}</maxHistory> + <totalSizeCap>${TOTAL_SIZE}</totalSizeCap> + <timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP"> + <maxFileSize>${MAX_FILE_SIZE}</maxFileSize> + </timeBasedFileNamingAndTriggeringPolicy> + </rollingPolicy> + <encoder> + <pattern>[%d{yyyy-MM-dd HH:mm:ss}] [%thread] %-5level %logger{36} - %msg%n</pattern> + </encoder> + <!-- INFO 레벨만 허용 --> + <filter class="ch.qos.logback.classic.filter.LevelFilter"> + <level>INFO</level> + <onMatch>ACCEPT</onMatch> + <onMismatch>DENY</onMismatch> + </filter> + </appender> + + <!-- WARN 로그 파일 저장 --> + <appender name="WARN_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender"> + <file>/data/logs/warn.log</file> + <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy"> + <fileNamePattern>/data/logs/warn.%d{yyyy-MM-dd}.%i.log.gz</fileNamePattern> + <maxHistory>${MAX_HISTORY}</maxHistory> + <totalSizeCap>${TOTAL_SIZE}</totalSizeCap> + <timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP"> + <maxFileSize>${MAX_FILE_SIZE}</maxFileSize> + </timeBasedFileNamingAndTriggeringPolicy> + </rollingPolicy> + <encoder> + <pattern>[%d{yyyy-MM-dd HH:mm:ss}] [%thread] %-5level %logger{36} - %msg%n</pattern> + </encoder> + <!-- WARN 레벨만 허용 --> + <filter class="ch.qos.logback.classic.filter.LevelFilter"> + <level>WARN</level> + <onMatch>ACCEPT</onMatch> + <onMismatch>DENY</onMismatch> + </filter> + </appender> + + <!-- ERROR 로그 파일 저장 --> + <appender name="ERROR_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender"> + <file>/data/logs/error.log</file> + <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy"> + <fileNamePattern>/data/logs/error.%d{yyyy-MM-dd}.%i.log.gz</fileNamePattern> + <maxHistory>${MAX_HISTORY}</maxHistory> + <totalSizeCap>${TOTAL_SIZE}</totalSizeCap> + <timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP"> + <maxFileSize>${MAX_FILE_SIZE}</maxFileSize> + </timeBasedFileNamingAndTriggeringPolicy> + </rollingPolicy> + <encoder> + <pattern>[%d{yyyy-MM-dd HH:mm:ss}] [%thread] %-5level %logger{36} - %msg%n</pattern> + </encoder> + <!-- ERROR 레벨만 허용 --> + <filter class="ch.qos.logback.classic.filter.LevelFilter"> + <level>ERROR</level> + <onMatch>ACCEPT</onMatch> + <onMismatch>DENY</onMismatch> + </filter> + </appender> + + <logger name="com.aolda.itda" additivity="false"> + <!-- 각 Appender 참조 (필터는 Appender 내부에 정의됨) --> + <appender-ref ref="INFO_FILE"/> + <appender-ref ref="WARN_FILE"/> + <appender-ref ref="ERROR_FILE"/> + <!-- 콘솔 출력 --> + <appender-ref ref="CONSOLE"/> + </logger> + </configuration> \ No newline at end of file -- GitLab