Logstash 필터 elapsed

특정 작업의 생성부터 소멸까지의 수명 주기가 jobID라는 식별자로 구분되는 로그가 있다. 하나의 작업에 소요된 시간을 구해보자. 마지막 작업이 실행된 시간에서 최초 작업 실행 시간을 빼면 된다.

1
2
[08:00:37.410] SendJob(jobID:75343414529)
[08:00:39.235] SendReport(jobID:75343414529)

근데 어떻게 하지? 가장 간단한 방법은 서로 다른 시점에 발생한 두 로그 간의 시간차를 계산해주는 로그스태시 필터 플러그인 elapsed를 사용하는 것. 다음은 파이프라인 설정. 작업을 시작할 때는 send_begin, 작업이 끝날 때는 send_end 태그를 추가했으며, elapsed 플러그인은 해당 태그를 이용해서 계산이 필요한 시간대의 시작과 끝을 결정한다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
input {
 file {
  path => "D:/test.log"
  start_position => "beginning"
  sincedb_path => "nul"
 }
}
‌
filter {
 dissect {
  mapping => { "message" => "[%{timestamp}] %{info}jobID:%{jobid})" }
  remove_field => [ "path", "host", "@version", "message" ]
 }
‌
 date { 
  match => [ "timestamp", "HH:mm:ss.SSS" ]
  remove_field => "timestamp" 
 }
‌
 if "SendJob" in [info] {
  mutate { add_tag => "send_begin" }
 } else {
  mutate { add_tag => "send_end" }
 }
‌
 elapsed {
  unique_id_field => "jobid"
  start_tag => "send_begin"
  end_tag => "send_end"
 }
}
‌
output {
 stdout {}
}

다음은 실행 결과. 작업이 끝났음을 알리는 send_end 태그가 달린 로그에 두 로그 간 시간차가 기록된 elapsed_time 필드가 추가된다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
PS D:\ELK\logstash-7.5.2\bin> .\logstash -f d:\test.conf
Thread.exclusive is deprecated, use Thread::Mutex
Sending Logstash logs to D:/ELK/logstash-7.5.2/logs which is now configured via log4j2.properties
[2020-02-11T21:56:05,761][WARN ][logstash.config.source.multilocal] Ignoring the 'pipelines.yml' file because modules or command line options are specified
[2020-02-11T21:56:05,906][INFO ][logstash.runner ] Starting Logstash {"logstash.version"=>"7.5.2"}
[2020-02-11T21:56:08,942][INFO ][org.reflections.Reflections] Reflections took 33 ms to scan 1 urls, producing 20 keys and 40 values
[2020-02-11T21:56:11,792][INFO ][logstash.filters.elapsed ][main] Elapsed, timeout: 1800 seconds
[2020-02-11T21:56:11,945][WARN ][org.logstash.instrument.metrics.gauge.LazyDelegatingGauge][main] A gauge metric of an unknown type (org.jruby.RubyArray) has been create for key: cluster_uuids. This may result in invalid serialization. It is recommended to log an issue to the responsible developer/development team.
[2020-02-11T21:56:11,955][INFO ][logstash.javapipeline ][main] Starting pipeline {:pipeline_id=>"main", "pipeline.workers"=>1, "pipeline.batch.size"=>125, "pipeline.batch.delay"=>50, "pipeline.max_inflight"=>125, "pipeline.sources"=>["d:/test.conf"], :thread=>"#"}
[2020-02-11T21:56:12,604][INFO ][logstash.javapipeline ][main] Pipeline started {"pipeline.id"=>"main"}
[2020-02-11T21:56:12,691][INFO ][logstash.agent ] Pipelines running {:count=>1, :running_pipelines=>[:main], :non_running_pipelines=>[]}
[2020-02-11T21:56:12,695][INFO ][filewatch.observingtail ][main] START, creating Discoverer, Watch with file and sincedb collections
[2020-02-11T21:56:13,196][INFO ][logstash.agent ] Successfully started Logstash API endpoint {:port=>9601}
D:/ELK/logstash-7.5.2/vendor/bundle/jruby/2.5.0/gems/awesome_print-1.7.0/lib/awesome_print/formatters/base_formatter.rb:31: warning: constant ::Fixnum is deprecated
{
                   "tags" => [
                 [0] "send_begin"
               ],
                  "jobid" => "75343414529",
             "@timestamp" => 2019-12-31T23:00:37.410Z,
                   "info" => "SendJob("
}
{
           "elapsed_time" => 1.825,
                   "tags" => [
                 [0] "send_end",
                 [1] "elapsed",
                 [2] "elapsed_match"
               ],
"elapsed_timestamp_start" => 2019-12-31T23:00:37.410Z,
                  "jobid" => "75343414529",
             "@timestamp" => 2019-12-31T23:00:39.235Z,
                   "info" => "SendReport("
}

그런데 요거 쓸만하겠다란 생각을 할 때쯤 시간차를 계산하지 못하는 상황이 발생한다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
{
                  "tags" => [
                [0] "send_begin"
              ],
                 "jobid" => "75343414529",
            "@timestamp" => 2019-12-31T23:00:37.410Z,
                  "info" => "SendJob("
}
{
                  "tags" => [
                [0] "send_end",
                [1] "elapsed_end_without_start"
              ],
                 "jobid" => "75343414529",
            "@timestamp" => 2019-12-31T23:00:39.235Z,
                  "info" => "SendReport("
}

대략 대여섯 번에 한 번 꼴로 시간차를 계산하지 못한다. 왜 그럴까? 혹시나 싶어 '-w' 옵션으로 CPU 코어를 1개로 제한했더니 시간차를 구하지 못하는 상황이 사라진다.

1
PS D:\ELK\logstash-7.5.2\bin> .\logstash -f d:\test.conf -w 1

로그스태시는 코어를 전부 사용하는데, 코어별로 로그를 처리하는 과정에서 순서가 뒤섞일 수 있다. 그래서 멀티 코어 환경에서는 로그 간 관계를 이용한 처리 시 거의 반드시 오류가 발생한다(..)

로그양이 많지 않아서 싱글 코어로도 충분히 처리 가능하다면 해피엔딩. 그렇지 않다면 멀티 코어 환경에서 처리 순서 정렬 문제가 해결될 때까지는 로그스태시 대신 애플리케이션을 따로 개발하는 게 나을 듯. 참고로 해당 플러그인은 기본 포함되어 있지 않기 때문에 별도 설치가 필요하다.

1
2
3
4
PS D:\ELK\logstash-7.5.2\bin> .\logstash-plugin install logstash-filter-elapsed
Validating logstash-filter-elapsed
Installing logstash-filter-elapsed
Installation successful

Popit은 페이스북 댓글만 사용하고 있습니다. 페이스북 로그인 후 글을 보시면 댓글이 나타납니다.