fluent-plugin-simplearithmetic 0.0.1.pre → 0.0.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: f7a35e0538f55c58d65296c4c8338ecf00a9667b
4
- data.tar.gz: dbcec7416b39c15cc4a0f17bb6a8b923dae573fd
3
+ metadata.gz: 9896bc5f77125536a6e6efec0c519947c8b8c487
4
+ data.tar.gz: 0416741cba7d514ed3bdaf97f063ad03a3d87f33
5
5
  SHA512:
6
- metadata.gz: 285494a14b1989efb7521c7aecc4e307fb1d0c75eeb88f3325bcd70ea6d62ad2bc4a88e8ff736fd946f78c5a7b5f4db22e654d44348a9838868d084e0d32eadb
7
- data.tar.gz: 93a694065302c235b457bc01ccf629145b4ffec7a414a0c890279690667d606d78ff2090fc84c856e28630a755097048afc160016d38343b82ccdae102badbbc
6
+ metadata.gz: 6f18b7a4f4f43996d715a41231946bf83eecf67a2af69d096e82a5f72d60a7e0946c62a9a3c88482fc635b3dbd57d0905f95ba3718fdf6d35c89a2d7e4089ed7
7
+ data.tar.gz: 2574ec4b858814077aa20b9ceb44a4d8f95588fc233ee661229495035394aec602132399e88e2cc35446071eec68ead80be5151540a34d2beb1070a044646f0f
data/README.md CHANGED
@@ -24,7 +24,7 @@ Suppose you have a message like:
24
24
  }
25
25
  ```
26
26
 
27
- Now you can calculate with this `td-agent.conf`:
27
+ Now you can calculate with this configuration:
28
28
 
29
29
  ```
30
30
  <match arithmetic.test>
@@ -32,7 +32,7 @@ Now you can calculate with this `td-agent.conf`:
32
32
  tag calculated.test
33
33
 
34
34
  <formulas>
35
- total_price apple * 200 - orange * 100
35
+ total_price apple * 200 + orange * 100
36
36
 
37
37
  # Calculation order is from up to down.
38
38
  budget 2000 - total_price
@@ -55,31 +55,89 @@ Calculated results will be:
55
55
  "orange": 3,
56
56
  "time_start": "2001-02-03T04:05:06Z",
57
57
  "time_finish": "2001-02-03T04:06:12Z",
58
- "total_price": 1100,
59
- "budget": 900,
58
+ "total_price": 1700,
59
+ "budget": 300,
60
60
  "time_elapsed": 66.0
61
61
  }
62
62
  ```
63
63
 
64
+ If some fields are already defined before calculation, these fields will be overwritten.
65
+
64
66
 
65
67
  ## Configuration
66
68
 
69
+ ### tag
70
+ The tag prefix for emitted event messages. Default is `simple_arithmetic`.
67
71
 
68
72
  ### undefined_variables
69
- 1. `nil`
70
73
 
71
- 2. `undefined` (default)
74
+ A message such like `{'a': 20, 'x': 50}` with the formulas:
75
+
76
+ ```
77
+ <formulas>
78
+ c a + b
79
+ </formulas>
80
+ ```
81
+
82
+ When undefined_variables is `undefined` (default) you get `{'a': 20, 'x': 50}`. Field `'c'` will not be defined.
83
+
84
+ When `nil` you get `{'a': 20, 'c': nil, 'x': 50}`.
85
+
72
86
 
73
87
  ### how_to_process_error
74
- 1. `nil`
75
88
 
76
- 2. `undefined`
89
+ A message such like `{'a': 20, 'b': "string"}` with the formulas:
77
90
 
78
- 3. `error_string` (default)
91
+ ```
92
+ <formulas>
93
+ c a + b
94
+ </formulas>
95
+ ```
79
96
 
97
+ In ruby, this calculation will be raise an error:
80
98
 
81
- ### tag
82
- The tag prefix for emitted event messages. Default is `simple_arithmetic`.
99
+ ```
100
+ irb(main):052:0* a = 20
101
+ => 20
102
+ irb(main):053:0> b = "String"
103
+ => "String"
104
+ irb(main):054:0> c = a + b
105
+ TypeError: String can't be coerced into Fixnum
106
+ from (irb):54:in `+'
107
+ from (irb):54
108
+ from /opt/td-agent/embedded/bin/irb:11:in `<main>'
109
+ ```
110
+
111
+ When how_to_process_error is `nil` you get `{'a': 20, 'b': "string", 'c': nil}`.
112
+
113
+ When `undefined`, you get `{'a': 20, 'b': "string"}`. If an error is raised in the calculation, the field will not be defined.
114
+
115
+ When `error_string` (default), you get: `{'a': 20, 'b': "String", 'c'=>"String can't be coerced into Fixnum"}`. An error message will be assigned to the field.
116
+
117
+ ### replace_hyphen, replace_dollar
118
+
119
+ All formulas will be evaluated as ruby sentences. Some json fields will not be fitted as ruby variables. For example,
120
+
121
+ ```
122
+ <formulas>
123
+ var-1 a + b
124
+ var$2 c * d
125
+ </formulas>
126
+ ```
127
+
128
+ will raise an syntax error in the initialize process of fluentd.
129
+
130
+ To get rid of this case, you can set `replace_hyphen` and `replace_dollar` in the configuration and formulas.
131
+
132
+ ```
133
+ replace_hyphen __H__
134
+ replace_dollar __D__
135
+
136
+ <formulas>
137
+ var__H__1 a + b
138
+ var__D__2 c * d
139
+ </formulas>
140
+ ```
83
141
 
84
142
 
85
143
  ## Copyright
@@ -3,7 +3,7 @@ $:.push File.expand_path("../lib", __FILE__)
3
3
 
4
4
  Gem::Specification.new do |spec|
5
5
  spec.name = "fluent-plugin-simplearithmetic"
6
- spec.version = "0.0.1.pre"
6
+ spec.version = "0.0.1"
7
7
  spec.authors = ["Takahiro Kamatani"]
8
8
  spec.email = ["buhii314@gmail.com"]
9
9
  spec.description = %q{Fluent plugin to calculate messages.}
@@ -11,6 +11,9 @@ module Fluent
11
11
  # 'nil', 'undefined', 'error_string'
12
12
  config_param :how_to_process_error, :string, :default => 'error_string'
13
13
 
14
+ config_param :replace_hyphen, :string, :default => '__HYPHON__'
15
+ config_param :replace_dollar, :string, :default => '__DOLLAR__'
16
+
14
17
  attr_accessor :_formulas
15
18
 
16
19
  def initialize
@@ -41,10 +44,9 @@ module Fluent
41
44
 
42
45
  # Create functions
43
46
  @_formulas = []
44
-
45
47
  def create_func(var, expr)
46
48
  begin
47
- f_argv = expr.scan(/[a-zA-Z][\w\d\.]*/).uniq.select{|x| not x.start_with?('Time.iso8601')}
49
+ f_argv = expr.scan(/[a-zA-Z\_][\w\d\.\_]*/).uniq.select{|x| not x.start_with?('Time.iso8601')}
48
50
  f = eval('lambda {|' + f_argv.join(',') + '| ' + expr + '}')
49
51
  return [f, f_argv]
50
52
  rescue SyntaxError
@@ -61,6 +63,10 @@ module Fluent
61
63
  @_formulas.push [var, f_argv, formula]
62
64
  }
63
65
  }
66
+ if @_formulas.empty?
67
+ raise Fluent::ConfigError, "No formulas found"
68
+ end
69
+
64
70
  end
65
71
 
66
72
  def has_all_keys?(record, argv)
@@ -80,7 +86,30 @@ module Fluent
80
86
  return formula.call(*argv)
81
87
  end
82
88
 
89
+ # functions for symbols
90
+ def replace_symbols(record)
91
+ # 'var-1' -> 'var__HYPHEN__1'
92
+ new_record = {}
93
+ record.each_pair {|key, value|
94
+ new_key = key.gsub('-', @replace_hyphen).gsub('$', @replace_dollar)
95
+ new_record[new_key] = value
96
+ }
97
+ return new_record
98
+ end
99
+
100
+ def restore_symbols(record)
101
+ # 'var__HYPHEN__1' -> 'var-1'
102
+ new_record = {}
103
+ record.each_pair {|key, value|
104
+ new_key = key.gsub(@replace_hyphen, '-').gsub(@replace_dollar, '$')
105
+ new_record[new_key] = value
106
+ }
107
+ new_record
108
+ end
109
+
83
110
  def calculate(record)
111
+ record = replace_symbols(record)
112
+
84
113
  @_formulas.each {|var, f_argv, formula|
85
114
  if not has_all_keys?(record, f_argv)
86
115
  if @undefined_variables == 'nil'
@@ -100,7 +129,8 @@ module Fluent
100
129
  end
101
130
  end
102
131
  }
103
- record
132
+
133
+ restore_symbols(record)
104
134
  end
105
135
 
106
136
  def emit(tag, es, chain)
data/test/helper.rb CHANGED
@@ -22,7 +22,7 @@ unless ENV.has_key?('VERBOSE')
22
22
  $log = nulllogger
23
23
  end
24
24
 
25
- require 'fluent/plugin/out_simplearithmetic'
25
+ require 'fluent/plugin/out_simple_arithmetic'
26
26
 
27
27
  class Test::Unit::TestCase
28
28
  end
@@ -0,0 +1,216 @@
1
+ # -*- coding: utf-8 -*-
2
+ require 'helper'
3
+
4
+ class SimpleArithmeticOutputTest < Test::Unit::TestCase
5
+ def setup
6
+ Fluent::Test.setup
7
+ end
8
+
9
+ CONFIG = %[
10
+ type simple_arithmetic
11
+ tag calculated.test
12
+ undefined_variables nil
13
+ how_to_process_error error_string
14
+
15
+ <formulas>
16
+ x3 x1 * 100 - x2
17
+ var1 Time.iso8601(t1) - Time.iso8601(t2)
18
+ var2 x3 - var1
19
+ </formulas>
20
+ ]
21
+
22
+ def create_driver(conf = CONFIG, tag='test.input')
23
+ Fluent::Test::OutputTestDriver.new(Fluent::SimpleArithmeticOutput, tag).configure(conf)
24
+ end
25
+
26
+ def test_configure
27
+ # No formulas
28
+ assert_raise(Fluent::ConfigError) {
29
+ d = create_driver('')
30
+ }
31
+ # No formulas
32
+ assert_raise(Fluent::ConfigError) {
33
+ d = create_driver %[
34
+ <formulas>
35
+
36
+ </formulas>
37
+ ]
38
+ }
39
+ # Syntax error
40
+ assert_raise(Fluent::ConfigError) {
41
+ d = create_driver %[
42
+ <formulas>
43
+ var1 var2 * var3 +
44
+ </formulas>
45
+ ]
46
+ }
47
+ end
48
+
49
+ def test_replace_functions
50
+ d1 = create_driver %[
51
+ replace_hyphen __H__
52
+ replace_dollar __D__
53
+ <formulas>
54
+ var__H__1 __H__2 * var__D__3
55
+ __D__3 __D__1 + __D__2
56
+ </formulas>
57
+ ]
58
+ assert_equal '__H__', d1.instance.replace_hyphen
59
+ assert_equal '__D__', d1.instance.replace_dollar
60
+ d1.run do
61
+ time = Time.parse("2011-01-02 13:14:15 UTC").to_i
62
+ d1.emit({'-2'=>10, 'var$3'=>20}, time)
63
+ d1.emit({'$1'=>10, '$2'=>20}, time)
64
+ end
65
+ assert_equal d1.emits[0][2], {"-2"=>10, "var$3"=>20, "var-1"=>200}
66
+ assert_equal d1.emits[1][2], {"$1"=>10, "$2"=>20, "$3"=>30}
67
+ end
68
+
69
+ def test_undefined_variables
70
+ # undefined_variables must be either `nil` or `undefined`
71
+ assert_raise(Fluent::ConfigError) {
72
+ d = create_driver %[
73
+ undefined_variables non_existent_config
74
+ <formulas>
75
+ a b + c
76
+ </formulas>
77
+ ]
78
+ }
79
+
80
+ time = Time.parse("2011-01-02 13:14:15 UTC").to_i
81
+
82
+ # nil
83
+ d1 = create_driver %[
84
+ undefined_variables nil
85
+ <formulas>
86
+ a b + c
87
+ </formulas>
88
+ ]
89
+ d1.run do
90
+ d1.emit({'b'=>10, 'c'=>20}, time)
91
+ d1.emit({'b'=>10, 'non-related'=>100}, time)
92
+ end
93
+ assert_equal d1.emits[0][2], {'a'=>30, 'b'=>10, 'c'=>20}
94
+ assert_equal d1.emits[1][2], {'a'=>nil, 'b'=>10, 'non-related'=>100}
95
+
96
+ # undefined
97
+ d2 = create_driver %[
98
+ undefined_variables undefined
99
+ <formulas>
100
+ a b + c
101
+ </formulas>
102
+ ]
103
+ d2.run do
104
+ d2.emit({'b'=>10, 'c'=>20}, time)
105
+ d2.emit({'b'=>10, 'non-related'=>100}, time)
106
+ end
107
+ assert_equal d2.emits[0][2], {'a'=>30, 'b'=>10, 'c'=>20}
108
+ assert_equal d2.emits[1][2], {'b'=>10, 'non-related'=>100}
109
+ end
110
+
111
+ def test_how_to_process_error
112
+ # undefined_variables must be either `nil` or `undefined`, `error_string`
113
+ assert_raise(Fluent::ConfigError) {
114
+ d = create_driver %[
115
+ how_to_process_error non_existent_config
116
+ <formulas>
117
+ a b + c
118
+ </formulas>
119
+ ]
120
+ }
121
+
122
+ time = Time.parse("2011-01-02 13:14:15 UTC").to_i
123
+
124
+ # nil
125
+ d1 = create_driver %[
126
+ how_to_process_error nil
127
+ <formulas>
128
+ a b + c
129
+ </formulas>
130
+ ]
131
+ d1.run do
132
+ d1.emit({'b'=>10, 'c'=>20}, time)
133
+ d1.emit({'b'=>10, 'c'=>'string'}, time)
134
+ end
135
+ assert_equal d1.emits[0][2], {'a'=>30, 'b'=>10, 'c'=>20}
136
+ assert_equal d1.emits[1][2], {'a'=>nil, 'b'=>10, 'c'=>'string'}
137
+
138
+ # undefined
139
+ d2 = create_driver %[
140
+ how_to_process_error undefined
141
+ <formulas>
142
+ a b + c
143
+ </formulas>
144
+ ]
145
+ d2.run do
146
+ d2.emit({'b'=>10, 'c'=>20}, time)
147
+ d2.emit({'b'=>10, 'c'=>'string'}, time)
148
+ end
149
+ assert_equal d2.emits[0][2], {'a'=>30, 'b'=>10, 'c'=>20}
150
+ assert_equal d2.emits[1][2], {'b'=>10, 'c'=>'string'}
151
+
152
+ # error_string
153
+ d3 = create_driver %[
154
+ how_to_process_error error_string
155
+ <formulas>
156
+ a b + c
157
+ </formulas>
158
+ ]
159
+ d3.run do
160
+ d3.emit({'b'=>10, 'c'=>20}, time)
161
+ d3.emit({'b'=>10, 'c'=>'string'}, time)
162
+ end
163
+ assert_equal d3.emits[0][2], {'a'=>30, 'b'=>10, 'c'=>20}
164
+ assert_equal d3.emits[1][2], {'a'=>"String can't be coerced into Fixnum",
165
+ 'b'=>10, 'c'=>'string'}
166
+ end
167
+
168
+ def test_plus_num_and_string
169
+ def calculated(record)
170
+ record['a'] = record['b'] + record['c']
171
+ record
172
+ end
173
+ data = [
174
+ {'b'=>10, 'c'=>20},
175
+ {'b'=>'Dr. Strangelove or: ',
176
+ 'c'=>'How I Learned to Stop Worrying and Love the Bomb'},
177
+ ]
178
+
179
+ time = Time.parse("2011-01-02 13:14:15 UTC").to_i
180
+
181
+ d = create_driver %[
182
+ <formulas>
183
+ a b + c
184
+ </formulas>
185
+ ]
186
+ d.run do
187
+ data.each {|record|
188
+ d.emit(record, time)
189
+ }
190
+ end
191
+ data.each_with_index {|record, index|
192
+ assert_equal d.emits[index][2], calculated(data[index])
193
+ }
194
+ end
195
+
196
+ def test_iso8601
197
+ d = create_driver %[
198
+ <formulas>
199
+ time_diff Time.iso8601(time_finish) - Time.iso8601(time_start)
200
+ </formulas>
201
+ ]
202
+ time = Time.parse("2011-01-02 13:14:15 UTC").to_i
203
+ d.run do
204
+ d.emit(
205
+ {
206
+ 'time_start' => '2001-02-03T04:05:06Z',
207
+ 'time_finish' => '2001-02-03T04:06:12Z',
208
+ }, time)
209
+ end
210
+ assert_equal d.emits[0][2], {
211
+ 'time_start' => '2001-02-03T04:05:06Z',
212
+ 'time_finish'=> '2001-02-03T04:06:12Z',
213
+ 'time_diff'=> 66.0}
214
+ end
215
+
216
+ end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: fluent-plugin-simplearithmetic
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.1.pre
4
+ version: 0.0.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Takahiro Kamatani
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2014-07-11 00:00:00.000000000 Z
11
+ date: 2014-07-13 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: fluentd
@@ -53,7 +53,7 @@ files:
53
53
  - fluent-plugin-simplearithmetic.gemspec
54
54
  - lib/fluent/plugin/out_simple_arithmetic.rb
55
55
  - test/helper.rb
56
- - test/plugin/test_out_simplearithmetic.rb
56
+ - test/plugin/test_out_simple_arithmetic.rb
57
57
  homepage: https://github.com/buhii/fluent-plugin-simplearithmetic
58
58
  licenses:
59
59
  - Apache License, Version 2.0
@@ -69,9 +69,9 @@ required_ruby_version: !ruby/object:Gem::Requirement
69
69
  version: '0'
70
70
  required_rubygems_version: !ruby/object:Gem::Requirement
71
71
  requirements:
72
- - - ">"
72
+ - - ">="
73
73
  - !ruby/object:Gem::Version
74
- version: 1.3.1
74
+ version: '0'
75
75
  requirements: []
76
76
  rubyforge_project:
77
77
  rubygems_version: 2.2.2
@@ -80,4 +80,4 @@ specification_version: 4
80
80
  summary: Fluent plugin to calculate messages.
81
81
  test_files:
82
82
  - test/helper.rb
83
- - test/plugin/test_out_simplearithmetic.rb
83
+ - test/plugin/test_out_simple_arithmetic.rb
@@ -1,60 +0,0 @@
1
- # -*- coding: utf-8 -*-
2
- require 'helper'
3
-
4
- class SimpleArithmeticOutputTest < Test::Unit::TestCase
5
- def setup
6
- Fluent::Test.setup
7
- end
8
-
9
- CONFIG = %[
10
- type simple_arithmetic
11
- tag calculated.test
12
- undefined_variables nil # nil, undefined
13
- how_to_process_error error_string # nil, undefined, error_string
14
-
15
- <formulas>
16
- x3 x1 * 100 - x2
17
- var1 Time.iso8601(t1) - Time.iso8601(t2)
18
- var2 x3 - var1
19
- </formulas>
20
- ]
21
-
22
- def create_driver(conf = CONFIG, tag='test.input')
23
- Fluent::Test::OutputTestDriver.new(Fluent::SimpleArithmeticOutput, tag).configure(conf)
24
- end
25
-
26
- def test_configure
27
- assert_raise(Fluent::ConfigError) {
28
- d = create_driver('')
29
- }
30
- # no variables for calculation
31
- assert_raise(Fluent::ConfigError) {
32
- d = create_driver %[
33
- <formulas>
34
-
35
- </formulas>
36
- ]
37
- }
38
- # Syntax Error
39
- assert_raise(Fluent::ConfigError) {
40
- d = create_driver %[
41
- <formulas>
42
- var_undefined
43
- </formulas>
44
- ]
45
- }
46
- d = create_driver %[
47
- <formulas>
48
- var1 var2 * var3
49
- </formulas>
50
- ]
51
- end
52
-
53
- def test_create_formula
54
- d = create_driver
55
- end
56
-
57
- def test_write
58
- d = create_driver
59
- end
60
- end