문제의 발생 새로운 프로젝트를 시작하면서, 로그를 다시 붙여야할 일이 생겼다. 기존 프로젝트에 로그를 개발하면서 했던 파이프라인을 그대로 가져와서 붙여넣었는데, POST 요청에서 이상하게 동작하지 않았다. 원인을 분석하면서 생긴 일을 정리해보려고 한다. 우선 현재 시스템에서 로그를 어떻게 찍는지 간단히 정리해보고 가자. 1. Controller에서 API 요청을 받아서 서비스로직까지 처리한 후 return 2. 이 return 할 때 AOP AfterReturning을 통해 캐치 3. 이때 발생하는 return object와 요청 정보를 담고 있는 HttpServletRequest을 통해서 로그를 생성 이 과정 중 3번에서 문제가 발생했다. 사실 스프링부트에서 POST 요청의 RequestBody를 가져..
이전 글에서 AOP로 로그를 처리하도록 구현하고 만족도가 너무 높아서 추가적으로 AOP로 간단히 처리할게 뭐가 있을까에 대해 고민했었다. 코드를 쭉 보다보니, 요청 객체를 검증하기 위해 사용하는 @Valid 어노테이션과 BindingResult가 눈에 들어왔다. @GetMapping("...") public ResultVo validRequestTest(@Valid RequestObject requestObjectDto, BindingResult bindingResult) { if(bindingResult.hasErrors()) { throw new BadRequestException(); } return exampleService.get(requestObjectDto); } 요청 객체가 정상적이지 않을..
이전글 스프링부트에 로그 남기기의 개선 사항이다. 이렇게 로그를 남기려고 하니, 몇 가지 문제가 있었다. 1. 로그가 두 번 남는 문제 2. message에 똑같은 로그가 한번 더 출력되는 문제 3. 모든 API 마다 set을 해줘야함 4. 윗 글엔 작성하지 않았지만, 요청 객체를 남기는 방식의 문제 이번 글에서는 1, 2, 3번 내용만 다룰 거고, 4번은 다음 글에서 다루려고 한다. 로그가 두번 남는 이슈 이 문제는 slf4j와 logback 설정을 잘못 이해해서였다. 기존 logback-spring.xml을 열어보면 아래와 같이 설정되어 있었다. [ignore] [ignore] [ignore] [ignore] [ignore] [ignore] [ignore] 별도의 새로 구현한 로그매니저를 통해 관리하..
그동안 서버에서 비동기 처리를 할 일이 많지 않았었는데 이번에 멀티쓰레드를 처음 사용해볼 기회가 생겼다. 다행히 스프링 부트는 멀티쓰레드 개발의 초심자인 사람도 편하게 사용할 수 있게끔 다양한 기능을 제공해 주고 있었다. 이 내용을 소개해 보려고 한다. 비동기(Asynchorous)란? 멀티 쓰레드가 필요한 이유. 비동기는 다른 곳에서도 많이 다루기 때문에 간단히 말하고 넘어가려고한다. 한줄 요약하면, 앞선 작업이 끝나기를 대기하며 수행(동기적)되는게 아니라 앞선 작업의 종료까지 대기하지 않고, 다음 작업을 바로 수행(비동기)한다는 의미이다. 다들 한번쯤 봤을 만한 그림을 첨부한다. @Async 이 어노테이션 하나면 비동기적으로 동작하게 코드를 구현할 수 있다. 자바에서 Thread를 상속받거나 Runn..
이직 후 맡은 첫 작업은 LOG 였다. 서비스 분석을 위해 코드를 처음 까봤을 때 굉장히 당황스러웠던 게 몇가지 있었는데, 그중 대표적인게 로그 부분이었다. 당황스럽게도, 남기고 있는 로그들은 전부 디버그 수준에서 남길만한 정보들만 남기고 있었다. if (oldUser != null) { log.info("이미 존재하는 사용자입니다. user : {} oldUser : {} ", user, oldUser); userResponseDTO.setCode(-1); userResponseDTO.setErrorMsg("이미 존재하는 사용자입니다."); return userResponseDTO; } 위와 같은 메시지들이 json 형태도 아닌 일반 cout 형태로 출력되고 있었다. 이런 로그들은 서비스를 운영하고 모..
흔히 볼 수 있는 교차 출처 리소스 공유(Cross-Origin Resource Sharing, CORS) 에러... CORS를 간단히 정리하면 아래와 같다. CORS는 다른 도메인 간에 리소스를 공유할 때 발생하는 보안상의 이슈를 해결하기 위해 만들어진 매커니즘. 웹 브라우저에서는 보안상의 이유로 다른 출처(Origin)에 있는 리소스를 직접 요청할 수 없다. 자세히 정리된 곳은 많으니 따로 정리하진 않겠다. 스프링 프레임워크에서는 간단히 해결이 가능하다. @Configuration public class CorsConfig implements WebMvcConfigurer { @Override public void addCorsMappings(CorsRegistry registry) { registr..
앞선 글에서는 캐시에 단순 String만 저장했다. 그런데 작업을 하다보면 한 줄의 단순한 String 보다는 더 많은 정보를 담고싶기 때문에 Object를 저장하고 싶을 것이다. 이 내용을 정리해봤다. 1. 저장하기 객체를 스트림으로 변환 후 Byte[] 형태로 저장한다. id는 기존 String을 저장하는 방식과 같이 UUID로 랜덤값을 생성했다. public String saveObjectCache(ObjectVo value) { Cache cache = cacheManager.getCache("myCache"); String id = UUID.randomUUID().toString(); byte[] bytes = null; try (ByteArrayOutputStream bos = new Byte..
앞선 글에서 캐시를 삭제하는 부분이 빠졌었다. 사실, 서버 입장에서는 캐시를 만드는 것 보다 캐시를 삭제하는게 더 중요하다. 캐시를 삭제하지않고 계속 쌓게되면 100% 확률로 서버는 언젠가 죽기 때문이다. 이를 방지하기 위해 캐시를 꼭 삭제해야한다. 캐시 삭제 전략 일단 캐시의 삭제 전략은 크게 세가지가 있다. (더 있으면 알려주세요..) 1. ID별로 만든 캐시를 하나씩 수동 삭제하기 2. 특정시간 마다 통으로 캐시 비우기 3. TTL(Time-to-Live)을 설정해 ID별 캐시가 살아있는 시간 설정 안정적으로 설계를 잘한다면 1번만으로 사용이 가능하겠지만, 예외 발생시 캐시를 삭제 안하고 넘어가는 경우가 분명 발생할 것이다. 때문에, 사용하지 않는 캐시를 주기적으로 삭제하는 2번 전략도 필요하다. ..
- Total
- Today
- Yesterday
- 스프링부트
- Log
- OpenAI
- springboot
- terraform
- JWT
- ChatGPT
- S3
- cache
- GIT
- 람다
- elasticsearch
- jenkins
- serverless
- AWS
- 코딩테스트
- Spring
- Kotlin
- docker
- AOP
- lambda
- EKS
- chat GPT
- awskrug
- CloudFront
- java
- MySQL
- AWS EC2
- openAI API
- Elastic cloud
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
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 | 31 |