Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
bc48bce
feat : 필터 설정 #289
PicturePark1101 Jan 23, 2025
2de5732
feat : 로깅 출력 클래스 생성 #289
PicturePark1101 Jan 23, 2025
32a3919
feat : 로그 생성 클래스 생성 #289
PicturePark1101 Jan 23, 2025
c8267fa
feat : 필터 설정 추가 #289
PicturePark1101 Jan 23, 2025
ddc0df9
feat : 로그 팩토리 생성 #289
PicturePark1101 Jan 23, 2025
feaf5f6
feat : MDC에 userId 넣는 로직 추가 #289
PicturePark1101 Jan 23, 2025
7645cf6
feat : 필터 구현 완료 #290
PicturePark1101 Jan 24, 2025
47b0984
feat : 필터 로깅 설정 추가 #290
PicturePark1101 Jan 24, 2025
4f42a37
feat : 필터 생성 관련 로직 완료 #289
PicturePark1101 Jan 24, 2025
27dc3f5
feat : MDC 생성 로직 묶음 #289
PicturePark1101 Jan 24, 2025
ee80961
feat : 커스텀ServletRequest 생성 #289
PicturePark1101 Jan 24, 2025
68b1c31
refactor : 불필요한 어노테이션 제거 #289
PicturePark1101 Jan 24, 2025
33e83a3
Merge pull request #293 from Juinjang/feat/289
PicturePark1101 Jan 24, 2025
ce3cdbc
fix : 필터 설정 변경 #289
PicturePark1101 Jan 24, 2025
8ae1a74
fix : 프로메테우스 관련 요청은 로그로 수집하지 않도록 변경 #289
PicturePark1101 Jan 24, 2025
1e9ac00
fix : 프로메테우스 관련 요청은 로그로 수집하지 않도록 변경 #289
PicturePark1101 Jan 24, 2025
ae42bb5
Merge pull request #294 from Juinjang/feat/289
PicturePark1101 Jan 24, 2025
95386b9
fix : 필터에서 특정 요청 url 거르도록 변경 #289
PicturePark1101 Jan 24, 2025
4f2991e
Merge pull request #295 from Juinjang/feat/289
PicturePark1101 Jan 24, 2025
aca8f2b
fix: record Delete API
ihyeon02 Feb 6, 2025
6f50e1c
[fix/#297]: record Delete API
2hy2on Feb 6, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view

This file was deleted.

27 changes: 27 additions & 0 deletions src/main/java/umc/th/juinjang/config/ApiFilterConfig.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package umc.th.juinjang.config;

import java.util.List;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.Ordered;
import umc.th.juinjang.controller.monitoring.APILoggerFilter;

@Configuration
@Slf4j
public class ApiFilterConfig {

@Value("${logging.api.excluded-paths}")
private List<String> excludedUrls;

@Bean
public FilterRegistrationBean<APILoggerFilter> loggingFilter() {
FilterRegistrationBean<APILoggerFilter> registrationBean = new FilterRegistrationBean<>();
registrationBean.setFilter(new APILoggerFilter(excludedUrls));
registrationBean.setOrder(Ordered.HIGHEST_PRECEDENCE); // 순서 설정
registrationBean.setUrlPatterns(List.of("/*"));
return registrationBean;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
package umc.th.juinjang.controller.monitoring;

import static umc.th.juinjang.utils.LoggerProvider.getLogger;
import static umc.th.juinjang.utils.LoggerProvider.registerRequestId;

import jakarta.servlet.FilterChain;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import java.util.List;
import java.util.UUID;
import lombok.extern.slf4j.Slf4j;
import org.slf4j.Logger;
import org.slf4j.MDC;
import org.springframework.util.AntPathMatcher;
import org.springframework.web.filter.OncePerRequestFilter;
import org.springframework.web.util.ContentCachingResponseWrapper;

@Slf4j
public class APILoggerFilter extends OncePerRequestFilter {

private final APILoggerPrinter apiLoggerPrinter = new APILoggerPrinter();
private static final Logger logger = getLogger(APILoggerFilter.class);
private final AntPathMatcher pathMatcher = new AntPathMatcher();
private final List<String> EXCLUDED_URLS;

public APILoggerFilter(List<String> EXCLUDED_URLS) {
this.EXCLUDED_URLS = EXCLUDED_URLS;
}

@Override
protected void doFilterInternal(HttpServletRequest servletRequest, HttpServletResponse servletResponse, FilterChain chain ) {
CustomContentCachingHttpRequestWrapper requestWrapper = new CustomContentCachingHttpRequestWrapper(servletRequest);
ContentCachingResponseWrapper responseWrapper = new ContentCachingResponseWrapper(servletResponse);
registerRequestId(UUID.randomUUID().toString());

try {
if (shouldNotFilter(requestWrapper)) {
chain.doFilter(requestWrapper, responseWrapper);
return;
}
apiLoggerPrinter.print(new APIRequestLoggerGenerator(requestWrapper));
chain.doFilter(requestWrapper, responseWrapper);
apiLoggerPrinter.print(new APIResponseLoggerGenerator(responseWrapper));
responseWrapper.copyBodyToResponse();
} catch (Exception e) {
logger.error("APILogger 필터 오류");
} finally {
MDC.clear();
}
}

@Override
protected boolean shouldNotFilter(HttpServletRequest request) {
return EXCLUDED_URLS.stream().anyMatch(pattern -> pathMatcher.match(pattern, request.getRequestURI()));
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
package umc.th.juinjang.controller.monitoring;

import static umc.th.juinjang.utils.LoggerProvider.getLogger;

import org.slf4j.Logger;
import org.slf4j.MDC;

public abstract class APILoggerGenerator {

protected static final Logger logger = getLogger(APILoggerGenerator.class);

public APILoggerGenerator() {
}

protected StringBuilder getBaseLogInfo() {
StringBuilder logBuilder = new StringBuilder();
logBuilder.append("[request_id] ").append(MDC.get("request_id")).append(" ");
return logBuilder;
}

abstract public String generateLog();

abstract protected String getBody(byte[] info);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package umc.th.juinjang.controller.monitoring;

import static umc.th.juinjang.utils.LoggerProvider.getLogger;

import java.util.List;
import org.slf4j.Logger;
import org.springframework.stereotype.Component;

@Component
public class APILoggerPrinter {
private static final Logger logger = getLogger(APILoggerPrinter.class);

public APILoggerPrinter() {
}

public void print(APILoggerGenerator apiLoggerGenerator) {
logger.info(apiLoggerGenerator.generateLog());
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
package umc.th.juinjang.controller.monitoring;

import jakarta.servlet.http.HttpServletRequest;
import java.nio.charset.StandardCharsets;
import java.util.Collections;
import java.util.stream.Collectors;

public class APIRequestLoggerGenerator extends APILoggerGenerator{

private final CustomContentCachingHttpRequestWrapper request;

public APIRequestLoggerGenerator(CustomContentCachingHttpRequestWrapper request) {
this.request = request;
}

@Override
public String generateLog() {
StringBuilder logBuilder = new StringBuilder();

logBuilder.append("Request : ").append(" ");
logBuilder.append(getBaseLogInfo());
logBuilder.append("[method] ").append(request.getMethod()).append(" ");
logBuilder.append("[uri] ").append(getQuery()).append(" ");
logBuilder.append("[headers] ").append(getHeadersAsString(request)).append(" ");
logBuilder.append("[requestBody] ").append(getBody(request.getCachedBody())).append(" ");

return logBuilder.toString();
}

private String getQuery() {
String uri = request.getRequestURI();
String queryString = request.getQueryString();

if (queryString != null) {
uri += "?" + queryString;
}
return uri;
}

private String getHeadersAsString(HttpServletRequest request) {
return Collections.list(request.getHeaderNames()).stream()
.filter(headerName -> !headerName.equalsIgnoreCase("Authorization"))
.filter(headerName -> !headerName.equalsIgnoreCase("refresh-token"))
.map(headerName -> headerName + "=" + request.getHeader(headerName))
.collect(Collectors.joining(", "));
}

protected String getBody(byte[] info) {
return new String(info, StandardCharsets.UTF_8).replace("\n", "").replace("\r", "");
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
package umc.th.juinjang.controller.monitoring;

import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import java.nio.charset.StandardCharsets;
import org.springframework.web.util.ContentCachingResponseWrapper;

public class APIResponseLoggerGenerator extends APILoggerGenerator {
private final ContentCachingResponseWrapper response;

public APIResponseLoggerGenerator(ContentCachingResponseWrapper response) {
this.response = response;
}

@Override
public String generateLog() {
StringBuilder logBuilder = new StringBuilder();

logBuilder.append("Response : ").append(" ");
logBuilder.append(getBaseLogInfo());
logBuilder.append("[status] ").append(response.getStatus()).append(" ");
logBuilder.append("[responseBody] ").append(getBody(response.getContentAsByteArray())).append(" ");

return logBuilder.toString();
}

protected String getBody(byte[] info) {
String responseBody = "";
try {
ObjectMapper objectMapper = new ObjectMapper();
JsonNode rootNode = objectMapper.readTree(new String(info, StandardCharsets.UTF_8));
responseBody = replaceToken(rootNode.path("message").asText("N/A"));
} catch (Exception e) {
logger.error("responseBody 추출 오류");
}
return responseBody;
}

private String replaceToken(String responseBody) {
return responseBody.replaceAll("\"accessToken\":\"[^\"]*\"", "\"accessToken\":\"[TOKEN]\"")
.replaceAll("\"refreshToken\":\"[^\"]*\"", "\"refreshToken\":\"[TOKEN]\"");
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
package umc.th.juinjang.controller.monitoring;

import static umc.th.juinjang.utils.LoggerProvider.getLogger;

import jakarta.servlet.ReadListener;
import jakarta.servlet.ServletInputStream;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletRequestWrapper;
import java.io.ByteArrayInputStream;
import org.slf4j.Logger;

public class CustomContentCachingHttpRequestWrapper extends HttpServletRequestWrapper {

private final Logger logger = getLogger(CustomContentCachingHttpRequestWrapper.class);
private final byte[] cachedBody;

public CustomContentCachingHttpRequestWrapper(HttpServletRequest request) {
super(request);
byte[] tempBody = new byte[0];
try {
tempBody = request.getInputStream().readAllBytes();
} catch (Exception e) {
logger.error("CustomContentCachingHttpRequestWrapper init error {}", e.getMessage());
} finally {
this.cachedBody = tempBody;
}
}

@Override
public ServletInputStream getInputStream() {
ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(cachedBody);
return new ServletInputStream() {
@Override
public int read() {
return byteArrayInputStream.read();
}

@Override
public boolean isFinished() {
return byteArrayInputStream.available() <= 0;
}

@Override
public boolean isReady() {
return true;
}

@Override
public void setReadListener(ReadListener readListener) {
}
};
}

public byte[] getCachedBody() {
return this.cachedBody;
}
}
25 changes: 17 additions & 8 deletions src/main/java/umc/th/juinjang/service/auth/JwtService.java
Original file line number Diff line number Diff line change
@@ -1,15 +1,28 @@
package umc.th.juinjang.service.auth;

import static umc.th.juinjang.utils.LoggerProvider.registerUserId;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import io.jsonwebtoken.*;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Header;
import io.jsonwebtoken.Jws;
import io.jsonwebtoken.JwtException;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import jakarta.servlet.http.HttpServletRequest;
import java.nio.charset.StandardCharsets;
import java.security.PublicKey;
import java.util.Base64;
import java.util.Date;
import java.util.Map;
import lombok.RequiredArgsConstructor;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.slf4j.MDC;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.apache.commons.lang3.StringUtils;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.userdetails.UserDetails;
Expand All @@ -22,12 +35,7 @@
import umc.th.juinjang.model.dto.auth.apple.AppleInfo;
import umc.th.juinjang.repository.limjang.MemberRepository;
import umc.th.juinjang.utils.ApplePublicKeyGenerator;

import java.nio.charset.StandardCharsets;
import java.security.PublicKey;
import java.util.Base64;
import java.util.Date;
import java.util.Map;
import umc.th.juinjang.utils.LoggerProvider;

@Service
@RequiredArgsConstructor
Expand Down Expand Up @@ -130,6 +138,7 @@ public Authentication getAuthentication(String token) {
System.out.println(this.getMemberIdFromJwtToken(token));

UserDetails userDetails = userDetailService.loadUserByUsername(this.getMemberIdFromJwtToken(token).toString());
registerUserId(String.valueOf(this.getMemberIdFromJwtToken(token)));
return new UsernamePasswordAuthenticationToken(userDetails, token, userDetails.getAuthorities());
}

Expand Down
Loading