logstash-filter-translate 3.1.0 → 3.2.0

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.
@@ -17,8 +17,8 @@ describe LogStash::Filters::Translate do
17
17
  "300", "Redirect",
18
18
  "400", "Client Error",
19
19
  "500", "Server Error" ],
20
- "exact" => true,
21
- "regex" => false
20
+ "exact" => true,
21
+ "regex" => false
22
22
  }
23
23
  end
24
24
 
@@ -33,51 +33,96 @@ describe LogStash::Filters::Translate do
33
33
 
34
34
 
35
35
  describe "multi translation" do
36
+ context "when using an inline dictionary" do
37
+ let(:config) do
38
+ {
39
+ "field" => "status",
40
+ "destination" => "translation",
41
+ "dictionary" => [ "200", "OK",
42
+ "300", "Redirect",
43
+ "400", "Client Error",
44
+ "500", "Server Error" ],
45
+ "exact" => false,
46
+ "regex" => false
47
+ }
48
+ end
36
49
 
37
- let(:config) do
38
- {
39
- "field" => "status",
40
- "destination" => "translation",
41
- "dictionary" => [ "200", "OK",
42
- "300", "Redirect",
43
- "400", "Client Error",
44
- "500", "Server Error" ],
45
- "exact" => false,
46
- "regex" => false
47
- }
50
+ let(:event) { LogStash::Event.new("status" => "200 & 500") }
51
+
52
+ it "return the exact translation" do
53
+ subject.register
54
+ subject.filter(event)
55
+ expect(event.get("translation")).to eq("OK & Server Error")
56
+ end
48
57
  end
49
58
 
50
- let(:event) { LogStash::Event.new("status" => "200 & 500") }
59
+ context "when using a file based dictionary" do
60
+ let(:dictionary_path) { File.join(File.dirname(__FILE__), "..", "fixtures", "regex_union_dict.csv") }
61
+ let(:config) do
62
+ {
63
+ "field" => "status",
64
+ "destination" => "translation",
65
+ "dictionary_path" => dictionary_path,
66
+ "refresh_interval" => 0,
67
+ "exact" => false,
68
+ "regex" => false
69
+ }
70
+ end
51
71
 
52
- it "return the exact translation" do
53
- subject.register
54
- subject.filter(event)
55
- expect(event.get("translation")).to eq("OK & Server Error")
56
- end
72
+ let(:event) { LogStash::Event.new("status" => "200 & 500") }
57
73
 
74
+ it "return the exact regex translation" do
75
+ subject.register
76
+ subject.filter(event)
77
+ expect(event.get("translation")).to eq("OK & Server Error")
78
+ end
79
+ end
58
80
  end
59
81
 
60
82
  describe "regex translation" do
83
+ context "when using an inline dictionary" do
84
+ let(:config) do
85
+ {
86
+ "field" => "status",
87
+ "destination" => "translation",
88
+ "dictionary" => [ "^2[0-9][0-9]$", "OK",
89
+ "^3[0-9][0-9]$", "Redirect",
90
+ "^4[0-9][0-9]$", "Client Error",
91
+ "^5[0-9][0-9]$", "Server Error" ],
92
+ "exact" => true,
93
+ "regex" => true
94
+ }
95
+ end
61
96
 
62
- let(:config) do
63
- {
64
- "field" => "status",
65
- "destination" => "translation",
66
- "dictionary" => [ "^2[0-9][0-9]$", "OK",
67
- "^3[0-9][0-9]$", "Redirect",
68
- "^4[0-9][0-9]$", "Client Error",
69
- "^5[0-9][0-9]$", "Server Error" ],
70
- "exact" => true,
71
- "regex" => true
72
- }
97
+ let(:event) { LogStash::Event.new("status" => "200") }
98
+
99
+ it "return the exact regex translation" do
100
+ subject.register
101
+ subject.filter(event)
102
+ expect(event.get("translation")).to eq("OK")
103
+ end
73
104
  end
74
105
 
75
- let(:event) { LogStash::Event.new("status" => "200") }
106
+ context "when using a file based dictionary" do
107
+ let(:dictionary_path) { File.join(File.dirname(__FILE__), "..", "fixtures", "regex_dict.csv") }
108
+ let(:config) do
109
+ {
110
+ "field" => "status",
111
+ "destination" => "translation",
112
+ "dictionary_path" => dictionary_path,
113
+ "refresh_interval" => 0,
114
+ "exact" => true,
115
+ "regex" => true
116
+ }
117
+ end
76
118
 
77
- it "return the exact translation" do
78
- subject.register
79
- subject.filter(event)
80
- expect(event.get("translation")).to eq("OK")
119
+ let(:event) { LogStash::Event.new("status" => "200") }
120
+
121
+ it "return the exact regex translation" do
122
+ subject.register
123
+ subject.filter(event)
124
+ expect(event.get("translation")).to eq("OK")
125
+ end
81
126
  end
82
127
  end
83
128
 
@@ -129,14 +174,15 @@ describe LogStash::Filters::Translate do
129
174
  "field" => "status",
130
175
  "destination" => "translation",
131
176
  "dictionary_path" => dictionary_path,
177
+ "refresh_interval" => -1,
132
178
  "exact" => true,
133
179
  "regex" => false
134
180
  }
135
181
  end
136
182
 
137
183
  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}")
184
+ error = /mapping values are not allowed here at line 1 column 45 when loading dictionary file/
185
+ expect { subject.register }.to raise_error(error)
140
186
  end
141
187
 
142
188
  context "when using a yml file" do
@@ -150,6 +196,28 @@ describe LogStash::Filters::Translate do
150
196
  end
151
197
  end
152
198
 
199
+ context "when using a map tagged yml file" do
200
+ let(:dictionary_path) { File.join(File.dirname(__FILE__), "..", "fixtures", "tag-map-dict.yml") }
201
+ let(:event) { LogStash::Event.new("status" => "six") }
202
+
203
+ it "return the exact translation" do
204
+ subject.register
205
+ subject.filter(event)
206
+ expect(event.get("translation")).to eq("val-6-1|val-6-2")
207
+ end
208
+ end
209
+
210
+ context "when using a omap tagged yml file" do
211
+ let(:dictionary_path) { File.join(File.dirname(__FILE__), "..", "fixtures", "tag-omap-dict.yml") }
212
+ let(:event) { LogStash::Event.new("status" => "nine") }
213
+
214
+ it "return the exact translation" do
215
+ subject.register
216
+ subject.filter(event)
217
+ expect(event.get("translation")).to eq("val-9-1|val-9-2")
218
+ end
219
+ end
220
+
153
221
  context "when using a json file" do
154
222
  let(:dictionary_path) { File.join(File.dirname(__FILE__), "..", "fixtures", "dict.json") }
155
223
  let(:event) { LogStash::Event.new("status" => "b") }
@@ -172,15 +240,84 @@ describe LogStash::Filters::Translate do
172
240
  end
173
241
  end
174
242
 
175
- context "when using an uknown file" do
243
+ context "when using an unknown file" do
176
244
  let(:dictionary_path) { File.join(File.dirname(__FILE__), "..", "fixtures", "dict.other") }
177
245
 
178
- it "return the exact translation" do
179
- expect { subject.register }.to raise_error(RuntimeError, /Dictionary #{dictionary_path} have a non valid format/)
246
+ it "raises error" do
247
+ expect { subject.register }.to raise_error(RuntimeError, /Dictionary #{dictionary_path} has a non valid format/)
180
248
  end
181
249
  end
182
250
  end
183
251
 
252
+ describe "iterate_on functionality" do
253
+ describe "when iterate_on is the same as field, AKA array of values" do
254
+ let(:dictionary_path) { File.join(File.dirname(__FILE__), "..", "fixtures", "tag-map-dict.yml") }
255
+ let(:config) do
256
+ {
257
+ "iterate_on" => "foo",
258
+ "field" => "foo",
259
+ "destination" => "baz",
260
+ "fallback" => "nooo",
261
+ "dictionary_path" => dictionary_path,
262
+ # "override" => true,
263
+ "refresh_interval" => 0
264
+ }
265
+ end
266
+
267
+ let(:event) { LogStash::Event.new("foo" => ["nine","eight", "seven"]) }
268
+ it "adds a translation to destination array for each value in field array" do
269
+ subject.register
270
+ subject.filter(event)
271
+ expect(event.get("baz")).to eq(["val-9-1|val-9-2", "val-8-1|val-8-2", "val-7-1|val-7-2"])
272
+ end
273
+ end
274
+
275
+ describe "when iterate_on is not the same as field, AKA array of objects" do
276
+ let(:dictionary_path) { File.join(File.dirname(__FILE__), "..", "fixtures", "tag-map-dict.yml") }
277
+ let(:config) do
278
+ {
279
+ "iterate_on" => "foo",
280
+ "field" => "bar",
281
+ "destination" => "baz",
282
+ "fallback" => "nooo",
283
+ "dictionary_path" => dictionary_path,
284
+ # "override" => true,
285
+ "refresh_interval" => 0
286
+ }
287
+ end
288
+
289
+ let(:event) { LogStash::Event.new("foo" => [{"bar"=>"two"},{"bar"=>"one"}, {"bar"=>"six"}]) }
290
+ it "adds a translation to each map" do
291
+ subject.register
292
+ subject.filter(event)
293
+ expect(event.get("[foo][0][baz]")).to eq("val-2-1|val-2-2")
294
+ expect(event.get("[foo][1][baz]")).to eq("val-1-1|val-1-2")
295
+ expect(event.get("[foo][2][baz]")).to eq("val-6-1|val-6-2")
296
+ end
297
+ end
298
+ end
299
+
300
+ describe "field and destination are the same (needs override)" do
301
+ let(:dictionary_path) { File.join(File.dirname(__FILE__), "..", "fixtures", "tag-map-dict.yml") }
302
+ let(:config) do
303
+ {
304
+ "field" => "foo",
305
+ "destination" => "foo",
306
+ "dictionary_path" => dictionary_path,
307
+ "override" => true,
308
+ "refresh_interval" => -1
309
+ }
310
+ end
311
+
312
+ let(:event) { LogStash::Event.new("foo" => "nine") }
313
+
314
+ it "overwrites existing value" do
315
+ subject.register
316
+ subject.filter(event)
317
+ expect(event.get("foo")).to eq("val-9-1|val-9-2")
318
+ end
319
+ end
320
+
184
321
  describe "general configuration" do
185
322
  let(:dictionary_path) { File.join(File.dirname(__FILE__), "..", "fixtures", "dict.yml") }
186
323
  let(:config) do
@@ -206,7 +343,7 @@ describe LogStash::Filters::Translate do
206
343
  "field" => "status",
207
344
  "destination" => "translation",
208
345
  "dictionary_path" => dictionary_path,
209
- "refresh_interval" => 10000, # we're controlling this manually
346
+ "refresh_interval" => -1, # we're controlling this manually
210
347
  "exact" => true,
211
348
  "regex" => false,
212
349
  "fallback" => "no match",
@@ -229,7 +366,7 @@ describe LogStash::Filters::Translate do
229
366
  it "overwrites existing entries" do
230
367
  subject.filter(before_mod)
231
368
  IO.write(dictionary_path, modified_content)
232
- subject.send(:load_dictionary)
369
+ subject.lookup.load_dictionary
233
370
  subject.filter(after_mod)
234
371
  expect(before_mod.get("translation")).to eq(2)
235
372
  expect(after_mod.get("translation")).to eq(4)
@@ -237,7 +374,7 @@ describe LogStash::Filters::Translate do
237
374
  it "keeps leftover entries" do
238
375
  subject.filter(before_del)
239
376
  IO.write(dictionary_path, modified_content)
240
- subject.send(:load_dictionary)
377
+ subject.lookup.load_dictionary
241
378
  subject.filter(after_del)
242
379
  expect(before_del.get("translation")).to eq(3)
243
380
  expect(after_del.get("translation")).to eq(3)
@@ -249,7 +386,7 @@ describe LogStash::Filters::Translate do
249
386
  it "overwrites existing entries" do
250
387
  subject.filter(before_mod)
251
388
  IO.write(dictionary_path, modified_content)
252
- subject.send(:load_dictionary)
389
+ subject.lookup.load_dictionary
253
390
  subject.filter(after_mod)
254
391
  expect(before_mod.get("translation")).to eq(2)
255
392
  expect(after_mod.get("translation")).to eq(4)
@@ -257,11 +394,67 @@ describe LogStash::Filters::Translate do
257
394
  it "removes leftover entries" do
258
395
  subject.filter(before_del)
259
396
  IO.write(dictionary_path, modified_content)
260
- subject.send(:load_dictionary)
397
+ subject.lookup.load_dictionary
261
398
  subject.filter(after_del)
262
399
  expect(before_del.get("translation")).to eq(3)
263
400
  expect(after_del.get("translation")).to eq("no match")
264
401
  end
265
402
  end
266
403
  end
404
+
405
+ describe "loading an empty dictionary" do
406
+ let(:directory) { Pathname.new(Stud::Temporary.directory) }
407
+
408
+ let(:config) do
409
+ {
410
+ "field" => "status",
411
+ "destination" => "translation",
412
+ "dictionary_path" => dictionary_path.to_path,
413
+ "refresh_interval" => -1,
414
+ "fallback" => "no match",
415
+ "exact" => true,
416
+ "regex" => false
417
+ }
418
+ end
419
+
420
+ before do
421
+ dictionary_path.open("wb") do |file|
422
+ file.write("")
423
+ end
424
+ end
425
+
426
+ context "when using a yml file" do
427
+ let(:dictionary_path) { directory.join("dict-e.yml") }
428
+ let(:event) { LogStash::Event.new("status" => "a") }
429
+
430
+ it "return the exact translation" do
431
+
432
+ subject.register
433
+ subject.filter(event)
434
+ expect(event.get("translation")).to eq("no match")
435
+ end
436
+ end
437
+
438
+ context "when using a json file" do
439
+ let(:dictionary_path) { directory.join("dict-e.json") }
440
+ let(:event) { LogStash::Event.new("status" => "b") }
441
+
442
+ it "return the exact translation" do
443
+ subject.register
444
+ subject.filter(event)
445
+ expect(event.get("translation")).to eq("no match")
446
+ end
447
+ end
448
+
449
+ context "when using a csv file" do
450
+ let(:dictionary_path) { directory.join("dict-e.csv") }
451
+ let(:event) { LogStash::Event.new("status" => "c") }
452
+
453
+ it "return the exact translation" do
454
+ subject.register
455
+ subject.filter(event)
456
+ expect(event.get("translation")).to eq("no match")
457
+ end
458
+ end
459
+ end
267
460
  end
@@ -0,0 +1,16 @@
1
+ require "logstash/devutils/rspec/spec_helper"
2
+
3
+ require "logstash/filters/dictionary/yaml_visitor"
4
+
5
+ describe LogStash::Filters::Dictionary::YamlVisitor do
6
+ it 'works' do
7
+ yaml_string = "---\na: \n x: 3\nb: \n x: 4\n"
8
+ dictionary = {"c" => {"x" => 5}}
9
+ described_class.create.accept_with_dictionary(dictionary, Psych.parse_stream(yaml_string)).first
10
+ expect(dictionary.keys.sort).to eq(["a", "b", "c"])
11
+ values = dictionary.values
12
+ expect(values[0]).to eq({"x" => 5})
13
+ expect(values[1]).to eq({"x" => 3})
14
+ expect(values[2]).to eq({"x" => 4})
15
+ end
16
+ end
@@ -0,0 +1,4 @@
1
+ "^2[0-9][0-9]$","OK"
2
+ "^3[0-9][0-9]$","Redirect"
3
+ "^4[0-9][0-9]$","Client Error"
4
+ "^5[0-9][0-9]$","Server Error"
@@ -0,0 +1,4 @@
1
+ "200","OK"
2
+ "300","Redirect"
3
+ "400","Client Error"
4
+ "500","Server Error"
@@ -0,0 +1,21 @@
1
+ ---
2
+ !!map {
3
+ ? !!str "eight"
4
+ : !!str "val-8-1|val-8-2",
5
+ ? !!str "five"
6
+ : !!str "val-5-1|val-5-2",
7
+ ? !!str "four"
8
+ : !!str "val-4-1|val-4-2",
9
+ ? !!str "nine"
10
+ : !!str "val-9-1|val-9-2",
11
+ ? !!str "one"
12
+ : !!str "val-1-1|val-1-2",
13
+ ? !!str "seven"
14
+ : !!str "val-7-1|val-7-2",
15
+ ? !!str "six"
16
+ : !!str "val-6-1|val-6-2",
17
+ ? !!str "three"
18
+ : !!str "val-3-1|val-3-2",
19
+ ? !!str "two"
20
+ : !!str "val-2-1|val-2-2",
21
+ }
@@ -0,0 +1,21 @@
1
+ ---
2
+ !!omap {
3
+ ? !!str "eight"
4
+ : !!str "val-8-1|val-8-2",
5
+ ? !!str "five"
6
+ : !!str "val-5-1|val-5-2",
7
+ ? !!str "four"
8
+ : !!str "val-4-1|val-4-2",
9
+ ? !!str "nine"
10
+ : !!str "val-9-1|val-9-2",
11
+ ? !!str "one"
12
+ : !!str "val-1-1|val-1-2",
13
+ ? !!str "seven"
14
+ : !!str "val-7-1|val-7-2",
15
+ ? !!str "six"
16
+ : !!str "val-6-1|val-6-2",
17
+ ? !!str "three"
18
+ : !!str "val-3-1|val-3-2",
19
+ ? !!str "two"
20
+ : !!str "val-2-1|val-2-2",
21
+ }
@@ -0,0 +1,33 @@
1
+ # encoding: utf-8
2
+
3
+ require "securerandom"
4
+
5
+ module LogStash module Filters module Dictionary
6
+ def self.create_huge_csv_dictionary(directory, name, size)
7
+ tmppath = directory.join("temp_big.csv")
8
+ tmppath.open("w") do |file|
9
+ file.puts("foo,#{SecureRandom.hex(4)}")
10
+ file.puts("bar,#{SecureRandom.hex(4)}")
11
+ size.times do |i|
12
+ file.puts("#{SecureRandom.hex(12)},#{1000000 + i}")
13
+ end
14
+ file.puts("baz,quux")
15
+ end
16
+ tmppath.rename(directory.join(name))
17
+ end
18
+
19
+ def self.create_huge_json_dictionary(directory, name, size)
20
+ tmppath = directory.join("temp_big.json")
21
+ tmppath.open("w") do |file|
22
+ file.puts("{")
23
+ file.puts(' "foo":"'.concat(SecureRandom.hex(4)).concat('",'))
24
+ file.puts(' "bar":"'.concat(SecureRandom.hex(4)).concat('",'))
25
+ size.times do |i|
26
+ file.puts(' "'.concat(SecureRandom.hex(12)).concat('":"').concat("#{1000000 + i}").concat('",'))
27
+ end
28
+ file.puts(' "baz":"quux"')
29
+ file.puts("}")
30
+ end
31
+ tmppath.rename(directory.join(name))
32
+ end
33
+ end end end