fluent-plugin-elasticsearch-stats 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,42 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Fluent
4
+ module Plugin
5
+ module ElasticsearchStats
6
+ module Utils
7
+ def self.hash_flatten_keys(hash, overwite: false, separator: nil)
8
+ return nil unless hash.is_a?(Hash)
9
+
10
+ flattened = {}
11
+ stack = [hash.each]
12
+ keys = []
13
+
14
+ while stack.any?
15
+ current = stack.pop
16
+
17
+ begin
18
+ child_k, child_v = current.next
19
+ stack.push current
20
+
21
+ if child_v.is_a?(Hash)
22
+ stack.push child_v.each
23
+ keys.push child_k
24
+ else
25
+ flattened_key = keys + [child_k]
26
+ flattened_key = flattened_key.join(separator) if separator
27
+ raise KeyError, "key #{flattened_key} already present" if !overwite && flattened.key?(flattened_key)
28
+
29
+ flattened[flattened_key] = child_v
30
+ end
31
+ rescue StopIteration
32
+ keys.pop
33
+ next
34
+ end
35
+ end
36
+
37
+ flattened
38
+ end
39
+ end
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,13 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'elasticsearch_stats/client'
4
+ require_relative 'elasticsearch_stats/metadata'
5
+ require_relative 'elasticsearch_stats/metric'
6
+ require_relative 'elasticsearch_stats/collector'
7
+ require_relative 'elasticsearch_stats/base_data'
8
+ require_relative 'elasticsearch_stats/cluster_health_data'
9
+ require_relative 'elasticsearch_stats/cluster_stats_data'
10
+ require_relative 'elasticsearch_stats/nodes_stats_data'
11
+ require_relative 'elasticsearch_stats/indices_stats_data'
12
+ require_relative 'elasticsearch_stats/dangling_data'
13
+ require_relative 'elasticsearch_stats/utils'
@@ -0,0 +1,191 @@
1
+ # frozen_string_literal: true
2
+
3
+ #
4
+ # Copyright 2024- Thomas Tych
5
+ #
6
+ # Licensed under the Apache License, Version 2.0 (the "License");
7
+ # you may not use this file except in compliance with the License.
8
+ # You may obtain a copy of the License at
9
+ #
10
+ # http://www.apache.org/licenses/LICENSE-2.0
11
+ #
12
+ # Unless required by applicable law or agreed to in writing, software
13
+ # distributed under the License is distributed on an "AS IS" BASIS,
14
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15
+ # See the License for the specific language governing permissions and
16
+ # limitations under the License.
17
+
18
+ require 'fluent/plugin/input'
19
+
20
+ require_relative 'elasticsearch_stats'
21
+
22
+ module Fluent
23
+ module Plugin
24
+ class ElasticsearchStatsInput < Fluent::Plugin::Input
25
+ NAME = 'elasticsearch_stats'
26
+ Fluent::Plugin.register_input(NAME, self)
27
+
28
+ helpers :event_emitter, :timer
29
+
30
+ DEFAULT_TAG = NAME
31
+ DEFAULT_URLS = ['http://localhost:9200'].freeze
32
+ DEFAULT_TIMEOUT = 10
33
+ DEFAULT_USER_AGENT = NAME
34
+
35
+ DEFAULT_INTERVAL = 300
36
+
37
+ DEFAULT_TIMESTAMP_FORMAT = :iso
38
+
39
+ DEFAULT_CLUSTER_HEALTH = true
40
+ DEFAULT_CLUSTER_HEALTH_LEVEL = :cluster
41
+ DEFAULT_CLUSTER_HEALTH_LOCAL = false
42
+ DEFAULT_CLUSTER_STATS = true
43
+ DEFAULT_NODES_STATS = true
44
+ DEFAULT_NODES_STATS_LEVEL = :node
45
+ DEFAULT_NODES_STATS_METRICS = nil
46
+ DEFAULT_INDICES_STATS = true
47
+ DEFAULT_INDICES_STATS_LEVEL = :indices
48
+ DEFAULT_INDICES = nil
49
+ DEFAULT_SHARDS_STATS = true
50
+ DEFAULT_DANGLING = false
51
+ DEFAULT_INDEX_BASE_PATTERN = nil # '/(.*)/'
52
+ DEFAULT_INDEX_BASE_REPLACEMENT = '\1'
53
+ DEFAULT_EVENT_NAME_SEPARATOR = '/'
54
+ DEFAULT_SKIP_SYSTEM_INDICES = true
55
+
56
+ ALLOWED_CLUSTER_HEALTH_LEVELS = Fluent::Plugin::ElasticsearchStats::Client::ALLOWED_CLUSTER_HEALTH_LEVELS
57
+ ALLOWED_NODES_STATS_LEVELS = Fluent::Plugin::ElasticsearchStats::Client::ALLOWED_NODES_STATS_LEVELS
58
+ ALLOWED_INDICES_STATS_LEVELS = Fluent::Plugin::ElasticsearchStats::Client::ALLOWED_INDICES_LEVELS
59
+
60
+ desc 'tag to emit events on'
61
+ config_param :tag, :string, default: DEFAULT_TAG
62
+ desc 'list or urls to poll'
63
+ config_param :urls, :array, value_type: :string, default: DEFAULT_URLS
64
+ desc 'request timeout'
65
+ config_param :timeout, :integer, default: DEFAULT_TIMEOUT
66
+ desc 'username for basic auth'
67
+ config_param :username, :string, default: nil
68
+ desc 'password for basic auth'
69
+ config_param :password, :string, default: nil
70
+ desc 'request user agent'
71
+ config_param :user_agent, :string, default: DEFAULT_USER_AGENT
72
+ desc 'CA cert file to use for request'
73
+ config_param :ca_file, :string, default: nil
74
+ desc 'option to verify certificate/host'
75
+ config_param :verify_ssl, :bool, default: true
76
+
77
+ desc 'interval for probe execution'
78
+ config_param :interval, :time, default: DEFAULT_INTERVAL
79
+
80
+ desc 'prefix for metric fields'
81
+ config_param :metric_prefix, :string, default: nil
82
+ desc 'prefix for metadata fields'
83
+ config_param :metadata_prefix, :string, default: nil
84
+ desc 'event timestamp format'
85
+ config_param :timestamp_format, :enum, list: %i[iso epochmillis], default: DEFAULT_TIMESTAMP_FORMAT
86
+ desc 'event name separator'
87
+ config_param :event_name_separator, :string, default: DEFAULT_EVENT_NAME_SEPARATOR
88
+
89
+ desc 'collect cluster health events'
90
+ config_param :cluster_health, :bool, default: DEFAULT_CLUSTER_HEALTH
91
+ desc 'details level of the health information'
92
+ config_param :cluster_health_level, :enum, list: ALLOWED_CLUSTER_HEALTH_LEVELS,
93
+ default: DEFAULT_CLUSTER_HEALTH_LEVEL
94
+ desc 'retrieves information from the local node only'
95
+ config_param :cluster_health_local, :bool, default: DEFAULT_CLUSTER_HEALTH_LOCAL
96
+
97
+ desc 'collect cluster stats events'
98
+ config_param :cluster_stats, :bool, default: DEFAULT_CLUSTER_STATS
99
+
100
+ desc 'collect nodes stats events'
101
+ config_param :nodes_stats, :bool, default: DEFAULT_NODES_STATS
102
+ desc 'details level for the nodes stats'
103
+ config_param :nodes_stats_level, :enum, list: ALLOWED_NODES_STATS_LEVELS, default: DEFAULT_NODES_STATS_LEVEL
104
+ desc 'limits information to specific metrics for nodes stats'
105
+ config_param :nodes_stats_metrics, :array, value_type: :string, default: DEFAULT_NODES_STATS_METRICS
106
+
107
+ desc 'enable indices_stats collect'
108
+ config_param :indices_stats, :bool, default: DEFAULT_INDICES_STATS
109
+ desc 'indices_stats indices to collect'
110
+ config_param :indices, :array, value_type: :string, default: DEFAULT_INDICES
111
+ desc 'indices_stats details level'
112
+ config_param :indices_stats_level, :enum, list: ALLOWED_INDICES_STATS_LEVELS, default: DEFAULT_INDICES_STATS_LEVEL
113
+
114
+ desc 'collect dangling events'
115
+ config_param :dangling, :bool, default: DEFAULT_DANGLING
116
+
117
+ desc 'base index pattern to generate aggregated index metrics'
118
+ config_param :index_base_pattern, :regexp, default: DEFAULT_INDEX_BASE_PATTERN
119
+ desc 'base index pattern replacement to generate aggregated index metrics'
120
+ config_param :index_base_replacement, :string, default: DEFAULT_INDEX_BASE_REPLACEMENT
121
+
122
+ # desc 'skip system indices'
123
+ # config_param :skip_system_indices, :bool, default: DEFAULT_SKIP_SYSTEM_INDICES
124
+
125
+ def configure(conf)
126
+ super
127
+
128
+ raise Fluent::ConfigError, 'tag should not be empty' if tag.empty?
129
+ raise Fluent::ConfigError, 'urls should not be empty' if urls.empty?
130
+
131
+ @mutex_emit = Mutex.new
132
+
133
+ ElasticsearchStats::Metadata.metadata_prefix = metadata_prefix
134
+ ElasticsearchStats::Metric.metric_prefix = metric_prefix
135
+ ElasticsearchStats::Metric.timestamp_format = timestamp_format
136
+ ElasticsearchStats::Metric.index_base_pattern = index_base_pattern
137
+ ElasticsearchStats::Metric.index_base_replacement = index_base_replacement
138
+ ElasticsearchStats::Metric.name_separator = event_name_separator
139
+
140
+ configure_elasticsearchs
141
+ end
142
+
143
+ def configure_elasticsearchs
144
+ @elasticsearchs = []
145
+ urls.each do |url|
146
+ client = ElasticsearchStats::Client.new(
147
+ url: url, timeout: timeout, username: username, password: password,
148
+ user_agent: user_agent, ca_file: ca_file, verify_ssl: verify_ssl,
149
+ log: log
150
+ )
151
+ @elasticsearchs << ElasticsearchStats::Collector.new(
152
+ client: client,
153
+ stats_config: self,
154
+ log: log
155
+ )
156
+ end
157
+ end
158
+
159
+ def start
160
+ super
161
+
162
+ timer_execute(:execute_collect_first, 1, repeat: false, &method(:execute_collect)) if interval > 60
163
+
164
+ timer_execute(:execute_collect, interval, repeat: true, &method(:execute_collect))
165
+ end
166
+
167
+ def execute_collect
168
+ threads = []
169
+ @elasticsearchs.each do |elasticsearch|
170
+ threads << Thread.new do
171
+ metrics = elasticsearch.collect_stats_metrics
172
+ events = MultiEventStream.new(
173
+ [Fluent::EventTime.now] * metrics.size,
174
+ metrics
175
+ )
176
+ emit_events(events)
177
+ end
178
+ end
179
+ threads.each(&:join)
180
+ end
181
+
182
+ def emit_events(events)
183
+ return if !events || events.empty?
184
+
185
+ @mutex_emit.synchronize do
186
+ router.emit_stream(tag, events)
187
+ end
188
+ end
189
+ end
190
+ end
191
+ end
metadata ADDED
@@ -0,0 +1,253 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: fluent-plugin-elasticsearch-stats
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Thomas Tych
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2024-03-14 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: bump
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: 0.10.0
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: 0.10.0
27
+ - !ruby/object:Gem::Dependency
28
+ name: bundler
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: 2.5.6
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: 2.5.6
41
+ - !ruby/object:Gem::Dependency
42
+ name: byebug
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '11.1'
48
+ - - ">="
49
+ - !ruby/object:Gem::Version
50
+ version: 11.1.3
51
+ type: :development
52
+ prerelease: false
53
+ version_requirements: !ruby/object:Gem::Requirement
54
+ requirements:
55
+ - - "~>"
56
+ - !ruby/object:Gem::Version
57
+ version: '11.1'
58
+ - - ">="
59
+ - !ruby/object:Gem::Version
60
+ version: 11.1.3
61
+ - !ruby/object:Gem::Dependency
62
+ name: rake
63
+ requirement: !ruby/object:Gem::Requirement
64
+ requirements:
65
+ - - "~>"
66
+ - !ruby/object:Gem::Version
67
+ version: 13.1.0
68
+ type: :development
69
+ prerelease: false
70
+ version_requirements: !ruby/object:Gem::Requirement
71
+ requirements:
72
+ - - "~>"
73
+ - !ruby/object:Gem::Version
74
+ version: 13.1.0
75
+ - !ruby/object:Gem::Dependency
76
+ name: reek
77
+ requirement: !ruby/object:Gem::Requirement
78
+ requirements:
79
+ - - "~>"
80
+ - !ruby/object:Gem::Version
81
+ version: '6.1'
82
+ - - ">="
83
+ - !ruby/object:Gem::Version
84
+ version: 6.1.4
85
+ type: :development
86
+ prerelease: false
87
+ version_requirements: !ruby/object:Gem::Requirement
88
+ requirements:
89
+ - - "~>"
90
+ - !ruby/object:Gem::Version
91
+ version: '6.1'
92
+ - - ">="
93
+ - !ruby/object:Gem::Version
94
+ version: 6.1.4
95
+ - !ruby/object:Gem::Dependency
96
+ name: rubocop
97
+ requirement: !ruby/object:Gem::Requirement
98
+ requirements:
99
+ - - "~>"
100
+ - !ruby/object:Gem::Version
101
+ version: '1.56'
102
+ type: :development
103
+ prerelease: false
104
+ version_requirements: !ruby/object:Gem::Requirement
105
+ requirements:
106
+ - - "~>"
107
+ - !ruby/object:Gem::Version
108
+ version: '1.56'
109
+ - !ruby/object:Gem::Dependency
110
+ name: rubocop-rake
111
+ requirement: !ruby/object:Gem::Requirement
112
+ requirements:
113
+ - - "~>"
114
+ - !ruby/object:Gem::Version
115
+ version: 0.6.0
116
+ type: :development
117
+ prerelease: false
118
+ version_requirements: !ruby/object:Gem::Requirement
119
+ requirements:
120
+ - - "~>"
121
+ - !ruby/object:Gem::Version
122
+ version: 0.6.0
123
+ - !ruby/object:Gem::Dependency
124
+ name: simplecov
125
+ requirement: !ruby/object:Gem::Requirement
126
+ requirements:
127
+ - - "~>"
128
+ - !ruby/object:Gem::Version
129
+ version: 0.22.0
130
+ type: :development
131
+ prerelease: false
132
+ version_requirements: !ruby/object:Gem::Requirement
133
+ requirements:
134
+ - - "~>"
135
+ - !ruby/object:Gem::Version
136
+ version: 0.22.0
137
+ - !ruby/object:Gem::Dependency
138
+ name: test-unit
139
+ requirement: !ruby/object:Gem::Requirement
140
+ requirements:
141
+ - - "~>"
142
+ - !ruby/object:Gem::Version
143
+ version: 3.6.1
144
+ type: :development
145
+ prerelease: false
146
+ version_requirements: !ruby/object:Gem::Requirement
147
+ requirements:
148
+ - - "~>"
149
+ - !ruby/object:Gem::Version
150
+ version: 3.6.1
151
+ - !ruby/object:Gem::Dependency
152
+ name: timecop
153
+ requirement: !ruby/object:Gem::Requirement
154
+ requirements:
155
+ - - "~>"
156
+ - !ruby/object:Gem::Version
157
+ version: 0.9.6
158
+ type: :development
159
+ prerelease: false
160
+ version_requirements: !ruby/object:Gem::Requirement
161
+ requirements:
162
+ - - "~>"
163
+ - !ruby/object:Gem::Version
164
+ version: 0.9.6
165
+ - !ruby/object:Gem::Dependency
166
+ name: faraday
167
+ requirement: !ruby/object:Gem::Requirement
168
+ requirements:
169
+ - - "~>"
170
+ - !ruby/object:Gem::Version
171
+ version: '2.9'
172
+ type: :runtime
173
+ prerelease: false
174
+ version_requirements: !ruby/object:Gem::Requirement
175
+ requirements:
176
+ - - "~>"
177
+ - !ruby/object:Gem::Version
178
+ version: '2.9'
179
+ - !ruby/object:Gem::Dependency
180
+ name: fluentd
181
+ requirement: !ruby/object:Gem::Requirement
182
+ requirements:
183
+ - - ">="
184
+ - !ruby/object:Gem::Version
185
+ version: 0.14.10
186
+ - - "<"
187
+ - !ruby/object:Gem::Version
188
+ version: '2'
189
+ type: :runtime
190
+ prerelease: false
191
+ version_requirements: !ruby/object:Gem::Requirement
192
+ requirements:
193
+ - - ">="
194
+ - !ruby/object:Gem::Version
195
+ version: 0.14.10
196
+ - - "<"
197
+ - !ruby/object:Gem::Version
198
+ version: '2'
199
+ description:
200
+ email:
201
+ - thomas.tych@gmail.com
202
+ executables: []
203
+ extensions: []
204
+ extra_rdoc_files: []
205
+ files:
206
+ - ".gitignore"
207
+ - ".gitlab-ci.yml"
208
+ - ".rubocop.yml"
209
+ - ".ruby-version"
210
+ - Gemfile
211
+ - Gemfile.lock
212
+ - LICENSE
213
+ - README.md
214
+ - Rakefile
215
+ - fluent-plugin-elasticsearch-stats.gemspec
216
+ - lib/fluent/plugin/elasticsearch_stats.rb
217
+ - lib/fluent/plugin/elasticsearch_stats/base_data.rb
218
+ - lib/fluent/plugin/elasticsearch_stats/client.rb
219
+ - lib/fluent/plugin/elasticsearch_stats/cluster_health_data.rb
220
+ - lib/fluent/plugin/elasticsearch_stats/cluster_stats_data.rb
221
+ - lib/fluent/plugin/elasticsearch_stats/collector.rb
222
+ - lib/fluent/plugin/elasticsearch_stats/dangling_data.rb
223
+ - lib/fluent/plugin/elasticsearch_stats/indices_stats_data.rb
224
+ - lib/fluent/plugin/elasticsearch_stats/metadata.rb
225
+ - lib/fluent/plugin/elasticsearch_stats/metric.rb
226
+ - lib/fluent/plugin/elasticsearch_stats/nodes_stats_data.rb
227
+ - lib/fluent/plugin/elasticsearch_stats/utils.rb
228
+ - lib/fluent/plugin/in_elasticsearch_stats.rb
229
+ homepage: https://gitlab.com/ttych/fluent-plugin-elasticsearch-status
230
+ licenses:
231
+ - Apache-2.0
232
+ metadata:
233
+ rubygems_mfa_required: 'true'
234
+ post_install_message:
235
+ rdoc_options: []
236
+ require_paths:
237
+ - lib
238
+ required_ruby_version: !ruby/object:Gem::Requirement
239
+ requirements:
240
+ - - ">="
241
+ - !ruby/object:Gem::Version
242
+ version: 2.4.0
243
+ required_rubygems_version: !ruby/object:Gem::Requirement
244
+ requirements:
245
+ - - ">="
246
+ - !ruby/object:Gem::Version
247
+ version: '0'
248
+ requirements: []
249
+ rubygems_version: 3.5.6
250
+ signing_key:
251
+ specification_version: 4
252
+ summary: fluentd plugin to generate elasticsearch cluster stats events.
253
+ test_files: []