statue 0.2.7 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 60532afa98d1f352a73de3b13d62ba8ac557e2ff
4
- data.tar.gz: 403998b67478dba13d28bdcea552d4410502e7b0
3
+ metadata.gz: 4babeecc571be33fbda04a81c3eabc6455368aff
4
+ data.tar.gz: 6bced52052f52e3611df23562825e570a548d1d1
5
5
  SHA512:
6
- metadata.gz: d644f801e7d3cd830b07a1beb4b8354a608f4e994e3654785abdab1454098e2b687f5a0c3279bb2dbc0bb9d309ddb8eddaffe52f540a3bae735f56cb59e840db
7
- data.tar.gz: abab109194aee3868dd2c075c78dc4172d554405501fcf7f32c459c7c50dbf19d5c3b72f6016b5e8de593454c08f2a6f6caf39f3f903f8b65545bbc25394aaf3
6
+ metadata.gz: b73f850044ca23086c8f837fc3f969d94121390139292ab94ac28956a686567e27784b066ad000151629ba0f76492746dc127cb310f84a95609b5f8fe9f70087
7
+ data.tar.gz: bde0b2df82abc4ccc570bd87254cb176c435dbb3799cc24484622a502134b48351806be9ae3333e43b77d52940faddae1265d5c889543b56017948853d7024ad
@@ -1,3 +1,48 @@
1
+ ## [0.3.0] - Unreleased
2
+
3
+ ### Feature
4
+
5
+ - Extract duration measuring to `Statue::Clock` and be explicit that we are handling milliseconds.
6
+ - `RackStatistics` queue time is now taken from `X-Request-Start` header.
7
+
8
+ ### Backward incompatible changes
9
+
10
+ - All duration reports are now sent in milliseconds (as it should have always been). These includes:
11
+ - `Statue.report_duration`
12
+ - `RackStatistics` middleware metrics
13
+ - `Statue.stopwatch`
14
+ - Removed `Statue.duration`, you should use `Statue::Clock.duration_in_ms` (which is more explicit)
15
+ - `RackStatistics`: `request.<key>` metric was renamed to `request.<key>.runtime` to have more uniform names
16
+ - `RackStatistics`: now sends specific counter for when your application didn't handle the exception
17
+ - `UDPBacked`: now receives host/port named params or can be built from a string with
18
+ `UDPBacked.from_uri(<uri>)`
19
+
20
+ ## [0.2.7] - 2016-03-09
21
+
22
+ ## Fixes
23
+
24
+ - Make UDPBacked compatible with JRuby
25
+
26
+ ## [0.2.4] - 2016-02-04
27
+
28
+ ## Features
29
+
30
+ - Add support for gauges
31
+
32
+ ## [0.2.2] - 2016-02-02
33
+
34
+ ## Fixes
35
+
36
+ - Allow RackStatistics to handle not integer status codes
37
+
38
+ ## [0.2.1] - 2016-01-07
39
+
40
+ ## Features
41
+
42
+ - Add stopwatchs to report multiple partial times
43
+
1
44
  ## [0.2.0] - 2015-11-17
2
- ### Added
45
+
46
+ ### Features
47
+
3
48
  - Add support for multithreaded applications
@@ -7,9 +7,9 @@ require 'statue/stopwatch'
7
7
  module Statue
8
8
  extend self
9
9
 
10
- attr_accessor :namespace, :logger
11
-
12
- attr_accessor :backend
10
+ attr_accessor :namespace
11
+ attr_accessor :logger
12
+ attr_writer :backend
13
13
 
14
14
  def report_duration(metric_name, duration = nil, **options, &block)
15
15
  result = nil
@@ -29,13 +29,9 @@ module Statue
29
29
 
30
30
  def report_success_or_failure(metric_name, success_method: nil, **options, &block)
31
31
  result = block.call
32
- success = success_method ? result.public_send(success_method) : result
33
32
 
34
- if success
35
- report_increment("#{metric_name}.success", **options)
36
- else
37
- report_increment("#{metric_name}.failure", **options)
38
- end
33
+ success = success_method ? result.public_send(success_method) : result
34
+ report_increment("#{metric_name}.#{success ? "success" : "failure"}", **options)
39
35
 
40
36
  result
41
37
  rescue
@@ -48,13 +44,7 @@ module Statue
48
44
  end
49
45
 
50
46
  def backend
51
- @backend ||= UDPBackend.new
52
- end
53
-
54
- def duration
55
- start = Process.clock_gettime(Process::CLOCK_MONOTONIC)
56
- yield
57
- Process.clock_gettime(Process::CLOCK_MONOTONIC) - start
47
+ @backend ||= UDPBackend.from_uri("statsd://127.0.0.1:8125")
58
48
  end
59
49
 
60
50
  def debug(text, &block)
@@ -4,7 +4,12 @@ module Statue
4
4
  class UDPBackend
5
5
  attr_reader :host, :port
6
6
 
7
- def initialize(host = nil, port = nil)
7
+ def self.from_uri(uri)
8
+ uri = URI(uri)
9
+ new(host: uri.host, port: uri.port)
10
+ end
11
+
12
+ def initialize(host:, port:)
8
13
  @host = host
9
14
  @port = port
10
15
  end
@@ -0,0 +1,16 @@
1
+ module Statue
2
+ module Clock
3
+ extend self
4
+
5
+ def now_in_ms
6
+ Process.clock_gettime(Process::CLOCK_MONOTONIC) * 1_000
7
+ end
8
+
9
+ def duration_in_ms
10
+ start = now_in_ms
11
+ yield
12
+ now_in_ms - start
13
+ end
14
+
15
+ end
16
+ end
@@ -1,3 +1,5 @@
1
+ require 'statue/clock'
2
+
1
3
  module Statue
2
4
  class Metric
3
5
  TYPES = {
@@ -9,6 +11,7 @@ module Statue
9
11
  }
10
12
 
11
13
  attr_accessor :type, :name, :value, :sample_rate
14
+ attr_reader :full_name, :type_description
12
15
 
13
16
  def self.counter(name, value = 1, **options)
14
17
  new(type: :c, value: value, name: name, **options)
@@ -19,15 +22,17 @@ module Statue
19
22
  end
20
23
 
21
24
  def self.measure(name, duration: nil, **options, &block)
22
- value = duration || Statue.duration(&block)
25
+ value = duration || Statue::Clock.duration_in_ms(&block)
23
26
  new(type: :ms, value: value, name: name, **options)
24
27
  end
25
28
 
26
29
  def initialize(type:, name:, value:, sample_rate: 1.0)
30
+ @type_description = TYPES[type] or raise ArgumentError, "invalid type: #{type}"
27
31
  @type = type
28
32
  @name = name
29
33
  @value = value
30
34
  @sample_rate = sample_rate
35
+ @full_name = Statue.namespace ? "#{Statue.namespace}.#{@name}" : @name
31
36
  end
32
37
 
33
38
  def to_s
@@ -37,15 +42,7 @@ module Statue
37
42
  end
38
43
 
39
44
  def inspect
40
- "#<StatsD::Instrument::Metric #{full_name} #{TYPES[type]}(#{value})@#{sample_rate}>"
41
- end
42
-
43
- def full_name
44
- if Statue.namespace
45
- "#{Statue.namespace}.#{@name}"
46
- else
47
- @name
48
- end
45
+ "#<StatsD::Instrument::Metric #{full_name} #{type_description}(#{value})@#{sample_rate}>"
49
46
  end
50
47
 
51
48
  end
@@ -4,7 +4,7 @@ module Statue
4
4
  # Middleware to send metrics about rack requests
5
5
  #
6
6
  # this middleware reports metrics with the following pattern:
7
- # `request.{env['REQUEST_METHOD']}.{path_name}
7
+ # `{env['REQUEST_METHOD']}.{path_name}
8
8
  #
9
9
  # where `path_name` can be configured when inserting the middleware like this:
10
10
  # `use RackStatistics, path_name: ->(env) { ... build the path name ... }`
@@ -17,17 +17,18 @@ module Statue
17
17
  #
18
18
  # Counters:
19
19
  #
20
- # * <key>.status-XXX (where XXX is the status code)
21
- # * <key>.success (on any status 2XX)
22
- # * <key>.unmodified (on status 304)
23
- # * <key>.redirect (on any status 3XX)
24
- # * <key>.failure (on any status 4xx)
25
- # * <key>.error (on any status 5xx or when an exception is raised)
20
+ # * request.<key>.status-XXX (where XXX is the status code)
21
+ # * request.<key>.success (on any status 2XX)
22
+ # * request.<key>.unmodified (on status 304)
23
+ # * request.<key>.redirect (on any status 3XX)
24
+ # * request.<key>.failure (on any status 4xx)
25
+ # * request.<key>.error (on any status 5xx)
26
+ # * request.<key>.unhandled-exception (when an exception is raised that your application didn't handle)
26
27
  #
27
28
  # Timers (all measured from the middleware perspective):
28
29
  #
29
- # * <key> (request time)
30
- # * request.queue (queue time, depends on HTTP_X_QUEUE_START header)
30
+ # * request.<key>.runtime (request time)
31
+ # * request.queue (queue time, depends on HTTP_X_REQUEST_START header)
31
32
  #
32
33
  # To get accurate timers, the middleware should be as higher as
33
34
  # possible in your rack stack
@@ -35,25 +36,25 @@ module Statue
35
36
  class RackStatistics
36
37
  DEFAULT_PATH_NAME = lambda do |env|
37
38
  # Remove duplicate and trailing '/'
38
- path = env['REQUEST_PATH'].squeeze('/').chomp('/')
39
+ path = env['PATH_INFO'].squeeze('/').chomp('/')
39
40
  if path == ''
40
41
  'root'
41
42
  else
42
- # Skip leading '/'
43
+ # Skip leading '/' and replace statsd special characters by '-'
43
44
  env['REQUEST_PATH'][1..-1].tr('/,|', '-')
44
45
  end
45
46
  end
46
47
 
47
48
  def initialize(app, path_name: DEFAULT_PATH_NAME)
48
49
  @app = app
49
- @path_name = path_name
50
+ @path_name = path_name
50
51
  end
51
52
 
52
53
  def call(env)
53
54
  report_header_metrics(env)
54
55
 
55
56
  response = nil
56
- duration = Statue.duration do
57
+ duration = Statue::Clock.duration_in_ms do
57
58
  response = @app.call(env)
58
59
  end
59
60
 
@@ -67,9 +68,9 @@ module Statue
67
68
  private
68
69
 
69
70
  def report_header_metrics(env)
70
- if start_header = env['HTTP_X_QUEUE_START']
71
+ if start_header = (env['HTTP_X_REQUEST_START'] || env['HTTP_X_QUEUE_START'])
71
72
  queue_start = start_header[/t=([\d\.]+)/, 1].to_f
72
- Statue.report_duration 'request.queue', Time.now.to_f - queue_start
73
+ Statue.report_duration 'request.queue', (Time.now.to_f - queue_start) * 1_000
73
74
  end
74
75
  end
75
76
 
@@ -77,14 +78,14 @@ module Statue
77
78
  metric_name = metric_name(env)
78
79
  status, _headers, _body = response
79
80
 
80
- Statue.report_duration metric_name, duration
81
+ Statue.report_duration "#{metric_name}.runtime", duration
81
82
 
82
83
  Statue.report_increment "#{metric_name}.status-#{status}"
83
84
  Statue.report_increment "#{metric_name}.#{status_group(status)}"
84
85
  end
85
86
 
86
87
  def report_exception(env, _exception)
87
- Statue.report_increment "#{metric_name(env)}.error"
88
+ Statue.report_increment "#{metric_name(env)}.unhandled-exception"
88
89
  end
89
90
 
90
91
  def metric_name(env)
@@ -1,19 +1,19 @@
1
1
  module Statue
2
2
  class Stopwatch
3
3
 
4
- def initialize(name:, now: clock_now, reporter: Statue)
4
+ def initialize(name:, now: Clock.now_in_ms, reporter: Statue)
5
5
  @reporter = reporter
6
6
  @name = name
7
7
  @start = @partial = now
8
8
  end
9
9
 
10
- def partial(suffix = nil, now: clock_now, **options)
10
+ def partial(suffix = nil, now: Clock.now_in_ms, **options)
11
11
  previous, @partial = @partial, now
12
12
 
13
13
  @reporter.report_duration(metric_name(suffix || "runtime.partial"), @partial - previous, **options)
14
14
  end
15
15
 
16
- def stop(suffix = nil, now: clock_now, report_partial: false, **options)
16
+ def stop(suffix = nil, now: Clock.now_in_ms, report_partial: false, **options)
17
17
  partial(report_partial.is_a?(String) ? report_partial : nil, now: now, **options) if report_partial
18
18
 
19
19
  previous, @start = @start, now
@@ -21,7 +21,7 @@ module Statue
21
21
  @reporter.report_duration(metric_name(suffix || "runtime.total"), @start - previous, **options)
22
22
  end
23
23
 
24
- def reset(now: clock_now)
24
+ def reset(now: Clock.now_in_ms)
25
25
  @start = @partial = now
26
26
  end
27
27
 
@@ -31,9 +31,5 @@ module Statue
31
31
  "#{@name}.#{suffix}"
32
32
  end
33
33
 
34
- def clock_now
35
- Process.clock_gettime(Process::CLOCK_MONOTONIC)
36
- end
37
-
38
34
  end
39
35
  end
@@ -1,3 +1,3 @@
1
1
  module Statue
2
- VERSION = '0.2.7'
2
+ VERSION = '0.3.0'
3
3
  end
@@ -19,5 +19,7 @@ Gem::Specification.new do |spec|
19
19
 
20
20
  spec.add_development_dependency "bundler", "~> 1.7"
21
21
  spec.add_development_dependency "rake", "~> 10.0"
22
+ spec.add_development_dependency "rack", "~> 1.6"
23
+ spec.add_development_dependency "rack-test", "~> 0.6.3"
22
24
  spec.add_development_dependency "minitest"
23
25
  end
@@ -0,0 +1,140 @@
1
+ require 'test_helper'
2
+ require 'statue/rack_statistics'
3
+ require 'rack/test'
4
+
5
+ describe Statue::RackStatistics do
6
+ include Rack::Test::Methods
7
+ def app
8
+ Statue::RackStatistics.new(App.new)
9
+ end
10
+
11
+ def find_metric(name)
12
+ Statue.backend.captures.find { |m| m.name == name }
13
+ end
14
+
15
+ class App
16
+ def call(env)
17
+ raise "Uncaught error" if env['raise_error']
18
+ [
19
+ env['status'] || 200,
20
+ {},
21
+ []
22
+ ]
23
+ end
24
+ end
25
+
26
+ after do
27
+ Statue.backend.captures.clear
28
+ end
29
+
30
+ describe "request statistics on normal processing" do
31
+
32
+ it "sends queue time" do
33
+ header "X-Request-Start", "t=#{Time.now.to_f - 1}"
34
+ get "/"
35
+
36
+ queue_time = find_metric("request.queue")
37
+ assert queue_time, "Didn't report queue time"
38
+ assert_equal "measure", queue_time.type_description
39
+
40
+ # Measured time can't be less than 1000 ms because we set it to 1 sec before now.
41
+ # Allow a range of 30ms for ruby to do processing and avoid false positives
42
+ assert_in_delta 1015, queue_time.value, 15 # within range 1000-1030
43
+ end
44
+
45
+ it "sends request runtime" do
46
+ get "/"
47
+
48
+ runtime_time = find_metric("request.GET.root.runtime")
49
+ assert runtime_time, "Didn't report request runtime"
50
+ assert_equal "measure", runtime_time.type_description
51
+ # Allow a range of 30ms for ruby to do processing and avoid false positives
52
+ assert_in_delta 15, runtime_time.value, 15 # within range 1000-1030
53
+ end
54
+
55
+ it "sends counter for status-xxx" do
56
+ get "/"
57
+
58
+ runtime_time = find_metric("request.GET.root.status-200")
59
+ assert runtime_time, "Didn't report status-200 counter"
60
+ assert_equal "increment", runtime_time.type_description
61
+ assert_equal 1, runtime_time.value
62
+ end
63
+
64
+ it "sends counter for status group" do
65
+ get "/"
66
+
67
+ runtime_time = find_metric("request.GET.root.success")
68
+ assert runtime_time, "Didn't report sucess counter"
69
+ assert_equal "increment", runtime_time.type_description
70
+ assert_equal 1, runtime_time.value
71
+ end
72
+
73
+ it "sends counter for other status codes" do
74
+ get "/", {}, { 'status' => 502 }
75
+
76
+ runtime_time = find_metric("request.GET.root.status-502")
77
+ assert runtime_time, "Didn't report status-502 counter"
78
+ assert_equal "increment", runtime_time.type_description
79
+ assert_equal 1, runtime_time.value
80
+ end
81
+
82
+ it "sends counter for other status groups" do
83
+ get "/", {}, { 'status' => 502 }
84
+
85
+ runtime_time = find_metric("request.GET.root.error")
86
+ assert runtime_time, "Didn't report error counter"
87
+ assert_equal "increment", runtime_time.type_description
88
+ assert_equal 1, runtime_time.value
89
+ end
90
+
91
+ it "sends all metrics and only those" do
92
+ header "X-Request-Start", "t=#{Time.now.to_f}"
93
+ get "/"
94
+
95
+ metrics = Statue.backend.captures.map(&:name)
96
+ expected_metrics = %w[
97
+ request.queue
98
+ request.GET.root.runtime
99
+ request.GET.root.status-200
100
+ request.GET.root.success
101
+ ]
102
+ missing = expected_metrics - metrics
103
+ extra = metrics - expected_metrics
104
+
105
+ assert missing.empty?, "expect not to be missing, but these were missing: #{missing.inspect}"
106
+ assert extra.empty?, "expected no other metric to be found, but found these: #{extra.inspect}"
107
+ end
108
+
109
+ end
110
+
111
+ describe "request statistics on normal processing" do
112
+
113
+ it "sends queue time" do
114
+ header "X-Request-Start", "t=#{Time.now.to_f - 1}"
115
+ assert_raises do
116
+ get "/", {}, { 'raise_error' => true }
117
+ end
118
+
119
+ queue_time = find_metric("request.queue")
120
+ assert queue_time, "Didn't report queue time"
121
+ assert_equal "measure", queue_time.type_description
122
+
123
+ # Measured time can't be less than 1000 ms because we set it to 1 sec before now.
124
+ # Allow a range of 30ms for ruby to do processing and avoid false positives
125
+ assert_in_delta 1015, queue_time.value, 15 # within range 1000-1030
126
+ end
127
+
128
+ it "sends counter for other status codes" do
129
+ assert_raises do
130
+ get "/", {}, { 'raise_error' => true }
131
+ end
132
+
133
+ runtime_time = find_metric("request.GET.root.unhandled-exception")
134
+ assert runtime_time, "Didn't report unhandled-exception counter"
135
+ assert_equal "increment", runtime_time.type_description
136
+ assert_equal 1, runtime_time.value
137
+ end
138
+
139
+ end
140
+ end
@@ -24,8 +24,8 @@ describe Statue do
24
24
  describe ".report_duration" do
25
25
 
26
26
  it "adds a measure metric to the backend using the block call duration" do
27
- Statue.stub(:duration, 1.5) do
28
- result = Statue.report_duration("some.timer") { nil }
27
+ Statue::Clock.stub(:duration_in_ms, 1.5) do
28
+ _result = Statue.report_duration("some.timer") { nil }
29
29
 
30
30
  assert_equal 1, Statue.backend.captures.size
31
31
  assert_equal "some.timer:1.5|ms", Statue.backend.captures.first.to_s
@@ -39,7 +39,7 @@ describe Statue do
39
39
  end
40
40
 
41
41
  it "adds a measure metric to the backend using the fixed value" do
42
- result = Statue.report_duration("some.timer", 2.5)
42
+ _result = Statue.report_duration("some.timer", 2.5)
43
43
 
44
44
  assert_equal 1, Statue.backend.captures.size
45
45
  assert_equal "some.timer:2.5|ms", Statue.backend.captures.first.to_s
@@ -59,7 +59,7 @@ describe Statue do
59
59
  describe ".report_gauge" do
60
60
 
61
61
  it "adds a gauge metric to the backend using the fixed value" do
62
- result = Statue.report_gauge("some.gauge", 23)
62
+ _result = Statue.report_gauge("some.gauge", 23)
63
63
 
64
64
  assert_equal 1, Statue.backend.captures.size
65
65
  assert_equal "some.gauge:23|g", Statue.backend.captures.first.to_s
@@ -8,7 +8,7 @@ describe Statue::Stopwatch do
8
8
  describe "#partial" do
9
9
  it "reports the duration between start and the partial call" do
10
10
  stopwatch = Statue::Stopwatch.new(name: "my_watch", now: 0)
11
- stopwatch.partial(now: 42)
11
+ stopwatch.partial(now: 42) # 42 milliseconds after
12
12
 
13
13
  assert_equal 1, Statue.backend.captures.size
14
14
  assert_equal "my_watch.runtime.partial:42|ms", Statue.backend.captures.first.to_s
@@ -47,7 +47,7 @@ describe Statue::Stopwatch do
47
47
  stopwatch.stop(now: 21)
48
48
 
49
49
  assert_equal 21, Statue.backend.captures.size
50
- *partials, total = Statue.backend.captures
50
+ *_partials, total = Statue.backend.captures
51
51
  assert_equal "my_watch.runtime.total:21|ms", total.to_s
52
52
  end
53
53
 
@@ -70,7 +70,7 @@ describe Statue::Stopwatch do
70
70
  stopwatch.stop(now: 21, report_partial: "runtime.final_lap")
71
71
 
72
72
  assert_equal 22, Statue.backend.captures.size
73
- *partials, special_partial, total = Statue.backend.captures
73
+ *_partials, special_partial, _total = Statue.backend.captures
74
74
  assert_equal "my_watch.runtime.final_lap:1|ms", special_partial.to_s
75
75
  end
76
76
 
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: statue
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.7
4
+ version: 0.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Juan Barreneche
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2016-03-09 00:00:00.000000000 Z
11
+ date: 2017-03-13 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -38,6 +38,34 @@ dependencies:
38
38
  - - "~>"
39
39
  - !ruby/object:Gem::Version
40
40
  version: '10.0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: rack
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '1.6'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '1.6'
55
+ - !ruby/object:Gem::Dependency
56
+ name: rack-test
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: 0.6.3
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: 0.6.3
41
69
  - !ruby/object:Gem::Dependency
42
70
  name: minitest
43
71
  requirement: !ruby/object:Gem::Requirement
@@ -72,11 +100,13 @@ files:
72
100
  - lib/statue/backends/logger.rb
73
101
  - lib/statue/backends/null.rb
74
102
  - lib/statue/backends/udp.rb
103
+ - lib/statue/clock.rb
75
104
  - lib/statue/metric.rb
76
105
  - lib/statue/rack_statistics.rb
77
106
  - lib/statue/stopwatch.rb
78
107
  - lib/statue/version.rb
79
108
  - statue.gemspec
109
+ - test/rack_statistics_test.rb
80
110
  - test/statue_test.rb
81
111
  - test/stopwatch_test.rb
82
112
  - test/test_helper.rb
@@ -100,11 +130,13 @@ required_rubygems_version: !ruby/object:Gem::Requirement
100
130
  version: '0'
101
131
  requirements: []
102
132
  rubyforge_project:
103
- rubygems_version: 2.4.8
133
+ rubygems_version: 2.5.2
104
134
  signing_key:
105
135
  specification_version: 4
106
136
  summary: Easily track application metrics into Statsie
107
137
  test_files:
138
+ - test/rack_statistics_test.rb
108
139
  - test/statue_test.rb
109
140
  - test/stopwatch_test.rb
110
141
  - test/test_helper.rb
142
+ has_rdoc: