Skip to content

Commit 4db5327

Browse files
committed
* New metric types: accumulator and delta
* A little bit more debugging info
1 parent 72d0293 commit 4db5327

File tree

10 files changed

+166
-4
lines changed

10 files changed

+166
-4
lines changed

lib/salus.rb

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -129,11 +129,13 @@ def save_state(&block)
129129
end
130130

131131
def tick
132+
log DEBUG, "Tick..."
132133
lazy_eval
133134
return if @@_groups.empty?
134135
pause = (Salus.interval - Salus.tick_timeout - Salus.render_timeout) / 2
135136
pause = 1 if (pause <= 0)
136137

138+
log DEBUG, "Starting collection. Top-level groups to spawn: #{@@_groups.count}"
137139
latch = CountDownLatch.new(@@_groups.count)
138140
@@_groups.each do |k, v|
139141
pool.process do
@@ -150,6 +152,7 @@ def tick
150152
log DEBUG, "Collection finished. Threads: #{pool.spawned} spawned, #{pool.waiting} waiting, #{Thread.list.count} total"
151153

152154
return if @@_renders.empty?
155+
log DEBUG, "Starting #{@_renders.count} renderers"
153156
latch = CountDownLatch.new(@@_renders.count)
154157
@@_renders.each do |v|
155158
pool.process do

lib/salus/group.rb

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
11
require "forwardable"
22
require "salus/metric"
33
require "salus/metric/absolute"
4+
require "salus/metric/accumulator"
45
require "salus/metric/counter"
6+
require "salus/metric/delta"
57
require "salus/metric/derive"
68
require "salus/metric/gauge"
79
require "salus/metric/text"

lib/salus/metric.rb

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -144,6 +144,15 @@ def to_h
144144
end
145145
end
146146

147+
def clear
148+
synchronize do
149+
@last_calced_value = nil
150+
@last_calced_ts = nil
151+
@needs_update = true
152+
@values.clear
153+
end
154+
end
155+
147156
protected
148157
def option(key, *types)
149158
@attributes[key] = types

lib/salus/metric/accumulator.rb

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
module Salus
2+
class Accumulator < Metric
3+
STORAGE_DEPTH = 1
4+
5+
def push(opts={}, &block)
6+
opts = {} unless opts.is_a?(Hash)
7+
8+
synchronize do
9+
opts.each do |k, v|
10+
validate(k, v)
11+
@opts[k] = v unless [:value, :ttl, :timestamp].include?(k)
12+
end
13+
14+
if block_given?
15+
v = begin
16+
yield
17+
rescue Exception => e
18+
log DEBUG, e
19+
nil
20+
end
21+
validate(:value, v)
22+
opts[:value] = v
23+
end
24+
25+
prev = @values.empty? ? 0 : (@values.last.value || 0)
26+
curr = opts[:value] || 0
27+
28+
@values << Value.new(prev+curr, opts[:timestamp] || Time.now.to_f, opts[:ttl] || @opts[:ttl])
29+
@needs_update = true
30+
end
31+
end
32+
end
33+
end
34+

lib/salus/metric/delta.rb

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
module Salus
2+
class Delta < Metric
3+
def initialize(defaults={})
4+
super(defaults)
5+
option :minimum, Numeric
6+
validate(:minimum, @opts[:minimum]) if @opts.key?(:minimum)
7+
end
8+
9+
protected
10+
def calc
11+
super
12+
@last_calced_value = nil
13+
14+
if @values.length < STORAGE_DEPTH
15+
return
16+
elsif @values[0].expired?(@values[1].timestamp)
17+
return
18+
elsif !@values[0].value.is_a?(Numeric)
19+
return
20+
elsif !@values[1].value.is_a?(Numeric)
21+
return
22+
end
23+
24+
@last_calced_value = begin
25+
dt = (@values[1].timestamp - @values[0].timestamp)
26+
dv = (@values[1].value - @values[0].value)
27+
r = (dt == 0) ? nil : dv
28+
if @opts.key?(:minimum) && !r.nil? && r < @opts[:minimum]
29+
nil
30+
else
31+
r
32+
end
33+
end
34+
end
35+
end
36+
end

lib/salus/version.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
11
module Salus
2-
VERSION = "0.1.3"
2+
VERSION = "0.2.0"
33
end

salus.gemspec

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -21,9 +21,9 @@ Gem::Specification.new do |spec|
2121
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
2222
spec.require_paths = ["lib"]
2323

24-
spec.add_development_dependency "bundler", "~> 1.15"
24+
spec.add_development_dependency "bundler", "~> 2.1"
2525

26-
spec.add_dependency "thor", "~> 0.20"
27-
spec.add_development_dependency "rake", "~> 10.0"
26+
spec.add_dependency "thor", "~> 1.0"
27+
spec.add_development_dependency "rake", ">= 12.3.3"
2828
spec.add_development_dependency "rspec", "~> 3.0"
2929
end

spec/salus_accumulator_spec.rb

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
require "spec_helper"
2+
3+
RSpec.describe Salus::Accumulator do
4+
context "without ttl" do
5+
let(:metric) { Salus::Accumulator.new }
6+
7+
it "accumulates values as pushed" do
8+
metric.push value: 10.0
9+
expect(metric.value).to eq(10.0)
10+
metric.push value: 20.0
11+
expect(metric.value).to eq(30.0)
12+
metric.push value: 30.0
13+
expect(metric.value).to eq(60.0)
14+
end
15+
end
16+
end

spec/salus_delta_spec.rb

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
require "spec_helper"
2+
3+
RSpec.describe Salus::Delta do
4+
context "without ttl" do
5+
let(:metric) { Salus::Delta.new }
6+
7+
it "validates types" do
8+
expect{metric.push minimum: "just a test"}.to raise_error(ArgumentError)
9+
end
10+
11+
it "counts deltas" do
12+
metric.push value: 10, timestamp: 0
13+
expect(metric.value).to eq(nil)
14+
metric.push value: 20, timestamp: 10
15+
expect(metric.value).to eq(10)
16+
metric.push value: 100, timestamp: 20
17+
expect(metric.value).to eq(80)
18+
end
19+
20+
it "returns nil rate for dt == 0" do
21+
metric.push value: 10, timestamp: 10
22+
metric.push value: 20, timestamp: 10
23+
expect(metric.value).to eq(nil)
24+
end
25+
26+
it "returns nil if one value is nil" do
27+
metric.push value: 10, timestamp: 0
28+
metric.push value: nil, timestamp: 10
29+
expect(metric.value).to eq(nil)
30+
end
31+
32+
it "returns nil if delta is less than minimum" do
33+
metric.push value: 200, timestamp: 0, minimum: 0
34+
metric.push value: 1000, timestamp: 10
35+
expect(metric.value).to eq(800)
36+
metric.push value: 1, timestamp: 20
37+
expect(metric.value).to eq(nil)
38+
end
39+
end
40+
41+
context "with ttl" do
42+
let(:metric) { Salus::Delta.new }
43+
44+
it "returns nil if previous value is expired" do
45+
metric.push value: 0, timestamp: 0, ttl: 10
46+
metric.push value: 5, timestamp: 5, ttl: 10
47+
expect(metric.value).to eq(5)
48+
metric.push value: 100, timestamp: 100, ttl: 10
49+
expect(metric.value).to eq(nil)
50+
end
51+
end
52+
end

spec/salus_metric_spec.rb

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,16 @@
4646
expect(metric.value).to eq(30)
4747
end
4848

49+
it "clears values" do
50+
metric.push value: 10
51+
expect(metric.value).to eq(10)
52+
metric.push value: 20
53+
expect(metric.value).to eq(20)
54+
metric.clear
55+
expect(metric.value).to eq(nil)
56+
expect(metric.timestamp).to eq(nil)
57+
end
58+
4959
it "takes block" do
5060
metric.push do
5161
100 / 10

0 commit comments

Comments
 (0)