포스트

2022-02-11-TIL

2022-02-11-TIL

Today I Learned

Java Logging

어느 부분에 로그를 남기는 것이 좋을까? 주로 예외나 에러가 발생할만한 곳, 크리티컬한 곳, 입출력을 받는 곳 등이 있을 것이다.

링크된 글들이 공통으로 권하는 원칙은 다음과 같다.

  • 구현체에 직접 의존하지 않고 SLF4J 같은 로깅 퍼사드를 쓴다. Spring Boot는 기본으로 SLF4J와 Logback을 쓴다.
  • 레벨을 의도에 맞게 쓴다. ERROR는 즉시 확인이 필요한 실패, WARN은 당장 문제는 아니지만 살펴볼 상황, INFO는 주요 비즈니스 흐름, DEBUG는 개발 중 상세 정보다.
  • 메시지에 맥락을 담는다. “실패”만 남기지 말고 어떤 요청(주문 ID, 사용자 ID)에서 무엇이 실패했는지 적고, 예외는 메시지만이 아니라 예외 객체를 넘겨 스택 트레이스를 남긴다.
  • 문자열 결합 대신 log.info("order {} paid", orderId)처럼 자리표시자를 쓴다.
  • 비밀번호, 토큰, 개인정보는 로그에 남기지 않는다.
  • 로그를 수집하고 검색할 계획이라면 JSON 같은 구조화된 형식이 유리하다.

  • https://sematext.com/blog/java-logging-best-practices/
  • https://coralogix.com/blog/spring-boot-logging-best-practices-guide/
  • https://huisam.tistory.com/entry/springlogging

Swagger 적용

Springfox Swagger를 Spring 프로젝트에 적용하는 방법과, 자주 헷갈리는 두 애너테이션의 차이다. @ApiParam은 컨트롤러 메서드의 파라미터(쿼리 파라미터, 경로 변수)에 설명을 붙이고, @ApiModelProperty는 요청이나 응답 본문으로 쓰이는 모델 클래스의 필드에 설명과 예시 값을 붙인다. 즉 하나는 엔드포인트 쪽, 하나는 데이터 모델 쪽 문서화다.

  • https://hyeran-story.tistory.com/73
  • https://www.baeldung.com/swagger-apiparam-vs-apimodelproperty

AWS 배스천 호스트

배스천 호스트는 외부에서 접근할 수 없는 프라이빗 서브넷의 인스턴스에 접속하기 위해 퍼블릭 서브넷에 두는 관문 서버다. AWS Quick Start의 Linux 배스천 호스트 아키텍처는 배스천을 퍼블릭 서브넷에 두고, 관리자는 배스천에 SSH로 접속한 뒤 그곳에서 프라이빗 인스턴스로 다시 접속하는 구성을 제공한다. 프라이빗 인스턴스의 보안 그룹은 배스천에서 오는 SSH만 허용하고, 배스천 자체도 허용된 IP에서만 접속하게 제한해 공격 면을 한곳으로 줄인다.

  • https://aws.amazon.com/ko/quickstart/architecture/linux-bastion/
  • https://aws-quickstart.github.io/quickstart-linux-bastion/

MyBatis 트랜잭션 처리

MyBatis-Spring을 쓰면 트랜잭션을 MyBatis가 아니라 Spring이 관리한다. DataSourceTransactionManager를 등록하고 서비스 메서드에 @Transactional을 붙이면, 그 안에서 실행되는 여러 매퍼 호출이 같은 커넥션과 트랜잭션을 공유하고, 런타임 예외가 나면 함께 롤백된다. MyBatis-Spring 문서도 Spring의 트랜잭션 관리에 참여하는 방식을 기본으로 설명한다.

  • https://codevang.tistory.com/264
  • https://e2e2e2.tistory.com/12

for vs forEach

향상된 for문(for (T t : list))은 내부적으로 Iterator를 쓰고, 인덱스 for문은 get(i)를 호출한다. ArrayList에서는 둘의 차이가 거의 없지만, LinkedList에서 get(i)는 매번 처음부터 따라가므로 인덱스 for문이 전체 O(n²)이 된다. 그래서 컬렉션을 순회할 때는 향상된 for문이나 forEach()가 무난하다. Java 8의 Iterable.forEach()는 람다로 간결하게 쓸 수 있지만, 람다 안에서는 break, continue를 쓸 수 없고 바깥의 지역 변수를 바꿀 수 없다.

  • https://stackoverflow.com/questions/9226483/java-loop-efficiency-for-vs-foreach
  • https://siyoon210.tistory.com/99

RabbitMQ Tutorial

RabbitMQ 공식 튜토리얼의 첫 단계는 생산자가 큐에 메시지를 보내고 소비자가 받는 가장 단순한 구조를 Spring AMQP로 구현한다. RabbitTemplate.convertAndSend()로 보내고, @RabbitListener(queues = "hello")를 붙인 메서드가 메시지를 받는다. 이후 단계에서 작업 큐(여러 소비자에게 분배), 발행/구독(fanout exchange), 라우팅(direct exchange), 토픽(topic exchange)으로 확장된다. 나머지 링크는 설치 방법과 Spring Boot 연동 예제다.

  • https://kimseunghyun76.tistory.com/423
  • https://psychoria.tistory.com/550
  • https://www.rabbitmq.com/tutorials/tutorial-one-spring-amqp.html
  • https://yoonwould.tistory.com/157
  • https://co-de.tistory.com/9
  • https://colinch4.github.io/2020-12-03/README.rabbitmq-python/
  • https://velog.io/@hellozin/Spring-Boot%EC%99%80-RabbitMQ-%EC%B4%88%EA%B0%84%EB%8B%A8-%EC%84%A4%EB%AA%85%EC%84%9C
참고한 자료외부 출처 4

외부 출처

이 글은 저작권자의 CC BY 4.0 라이선스를 따릅니다.

댓글

아직 댓글이 없습니다