運(yùn)行 Logstash 時(shí),它會(huì)自動(dòng)捕獲可用于監(jiān)視Logstash部署的運(yùn)行狀況和性能的運(yùn)行時(shí)指標(biāo)。
Logstash 收集的指標(biāo)包括:
- Logstash 節(jié)點(diǎn)信息,如配置信息,OS 信息和 JVM 信息;
- 插件信息,包括已安裝插件的列表;
- 節(jié)點(diǎn)統(tǒng)計(jì)信息,如 JVM 統(tǒng)計(jì)信息,進(jìn)程統(tǒng)計(jì)信息,事件相關(guān)(event-related)統(tǒng)計(jì)信息和流水線運(yùn)行時(shí)(pipeline runtime)統(tǒng)計(jì)信息;
- 熱線程;
我們可以使用 X-Pack 中的monitoring UI 來(lái)查看這些指標(biāo),深入了解 Logstash 如何運(yùn)行,或者可以使用 Logstash 提供的基本監(jiān)視 API 來(lái)檢索這些指標(biāo)。對(duì)于我灣,調(diào)研確定采用 searchguard 作為核心安全插件,所以不會(huì)為了一個(gè)無(wú)法整合到監(jiān)控平臺(tái)的 X-Pack monitoring 功能而去引入,我決定直接走 API 的方式提供指標(biāo)數(shù)據(jù)。
監(jiān)控 API 介紹
Logstash提供以下監(jiān)視API來(lái)檢索有關(guān)Logstash的運(yùn)行時(shí)指標(biāo):
- 節(jié)點(diǎn)信息API
- 插件信息API
- 節(jié)點(diǎn)統(tǒng)計(jì)API
- 熱線程API
您可以使用根資源來(lái)檢索有關(guān)Logstash實(shí)例的一般信息,包括主機(jī)和版本。
curl -XGET 'localhost:9600/?pretty'
響應(yīng)示例:
{
"host": "skywalker",
"version": "5.5.0",
"http_address": "127.0.0.1:9600"
}
默認(rèn)情況下,監(jiān)視 API 嘗試綁定到 tcp:9600。如果此端口已被另一個(gè) Logstash 實(shí)例使用,則需要使用指定的—http.port 標(biāo)志啟動(dòng) Logstash 以綁定到其他端口。有關(guān)詳細(xì)信息,請(qǐng)參閱命令行標(biāo)志。
通用選項(xiàng)
以下選項(xiàng)可以應(yīng)用于所有 Logstash 監(jiān)控 API。
- Pretty 式返回
當(dāng)對(duì)任何請(qǐng)求進(jìn)行追加 ?pretty=true
時(shí),返回的 JSON 將被格式化展示(僅用于調(diào)試);
- Human-Readable 式輸出
對(duì)于Logstash 5.5.0,只有 Hot Threads API 支持該選項(xiàng)。當(dāng)指定
human=true
時(shí),結(jié)果將以純文本而不是 JSON 格式返回。默認(rèn)值為false。
統(tǒng)計(jì)信息會(huì)以適合人類閱讀的格式(例如 "exists_time": "1h"
or "size": "1kb"
)和計(jì)算機(jī)適合解釋處理的格式(例如 "exists_time_in_millis": 3600000
or "size_in_bytes": 1024
)返回。可以通過(guò)向查詢字符串添加 ?human=false
來(lái)關(guān)閉。當(dāng)統(tǒng)計(jì)數(shù)據(jù)的結(jié)果被監(jiān)視工具消費(fèi)時(shí),而不是為人類消費(fèi)而言,這是有道理的。human 標(biāo)識(shí)位默認(rèn)為 false。
節(jié)點(diǎn)信息 API
該 API 用于獲取關(guān)于 logstash 節(jié)點(diǎn)的信息:
curl -XGET 'localhost:9600/_node/<types>'
<types>
是可選項(xiàng),用來(lái)指定返回哪個(gè)類型的數(shù)據(jù)。
我們可以通過(guò)以下幾種類型的組合來(lái)限制返回的信息(類型之間用逗號(hào)間隔):
類型 | 描述 |
---|---|
pipeline |
獲取 pipeline 相關(guān)的信息和配置; |
os |
獲取節(jié)點(diǎn)級(jí)別的 OS 信息; |
jvm |
獲取節(jié)點(diǎn)級(jí)別的 JVM 信息,包括線程信息; |
Pipeline 信息
以下的請(qǐng)求返回 pipeline 相關(guān)信息,包括 workers 的數(shù)量,批處理大小,以及批處理延遲:
curl -XGET 'localhost:9600/_node/pipeline?pretty'
如果想獲得更多的 pipeline 信息,比如各個(gè) input/filter/output 的信息,可以參閱 Pipeline Stats 部分。
返回示例:
{
"pipeline": {
"workers": 8,
"batch_size": 125,
"batch_delay": 5,
"config_reload_automatic": true,
"config_reload_interval": 3
"id" : "main"
}
OS 信息
以下請(qǐng)求返回關(guān)于 OS 相關(guān)信息,比如 OS 名稱、架構(gòu)、版本和可用的處理器個(gè)數(shù):
curl -XGET 'localhost:9600/_node/os?pretty'
返回示例:
{
"os": {
"name": "Mac OS X",
"arch": "x86_64",
"version": "10.12.4",
"available_processors": 8
}
JVM 信息
以下請(qǐng)求返回節(jié)點(diǎn)級(jí)別 JVM 信息,比如節(jié)點(diǎn)級(jí)別 JVM 進(jìn)程號(hào)、版本、VM 信息、內(nèi)存使用率以及 GC 信息:
curl -XGET 'localhost:9600/_node/jvm?pretty'
返回示例:
{
"jvm": {
"pid": 59616,
"version": "1.8.0_65",
"vm_name": "Java HotSpot(TM) 64-Bit Server VM",
"vm_version": "1.8.0_65",
"vm_vendor": "Oracle Corporation",
"start_time_in_millis": 1484251185878,
"mem": {
"heap_init_in_bytes": 268435456,
"heap_max_in_bytes": 1037959168,
"non_heap_init_in_bytes": 2555904,
"non_heap_max_in_bytes": 0
},
"gc_collectors": [
"ParNew",
"ConcurrentMarkSweep"
]
}
}
插件信息 API
插件信息 API 可以獲取所有已安裝的 logstash 的插件信息。該 API 是基于 bin/logstash-plugin list --verbose
命令返回的信息進(jìn)行處理后得到的。
curl -XGET 'localhost:9600/_node/plugins?pretty'
返回示例:
{
"total": 93,
"plugins": [
{
"name": "logstash-codec-cef",
"version": "4.1.2"
},
{
"name": "logstash-codec-collectd",
"version": "3.0.3"
},
{
"name": "logstash-codec-dots",
"version": "3.0.2"
},
{
"name": "logstash-codec-edn",
"version": "3.0.2"
},
.
.
.
]
節(jié)點(diǎn)狀態(tài) API
節(jié)點(diǎn)狀態(tài) API 用于獲取 logstash 運(yùn)行時(shí)的統(tǒng)計(jì)信息。
curl -XGET 'localhost:9600/_node/stats/<types>'
<types>
是可選項(xiàng),用于指定具體返回類型。
默認(rèn)情況下,所有狀態(tài)都會(huì)返回。我們可以通過(guò)各種類型組合(以逗號(hào)分隔)來(lái)過(guò)濾出我們想要的信息:
類型 | 描述 |
---|---|
jvm |
獲取 JVM 狀態(tài),包括線程信息、內(nèi)存使用率、GC 和 uptime。 |
process |
獲取進(jìn)程信息,包括文件描述符、內(nèi)存占用以及 CPU 使用率。 |
pipeline |
獲取運(yùn)行時(shí) logstash pipeline 信息。 |
reloads |
獲取運(yùn)行時(shí)配置 reload 的失敗和成功信息。 |
os |
獲取運(yùn)行時(shí)當(dāng) logstash 運(yùn)行在容器中的 cgroups 信息。 |
JVM 信息
以下請(qǐng)求返回 JVM 信息:
curl -XGET 'localhost:9600/_node/stats/jvm?pretty'
返回示例:
{
"jvm": {
"threads": {
"count": 35,
"peak_count": 36
},
"mem": {
"heap_used_in_bytes": 318691184,
"heap_used_percent": 15,
"heap_committed_in_bytes": 519045120,
"heap_max_in_bytes": 2075918336,
"non_heap_used_in_bytes": 189382304,
"non_heap_committed_in_bytes": 200728576,
"pools": {
"survivor": {
"peak_used_in_bytes": 8912896,
"used_in_bytes": 9538656,
"peak_max_in_bytes": 35782656,
"max_in_bytes": 71565312,
"committed_in_bytes": 17825792
},
"old": {
"peak_used_in_bytes": 106946320,
"used_in_bytes": 181913072,
"peak_max_in_bytes": 715849728,
"max_in_bytes": 1431699456,
"committed_in_bytes": 357957632
},
"young": {
"peak_used_in_bytes": 71630848,
"used_in_bytes": 127239456,
"peak_max_in_bytes": 286326784,
"max_in_bytes": 572653568,
"committed_in_bytes": 143261696
}
}
},
"gc": {
"collectors": {
"old": {
"collection_time_in_millis": 58,
"collection_count": 2
},
"young": {
"collection_time_in_millis": 338,
"collection_count": 26
}
}
},
"uptime_in_millis": 382701
}
進(jìn)程信息
以下請(qǐng)求返回進(jìn)程信息:
curl -XGET 'localhost:9600/_node/stats/process?pretty'
返回示例
{
"process": {
"open_file_descriptors": 164,
"peak_open_file_descriptors": 166,
"max_file_descriptors": 10240,
"mem": {
"total_virtual_in_bytes": 5399474176
},
"cpu": {
"total_in_millis": 72810537000,
"percent": 0,
"load_average": {
"1m": 2.41943359375
}
}
}
}
Pipeline 信息
以下請(qǐng)求返回 pipeline 信息,包括:
- Input/filter/output 的事件數(shù)量;
- 配置的各個(gè) filter/output 信息;
- Config reload 成功或失敗的信息(當(dāng) config reload enable 情況下);
- 持久化隊(duì)列的信息(當(dāng) persistent queues enable 情況下);
curl -XGET 'localhost:9600/_node/stats/pipeline?pretty'
返回示例:
{
"pipeline" : {
"events" : {
"duration_in_millis" : 1955,
"in" : 100,
"filtered" : 100,
"out" : 100,
"queue_push_duration_in_millis" : 71
},
"plugins" : {
"inputs" : [ {
"id" : "729b0efdc657715a4a59103ab2643c010fc46e77-1",
"events" : {
"out" : 100,
"queue_push_duration_in_millis" : 71
},
"name" : "beats"
} ],
"filters" : [ {
"id" : "729b0efdc657715a4a59103ab2643c010fc46e77-2",
"events" : {
"duration_in_millis" : 64,
"in" : 100,
"out" : 100
},
"matches" : 100,
"patterns_per_field" : {
"message" : 1
},
"name" : "grok"
} ],
"outputs" : [ {
"id" : "729b0efdc657715a4a59103ab2643c010fc46e77-3",
"events" : {
"duration_in_millis" : 1724,
"in" : 100,
"out" : 100
},
"name" : "stdout"
} ]
},
"reloads" : {
"last_error" : null,
"successes" : 2,
"last_success_timestamp" : "2017-05-25T02:40:40.974Z",
"last_failure_timestamp" : null,
"failures" : 0
},
"queue" : {
"events" : 0,
"type" : "persisted",
"capacity" : {
"page_capacity_in_bytes" : 262144000,
"max_queue_size_in_bytes" : 8589934592,
"max_unread_events" : 0
},
"data" : {
"path" : "/path/to/data/queue",
"free_space_in_bytes" : 89280552960,
"storage_type" : "hfs"
}
},
"id" : "main"
}
}
Reload 信息
以下請(qǐng)求返回配置 reload 成功和失敗的信息:
curl -XGET 'localhost:9600/_node/stats/reloads?pretty'
返回示例:
{
"reloads": {
"successes": 0,
"failures": 0
}
}
OS 信息
當(dāng) logstash 運(yùn)行在容器中時(shí),以下請(qǐng)求返回 cgroups 相關(guān)信息,我們可以從中獲取更精確的 CPU 負(fù)載,包括容器是否達(dá)到瓶頸:
curl -XGET 'localhost:9600/_node/stats/os?pretty'
返回示例:
{
"os" : {
"cgroup" : {
"cpuacct" : {
"control_group" : "/elastic1",
"usage_nanos" : 378477588075
},
"cpu" : {
"control_group" : "/elastic1",
"cfs_period_micros" : 1000000,
"cfs_quota_micros" : 800000,
"stat" : {
"number_of_elapsed_periods" : 4157,
"number_of_times_throttled" : 460,
"time_throttled_nanos" : 581617440755
}
}
}
}
熱線程 API
熱線程 API 用來(lái)獲取當(dāng)前 logstash 的熱線程信息。熱線程的定義是:該線程占用很高的 CPU并且執(zhí)行指令持續(xù)很長(zhǎng)時(shí)間。
curl -XGET 'localhost:9600/_node/hot_threads?pretty'
返回示例:
{
"time": "2017-01-12T12:09:45-08:00",
"busiest_threads": 3,
"threads": [
{
"name": "LogStash::Runner",
"percent_of_cpu_time": 1.07,
"state": "timed_waiting",
"traces": [
"java.lang.Object.wait(Native Method)",
"java.lang.Thread.join(Thread.java:1253)",
"org.jruby.internal.runtime.NativeThread.join(NativeThread.java:75)",
"org.jruby.RubyThread.join(RubyThread.java:697)",
"org.jruby.RubyThread$INVOKER$i$0$1$join.call(RubyThread$INVOKER$i$0$1$join.gen)",
"org.jruby.internal.runtime.methods.JavaMethod$JavaMethodN.call(JavaMethod.java:663)",
"org.jruby.internal.runtime.methods.DynamicMethod.call(DynamicMethod.java:198)",
"org.jruby.runtime.callsite.CachingCallSite.cacheAndCall(CachingCallSite.java:306)",
"org.jruby.runtime.callsite.CachingCallSite.call(CachingCallSite.java:136)",
"org.jruby.ast.CallNoArgNode.interpret(CallNoArgNode.java:60)"
]
},
{
"name": "[main]>worker7",
"percent_of_cpu_time": 0.71,
"state": "waiting",
"traces": [
"sun.misc.Unsafe.park(Native Method)",
"java.util.concurrent.locks.LockSupport.park(LockSupport.java:175)",
"java.util.concurrent.locks.AbstractQueuedSynchronizer.parkAndCheckInterrupt(AbstractQueuedSynchronizer.java:836)",
"java.util.concurrent.locks.AbstractQueuedSynchronizer.doAcquireInterruptibly(AbstractQueuedSynchronizer.java:897)",
"java.util.concurrent.locks.AbstractQueuedSynchronizer.acquireInterruptibly(AbstractQueuedSynchronizer.java:1222)",
"java.util.concurrent.locks.ReentrantLock.lockInterruptibly(ReentrantLock.java:335)",
"org.jruby.RubyThread.lockInterruptibly(RubyThread.java:1470)",
"org.jruby.ext.thread.Mutex.lock(Mutex.java:91)",
"org.jruby.ext.thread.Mutex.synchronize(Mutex.java:147)",
"org.jruby.ext.thread.Mutex$INVOKER$i$0$0$synchronize.call(Mutex$INVOKER$i$0$0$synchronize.gen)"
]
},
{
"name": "[main]>worker3",
"percent_of_cpu_time": 0.71,
"state": "waiting",
"traces": [
"sun.misc.Unsafe.park(Native Method)",
"java.util.concurrent.locks.LockSupport.park(LockSupport.java:175)",
"java.util.concurrent.locks.AbstractQueuedSynchronizer.parkAndCheckInterrupt(AbstractQueuedSynchronizer.java:836)",
"java.util.concurrent.locks.AbstractQueuedSynchronizer.doAcquireInterruptibly(AbstractQueuedSynchronizer.java:897)",
"java.util.concurrent.locks.AbstractQueuedSynchronizer.acquireInterruptibly(AbstractQueuedSynchronizer.java:1222)",
"java.util.concurrent.locks.ReentrantLock.lockInterruptibly(ReentrantLock.java:335)",
"org.jruby.RubyThread.lockInterruptibly(RubyThread.java:1470)",
"org.jruby.ext.thread.Mutex.lock(Mutex.java:91)",
"org.jruby.ext.thread.Mutex.synchronize(Mutex.java:147)",
"org.jruby.ext.thread.Mutex$INVOKER$i$0$0$synchronize.call(Mutex$INVOKER$i$0$0$synchronize.gen)"
]
}
]
}
}
被允許使用的參數(shù)包括:
參數(shù) | 描述 |
---|---|
threads |
返回的熱線程個(gè)數(shù),默認(rèn)為 3。 |
human |
如為 true,返回 plain text,反之則是 json,默認(rèn)是 false。 |
ignore_idle_threads |
如為 true,不返回閑置線程,默認(rèn)是 true。 |
可以使用 ?human
參數(shù)返回可讀性較高的格式。
curl -XGET 'localhost:9600/_node/hot_threads?human=true'
human-readable 返回示例:
::: {}
Hot threads at 2017-01-12T12:10:15-08:00, busiestThreads=3:
================================================================================
1.02 % of cpu usage, state: timed_waiting, thread name: 'LogStash::Runner'
java.lang.Object.wait(Native Method)
java.lang.Thread.join(Thread.java:1253)
org.jruby.internal.runtime.NativeThread.join(NativeThread.java:75)
org.jruby.RubyThread.join(RubyThread.java:697)
org.jruby.RubyThread$INVOKER$i$0$1$join.call(RubyThread$INVOKER$i$0$1$join.gen)
org.jruby.internal.runtime.methods.JavaMethod$JavaMethodN.call(JavaMethod.java:663)
org.jruby.internal.runtime.methods.DynamicMethod.call(DynamicMethod.java:198)
org.jruby.runtime.callsite.CachingCallSite.cacheAndCall(CachingCallSite.java:306)
org.jruby.runtime.callsite.CachingCallSite.call(CachingCallSite.java:136)
org.jruby.ast.CallNoArgNode.interpret(CallNoArgNode.java:60)
--------------------------------------------------------------------------------
0.71 % of cpu usage, state: waiting, thread name: '[main]>worker7'
sun.misc.Unsafe.park(Native Method)
java.util.concurrent.locks.LockSupport.park(LockSupport.java:175)
java.util.concurrent.locks.AbstractQueuedSynchronizer.parkAndCheckInterrupt(AbstractQueuedSynchronizer.java:836)
java.util.concurrent.locks.AbstractQueuedSynchronizer.doAcquireInterruptibly(AbstractQueuedSynchronizer.java:897)
java.util.concurrent.locks.AbstractQueuedSynchronizer.acquireInterruptibly(AbstractQueuedSynchronizer.java:1222)
java.util.concurrent.locks.ReentrantLock.lockInterruptibly(ReentrantLock.java:335)
org.jruby.RubyThread.lockInterruptibly(RubyThread.java:1470)
org.jruby.ext.thread.Mutex.lock(Mutex.java:91)
org.jruby.ext.thread.Mutex.synchronize(Mutex.java:147)
org.jruby.ext.thread.Mutex$INVOKER$i$0$0$synchronize.call(Mutex$INVOKER$i$0$0$synchronize.gen)
--------------------------------------------------------------------------------
0.71 % of cpu usage, state: timed_waiting, thread name: '[main]>worker3'
sun.misc.Unsafe.park(Native Method)
java.util.concurrent.locks.LockSupport.parkNanos(LockSupport.java:215)
java.util.concurrent.SynchronousQueue$TransferStack.awaitFulfill(SynchronousQueue.java:460)
java.util.concurrent.SynchronousQueue$TransferStack.transfer(SynchronousQueue.java:362)
java.util.concurrent.SynchronousQueue.poll(SynchronousQueue.java:941)
sun.reflect.GeneratedMethodAccessor6.invoke(Unknown Source)
sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
java.lang.reflect.Method.invoke(Method.java:497)
org.jruby.javasupport.JavaMethod.invokeDirectWithExceptionHandling(JavaMethod.java:466)
org.jruby.javasupport.JavaMethod.invokeDirect(JavaMethod.java:324)
參考文獻(xiàn)
https://www.elastic.co/guide/en/logstash/current/monitoring-logstash.html