[Logstash] ruby 필터는 왜 사용하죠?

devhans·2024년 8월 1일

Logstash

목록 보기
3/3
post-thumbnail

배경

logstash에서 단순한 코드 작업은 ruby 필터를 통해 해결할 수 있습니다.
커스텀 플러그인을 개발하지 않아도 되서 속도가 크게 중요하지 않거나 라이브러리가 필요한게 아니라면 그자리에서 코드를 작성하여 사용하고 있습니다.

ruby 필터

Configuration Options

SettingInput typeRequiredDescription
codestringNo코드는 매 이벤트마다 실행됩니다.
각 이벤트마다 실행할 코드를 설정합니다.
이벤트 자체를 나타내는 event 변수를 사용할 수 있습니다.
이 설정은 path와 함께 사용할 수 없습니다.
initstringNoLogstash 시작 시 실행할 코드를 설정합니다.
pathstringNo이 설정은 code와 함께 사용할 수 없습니다.
필터 메서드를 구현하는 Ruby 스크립트 파일의 경로를 설정합니다.
script_paramshash, {}Nopath에 정의된 Ruby 스크립트 파일의 register 메서드에 전달되는 매개 변수의 키/값 해시입니다.
tag_on_exceptionstring, _rubyexceptionNoRuby 코드(인라인 또는 파일 기반)에서 예외가 발생할 경우 이벤트에 추가할 태그입니다.
tag_with_exception_messageboolean, _falseNotrue로 설정하면 예외 메시지와 결합된 태그를 이벤트에 추가합니다.

code

event API

codeevent API를 통해서 event의 값을 조작할 수 있습니다.

Syntax: event.set(field, value)

filter{
  ruby {
    code => '
      event.set("foo", "baz")
      event.set("[foo]", "zab")
      event.set("[foo][bar]", 1)
      event.set("[foo][bar]", 1.0)
      event.set("[foo][bar]", [1, 2, 3])
      event.set("[foo][bar]", {"a" => 1, "b" => 2})
      event.set("[foo][bar]", {"a" => 1, "b" => 2, "c" => [1, 2]})
      event.set("[@metadata][foo]", "baz")
    '
  }
}

Syntax: event.get(field)

filter{
  ruby {
    code => '
      event.get("foo" ) # => "baz"
      event.get("[foo]") # => "zab"
      event.get("[foo][bar]") # => 1
      event.get("[foo][bar]") # => 1.0
      event.get("[foo][bar]") # =>  [1, 2, 3]
      event.get("[foo][bar]") # => {"a" => 1, "b" => 2}
      event.get("[foo][bar]") # =>  {"a" => 1, "b" => 2, "c" => [1, 2]}
   '
  }
}

init

init은 logstash가 실행될 때 같이 실행됩니다.
ruby에서 필요한 라이브러리를 미리 선언하거나, 함수를 정의하는데 사용하면 좋습니다.
이 부분에 미리 사용할 함수를 정의하면 code에서 각 event마다 실행되는 것에 비해 속도에서 이점을 갖습니다.

filter {
  if [boarding_time] {
    date {
      match => ["boarding_time", "yyyyMMddHHmmss"]
      target => "@boarding_timestamp"
    }
    ruby {
      init => '
        class TimestampConverter
          def self.convert_to_unix_timestamp(timestamp)
            if timestamp
              timestamp_str = timestamp.to_s
              ms = timestamp_str[-4..-2].to_i
              (timestamp.to_i * 1000) + ms
            end
          end
        end
      '
      code => '
        boarding_timestamp = event.get("@boarding_timestamp")
        event.set("@boarding_time", boarding_timestamp.to_i) if boarding_timestamp

        timestamp = event.get("@timestamp")
        unix_timestamp = TimestampConverter.convert_to_unix_timestamp(timestamp)
        event.set("@unix_timestamp", unix_timestamp) if unix_timestamp
      '
    }
  }
}

tag_on_exception, tag_with_exception_message

ruby filter에서 코드 실행을 실패하는 경우를 고려할 수도 있습니다.

filter {
  if [boarding_time] {
    date {
      match => ["boarding_time", "yyyyMMddHHmmss"]
      target => "@boarding_timestamp"
    }
    ruby {
      init => '
        class TimestampConverter
          def self.convert_to_unix_timestamp(timestamp)
            begin
              if timestamp
                timestamp_str = timestamp.to_s
                ms = timestamp_str[-4..-2].to_i
                (timestamp.to_i * 1000) + ms  
              end
            rescue StandardError => e
              raise e  # 예외를 다시 발생시켜 필터의 tag_on_exception으로 처리
            end
          end
        end
      '
      code => '
        boarding_timestamp = event.get("@boarding_timestamp")
        event.set("@boarding_time", boarding_timestamp.to_i) if boarding_timestamp

        timestamp = event.get("@timestamp")
        unix_timestamp = TimestampConverter.convert_to_unix_timestamp(timestamp)
        
        if unix_timestamp.nil?
          @logger.warn("Failed to convert timestamp to Unix timestamp: #{timestamp}")
        else
          event.set("@unix_timestamp", unix_timestamp)
        end
      '
      tag_on_exception => "timestamp_conversion_error"  # 예외 발생 시 추가할 태그
      tag_with_exception_message => true  # 예외 메시지를 태그에 포함
    }
  }
}
profile
책 읽고 운동하기

0개의 댓글