RequestBody의 내용을 로그로 남기고 싶다(2)

이미 일년도 넘은 내용이지만 에버노트에서 꺼내보면서 이것 저것 정리도 해볼겸 RequestBody의 내용을 로그로 남기고 싶다. 에 이어서 좀 더 관련 내용을 적어보았다. filter 를 이용해서 request body 를 로그로 찍어보자.

우선 문자열과 input stream 의 편리한 처리를 위해서 다음과 같이 의존성을 추가한 다음에 진행하였다.

1
2
3
4
5
6
7
8
9
10
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>3.8.1</version>
</dependency>
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.6</version>
</dependency>

Read More

카프카 컨슈머

카프카, 데이터 플랫폼의 최강자 의 5장 카프카 컨슈머 요약

컨슈머의 주요 기능

  • 특정 파티션을 관리하고 있는 파티션 리더에게 메시지를 가져오도록 요청
    • 각 요청은 로그의 오프셋을 명시
    • 그 위치로 부터 로그 메시지를 수신
    • 이를 통해 가져올 메시지의 위치를 조정, 필요한 경우 이미 가져온 데이터도 다시 수신 가능
  • 버그를 수정한 후 가져왔던 메시지들을 다시 가져올 수 있음
    • 래빗 엠큐와 같은 일반적인 메시지큐 솔루션에서는 제공하지 않는 기능

Read More

카프카 프로듀서

카프카, 데이터 플랫폼의 최강자 의 4장 카프카 프로듀서 요약

카프카 프로듀서

  • 프로듀서의 주요 옵션
  • 프로듀서 활용 예제
  • 다양한 메시지 전송 방법

카프카 프로듀싱 - 자바

  • send() 로 메시지를 보내는 방식은 3가지
  1. 메시지를 보내고 확인하지 않기
  2. 동기 전송
  3. 비동기 전송

메시지를 보내고 확인하지 않기

  • 프로듀서에서 서버로 메시지를 보내고 난 후에 성공적으로 도착했는지 까지 확인하지 않음
  • 프로듀서가 자동으로 재전송하기 때문에 대부분의 경우 성공적으로 전송
    • 일부 메시지는 손실 될 수도 있음
  • 메시지는 버퍼에 저장되고 별도의 스레드를 통해 브로커로 전달
  • send() 는 자바 퓨처(Future) 객체로 RecordMetadata를 리턴 받음
    • 리턴값을 무시하기 때문에 메시지가 성공적으로 전송되었는지 알 수 없음
    • 메시지 손실 가능성이 있기 때문에 일반적인 서비스에서는 사용하지 않음
  • 브로커에게 메시지를 보낸 후의 에러는 무시하지만, 보내기 전에 에러가 발생하면 예외를 처리할 수 있음

Read More

카프카 디자인

카프카, 데이터 플랫폼의 최강자 의 3장 카프카 디자인 요약

카프카 디자인

  • 대용량 데이터 처리
    • ex 실시간 로그 집계
    • 어플리케이션의 처리량이 높아야
    • 배치 전송, 파티션, 분산 처리
  • 데이터의 안정적인 저장
    • 리플리케이션 기능
  • 분산된 서버에서 자동으로 파티션의 리더를 선출

카프카 디자인의 특징

  • 필요
    • 분산된 데이터 파이프 라인의 표준화/통합
    • 높은 처리량
  • 목적
    • 높은 처리량
    • 빠른 메시지 전송
    • 운영 효율화
  • 구현
    • 분산 시스템
    • 페이지 캐시
    • 배치 전송 처리

카프카 디자인 1 - 분산 시스템

  • 분산 시스템은 네트워크로 이루어진 컴퓨터들의 그룹
  • 시스템 전체가 공통의 목표를 공유
  • 같은 역할을 하는 여러 대의 서버로 이뤄진 서버 그룹
  • 장점
    • 단일 시스템보다 더 높은 성능을 얻을 수 있음
    • 분산 시스템 중 하나의 서버 또는 노드 등이 장애가 발생하면 다른 서버 또는 노드가 대신 처리
    • 시스템 확장이 용이

Read More

RequestBody의 내용을 로그로 남기고 싶다.

다음은 최초에 제가 가졌던 니즈입니다.

  1. POST 방식으로 호출되는 http request의 payload를 로그로 남기고 싶다.
  2. controller 내부에서 한땀 한땀 로그로 남기는 방법 말고 다른 방법으로 남겨보고 싶다.

스프링 프레임워크 위에서 비즈니스 로직을 구현하고 있지만, 스프링 기반의 프로젝트의 구조에 관심을 이제서야 조금씩 가지다 보니 새롭고 좋네요. 한번도 완독해본적 없는 토비의 스프링이나 스프링 인 액션을 찬찬히 다시 한번 봐야겠습니다. 올해는 꼭 성공하면 좋겠네요.

일단 서비스가 돌아가고 있는 프로젝트의 소스 코드를 쭉 훑어보았습니다. 우선 기존에 쌓이고 있는 로그를 읽어가며 역으로 소스코드를 따라 들어가보았습니다. config 관련된 클래스들을 별도의 패키지에서 관리하고 있는데요. WebMvcConfigurationSupport 클래스를 상속받은 ServletApplicationContextConfig 가 있고, HandlerInterceptorAdapter 를 상속하여 구현한 인터셉터들이 있네요. 구현된 인터셉터들은 ServletAppliationContextConfig 내에서 등록하여 사용하고 있었습니다. 인터셉터의 내부에서 HttpRequest의 내용을 간략하게 남기고 있는 것을 보아하니, 별도의 인터셉터 클래스를 만들어 주어 request의 body를 찍어주게 하면 될 것 같은 느낌을 받았습니다.

스트림을 읽어들인 다음 문자열로 변환 시킨 후 로그로 남기도록 구현하였습니다. HandlerInterceptorAdapter 를 상속하여 만든 ApiLoggingInterceptor 클래스의 afterCompletion() 메소드에 이쁘게 로그를 찍어주도록 만들었습니다. 기쁜 마음으로 톰캣 인스턴스를 띄우고, http request를 하나 날려보았습니다. 찍히길 기대했던 로그는 안찍히고 다른 로그가 올라오네요. 별거 아니라고 생각하며 기쁜 마음으로 서버 로그가 찍히길 기다렸는데, 이미 스트림이 닫혀있다는 예외 메시지만 출력되었습니다. 다음과 같이요.

Read More

PreUpdate 어노테이션은 왜 동작하지 않았는가?

DummyEntity라는 엔티티가 있다고 해보겠습니다. 특별한 건 없고, modifiedAt 이라는 필드에 @PreUpdate 어노테이션이 선언되어 있습니다.

1
2
3
4
5
6
7
8
// DummyEntity.javascript
private String description;
private Date modifiedAt;
@PreUpdate
public void preUpdate() {
modifiedAt = new Date();
}

아래의 DummyServiceImpl 제가 짠 소스 코드 입니다. 문제가 있는 소스 코드입니다. 회사 코드가 유출되면 안되니 간단하게 바꾸었습니다. 엔티티를 조회한 다음, 엔티티의 특정 필드의 값을 수정하여 변경 사항을 저장한 후에 큐로 이벤트를 발행할 때, modifiedAt 에는 변경이 이루어진 시간을 세팅하여 전달하고 싶었습니다.

Read More

Webpack 시작하기

본 포스트는 프로 리액트: React.js를 이용한 모던 프런트엔드 구축부록A - 웹팩을 공부하며 정리한 글 입니다. 문제시 삭제하도록 하겠습니다. 도서에 포함된 칸반 앱의 소스 코드들이 이전 버전의 리액트로 작성되어 있어서, 그대로 따라서 타이핑 하면 수없이 많은 에러들과 부딪힐 수 있습니다. 우리말로 된 리액트 서적이 없다는 점을 감안하더라도 프로 리액트는 리액트를 처음 접하는 입장에서 굉장히 많은 도움이 되는 책입니다. 새롭게 바뀐 리액트 환경에서 칸반 앱을 동작하게 만드는 재미도 쏠쏠합니다. 리액트를 처음 접하는 개발자라면 한번쯤 처음부터 끝까지 찬찬히 일독하기를 조심스레 권해봅니다.

웹팩?!

웹팩은 프로젝트의 구조를 분석하여, 프로젝트에 포함된 모듈과 자바스크립트 파일을 번들로 묶고 패킹하는 모듈 번들러(module bundler)이다. 웹팩은 메인 파일에서 부터 프로젝트의 구조를 분석하는데, require와 import 키워드를 참고해서 프로젝트의 모든 의존성을 조사한다. 로더를 이용해서 각 소스 파일을 처리하고, 프로젝트의 자바스크립트 모듈을 번들로 묶은 자바스크립트 파일을 생성한다. 일반적으로 하나의 파일로 떨군다.

웹팩 설치 및 실행

웹팩을 사용하기 위해서 가장 먼저 비어있는 디렉토리에서 npm init으로 초기화 시켜주고, 웹팩을 설치한다. 이미 package.json 으로 의존성을 관리하고 있다면 npm init 은 생략해도 무방하다.

1
$ npm init && npm install --save-dev webpack

설치된 웹팩은 다음과 같은 형태로 사용한다.

1
$ node_modules/.bin/webpack {최상위 파일} {최종 번들 파일}

아무런 오류 없이 bundle.js 이 생성되었다면 성공적으로 번들링이 수행된 것이다.

Read More