본문 바로가기

IT/Logstash

Logstash Filter 플러그인을 만들어보자. #1

분리된 프레임워크에서 적재해주는 문서를 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 플러그인을 위한 준비과정을 알아보도록 하자.