logstash-filter-translate 2.0.2 → 2.1.3
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 +4 -4
- data/CHANGELOG.md +17 -4
- data/README.md +3 -0
- data/lib/logstash/filters/translate.rb +80 -37
- data/logstash-filter-translate.gemspec +2 -2
- data/spec/filters/translate_spec.rb +60 -0
- data/spec/fixtures/dict-wrong.yml +1 -0
- data/spec/fixtures/dict.csv +3 -0
- data/spec/fixtures/dict.json +5 -0
- data/spec/fixtures/dict.other +3 -0
- data/spec/fixtures/dict.yml +3 -0
- metadata +21 -17
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 8003929e0ef9c30f41f95b144ce3872b60cceaa7
|
4
|
+
data.tar.gz: b92c98f43df88c648a684f638cd04fed8e12336b
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 2a65ab7595ecbd6eb16bbec0127f9052060c6601be096658b76b9ccdbb4ede9b176047adae3c9aaeeb8e17d22d6cf7f54a8bd6ca00bed52052c40b8f95494cbc
|
7
|
+
data.tar.gz: 0a7bb3d83cebf55531bf35bff3a626528932fe78de627e46ac0edc91fa7230296069943503529fec868f942a79dd914c74492550fd658ce69f98df98df458c51
|
data/CHANGELOG.md
CHANGED
@@ -1,7 +1,20 @@
|
|
1
|
+
# 2.1.3
|
2
|
+
- Depend on logstash-core-plugin-api instead of logstash-core, removing the need to mass update plugins on major releases of logstash
|
3
|
+
# 2.1.2
|
4
|
+
- New dependency requirements for logstash-core for the 5.0 release
|
5
|
+
## 2.1.1
|
6
|
+
- Add more descriptive message with the dictionary could not be loaded,
|
7
|
+
also include test for it.
|
8
|
+
|
9
|
+
## 2.1.0
|
10
|
+
- Added other formats, a part from YAML, to be used when loading
|
11
|
+
dictionaries from files in this plugin. Current supported formats are
|
12
|
+
YAML, JSON and CSV.
|
13
|
+
|
1
14
|
## 2.0.0
|
2
|
-
|
3
|
-
|
4
|
-
|
15
|
+
- Plugins were updated to follow the new shutdown semantic, this mainly allows Logstash to instruct input plugins to terminate gracefully,
|
16
|
+
instead of using Thread.raise on the plugins' threads. Ref: https://github.com/elastic/logstash/pull/3895
|
17
|
+
- Dependency on logstash-core update to 2.0
|
5
18
|
|
6
|
-
|
19
|
+
## 0.1.10
|
7
20
|
- fix failing test due to a missing encoding: utf8 magic header
|
data/README.md
CHANGED
@@ -1,5 +1,8 @@
|
|
1
1
|
# Logstash Plugin
|
2
2
|
|
3
|
+
[](http://build-eu-00.elastic.co/view/LS%20Plugins/view/LS%20Filters/job/logstash-plugin-filter-translate-unit/)
|
5
|
+
|
3
6
|
This is a plugin for [Logstash](https://github.com/elastic/logstash).
|
4
7
|
|
5
8
|
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.
|
@@ -1,13 +1,16 @@
|
|
1
1
|
# encoding: utf-8
|
2
2
|
require "logstash/filters/base"
|
3
3
|
require "logstash/namespace"
|
4
|
+
require "json"
|
5
|
+
require "csv"
|
4
6
|
|
5
7
|
# A general search and replace tool which uses a configured hash
|
6
|
-
# and/or a
|
8
|
+
# and/or a file to determine replacement values. Currently supported are
|
9
|
+
# YAML, JSON and CSV files.
|
7
10
|
#
|
8
11
|
# The dictionary entries can be specified in one of two ways: First,
|
9
12
|
# the `dictionary` configuration item may contain a hash representing
|
10
|
-
# the mapping. Second, an external
|
13
|
+
# the mapping. Second, an external file (readable by logstash) may be specified
|
11
14
|
# in the `dictionary_path` configuration item. These two methods may not be used
|
12
15
|
# in conjunction; it will produce an error.
|
13
16
|
#
|
@@ -39,7 +42,7 @@ class LogStash::Filters::Translate < LogStash::Filters::Base
|
|
39
42
|
config :override, :validate => :boolean, :default => false
|
40
43
|
|
41
44
|
# The dictionary to use for translation, when specified in the logstash filter
|
42
|
-
# configuration item (i.e. do not use the `@dictionary_path`
|
45
|
+
# configuration item (i.e. do not use the `@dictionary_path` file)
|
43
46
|
# Example:
|
44
47
|
# [source,ruby]
|
45
48
|
# filter {
|
@@ -53,22 +56,27 @@ class LogStash::Filters::Translate < LogStash::Filters::Base
|
|
53
56
|
# NOTE: it is an error to specify both `dictionary` and `dictionary_path`
|
54
57
|
config :dictionary, :validate => :hash, :default => {}
|
55
58
|
|
56
|
-
# The full path of the external
|
57
|
-
# should be a standard YAML
|
58
|
-
# in quotes.
|
59
|
+
# The full path of the external dictionary file. The format of the table
|
60
|
+
# should be a standard YAML, JSON or CSV. Make sure you specify any integer-based keys
|
61
|
+
# in quotes. For example, the YAML file should look something like this:
|
59
62
|
# [source,ruby]
|
60
63
|
# "100": Continue
|
61
64
|
# "101": Switching Protocols
|
62
65
|
# merci: gracias
|
63
66
|
# old version: new version
|
64
|
-
#
|
67
|
+
#
|
65
68
|
# NOTE: it is an error to specify both `dictionary` and `dictionary_path`
|
69
|
+
# NOTE: Currently supported formats are YAML, JSON and CSV, format selection is
|
70
|
+
# based on the file extension, json for JSON, (yaml|yml) for YAML and csv for CSV.
|
71
|
+
# NOTE: The JSON format only supports simple key/value, unnested objects. The CSV
|
72
|
+
# format expects exactly two columns with the first serving as the original text,
|
73
|
+
# the second column as the replacement
|
66
74
|
config :dictionary_path, :validate => :path
|
67
75
|
|
68
76
|
# When using a dictionary file, this setting will indicate how frequently
|
69
|
-
# (in seconds) logstash will check the
|
77
|
+
# (in seconds) logstash will check the dictionary file for updates.
|
70
78
|
config :refresh_interval, :validate => :number, :default => 300
|
71
|
-
|
79
|
+
|
72
80
|
# The destination field you wish to populate with the translated code. The default
|
73
81
|
# is a field named `translation`. Set this to the same value as source if you want
|
74
82
|
# to do a substitution, in this case filter will allways succeed. This will clobber
|
@@ -86,7 +94,7 @@ class LogStash::Filters::Translate < LogStash::Filters::Base
|
|
86
94
|
#
|
87
95
|
# If logstash receives an event with the `data` field set to `foo`, and `exact => true`,
|
88
96
|
# the destination field will be populated with the string `bar`.
|
89
|
-
|
97
|
+
|
90
98
|
# If `exact => false`, and logstash receives the same event, the destination field
|
91
99
|
# will be also set to `bar`. However, if logstash receives an event with the `data` field
|
92
100
|
# set to `foofing`, the destination field will be set to `barfing`.
|
@@ -112,14 +120,13 @@ class LogStash::Filters::Translate < LogStash::Filters::Base
|
|
112
120
|
# This configuration can be dynamic and include parts of the event using the `%{field}` syntax.
|
113
121
|
config :fallback, :validate => :string
|
114
122
|
|
115
|
-
public
|
116
123
|
def register
|
117
124
|
if @dictionary_path
|
118
125
|
@next_refresh = Time.now + @refresh_interval
|
119
|
-
|
120
|
-
|
126
|
+
raise_exception = true
|
127
|
+
load_dictionary(raise_exception)
|
121
128
|
end
|
122
|
-
|
129
|
+
|
123
130
|
@logger.debug? and @logger.debug("#{self.class.name}: Dictionary - ", :dictionary => @dictionary)
|
124
131
|
if @exact
|
125
132
|
@logger.debug? and @logger.debug("#{self.class.name}: Dictionary translation method - Exact")
|
@@ -128,36 +135,15 @@ class LogStash::Filters::Translate < LogStash::Filters::Base
|
|
128
135
|
end
|
129
136
|
end # def register
|
130
137
|
|
131
|
-
public
|
132
|
-
def load_yaml(registering=false)
|
133
|
-
if !File.exists?(@dictionary_path)
|
134
|
-
@logger.warn("dictionary file read failure, continuing with old dictionary", :path => @dictionary_path)
|
135
|
-
return
|
136
|
-
end
|
137
|
-
|
138
|
-
begin
|
139
|
-
@dictionary.merge!(YAML.load_file(@dictionary_path))
|
140
|
-
rescue Exception => e
|
141
|
-
if registering
|
142
|
-
raise "#{self.class.name}: Bad Syntax in dictionary file #{@dictionary_path}"
|
143
|
-
else
|
144
|
-
@logger.warn("#{self.class.name}: Bad Syntax in dictionary file, continuing with old dictionary", :dictionary_path => @dictionary_path)
|
145
|
-
end
|
146
|
-
end
|
147
|
-
end
|
148
|
-
|
149
|
-
public
|
150
138
|
def filter(event)
|
151
|
-
|
152
|
-
|
153
139
|
if @dictionary_path
|
154
140
|
if @next_refresh < Time.now
|
155
|
-
|
141
|
+
load_dictionary
|
156
142
|
@next_refresh = Time.now + @refresh_interval
|
157
143
|
@logger.info("refreshing dictionary file")
|
158
144
|
end
|
159
145
|
end
|
160
|
-
|
146
|
+
|
161
147
|
return unless event.include?(@field) # Skip translation in case event does not have @event field.
|
162
148
|
return if event.include?(@destination) and not @override # Skip translation in case @destination field already exists and @override is disabled.
|
163
149
|
|
@@ -193,4 +179,61 @@ class LogStash::Filters::Translate < LogStash::Filters::Base
|
|
193
179
|
@logger.error("Something went wrong when attempting to translate from dictionary", :exception => e, :field => @field, :event => event)
|
194
180
|
end
|
195
181
|
end # def filter
|
182
|
+
|
183
|
+
private
|
184
|
+
|
185
|
+
def load_dictionary(raise_exception=false)
|
186
|
+
if /.y[a]?ml$/.match(@dictionary_path)
|
187
|
+
load_yaml(raise_exception)
|
188
|
+
elsif @dictionary_path.end_with?(".json")
|
189
|
+
load_json(raise_exception)
|
190
|
+
elsif @dictionary_path.end_with?(".csv")
|
191
|
+
load_csv(raise_exception)
|
192
|
+
else
|
193
|
+
raise "#{self.class.name}: Dictionary #{@dictionary_path} have a non valid format"
|
194
|
+
end
|
195
|
+
rescue => e
|
196
|
+
loading_exception(e, raise_exception)
|
197
|
+
end
|
198
|
+
|
199
|
+
def load_yaml(raise_exception=false)
|
200
|
+
if !File.exists?(@dictionary_path)
|
201
|
+
@logger.warn("dictionary file read failure, continuing with old dictionary", :path => @dictionary_path)
|
202
|
+
return
|
203
|
+
end
|
204
|
+
merge_dictionary!(YAML.load_file(@dictionary_path), raise_exception)
|
205
|
+
end
|
206
|
+
|
207
|
+
def load_json(raise_exception=false)
|
208
|
+
if !File.exists?(@dictionary_path)
|
209
|
+
@logger.warn("dictionary file read failure, continuing with old dictionary", :path => @dictionary_path)
|
210
|
+
return
|
211
|
+
end
|
212
|
+
merge_dictionary!(JSON.parse(File.read(@dictionary_path)), raise_exception)
|
213
|
+
end
|
214
|
+
|
215
|
+
def load_csv(raise_exception=false)
|
216
|
+
if !File.exists?(@dictionary_path)
|
217
|
+
@logger.warn("dictionary file read failure, continuing with old dictionary", :path => @dictionary_path)
|
218
|
+
return
|
219
|
+
end
|
220
|
+
data = CSV.read(@dictionary_path).inject(Hash.new) do |acc, v|
|
221
|
+
acc[v[0]] = v[1]
|
222
|
+
acc
|
223
|
+
end
|
224
|
+
merge_dictionary!(data, raise_exception)
|
225
|
+
end
|
226
|
+
|
227
|
+
def merge_dictionary!(data, raise_exception=false)
|
228
|
+
@dictionary.merge!(data)
|
229
|
+
end
|
230
|
+
|
231
|
+
def loading_exception(e, raise_exception=false)
|
232
|
+
msg = "#{self.class.name}: #{e.message} when loading dictionary file at #{@dictionary_path}"
|
233
|
+
if raise_exception
|
234
|
+
raise RuntimeError.new(msg)
|
235
|
+
else
|
236
|
+
@logger.warn("#{msg}, continuing with old dictionary", :dictionary_path => @dictionary_path)
|
237
|
+
end
|
238
|
+
end
|
196
239
|
end # class LogStash::Filters::Translate
|
@@ -1,7 +1,7 @@
|
|
1
1
|
Gem::Specification.new do |s|
|
2
2
|
|
3
3
|
s.name = 'logstash-filter-translate'
|
4
|
-
s.version = '2.
|
4
|
+
s.version = '2.1.3'
|
5
5
|
s.licenses = ['Apache License (2.0)']
|
6
6
|
s.summary = "A general search and replace tool which uses a configured hash and/or a YAML file to determine replacement values."
|
7
7
|
s.description = "This gem is a logstash plugin required to be installed on top of the Logstash core pipeline using $LS_HOME/bin/plugin install gemname. This gem is not a stand-alone program"
|
@@ -20,7 +20,7 @@ Gem::Specification.new do |s|
|
|
20
20
|
s.metadata = { "logstash_plugin" => "true", "logstash_group" => "filter" }
|
21
21
|
|
22
22
|
# Gem dependencies
|
23
|
-
s.add_runtime_dependency "logstash-core", "
|
23
|
+
s.add_runtime_dependency "logstash-core-plugin-api", "~> 1.0"
|
24
24
|
|
25
25
|
s.add_development_dependency 'logstash-devutils'
|
26
26
|
end
|
@@ -120,4 +120,64 @@ describe LogStash::Filters::Translate do
|
|
120
120
|
end
|
121
121
|
end
|
122
122
|
|
123
|
+
describe "loading a dictionary" do
|
124
|
+
|
125
|
+
let(:dictionary_path) { File.join(File.dirname(__FILE__), "..", "fixtures", "dict-wrong.yml") }
|
126
|
+
|
127
|
+
let(:config) do
|
128
|
+
{
|
129
|
+
"field" => "status",
|
130
|
+
"destination" => "translation",
|
131
|
+
"dictionary_path" => dictionary_path,
|
132
|
+
"exact" => true,
|
133
|
+
"regex" => false
|
134
|
+
}
|
135
|
+
end
|
136
|
+
|
137
|
+
it "raises exception when loading" do
|
138
|
+
error = "(#{dictionary_path}): mapping values are not allowed here at line 1 column 45 when loading dictionary file at #{dictionary_path}"
|
139
|
+
expect { subject.register }.to raise_error("#{described_class}: #{error}")
|
140
|
+
end
|
141
|
+
|
142
|
+
context "when using a yml file" do
|
143
|
+
let(:dictionary_path) { File.join(File.dirname(__FILE__), "..", "fixtures", "dict.yml") }
|
144
|
+
let(:event) { LogStash::Event.new("status" => "a") }
|
145
|
+
|
146
|
+
it "return the exact translation" do
|
147
|
+
subject.register
|
148
|
+
subject.filter(event)
|
149
|
+
expect(event["translation"]).to eq(1)
|
150
|
+
end
|
151
|
+
end
|
152
|
+
|
153
|
+
context "when using a json file" do
|
154
|
+
let(:dictionary_path) { File.join(File.dirname(__FILE__), "..", "fixtures", "dict.json") }
|
155
|
+
let(:event) { LogStash::Event.new("status" => "b") }
|
156
|
+
|
157
|
+
it "return the exact translation" do
|
158
|
+
subject.register
|
159
|
+
subject.filter(event)
|
160
|
+
expect(event["translation"]).to eq(20)
|
161
|
+
end
|
162
|
+
end
|
163
|
+
|
164
|
+
context "when using a csv file" do
|
165
|
+
let(:dictionary_path) { File.join(File.dirname(__FILE__), "..", "fixtures", "dict.csv") }
|
166
|
+
let(:event) { LogStash::Event.new("status" => "c") }
|
167
|
+
|
168
|
+
it "return the exact translation" do
|
169
|
+
subject.register
|
170
|
+
subject.filter(event)
|
171
|
+
expect(event["translation"]).to eq("300")
|
172
|
+
end
|
173
|
+
end
|
174
|
+
|
175
|
+
context "when using an uknown file" do
|
176
|
+
let(:dictionary_path) { File.join(File.dirname(__FILE__), "..", "fixtures", "dict.other") }
|
177
|
+
|
178
|
+
it "return the exact translation" do
|
179
|
+
expect { subject.register }.to raise_error(RuntimeError, /Dictionary #{dictionary_path} have a non valid format/)
|
180
|
+
end
|
181
|
+
end
|
182
|
+
end
|
123
183
|
end
|
@@ -0,0 +1 @@
|
|
1
|
+
foo: somebody said I should put a colon here: so I did
|
metadata
CHANGED
@@ -1,39 +1,33 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: logstash-filter-translate
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 2.
|
4
|
+
version: 2.1.3
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Elastic
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2016-03-24 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
requirement: !ruby/object:Gem::Requirement
|
15
15
|
requirements:
|
16
|
-
- -
|
16
|
+
- - "~>"
|
17
17
|
- !ruby/object:Gem::Version
|
18
|
-
version:
|
19
|
-
|
20
|
-
- !ruby/object:Gem::Version
|
21
|
-
version: 3.0.0
|
22
|
-
name: logstash-core
|
18
|
+
version: '1.0'
|
19
|
+
name: logstash-core-plugin-api
|
23
20
|
prerelease: false
|
24
21
|
type: :runtime
|
25
22
|
version_requirements: !ruby/object:Gem::Requirement
|
26
23
|
requirements:
|
27
|
-
- -
|
28
|
-
- !ruby/object:Gem::Version
|
29
|
-
version: 2.0.0.beta2
|
30
|
-
- - <
|
24
|
+
- - "~>"
|
31
25
|
- !ruby/object:Gem::Version
|
32
|
-
version:
|
26
|
+
version: '1.0'
|
33
27
|
- !ruby/object:Gem::Dependency
|
34
28
|
requirement: !ruby/object:Gem::Requirement
|
35
29
|
requirements:
|
36
|
-
- -
|
30
|
+
- - ">="
|
37
31
|
- !ruby/object:Gem::Version
|
38
32
|
version: '0'
|
39
33
|
name: logstash-devutils
|
@@ -41,7 +35,7 @@ dependencies:
|
|
41
35
|
type: :development
|
42
36
|
version_requirements: !ruby/object:Gem::Requirement
|
43
37
|
requirements:
|
44
|
-
- -
|
38
|
+
- - ">="
|
45
39
|
- !ruby/object:Gem::Version
|
46
40
|
version: '0'
|
47
41
|
description: This gem is a logstash plugin required to be installed on top of the Logstash core pipeline using $LS_HOME/bin/plugin install gemname. This gem is not a stand-alone program
|
@@ -59,6 +53,11 @@ files:
|
|
59
53
|
- lib/logstash/filters/translate.rb
|
60
54
|
- logstash-filter-translate.gemspec
|
61
55
|
- spec/filters/translate_spec.rb
|
56
|
+
- spec/fixtures/dict-wrong.yml
|
57
|
+
- spec/fixtures/dict.csv
|
58
|
+
- spec/fixtures/dict.json
|
59
|
+
- spec/fixtures/dict.other
|
60
|
+
- spec/fixtures/dict.yml
|
62
61
|
homepage: http://www.elastic.co/guide/en/logstash/current/index.html
|
63
62
|
licenses:
|
64
63
|
- Apache License (2.0)
|
@@ -71,12 +70,12 @@ require_paths:
|
|
71
70
|
- lib
|
72
71
|
required_ruby_version: !ruby/object:Gem::Requirement
|
73
72
|
requirements:
|
74
|
-
- -
|
73
|
+
- - ">="
|
75
74
|
- !ruby/object:Gem::Version
|
76
75
|
version: '0'
|
77
76
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
78
77
|
requirements:
|
79
|
-
- -
|
78
|
+
- - ">="
|
80
79
|
- !ruby/object:Gem::Version
|
81
80
|
version: '0'
|
82
81
|
requirements: []
|
@@ -87,3 +86,8 @@ specification_version: 4
|
|
87
86
|
summary: A general search and replace tool which uses a configured hash and/or a YAML file to determine replacement values.
|
88
87
|
test_files:
|
89
88
|
- spec/filters/translate_spec.rb
|
89
|
+
- spec/fixtures/dict-wrong.yml
|
90
|
+
- spec/fixtures/dict.csv
|
91
|
+
- spec/fixtures/dict.json
|
92
|
+
- spec/fixtures/dict.other
|
93
|
+
- spec/fixtures/dict.yml
|