fluent-plugin-librato-metrics 0.2.2
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.
- data/.gitignore +4 -0
- data/ChangeLog +5 -0
- data/Gemfile +4 -0
- data/README.rdoc +51 -0
- data/Rakefile +12 -0
- data/VERSION +1 -0
- data/fluent-plugin-librato-metrics.gemspec +23 -0
- data/lib/fluent/plugin/out_librato_metrics.rb +148 -0
- data/lib/fluent/plugin/out_librato_metrics_mixin.rb +317 -0
- data/test/out_librato_metrics.rb +81 -0
- metadata +84 -0
data/.gitignore
ADDED
data/Gemfile
ADDED
data/README.rdoc
ADDED
@@ -0,0 +1,51 @@
|
|
1
|
+
= Librato Metrics output plugin for Fluent event collector
|
2
|
+
|
3
|
+
== Overview
|
4
|
+
|
5
|
+
*librato_metrics* output plugin buffers aggregate logs and upload them to Librato Metrics periodically.
|
6
|
+
|
7
|
+
== Installation
|
8
|
+
|
9
|
+
Simply use RubyGems:
|
10
|
+
|
11
|
+
gem install fluent-plugin-librato-metrics
|
12
|
+
|
13
|
+
== Configuration
|
14
|
+
|
15
|
+
<match pattern>
|
16
|
+
type librato_metrics
|
17
|
+
|
18
|
+
librato_user YOUR_LIBRATO_USER_NAME
|
19
|
+
librato_token YOUR_LIBRATO_TOKEN
|
20
|
+
|
21
|
+
# simple key-value metrics
|
22
|
+
<metrics metrics.status.**>
|
23
|
+
name status
|
24
|
+
each_key key
|
25
|
+
value_key value
|
26
|
+
</metrics>
|
27
|
+
|
28
|
+
# single-stream event count
|
29
|
+
<metrics metrics.event.mytask>
|
30
|
+
name mytask.count
|
31
|
+
</metrics>
|
32
|
+
|
33
|
+
# single-stream event sum
|
34
|
+
<metrics metrics.event.mytask>
|
35
|
+
name mytask.size
|
36
|
+
value_key size
|
37
|
+
</metrics>
|
38
|
+
|
39
|
+
# single-stream event sum; value type is float
|
40
|
+
<metrics metrics.event.mytask>
|
41
|
+
name mytask.elapsed
|
42
|
+
value_key elapsed
|
43
|
+
type float
|
44
|
+
</metrics>
|
45
|
+
|
46
|
+
</match>
|
47
|
+
|
48
|
+
[librato_user (required)] User name of librato metrics
|
49
|
+
|
50
|
+
[librato_token (required)] Token of librato metrics
|
51
|
+
|
data/Rakefile
ADDED
data/VERSION
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
0.2.2
|
@@ -0,0 +1,23 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
$:.push File.expand_path("../lib", __FILE__)
|
3
|
+
|
4
|
+
Gem::Specification.new do |s|
|
5
|
+
s.name = "fluent-plugin-librato-metrics"
|
6
|
+
s.version = File.read("VERSION").strip
|
7
|
+
s.authors = ["Sadayuki Furuhashi"]
|
8
|
+
s.email = ["frsyuki@gmail.com"]
|
9
|
+
#s.homepage = "https://github.com/fluent/fluent-plugin-librato-metrics" # TODO
|
10
|
+
s.summary = %q{Librato metrics output plugin for Fluent event collector}
|
11
|
+
s.description = %q{Librato metrics output plugin for Fluent event collector}
|
12
|
+
|
13
|
+
s.files = `git ls-files`.split("\n")
|
14
|
+
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
15
|
+
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
16
|
+
s.require_paths = ["lib"]
|
17
|
+
|
18
|
+
# specify any dependencies here; for example:
|
19
|
+
# s.add_development_dependency "rspec"
|
20
|
+
# s.add_runtime_dependency "rest-client"
|
21
|
+
s.add_dependency "fluentd", "~> 0.10.0"
|
22
|
+
s.add_development_dependency "rake", ">= 0.9.2"
|
23
|
+
end
|
@@ -0,0 +1,148 @@
|
|
1
|
+
#
|
2
|
+
# fluent-plugin-librato-metrics
|
3
|
+
#
|
4
|
+
# Copyright (C) 2011-2012 Sadayuki Furuhashi
|
5
|
+
#
|
6
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
7
|
+
# you may not use this file except in compliance with the License.
|
8
|
+
# You may obtain a copy of the License at
|
9
|
+
#
|
10
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
11
|
+
#
|
12
|
+
# Unless required by applicable law or agreed to in writing, software
|
13
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
14
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
15
|
+
# See the License for the specific language governing permissions and
|
16
|
+
# limitations under the License.
|
17
|
+
#
|
18
|
+
module Fluent
|
19
|
+
|
20
|
+
|
21
|
+
class LibratoMetricsOutput < Fluent::BufferedOutput
|
22
|
+
Fluent::Plugin.register_output('librato_metrics', self)
|
23
|
+
|
24
|
+
require 'net/http'
|
25
|
+
require "#{File.dirname(__FILE__)}/out_librato_metrics_mixin"
|
26
|
+
include MetricsMixin
|
27
|
+
|
28
|
+
config_param :librato_user, :string
|
29
|
+
config_param :librato_token, :string
|
30
|
+
config_param :source, :string, :default => nil
|
31
|
+
|
32
|
+
def initialize
|
33
|
+
super
|
34
|
+
end
|
35
|
+
|
36
|
+
def configure(conf)
|
37
|
+
super
|
38
|
+
end
|
39
|
+
|
40
|
+
def format(tag, time, record)
|
41
|
+
out = ''.force_encoding('ASCII-8BIT')
|
42
|
+
each_metrics(tag, time, record) {|d|
|
43
|
+
name = d.name
|
44
|
+
if d.each_keys.empty?
|
45
|
+
key = name
|
46
|
+
else
|
47
|
+
key = "#{name}.#{d.keys.join('.')}"
|
48
|
+
end
|
49
|
+
partitioned_time = time / 60 * 60
|
50
|
+
[key, partitioned_time, d.value*d.count].to_msgpack(out)
|
51
|
+
}
|
52
|
+
out
|
53
|
+
end
|
54
|
+
|
55
|
+
def write(chunk)
|
56
|
+
counters = {} #=> {partitioned_time => {name => CounterAggregator}}
|
57
|
+
gauges = {} #=> {partitioned_time => {name => GaugeAggregator}}
|
58
|
+
|
59
|
+
chunk.msgpack_each {|key,partitioned_time,value|
|
60
|
+
if m = /^counter\.(.*)$/.match(key)
|
61
|
+
name = m[1]
|
62
|
+
((counters[partitioned_time] ||= {})[name] ||= CounterAggregator.new).add(value)
|
63
|
+
elsif m = /^gauge\.(.*)$/.match(key)
|
64
|
+
name = m[1]
|
65
|
+
((gauges[partitioned_time] ||= {})[name] ||= GaugeAggregator.new).add(value)
|
66
|
+
else
|
67
|
+
name = key
|
68
|
+
((gauges[partitioned_time] ||= {})[name] ||= GaugeAggregator.new).add(value)
|
69
|
+
end
|
70
|
+
}
|
71
|
+
|
72
|
+
#http = Net::HTTP.new('metrics-api.librato.com', 80)
|
73
|
+
http = Net::HTTP.new('metrics-api.librato.com', 443)
|
74
|
+
http.use_ssl = true
|
75
|
+
#http.verify_mode = OpenSSL::SSL::VERIFY_PEER
|
76
|
+
http.verify_mode = OpenSSL::SSL::VERIFY_NONE # TODO verify
|
77
|
+
http.cert_store = OpenSSL::X509::Store.new
|
78
|
+
header = {}
|
79
|
+
|
80
|
+
begin
|
81
|
+
{'counters'=>counters, 'gauges'=>gauges}.each_pair {|type,partitions|
|
82
|
+
partitions.each_pair {|partitioned_time,name_aggrs|
|
83
|
+
req = Net::HTTP::Post.new('/v1/metrics', header)
|
84
|
+
req.basic_auth @librato_user, @librato_token
|
85
|
+
|
86
|
+
params = {
|
87
|
+
'measure_time' => partitioned_time.to_s,
|
88
|
+
}
|
89
|
+
params['source'] = @source if @source
|
90
|
+
|
91
|
+
name_aggrs.each_with_index {|(name,aggr),i|
|
92
|
+
params["#{type}[#{i}][name]"] = name
|
93
|
+
params["#{type}[#{i}][value]"] = aggr.get.to_s
|
94
|
+
}
|
95
|
+
|
96
|
+
$log.trace { "librato metrics: #{params.inspect}" }
|
97
|
+
req.set_form_data(params)
|
98
|
+
res = http.request(req)
|
99
|
+
|
100
|
+
# TODO error handling
|
101
|
+
if res.code != "200"
|
102
|
+
$log.warn "librato_metrics: #{res.code}: #{res.body}"
|
103
|
+
end
|
104
|
+
}
|
105
|
+
}
|
106
|
+
ensure
|
107
|
+
http.finish if http.started?
|
108
|
+
end
|
109
|
+
end
|
110
|
+
|
111
|
+
|
112
|
+
# max(value) aggregator
|
113
|
+
class CounterAggregator
|
114
|
+
def initialize
|
115
|
+
@value = 0
|
116
|
+
end
|
117
|
+
|
118
|
+
def add(value)
|
119
|
+
@value = value if @value < value
|
120
|
+
end
|
121
|
+
|
122
|
+
def get
|
123
|
+
# librato metrics's counter only supports integer:
|
124
|
+
# 'invalid value for Integer(): "0.06268015"'
|
125
|
+
@value.to_i
|
126
|
+
end
|
127
|
+
end
|
128
|
+
|
129
|
+
# avg(value) aggregator
|
130
|
+
class GaugeAggregator
|
131
|
+
def initialize
|
132
|
+
@value = 0
|
133
|
+
@num = 0
|
134
|
+
end
|
135
|
+
|
136
|
+
def add(value)
|
137
|
+
@value += value
|
138
|
+
@num += 1
|
139
|
+
end
|
140
|
+
|
141
|
+
def get
|
142
|
+
@value / @num
|
143
|
+
end
|
144
|
+
end
|
145
|
+
end
|
146
|
+
|
147
|
+
|
148
|
+
end
|
@@ -0,0 +1,317 @@
|
|
1
|
+
#
|
2
|
+
# fluent-plugin-librato-metrics
|
3
|
+
#
|
4
|
+
# Copyright (C) 2011 FURUHASHI Sadayuki
|
5
|
+
#
|
6
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
7
|
+
# you may not use this file except in compliance with the License.
|
8
|
+
# You may obtain a copy of the License at
|
9
|
+
#
|
10
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
11
|
+
#
|
12
|
+
# Unless required by applicable law or agreed to in writing, software
|
13
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
14
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
15
|
+
# See the License for the specific language governing permissions and
|
16
|
+
# limitations under the License.
|
17
|
+
#
|
18
|
+
module Fluent
|
19
|
+
|
20
|
+
|
21
|
+
module LibratoMetricsOutput::MetricsMixin
|
22
|
+
include Configurable
|
23
|
+
|
24
|
+
def initialize
|
25
|
+
super
|
26
|
+
@metrics = []
|
27
|
+
end
|
28
|
+
|
29
|
+
attr_reader :metrics
|
30
|
+
|
31
|
+
config_param :default_value_key, :string, :default => nil
|
32
|
+
config_param :default_count_key, :string, :default => nil
|
33
|
+
config_param :default_type, :string, :default => nil
|
34
|
+
config_param :match_key, :string, :default => nil
|
35
|
+
|
36
|
+
def configure(conf)
|
37
|
+
super
|
38
|
+
|
39
|
+
defaults = {
|
40
|
+
'value_key' => @default_value_key,
|
41
|
+
'count_key' => @default_count_key,
|
42
|
+
'type' => @default_type,
|
43
|
+
}
|
44
|
+
|
45
|
+
conf.elements.select {|e|
|
46
|
+
e.name == 'metrics'
|
47
|
+
}.each {|e|
|
48
|
+
defaults.each_pair {|k,v| e[k] = v if v != nil }
|
49
|
+
add_metrics(e, e.arg)
|
50
|
+
}
|
51
|
+
|
52
|
+
if mk = @match_key
|
53
|
+
@match_key_proc = Proc.new {|tag,record| record[mk] }
|
54
|
+
else
|
55
|
+
@match_key_proc = Proc.new {|tag,record| tag }
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
def add_metrics(conf, pattern)
|
60
|
+
m = Metrics.new(pattern)
|
61
|
+
m.configure(conf)
|
62
|
+
@metrics << m
|
63
|
+
end
|
64
|
+
|
65
|
+
class Data
|
66
|
+
def initialize(metrics)
|
67
|
+
@metrics = metrics
|
68
|
+
@name = metrics.name
|
69
|
+
@each_keys = metrics.each_keys
|
70
|
+
@value_key = metrics.value_key
|
71
|
+
@count_key = metrics.count_key
|
72
|
+
end
|
73
|
+
|
74
|
+
attr_reader :metrics
|
75
|
+
attr_reader :name, :each_keys, :value_key, :count_key
|
76
|
+
attr_accessor :keys, :value, :count
|
77
|
+
end
|
78
|
+
|
79
|
+
class Metrics
|
80
|
+
include Configurable
|
81
|
+
|
82
|
+
def initialize(pattern)
|
83
|
+
super()
|
84
|
+
if pattern && !pattern.empty?
|
85
|
+
@pattern = MatchPattern.create(pattern)
|
86
|
+
else
|
87
|
+
@pattern = nil
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
attr_reader :pattern
|
92
|
+
|
93
|
+
config_param :name, :string
|
94
|
+
|
95
|
+
config_param :each_key, :string, :default => nil
|
96
|
+
attr_reader :each_keys # parsed 'each_key'
|
97
|
+
|
98
|
+
config_param :value_key, :string, :default => nil
|
99
|
+
config_param :default_value, :string, :default => nil
|
100
|
+
|
101
|
+
config_param :count_key, :string, :default => nil
|
102
|
+
|
103
|
+
config_param :type, :default => :int do |val|
|
104
|
+
case val
|
105
|
+
when 'int'
|
106
|
+
:int
|
107
|
+
when 'float'
|
108
|
+
:float
|
109
|
+
else
|
110
|
+
raise ConfigError, "unexpected 'type' parameter on metrics: expected int or float"
|
111
|
+
end
|
112
|
+
end
|
113
|
+
|
114
|
+
config_param :match_key, :string, :default => nil
|
115
|
+
|
116
|
+
attr_accessor :key_proc
|
117
|
+
attr_accessor :value_proc
|
118
|
+
attr_accessor :count_proc
|
119
|
+
attr_accessor :match_proc
|
120
|
+
|
121
|
+
def configure(conf)
|
122
|
+
super
|
123
|
+
|
124
|
+
if @each_key
|
125
|
+
@each_keys = @each_key.split(',').map {|e| e.strip }
|
126
|
+
@key_proc = create_combined_key_proc(@each_keys)
|
127
|
+
else
|
128
|
+
@each_keys = []
|
129
|
+
use_keys = [@name]
|
130
|
+
@key_proc = Proc.new {|record| use_keys }
|
131
|
+
end
|
132
|
+
|
133
|
+
case @type
|
134
|
+
when :int
|
135
|
+
if vk = @value_key
|
136
|
+
dv = @default_value ? @default_value.to_i : nil
|
137
|
+
@value_proc = Proc.new {|record| val = record[vk]; val ? val.to_i : dv }
|
138
|
+
else
|
139
|
+
dv = @default_value ? @default_value.to_i : 1
|
140
|
+
@value_proc = Proc.new {|record| dv }
|
141
|
+
end
|
142
|
+
when :float
|
143
|
+
if vk = @value_key
|
144
|
+
dv = @default_value ? @default_value.to_f : nil
|
145
|
+
@value_proc = Proc.new {|record| val = record[vk]; val ? val.to_f : dv }
|
146
|
+
else
|
147
|
+
dv = @default_value ? @default_value.to_f : 1.0
|
148
|
+
@value_proc = Proc.new {|record| dv }
|
149
|
+
end
|
150
|
+
end
|
151
|
+
|
152
|
+
if ck = @count_key
|
153
|
+
@count_proc = Proc.new {|record| val = record[ck].to_i; val == 0 ? 1 : val }
|
154
|
+
else
|
155
|
+
@count_proc = Proc.new {|record| 1 }
|
156
|
+
end
|
157
|
+
|
158
|
+
if pt = @pattern
|
159
|
+
@match_proc = Proc.new {|tag| pt.match(tag) }
|
160
|
+
else
|
161
|
+
@match_proc = Proc.new {|tag| true }
|
162
|
+
end
|
163
|
+
|
164
|
+
@data = Data.new(self)
|
165
|
+
end
|
166
|
+
|
167
|
+
def create_combined_key_proc(keys)
|
168
|
+
if keys.length == 1
|
169
|
+
key = keys[0]
|
170
|
+
Proc.new {|record|
|
171
|
+
val = record[key]
|
172
|
+
val ? [val] : nil
|
173
|
+
}
|
174
|
+
else
|
175
|
+
Proc.new {|record|
|
176
|
+
keys.map {|key|
|
177
|
+
val = record[key]
|
178
|
+
break nil unless val
|
179
|
+
val
|
180
|
+
}
|
181
|
+
}
|
182
|
+
end
|
183
|
+
end
|
184
|
+
|
185
|
+
def evaluate(tag, time, record)
|
186
|
+
return nil unless @match_proc.call(tag)
|
187
|
+
|
188
|
+
data = @data
|
189
|
+
|
190
|
+
keys = data.keys = @key_proc.call(record)
|
191
|
+
return nil unless keys
|
192
|
+
|
193
|
+
value = data.value = @value_proc.call(record)
|
194
|
+
return nil unless value
|
195
|
+
|
196
|
+
data.count = @count_proc.call(record)
|
197
|
+
|
198
|
+
return data
|
199
|
+
end
|
200
|
+
end
|
201
|
+
|
202
|
+
def each_metrics(tag, time, record, &block)
|
203
|
+
mk = @match_key_proc.call(tag, record)
|
204
|
+
return [] unless mk
|
205
|
+
@metrics.map {|m|
|
206
|
+
data = m.evaluate(mk, time, record)
|
207
|
+
next unless data
|
208
|
+
block.call(data)
|
209
|
+
}
|
210
|
+
end
|
211
|
+
end
|
212
|
+
|
213
|
+
|
214
|
+
## Example
|
215
|
+
#
|
216
|
+
#class MetricsOutput < Output
|
217
|
+
# Plugin.register_output('metrics', self)
|
218
|
+
#
|
219
|
+
# include MetricsMixin
|
220
|
+
#
|
221
|
+
# def initialize
|
222
|
+
# super
|
223
|
+
# end
|
224
|
+
#
|
225
|
+
# config_param :tag, :string, :default => nil
|
226
|
+
# config_param :tag_prefix, :string, :default => nil
|
227
|
+
#
|
228
|
+
# def configure(conf)
|
229
|
+
# super
|
230
|
+
#
|
231
|
+
# if constant_tag = @tag
|
232
|
+
# @tag_proc = Proc.new {|name,tag| constant_tag }
|
233
|
+
# elsif tag_prefix = @tag_prefix
|
234
|
+
# @tag_proc = Proc.new {|name,tag| "#{tag_prefix}.#{name}.#{tag}" }
|
235
|
+
# else
|
236
|
+
# @tag_proc = Proc.new {|name,tag| "#{name}.#{tag}" }
|
237
|
+
# end
|
238
|
+
# end
|
239
|
+
#
|
240
|
+
# def emit(tag, es, chain)
|
241
|
+
# es.each {|time,record|
|
242
|
+
# each_metrics(tag, time, record) {|m|
|
243
|
+
# otag = @tag_proc.call(m.name, tag)
|
244
|
+
# orecord = {
|
245
|
+
# 'name' => m.name,
|
246
|
+
# 'key' => m.keys.join(','),
|
247
|
+
# 'keys' => m.keys,
|
248
|
+
# 'key_hash' => Hash[ m.each_keys.zip(m.keys) ],
|
249
|
+
# 'value' => m.value,
|
250
|
+
# 'value_hash' => {m.value_key => m.value},
|
251
|
+
# 'count' => m.count,
|
252
|
+
# }
|
253
|
+
# Engine.emit(otag, time, orecord)
|
254
|
+
# }
|
255
|
+
# }
|
256
|
+
# chain.next
|
257
|
+
# end
|
258
|
+
#end
|
259
|
+
|
260
|
+
|
261
|
+
## Example
|
262
|
+
#
|
263
|
+
#require 'metrics'
|
264
|
+
#
|
265
|
+
#class ExampleAggregationOutput < BufferedOutput
|
266
|
+
# Plugin.register_output('aggregation_example', self)
|
267
|
+
#
|
268
|
+
# include MetricsMixin
|
269
|
+
#
|
270
|
+
# def initialize
|
271
|
+
# super
|
272
|
+
# end
|
273
|
+
#
|
274
|
+
# def configure(conf)
|
275
|
+
# super
|
276
|
+
#
|
277
|
+
# # do something ...
|
278
|
+
# end
|
279
|
+
#
|
280
|
+
# def format(tag, time, record)
|
281
|
+
# # call each_metrics(tag, time,record):
|
282
|
+
# each_metrics(tag, time, record) {|m|
|
283
|
+
# # 'm.name' is always avaiable
|
284
|
+
# name = m.name
|
285
|
+
#
|
286
|
+
# # 'keys' is an array of record value if each_key option is specified.
|
287
|
+
# # otherwise, 'keys' is same as [m.name]
|
288
|
+
# key = m.keys.join(',')
|
289
|
+
#
|
290
|
+
# if !m.each_keys.empty?
|
291
|
+
# # you can create Hash of the record using 'm.each_keys'
|
292
|
+
# key_hash = Hash[ m.each_keys.zip(m.keys) ]
|
293
|
+
# else
|
294
|
+
# # m.keys is [name]
|
295
|
+
# end
|
296
|
+
#
|
297
|
+
# if m.value_key
|
298
|
+
# # value is parsed record value
|
299
|
+
# value_hash = {m.value_key => m.value}
|
300
|
+
# else
|
301
|
+
# # m.value is 1 or 1.0
|
302
|
+
# end
|
303
|
+
#
|
304
|
+
# if m.count_key
|
305
|
+
# # value is parsed record value
|
306
|
+
# count_hash = {m.count_key => m.count}
|
307
|
+
# else
|
308
|
+
# # count is 1
|
309
|
+
# end
|
310
|
+
#
|
311
|
+
# # ...
|
312
|
+
# }
|
313
|
+
# end
|
314
|
+
#end
|
315
|
+
|
316
|
+
|
317
|
+
end
|
@@ -0,0 +1,81 @@
|
|
1
|
+
$:.push File.expand_path("../lib", __FILE__)
|
2
|
+
require 'fluent/test'
|
3
|
+
require 'fluent/plugin/out_librato_metrics'
|
4
|
+
|
5
|
+
class LibratoMetricsOutputTest < Test::Unit::TestCase
|
6
|
+
def setup
|
7
|
+
Fluent::Test.setup
|
8
|
+
end
|
9
|
+
|
10
|
+
CONFIG = %[
|
11
|
+
librato_user test
|
12
|
+
librato_token TEST
|
13
|
+
|
14
|
+
# simple key-value metrics
|
15
|
+
<metrics test1.**>
|
16
|
+
name test1
|
17
|
+
each_key key
|
18
|
+
value_key value
|
19
|
+
count_key count
|
20
|
+
</metrics>
|
21
|
+
|
22
|
+
# single-stream event count
|
23
|
+
<metrics test2.**>
|
24
|
+
name test2.count
|
25
|
+
</metrics>
|
26
|
+
|
27
|
+
# single-stream event sum
|
28
|
+
<metrics test3.**>
|
29
|
+
name test3.size
|
30
|
+
value_key size
|
31
|
+
</metrics>
|
32
|
+
|
33
|
+
# single-stream event sum; value type is float
|
34
|
+
<metrics test3.test4>
|
35
|
+
name test4.elapsed
|
36
|
+
value_key elapsed
|
37
|
+
type float
|
38
|
+
</metrics>
|
39
|
+
]
|
40
|
+
|
41
|
+
TIME = Time.parse("2011-01-02 13:14:15 UTC").to_i
|
42
|
+
|
43
|
+
def create_driver(tag="test", conf=CONFIG)
|
44
|
+
Fluent::Test::BufferedOutputTestDriver.new(Fluent::LibratoMetricsOutput, tag) do
|
45
|
+
def write(chunk)
|
46
|
+
chunk.read
|
47
|
+
end
|
48
|
+
end.configure(conf)
|
49
|
+
end
|
50
|
+
|
51
|
+
def test_configure
|
52
|
+
d = create_driver
|
53
|
+
assert_equal 'test', d.instance.librato_user
|
54
|
+
assert_equal 'TEST', d.instance.librato_token
|
55
|
+
end
|
56
|
+
|
57
|
+
def test_format
|
58
|
+
d = create_driver("test1.1")
|
59
|
+
d.emit({"key"=>"a", "value"=>10, "count"=>2}, TIME)
|
60
|
+
d.expect_format ["test1.a", TIME/60*60, 20].to_msgpack
|
61
|
+
d.run
|
62
|
+
|
63
|
+
d = create_driver("test2.2")
|
64
|
+
d.emit({}, TIME)
|
65
|
+
d.expect_format ["test2.count", TIME/60*60, 1].to_msgpack
|
66
|
+
d.run
|
67
|
+
|
68
|
+
d = create_driver("test3.3")
|
69
|
+
d.emit({"size"=>2100}, TIME)
|
70
|
+
d.expect_format ["test3.size", TIME/60*60, 2100].to_msgpack
|
71
|
+
d.run
|
72
|
+
|
73
|
+
d = create_driver("test3.test4")
|
74
|
+
d.emit({"size"=>2400, "elapsed"=>10.0}, TIME)
|
75
|
+
d.expect_format ["test3.size", TIME/60*60, 2400].to_msgpack
|
76
|
+
d.expect_format ["test4.elapsed", TIME/60*60, 10.0].to_msgpack
|
77
|
+
d.run
|
78
|
+
end
|
79
|
+
|
80
|
+
end
|
81
|
+
|
metadata
ADDED
@@ -0,0 +1,84 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: fluent-plugin-librato-metrics
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.2.2
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Sadayuki Furuhashi
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2012-03-30 00:00:00.000000000Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: fluentd
|
16
|
+
requirement: &70131020756540 !ruby/object:Gem::Requirement
|
17
|
+
none: false
|
18
|
+
requirements:
|
19
|
+
- - ~>
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: 0.10.0
|
22
|
+
type: :runtime
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: *70131020756540
|
25
|
+
- !ruby/object:Gem::Dependency
|
26
|
+
name: rake
|
27
|
+
requirement: &70131020756060 !ruby/object:Gem::Requirement
|
28
|
+
none: false
|
29
|
+
requirements:
|
30
|
+
- - ! '>='
|
31
|
+
- !ruby/object:Gem::Version
|
32
|
+
version: 0.9.2
|
33
|
+
type: :development
|
34
|
+
prerelease: false
|
35
|
+
version_requirements: *70131020756060
|
36
|
+
description: Librato metrics output plugin for Fluent event collector
|
37
|
+
email:
|
38
|
+
- frsyuki@gmail.com
|
39
|
+
executables: []
|
40
|
+
extensions: []
|
41
|
+
extra_rdoc_files: []
|
42
|
+
files:
|
43
|
+
- .gitignore
|
44
|
+
- ChangeLog
|
45
|
+
- Gemfile
|
46
|
+
- README.rdoc
|
47
|
+
- Rakefile
|
48
|
+
- VERSION
|
49
|
+
- fluent-plugin-librato-metrics.gemspec
|
50
|
+
- lib/fluent/plugin/out_librato_metrics.rb
|
51
|
+
- lib/fluent/plugin/out_librato_metrics_mixin.rb
|
52
|
+
- test/out_librato_metrics.rb
|
53
|
+
homepage:
|
54
|
+
licenses: []
|
55
|
+
post_install_message:
|
56
|
+
rdoc_options: []
|
57
|
+
require_paths:
|
58
|
+
- lib
|
59
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
60
|
+
none: false
|
61
|
+
requirements:
|
62
|
+
- - ! '>='
|
63
|
+
- !ruby/object:Gem::Version
|
64
|
+
version: '0'
|
65
|
+
segments:
|
66
|
+
- 0
|
67
|
+
hash: -197996435032986197
|
68
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
69
|
+
none: false
|
70
|
+
requirements:
|
71
|
+
- - ! '>='
|
72
|
+
- !ruby/object:Gem::Version
|
73
|
+
version: '0'
|
74
|
+
segments:
|
75
|
+
- 0
|
76
|
+
hash: -197996435032986197
|
77
|
+
requirements: []
|
78
|
+
rubyforge_project:
|
79
|
+
rubygems_version: 1.8.12
|
80
|
+
signing_key:
|
81
|
+
specification_version: 3
|
82
|
+
summary: Librato metrics output plugin for Fluent event collector
|
83
|
+
test_files:
|
84
|
+
- test/out_librato_metrics.rb
|