fluent-plugin-yohoushi 0.0.5 → 0.1.0

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