fluent-plugin-yohoushi 0.0.5 → 0.1.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 0d33e56754f4290c20f7b06b38587f735fc86c2f
4
- data.tar.gz: f5e963e6b9fa7bb2ff74c8c63d551906277da04f
3
+ metadata.gz: 65e9f7d306f6d8b262d7af0585fd52b898ed2c3b
4
+ data.tar.gz: d9caea2616664dd9d2bbffc6abefba2855d9d5ea
5
5
  SHA512:
6
- metadata.gz: e7c1f30ae26ff1025657de6b2812a88e46785e510b69a3d0e98aca8a51065349a481c6551e23b643c4d6d6ec9db2e30218fcbd767ea89d50d4a7a64db9ac7a94
7
- data.tar.gz: 667ae677f9de049f407561f5425c945748189581b53bd65282fac15546c261150658d2af240994519a4838c06db0650e155e384e5690799d08d23cbee62f1515
6
+ metadata.gz: 7f1e6c7d991049ad623219a997452a279aa0a105c9ea2353ea5d4549b3df0f92a2f74169e74e4619348cb74966a2c222ee1b692e290b5da501ca191313ef6832
7
+ data.tar.gz: 8ec234f0bc39e5c4df6a8f5804ccb29759fd256e96966ad3733730f3c870c4063972df958d557fa626c537a9a6bb095616984f0bdb925ebe0bc36decd5282a51
data/CHANGELOG.md CHANGED
@@ -1,3 +1,9 @@
1
+ ## 0.1.0 (2014/01/29)
2
+
3
+ Changes:
4
+
5
+ * fluent-plugin-yohoushi is now a buffer plugin
6
+
1
7
  ## 0.0.5 (2014/01/25)
2
8
 
3
9
  Fixes:
@@ -3,7 +3,7 @@ $:.push File.expand_path("../lib", __FILE__)
3
3
 
4
4
  Gem::Specification.new do |s|
5
5
  s.name = "fluent-plugin-yohoushi"
6
- s.version = "0.0.5"
6
+ s.version = "0.1.0"
7
7
  s.authors = ["Naotoshi Seo"]
8
8
  s.email = ["sonots@gmail.com"]
9
9
  s.homepage = "https://github.com/sonots/fluent-plugin-yohoushi"
@@ -1,227 +1,239 @@
1
- class Fluent::YohoushiOutput < Fluent::Output
2
- Fluent::Plugin.register_output('yohoushi', self)
3
-
4
- MAPPING_MAX_NUM = 20
5
- KEY_MAX_NUM = 20
6
-
7
- def initialize
8
- super
9
- require 'socket'
10
- require 'multiforecast-client'
11
- require 'yohoushi-client'
12
- end
13
-
14
- config_param :base_uri, :string, :default => nil
15
- (1..MAPPING_MAX_NUM).each {|i| config_param "mapping#{i}".to_sym, :string, :default => nil }
16
- config_param :key_pattern, :string, :default => nil
17
- (1..KEY_MAX_NUM).each {|i| config_param "key#{i}".to_sym, :string, :default => nil }
18
- config_param :enable_float_number, :bool, :default => false
19
- config_param :mode, :default => :gauge do |val|
20
- case val.downcase
21
- when 'gauge'
22
- :gauge
23
- when 'count'
24
- :count
25
- when 'modified'
26
- :modified
27
- when 'derive'
28
- :derive
29
- else
30
- raise Fluent::ConfigError, "stdout output output_type should be `gauge`, `count`, `modified`, or `derive`"
1
+ module Fluent
2
+ class YohoushiOutput < BufferedOutput
3
+ Plugin.register_output('yohoushi', self)
4
+
5
+ MAPPING_MAX_NUM = 20
6
+ KEY_MAX_NUM = 20
7
+
8
+ def initialize
9
+ super
10
+ require 'socket'
11
+ require 'multiforecast-client'
12
+ require 'yohoushi-client'
31
13
  end
32
- end
33
- config_param :enable_ruby, :bool, :default => true # true for lower version compatibility
34
-
35
- # for test
36
- attr_reader :client
37
- attr_reader :mapping
38
- attr_reader :keys
39
- attr_reader :key_pattern
40
- attr_reader :key_pattern_path
41
-
42
- def configure(conf)
43
- super
44
-
45
- if @base_uri
46
- @client = Yohoushi::Client.new(@base_uri)
47
- else
48
- @mapping = {}
49
- (1..MAPPING_MAX_NUM).each do |i|
50
- next unless conf["mapping#{i}"]
51
- from, to = conf["mapping#{i}"].split(/ +/, 2)
52
- raise Fluent::ConfigError, "mapping#{i} does not contain 2 parameters" unless to
53
- @mapping[from] = to
54
- end
55
- @client = MultiForecast::Client.new('mapping' => @mapping) unless @mapping.empty?
56
- end
57
- raise Fluent::ConfigError, "Either of `base_uri` or `mapping1` must be specified" unless @client
58
-
59
- if @key_pattern
60
- key_pattern, @key_pattern_path = @key_pattern.split(/ +/, 2)
61
- raise Fluent::ConfigError, "key_pattern does not contain 2 parameters" unless @key_pattern_path
62
- @key_pattern = Regexp.compile(key_pattern)
63
- else
64
- @keys = {}
65
- (1..KEY_MAX_NUM).each do |i|
66
- next unless conf["key#{i}"]
67
- key, path = conf["key#{i}"].split(/ +/, 2)
68
- raise Fluent::ConfigError, "key#{i} does not contain 2 parameters" unless path
69
- @keys[key] = path
14
+
15
+ config_param :base_uri, :string, :default => nil
16
+ (1..MAPPING_MAX_NUM).each {|i| config_param "mapping#{i}".to_sym, :string, :default => nil }
17
+ config_param :key_pattern, :string, :default => nil
18
+ (1..KEY_MAX_NUM).each {|i| config_param "key#{i}".to_sym, :string, :default => nil }
19
+ config_param :enable_float_number, :bool, :default => false
20
+ config_param :mode, :default => :gauge do |val|
21
+ case val.downcase
22
+ when 'gauge'
23
+ :gauge
24
+ when 'count'
25
+ :count
26
+ when 'modified'
27
+ :modified
28
+ when 'derive'
29
+ :derive
30
+ else
31
+ raise ConfigError, "stdout output output_type should be `gauge`, `count`, `modified`, or `derive`"
70
32
  end
71
33
  end
72
- raise Fluent::ConfigError, "Either of `key_pattern` or `key1` must be specified" if (@key_pattern.nil? and @keys.empty?)
73
-
74
- @placeholder_expander =
75
- if @enable_ruby
76
- # require utilities which would be used in ruby placeholders
77
- require 'pathname'
78
- require 'uri'
79
- require 'cgi'
80
- RubyPlaceholderExpander.new
34
+ config_param :enable_ruby, :bool, :default => true # true for lower version compatibility
35
+
36
+ # Override default parameters of Bufferedoutput options
37
+ config_param :buffer_type, :string, :default => 'memory'
38
+ config_param :flush_interval, :time, :default => 0 # we can not wait 1 minute to create 1 minute graphs (originally, 60)
39
+ config_param :try_flush_interval, :float, :default => 1 # we would be able to shorten more
40
+ config_param :retry_limit, :integer, :default => 1 # growthforecast requires a realtime post, so retry only once (originally, 17)
41
+ config_param :retry_wait, :time, :default => 1.0
42
+ config_param :max_retry_wait, :time, :default => nil
43
+ config_param :num_threads, :integer, :default => 1
44
+ config_param :queued_chunk_flush_interval, :time, :default => 1
45
+
46
+ # for test
47
+ attr_reader :client
48
+ attr_reader :mapping
49
+ attr_reader :keys
50
+ attr_reader :key_pattern
51
+ attr_reader :key_pattern_path
52
+
53
+ def configure(conf)
54
+ super
55
+
56
+ if @base_uri
57
+ @client = Yohoushi::Client.new(@base_uri)
81
58
  else
82
- PlaceholderExpander.new
59
+ @mapping = {}
60
+ (1..MAPPING_MAX_NUM).each do |i|
61
+ next unless conf["mapping#{i}"]
62
+ from, to = conf["mapping#{i}"].split(/ +/, 2)
63
+ raise ConfigError, "mapping#{i} does not contain 2 parameters" unless to
64
+ @mapping[from] = to
65
+ end
66
+ @client = MultiForecast::Client.new('mapping' => @mapping) unless @mapping.empty?
83
67
  end
68
+ raise ConfigError, "Either of `base_uri` or `mapping1` must be specified" unless @client
84
69
 
85
- @hostname = Socket.gethostname
86
- rescue => e
87
- raise Fluent::ConfigError, "#{e.class} #{e.message} #{e.backtrace.first}"
88
- end
89
-
90
- def start
91
- super
92
- end
93
-
94
- def shutdown
95
- super
96
- end
97
-
98
- def post(path, number)
99
- if @enable_float_number
100
- @client.post_graph(path, { 'number' => number.to_f, 'mode' => @mode.to_s })
101
- else
102
- @client.post_graph(path, { 'number' => number.to_i, 'mode' => @mode.to_s })
103
- end
104
- rescue => e
105
- $log.warn "out_yohoushi: #{e.class} #{e.message} #{e.backtrace.first}"
106
- end
107
-
108
- def emit(tag, es, chain)
109
- tag_parts = tag.split('.')
110
- tag_prefix = tag_prefix(tag_parts)
111
- tag_suffix = tag_suffix(tag_parts)
112
- placeholders = {
113
- 'tag' => tag,
114
- 'tags' => tag_parts, # for lower compatibility
115
- 'tag_parts' => tag_parts,
116
- 'tag_prefix' => tag_prefix,
117
- 'tag_suffix' => tag_suffix,
118
- 'hostname' => @hostname,
119
- }
120
- if @key_pattern
121
- es.each do |time, record|
122
- record.each do |key, value|
123
- next unless key =~ @key_pattern
124
- placeholders['key'] = key
125
- path = expand_placeholder(@key_pattern_path, time, record, placeholders)
126
- post(path, value)
70
+ if @key_pattern
71
+ key_pattern, @key_pattern_path = @key_pattern.split(/ +/, 2)
72
+ raise ConfigError, "key_pattern does not contain 2 parameters" unless @key_pattern_path
73
+ @key_pattern = Regexp.compile(key_pattern)
74
+ else
75
+ @keys = {}
76
+ (1..KEY_MAX_NUM).each do |i|
77
+ next unless conf["key#{i}"]
78
+ key, path = conf["key#{i}"].split(/ +/, 2)
79
+ raise ConfigError, "key#{i} does not contain 2 parameters" unless path
80
+ @keys[key] = path
127
81
  end
128
82
  end
129
- else # keys
130
- es.each do |time, record|
131
- @keys.each do |key, path|
132
- next unless value = record[key]
133
- placeholders['key'] = key
134
- path = expand_placeholder(path, time, record, placeholders)
135
- post(path, value)
83
+ raise ConfigError, "Either of `key_pattern` or `key1` must be specified" if (@key_pattern.nil? and @keys.empty?)
84
+
85
+ @placeholder_expander =
86
+ if @enable_ruby
87
+ # require utilities which would be used in ruby placeholders
88
+ require 'pathname'
89
+ require 'uri'
90
+ require 'cgi'
91
+ RubyPlaceholderExpander.new
92
+ else
93
+ PlaceholderExpander.new
136
94
  end
137
- end
95
+
96
+ @hostname = Socket.gethostname
97
+ rescue => e
98
+ raise ConfigError, "#{e.class} #{e.message} #{e.backtrace.first}"
138
99
  end
139
100
 
140
- chain.next
141
- rescue => e
142
- $log.warn "out_yohoushi: #{e.class} #{e.message} #{e.backtrace.first}"
143
- end
101
+ def start
102
+ super
103
+ end
144
104
 
145
- def expand_placeholder(value, time, record, opts)
146
- @placeholder_expander.prepare_placeholders(time, record, opts)
147
- @placeholder_expander.expand(value)
148
- end
105
+ def shutdown
106
+ super
107
+ end
149
108
 
150
- def tag_prefix(tag_parts)
151
- return [] if tag_parts.empty?
152
- tag_prefix = [tag_parts.first]
153
- 1.upto(tag_parts.size-1).each do |i|
154
- tag_prefix[i] = "#{tag_prefix[i-1]}.#{tag_parts[i]}"
109
+ def post(path, number)
110
+ if @enable_float_number
111
+ @client.post_graph(path, { 'number' => number.to_f, 'mode' => @mode.to_s })
112
+ else
113
+ @client.post_graph(path, { 'number' => number.to_i, 'mode' => @mode.to_s })
114
+ end
115
+ rescue => e
116
+ $log.warn "out_yohoushi: #{e.class} #{e.message} #{e.backtrace.first}"
155
117
  end
156
- tag_prefix
157
- end
158
118
 
159
- def tag_suffix(tag_parts)
160
- return [] if tag_parts.empty?
161
- rev_tag_parts = tag_parts.reverse
162
- rev_tag_suffix = [rev_tag_parts.first]
163
- 1.upto(tag_parts.size-1).each do |i|
164
- rev_tag_suffix[i] = "#{rev_tag_parts[i]}.#{rev_tag_suffix[i-1]}"
119
+ def format(tag, time, record)
120
+ [tag, time, record].to_msgpack
165
121
  end
166
- rev_tag_suffix.reverse
167
- end
168
122
 
169
- class PlaceholderExpander
170
- attr_reader :placeholders
171
-
172
- def prepare_placeholders(time, record, opts)
173
- placeholders = { '${time}' => Time.at(time).to_s }
174
- record.each {|key, val| placeholders.store("${#{key}}", val) }
175
-
176
- opts.each do |key, val|
177
- if val.kind_of?(Array)
178
- size = val.size
179
- val.each_with_index { |t, idx|
180
- placeholders.store("${#{key}[#{idx}]}", t)
181
- placeholders.store("${#{key}[#{idx-size}]}", t) # support [-1]
182
- }
183
- else # string, interger, float, and others?
184
- placeholders["${#{key}}"] = val
123
+ def write(chunk)
124
+ chunk.msgpack_each do |tag, time, record|
125
+ tag_parts = tag.split('.')
126
+ tag_prefix = tag_prefix(tag_parts)
127
+ tag_suffix = tag_suffix(tag_parts)
128
+ placeholders = {
129
+ 'tag' => tag,
130
+ 'tags' => tag_parts, # for lower compatibility
131
+ 'tag_parts' => tag_parts,
132
+ 'tag_prefix' => tag_prefix,
133
+ 'tag_suffix' => tag_suffix,
134
+ 'hostname' => @hostname,
135
+ }
136
+ if @key_pattern
137
+ record.each do |key, value|
138
+ next unless key =~ @key_pattern
139
+ placeholders['key'] = key
140
+ path = expand_placeholder(@key_pattern_path, time, record, placeholders)
141
+ post(path, value)
142
+ end
143
+ else # keys
144
+ @keys.each do |key, path|
145
+ next unless value = record[key]
146
+ placeholders['key'] = key
147
+ path = expand_placeholder(path, time, record, placeholders)
148
+ post(path, value)
149
+ end
185
150
  end
186
151
  end
152
+ rescue => e
153
+ $log.warn "out_yohoushi: #{e.class} #{e.message} #{e.backtrace.first}"
154
+ end
187
155
 
188
- @placeholders = placeholders
156
+ def expand_placeholder(value, time, record, opts)
157
+ @placeholder_expander.prepare_placeholders(time, record, opts)
158
+ @placeholder_expander.expand(value)
189
159
  end
190
160
 
191
- def expand(str)
192
- str.gsub(/(\${[a-z_]+(\[-?[0-9]+\])?}|__[A-Z_]+__)/) {
193
- $log.warn "record_reformer: unknown placeholder `#{$1}` found" unless @placeholders.include?($1)
194
- @placeholders[$1]
195
- }
161
+ def tag_prefix(tag_parts)
162
+ return [] if tag_parts.empty?
163
+ tag_prefix = [tag_parts.first]
164
+ 1.upto(tag_parts.size-1).each do |i|
165
+ tag_prefix[i] = "#{tag_prefix[i-1]}.#{tag_parts[i]}"
166
+ end
167
+ tag_prefix
196
168
  end
197
- end
198
169
 
199
- class RubyPlaceholderExpander
200
- attr_reader :placeholders
201
-
202
- # Get placeholders as a struct
203
- #
204
- # @param [Time] time the time
205
- # @param [Hash] record the record
206
- # @param [Hash] opts others
207
- def prepare_placeholders(time, record, opts)
208
- struct = UndefOpenStruct.new(record)
209
- struct.time = Time.at(time)
210
- opts.each {|key, val| struct.__send__("#{key}=", val) }
211
- @placeholders = struct
170
+ def tag_suffix(tag_parts)
171
+ return [] if tag_parts.empty?
172
+ rev_tag_parts = tag_parts.reverse
173
+ rev_tag_suffix = [rev_tag_parts.first]
174
+ 1.upto(tag_parts.size-1).each do |i|
175
+ rev_tag_suffix[i] = "#{rev_tag_parts[i]}.#{rev_tag_suffix[i-1]}"
176
+ end
177
+ rev_tag_suffix.reverse
212
178
  end
213
179
 
214
- # Replace placeholders in a string
215
- #
216
- # @param [String] str the string to be replaced
217
- def expand(str)
218
- str = str.gsub(/\$\{([^}]+)\}/, '#{\1}') # ${..} => #{..}
219
- eval "\"#{str}\"", @placeholders.instance_eval { binding }
180
+ class PlaceholderExpander
181
+ attr_reader :placeholders
182
+
183
+ def prepare_placeholders(time, record, opts)
184
+ placeholders = { '${time}' => Time.at(time).to_s }
185
+ record.each {|key, value| placeholders.store("${#{key}}", value) }
186
+
187
+ opts.each do |key, value|
188
+ if value.kind_of?(Array) # tag_parts, etc
189
+ size = value.size
190
+ value.each_with_index { |v, idx|
191
+ placeholders.store("${#{key}[#{idx}]}", v)
192
+ placeholders.store("${#{key}[#{idx-size}]}", v) # support [-1]
193
+ }
194
+ else # string, interger, float, and others?
195
+ placeholders.store("${#{key}}", value)
196
+ end
197
+ end
198
+
199
+ @placeholders = placeholders
200
+ end
201
+
202
+ def expand(str)
203
+ str.gsub(/(\${[a-z_]+(\[-?[0-9]+\])?}|__[A-Z_]+__)/) {
204
+ $log.warn "record_reformer: unknown placeholder `#{$1}` found" unless @placeholders.include?($1)
205
+ @placeholders[$1]
206
+ }
207
+ end
220
208
  end
221
209
 
222
- class UndefOpenStruct < OpenStruct
223
- (Object.instance_methods).each do |m|
224
- undef_method m unless m.to_s =~ /^__|respond_to_missing\?|object_id|public_methods|instance_eval|method_missing|define_singleton_method|respond_to\?|new_ostruct_member/
210
+ class RubyPlaceholderExpander
211
+ attr_reader :placeholders
212
+
213
+ # Get placeholders as a struct
214
+ #
215
+ # @param [Time] time the time
216
+ # @param [Hash] record the record
217
+ # @param [Hash] opts others
218
+ def prepare_placeholders(time, record, opts)
219
+ struct = UndefOpenStruct.new(record)
220
+ struct.time = Time.at(time)
221
+ opts.each {|key, value| struct.__send__("#{key}=", value) }
222
+ @placeholders = struct
223
+ end
224
+
225
+ # Replace placeholders in a string
226
+ #
227
+ # @param [String] str the string to be replaced
228
+ def expand(str)
229
+ str = str.gsub(/\$\{([^}]+)\}/, '#{\1}') # ${..} => #{..}
230
+ eval "\"#{str}\"", @placeholders.instance_eval { binding }
231
+ end
232
+
233
+ class UndefOpenStruct < OpenStruct
234
+ (Object.instance_methods).each do |m|
235
+ undef_method m unless m.to_s =~ /^__|respond_to_missing\?|object_id|public_methods|instance_eval|method_missing|define_singleton_method|respond_to\?|new_ostruct_member/
236
+ end
225
237
  end
226
238
  end
227
239
  end
@@ -19,9 +19,8 @@ describe Fluent::YohoushiOutput do
19
19
  let(:yohoushi_base_uri) { 'http://localhost:4804' }
20
20
  let(:growthforecast_base_uri) { 'http://localhost:5125' }
21
21
  let(:tag) { 'test' }
22
- let(:driver) { Fluent::Test::OutputTestDriver.new(Fluent::YohoushiOutput, tag).configure(config) }
22
+ let(:driver) { Fluent::Test::BufferedOutputTestDriver.new(Fluent::YohoushiOutput, tag).configure(config) }
23
23
  let(:instance) { driver.instance }
24
- let(:emit) { driver.run { messages.each {|message| driver.emit(message, time) } } }
25
24
 
26
25
  describe 'test configure' do
27
26
  context "empty" do
@@ -80,6 +79,7 @@ describe Fluent::YohoushiOutput do
80
79
  end
81
80
 
82
81
  describe 'test emit' do
82
+ let(:emit) { d = driver; messages.each {|message| d.emit(message, time) }; d.run; }
83
83
  let(:time) { Time.now.to_i }
84
84
  let(:messages) do
85
85
  [
@@ -144,7 +144,7 @@ describe Fluent::YohoushiOutput do
144
144
  let(:tag) { 'fluent.error' }
145
145
  let(:time) { Time.now.to_i }
146
146
  let(:record) { { 'foo_count' => "1" } }
147
- let(:emit) { driver.run { driver.emit(record, time) } }
147
+ let(:emit) { d = driver; d.emit(record, time); d.run; }
148
148
  let(:expected_path) { "/fluent/error/fluent.error/1/foo_count/#{Time.at(time)}" }
149
149
  let(:expected_value) { '1' }
150
150
  before { driver.instance.should_receive(:post).with(expected_path, expected_value) }
@@ -173,7 +173,7 @@ describe Fluent::YohoushiOutput do
173
173
  let(:tag) { 'fluent.error' }
174
174
  let(:time) { Time.now.to_i }
175
175
  let(:record) { { 'foo_count' => "1" } }
176
- let(:emit) { driver.run { driver.emit(record, time) } }
176
+ let(:emit) { d = driver; d.emit(record, time); d.run; }
177
177
  let(:expected_path) { "/fluent/error/fluent.error/1/foo_count/#{Time.at(time)}" }
178
178
  let(:expected_value) { '1' }
179
179
  before { driver.instance.should_receive(:post).with(expected_path, expected_value) }
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: fluent-plugin-yohoushi
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.5
4
+ version: 0.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Naotoshi Seo
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2014-01-25 00:00:00.000000000 Z
11
+ date: 2014-01-28 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: fluentd