분리된 프레임워크에서 적재해주는 문서를 Elasticsearch에 색인하기 위해 요 한 주간 Logstash를 만져봤다.
원하는 기능을 수행하기 위해 Logstash에서 제공하는 플러그인들의 목록을 이리 뒤지고 저리 뒤져보았지만,
다른 사람들이 짜놓은 플러그인들이 완성도는 높을지 모르나 내 의도대로 처리하기엔 직접 짜는 것만 못하더라.
기억 및 공유를 위해 플러그인을 짜고 적용해 본 과정을 기록해둔다.
본 포스트에서는 Logstash 플러그인의 제한적인 배포만을 다룬다.
Github 및 Rubygems.org에 등록 없이 로컬에서만 빌드 및 설치를 수행했다.
Logstash 공식 도큐먼트의 플러그인 가이드를 적극 참고했다.
아직 어지럽고 허술하지만 대략적인 가이드라인으로는 모자람이 없다.
https://www.elastic.co/guide/en/logstash/current/_how_to_write_a_logstash_filter_plugin.html
#1 : 본격적인 플러그인 삽질 전에 input 설정부터!
정해진 시간에 정해진 경로에 떨어지는 문서를 파싱하여 Elasticsearch에 색인해야한다.
각 라인을 Key / Value로 추출해야하는 문서의 형태는 대충 다음과 같았다.
<DOCID>C20002 <DATE>20150128083104 <ID>20002 <TITLE>SCORE <TITLE_SRCH>SCORE <TITLE_SORT>SCORE <TITLE_ENG>SCORE <TITLE_ENG_SRCH>SCORE <TITLE_ENG_SORT>SCORE <USER_PHOTO_FILE_PATH_VAL> <USER_EMAIL_ADDR> <USER_TELNO> <USER_CELNO> <SORT>2 <SORT2>1 <USER_STAT_CD> <USER_SECT_CD> <CO_NM> <ALIAS>C # .. 포맷 반복
Logstash는 리눅스의 -tail의 형태처럼 파일을 감시(watch)하며 줄 단위로 읽어들이기 때문에,
여러 줄을 하나의 이벤트로 인식해야만 하는 작업의 특성상 input 단계에서 multiline codec을 적용해야한다.
Logstash를 구동하기 위한 .conf 파일 중 input의 설정코드는 다음과 같았다.
input { file { path => "C:/logstash-2.0.0/data/scd/*" start_position => beginning codec => multiline { # Specify the last attribute of a individual document. pattern => "^<ALIAS>" negate => true what => "next" } } }
Logstash에서 기본적으로 제공하는 file input 플러그인을 적용해서 event를 생성한다.
path와 start_position은 Logstash에서 따로 준비해둔 페이지를 보면 어떤 속성인지 알 수 있으니,
multiline codec을 적용한 부분을 조금 더 살펴보자.
pattern에는 multiline codec이 실제로 적용되는 라인의 패턴이 들어간다.
파싱해야할 문서의 특성상 <DOCID>부터 <ALIAS>까지 반복되기 때문에 "^<ALIAS>"로 설정해주었다.
what을 "next"로 해주면 pattern을 만족하는 라인은 다음 이벤트의 문자열로 병합된다.
pattern => "^<DOCID>" what => "previous"의 조합도 사용해보았으나, 마지막 문서가 색인되지 않는 문제가 있었다.
negate는 true로 값을 줄 경우 pattern이 일치하지 않는 값에 대해 무시한다고 되어있는데.. 구동원리는 잘 모르겠다-_-;
input { file { path => "C:/logstash-2.0.0/data/scd/*" start_position => beginning codec => multiline { # Specify the last attribute of a individual document. pattern => "^<ALIAS>" negate => true what => "next" } } } filter { } output { stdout { codec => rubydebug { metadata => true } } }
이렇게 설정하고 파일을 땡겨오면 다음과 같이 콘솔에 찍혀나온다.
{ "@timestamp" => "2015-11-25T08:58:06.525Z", "message" => "<DOCID>C20002\n<DATE>20150128083104\n<ID>20002\n<TITLE>SCORE \n<TITLE_SRCH>SCORE\n<TITLE_SORT>SCORE\n<TITLE_ENG>SCORE\n<TITLE_ENG_SRCH>SCORE \n<TITLE_ENG_SORT>SCORE\n<USER_PHOTO_FILE_PATH_VAL>\n<USER_EMAIL_ADDR>\n<USER_TELNO> \n<USER_CELNO>\n<SORT>2\n<SORT2>1\n<USER_STAT_CD>\n<USER_SECT_CD>\n<WKSPACE_STAT_CD> \n<WKSPACE_TYP_CD>\n<CO_NM>\n<ALIAS>C", "@version" => "1", "tags" => [ [0] "multiline" ], "host" => "HOST0001", "path" => "C:/logstash-2.0.0/data/scd/B-00-201511200239-34142-I-C.SCD" , "@metadata" => { "path" => "C:/logstash-2.0.0/data/scd/B-00-201511200239-34142-I-C.SCD" } }
Logstash File input 플러그인은 읽어들인 파일의 내용을 event의 message 필드에 담아 넘겨준다.
콘솔을 잘 살펴보면 message 필드에 multiline codec에서 설정한 영역 만큼이 넘겨져오는 것을 확인할 수 있다.
Logstash Elasticsearch output 플러그인은 기본적으로 event의 모든 필드를 던져 색인을 요청하므로,
Filter 플러그인을 통해 message 필드의 값을 적절하게 파싱하여 event에 필드별로 할당해주는 작업을 해주어야한다.
다음 포스트에선 이 message 필드값을 조작하기 위한 Logstash Filter 플러그인을 위한 준비과정을 알아보도록 하자.