diff --git a/stempo-auth/src/main/java/com/stempo/config/SecurityConfig.java b/stempo-auth/src/main/java/com/stempo/config/SecurityConfig.java index 43466ee..d6566ed 100644 --- a/stempo-auth/src/main/java/com/stempo/config/SecurityConfig.java +++ b/stempo-auth/src/main/java/com/stempo/config/SecurityConfig.java @@ -3,6 +3,7 @@ import com.stempo.application.JwtTokenService; import com.stempo.filter.CustomBasicAuthenticationFilter; import com.stempo.filter.JwtAuthenticationFilter; +import com.stempo.filter.MDCFilter; import com.stempo.util.ApiLogger; import com.stempo.util.HttpReqResUtils; import com.stempo.util.IpWhitelistValidator; @@ -37,6 +38,7 @@ public class SecurityConfig { .AuthorizationManagerRequestMatcherRegistry> authorizeHttpRequestsCustomizer; private final JwtTokenService tokenService; private final IpWhitelistValidator ipWhitelistValidator; + private final MDCFilter mdcFilter; @Bean public SecurityFilterChain filterChain(HttpSecurity http) throws Exception { @@ -48,6 +50,10 @@ public SecurityFilterChain filterChain(HttpSecurity http) throws Exception { .authorizeHttpRequests( authorizeHttpRequestsCustomizer ) + .addFilterBefore( + mdcFilter, + UsernamePasswordAuthenticationFilter.class + ) .addFilterBefore( new CustomBasicAuthenticationFilter(authenticationManager, ipWhitelistValidator), UsernamePasswordAuthenticationFilter.class diff --git a/stempo-auth/src/main/java/com/stempo/filter/MDCFilter.java b/stempo-auth/src/main/java/com/stempo/filter/MDCFilter.java new file mode 100644 index 0000000..7d95fdb --- /dev/null +++ b/stempo-auth/src/main/java/com/stempo/filter/MDCFilter.java @@ -0,0 +1,40 @@ +package com.stempo.filter; + +import jakarta.servlet.Filter; +import jakarta.servlet.FilterChain; +import jakarta.servlet.ServletException; +import jakarta.servlet.ServletRequest; +import jakarta.servlet.ServletResponse; +import jakarta.servlet.http.HttpServletRequest; +import java.io.IOException; +import java.util.UUID; +import org.slf4j.MDC; +import org.springframework.stereotype.Component; + +@Component +public class MDCFilter implements Filter { + + @Override + public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) + throws IOException, ServletException { + + HttpServletRequest httpRequest = (HttpServletRequest) request; + try { + String transactionId = httpRequest.getHeader("X-Transaction-Id"); + if (transactionId == null || transactionId.isEmpty()) { + transactionId = UUID.randomUUID().toString(); + } + MDC.put("transactionId", transactionId); + + String requestId = httpRequest.getHeader("X-Request-Id"); + if (requestId == null || requestId.isEmpty()) { + requestId = UUID.randomUUID().toString(); + } + MDC.put("requestId", requestId); + + chain.doFilter(request, response); + } finally { + MDC.clear(); + } + } +} diff --git a/stempo-common/src/main/java/com/stempo/util/ApiLogger.java b/stempo-common/src/main/java/com/stempo/util/ApiLogger.java index 6ddabe0..6737295 100644 --- a/stempo-common/src/main/java/com/stempo/util/ApiLogger.java +++ b/stempo-common/src/main/java/com/stempo/util/ApiLogger.java @@ -3,6 +3,7 @@ import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletResponse; import lombok.extern.slf4j.Slf4j; +import org.slf4j.MDC; import org.springframework.security.core.Authentication; import org.springframework.security.core.context.SecurityContextHolder; import org.springframework.stereotype.Component; @@ -14,44 +15,96 @@ public class ApiLogger { private ApiLogger() { } - public static void logRequest(HttpServletRequest request, HttpServletResponse response, String clientIpAddress, - String message) { + public static void logRequest(HttpServletRequest request, HttpServletResponse response, + String clientIpAddress, String message) { Authentication authentication = SecurityContextHolder.getContext().getAuthentication(); - String id = - (authentication == null || authentication.getName() == null) ? "anonymous" : authentication.getName(); + String userId = (authentication == null || authentication.getName() == null) + ? "anonymous" : authentication.getName(); String requestUrl = request.getRequestURI(); String queryString = request.getQueryString(); - String fullUrl = queryString == null ? requestUrl : requestUrl + "?" + queryString; - + if (queryString != null) { + requestUrl += "?" + queryString; + } String httpMethod = request.getMethod(); int httpStatus = response.getStatus(); - log.info("[{}:{}] {} {} {} {}", clientIpAddress, id, fullUrl, httpMethod, httpStatus, message); + String userAgent = request.getHeader("User-Agent"); + String serviceName = "stempo-core"; + String env = System.getProperty("spring.profiles.active", "default"); + + MDC.put("clientIp", clientIpAddress); + MDC.put("userId", userId); + MDC.put("requestUrl", requestUrl); + MDC.put("httpMethod", httpMethod); + MDC.put("httpStatus", String.valueOf(httpStatus)); + if (userAgent != null) { + MDC.put("userAgent", userAgent); + } + MDC.put("serviceName", serviceName); + MDC.put("env", env); + + log.info(message); + + MDC.remove("clientIp"); + MDC.remove("userId"); + MDC.remove("requestUrl"); + MDC.remove("httpMethod"); + MDC.remove("httpStatus"); + MDC.remove("userAgent"); + MDC.remove("serviceName"); + MDC.remove("env"); } public static void logRequestDuration(HttpServletRequest request, HttpServletResponse response, Exception ex) { Authentication authentication = SecurityContextHolder.getContext().getAuthentication(); - String id = - (authentication == null || authentication.getName() == null) ? "anonymous" : authentication.getName(); - String clientIpAddress = HttpReqResUtils.getClientIpAddressIfServletRequestExist(); + String userId = (authentication == null || authentication.getName() == null) + ? "anonymous" : authentication.getName(); + String clientIpAddress = HttpReqResUtils.getClientIpAddressIfServletRequestExist(); String requestUrl = request.getRequestURI(); String queryString = request.getQueryString(); - String fullUrl = queryString == null ? requestUrl : requestUrl + "?" + queryString; - + if (queryString != null) { + requestUrl += "?" + queryString; + } String httpMethod = request.getMethod(); int httpStatus = response.getStatus(); long startTime = (Long) request.getAttribute("startTime"); - long endTime = TimeUtils.currentTimeMillis(); - long duration = endTime - startTime; + long duration = System.currentTimeMillis() - startTime; + + String userAgent = request.getHeader("User-Agent"); + String serviceName = "stempo-core"; + String env = System.getProperty("spring.profiles.active", "default"); + + MDC.put("clientIp", clientIpAddress); + MDC.put("userId", userId); + MDC.put("requestUrl", requestUrl); + MDC.put("httpMethod", httpMethod); + MDC.put("httpStatus", String.valueOf(httpStatus)); + MDC.put("durationMs", String.valueOf(duration)); + if (userAgent != null) { + MDC.put("userAgent", userAgent); + } + MDC.put("serviceName", serviceName); + MDC.put("env", env); if (ex == null) { - log.info("[{}:{}] {} {} {} {}ms", clientIpAddress, id, fullUrl, httpMethod, httpStatus, duration); + log.info("Request completed successfully"); } else { - log.error("[{}:{}] {} {} {} {}ms, Exception: {}", clientIpAddress, id, fullUrl, httpMethod, httpStatus, - duration, ex.getMessage()); + MDC.put("exception", ex.getMessage()); + log.error("Request completed with error"); + MDC.remove("exception"); } + + MDC.remove("clientIp"); + MDC.remove("userId"); + MDC.remove("requestUrl"); + MDC.remove("httpMethod"); + MDC.remove("httpStatus"); + MDC.remove("durationMs"); + MDC.remove("userAgent"); + MDC.remove("serviceName"); + MDC.remove("env"); } }