logstash-filter-translate 0.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml ADDED
@@ -0,0 +1,15 @@
1
+ ---
2
+ !binary "U0hBMQ==":
3
+ metadata.gz: !binary |-
4
+ ZDBkYzAwNTgzMTNiNzVjZmJhNzY0YjFiYzUzYTc4YzU1Yjk4ZTI2OQ==
5
+ data.tar.gz: !binary |-
6
+ NjdlYzhlZDU2NDdhNDY1ODM5OTMyNTRhNjk0MmI0MGU0M2ViMjBmOA==
7
+ SHA512:
8
+ metadata.gz: !binary |-
9
+ NGE5ZGEzMjkwMjRmZmJiMTllY2IyN2M3NWM3YTBkMjhjNmM1OWViZDM3MTZi
10
+ ODZmZDBiNmNlN2RmODA2NDJiNDM0NDJhZjY4MjczM2YwMzJlOTIwYTM3NDli
11
+ MmM2NzBhZjFiNmQ4MjVkNjdjZWQ4NDg1NjA3NDE0YzYzYmEzMDA=
12
+ data.tar.gz: !binary |-
13
+ MDM1NjFkOWE3ZWVhYTBjM2M1OWY5MmFmY2Q1OWJiNDhlY2RmOTYxODU1N2Vj
14
+ NTg0MjQwZDg1NjY3MzI5NmE3ZDIwYzlkYWRhYjc3NDUxMmVjNDMxYzJiNTBj
15
+ YjdkNzQ4NzBmNjU1N2RiZDY2ODg0ZjFiMDAyNzEzMGM3YjVmYmM=
data/.gitignore ADDED
@@ -0,0 +1 @@
1
+ *.gem
@@ -0,0 +1,195 @@
1
+ # encoding: utf-8
2
+ require "logstash/filters/base"
3
+ require "logstash/namespace"
4
+
5
+ # A general search and replace tool which uses a configured hash
6
+ # and/or a YAML file to determine replacement values.
7
+ #
8
+ # The dictionary entries can be specified in one of two ways: First,
9
+ # the "dictionary" configuration item may contain a hash representing
10
+ # the mapping. Second, an external YAML file (readable by logstash) may be specified
11
+ # in the "dictionary_path" configuration item. These two methods may not be used
12
+ # in conjunction; it will produce an error.
13
+ #
14
+ # Operationally, if the event field specified in the "field" configuration
15
+ # matches the EXACT contents of a dictionary entry key (or matches a regex if
16
+ # "regex" configuration item has been enabled), the field's value will be substituted
17
+ # with the matched key's value from the dictionary.
18
+ #
19
+ # By default, the translate filter will replace the contents of the
20
+ # maching event field (in-place). However, by using the "destination"
21
+ # configuration item, you may also specify a target event field to
22
+ # populate with the new translated value.
23
+ #
24
+ # Alternatively, for simple string search and replacements for just a few values
25
+ # you might consider using the gsub function of the mutate filter.
26
+
27
+ class LogStash::Filters::Translate < LogStash::Filters::Base
28
+ config_name "translate"
29
+ milestone 1
30
+
31
+ # The name of the logstash event field containing the value to be compared for a
32
+ # match by the translate filter (e.g. "message", "host", "response_code").
33
+ #
34
+ # If this field is an array, only the first value will be used.
35
+ config :field, :validate => :string, :required => true
36
+
37
+ # If the destination (or target) field already exists, this configuration item specifies
38
+ # whether the filter should skip translation (default) or overwrite the target field
39
+ # value with the new translation value.
40
+ config :override, :validate => :boolean, :default => false
41
+
42
+ # The dictionary to use for translation, when specified in the logstash filter
43
+ # configuration item (i.e. do not use the @dictionary_path YAML file)
44
+ # Example:
45
+ #
46
+ # filter {
47
+ # %PLUGIN% {
48
+ # dictionary => [ "100", "Continue",
49
+ # "101", "Switching Protocols",
50
+ # "merci", "thank you",
51
+ # "old version", "new version" ]
52
+ # }
53
+ # }
54
+ # NOTE: it is an error to specify both dictionary and dictionary_path
55
+ config :dictionary, :validate => :hash, :default => {}
56
+
57
+ # The full path of the external YAML dictionary file. The format of the table
58
+ # should be a standard YAML file. Make sure you specify any integer-based keys
59
+ # in quotes. The YAML file should look something like this:
60
+ #
61
+ # "100": Continue
62
+ # "101": Switching Protocols
63
+ # merci: gracias
64
+ # old version: new version
65
+ #
66
+ # NOTE: it is an error to specify both dictionary and dictionary_path
67
+ config :dictionary_path, :validate => :path
68
+
69
+ # When using a dictionary file, this setting will indicate how frequently
70
+ # (in seconds) logstash will check the YAML file for updates.
71
+ config :refresh_interval, :validate => :number, :default => 300
72
+
73
+ # The destination field you wish to populate with the translated code. The default
74
+ # is a field named "translation". Set this to the same value as source if you want
75
+ # to do a substitution, in this case filter will allways succeed. This will clobber
76
+ # the old value of the source field!
77
+ config :destination, :validate => :string, :default => "translation"
78
+
79
+ # When `exact => true`, the translate filter will populate the destination field
80
+ # with the exact contents of the dictionary value. When `exact => false`, the
81
+ # filter will populate the destination field with the result of any existing
82
+ # destination field's data, with the translated value substituted in-place.
83
+ #
84
+ # For example, consider this simple translation.yml, configured to check the `data` field:
85
+ # foo: bar
86
+ #
87
+ # If logstash receives an event with the `data` field set to "foo", and `exact => true`,
88
+ # the destination field will be populated with the string "bar".
89
+
90
+ # If `exact => false`, and logstash receives the same event, the destination field
91
+ # will be also set to "bar". However, if logstash receives an event with the `data` field
92
+ # set to "foofing", the destination field will be set to "barfing".
93
+ #
94
+ # Set both `exact => true` AND `regex => `true` if you would like to match using dictionary
95
+ # keys as regular expressions. A large dictionary could be expensive to match in this case.
96
+ config :exact, :validate => :boolean, :default => true
97
+
98
+ # If you'd like to treat dictionary keys as regular expressions, set `exact => true`.
99
+ # Note: this is activated only when `exact => true`.
100
+ config :regex, :validate => :boolean, :default => false
101
+
102
+ # In case no translation occurs in the event (no matches), this will add a default
103
+ # translation string, which will always populate "field", if the match failed.
104
+ #
105
+ # For example, if we have configured `fallback => "no match"`, using this dictionary:
106
+ #
107
+ # foo: bar
108
+ #
109
+ # Then, if logstash received an event with the field `foo` set to "bar", the destination
110
+ # field would be set to "bar". However, if logstash received an event with `foo` set to "nope",
111
+ # then the destination field would still be populated, but with the value of "no match".
112
+ config :fallback, :validate => :string
113
+
114
+ public
115
+ def register
116
+ if @dictionary_path
117
+ @next_refresh = Time.now + @refresh_interval
118
+ registering = true
119
+ load_yaml(registering)
120
+ end
121
+
122
+ @logger.debug? and @logger.debug("#{self.class.name}: Dictionary - ", :dictionary => @dictionary)
123
+ if @exact
124
+ @logger.debug? and @logger.debug("#{self.class.name}: Dictionary translation method - Exact")
125
+ else
126
+ @logger.debug? and @logger.debug("#{self.class.name}: Dictionary translation method - Fuzzy")
127
+ end
128
+ end # def register
129
+
130
+ public
131
+ def load_yaml(registering=false)
132
+ if !File.exists?(@dictionary_path)
133
+ @logger.warn("dictionary file read failure, continuing with old dictionary", :path => @dictionary_path)
134
+ return
135
+ end
136
+
137
+ begin
138
+ @dictionary.merge!(YAML.load_file(@dictionary_path))
139
+ rescue Exception => e
140
+ if registering
141
+ raise "#{self.class.name}: Bad Syntax in dictionary file #{@dictionary_path}"
142
+ else
143
+ @logger.warn("#{self.class.name}: Bad Syntax in dictionary file, continuing with old dictionary", :dictionary_path => @dictionary_path)
144
+ end
145
+ end
146
+ end
147
+
148
+ public
149
+ def filter(event)
150
+ return unless filter?(event)
151
+
152
+ if @dictionary_path
153
+ if @next_refresh < Time.now
154
+ load_yaml
155
+ @next_refresh = Time.now + @refresh_interval
156
+ @logger.info("refreshing dictionary file")
157
+ end
158
+ end
159
+
160
+ return unless event.include?(@field) # Skip translation in case event does not have @event field.
161
+ return if event.include?(@destination) and not @override # Skip translation in case @destination field already exists and @override is disabled.
162
+
163
+ begin
164
+ #If source field is array use first value and make sure source value is string
165
+ source = event[@field].is_a?(Array) ? event[@field].first.to_s : event[@field].to_s
166
+ matched = false
167
+ if @exact
168
+ if @regex
169
+ key = @dictionary.keys.detect{|k| source.match(Regexp.new(k))}
170
+ if key
171
+ event[@destination] = @dictionary[key]
172
+ matched = true
173
+ end
174
+ elsif @dictionary.include?(source)
175
+ event[@destination] = @dictionary[source]
176
+ matched = true
177
+ end
178
+ else
179
+ translation = source.gsub(Regexp.union(@dictionary.keys), @dictionary)
180
+ if source != translation
181
+ event[@destination] = translation.force_encoding(Encoding::UTF_8)
182
+ matched = true
183
+ end
184
+ end
185
+
186
+ if not matched and @fallback
187
+ event[@destination] = @fallback
188
+ matched = true
189
+ end
190
+ filter_matched(event) if matched or @field == @destination
191
+ rescue Exception => e
192
+ @logger.error("Something went wrong when attempting to translate from dictionary", :exception => e, :field => @field, :event => event)
193
+ end
194
+ end # def filter
195
+ end # class LogStash::Filters::Translate
@@ -0,0 +1,27 @@
1
+ Gem::Specification.new do |s|
2
+
3
+ s.name = 'logstash-filter-translate'
4
+ s.version = '0.1.1'
5
+ s.licenses = ['Apache License (2.0)']
6
+ s.summary = "A general search and replace tool which uses a configured hash and/or a YAML file to determine replacement values."
7
+ s.description = "A general search and replace tool which uses a configured hash and/or a YAML file to determine replacement values."
8
+ s.authors = ["Elasticsearch"]
9
+ s.email = 'richard.pijnenburg@elasticsearch.com'
10
+ s.homepage = "http://logstash.net/"
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", "group" => "filter" }
21
+
22
+ # Gem dependencies
23
+ s.add_runtime_dependency 'logstash', '>= 1.4.0', '< 2.0.0'
24
+
25
+ s.add_development_dependency 'gem_publisher', '~> 1.4.0'
26
+ end
27
+
@@ -0,0 +1,70 @@
1
+ require "test_utils"
2
+ require "logstash/filters/translate"
3
+
4
+ describe LogStash::Filters::Translate do
5
+ extend LogStash::RSpec
6
+
7
+ describe "exact translation" do
8
+ config <<-CONFIG
9
+ filter {
10
+ translate {
11
+ field => "status"
12
+ destination => "translation"
13
+ dictionary => [ "200", "OK",
14
+ "300", "Redirect",
15
+ "400", "Client Error",
16
+ "500", "Server Error" ]
17
+ exact => true
18
+ regex => false
19
+ }
20
+ }
21
+ CONFIG
22
+
23
+ sample("status" => 200) do
24
+ insist { subject["translation"] } == "OK"
25
+ end
26
+ end
27
+
28
+ describe "multi translation" do
29
+ config <<-CONFIG
30
+ filter {
31
+ translate {
32
+ field => "status"
33
+ destination => "translation"
34
+ dictionary => [ "200", "OK",
35
+ "300", "Redirect",
36
+ "400", "Client Error",
37
+ "500", "Server Error" ]
38
+ exact => false
39
+ regex => false
40
+ }
41
+ }
42
+ CONFIG
43
+
44
+ sample("status" => "200 & 500") do
45
+ insist { subject["translation"] } == "OK & Server Error"
46
+ end
47
+ end
48
+
49
+ describe "regex translation" do
50
+ config <<-CONFIG
51
+ filter {
52
+ translate {
53
+ field => "status"
54
+ destination => "translation"
55
+ dictionary => [ "^2[0-9][0-9]$", "OK",
56
+ "^3[0-9][0-9]$", "Redirect",
57
+ "^4[0-9][0-9]$", "Client Error",
58
+ "^5[0-9][0-9]$", "Server Error" ]
59
+ exact => true
60
+ regex => true
61
+ }
62
+ }
63
+ CONFIG
64
+
65
+ sample("status" => "200") do
66
+ insist { subject["translation"] } == "OK"
67
+ end
68
+ end
69
+
70
+ end
metadata ADDED
@@ -0,0 +1,86 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: logstash-filter-translate
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.1
5
+ platform: ruby
6
+ authors:
7
+ - Elasticsearch
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2014-09-11 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: logstash
15
+ requirement: !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
+ type: :runtime
24
+ prerelease: false
25
+ version_requirements: !ruby/object:Gem::Requirement
26
+ requirements:
27
+ - - ! '>='
28
+ - !ruby/object:Gem::Version
29
+ version: 1.4.0
30
+ - - <
31
+ - !ruby/object:Gem::Version
32
+ version: 2.0.0
33
+ - !ruby/object:Gem::Dependency
34
+ name: gem_publisher
35
+ requirement: !ruby/object:Gem::Requirement
36
+ requirements:
37
+ - - ~>
38
+ - !ruby/object:Gem::Version
39
+ version: 1.4.0
40
+ type: :development
41
+ prerelease: false
42
+ version_requirements: !ruby/object:Gem::Requirement
43
+ requirements:
44
+ - - ~>
45
+ - !ruby/object:Gem::Version
46
+ version: 1.4.0
47
+ description: A general search and replace tool which uses a configured hash and/or
48
+ a YAML file to determine replacement values.
49
+ email: richard.pijnenburg@elasticsearch.com
50
+ executables: []
51
+ extensions: []
52
+ extra_rdoc_files: []
53
+ files:
54
+ - .gitignore
55
+ - lib/logstash/filters/translate.rb
56
+ - logstash-filter-translate.gemspec
57
+ - spec/filters/translate.rb
58
+ homepage: http://logstash.net/
59
+ licenses:
60
+ - Apache License (2.0)
61
+ metadata:
62
+ logstash_plugin: 'true'
63
+ group: filter
64
+ post_install_message:
65
+ rdoc_options: []
66
+ require_paths:
67
+ - lib
68
+ required_ruby_version: !ruby/object:Gem::Requirement
69
+ requirements:
70
+ - - ! '>='
71
+ - !ruby/object:Gem::Version
72
+ version: '0'
73
+ required_rubygems_version: !ruby/object:Gem::Requirement
74
+ requirements:
75
+ - - ! '>='
76
+ - !ruby/object:Gem::Version
77
+ version: '0'
78
+ requirements: []
79
+ rubyforge_project:
80
+ rubygems_version: 2.4.1
81
+ signing_key:
82
+ specification_version: 4
83
+ summary: A general search and replace tool which uses a configured hash and/or a YAML
84
+ file to determine replacement values.
85
+ test_files:
86
+ - spec/filters/translate.rb