fluent-plugin-metricsense 0.1.1 → 0.2.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.
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