fluentd의 configuration file은 fluentd의 동작 전부를 결정하는 아주 중요한 요소이다.
1. input source와 output destination을 무엇으로 쓸 것인지(plugin) 결정하고
2. input과 output plugin에 대한 parameter를 결정하며
3. 이 configuration을 기반으로 fluentd가 동작한다.
즉, 어느 source에서 input event data를 받아서 어떤 곳에 output을 전달해줄 지 결정한다는 것이다.
event cycle을 설명하기 위해서 간단한 example을 알아볼 것인데, in_http
plugin을 만들어 http요청을 받아 log data를 가져오고, out_stdout
plugin을 만들어 이 data를 stdout
에 뿌려주도록 할 것이다. 이 두 plguin은 basic.conf
파일 하나에 적어주면 된다.
basic.conf
<source>
@type http
port 8888
bind 0.0.0.0
</source>
<match test.cycle>
@type stdout
</match>
<source>
부분이 바로 in_http
plugin에 해당하는 부분으로 @type
으로 http
를 가지겠다는 것이다. 또한 port
로 8888
을 TCP로 열고, host는 0.0.0.0(localhost)
로 가져오겠다는 것이다.
<match test.cycle>
부분이 out_stdout
plugin에 해당하는 부분으로 source로부터 들어오는 log data의 tag
가 test.cycle
이라면 stdout
으로 보내겠다는 것이다.
이제 fleuntd
container에 다음의 conf파일을 적용시켜보도록 하자.
docker run -p 8888:8888 -v ./conf:/fluentd/etc fluent/fluentd:edge-debian -c /fluentd/etc/basic.conf
잘 실행되었다면 8888
port로 http요청을 보내도록 하자. 이때 data를 써주면 fluentd
에서 source로 받아 output으로 뽑아내줄 것이다. 단, 요청 시에는 반드시 test.cycle
이라는 태그가 매칭되어야 하기 때문에 다음과 같이 요청해주어야 한다.
curl -i -X POST -d 'json={"action":"login","user":2}' http://localhost:8888/test.cycle
fluentd container에서는 다음의 로그가 찍혔을 것이다.
2023-10-20 08:46:57 +0000 [info]: #0 starting fluentd worker pid=16 ppid=7 worker=0
2023-10-20 08:46:57 +0000 [info]: #0 fluentd worker is now running worker=0
2023-10-20 08:47:10.748692079 +0000 test.cycle: {"action":"login","user":2}
우리가 만든 in_http
plugin과 out_stdout
plugin이 잘 적용된 것을 볼 수 있다. 이처럼 fluentd는 configuration file을 통해서, plugin을 설정할 수 있으며 plugin은 source와 output에 대해서 관여해 log event들을 어디서 받고 어디로 내보낼 지 결정해준다.
fluentd에서 다루는 data를 event
라고 부른다. event는 3가지 구조로 이루어져 있다.
tag
: tag는 어디서부터 event가 왔는 지를 나타낸다. 따라서 하나의 식별자 역할을 하여 메시지 라우팅에 있어 사용된다.time
: 나노초 단위로 event가 발생했을 때의 시간을 알려준다.record
: JSON object로 실제 로그를 나타낸다.즉, source로 부터 들어온 log를 record로 만들고, tag와 time이라는 특성을 붙여 event
로 만드는 것이다. 또한, input plugin 설정을 통해서 여러 data source들에서 온 log를 fluent event로 만들어주는데, in_tail
input plugin을 사용하면 text line으로부터 다음과 같은 events를 만들어준다.
다음의 아파치 로그를
192.168.0.1 - - [28/Feb/2013:12:00:00 +0900] "GET / HTTP/1.1" 200 777
아래의 fluentd log로 만들어준다.
tag: apache.access # set by configuration
time: 1362020400.000000000 # 28/Feb/2013:12:00:00 +0900
record: {"user":"-","method":"GET","code":200,"size":777,"host":"192.168.0.1","path":"/"}
Setup
이 정의되면 Route Engine
이 서로 다른 input data에 대해서 몇 가지를 rule들을 포함한다. 내부적으로 Event
는 일련의 절차를 걸쳐 정제되는 것이다.
Setup
으로 Filter
를 사용하여 어떻게 Events
cycle이 변경되는 지 확인해보자. Filter
는 말 그대로 rule에 따라서 event를 pass할지 거절할 지를 결정하는 것이다. 다음은 Filter
정의를 추가한 configuration 파일이다.
<source>
@type http
port 8888
bind 0.0.0.0
</source>
<filter test.cycle>
@type grep
<exclude>
key action
pattern ^logout$
</exclude>
</filter>
<match test.cycle>
@type stdout
</match>
위의 configuration은 source
인 http로부터 event를 받는데, test.cycle
요청의 경우에 filter
를 통과한다. filter
는 grep
으로 key
가 action
인데 value
같이 pattern
에 일치하면 제외시키는 것이다. 다음의 그림을 참고하도록 하자.
|----http----| |-------grep------| |------stdout-----|
|Tag: null |----|Match: test.cycle|-----|Match: test.cycle|
|------------| |-----------------| |-----------------|
먼저 basic-filter.conf
를 적용한 fluentd container를 배포하도록 하자.
docker run -p 8888:8888 -v ./conf:/fluentd/etc fluent/fluentd:edge-debian -c /fluentd/etc/basic-filter.conf
다음의 요청을 보내보도록 하자.
curl -i -X POST -d 'json={"action":"login","user":2}' http://localhost:8888/test.cycle
tag
가 test.cycle
이지만 action
이 login
이라 filter되지 않는다. fluentd container의 log에 다음과 같이 나온다.
2023-10-23 02:04:04.669503595 +0000 test.cycle: {"action":"login","user":2}
다음의 요청을 보내보도록 하자.
curl -i -X POST -d 'json={"action":"logout","user":2}' http://localhost:8888/test.cycle
tag
가 test.cycle
이고, action
이 logout
이며 이기 때문에 filter
의 rule에 일치한다. 따라서 fluentd container output에 다음의 event는 필터링된다.
위에서 보았듯이 Events
는 step-by-step 단계를 순서대로 따라가 정제된다. 그러나 점점 configuration이 복잡해지고, 다양한 source의 event들이 들어오기 시작하면서 reader입장에서 fluentd 설정이 너무 복잡해지는데, 이러한 문제를 해결하고자 Labels
라는 것이 도입되었다.
Labels
는 configuration file 복잡도를 해결하고 새로운 Routing
section을 도입하는데, 이는 configuration의 top-bottom 순서대로 event가 흐르는 것이 아니라 linked 레페런스와 같이 동작하도록 만드는 것이다.
다음의 setup을 보도록 하자.
<source>
@type http
bind 0.0.0.0
port 8888
@label @STAGING
</source>
<filter test.cycle>
@type grep
<exclude>
key action
pattern ^login$
</exclude>
</filter>
<label @STAGING>
<filter test.cycle>
@type grep
<exclude>
key action
pattern ^logout$
</exclude>
</filter>
<match test.cycle>
@type stdout
</match>
</label>
위의 예제를 잘보면 <source>
에 @label @STAGING
이 있는 것을 볼 수 있다. 이 <source>
로 부터 들어온 event들은 <fitler test.cycle>
을 거치는 것이 아니라, <label @STAGING>
으로 바로 거친다. 따라서, 현재는 <fitler test.cycle>
를 거치는 경우가 없다.
filter
내용이 같아서 결과에는 큰 변화가 없지만, 다양한 source로부터 event들이 들어올 때, 이들을 쉽게 라우팅해주기 좋다.
지금까지 output
plugin으로 stdout
만 사용하였다. 그러나 stdout
은 non-buffer이므로 실제 production환경에서는 buffered 모드인 forware
, mongodb
, s3
등을 사용한다. buffered output plugin을 사용하는 경우에 event들이 buffer에 차오르기 시작하고, flush조건을 만족하면 내용물들을 destination으로 전달하여 buffer를 비워낸다. 따라서, buffered output을 사용하면 stdout
과 같은 non-buffered output처럼 즉각적으로 output을 확인할 필요가 사라진다.