티스토리 뷰
작년 입사 후 얼마 지나지 않아서 로그 파이프라인을 구성했었다.
2023.05.28 - [개발/SPRING] - 스프링부트 서비스에 LOG 남기기 (with. Logback)
당시에는 요청에 대한 로그가 없어서 급하게 구축하게 됐는데,
지금 생각해보면 입사한지 한달도 되지 않은 개발자가 로그 파이프라인을 구성한다는 자체가 말이 좀 안되는 일이긴했다.
그래서 로그 파이프라인에 구멍이 조금씩 있었는데, 최근에 가장 큰 구멍을 알게되서 개선이 필요했다.
바로 Multipart/form-data 형식에서 MultipartFile에 대한 처리가 없어서, 어떤 파일이 업로드가 되었는지 알 수 없었다.
그런데, 현재 담당하고 있는 서비스가 파일 업로드를 지원하기 때문에 로그의 개선을 필요로 했다.
로그를 몇 번 개선하면서, 현재 로그는 AOP에서 처리하게 구성했다.
2023.07.10 - [개발/SPRING] - 스프링부트 AOP를 이용해 로깅 처리하기
위 글에도 남겨놨듯이 이슈는 인지는 하고 있었다. 당시에 처리를 하지 못했을 뿐.
구축 당시에 비해 도메인 지식 & 스프링에 대해서 조금 더 알게되면서 문제를 개선할 수 있게 됐다.
MultipartFile의 정보를 얻어오기 위해서는 두 가지 방법이 있을 것 같다.
1. AOP의 JointPoint 이용하기
2. MultipartResolver로 HttpServletRequest를 MultipartHttpServletRequest로 변환
1번이 조금 더 간단하고 현재 로그 파이프라인에 맞기 때문에 1번을 채택했지만,
이번 포스팅에서는 두 가지 방법을 모두 정리해보려고 한다.
1. AOP의 JointPoint 이용하기
초창기에는 Controller에 LogMessageManager라는 객체를 주입받아 모든 요청마다 setLogMessage 매서드를 붙였다.
이 방식이 너무 불편해서, 현재는 AOP를 이용해 Controller에서 Return이 발생할 때마다 로그를 남기도록 만들어 놨다.
AOP의 파라미터 중 JointPoint를 이용하면 Contoller의 요청 객체의 정보를 가져올 수 있다.
@AfterReturning(pointcut = "execution([Controller 포인트컷 위치 지정])", returning = "result")
public void loggingAspect(JoinPoint joinPoint, Object result) {
Object[] objectArgs = joinPoint.getArgs();
List<MultipartFileLogVo> multipartFileLogVoList = new ArrayList<>();
for (Object arg : objectArgs) {
if (arg instanceof MultipartFile) {
MultipartFile file = (MultipartFile) arg;
...
} else if (arg instanceof MultipartFile[]) {
MultipartFile[] files = (MultipartFile[]) arg;
for (MultipartFile file : files) {
...
}
} else {
...
}
}
logMessageManager.setRequestLogMessage(result, multipartFileLogVoList);
}
실제 코드에 적용된 방식은 조금 다르긴한데, JoinPoint에서 요청 객체에 MultipartFile이 포함 될 경우 파일에 대한 정보를 가져오면된다.
파일 크기부터 이름까지 파일에 대한 모든 정보가 그대로 담겨있기 때문에 파일 정보를 로그에 남기면 된다.
요청객체 objectArgs를 깠을 때 MultipartFile이 Array인 경우가 있는데, 이건 파일을 여러개 보내는 경우 위와 같이 처리된다.
2. MultipartResolver로 HttpServletRequest를 MultipartHttpServletRequest로 변환
AOP를 잘 모르겠다면 이 방법이 더 쉽다.
private final HttpServletRequest httpServletRequest;
...
WebApplicationContext webApplicationContext = WebApplicationContextUtils.getWebApplicationContext(httpServletRequest.getServletContext());
MultipartResolver multipartResolver = webApplicationContext.getBean(MultipartResolver.class);
MultipartHttpServletRequest multipartHttpServletRequest = multipartResolver.resolveMultipart(httpServletRequest);
Map<String, MultipartFile> multipartFileMap = multipartHttpServletRequest.getFileMap();
for(String key : multipartFileMap.keySet()) {
MultipartFile multipartFile = multipartFileMap.get(key);
System.out.println(multipartFile.getOriginalFilename());
System.out.println(multipartFile.getSize());
}
모든 요청에 대한 정보는 HttpServletRequest가 다 담고 있다.
당연히, Multipart/form-data에 대한 정보도 다 가지고 있는데, 그냥 사용할 수 없다.
MultipartResolver로 HttpServletRequest를 MultipartHttpServletRequest로 변환해줘야 MultipartFile에 대한 정보를 가져올 수 있다.
이 방법을 좀 늦게 알았는데, 이전 코드가 조금 복잡하게 구성되어있어 이 방식으로 리뉴얼할 예정이다.
최종적으로는 아래와 같이 구성된다.
{
"@timestamp": "2024-02-10T10:56:30.248Z",
"message": "LOG",
"logger_name": "...",
"level": "INFO",
"code": "20000",
"method": "POST",
"parameter": "{\"multipart-files\":[{\"fileName\":\"가정통신문.hwp\",\"fileSize\":\"1.0MB\"}]}",
"id": "...",
"url": "..."
}
마치며
글은 간단하게 썼는데, 현재 코드에 여러가지 함정들이 깔려있어서 굉장히 당황스러웠다.
결국 문제는 HttpServletRequest에서 MultipartFIle 형식을 가져오는 법을 알지 못해서 생긴 문제였고,
일단은 잘 나오는 상태다.
이번에 좀 크게 만져놔서 한동안은 괜찮지 않을까 싶다.
'개발 > SPRING' 카테고리의 다른 글
OpenFeign 간단 사용법과 FeignException 핸들링하기 (0) | 2024.03.22 |
---|---|
Google Document Translation API 사용하기 (with. Spring Boot) (1) | 2024.02.20 |
SpringBoot에서 Google Indexing API 사용하기 2 - Batch 사용하기 (1) | 2024.02.07 |
스프링부트에서 상태 검사(health check)하기 (0) | 2024.01.26 |
API 문서화 : Kotlin + Open API 3 + Swagger-ui 사용하기(springdoc-openapi v2.x.x) (0) | 2024.01.20 |
- Total
- Today
- Yesterday
- cache
- MySQL
- AWS EC2
- 티스토리챌린지
- 후쿠오카
- GIT
- docker
- elasticsearch
- Log
- openAI API
- AOP
- OpenAI
- AWS
- CloudFront
- EKS
- 오블완
- springboot
- ChatGPT
- Elastic cloud
- Kotlin
- OpenFeign
- 람다
- terraform
- 스프링부트
- java
- Spring
- S3
- lambda
- JWT
- serverless
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | |||||
3 | 4 | 5 | 6 | 7 | 8 | 9 |
10 | 11 | 12 | 13 | 14 | 15 | 16 |
17 | 18 | 19 | 20 | 21 | 22 | 23 |
24 | 25 | 26 | 27 | 28 | 29 | 30 |