fluent-plugin-metricsense 0.1.1 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
data/Gemfile CHANGED
@@ -1,2 +1,3 @@
1
- source :rubygems
1
+ source 'https://rubygems.org'
2
+
2
3
  gemspec
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.1.1
1
+ 0.2.0
@@ -22,7 +22,7 @@ module Fluent::MetricSenseOutput::Backends
22
22
  require 'json'
23
23
 
24
24
  class LibratoBackend < Fluent::MetricSenseOutput::Backend
25
- Fluent::MetricSenseOutput::BACKENDS['librato'] = self
25
+ Fluent::MetricSenseOutput.register_backend('librato', self)
26
26
 
27
27
  config_param :librato_user, :string
28
28
  config_param :librato_token, :string
@@ -48,7 +48,7 @@ module Fluent::MetricSenseOutput::Backends
48
48
  req.basic_auth @librato_user, @librato_token
49
49
 
50
50
  data = []
51
- slice.each_with_index {|(tag,time,value,seg_key,seg_val),i|
51
+ slice.each_with_index {|(tag,time,value,seg_key,seg_val,mode),i|
52
52
  if seg_key
53
53
  name = "#{tag}:#{seg_key}"
54
54
  source = seg_val
@@ -63,7 +63,7 @@ module Fluent::MetricSenseOutput::Backends
63
63
  }
64
64
  h["source"] = source.to_s if source
65
65
  data << h
66
- ensure_metric_initialized(http, name)
66
+ ensure_metric_initialized(http, name, mode)
67
67
  }
68
68
  body = {"gauges"=>data}.to_json
69
69
 
@@ -83,22 +83,32 @@ module Fluent::MetricSenseOutput::Backends
83
83
  end
84
84
  end
85
85
 
86
- METRIC_INITIALIZE_REQUEST = [
87
- "type=gauge",
88
- "attributes[source_aggregate]=true",
89
- "attributes[summarize_function]=sum",
90
- "attributes[display_stacked]=true",
91
- ].join('&')
86
+ METRIC_INITIALIZE_REQUEST_PER_MODE = []
92
87
 
93
- def ensure_metric_initialized(http, name)
88
+ METRIC_INITIALIZE_REQUEST_PER_MODE[UpdateMode::ADD] = {
89
+ "type" => "gauge",
90
+ "attributes" => {
91
+ "source_aggregate" => true,
92
+ "summarize_function" => "sum",
93
+ }
94
+ }.to_json
95
+
96
+ METRIC_INITIALIZE_REQUEST_PER_MODE[UpdateMode::LATEST] = {
97
+ "type" => "gauge",
98
+ "attributes" => {
99
+ }
100
+ }.to_json
101
+
102
+ def ensure_metric_initialized(http, name, mode)
94
103
  return if @initialized_metrics[name]
95
104
 
96
105
  header = {}
97
106
  req = Net::HTTP::Put.new("/v1/metrics/#{CGI.escape name}", header)
98
107
  req.basic_auth @librato_user, @librato_token
99
108
 
100
- $log.trace { "librato initialize metric: #{name}" }
101
- req.body = METRIC_INITIALIZE_REQUEST
109
+ $log.trace { "librato initialize metric with mode #{mode}: #{name}" }
110
+ req.body = METRIC_INITIALIZE_REQUEST_PER_MODE[mode]
111
+ req.set_content_type("application/json")
102
112
  res = http.request(req)
103
113
 
104
114
  # TODO error handling
@@ -18,9 +18,7 @@
18
18
  module Fluent::MetricSenseOutput::Backends
19
19
 
20
20
  class RDBTSDBBackend < Fluent::MetricSenseOutput::Backend
21
- include Fluent::Configurable
22
-
23
- Fluent::MetricSenseOutput::BACKENDS['rdb_tsdb'] = self
21
+ Fluent::MetricSenseOutput.register_backend('rdb_tsdb', self)
24
22
 
25
23
  config_param :rdb_url, :string
26
24
  config_param :rdb_table_prefix, :string
@@ -180,7 +178,8 @@ module Fluent::MetricSenseOutput::Backends
180
178
  ensure_connect do |db|
181
179
  # group by row_key (base_time,metric_id,segment_id)
182
180
  rows = {}
183
- data.each {|(tag,time,value,seg_key,seg_val)|
181
+ data.each {|tag,time,value,seg_key,seg_val,mode|
182
+ # TODO update_mode is not supported yet
184
183
  base_time = time / ROW_TIME_WINDOW
185
184
  metric_id = get_metric_id(db, tag, seg_key)
186
185
  segment_id = get_segment_id(db, seg_val) if seg_val
@@ -18,10 +18,10 @@
18
18
  module Fluent::MetricSenseOutput::Backends
19
19
 
20
20
  class StdoutBackend < Fluent::MetricSenseOutput::Backend
21
- Fluent::MetricSenseOutput::BACKENDS['stdout'] = self
21
+ Fluent::MetricSenseOutput.register_backend('stdout', self)
22
22
 
23
23
  def write(data)
24
- data.each {|tag,time,value,seg_key,seg_val|
24
+ data.each {|tag,time,value,seg_key,seg_val,mode|
25
25
  if seg_key
26
26
  puts "#{Time.at(time)} #{tag}: #{value}"
27
27
  else
@@ -23,28 +23,43 @@ module Fluent
23
23
 
24
24
  BACKENDS = {}
25
25
 
26
+ def self.register_backend(name, klass)
27
+ BACKENDS[name] = klass
28
+ end
29
+
30
+ module UpdateMode
31
+ ADD = 0
32
+ LATEST = 1
33
+ end
34
+
26
35
  class Backend
36
+ UpdateMode = MetricSenseOutput::UpdateMode
27
37
  include Configurable
28
-
29
38
  def start
30
39
  end
31
-
32
40
  def shutdown
33
41
  end
34
42
  end
35
43
 
36
- backend_dir = "#{File.dirname(__FILE__)}/backend"
37
- Dir.glob("#{backend_dir}/*_backend.rb") {|e|
38
- require e
39
- }
44
+ module Backends
45
+ backend_dir = "#{File.dirname(__FILE__)}/backends"
46
+ require "#{backend_dir}/librato_backend"
47
+ require "#{backend_dir}/rdb_tsdb_backend"
48
+ require "#{backend_dir}/stdout_backend"
49
+ end
40
50
 
41
- config_param :segment_keys, :string, :default => nil
42
- config_param :all_segment, :bool, :default => false
43
51
  config_param :value_key, :string, :default => 'value'
44
52
 
45
- config_param :backend, :string
53
+ config_param :no_segment_keys, :bool, :default => false
54
+ config_param :only_segment_keys, :string, :default => nil
55
+ config_param :exclude_segment_keys, :string, :default => nil
56
+
57
+ config_param :update_mode_key, :string, :default => 'update_mode'
46
58
 
47
59
  config_param :remove_tag_prefix, :string, :default => nil
60
+ config_param :add_tag_prefix, :string, :default => nil
61
+
62
+ config_param :backend, :string
48
63
 
49
64
  def configure(conf)
50
65
  super
@@ -53,16 +68,14 @@ module Fluent
53
68
  @remove_tag_prefix = Regexp.new('^' + Regexp.escape(@remove_tag_prefix) + "\\.?")
54
69
  end
55
70
 
56
- if conf.has_key?('all_segment') && conf['all_segment'].empty?
57
- @all_segment = true
71
+ @no_segment_keys = (conf.has_key?('no_segment_keys') && (conf['no_segment_keys'].empty? || conf['no_segment_keys'] == 'true'))
72
+
73
+ if @only_segment_keys
74
+ @only_segment_keys = @only_segment_keys.strip.split(/\s*,\s*/)
58
75
  end
59
76
 
60
- if @all_segment
61
- @segment_keys = nil
62
- elsif @segment_keys
63
- @segment_keys = @segment_keys.strip.split(/\s*,\s*/)
64
- else
65
- @segment_keys = []
77
+ if @exclude_segment_keys
78
+ @exclude_segment_keys = @exclude_segment_keys.strip.split(/\s*,\s*/)
66
79
  end
67
80
 
68
81
  be = BACKENDS[@backend]
@@ -85,14 +98,27 @@ module Fluent
85
98
  end
86
99
 
87
100
  def format_stream(tag, es)
88
- out = ''
101
+ # modify tag
89
102
  tag = tag.sub(@remove_tag_prefix, '') if @remove_tag_prefix
103
+ tag = "#{add_tag_prefix}.#{tag}" if @add_tag_prefix
104
+
105
+ out = ''
90
106
  es.each do |time,record|
91
- value = record[@value_key]
107
+ # dup record to modify
108
+ record = record.dup
92
109
 
93
- fv = value.to_f
110
+ # get value
111
+ value = record.delete(@value_key)
112
+
113
+ # ignore record if value is invalid or 0
114
+ begin
115
+ fv = value.to_f
116
+ rescue
117
+ next
118
+ end
94
119
  next if fv == 0.0
95
120
 
121
+ # use integer if value.to_f == value.to_f.to_i
96
122
  iv = fv.to_i
97
123
  if iv.to_f == fv
98
124
  value = iv
@@ -100,35 +126,71 @@ module Fluent
100
126
  value = fv
101
127
  end
102
128
 
103
- seg_keys = @segment_keys
104
- unless seg_keys
105
- seg_keys = record.keys
106
- seg_keys.delete(@value_key)
129
+ # get update_mode key
130
+ update_mode = record.delete(@update_mode_key)
131
+ case update_mode
132
+ when "latest"
133
+ update_mode = UpdateMode::LATEST
134
+ else
135
+ # default is add
136
+ update_mode = UpdateMode::ADD
107
137
  end
108
138
 
109
- segs = []
110
- seg_keys.each {|seg_key|
111
- if seg_val = record[seg_key]
112
- segs << seg_key
113
- segs << seg_val
139
+ # get segments
140
+ if @no_segment_keys
141
+ segments = {}
142
+ else
143
+ if @only_segment_keys
144
+ segments = {}
145
+ @only_segment_keys.each {|key|
146
+ if v = record[key]
147
+ segments[key] = v
148
+ end
149
+ }
150
+ else
151
+ segments = record
114
152
  end
115
- }
153
+ if @exclude_segment_keys
154
+ @exclude_segment_keys.each {|key|
155
+ segments.delete(key)
156
+ }
157
+ end
158
+ end
116
159
 
117
- [tag, time, value, segs].to_msgpack(out)
160
+ [tag, time, value, segments, update_mode].to_msgpack(out)
118
161
  end
162
+
119
163
  out
120
164
  end
121
165
 
122
- class SumAggregator
166
+ class AddUpdater
123
167
  def initialize
124
168
  @value = 0
125
169
  end
170
+ attr_reader :value
126
171
 
127
172
  def add(value)
128
173
  @value += value
129
174
  end
130
175
 
176
+ def mode
177
+ UpdateMode::ADD
178
+ end
179
+ end
180
+
181
+ class LatestUpdater
182
+ def initialize
183
+ @value = 0
184
+ end
131
185
  attr_reader :value
186
+
187
+ def add(value)
188
+ @value += value
189
+ end
190
+
191
+ def mode
192
+ UpdateMode::LATEST
193
+ end
132
194
  end
133
195
 
134
196
  AggregationKey = Struct.new(:tag, :time, :seg_val, :seg_key)
@@ -137,21 +199,34 @@ module Fluent
137
199
  counters = {}
138
200
 
139
201
  # select sum(value) from chunk group by tag, time/60, seg_val, seg_key
140
- chunk.msgpack_each {|tag,time,value,segs|
202
+ chunk.msgpack_each {|tag,time,value,segments,update_mode|
141
203
  time = time / 60 * 60
142
204
 
205
+ case update_mode
206
+ when UpdateMode::ADD
207
+ updater = AddUpdater
208
+ when UpdateMode::LATEST
209
+ updater = LatestUpdater
210
+ else # default is AddUpdater
211
+ updater = AddUpdater
212
+ end
213
+
214
+ # total value
143
215
  ak = AggregationKey.new(tag, time, nil, nil)
144
- (counters[ak] ||= SumAggregator.new).add(value)
216
+ (counters[ak] ||= updater.new).add(value)
217
+
218
+ # segmented values
219
+ segments = Hash[segments] if segments.is_a?(Array) # for backward compat
145
220
 
146
- segs.each_slice(2) {|seg_key,seg_val|
221
+ segments.each_pair {|seg_key,seg_val|
147
222
  ak = AggregationKey.new(tag, time, seg_val, seg_key)
148
- (counters[ak] ||= SumAggregator.new).add(value)
223
+ (counters[ak] ||= updater.new).add(value)
149
224
  }
150
225
  }
151
226
 
152
227
  data = []
153
- counters.each_pair {|ak,aggr|
154
- data << [ak.tag, ak.time, aggr.value, ak.seg_key, ak.seg_val]
228
+ counters.each_pair {|ak,up|
229
+ data << [ak.tag, ak.time, up.value, ak.seg_key, ak.seg_val, up.mode]
155
230
  }
156
231
 
157
232
  @backend.write(data)
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: fluent-plugin-metricsense
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.1
4
+ version: 0.2.0
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2013-04-26 00:00:00.000000000 Z
12
+ date: 2013-05-10 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: fluentd
@@ -87,9 +87,9 @@ files:
87
87
  - Rakefile
88
88
  - VERSION
89
89
  - fluent-plugin-metricsense.gemspec
90
- - lib/fluent/plugin/backend/librato_backend.rb
91
- - lib/fluent/plugin/backend/rdb_tsdb_backend.rb
92
- - lib/fluent/plugin/backend/stdout_backend.rb
90
+ - lib/fluent/plugin/backends/librato_backend.rb
91
+ - lib/fluent/plugin/backends/rdb_tsdb_backend.rb
92
+ - lib/fluent/plugin/backends/stdout_backend.rb
93
93
  - lib/fluent/plugin/out_metricsense.rb
94
94
  homepage: https://github.com/treasure-data/fluent-plugin-metricsense
95
95
  licenses: []
@@ -103,18 +103,12 @@ required_ruby_version: !ruby/object:Gem::Requirement
103
103
  - - ! '>='
104
104
  - !ruby/object:Gem::Version
105
105
  version: '0'
106
- segments:
107
- - 0
108
- hash: 143460017522358519
109
106
  required_rubygems_version: !ruby/object:Gem::Requirement
110
107
  none: false
111
108
  requirements:
112
109
  - - ! '>='
113
110
  - !ruby/object:Gem::Version
114
111
  version: '0'
115
- segments:
116
- - 0
117
- hash: 143460017522358519
118
112
  requirements: []
119
113
  rubyforge_project:
120
114
  rubygems_version: 1.8.23
@@ -122,3 +116,4 @@ signing_key:
122
116
  specification_version: 3
123
117
  summary: MetricSense - application metrics aggregation plugin for Fluentd
124
118
  test_files: []
119
+ has_rdoc: false