logstash-filter-translate 0.1.1

Sign up to get free protection for your applications and to get access to all the features.
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