📌 상황
프로젝트를 진행하면서 프론트와 백엔드 간의 API 연동이 활발해졌고,
그 과정에서 백엔드에서 처리하지 못한 예외로 수정 작업이 종종 발생했다.
에러가 발생한 직후 빠르게 대응할 수 있도록,
에러 로그가 발생하면 개발자에게 즉시 이메일로 알림을 보내는 구조를 도입했다.
🧱 환경 정보
- Spring Boot: 3.4.2
- spring-boot-starter-mail: 3.4.2
- 메일 서버: Gmail SMTP 사용
- 로그 시스템: Logback (Spring Boot 기본)
- 로그 분석 스케줄러: Spring @Scheduled
1. 📦 의존성 추가
먼저 메일 기능을 사용하기 위해 아래와 같이 의존성을 추가했다.
implementation 'org.springframework.boot:spring-boot-starter-mail'
2. 📝 Logback 설정 – logback-spring.xml
로그를 파일로 저장하고, 에러 발생 시 메일로 전송하도록 설정한다.
<configuration>
<property name="LOG_PATH" value="logs" />
<!-- 로그 파일 저장 (일자별) -->
<appender name="DAILY_ROLLING_FILE_APPENDER" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>${LOG_PATH}/app.log</file>
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<fileNamePattern>${LOG_PATH}/app.%d{yyyy-MM-dd}.log</fileNamePattern>
<maxHistory>30</maxHistory>
</rollingPolicy>
<encoder>
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>
</encoder>
</appender>
<!-- 에러 로그를 이메일로 전송 -->
<appender name="EMAIL" class="ch.qos.logback.classic.net.SMTPAppender">
<smtpHost>smtp.gmail.com</smtpHost>
<smtpPort>587</smtpPort>
<username>${GMAIL_USERNAME}</username>
<password>${GMAIL_PASSWORD}</password>
<STARTTLS>true</STARTTLS>
<to>${GMAIL_USERNAME}</to>
<from>${GMAIL_USERNAME}</from>
<subject>[ALERT] Spring App Log 경고 발생</subject>
<layout class="ch.qos.logback.classic.PatternLayout">
<pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>
</layout>
<threshold>ERROR</threshold>
</appender>
<!-- 콘솔 출력 (선택) -->
<appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>
</encoder>
</appender>
<!-- 전체 로그 설정 -->
<root level="INFO">
<appender-ref ref="DAILY_ROLLING_FILE_APPENDER" />
<appender-ref ref="CONSOLE" />
<appender-ref ref="EMAIL" />
</root>
</configuration>
- EMAIL Appender는 에러 로그(LEVEL: ERROR) 발생 시 지정된 이메일로 전송한다.
- Gmail SMTP를 사용하며, Gmail 보안 설정에서 앱 비밀번호 또는 OAuth 설정이 필요하다.
3. 📬 커스텀 이메일 전송 (선택적 로그 감지)
Logback 설정은 모든 ERROR 로그를 전송하지만,
실제로는 특정 오류에 대해서만 알림이 필요할 수 있다.
예: Redis 토큰 저장 실패 등 중요 로직
그래서 @Scheduled로 주기적으로 로그를 확인하고,
특정 키워드가 포함된 로그만 메일로 전송하도록 구성했다.
@Component
@RequiredArgsConstructor
public class LogMonitor {
@Value("${spring.mail.username}")
private String sendToEmail;
private final JavaMailSender mailSender;
@Scheduled(fixedDelay = 3600000) // 1시간마다 실행
public void checkLogFile() throws IOException {
Path logPath = Paths.get("logs/app.log");
if (!Files.exists(logPath)) return;
List<String> lines = Files.readAllLines(logPath);
LocalDateTime oneHourAgo = LocalDateTime.now().minusHours(1);
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss.SSS");
for (String line : lines) {
try {
String timestamp = line.substring(0, 23);
LocalDateTime logTime = LocalDateTime.parse(timestamp, formatter);
if (logTime.isAfter(oneHourAgo) && line.contains("redis refresh token 저장 오류 발생")) {
sendEmail(line);
break; // 중복 전송 방지
}
} catch (Exception ignored) {}
}
}
private void sendEmail(String logMessage) {
SimpleMailMessage message = new SimpleMailMessage();
message.setTo(sendToEmail);
message.setFrom(sendToEmail);
message.setSubject("[ERROR 발생] Spring 로그 알림");
message.setText("🚨 로그에서 다음과 같은 오류가 감지되었습니다:\\n\\n" + logMessage);
mailSender.send(message);
}
}
- logs/app.log에서 최근 1시간 이내의 로그만 필터링
- "redis refresh token 저장 오류 발생" 메시지가 있으면 알림 전송
- 중복 전송을 방지하기 위해 한 건만 처리 후 break
✅ 결과
설정된 조건에 따라 다음과 같은 방식으로 알림 메일을 받을 수 있다:
구분 설명
제목 | [ERROR 발생] Spring 로그 알림 |
본문 | 오류 로그 내용 (스택 트레이스 또는 커스텀 메시지) |
수신 | 개발자 이메일 (Gmail 등) |

🔧 개선점 및 향후 계획
현재는 로그 정보를 단순 파일 형태로 저장하고,
스케줄러가 해당 로그 파일을 **라인 단위로 전부 순회(full scan)**하며 에러 여부를 탐지하고 있다.
이 방식은 구조가 단순하다는 장점이 있지만,
로그가 많아질수록 탐색 시간도 선형적으로 증가하게 된다.
또한, 로그 데이터에 대한 시계열 분석이나 조건별 필터링이 제한적이기 때문에
성능 및 분석 측면에서 아쉬움이 있다.
📉 현재 방식의 한계
- 매 스캔 시 로그 파일 전체를 읽기 때문에 비효율적
- 로그의 시간 범위 필터링이 어려움 (첫 줄부터 전체 확인 필요)
- 정렬, 집계, 시각화 등의 분석 기능이 미흡
- 에러 유형별 통계나 추세를 알기 어려움
📈 개선 계획: Elasticsearch 도입
이를 보완하기 위해, 다음 단계로는 Elasticsearch 기반 로그 분석 시스템을 구축할 계획이다.
- 로그 데이터를 Elasticsearch에 저장하고,
- Kibana 시각화를 통해 실시간 모니터링 및 분석이 가능하도록 개선할 예정이다.
- 시계열 데이터로 저장된 로그는 기간 필터, 쿼리 검색, 집계 분석 등 다양한 기능을 제공하므로, 정확한 원인 분석, 에러 추적, 안정성 점검이 쉬워진다.
🎯 기대 효과
- 검색 속도 개선: full scan 없이 시간대 검색 가능
- 정확한 오류 감지 및 분석: 다양한 쿼리 조합 가능
- 로그 시각화: 에러 패턴과 발생 추세를 한눈에 파악
- 운영 안정성 확보: 문제 발생 시 더 빠르게 대응 가능
'Springboot' 카테고리의 다른 글
[Spring] 요청 데이터 처리 원리 (0) | 2025.03.26 |
---|---|
[Spring + Redis] 비밀번호 설정 및 Lettuce 연결 설정 정리 (0) | 2025.03.21 |
[스프링부트] ObjectMapper JsonNode Object로 변환 (0) | 2025.03.12 |
[SpringSecurity] BCrypt 비밀번호 인증 구현 (0) | 2025.03.12 |
[SpringBoot] Filter에서의 예외처리 (0) | 2025.03.08 |