logstash-filter-units 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 693aa67dfac7153254fb62cfdb716c9d108fb92c
4
+ data.tar.gz: e10a3496e7c6ae1ce57972e3981be82776a20246
5
+ SHA512:
6
+ metadata.gz: 714eec4b166ca567bf3c5440c752e01966cc1c09eb392e337d8094200dac7c98c4d8bbd53efe78284e51ddaf500fd6fbcde3e6064187391a6d3d2d48de650656
7
+ data.tar.gz: d54019094055725ccb20cc9d5bc521b0c0a543e33862d38b81c48e78872e1e420efd46ddbbad6d94ce622e6b16adef49144b3452d7c45879d1530cada29912c2
data/.gitignore ADDED
@@ -0,0 +1,11 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /Gemfile.lock
4
+ /_yardoc/
5
+ /coverage/
6
+ /doc/
7
+ /pkg/
8
+ /spec/reports/
9
+ /tmp/
10
+ /.DS_Store/
11
+ /vendor/
data/CONTRIBUTORS ADDED
@@ -0,0 +1,12 @@
1
+ The following is a list of people who have contributed ideas, code, bug
2
+ reports, or in general have helped logstash along its way.
3
+
4
+ Contributors:
5
+ * Alex Braun (Alex.Braun.VFX@gmail.com)
6
+ * Chad Dombrova (ChadD@luma-pictures.com)
7
+ * Chris Lyon (ChrisL@luma-pictures.com)
8
+
9
+ Note: If you've sent us patches, bug reports, or otherwise contributed to
10
+ Logstash, and you aren't on the list above and want to be, please let us know
11
+ and we'll make sure you're here. Contributions from folks like you are what make
12
+ open source awesome.
data/Gemfile ADDED
@@ -0,0 +1,12 @@
1
+ source 'http://rubygems.org'
2
+ # gem 'treetop'
3
+ # gem 'jrjackson'
4
+ # gem 'stud'
5
+ # gem 'clamp'
6
+ # gem 'i18n'
7
+ # gem 'filesize'
8
+ # gem 'cabin'
9
+ # gem 'rake'
10
+ # gem 'unitwise'
11
+ gem "logstash", :github => "elasticsearch/logstash", :branch => "1.5"
12
+ gemspec
data/LICENSE ADDED
@@ -0,0 +1,13 @@
1
+ Copyright (c) 2012-2015 Elasticsearch <http://www.elasticsearch.org>
2
+
3
+ Licensed under the Apache License, Version 2.0 (the "License");
4
+ you may not use this file except in compliance with the License.
5
+ You may obtain a copy of the License at
6
+
7
+ http://www.apache.org/licenses/LICENSE-2.0
8
+
9
+ Unless required by applicable law or agreed to in writing, software
10
+ distributed under the License is distributed on an "AS IS" BASIS,
11
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ See the License for the specific language governing permissions and
13
+ limitations under the License.
data/README.md ADDED
@@ -0,0 +1,86 @@
1
+ # Logstash Plugin
2
+
3
+ This is a plugin for [Logstash](https://github.com/elasticsearch/logstash).
4
+
5
+ It is fully free and fully open source. The license is Apache 2.0, meaning you are pretty much free to use it however you want in whatever way.
6
+
7
+ ## Documentation
8
+
9
+ Logstash provides infrastructure to automatically generate documentation for this plugin. We use the asciidoc format to write documentation so any comments in the source code will be first converted into asciidoc and then into html. All plugin documentation are placed under one [central location](http://www.elasticsearch.org/guide/en/logstash/current/).
10
+
11
+ - For formatting code or config example, you can use the asciidoc `[source,ruby]` directive
12
+ - For more asciidoc formatting tips, see the excellent reference here https://github.com/elasticsearch/docs#asciidoc-guide
13
+
14
+ ## Need Help?
15
+
16
+ Need help? Try #logstash on freenode IRC or the logstash-users@googlegroups.com mailing list.
17
+
18
+ ## Developing
19
+
20
+ ### 1. Plugin Developement and Testing
21
+
22
+ #### Code
23
+ - To get started, you'll need JRuby with the Bundler gem installed.
24
+
25
+ - Create a new plugin or clone and existing from the GitHub [logstash-plugins](https://github.com/logstash-plugins) organization. We also provide [example plugins](https://github.com/logstash-plugins?query=example).
26
+
27
+ - Install dependencies
28
+ ```sh
29
+ bundle install
30
+ ```
31
+
32
+ #### Test
33
+
34
+ - Update your dependencies
35
+
36
+ ```sh
37
+ bundle install
38
+ ```
39
+
40
+ - Run tests
41
+
42
+ ```sh
43
+ bundle exec rspec
44
+ ```
45
+
46
+ ### 2. Running your unpublished Plugin in Logstash
47
+
48
+ #### 2.1 Run in a local Logstash clone
49
+
50
+ - Edit Logstash `Gemfile` and add the local plugin path, for example:
51
+ ```ruby
52
+ gem "logstash-filter-awesome", :path => "/your/local/logstash-filter-awesome"
53
+ ```
54
+ - Install plugin
55
+ ```sh
56
+ bin/plugin install --no-verify
57
+ ```
58
+ - Run Logstash with your plugin
59
+ ```sh
60
+ bin/logstash -e 'filter {awesome {}}'
61
+ ```
62
+ At this point any modifications to the plugin code will be applied to this local Logstash setup. After modifying the plugin, simply rerun Logstash.
63
+
64
+ #### 2.2 Run in an installed Logstash
65
+
66
+ You can use the same **2.1** method to run your plugin in an installed Logstash by editing its `Gemfile` and pointing the `:path` to your local plugin development directory or you can build the gem and install it using:
67
+
68
+ - Build your plugin gem
69
+ ```sh
70
+ gem build logstash-filter-awesome.gemspec
71
+ ```
72
+ - Install the plugin from the Logstash home
73
+ ```sh
74
+ bin/plugin install /your/local/plugin/logstash-filter-awesome.gem
75
+ ```
76
+ - Start Logstash and proceed to test the plugin
77
+
78
+ ## Contributing
79
+
80
+ All contributions are welcome: ideas, patches, documentation, bug reports, complaints, and even something you drew up on a napkin.
81
+
82
+ Programming is not a required skill. Whatever you've seen about open source and maintainers or community members saying "send patches or die" - you will not see that here.
83
+
84
+ It is more important to the community that you are able to contribute.
85
+
86
+ For more information about contributing, see the [CONTRIBUTING](https://github.com/elasticsearch/logstash/blob/master/CONTRIBUTING.md) file.
data/Rakefile ADDED
@@ -0,0 +1 @@
1
+ require "logstash/devutils/rake"
@@ -0,0 +1,280 @@
1
+ # encoding: utf-8
2
+
3
+ require "logstash/filters/base"
4
+ require "logstash/namespace"
5
+ require "unitwise"
6
+
7
+ # The units filter is used for converting specified fields from one
8
+ # unit of measure to another (or many others).
9
+
10
+ class LogStash::Filters::Units < LogStash::Filters::Base
11
+ config_name "units"
12
+ milestone 1
13
+
14
+ config(:fields, :validate => :array, :required => true)
15
+ # The source fields to be converted
16
+ # Fields may be specified in three different ways:
17
+ # - Fields may be referenced specifically, by drilling
18
+ # down the field hierarchy using the square bracket syntax. If
19
+ # they are specified in this manner, then only the exact field
20
+ # specified will be converted.
21
+ # - Fields may also be specifed more generally simply by proving
22
+ # the field name. If done this way, the given field will convert
23
+ # any bottom level field of the same name.
24
+ # - If provided a string rather than an array of fields, the field
25
+ # provided will be converted in place rather then prepended with
26
+ # additional fields.
27
+ # Example:
28
+ # [source,ruby]
29
+ # filter {
30
+ # units {
31
+ # fields => ["top_level_field",
32
+ # "bottom_level_field",
33
+ # "[a][nested][field]"]
34
+ # output_units => ["kilobyte", "megabyte"]
35
+ # }
36
+ # }
37
+ # Example:
38
+ # [source,ruby]
39
+ # filter {
40
+ # units {
41
+ # fields => "in_place_conversion"
42
+ # output_units => ["megabyte"]
43
+ # }
44
+ # }
45
+
46
+ config(:input_unit, :validate => :string, :default => "byte")
47
+ # The unit of measure of the source fields to be converted.
48
+ # This parameter supports all units of measure specified by
49
+ # the unitwise gem.
50
+ # http://github.com/joshwlewis/unitwise
51
+ # Example:
52
+ # [source,ruby]
53
+ # filter {
54
+ # units {
55
+ # fields => ["length", "height"]
56
+ # input_unit => "millimeter"
57
+ # output_units => ["centimeter", "meter"]
58
+ # }
59
+ # }
60
+
61
+ config(:output_units, :required => true)
62
+ # The units of measure used for conversion.
63
+ # This parameter supports all units of measure specified by
64
+ # the unitwise gem.
65
+ # http://github.com/joshwlewis/unitwise
66
+ # By default, new fields will be named according to these units.
67
+ # Example:
68
+ # [source,ruby]
69
+ # filter {
70
+ # units {
71
+ # fields => ["length", "height"]
72
+ # input_unit => "millimeter"
73
+ # output_units => ["centimeter", "meter"]
74
+ # }
75
+ # }
76
+
77
+ config(:root_field, :validate => :string)
78
+ # If specified, the fields generated by the filter will be
79
+ # placed within a hierarchy mirroring that of the fields
80
+ # listed within the fields parameter, which is itself nested
81
+ # under the given root field.
82
+ # For example, with this config:
83
+ # [source,ruby]
84
+ # filter {
85
+ # units {
86
+ # fields => ["c"]
87
+ # input_unit => "byte"
88
+ # output_units => ["kilobyte", "megabyte"]
89
+ # root_field => "special"
90
+ # }
91
+ # }
92
+ #
93
+ # {
94
+ # "a" => {
95
+ # "b" => {
96
+ # "c" => 1000000
97
+ # }
98
+ # }
99
+ # }
100
+ #
101
+ # becomes
102
+ #
103
+ # {
104
+ # "a" => {
105
+ # "b" => {
106
+ # "c" => 1000000
107
+ # }
108
+ # },
109
+ # "special" => {
110
+ # "a" => {
111
+ # "b" => {
112
+ # "c" => {
113
+ # "kilobyte" => 1000,
114
+ # "megabyte" => 1
115
+ # }
116
+ # }
117
+ # }
118
+ # }
119
+ # }
120
+
121
+ config(:rename_labels, :validate => :hash, :default => {})
122
+ # Renames the resulting output fields according to a hash.
123
+ # Keys should be the output fields and values should be their
124
+ # desired names, respectively. Unamed fields will persist.
125
+ # Example:
126
+ # [source,ruby]
127
+ # filter {
128
+ # units {
129
+ # fields => ["file_size"]
130
+ # input_unit => "byte"
131
+ # output_units => ["kilobyte", "megabyte"]
132
+ # rename_labels => {
133
+ # "kilobyte" => "kB"
134
+ # "megabyte" => "mB"
135
+ # }
136
+ # }
137
+ # }
138
+
139
+ def initialize(*args)
140
+ super(*args)
141
+ end
142
+
143
+ public
144
+ def register()
145
+ end
146
+
147
+ private
148
+ def nested_hash_to_matrix(data)
149
+ @sep = '.'
150
+ @output = []
151
+ def _nested_hash_to_matrix(data, name)
152
+ data.each do |key, val|
153
+ new_key = name + @sep + key.to_s
154
+ if val.is_a?(Hash) and val != {}
155
+ _nested_hash_to_matrix(val, new_key)
156
+ else
157
+ @output.push([new_key, val])
158
+ end
159
+ end
160
+ return @output
161
+ end
162
+
163
+ @output = _nested_hash_to_matrix(data, @sep)
164
+ @output = @output.map { |key, val| [key.split('.')[2..-1], val] }
165
+ return @output
166
+ end
167
+
168
+ private
169
+ def matrix_to_nested_hash(data)
170
+ output = {}
171
+ data.each do |keys, value|
172
+ cursor = output
173
+ for key in keys[0..-2]
174
+ if !cursor.include?(key)
175
+ cursor[key] = {}
176
+ cursor = cursor[key]
177
+ else
178
+ cursor = cursor[key]
179
+ end
180
+ end
181
+ cursor[keys[-1]] = value
182
+ end
183
+ return output
184
+ end
185
+
186
+ private
187
+ def convert_to_dict(value)
188
+ # convert a single value to a hash of converted values
189
+ output = {}
190
+ for output_unit in @output_units do
191
+ output_value = convert(value, output_unit)
192
+ if @rename_labels.include?(output_unit)
193
+ output_unit = @rename_labels[output_unit]
194
+ end
195
+ output[output_unit] = output_value
196
+ end
197
+ return output
198
+ end
199
+
200
+ private
201
+ def convert(value, output_unit)
202
+ begin
203
+ return output_value = Unitwise(value, @input_unit).convert_to(output_unit).value
204
+ rescue Exception
205
+ raise StandardError
206
+ end
207
+ end
208
+
209
+ private
210
+ def field_handler(fields)
211
+ output = {"exact" => [], "partial" => []}
212
+ for field in fields
213
+ if /\[|\]/.match(field)
214
+ temp = field.split(/\]\[|^\[|\]$/)[1..-1]
215
+ output["exact"].push(temp)
216
+ else
217
+ output["partial"].push(field)
218
+ end
219
+ end
220
+ return output
221
+ end
222
+
223
+ public
224
+ def filter(event)
225
+ return unless filter?(event)
226
+ begin
227
+ # flag for converting a value in place or expanding it into
228
+ # a hash
229
+ inplace = @output_units.is_a?(String)
230
+ matrix = nested_hash_to_matrix(event.to_hash)
231
+
232
+ # convert matching fields and remove rows that
233
+ # do not contain leaf nodes that match @fields
234
+ fields = field_handler(@fields)
235
+ del = []
236
+ matrix.each do |row|
237
+ if fields["exact"].include?(row[0])
238
+ if inplace
239
+ row[1] = convert(row[1], @output_units)
240
+ else
241
+ row[1] = convert_to_dict(row[1])
242
+ end
243
+ elsif fields["partial"].include?(row[0][-1])
244
+ if inplace
245
+ row[1] = convert(row[1], @output_units)
246
+ else
247
+ row[1] = convert_to_dict(row[1])
248
+ end
249
+ else
250
+ del.push(row)
251
+ end
252
+ end
253
+ # delete all rows that do not have leaf nodes listed
254
+ # in fields
255
+ for row in del
256
+ matrix.delete(row)
257
+ end
258
+
259
+ new_hash = matrix_to_nested_hash(matrix)
260
+ if @root_field
261
+ new_hash = {@root_field => new_hash}
262
+ end
263
+
264
+ # merge new hash into event's hash
265
+ # assignment of items from new_hash with a prior merge
266
+ # will destroy unmatched branches
267
+ data = event.to_hash().merge(new_hash)
268
+ data.each do |key, value|
269
+ event[key] = value
270
+ end
271
+ return filter_matched(event)
272
+ rescue StandardError
273
+ event.tag("_unitsparsefailure")
274
+ return event
275
+ rescue Logstash::ShutdownSignal
276
+ event.cancel()
277
+ @logger.debug(e)
278
+ end
279
+ end
280
+ end
@@ -0,0 +1,26 @@
1
+ Gem::Specification.new do |s|
2
+
3
+ s.name = 'logstash-filter-units'
4
+ s.version = '0.1.0'
5
+ s.licenses = ['Apache License (2.0)']
6
+ s.summary = "A filter for performing unit conversions on specified fields."
7
+ s.description = "The units filter is used for converting specified fields from one unit of measure to another (or many others)."
8
+ s.authors = ["Alex Braun"]
9
+ s.email = 'Alex.Braun.VFX@gmail.com'
10
+ s.homepage = "http://www.elasticsearch.org/guide/en/logstash/current/index.html"
11
+ s.require_paths = ["lib"]
12
+
13
+ # Files
14
+ s.files = `git ls-files`.split($\)
15
+
16
+ # Tests
17
+ s.test_files = s.files.grep(%r{^(test|spec|features)/})
18
+
19
+ # Special flag to let us know this is actually a logstash plugin
20
+ s.metadata = { "logstash_plugin" => "true", "logstash_group" => "filter" }
21
+
22
+ # Gem dependencies
23
+ s.add_runtime_dependency "logstash", '>= 1.4.0', '< 2.0.0'
24
+ s.add_runtime_dependency "unitwise", ">= 1.0.4"
25
+ s.add_development_dependency "logstash-devutils"
26
+ end
@@ -0,0 +1,75 @@
1
+ # encoding: utf-8
2
+ require "logstash/devutils/rspec/spec_helper"
3
+ require "logstash/filters/units"
4
+
5
+ describe LogStash::Filters::Units do
6
+ describe "special field" do
7
+ let(:config) do <<-CONFIG
8
+ filter {
9
+ units {
10
+ fields => ["[a1][a2]", "b1", "c1", "d2"]
11
+ input_unit => "byte"
12
+ output_units => ["kibibyte", "mebibyte"]
13
+ root_field => "special"
14
+ rename_labels => {
15
+ "kibibyte" => "kb"
16
+ "mebibyte" => "mb"
17
+ }
18
+ }
19
+ }
20
+ CONFIG
21
+ end
22
+
23
+ event = {
24
+ "a1" => {
25
+ "a2" => 1024
26
+ },
27
+ "b1" => 1024,
28
+ "c1" => 1024,
29
+ "d1" => {
30
+ "d2" => 1024
31
+ }
32
+ }
33
+ sample(event) do
34
+ insist { subject["special"]["a1"]["a2"]["kb"] } == 1
35
+ insist { subject["special"]["a1"]["a2"]["kb"] } == 1
36
+ insist { subject["special"]["b1"]["kb"] } == 1
37
+ insist { subject["special"]["c1"]["kb"] } == 1
38
+ insist { subject["special"]["d1"]["d2"]["kb"] } == 1
39
+ end
40
+ end
41
+
42
+ describe "in place" do
43
+ let(:config) do <<-CONFIG
44
+ filter {
45
+ units {
46
+ fields => ["[a1][a2]", "b1", "c1", "d2"]
47
+ input_unit => "byte"
48
+ output_units => ["kibibyte", "mebibyte"]
49
+ rename_labels => {
50
+ "kibibyte" => "kb"
51
+ "mebibyte" => "mb"
52
+ }
53
+ }
54
+ }
55
+ CONFIG
56
+ end
57
+
58
+ event = {
59
+ "a1" => {
60
+ "a2" => 1024**2
61
+ },
62
+ "b1" => 1024**2,
63
+ "c1" => 1024**2,
64
+ "d1" => {
65
+ "d2" => 1024**2
66
+ }
67
+ }
68
+ sample(event) do
69
+ insist { subject["a1"]["a2"]["mb"] } == 1
70
+ insist { subject["b1"]["mb"] } == 1
71
+ insist { subject["c1"]["mb"] } == 1
72
+ insist { subject["d1"]["d2"]["mb"] } == 1
73
+ end
74
+ end
75
+ end
metadata ADDED
@@ -0,0 +1,103 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: logstash-filter-units
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Alex Braun
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2015-03-16 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: logstash
15
+ version_requirements: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - '>='
18
+ - !ruby/object:Gem::Version
19
+ version: 1.4.0
20
+ - - <
21
+ - !ruby/object:Gem::Version
22
+ version: 2.0.0
23
+ requirement: !ruby/object:Gem::Requirement
24
+ requirements:
25
+ - - '>='
26
+ - !ruby/object:Gem::Version
27
+ version: 1.4.0
28
+ - - <
29
+ - !ruby/object:Gem::Version
30
+ version: 2.0.0
31
+ prerelease: false
32
+ type: :runtime
33
+ - !ruby/object:Gem::Dependency
34
+ name: unitwise
35
+ version_requirements: !ruby/object:Gem::Requirement
36
+ requirements:
37
+ - - '>='
38
+ - !ruby/object:Gem::Version
39
+ version: 1.0.4
40
+ requirement: !ruby/object:Gem::Requirement
41
+ requirements:
42
+ - - '>='
43
+ - !ruby/object:Gem::Version
44
+ version: 1.0.4
45
+ prerelease: false
46
+ type: :runtime
47
+ - !ruby/object:Gem::Dependency
48
+ name: logstash-devutils
49
+ version_requirements: !ruby/object:Gem::Requirement
50
+ requirements:
51
+ - - '>='
52
+ - !ruby/object:Gem::Version
53
+ version: '0'
54
+ requirement: !ruby/object:Gem::Requirement
55
+ requirements:
56
+ - - '>='
57
+ - !ruby/object:Gem::Version
58
+ version: '0'
59
+ prerelease: false
60
+ type: :development
61
+ description: The units filter is used for converting specified fields from one unit of measure to another (or many others).
62
+ email: Alex.Braun.VFX@gmail.com
63
+ executables: []
64
+ extensions: []
65
+ extra_rdoc_files: []
66
+ files:
67
+ - .gitignore
68
+ - CONTRIBUTORS
69
+ - Gemfile
70
+ - LICENSE
71
+ - README.md
72
+ - Rakefile
73
+ - lib/logstash/filters/units.rb
74
+ - logstash-filter-units.gemspec
75
+ - spec/filters/units_spec.rb
76
+ homepage: http://www.elasticsearch.org/guide/en/logstash/current/index.html
77
+ licenses:
78
+ - Apache License (2.0)
79
+ metadata:
80
+ logstash_plugin: 'true'
81
+ logstash_group: filter
82
+ post_install_message:
83
+ rdoc_options: []
84
+ require_paths:
85
+ - lib
86
+ required_ruby_version: !ruby/object:Gem::Requirement
87
+ requirements:
88
+ - - '>='
89
+ - !ruby/object:Gem::Version
90
+ version: '0'
91
+ required_rubygems_version: !ruby/object:Gem::Requirement
92
+ requirements:
93
+ - - '>='
94
+ - !ruby/object:Gem::Version
95
+ version: '0'
96
+ requirements: []
97
+ rubyforge_project:
98
+ rubygems_version: 2.4.6
99
+ signing_key:
100
+ specification_version: 4
101
+ summary: A filter for performing unit conversions on specified fields.
102
+ test_files:
103
+ - spec/filters/units_spec.rb