Add HTTP session logging for authentication events

This commit is contained in:
Rinjae
2026-01-20 18:00:30 +09:00
parent 27ca5ead81
commit 9eb8e78b35
12 changed files with 503 additions and 3 deletions
@@ -0,0 +1,99 @@
package com.eactive.apim.portal.common.util;
import javax.servlet.http.HttpServletRequest;
/**
* HTTP 요청 관련 유틸리티 클래스
*/
public class HttpRequestUtil {
private static final String[] IP_HEADER_CANDIDATES = {
"X-Forwarded-For",
"Proxy-Client-IP",
"WL-Proxy-Client-IP",
"HTTP_X_FORWARDED_FOR",
"HTTP_X_FORWARDED",
"HTTP_X_CLUSTER_CLIENT_IP",
"HTTP_CLIENT_IP",
"HTTP_FORWARDED_FOR",
"HTTP_FORWARDED",
"HTTP_VIA",
"REMOTE_ADDR",
"X-Real-IP"
};
/**
* Proxy를 통한 접속도 고려하여 실제 클라이언트 IP 주소를 반환
*
* @param request HttpServletRequest 객체
* @return 클라이언트 IP 주소
*/
public static String getClientIpAddress(HttpServletRequest request) {
if (request == null) {
return "unknown";
}
String ip = null;
// 헤더들을 순회하면서 IP 주소 찾기
for (String header : IP_HEADER_CANDIDATES) {
ip = request.getHeader(header);
if (ip != null && !ip.isEmpty() && !"unknown".equalsIgnoreCase(ip)) {
break;
}
}
// 헤더에서 IP를 찾지 못한 경우 기본 메서드 사용
if (ip == null || ip.isEmpty() || "unknown".equalsIgnoreCase(ip)) {
ip = request.getRemoteAddr();
}
// X-Forwarded-For 헤더는 여러 IP를 포함할 수 있음 (쉼표로 구분)
// 첫 번째 IP가 실제 클라이언트 IP
if (ip != null && ip.contains(",")) {
ip = ip.split(",")[0].trim();
}
return ip;
}
/**
* Proxy를 통한 접속도 고려하여 실제 클라이언트 호스트명을 반환
*
* @param request HttpServletRequest 객체
* @return 클라이언트 호스트명
*/
public static String getClientHost(HttpServletRequest request) {
if (request == null) {
return "unknown";
}
String host = request.getHeader("X-Forwarded-Host");
if (host == null || host.isEmpty() || "unknown".equalsIgnoreCase(host)) {
host = request.getRemoteHost();
}
return host;
}
/**
* 요청이 Proxy를 통해 들어왔는지 확인
*
* @param request HttpServletRequest 객체
* @return Proxy를 통한 접속이면 true, 아니면 false
*/
public static boolean isProxied(HttpServletRequest request) {
if (request == null) {
return false;
}
for (String header : IP_HEADER_CANDIDATES) {
String value = request.getHeader(header);
if (value != null && !value.isEmpty() && !"unknown".equalsIgnoreCase(value)) {
return true;
}
}
return false;
}
}
@@ -0,0 +1,43 @@
package com.eactive.apim.portal.common.util;
/**
* JDK 8 호환성을 위한 문자열 반복 유틸리티
*/
public class StringRepeatUtil {
/**
* 문자를 지정된 횟수만큼 반복하여 문자열을 생성
*
* @param ch 반복할 문자
* @param count 반복 횟수
* @return 반복된 문자열
*/
public static String repeat(char ch, int count) {
if (count <= 0) {
return "";
}
char[] chars = new char[count];
for (int i = 0; i < count; i++) {
chars[i] = ch;
}
return new String(chars);
}
/**
* 문자열을 지정된 횟수만큼 반복
*
* @param str 반복할 문자열
* @param count 반복 횟수
* @return 반복된 문자열
*/
public static String repeat(String str, int count) {
if (str == null || count <= 0) {
return "";
}
StringBuilder sb = new StringBuilder(str.length() * count);
for (int i = 0; i < count; i++) {
sb.append(str);
}
return sb.toString();
}
}
@@ -3,6 +3,8 @@ package com.eactive.apim.portal.config;
import com.eactive.apim.portal.apps.login.constants.LoginConstants; import com.eactive.apim.portal.apps.login.constants.LoginConstants;
import com.eactive.apim.portal.apps.user.service.PortalUserLogService; import com.eactive.apim.portal.apps.user.service.PortalUserLogService;
import com.eactive.apim.portal.common.exception.UserNotFoundException; import com.eactive.apim.portal.common.exception.UserNotFoundException;
import com.eactive.apim.portal.common.util.HttpRequestUtil;
import com.eactive.apim.portal.common.util.StringRepeatUtil;
import com.eactive.apim.portal.portaluser.entity.PortalUser; import com.eactive.apim.portal.portaluser.entity.PortalUser;
import com.eactive.apim.portal.portaluser.repository.PortalUserRepository; import com.eactive.apim.portal.portaluser.repository.PortalUserRepository;
import com.eactive.apim.portal.template.entity.MessageCode; import com.eactive.apim.portal.template.entity.MessageCode;
@@ -23,6 +25,8 @@ import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession; import javax.servlet.http.HttpSession;
import java.io.IOException; import java.io.IOException;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
/** /**
* Created by Sungpil Hyun * Created by Sungpil Hyun
@@ -32,6 +36,9 @@ import java.io.IOException;
public class PortalAuthenticationFailureHandler implements AuthenticationFailureHandler { public class PortalAuthenticationFailureHandler implements AuthenticationFailureHandler {
private static final Logger logger = LoggerFactory.getLogger(PortalAuthenticationFailureHandler.class); private static final Logger logger = LoggerFactory.getLogger(PortalAuthenticationFailureHandler.class);
private static final Logger sessionLogger = LoggerFactory.getLogger("eapim.portal.session");
private static final DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss.SSS");
private final PortalUserRepository portalUserRepository; private final PortalUserRepository portalUserRepository;
private final PortalUserLogService userLogService; private final PortalUserLogService userLogService;
private final MessageHandlerService messageHandlerService; private final MessageHandlerService messageHandlerService;
@@ -82,10 +89,39 @@ public class PortalAuthenticationFailureHandler implements AuthenticationFailure
userLogService.logFailure(username, ip, sessionId); userLogService.logFailure(username, ip, sessionId);
// 로그인 실패 시 세션 정보 로깅
logLoginFailure(request, username, exception);
HttpSession session = request.getSession(); HttpSession session = request.getSession();
session.setAttribute(LoginConstants.LOGIN_MESSAGE, exception.getLocalizedMessage()); session.setAttribute(LoginConstants.LOGIN_MESSAGE, exception.getLocalizedMessage());
session.setAttribute("loginId", username); session.setAttribute("loginId", username);
String contextPath = request.getContextPath(); String contextPath = request.getContextPath();
response.sendRedirect(contextPath + "/login"); response.sendRedirect(contextPath + "/login");
} }
private void logLoginFailure(HttpServletRequest request, String username, AuthenticationException exception) {
StringBuilder logMessage = new StringBuilder();
logMessage.append("\n");
logMessage.append(StringRepeatUtil.repeat('=', 80)).append("\n");
logMessage.append("USER LOGIN FAILURE\n");
logMessage.append(StringRepeatUtil.repeat('=', 80)).append("\n");
logMessage.append("Username: ").append(username).append("\n");
logMessage.append("Session ID: ").append(request.getSession().getId()).append("\n");
logMessage.append("Failed At: ").append(LocalDateTime.now().format(formatter)).append("\n");
logMessage.append("Failure Reason: ").append(exception.getLocalizedMessage()).append("\n");
logMessage.append("\n");
logMessage.append(StringRepeatUtil.repeat('-', 80)).append("\n");
logMessage.append("REQUEST INFORMATION\n");
logMessage.append(StringRepeatUtil.repeat('-', 80)).append("\n");
logMessage.append("Client IP Address: ").append(HttpRequestUtil.getClientIpAddress(request)).append("\n");
logMessage.append("Client Host: ").append(HttpRequestUtil.getClientHost(request)).append("\n");
logMessage.append("Is Proxied: ").append(HttpRequestUtil.isProxied(request)).append("\n");
logMessage.append("Remote Address (Direct): ").append(request.getRemoteAddr()).append("\n");
logMessage.append("Remote Host (Direct): ").append(request.getRemoteHost()).append("\n");
logMessage.append("Request URI: ").append(request.getRequestURI()).append("\n");
logMessage.append("User-Agent: ").append(request.getHeader("User-Agent")).append("\n");
logMessage.append(StringRepeatUtil.repeat('=', 80)).append("\n");
sessionLogger.warn(logMessage.toString());
}
} }
@@ -2,6 +2,8 @@ package com.eactive.apim.portal.config;
import com.eactive.apim.portal.apps.user.repository.PortalOrgRepository; import com.eactive.apim.portal.apps.user.repository.PortalOrgRepository;
import com.eactive.apim.portal.apps.user.service.PortalUserLogService; import com.eactive.apim.portal.apps.user.service.PortalUserLogService;
import com.eactive.apim.portal.common.util.HttpRequestUtil;
import com.eactive.apim.portal.common.util.StringRepeatUtil;
import com.eactive.apim.portal.invitation.entity.UserInvitation; import com.eactive.apim.portal.invitation.entity.UserInvitation;
import com.eactive.apim.portal.invitation.entity.UserInvitationEnums.InvitationStatus; import com.eactive.apim.portal.invitation.entity.UserInvitationEnums.InvitationStatus;
import com.eactive.apim.portal.invitation.repository.UserInvitationRepository; import com.eactive.apim.portal.invitation.repository.UserInvitationRepository;
@@ -15,6 +17,8 @@ import com.eactive.apim.portal.template.entity.MessageCode;
import com.eactive.apim.portal.template.entity.MessageRequest; import com.eactive.apim.portal.template.entity.MessageRequest;
import com.eactive.apim.portal.template.repository.MessageRequestRepository; import com.eactive.apim.portal.template.repository.MessageRequestRepository;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.security.core.Authentication; import org.springframework.security.core.Authentication;
import org.springframework.security.web.authentication.AuthenticationSuccessHandler; import org.springframework.security.web.authentication.AuthenticationSuccessHandler;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
@@ -26,6 +30,7 @@ import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession; import javax.servlet.http.HttpSession;
import java.io.IOException; import java.io.IOException;
import java.time.LocalDateTime; import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Optional; import java.util.Optional;
@@ -34,6 +39,9 @@ import java.util.Optional;
@RequiredArgsConstructor @RequiredArgsConstructor
public class PortalAuthenticationSuccessHandler implements AuthenticationSuccessHandler { public class PortalAuthenticationSuccessHandler implements AuthenticationSuccessHandler {
private static final Logger sessionLogger = LoggerFactory.getLogger("eapim.portal.session");
private static final DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss.SSS");
private final PortalUserRepository portalUserRepository; private final PortalUserRepository portalUserRepository;
private final PortalProperties portalProperties; private final PortalProperties portalProperties;
private final PortalUserLogService userLogService; private final PortalUserLogService userLogService;
@@ -104,6 +112,9 @@ public class PortalAuthenticationSuccessHandler implements AuthenticationSuccess
} }
} }
// 로그인 성공 시 세션 정보 로깅
logLoginSuccess(request, session, username);
String decisionToken = (String) request.getSession().getAttribute("decisionToken"); String decisionToken = (String) request.getSession().getAttribute("decisionToken");
if (decisionToken != null) { if (decisionToken != null) {
response.sendRedirect(contextPath + "/signup/decision_process"); response.sendRedirect(contextPath + "/signup/decision_process");
@@ -112,6 +123,31 @@ public class PortalAuthenticationSuccessHandler implements AuthenticationSuccess
} }
} }
private void logLoginSuccess(HttpServletRequest request, HttpSession session, String username) {
StringBuilder logMessage = new StringBuilder();
logMessage.append("\n");
logMessage.append(StringRepeatUtil.repeat('=', 80)).append("\n");
logMessage.append("USER LOGIN SUCCESS\n");
logMessage.append(StringRepeatUtil.repeat('=', 80)).append("\n");
logMessage.append("Username: ").append(username).append("\n");
logMessage.append("Session ID: ").append(session.getId()).append("\n");
logMessage.append("Login At: ").append(LocalDateTime.now().format(formatter)).append("\n");
logMessage.append("\n");
logMessage.append(StringRepeatUtil.repeat('-', 80)).append("\n");
logMessage.append("REQUEST INFORMATION\n");
logMessage.append(StringRepeatUtil.repeat('-', 80)).append("\n");
logMessage.append("Client IP Address: ").append(HttpRequestUtil.getClientIpAddress(request)).append("\n");
logMessage.append("Client Host: ").append(HttpRequestUtil.getClientHost(request)).append("\n");
logMessage.append("Is Proxied: ").append(HttpRequestUtil.isProxied(request)).append("\n");
logMessage.append("Remote Address (Direct): ").append(request.getRemoteAddr()).append("\n");
logMessage.append("Remote Host (Direct): ").append(request.getRemoteHost()).append("\n");
logMessage.append("Request URI: ").append(request.getRequestURI()).append("\n");
logMessage.append("User-Agent: ").append(request.getHeader("User-Agent")).append("\n");
logMessage.append(StringRepeatUtil.repeat('=', 80)).append("\n");
sessionLogger.info(logMessage.toString());
}
private boolean isPasswordChangeRequired(PortalUser user) { private boolean isPasswordChangeRequired(PortalUser user) {
// 가장 최근 비밀번호 변경 이력 조회 // 가장 최근 비밀번호 변경 이력 조회
Optional<UserPasswordHistory> latestHistory = passwordHistoryRepository Optional<UserPasswordHistory> latestHistory = passwordHistoryRepository
@@ -1,5 +1,6 @@
package com.eactive.apim.portal.config; package com.eactive.apim.portal.config;
import com.eactive.apim.portal.common.util.HttpRequestUtil;
import com.eactive.apim.portal.common.util.SecurityUtil; import com.eactive.apim.portal.common.util.SecurityUtil;
import org.aspectj.lang.JoinPoint; import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.annotation.Aspect;
@@ -29,7 +30,7 @@ public class PortalConfigLog {
String method = request.getMethod(); String method = request.getMethod();
String path = request.getRequestURI(); String path = request.getRequestURI();
String query = request.getQueryString(); String query = request.getQueryString();
String ip = request.getRemoteAddr(); String ip = HttpRequestUtil.getClientIpAddress(request);
String user = SecurityUtil.getCurrentLoginId(); String user = SecurityUtil.getCurrentLoginId();
@@ -31,13 +31,17 @@ public class PortalConfigSecurity {
private final PortalAuthenticationManager portalAuthenticationManager; private final PortalAuthenticationManager portalAuthenticationManager;
private final PortalLogoutSuccessHandler logoutSuccessHandler;
@Autowired @Autowired
public PortalConfigSecurity(PortalAuthenticationFailureHandler authenticationFailureHandler, public PortalConfigSecurity(PortalAuthenticationFailureHandler authenticationFailureHandler,
PortalAuthenticationSuccessHandler authenticationSuccessHandler, PortalAuthenticationSuccessHandler authenticationSuccessHandler,
PortalAuthenticationManager portalAuthenticationManager) { PortalAuthenticationManager portalAuthenticationManager,
PortalLogoutSuccessHandler logoutSuccessHandler) {
this.authenticationFailureHandler = authenticationFailureHandler; this.authenticationFailureHandler = authenticationFailureHandler;
this.authenticationSuccessHandler = authenticationSuccessHandler; this.authenticationSuccessHandler = authenticationSuccessHandler;
this.portalAuthenticationManager = portalAuthenticationManager; this.portalAuthenticationManager = portalAuthenticationManager;
this.logoutSuccessHandler = logoutSuccessHandler;
} }
@Bean @Bean
@@ -71,7 +75,7 @@ public class PortalConfigSecurity {
.successHandler(authenticationSuccessHandler)) .successHandler(authenticationSuccessHandler))
.logout(logout -> logout .logout(logout -> logout
.logoutRequestMatcher(new AntPathRequestMatcher("/actionLogout.do", "GET")) .logoutRequestMatcher(new AntPathRequestMatcher("/actionLogout.do", "GET"))
.logoutSuccessUrl("/")) .logoutSuccessHandler(logoutSuccessHandler))
.csrf(csrf -> csrf .csrf(csrf -> csrf
.csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse()) .csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse())
.ignoringRequestMatchers(new AntPathRequestMatcher("/_proxy/**/*")) .ignoringRequestMatchers(new AntPathRequestMatcher("/_proxy/**/*"))
@@ -0,0 +1,87 @@
package com.eactive.apim.portal.config;
import com.eactive.apim.portal.common.util.HttpRequestUtil;
import com.eactive.apim.portal.common.util.StringRepeatUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.security.core.Authentication;
import org.springframework.security.web.authentication.logout.LogoutSuccessHandler;
import org.springframework.stereotype.Component;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.io.IOException;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Enumeration;
/**
* 로그아웃 성공 시 세션 정보를 로깅하는 핸들러
*/
@Component
public class PortalLogoutSuccessHandler implements LogoutSuccessHandler {
private static final Logger sessionLogger = LoggerFactory.getLogger("eapim.portal.session");
private static final DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss.SSS");
@Override
public void onLogoutSuccess(HttpServletRequest request, HttpServletResponse response,
Authentication authentication) throws IOException, ServletException {
HttpSession session = request.getSession(false);
if (session != null) {
StringBuilder logMessage = new StringBuilder();
logMessage.append("\n");
logMessage.append(StringRepeatUtil.repeat('=', 80)).append("\n");
logMessage.append("USER LOGOUT\n");
logMessage.append(StringRepeatUtil.repeat('=', 80)).append("\n");
logMessage.append("Session ID: ").append(session.getId()).append("\n");
logMessage.append("Logout At: ").append(LocalDateTime.now().format(formatter)).append("\n");
if (authentication != null) {
logMessage.append("Username: ").append(authentication.getName()).append("\n");
logMessage.append("Authenticated: ").append(authentication.isAuthenticated()).append("\n");
}
logMessage.append("\n");
logMessage.append(StringRepeatUtil.repeat('-', 80)).append("\n");
logMessage.append("REQUEST INFORMATION\n");
logMessage.append(StringRepeatUtil.repeat('-', 80)).append("\n");
logMessage.append("Client IP Address: ").append(HttpRequestUtil.getClientIpAddress(request)).append("\n");
logMessage.append("Client Host: ").append(HttpRequestUtil.getClientHost(request)).append("\n");
logMessage.append("Is Proxied: ").append(HttpRequestUtil.isProxied(request)).append("\n");
logMessage.append("Remote Address (Direct): ").append(request.getRemoteAddr()).append("\n");
logMessage.append("Remote Host (Direct): ").append(request.getRemoteHost()).append("\n");
logMessage.append("Request URI: ").append(request.getRequestURI()).append("\n");
logMessage.append("User-Agent: ").append(request.getHeader("User-Agent")).append("\n");
logMessage.append("\n");
logMessage.append(StringRepeatUtil.repeat('-', 80)).append("\n");
logMessage.append("SESSION ATTRIBUTES (Before Invalidation)\n");
logMessage.append(StringRepeatUtil.repeat('-', 80)).append("\n");
try {
Enumeration<String> attributeNames = session.getAttributeNames();
while (attributeNames.hasMoreElements()) {
String attrName = attributeNames.nextElement();
Object attrValue = session.getAttribute(attrName);
String valueStr = attrValue != null ? attrValue.toString() : "null";
if (valueStr.length() > 100) {
valueStr = valueStr.substring(0, 97) + "...";
}
logMessage.append(String.format(" %-30s : %s\n", attrName, valueStr));
}
} catch (Exception e) {
logMessage.append(" Unable to retrieve session attributes\n");
}
logMessage.append(StringRepeatUtil.repeat('=', 80)).append("\n");
sessionLogger.info(logMessage.toString());
}
response.sendRedirect(request.getContextPath() + "/");
}
}
@@ -0,0 +1,134 @@
package com.eactive.apim.portal.config;
import com.eactive.apim.portal.common.util.HttpRequestUtil;
import com.eactive.apim.portal.common.util.StringRepeatUtil;
import lombok.extern.slf4j.Slf4j;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
import javax.servlet.http.HttpSessionEvent;
import javax.servlet.http.HttpSessionListener;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Enumeration;
/**
* HttpSession 생성 시 요청 헤더 정보를 로깅하는 리스너
*/
@Component
public class SessionLoggingListener implements HttpSessionListener {
private static final Logger sessionLogger = LoggerFactory.getLogger("eapim.portal.session");
private static final DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss.SSS");
@Override
public void sessionCreated(HttpSessionEvent se) {
HttpSession session = se.getSession();
// HttpServletRequest 가져오기
HttpServletRequest request = (HttpServletRequest) session.getAttribute("org.springframework.web.context.request.RequestContextListener.REQUEST_ATTRIBUTES");
// Spring의 RequestContextHolder를 통해 현재 요청 가져오기
try {
org.springframework.web.context.request.RequestAttributes requestAttributes =
org.springframework.web.context.request.RequestContextHolder.getRequestAttributes();
if (requestAttributes instanceof org.springframework.web.context.request.ServletRequestAttributes) {
request = ((org.springframework.web.context.request.ServletRequestAttributes) requestAttributes).getRequest();
}
} catch (Exception e) {
// RequestContextHolder를 통해 요청을 가져올 수 없는 경우 무시
}
StringBuilder logMessage = new StringBuilder();
logMessage.append("\n");
logMessage.append(StringRepeatUtil.repeat('=', 80)).append("\n");
logMessage.append("NEW HTTP SESSION CREATED\n");
logMessage.append(StringRepeatUtil.repeat('=', 80)).append("\n");
logMessage.append("Session ID: ").append(session.getId()).append("\n");
logMessage.append("Created At: ").append(LocalDateTime.now().format(formatter)).append("\n");
logMessage.append("Max Inactive Interval: ").append(session.getMaxInactiveInterval()).append(" seconds\n");
if (request != null) {
logMessage.append("\n");
logMessage.append(StringRepeatUtil.repeat('-', 80)).append("\n");
logMessage.append("REQUEST INFORMATION\n");
logMessage.append(StringRepeatUtil.repeat('-', 80)).append("\n");
logMessage.append("Client IP Address: ").append(HttpRequestUtil.getClientIpAddress(request)).append("\n");
logMessage.append("Client Host: ").append(HttpRequestUtil.getClientHost(request)).append("\n");
logMessage.append("Is Proxied: ").append(HttpRequestUtil.isProxied(request)).append("\n");
logMessage.append("Remote Address (Direct): ").append(request.getRemoteAddr()).append("\n");
logMessage.append("Remote Host (Direct): ").append(request.getRemoteHost()).append("\n");
logMessage.append("Remote Port: ").append(request.getRemotePort()).append("\n");
logMessage.append("Request Method: ").append(request.getMethod()).append("\n");
logMessage.append("Request URI: ").append(request.getRequestURI()).append("\n");
logMessage.append("Request URL: ").append(request.getRequestURL()).append("\n");
logMessage.append("Query String: ").append(request.getQueryString()).append("\n");
logMessage.append("Protocol: ").append(request.getProtocol()).append("\n");
logMessage.append("Scheme: ").append(request.getScheme()).append("\n");
logMessage.append("Server Name: ").append(request.getServerName()).append("\n");
logMessage.append("Server Port: ").append(request.getServerPort()).append("\n");
logMessage.append("Context Path: ").append(request.getContextPath()).append("\n");
logMessage.append("\n");
logMessage.append(StringRepeatUtil.repeat('-', 80)).append("\n");
logMessage.append("REQUEST HEADERS\n");
logMessage.append(StringRepeatUtil.repeat('-', 80)).append("\n");
Enumeration<String> headerNames = request.getHeaderNames();
while (headerNames.hasMoreElements()) {
String headerName = headerNames.nextElement();
Enumeration<String> headerValues = request.getHeaders(headerName);
while (headerValues.hasMoreElements()) {
String headerValue = headerValues.nextElement();
logMessage.append(String.format(" %-30s : %s\n", headerName, headerValue));
}
}
} else {
logMessage.append("\n");
logMessage.append("WARNING: HttpServletRequest not available\n");
}
logMessage.append(StringRepeatUtil.repeat('=', 80)).append("\n");
sessionLogger.info(logMessage.toString());
}
@Override
public void sessionDestroyed(HttpSessionEvent se) {
HttpSession session = se.getSession();
StringBuilder logMessage = new StringBuilder();
logMessage.append("\n");
logMessage.append(StringRepeatUtil.repeat('=', 80)).append("\n");
logMessage.append("HTTP SESSION DESTROYED\n");
logMessage.append(StringRepeatUtil.repeat('=', 80)).append("\n");
logMessage.append("Session ID: ").append(session.getId()).append("\n");
logMessage.append("Destroyed At: ").append(LocalDateTime.now().format(formatter)).append("\n");
logMessage.append("Max Inactive Interval: ").append(session.getMaxInactiveInterval()).append(" seconds\n");
// 세션 속성 정보 로깅
try {
logMessage.append("\n");
logMessage.append(StringRepeatUtil.repeat('-', 80)).append("\n");
logMessage.append("SESSION ATTRIBUTES\n");
logMessage.append(StringRepeatUtil.repeat('-', 80)).append("\n");
java.util.Enumeration<String> attributeNames = session.getAttributeNames();
while (attributeNames.hasMoreElements()) {
String attrName = attributeNames.nextElement();
Object attrValue = session.getAttribute(attrName);
logMessage.append(String.format(" %-30s : %s\n", attrName, attrValue));
}
} catch (Exception e) {
logMessage.append(" Unable to retrieve session attributes\n");
}
logMessage.append(StringRepeatUtil.repeat('=', 80)).append("\n");
sessionLogger.info(logMessage.toString());
}
}
+15
View File
@@ -46,6 +46,17 @@
</encoder> </encoder>
</appender> </appender>
<appender name="HTTP_SESSION" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>${LOG_PATH}/http-session.log</file>
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<fileNamePattern>${LOG_PATH}/backup/http-session.%d{yyyy-MM-dd}.log</fileNamePattern>
<maxHistory>30</maxHistory>
</rollingPolicy>
<encoder>
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level - %msg%n</pattern>
</encoder>
</appender>
<root level="DEBUG"> <root level="DEBUG">
<appender-ref ref="FILE"/> <appender-ref ref="FILE"/>
@@ -79,4 +90,8 @@
<logger name="com.atomikos" level="DEBUG" additivity="false"> <logger name="com.atomikos" level="DEBUG" additivity="false">
<appender-ref ref="FILE_HIBERNATE" /> <appender-ref ref="FILE_HIBERNATE" />
</logger> </logger>
<logger name="eapim.portal.session" level="INFO" additivity="false">
<appender-ref ref="HTTP_SESSION" />
</logger>
</configuration> </configuration>
+15
View File
@@ -30,6 +30,17 @@
</encoder> </encoder>
</appender> </appender>
<appender name="HTTP_SESSION" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>${LOG_PATH}/http-session.log</file>
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<fileNamePattern>${LOG_PATH}/backup/http-session.%d{yyyy-MM-dd}.log</fileNamePattern>
<maxHistory>30</maxHistory>
</rollingPolicy>
<encoder>
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level - %msg%n</pattern>
</encoder>
</appender>
@@ -65,4 +76,8 @@
<logger name="com.atomikos" level="DEBUG" additivity="false"> <logger name="com.atomikos" level="DEBUG" additivity="false">
<appender-ref ref="FILE_HIBERNATE" /> <appender-ref ref="FILE_HIBERNATE" />
</logger> </logger>
<logger name="eapim.portal.session" level="INFO" additivity="false">
<appender-ref ref="HTTP_SESSION" />
</logger>
</configuration> </configuration>
+15
View File
@@ -38,6 +38,17 @@
</encoder> </encoder>
</appender> </appender>
<appender name="HTTP_SESSION" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>${LOG_PATH}/http-session.log</file>
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<fileNamePattern>${LOG_PATH}/backup/http-session.%d{yyyy-MM-dd}.log</fileNamePattern>
<maxHistory>30</maxHistory>
</rollingPolicy>
<encoder>
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level - %msg%n</pattern>
</encoder>
</appender>
<root level="INFO"> <root level="INFO">
<appender-ref ref="FILE"/> <appender-ref ref="FILE"/>
@@ -79,4 +90,8 @@
<appender-ref ref="FILE_REPORT" /> <appender-ref ref="FILE_REPORT" />
</logger> </logger>
<logger name="eapim.portal.session" level="INFO" additivity="false">
<appender-ref ref="HTTP_SESSION" />
</logger>
</configuration> </configuration>
+15
View File
@@ -46,6 +46,17 @@
</encoder> </encoder>
</appender> </appender>
<appender name="HTTP_SESSION" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>${LOG_PATH}/http-session.log</file>
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<fileNamePattern>${LOG_PATH}/backup/http-session.%d{yyyy-MM-dd}.log</fileNamePattern>
<maxHistory>30</maxHistory>
</rollingPolicy>
<encoder>
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level - %msg%n</pattern>
</encoder>
</appender>
<appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender"> <appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
<encoder><Pattern>${CONSOLE_PATTERN}</Pattern></encoder> <encoder><Pattern>${CONSOLE_PATTERN}</Pattern></encoder>
</appender> </appender>
@@ -55,6 +66,10 @@
<appender-ref ref="NEED_FIX" /> <appender-ref ref="NEED_FIX" />
</logger> </logger>
<logger name="eapim.portal.session" level="INFO" additivity="false">
<appender-ref ref="HTTP_SESSION" />
</logger>
<root level="INFO"> <root level="INFO">
<appender-ref ref="ROLLING"/> <appender-ref ref="ROLLING"/>