librato-rack 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- data/LICENSE +24 -0
- data/README.md +176 -0
- data/Rakefile +25 -0
- data/lib/librato-rack.rb +1 -0
- data/lib/librato/collector.rb +48 -0
- data/lib/librato/collector/aggregator.rb +97 -0
- data/lib/librato/collector/counter_cache.rb +113 -0
- data/lib/librato/collector/group.rb +29 -0
- data/lib/librato/rack.rb +116 -0
- data/lib/librato/rack/configuration.rb +61 -0
- data/lib/librato/rack/errors.rb +7 -0
- data/lib/librato/rack/logger.rb +71 -0
- data/lib/librato/rack/tracker.rb +137 -0
- data/lib/librato/rack/validating_queue.rb +41 -0
- data/lib/librato/rack/version.rb +5 -0
- data/lib/librato/rack/worker.rb +49 -0
- data/test/apps/basic.ru +20 -0
- data/test/apps/custom.ru +27 -0
- data/test/apps/heroku.ru +27 -0
- data/test/integration/custom_test.rb +59 -0
- data/test/integration/heroku_test.rb +36 -0
- data/test/integration/request_test.rb +69 -0
- data/test/remote/tracker_test.rb +198 -0
- data/test/test_helper.rb +22 -0
- data/test/unit/collector/aggregator_test.rb +69 -0
- data/test/unit/collector/counter_cache_test.rb +96 -0
- data/test/unit/collector/group_test.rb +53 -0
- data/test/unit/collector_test.rb +23 -0
- data/test/unit/rack/configuration_test.rb +86 -0
- data/test/unit/rack/logger_test.rb +91 -0
- data/test/unit/rack/tracker_test.rb +44 -0
- data/test/unit/rack/worker_test.rb +36 -0
- metadata +132 -0
data/LICENSE
ADDED
@@ -0,0 +1,24 @@
|
|
1
|
+
Copyright (c) 2012. Librato, Inc.
|
2
|
+
All rights reserved.
|
3
|
+
|
4
|
+
Redistribution and use in source and binary forms, with or without
|
5
|
+
modification, are permitted provided that the following conditions are met:
|
6
|
+
* Redistributions of source code must retain the above copyright
|
7
|
+
notice, this list of conditions and the following disclaimer.
|
8
|
+
* Redistributions in binary form must reproduce the above copyright
|
9
|
+
notice, this list of conditions and the following disclaimer in the
|
10
|
+
documentation and/or other materials provided with the distribution.
|
11
|
+
* Neither the name of the <organization> nor the
|
12
|
+
names of its contributors may be used to endorse or promote products
|
13
|
+
derived from this software without specific prior written permission.
|
14
|
+
|
15
|
+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
16
|
+
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
17
|
+
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
18
|
+
DISCLAIMED. IN NO EVENT SHALL LIBRATO, INC. BE LIABLE FOR ANY
|
19
|
+
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
20
|
+
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
21
|
+
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
22
|
+
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
23
|
+
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
24
|
+
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
data/README.md
ADDED
@@ -0,0 +1,176 @@
|
|
1
|
+
librato-rack
|
2
|
+
=======
|
3
|
+
|
4
|
+
[![Build Status](https://secure.travis-ci.org/librato/librato-rack.png?branch=master)](http://travis-ci.org/librato/librato-rack)
|
5
|
+
|
6
|
+
*Note: librato-rack is currently in beta and is currently recommended primarily for early-adopter use*
|
7
|
+
|
8
|
+
`librato-rack` provides rack middleware which will report key statistics for your rack applications to [Librato Metrics](https://metrics.librato.com/). It will also allow you to easily track your own custom metrics. Metrics are delivered asynchronously behind the scenes so they won't affect performance of your requests.
|
9
|
+
|
10
|
+
Currently Ruby 1.9.2+ is required.
|
11
|
+
|
12
|
+
## Quick Start
|
13
|
+
|
14
|
+
Install `librato-rack` as middleware in your application:
|
15
|
+
|
16
|
+
use Librato::Rack
|
17
|
+
|
18
|
+
Configuring and relaunching your application will start the reporting of performance and request metrics. You can also track custom metrics by adding simple one-liners to your code:
|
19
|
+
|
20
|
+
# keep counts of key events
|
21
|
+
Librato.increment 'user.signup'
|
22
|
+
|
23
|
+
# benchmark sections of code to verify production performance
|
24
|
+
Librato.timing 'my.complicated.work' do
|
25
|
+
# do work
|
26
|
+
end
|
27
|
+
|
28
|
+
# track averages across requests
|
29
|
+
Librato.measure 'user.social_graph.nodes', user.social_graph.size
|
30
|
+
|
31
|
+
## Installation & Configuration
|
32
|
+
|
33
|
+
Install the gem:
|
34
|
+
|
35
|
+
$ gem install librato-rack
|
36
|
+
|
37
|
+
Or add to your Gemfile if using bundler:
|
38
|
+
|
39
|
+
gem "librato-rack"
|
40
|
+
|
41
|
+
In your rackup file or equivalent, require and add the middleware:
|
42
|
+
|
43
|
+
require 'librato-rack'
|
44
|
+
use Librato::Rack
|
45
|
+
|
46
|
+
If you don't have a Metrics account already, [sign up](https://metrics.librato.com/). In order to send measurements to Metrics you need to provide your account credentials to `librato-rack`. You can provide these one of two ways:
|
47
|
+
|
48
|
+
##### Use environment variables
|
49
|
+
|
50
|
+
By default you can use `LIBRATO_USER` and `LIBRATO_TOKEN` to pass your account data to the middleware. While these are the only required variables, there are a few more optional environment variables you may find useful.
|
51
|
+
|
52
|
+
* `LIBRATO_SOURCE` - the default source to use for submitted metrics. If this is not set, hostname of the executing machine will be the default source
|
53
|
+
* `LIBRATO_PREFIX` - a prefix which will be appended to all metric names
|
54
|
+
* `LIBRATO_LOG_LEVEL` - see logging section for more
|
55
|
+
|
56
|
+
##### Use a configuration object
|
57
|
+
|
58
|
+
If you want to do more complex configuration, use your own environment variables, or control your configuration in code, you can use a configuration object:
|
59
|
+
|
60
|
+
config = Librato::Rack::Configuration.new
|
61
|
+
config.user = 'myuser@mysite.com'
|
62
|
+
config.token = 'mytoken'
|
63
|
+
# …more configuration
|
64
|
+
|
65
|
+
use Librato::Rack, config
|
66
|
+
|
67
|
+
See the configuration class for all available options.
|
68
|
+
|
69
|
+
##### Running on Heroku
|
70
|
+
|
71
|
+
If you are using the Librato Metrics Heroku addon, your `LIBRATO_USER` and `LIBRATO_TOKEN` environment variables will already be set in your Heroku environment. If you are running without the addon you will need to provide them yourself.
|
72
|
+
|
73
|
+
You must also specify a custom source for your app to track properly. If an explicit source is not set, `librato-rack` will not start. You can set the source in your environment:
|
74
|
+
|
75
|
+
heroku config:add LIBRATO_SOURCE=myappname
|
76
|
+
|
77
|
+
NOTE: if Heroku idles your application no measurements will be sent until it receives another request and is restarted. If you see intermittent gaps in your measurements during periods of low traffic this is the most likely cause.
|
78
|
+
|
79
|
+
## Custom Measurements
|
80
|
+
|
81
|
+
Tracking anything that interests you is easy with Metrics. There are four primary helpers available:
|
82
|
+
|
83
|
+
#### increment
|
84
|
+
|
85
|
+
Use for tracking a running total of something _across_ requests, examples:
|
86
|
+
|
87
|
+
# increment the 'sales_completed' metric by one
|
88
|
+
Librato.increment 'sales.completed'
|
89
|
+
|
90
|
+
# increment by five
|
91
|
+
Librato.increment 'items.purchased', :by => 5
|
92
|
+
|
93
|
+
# increment with a custom source
|
94
|
+
Librato.increment 'user.purchases', :source => user.id
|
95
|
+
|
96
|
+
Other things you might track this way: user signups, requests of a certain type or to a certain route, total jobs queued or processed, emails sent or received
|
97
|
+
|
98
|
+
###### Sporadic Increment Reporting
|
99
|
+
|
100
|
+
Note that `increment` is primarily used for tracking the rate of occurrence of some event. Given this increment metrics are _continuous by default_: after being called on a metric once they will report on every interval, reporting zeros for any interval when increment was not called on the metric.
|
101
|
+
|
102
|
+
Especially with custom sources you may want the opposite behavior - reporting a measurement only during intervals where `increment` was called on the metric:
|
103
|
+
|
104
|
+
# report a value for 'user.uploaded_file' only during non-zero intervals
|
105
|
+
Librato.increment 'user.uploaded_file', :source => user.id, :sporadic => true
|
106
|
+
|
107
|
+
#### measure
|
108
|
+
|
109
|
+
Use when you want to track an average value _per_-request. Examples:
|
110
|
+
|
111
|
+
Librato.measure 'user.social_graph.nodes', 212
|
112
|
+
|
113
|
+
# report from a custom source
|
114
|
+
Librato.measure 'jobs.queued', 3, :source => 'worker.12'
|
115
|
+
|
116
|
+
#### timing
|
117
|
+
|
118
|
+
Like `Librato.measure` this is per-request, but specialized for timing information:
|
119
|
+
|
120
|
+
Librato.timing 'twitter.lookup.time', 21.2
|
121
|
+
|
122
|
+
The block form auto-submits the time it took for its contents to execute as the measurement value:
|
123
|
+
|
124
|
+
Librato.timing 'twitter.lookup.time' do
|
125
|
+
@twitter = Twitter.lookup(user)
|
126
|
+
end
|
127
|
+
|
128
|
+
#### group
|
129
|
+
|
130
|
+
There is also a grouping helper, to make managing nested metrics easier. So this:
|
131
|
+
|
132
|
+
Librato.measure 'memcached.gets', 20
|
133
|
+
Librato.measure 'memcached.sets', 2
|
134
|
+
Librato.measure 'memcached.hits', 18
|
135
|
+
|
136
|
+
Can also be written as:
|
137
|
+
|
138
|
+
Librato.group 'memcached' do |g|
|
139
|
+
g.measure 'gets', 20
|
140
|
+
g.measure 'sets', 2
|
141
|
+
g.measure 'hits', 18
|
142
|
+
end
|
143
|
+
|
144
|
+
Symbols can be used interchangably with strings for metric names.
|
145
|
+
|
146
|
+
## Cross-Process Aggregation
|
147
|
+
|
148
|
+
`librato-rack` submits measurements back to the Librato platform on a _per-process_ basis. By default these measurements are then combined into a single measurement per source (default is your hostname) before persisting the data.
|
149
|
+
|
150
|
+
For example if you have 4 hosts with 8 unicorn instances each (i.e. 32 processes total), on the Metrics site you'll find 4 data streams (1 per host) instead of 32.
|
151
|
+
Current pricing applies after aggregation, so in this case you will be charged for 4 streams instead of 32.
|
152
|
+
|
153
|
+
If you want to report per-process instead, you can set `source_pids` to `true` in
|
154
|
+
your config, which will append the process id to the source name used by each thread.
|
155
|
+
|
156
|
+
## Troubleshooting
|
157
|
+
|
158
|
+
Note that it may take 2-3 minutes for the first results to show up in your Metrics account after you have started your servers with `librato-rack` enabled and the first request has been received.
|
159
|
+
|
160
|
+
For more information about startup and submissions to the Metrics service you can set your `log_level` to `debug`. If you are having an issue with a specific metric, using `trace` will add the exact measurements being sent to your logs along with other details about `librato-rack` execution. Neither of these modes are recommended long-term in production as they will add significant volume to your log file and may slow operation somewhat.
|
161
|
+
|
162
|
+
Submission times are total time but submission I/O is non-blocking - your process will continue to handle requests during submissions.
|
163
|
+
|
164
|
+
If you are debugging setup locally you can set `flush_interval` to something shorter (say 10s) to force submission more frequently. Don't change your `flush_interval` in production as it will not result in measurements showing up more quickly, but may affect performance.
|
165
|
+
|
166
|
+
## Contribution
|
167
|
+
|
168
|
+
* Check out the latest master to make sure the feature hasn't been implemented or the bug hasn't been fixed yet.
|
169
|
+
* Check out the issue tracker to make sure someone already hasn't requested it and/or contributed it.
|
170
|
+
* Fork the project and submit a pull request from a feature or bugfix branch.
|
171
|
+
* Please include tests. This is important so we don't break your changes unintentionally in a future version.
|
172
|
+
* Please don't modify the gemspec, Rakefile, version, or changelog. If you do change these files, please isolate a separate commit so we can cherry-pick around it.
|
173
|
+
|
174
|
+
## Copyright
|
175
|
+
|
176
|
+
Copyright (c) 2013 [Librato Inc.](http://librato.com) See LICENSE for details.
|
data/Rakefile
ADDED
@@ -0,0 +1,25 @@
|
|
1
|
+
#!/usr/bin/env rake
|
2
|
+
begin
|
3
|
+
require 'bundler/setup'
|
4
|
+
rescue LoadError
|
5
|
+
puts 'You must `gem install bundler` and `bundle install` to run rake tasks'
|
6
|
+
end
|
7
|
+
|
8
|
+
# console
|
9
|
+
desc "Open an console session preloaded with this library"
|
10
|
+
task :console do
|
11
|
+
sh "pry -rubygems -r ./lib/librato-rack.rb"
|
12
|
+
end
|
13
|
+
|
14
|
+
Bundler::GemHelper.install_tasks
|
15
|
+
|
16
|
+
require 'rake/testtask'
|
17
|
+
|
18
|
+
Rake::TestTask.new(:test) do |t|
|
19
|
+
t.libs << 'lib'
|
20
|
+
t.libs << 'test'
|
21
|
+
t.pattern = 'test/**/*_test.rb'
|
22
|
+
t.verbose = false
|
23
|
+
end
|
24
|
+
|
25
|
+
task :default => :test
|
data/lib/librato-rack.rb
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require 'librato/rack'
|
@@ -0,0 +1,48 @@
|
|
1
|
+
module Librato
|
2
|
+
# collects and stores measurement values over time so they can be
|
3
|
+
# reported periodically to the Metrics service
|
4
|
+
#
|
5
|
+
class Collector
|
6
|
+
extend Forwardable
|
7
|
+
|
8
|
+
def_delegators :counters, :increment
|
9
|
+
def_delegators :aggregate, :measure, :timing
|
10
|
+
|
11
|
+
# access to internal aggregator object
|
12
|
+
def aggregate
|
13
|
+
@aggregator_cache ||= Aggregator.new(:prefix => @prefix)
|
14
|
+
end
|
15
|
+
|
16
|
+
# access to internal counters object
|
17
|
+
def counters
|
18
|
+
@counter_cache ||= CounterCache.new
|
19
|
+
end
|
20
|
+
|
21
|
+
# remove any accumulated but unsent metrics
|
22
|
+
def delete_all
|
23
|
+
aggregate.delete_all
|
24
|
+
counters.delete_all
|
25
|
+
end
|
26
|
+
alias :clear :delete_all
|
27
|
+
|
28
|
+
def group(prefix)
|
29
|
+
group = Group.new(self, prefix)
|
30
|
+
yield group
|
31
|
+
end
|
32
|
+
|
33
|
+
# update prefix
|
34
|
+
def prefix=(new_prefix)
|
35
|
+
@prefix = new_prefix
|
36
|
+
aggregate.prefix = @prefix
|
37
|
+
end
|
38
|
+
|
39
|
+
def prefix
|
40
|
+
@prefix
|
41
|
+
end
|
42
|
+
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
require 'librato/collector/aggregator'
|
47
|
+
require 'librato/collector/counter_cache'
|
48
|
+
require 'librato/collector/group'
|
@@ -0,0 +1,97 @@
|
|
1
|
+
module Librato
|
2
|
+
class Collector
|
3
|
+
# maintains storage of timing and measurement type measurements
|
4
|
+
#
|
5
|
+
class Aggregator
|
6
|
+
extend Forwardable
|
7
|
+
|
8
|
+
def_delegators :@cache, :empty?, :prefix, :prefix=
|
9
|
+
|
10
|
+
def initialize(options={})
|
11
|
+
@cache = Librato::Metrics::Aggregator.new(:prefix => options[:prefix])
|
12
|
+
@lock = Mutex.new
|
13
|
+
end
|
14
|
+
|
15
|
+
def [](key)
|
16
|
+
fetch(key)
|
17
|
+
end
|
18
|
+
|
19
|
+
def fetch(key, options={})
|
20
|
+
return nil if @cache.empty?
|
21
|
+
gauges = nil
|
22
|
+
source = options[:source]
|
23
|
+
@lock.synchronize { gauges = @cache.queued[:gauges] }
|
24
|
+
gauges.each do |metric|
|
25
|
+
if metric[:name] == key.to_s
|
26
|
+
return metric if !source && !metric[:source]
|
27
|
+
return metric if source.to_s == metric[:source]
|
28
|
+
end
|
29
|
+
end
|
30
|
+
nil
|
31
|
+
end
|
32
|
+
|
33
|
+
def delete_all
|
34
|
+
@lock.synchronize { @cache.clear }
|
35
|
+
end
|
36
|
+
|
37
|
+
# transfer all measurements to queue and reset internal status
|
38
|
+
def flush_to(queue)
|
39
|
+
queued = nil
|
40
|
+
@lock.synchronize do
|
41
|
+
return if @cache.empty?
|
42
|
+
queued = @cache.queued
|
43
|
+
@cache.clear
|
44
|
+
end
|
45
|
+
queue.merge!(queued) if queued
|
46
|
+
end
|
47
|
+
|
48
|
+
# @example Simple measurement
|
49
|
+
# measure 'sources_returned', sources.length
|
50
|
+
#
|
51
|
+
# @example Simple timing in milliseconds
|
52
|
+
# timing 'twitter.lookup', 2.31
|
53
|
+
#
|
54
|
+
# @example Block-based timing
|
55
|
+
# timing 'db.query' do
|
56
|
+
# do_my_query
|
57
|
+
# end
|
58
|
+
#
|
59
|
+
# @example Custom source
|
60
|
+
# measure 'user.all_orders', user.order_count, :source => user.id
|
61
|
+
#
|
62
|
+
def measure(*args, &block)
|
63
|
+
options = {}
|
64
|
+
event = args[0].to_s
|
65
|
+
returned = nil
|
66
|
+
|
67
|
+
# handle block or specified argument
|
68
|
+
if block_given?
|
69
|
+
start = Time.now
|
70
|
+
returned = yield
|
71
|
+
value = ((Time.now - start) * 1000.0).to_i
|
72
|
+
elsif args[1]
|
73
|
+
value = args[1]
|
74
|
+
else
|
75
|
+
raise "no value provided"
|
76
|
+
end
|
77
|
+
|
78
|
+
# detect options hash if present
|
79
|
+
if args.length > 1 and args[-1].respond_to?(:each)
|
80
|
+
options = args[-1]
|
81
|
+
end
|
82
|
+
source = options[:source]
|
83
|
+
|
84
|
+
@lock.synchronize do
|
85
|
+
if source
|
86
|
+
@cache.add event => {:source => source, :value => value}
|
87
|
+
else
|
88
|
+
@cache.add event => value
|
89
|
+
end
|
90
|
+
end
|
91
|
+
returned
|
92
|
+
end
|
93
|
+
alias :timing :measure
|
94
|
+
|
95
|
+
end
|
96
|
+
end
|
97
|
+
end
|
@@ -0,0 +1,113 @@
|
|
1
|
+
module Librato
|
2
|
+
class Collector
|
3
|
+
# maintains storage of a set of incrementable, counter-like
|
4
|
+
# measurements
|
5
|
+
#
|
6
|
+
class CounterCache
|
7
|
+
SEPARATOR = '%%'
|
8
|
+
|
9
|
+
extend Forwardable
|
10
|
+
|
11
|
+
def_delegators :@cache, :empty?
|
12
|
+
|
13
|
+
def initialize
|
14
|
+
@cache = {}
|
15
|
+
@lock = Mutex.new
|
16
|
+
@sporadics = Set.new
|
17
|
+
end
|
18
|
+
|
19
|
+
# Retrieve the current value for a given metric. This is a short
|
20
|
+
# form for convenience which only retrieves metrics with no custom
|
21
|
+
# source specified. For more options see #fetch.
|
22
|
+
#
|
23
|
+
# @param [String|Symbol] key metric name
|
24
|
+
# @return [Integer|Float] current value
|
25
|
+
def [](key)
|
26
|
+
fetch(key)
|
27
|
+
end
|
28
|
+
|
29
|
+
# removes all tracked metrics. note this removes all measurement
|
30
|
+
# data AND metric names any continuously tracked metrics will not
|
31
|
+
# report until they get another measurement
|
32
|
+
def delete_all
|
33
|
+
@lock.synchronize { @cache.clear }
|
34
|
+
end
|
35
|
+
|
36
|
+
|
37
|
+
def fetch(key, options={})
|
38
|
+
if options[:source]
|
39
|
+
key = "#{key}#{SEPARATOR}#{options[:source]}"
|
40
|
+
end
|
41
|
+
@lock.synchronize do
|
42
|
+
@cache[key.to_s]
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
# transfer all measurements to queue and reset internal status
|
47
|
+
def flush_to(queue)
|
48
|
+
counts = nil
|
49
|
+
@lock.synchronize do
|
50
|
+
# work off of a duplicate data set so we block for
|
51
|
+
# as little time as possible
|
52
|
+
counts = @cache.dup
|
53
|
+
reset_cache
|
54
|
+
end
|
55
|
+
counts.each do |metric, value|
|
56
|
+
metric, source = metric.split(SEPARATOR)
|
57
|
+
if source
|
58
|
+
queue.add metric => {:value => value, :source => source}
|
59
|
+
else
|
60
|
+
queue.add metric => value
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
# Increment a given metric
|
66
|
+
#
|
67
|
+
# @example Increment metric 'foo' by 1
|
68
|
+
# increment :foo
|
69
|
+
#
|
70
|
+
# @example Increment metric 'bar' by 2
|
71
|
+
# increment :bar, :by => 2
|
72
|
+
#
|
73
|
+
# @example Increment metric 'foo' by 1 with a custom source
|
74
|
+
# increment :foo, :source => user.id
|
75
|
+
#
|
76
|
+
def increment(counter, options={})
|
77
|
+
if options.is_a?(Fixnum)
|
78
|
+
# suppport legacy style
|
79
|
+
options = {:by => options}
|
80
|
+
end
|
81
|
+
by = options[:by] || 1
|
82
|
+
if options[:source]
|
83
|
+
metric = "#{counter}#{SEPARATOR}#{options[:source]}"
|
84
|
+
else
|
85
|
+
metric = counter.to_s
|
86
|
+
end
|
87
|
+
if options[:sporadic]
|
88
|
+
make_sporadic(metric)
|
89
|
+
end
|
90
|
+
@lock.synchronize do
|
91
|
+
@cache[metric] ||= 0
|
92
|
+
@cache[metric] += by
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
private
|
97
|
+
|
98
|
+
def make_sporadic(metric)
|
99
|
+
@sporadics << metric
|
100
|
+
end
|
101
|
+
|
102
|
+
def reset_cache
|
103
|
+
# remove any source/metric pairs that aren't continuous
|
104
|
+
@sporadics.each { |metric| @cache.delete(metric) }
|
105
|
+
@sporadics.clear
|
106
|
+
# reset all continuous source/metric pairs to 0
|
107
|
+
@cache.each_key { |key| @cache[key] = 0 }
|
108
|
+
end
|
109
|
+
|
110
|
+
end
|
111
|
+
|
112
|
+
end
|
113
|
+
end
|