Springboot

springboot + fluentd + mongoDB 연동

25G 2023. 8. 16. 19:20

fluntd?

흔히 아는 ELK에 로그스테시와 같이 로그를 저장소에 적제하거나 필터링하고 어딘가로 전송해주는 큐 역할을 하는 툴입니다.
해당 글에선 docker를 사용해서 할 예정입니다.

fluntd Dockerfile

FROM fluent/fluentd:v1.11-debian-1

USER root

RUN buildDeps="sudo make gcc g++ libc-dev" \
 && apt-get update \
 && apt-get install -y --no-install-recommends ${buildDeps} \
 && sudo apt-get install -y libmariadb-dev \
 && sudo gem install fluent-plugin-mongo \
 && sudo gem install -V fluentd-ui \
 && sudo gem sources --clear-all \
 && SUDO_FORCE_REMOVE=yes \
    apt-get purge -y --auto-remove \
                  -o APT::AutoRemove::RecommendsImportant=false \
                  $buildDeps \
 && rm -rf /var/lib/apt/lists/* \
 && rm -rf /tmp/* /var/tmp/* /usr/lib/ruby/gems/*/cache/*.gem

USER fluent

fluent-plugin-mongo 여기서 해당 fluentd에는 몽고디비와 연결할수 있는 플러그인이 필요하기때문에 목록에 추가 해 줬고 sudo gem install -V fluentd-ui를 추가해서 fluentd를 ui 로 관리하기 위해서는 해당 ui툴을 다운받아줘야해서 위와같이 설정 해 줬습니다.

ui 초기 계정 정보

id: admin
password: changeme

fluentd docker run 명령어

docker run -d --network {네트워크id} -u root -p 24224:24224 -p 9292:9292 -v ~/Desktop/fluentd.conf:/fluentd/etc/fluent.conf --name fluentd_mongo 49809b8cae22

fluentd는 24224포트를사용하고 fluentd 의 ui 는 9292포트를 사용하기때문에 위와같이 포트를 두개 열어줘야합니다.

fluent.conf

볼륨으로 연결한fluent.conf는 fluentd를 핸들링하기위한 설정 파일입니다.

  • fluentd 설정
    <source>  //input
    @type forward // 해당 포트를 리스닝하고 포트로 오는 데이터를 받아주겠다
    port 24224
    </source>
    
    
    

<match **> // output
@type mongo

user userid
password pwd
database dbname
collection springboot_log
host mongodb-container
port 27017

capped

capped_size 1000m

time_key time @type file path /fluentd/log/buffer/manage_domain_log flush_interval 10s @type secondary_file directory /fluentd/log/secondary/manage_domain_log basename my.fail.logs


## mongodb docker run 명령어

docker run --network {fluentd와 동일한 네트워크 id} --name mongodb-container -v ~/data:/data/db -d -p 27017:27017 mongo


## Spring boot project logback 설정
fluentd 와 연동하기 위해서는 logback 설정을 해주고 fluentd와 연동하기위한 의존성을 추가해 줘야 합니다.
- gardle

implementation group: 'org.fluentd', name: 'fluent-logger', version: '0.3.4'
implementation group: 'com.sndyuk', name: 'logback-more-appenders', version: '1.5.6'


해당 라이브러리 사용법 예시
private static FluentLogger LOG = FluentLogger.getLogger("app");

@GetMapping("/log")
public ResponseEntity<?> log() {
    Map<String, Object> data = new HashMap<String, Object>();
    data.put("from", "userA");
    data.put("to", "userB");
    LOG.log("follow", data);
    LOG.close();
    return new ResponseEntity<>(HttpStatus.CREATED);
}

- logback.xml 설정
<appender name="FLUENT_TEXT" class="ch.qos.logback.more.appenders.DataFluentAppender">
    <!-- Check tag and label fluentd info: https://docs.fluentd.org/configuration/config-file-->
    <tag>applog</tag>
    <label>error_log</label>
    <remoteHost>${FLUENTD_HOST}</remoteHost>
    <port>${FLUENTD_PORT}</port>
</appender>
위 appender을 추가해줘야 fluentd 와 통신할 수 있습니다. 설정은 다음과 같이 해주면되고 tag와 label로 fluentd 설정에 보시면 metch의 태그와 매칭돼서 해당 output을 타게됩니다. 
해당글에서는 <match **>  로 와일드카드로 설정해놔서 어떻게 해놔도 상관 없습니다.

#### 주의 사항!
저도 삽질하면서 깨달은 사실은 logback.xml 설정과 위에서 컨트롤러에서 사용하는 FluentLogger 객체의 커넥션은 별개라는 점입니다.
저도 테스트하는데 console에 뜨는 로그는 잘 날라가는데 애플리케이션 코드로 보내는 로그는 fluentd와 커넥션이 전혀 안이루어 져서 두개를 같은 커넥션이라 생각해서 한참 해매다가 알게된 점입니다.
#### 개인적인 TIP
<appender name="FLUENT_TEXT" class="ch.qos.logback.more.appenders.DataFluentAppender">
    <filter class="ch.qos.logback.classic.filter.LevelFilter">
        <!-- 에러로그를 설정하고 로그의 레벨이 맞으면 onMatch, 아니라면 onMismatch  -->
        <level>error</level>
        <onMatch>ACCEPT</onMatch>
        <onMismatch>DENY</onMismatch>
    </filter>
    <!-- Check tag and label fluentd info: https://docs.fluentd.org/configuration/config-file-->
    <tag>applog</tag>
    <label>error_log</label>
    <remoteHost>${FLUENTD_HOST}</remoteHost>
    <port>${FLUENTD_PORT}</port>
</appender>

```
위 설정과같이 error 로그만 fluentd 에 보내도록 해 놓고 애플리케이션 코드 흐름상에서 애러 로그를 발생시키고 싶을땐 Slf4j 를 활용해서 일부러 콘솔에 에러로그를 띄우도록해서 fluentd로 전송하는 방법을 선택했습니다. 혼자 태스트할때는 애플리케이션 코드로는 커넥션이 되지 않아서 이렇게 해결했습니다.

사용 결과

/log 를 호출해서 해당 코드블럭을 실행하면

다음과같이 로그가 적제되는 것을 볼 수 있습니다.