엔지니어링

유지관리 가능하고 재사용 가능한 Logstash 파이프라인을 생성하는 방법

오픈 소스 데이터 처리 파이프라인인 Logstash는 하나 이상의 입력에서 이벤트들을 수집하여 변환한 다음, 각 이벤트를 하나 이상의 출력으로 전송합니다. 일부 Logstash 구현에는 많은 수의 코드 줄이 포함되어 있을 수 있으며 여러 입력 소스의 이벤트를 처리할 수도 있습니다. 이러한 구현을 더 쉽게 유지관리할 수 있도록 모듈형 구성 요소로 파이프라인을 만들어 코드 재사용성을 높이는 방법을 보여드리겠습니다.

동기

Logstash에서는 여러 입력 소스의 이벤트에 로직의 공통 하위 집합을 적용해야 하는 경우가 종종 있습니다. 이는 일반적으로 다음 두 가지 방법 중 하나로 이루어집니다. 

  1. 공통 로직이 모든 소스의 모든 이벤트에 손쉽게 적용될 수 있도록 단일 파이프라인에서 서로 다른 여러 입력 소스의 이벤트를 처리합니다. 이러한 구현에는 공통 로직 외에도 상당한 양의 조건부 로직이 존재합니다. 따라서 이러한 접근 방식을 사용하면 Logstash 구현이 복잡해지고 이해하기 어려워질 수 있습니다.
  2. 개별 입력 소스의 이벤트를 처리하는 개별 파이프라인을 실행합니다. 이 접근 방식을 사용하려면 파이프라인별로 공통 기능을 복제하고 복사해야 하므로 코드의 공통 부분을 유지관리하기가 어렵습니다. 

이 블로그에 제시된 기법은 모듈형 파이프라인 구성 요소를 서로 다른 파일에 저장한 다음 이러한 구성 요소를 결합하는 방식으로 파이프라인을 구성함으로써 위의 접근 방식의 단점을 해결합니다. 이 기법은 파이프라인 복잡성을 줄이고 코드 중복을 없앨 수 있습니다.

모듈형 파이프라인 구성

Logstash 구성 파일은 Logstash 파이프라인에서 실행되는 입력, 필터 및 출력으로 이루어집니다.  고급 설정에서는 여러 파이프라인을 실행하는 Logstash 인스턴스를 운영하는 것이 일반적입니다. 기본적으로 인수 없이 Logstash를 시작하면 Logstash는 pipelines.yml이라는 파일을 읽고 지정된 파이프라인을 인스턴스화합니다. 

Logstash 입력, 필터 및 출력은 여러 파일에 저장할 수 있으며 glob 표현식을 지정하여 파이프라인에 포함할 파일을 선택할 수 있습니다. glob 표현식과 일치하는 파일은 알파벳 순으로 결합됩니다. 필터 실행 순서가 중요한 경우가 많으므로 파일 이름에 숫자 식별자를 추가하면 원하는 순서로 파일이 결합되도록 하는 데 도움이 될 수 있습니다.

아래에서는 여러 모듈형 Logstash 구성 요소를 조합한 두 개의 개별 파이프라인을 정의하겠습니다. Logstash 구성 요소를 다음 파일에 저장합니다.

  • 입력 선언: 01_in.cfg, 02_in.cfg
  • 필터 선언: 01_filter.cfg, 02_filter.cfg, 03_filter.cfg
  • 출력 선언: 01_out.cfg

그런 다음 glob 표현식을 사용해 다음과 같이 원하는 구성 요소로 구성되도록 pipelines.yml에 파이프라인을 정의합니다. 

- pipeline.id: my-pipeline_1
  path.config: "<path>/{01_in,01_filter,02_filter,01_out}.cfg"
- pipeline.id: my-pipeline_2
  path.config: "<path>/{02_in,02_filter,03_filter,01_out}.cfg"

위의 파이프라인 구성에서는 두 파이프라인 모두에 02_filter.cfg 파일이 존재합니다. 이는 두 파이프라인에 공통인 코드를 어떻게 단일 파일에서 정의 및 유지관리할 수 있고 여러 파이프라인에서 실행할 수 있는지 보여줍니다.

파이프라인 테스트

이 섹션에서는 위의 pipelines.yml에 정의된 개별 파이프라인에 결합되는 파일들의 구체적인 예를 제공합니다. 그런 다음 이러한 파일들로 Logstash를 실행하고 생성된 출력을 표시합니다. 

구성 파일

입력 파일: 01_in.cfg

이 파일은 generator인 입력을 정의합니다. Generator 입력은 Logstash를 테스트하기 위해 작성되었으며 이 예제에서는 단일 이벤트를 생성하게 됩니다. 

input { 
  generator { 
    lines => ["Generated line"] 
    count => 1 
  } 
}

입력 파일: 02_in.cfg

이 파일은 stdin에서 수신 대기하는 Logstash 입력을 정의합니다.

input { 
  stdin {} 
}

필터 파일: 01_filter.cfg

filter { 
  mutate { 
    add_field => { "filter_name" => "Filter 01" } 
  } 
}

필터 파일: 02_filter.cfg

filter { 
  mutate { 
    add_field => { "filter_name" => "Filter 02" } 
  } 
}

필터 파일: 03_filter.cfg

filter { 
  mutate { 
    add_field => { "filter_name" => "Filter 03" } 
  } 
}

출력 파일: 01_out.cfg

output { 
  stdout { codec =>  "rubydebug" } 
}

파이프라인 실행

옵션이 전혀 없이 Logstash를 시작하면 앞에서 정의한 pipelines.yml 파일이 실행됩니다. 다음과 같이 Logstash를 실행합니다. 

./bin/logstash

my-pipeline_1 파이프라인이 입력 이벤트를 시뮬레이션하기 위해 generator를 실행하고 있으므로 Logstash 초기화가 완료되는 대로 다음 출력이 표시됩니다. 이는 01_filter.cfg02_filter.cfg의 콘텐츠가 예상대로 이 파이프라인에 의해 실행됨을 나타냅니다.

{ 
       "sequence" => 0, 
           "host" => "alexandersmbp2.lan", 
        "message" => "Generated line", 
     "@timestamp" => 2020-02-05T22:10:09.495Z, 
       "@version" => "1", 
    "filter_name" => [ 
        [0] "Filter 01", 
        [1] "Filter 02" 
    ] 
}

my-pipeline_2라는 다른 파이프라인이 stdin에서 입력을 기다리고 있으므로 해당 파이프라인에서 처리하는 이벤트는 아직 표시되지 않았습니다. Logstash가 실행되고 있는 터미널에 아무 문구나 입력한 후 [Return]을 눌러 이 파이프라인용 이벤트를 만드십시오. 그러면 다음과 같은 화면이 표시됩니다. 

{ 
    "filter_name" => [ 
        [0] "Filter 02", 
        [1] "Filter 03" 
    ], 
           "host" => "alexandersmbp2.lan", 
        "message" => "I’m testing my-pipeline_2", 
     "@timestamp" => 2020-02-05T22:20:43.250Z, 
       "@version" => "1" 
}

02_filter.cfg03_filter.cfg의 로직이 예상대로 적용되었음을 여기에서 확인할 수 있습니다.  

실행 순서

Logstash는 glob 표현식에 있는 파일 순서에 신경 쓰지 않는다는 점에 유의하십시오. Logstash는 포함할 파일을 결정하는 데만 glob 표현식을 사용하며 그 후에는 알파벳 순서로 파일을 정렬합니다. 즉, glob 표현식에서 03_filter.cfg02_filter.cfg 앞에 오도록 my-pipeline_2의 정의를 변경하더라도 각 이벤트는 03_filter.cfg에 정의된 필터 전에 02_filter.cfg의 필터를 먼저 통과합니다.

결론

glob 표현식을 사용하면 개별 파일로 저장된 모듈형 구성 요소로 Logstash 파이프라인을 구성할 수 있습니다. 이를 통해 코드의 유지관리성, 재사용성 및 가독성을 향상할 수 있습니다. 

참고로 이 블로그에서 설명한 기법 외에도 파이프라인 대 파이프라인 통신도 Logstash 구현 모듈성을 개선할 수 있는지 검토해야 합니다.