1. 로깅이란?
로깅은 어플리케이션의 동작 및 활동을 기록하고 추적하는 프로세스를 가리킵니다. 실행 중 발생하는 이벤트, 오류, 경고, 중요한 정보 및 디버깅 메시지를 기록하며, 이를 통해 다음과 같은 효과를 얻을 수 있습니다:
- 디버깅 및 오류 식별: 오류 발생 시 어떤 상황에서 문제가 발생했는지 추적하여 신속한 해결을 도울 수 있습니다.
- 성능 모니터링: 애플리케이션의 성능을 분석하고, 병목 현상을 식별해 성능을 최적화할 수 있습니다.
- 보안: 보안 로그를 통해 불법적인 접근을 추적하고, 시스템의 보안 상태를 모니터링할 수 있습니다.
- 이력 추적: 사용자 활동 기록 및 데이터 변경 내역을 추적해 감사 목적으로 사용할 수 있습니다.
2. 로깅 레벨
로깅 레벨은 로깅할 이벤트의 심각도를 정의하는 단계입니다. 로깅 레벨을 적절히 사용하면 로그의 양을 조절하고, 필요한 정보만 기록할 수 있습니다. 대표적인 로깅 레벨은 다음과 같습니다:
- TRACE: 가장 세밀한 디버깅 정보를 기록하며, 함수 호출이나 메서드 진입 및 종료와 같은 상세한 추적이 필요할 때 사용됩니다.
- DEBUG: 디버깅 목적으로 사용되며, 개발 단계에서 특정 로직이 어떻게 동작하는지 확인할 때 유용합니다.
- INFO: 정상적인 애플리케이션 실행의 주요 이벤트를 기록합니다. 예를 들어, 사용자의 로그인 성공, 중요한 작업 완료 등을 기록할 수 있습니다.
- WARN: 잠재적인 문제를 나타내며, 기능이 동작은 하지만 예외적인 상황이 발생했을 때 기록합니다. 예를 들어, 사용자가 잘못된 형식의 데이터를 입력했을 때.
- ERROR: 애플리케이션이 정상적으로 동작하지 못하게 하는 심각한 오류를 기록합니다. 예를 들어, 데이터베이스 연결 실패나 중요한 서비스의 다운 상태가 여기에 해당합니다.
3. 예외처리란?
예외 처리는 예상치 못한 문제나 오류 조건을 다루는 프로그래밍 기법으로, 이를 통해 어플리케이션의 안정성을 유지하고 예기치 않은 상황에서 비정상 종료를 방지할 수 있습니다. 예외 처리는 사용자 경험을 개선하고, 발생한 문제를 로깅하여 디버깅에 도움을 줍니다.
3.1 전역 예외 처리
Spring 프레임워크에서는 전역 예외 처리를 쉽게 구현할 수 있도록 @ControllerAdvice
와 @ExceptionHandler
를 제공합니다. 이를 통해 애플리케이션 전역에서 발생하는 예외를 일괄 처리할 수 있습니다.
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.ResponseStatus;
@ControllerAdvice
public class GlobalExceptionHandler {
@ExceptionHandler(CustomException.class)
@ResponseStatus(HttpStatus.BAD_REQUEST)
@ResponseBody
public String handleCustomException(CustomException ex) {
log.warn("커스텀 예외 발생: {}", ex.getMessage(), ex);
return "에러: " + ex.getMessage();
}
@ExceptionHandler(Exception.class)
@ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
@ResponseBody
public String handleGeneralException(Exception ex) {
log.error("예외 발생: {}", ex.getMessage(), ex);
return "전역 예외 처리기: " + ex.getMessage();
}
}
- 전역 예외 처리기:
@ControllerAdvice
를 사용하면 모든 컨트롤러에서 발생하는 예외를 중앙에서 처리할 수 있습니다. 이를 통해 코드 중복을 줄이고, 예외 처리 로직을 일관성 있게 관리할 수 있습니다. - HTTP 응답 코드 설정:
@ResponseStatus
를 통해 예외 발생 시 적절한 HTTP 상태 코드를 클라이언트에게 반환할 수 있습니다. 예를 들어, 잘못된 요청인 경우 400 Bad Request, 서버 내부 오류인 경우 500 Internal Server Error를 반환합니다.
3.2 특정 예외 처리
특정 컨트롤러나 서비스에서 발생하는 특정 예외를 처리하고자 할 때는 @ExceptionHandler
를 개별적으로 설정할 수 있습니다. 이 방법은 특정 예외에 맞춤형 처리가 필요할 때 유용합니다.
@ExceptionHandler(SQLException.class)
@ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
@ResponseBody
public String handleDatabaseException(SQLException ex) {
log.error("데이터베이스 연결 오류: {}", ex.getMessage(), ex);
return "데이터베이스 오류가 발생했습니다. 잠시 후 다시 시도해주세요.";
}
이 예시에서 데이터베이스 연결에 실패하면 SQLException
을 잡아 적절한 메시지를 클라이언트에 반환하고, 동시에 로그에 오류를 기록하여 개발자가 나중에 문제를 분석할 수 있도록 합니다.
4. 로깅 설정
이번 프로젝트에서는 Log4j2를 사용하여 로깅을 관리합니다. Spring Boot는 기본적으로 Logback을 사용하지만, Log4j2는 비동기 로깅과 더 높은 성능을 제공하기 때문에 대규모 시스템에서 선호됩니다.
4.1 Logback을 Log4j2로 교체
Logback 대신 Log4j2를 사용하기 위해 spring-boot-starter-logging
을 명시적으로 제외하고, spring-boot-starter-log4j2
를 사용합니다.
configurations {
all {
exclude group: 'org.springframework.boot', module: 'spring-boot-starter-logging'
}
}
dependencies {
implementation 'org.springframework.boot:spring-boot-starter-log4j2'
}
4.2 log4j2.xml 설정
<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="INFO">
<Properties>
<Property name="logNm">Board-Server-log4j2</Property>
<Property name="layoutPattern">%d{yyyy/MM/dd HH:mm:ss,SSS} [%p] %c - %m%n</Property>
</Properties>
<Appenders>
<Console name="Console_Appender" target="SYSTEM_OUT">
<PatternLayout pattern="${layoutPattern}"/>
</Console>
<RollingFile name="File_Appender" fileName="logs/${logNm}.log"
filePattern="logs/${logNm}_%d{yyyy-MM-dd}_%i.log.gz">
<PatternLayout pattern="${layoutPattern}"/>
<Policies>
<SizeBasedTriggeringPolicy size="200KB"/>
<TimeBasedTriggeringPolicy interval="1"/>
</Policies>
<DefaultRolloverStrategy max="10" fileIndex="min"/>
</RollingFile>
</Appenders>
<Loggers>
<Root level="INFO" additivity="false">
<AppenderRef ref="Console_Appender"/>
<AppenderRef ref="File_Appender"/>
</Root>
<Logger name="org.springframework" level="DEBUG" additivity="false">
<AppenderRef ref="Console_Appender"/>
<AppenderRef ref="File_Appender"/>
</Logger>
</Loggers>
</Configuration>
4.3 구성 설명
- Appenders: 로그 이벤트가 저장될 위치를 정의합니다.
Console
은 로그를 콘솔에 출력하고,RollingFile
은 일정 크기나 시간이 지나면 로그 파일을 새로운 파일로 분할(롤링)하여 저장합니다. - Loggers: 각 패키지나 클래스에서 어떤 레벨의 로그를 기록할지 정의합니다.
Root Logger
는 애플리케이션 전반의 로그 레벨을 설정하며,org.springframework
와 같은 패키지에 대해 별도의 로그 레벨을 설정할 수 있습니다.
4.4 RollingFileAppender의 중요성
RollingFileAppender
를 사용하여 로그 파일의 크기가 일정 크기(예: 200KB) 이상이 되면 새로운 파일로 저장합니다. 이를 통해 로그 파일이 너무 커지는 것을 방지하고, 관리와 모니터링이 더 쉬워집니다. 특히 대규모 트래픽을 처리하는 시스템에서는 로그 양이 많기 때문에, 로그 파일을 적절히 분할하여 성능 문제를 예방할 수 있습니다.
이번 포스팅에서는 로깅과 예외 처리의 개념과 실무에서의 활용 방법을 다루었습니다. 로깅을 통해 어플리케이션의 상태를 모니터
링하고, 예외 처리를 통해 예상치 못한 오류에 대응하는 전략을 효과적으로 세워 안정적인 시스템을 유지할 수 있습니다.
'프레임워크 > 자바 스프링' 카테고리의 다른 글
대규모 트래픽 게시판 구축 시리즈 #13: 알림 서비스 구현과 통합 - AWS SNS 및 Slack (0) | 2024.09.07 |
---|---|
대규모 트래픽 게시판 구축 시리즈 #12: 성능 테스트 (5) | 2024.09.07 |
대규모 트래픽 게시판 구축 시리즈 #10: 게시판 검색 API (0) | 2024.09.07 |
대규모 트래픽 게시판 구축 시리즈 #9: 게시판 API (0) | 2024.09.07 |
대규모 트래픽 게시판 구축 시리즈 #8: 카테고리 API (0) | 2024.09.07 |