ezmetrics 1.0.6 → 1.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +5 -5
- data/README.md +88 -7
- data/lib/ezmetrics.rb +64 -67
- data/lib/ezmetrics/benchmark.rb +13 -12
- metadata +30 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 5ba2e24bca76b2786c1264b779e72764e123094150855cae241d673505df95ad
|
4
|
+
data.tar.gz: 3c297b92a53c51b8b881fbbafb15929b9bac36eb53164c3faab37c2caa72db02
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 4d1e8118d48cac15dca166c6c4f0d8e38344b28bfcc85343fa87ff4877d34bc7f12b9841241de563723261df5a48210cf1838c09eece3bc15d5f2dde6a58c8c2
|
7
|
+
data.tar.gz: 8e62b7b53f73a6343c8fd6f11e0e8a9f856314dd262c10611cd9bf061636c8801255de58818a1736069679525bed73c949e6f61778910de8a306da30c352e2a2
|
data/README.md
CHANGED
@@ -4,7 +4,6 @@
|
|
4
4
|
|
5
5
|
A simple tool for capturing and displaying Rails metrics.
|
6
6
|
|
7
|
-
|
8
7
|
## Installation
|
9
8
|
|
10
9
|
```
|
@@ -16,6 +15,7 @@ gem 'ezmetrics'
|
|
16
15
|
### Getting started
|
17
16
|
|
18
17
|
This tool captures and aggregates Rails application metrics such as
|
18
|
+
|
19
19
|
- `duration`
|
20
20
|
- `views`
|
21
21
|
- `db`
|
@@ -30,6 +30,7 @@ You can change the timeframe according to your needs and save the metrics by cal
|
|
30
30
|
# Store the metrics for 60 seconds (default behaviour)
|
31
31
|
EZmetrics.new.log(duration: 100.5, views: 40.7, db: 59.8, queries: 4, status: 200)
|
32
32
|
```
|
33
|
+
|
33
34
|
or
|
34
35
|
|
35
36
|
```ruby
|
@@ -53,7 +54,6 @@ or
|
|
53
54
|
|
54
55
|
> Please note that you can combine these timeframes, for example - store for 10 minutes, display for 5 minutes.
|
55
56
|
|
56
|
-
|
57
57
|
### Capture metrics
|
58
58
|
|
59
59
|
Just add an initializer to your application:
|
@@ -121,6 +121,86 @@ This will return a hash with the following structure:
|
|
121
121
|
}
|
122
122
|
```
|
123
123
|
|
124
|
+
### Output configuration
|
125
|
+
|
126
|
+
The output can be easily configured by specifying aggregation options as in the following examples:
|
127
|
+
|
128
|
+
1. Single
|
129
|
+
|
130
|
+
```ruby
|
131
|
+
EZmetrics.new.show(duration: :max)
|
132
|
+
```
|
133
|
+
|
134
|
+
```ruby
|
135
|
+
{
|
136
|
+
duration: {
|
137
|
+
max: 9675
|
138
|
+
}
|
139
|
+
}
|
140
|
+
```
|
141
|
+
|
142
|
+
2. Multiple
|
143
|
+
|
144
|
+
```ruby
|
145
|
+
EZmetrics.new.show(queries: [:max, :avg])
|
146
|
+
```
|
147
|
+
|
148
|
+
```ruby
|
149
|
+
{
|
150
|
+
queries: {
|
151
|
+
max: 76,
|
152
|
+
avg: 26
|
153
|
+
}
|
154
|
+
}
|
155
|
+
```
|
156
|
+
|
157
|
+
3. Requests
|
158
|
+
|
159
|
+
```ruby
|
160
|
+
EZmetrics.new.show(requests: true)
|
161
|
+
```
|
162
|
+
|
163
|
+
```ruby
|
164
|
+
{
|
165
|
+
requests: {
|
166
|
+
all: 2000,
|
167
|
+
grouped: {
|
168
|
+
"2xx" => 1900,
|
169
|
+
"3xx" => 15,
|
170
|
+
"4xx" => 80,
|
171
|
+
"5xx" => 5
|
172
|
+
}
|
173
|
+
}
|
174
|
+
}
|
175
|
+
```
|
176
|
+
|
177
|
+
4. Combined
|
178
|
+
|
179
|
+
```ruby
|
180
|
+
EZmetrics.new.show(views: :avg, :db: [:avg, :max], requests: true)
|
181
|
+
```
|
182
|
+
|
183
|
+
```ruby
|
184
|
+
{
|
185
|
+
views: {
|
186
|
+
avg: 12
|
187
|
+
},
|
188
|
+
db: {
|
189
|
+
avg: 155,
|
190
|
+
max: 4382
|
191
|
+
},
|
192
|
+
requests: {
|
193
|
+
all: 2000,
|
194
|
+
grouped: {
|
195
|
+
"2xx" => 1900,
|
196
|
+
"3xx" => 15,
|
197
|
+
"4xx" => 80,
|
198
|
+
"5xx" => 5
|
199
|
+
}
|
200
|
+
}
|
201
|
+
}
|
202
|
+
```
|
203
|
+
|
124
204
|
### Performance
|
125
205
|
|
126
206
|
The implementation is based on **Redis** commands such as:
|
@@ -137,11 +217,12 @@ You can check the **aggregation** time by running:
|
|
137
217
|
EZmetrics::Benchmark.new.measure_aggregation
|
138
218
|
```
|
139
219
|
|
140
|
-
The result of running this benchmark on a
|
220
|
+
The result of running this benchmark on a _2017 Macbook Pro 2.9 GHz Intel Core i7 with 16 GB of RAM_:
|
141
221
|
|
142
222
|
| Interval | Duration (seconds) |
|
143
|
-
|
223
|
+
| :------: | :----------------: |
|
144
224
|
| 1 minute | 0.0 |
|
145
|
-
| 1 hour | 0.
|
146
|
-
| 12 hours |
|
147
|
-
| 24 hours |
|
225
|
+
| 1 hour | 0.05 |
|
226
|
+
| 12 hours | 0.66 |
|
227
|
+
| 24 hours | 1.83 |
|
228
|
+
| 48 hours | 4.06 |
|
data/lib/ezmetrics.rb
CHANGED
@@ -1,7 +1,11 @@
|
|
1
|
-
require "redis"
|
2
|
-
require "
|
1
|
+
require "redis"
|
2
|
+
require "redis/connection/hiredis"
|
3
|
+
require "oj"
|
3
4
|
|
4
5
|
class EZmetrics
|
6
|
+
METRICS = [:duration, :views, :db, :queries].freeze
|
7
|
+
AGGREGATION_FUNCTIONS = [:max, :avg].freeze
|
8
|
+
|
5
9
|
def initialize(interval_seconds=60)
|
6
10
|
@interval_seconds = interval_seconds.to_i
|
7
11
|
@redis = Redis.new
|
@@ -22,9 +26,9 @@ class EZmetrics
|
|
22
26
|
@this_second_metrics = redis.get("#{storage_key}:#{this_second}")
|
23
27
|
|
24
28
|
if this_second_metrics
|
25
|
-
@this_second_metrics =
|
29
|
+
@this_second_metrics = Oj.load(this_second_metrics)
|
26
30
|
|
27
|
-
|
31
|
+
METRICS.each do |metrics_type|
|
28
32
|
update_sum(metrics_type)
|
29
33
|
update_max(metrics_type)
|
30
34
|
end
|
@@ -47,31 +51,66 @@ class EZmetrics
|
|
47
51
|
this_second_metrics["statuses"][status_group] = 1
|
48
52
|
end
|
49
53
|
|
50
|
-
redis.setex("#{storage_key}:#{this_second}", interval_seconds,
|
51
|
-
|
54
|
+
redis.setex("#{storage_key}:#{this_second}", interval_seconds, Oj.dump(this_second_metrics))
|
52
55
|
true
|
53
56
|
rescue => error
|
54
57
|
formatted_error(error)
|
55
58
|
end
|
56
59
|
|
57
|
-
def show
|
60
|
+
def show(options=nil)
|
61
|
+
@options = options || default_options
|
58
62
|
interval_start = Time.now.to_i - interval_seconds
|
59
63
|
interval_keys = (interval_start..Time.now.to_i).to_a.map { |second| "#{storage_key}:#{second}" }
|
60
|
-
@interval_metrics = redis.mget(interval_keys).compact.map { |hash|
|
64
|
+
@interval_metrics = redis.mget(interval_keys).compact.map { |hash| Oj.load(hash) }
|
61
65
|
|
62
|
-
return
|
66
|
+
return {} unless interval_metrics.any?
|
63
67
|
|
64
68
|
@requests = interval_metrics.map { |hash| hash["statuses"]["all"] }.compact.sum
|
65
|
-
|
66
|
-
metrics_object
|
69
|
+
build_result
|
67
70
|
rescue
|
68
|
-
|
71
|
+
{}
|
69
72
|
end
|
70
73
|
|
71
74
|
private
|
72
75
|
|
73
|
-
attr_reader :redis, :interval_seconds, :interval_metrics, :requests,
|
74
|
-
:safe_payload, :this_second_metrics
|
76
|
+
attr_reader :redis, :interval_seconds, :interval_metrics, :requests,
|
77
|
+
:storage_key, :safe_payload, :this_second_metrics, :options
|
78
|
+
|
79
|
+
def build_result
|
80
|
+
result = {}
|
81
|
+
|
82
|
+
if options[:requests]
|
83
|
+
result[:requests] = {
|
84
|
+
all: requests,
|
85
|
+
grouped: {
|
86
|
+
"2xx" => count("2xx"),
|
87
|
+
"3xx" => count("3xx"),
|
88
|
+
"4xx" => count("4xx"),
|
89
|
+
"5xx" => count("5xx")
|
90
|
+
}
|
91
|
+
}
|
92
|
+
end
|
93
|
+
|
94
|
+
options.each do |metrics, aggregation_functions|
|
95
|
+
next unless METRICS.include?(metrics)
|
96
|
+
aggregation_functions = [aggregation_functions] unless aggregation_functions.is_a?(Array)
|
97
|
+
next unless aggregation_functions.any?
|
98
|
+
|
99
|
+
aggregation_functions.each do |aggregation_function|
|
100
|
+
result[metrics] ||= {}
|
101
|
+
result[metrics][aggregation_function] = aggregate(metrics, aggregation_function)
|
102
|
+
end
|
103
|
+
end
|
104
|
+
result
|
105
|
+
ensure
|
106
|
+
result
|
107
|
+
end
|
108
|
+
|
109
|
+
def aggregate(metrics, aggregation_function)
|
110
|
+
return unless AGGREGATION_FUNCTIONS.include?(aggregation_function)
|
111
|
+
return avg("#{metrics}_sum".to_sym) if aggregation_function == :avg
|
112
|
+
return max("#{metrics}_max".to_sym) if aggregation_function == :max
|
113
|
+
end
|
75
114
|
|
76
115
|
def update_sum(metrics)
|
77
116
|
this_second_metrics["#{metrics}_sum"] += safe_payload[metrics.to_sym]
|
@@ -94,65 +133,23 @@ class EZmetrics
|
|
94
133
|
interval_metrics.map { |h| h["statuses"][group.to_s] }.sum
|
95
134
|
end
|
96
135
|
|
97
|
-
def
|
136
|
+
def default_options
|
98
137
|
{
|
99
|
-
|
100
|
-
|
101
|
-
|
138
|
+
duration: AGGREGATION_FUNCTIONS,
|
139
|
+
views: AGGREGATION_FUNCTIONS,
|
140
|
+
db: AGGREGATION_FUNCTIONS,
|
141
|
+
queries: AGGREGATION_FUNCTIONS,
|
142
|
+
requests: true
|
102
143
|
}
|
103
144
|
end
|
104
145
|
|
105
|
-
def
|
106
|
-
{
|
107
|
-
duration: {
|
108
|
-
avg: avg(:duration_sum),
|
109
|
-
max: max(:duration_max)
|
110
|
-
},
|
111
|
-
views: {
|
112
|
-
avg: avg(:views_sum),
|
113
|
-
max: max(:views_max)
|
114
|
-
},
|
115
|
-
db: {
|
116
|
-
avg: avg(:db_sum),
|
117
|
-
max: max(:db_max)
|
118
|
-
},
|
119
|
-
queries: {
|
120
|
-
avg: avg(:queries_sum),
|
121
|
-
max: max(:queries_max)
|
122
|
-
},
|
123
|
-
requests: {
|
124
|
-
all: requests,
|
125
|
-
grouped: {
|
126
|
-
"2xx" => count("2xx"),
|
127
|
-
"3xx" => count("3xx"),
|
128
|
-
"4xx" => count("4xx"),
|
129
|
-
"5xx" => count("5xx")
|
130
|
-
}
|
131
|
-
}
|
132
|
-
}
|
133
|
-
end
|
134
|
-
|
135
|
-
def empty_metrics_object
|
146
|
+
def formatted_error(error)
|
136
147
|
{
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
},
|
141
|
-
views: {
|
142
|
-
avg: 0,
|
143
|
-
max: 0
|
144
|
-
},
|
145
|
-
db: {
|
146
|
-
avg: 0,
|
147
|
-
max: 0
|
148
|
-
},
|
149
|
-
queries: {
|
150
|
-
avg: 0,
|
151
|
-
max: 0
|
152
|
-
},
|
153
|
-
requests: {}
|
148
|
+
error: error.class.name,
|
149
|
+
message: error.message,
|
150
|
+
backtrace: error.backtrace.reject { |line| line.match(/ruby|gems/) }
|
154
151
|
}
|
155
152
|
end
|
156
153
|
end
|
157
154
|
|
158
|
-
require "ezmetrics/benchmark"
|
155
|
+
require "ezmetrics/benchmark"
|
data/lib/ezmetrics/benchmark.rb
CHANGED
@@ -11,7 +11,8 @@ class EZmetrics::Benchmark
|
|
11
11
|
"1.minute" => 60,
|
12
12
|
"1.hour " => 3600,
|
13
13
|
"12.hours" => 43200,
|
14
|
-
"24.hours" => 86400
|
14
|
+
"24.hours" => 86400,
|
15
|
+
"48.hours" => 172800
|
15
16
|
}
|
16
17
|
end
|
17
18
|
|
@@ -35,15 +36,15 @@ class EZmetrics::Benchmark
|
|
35
36
|
seconds.times do |i|
|
36
37
|
second = start - i
|
37
38
|
payload = {
|
38
|
-
"duration_sum"
|
39
|
-
"duration_max"
|
40
|
-
"views_sum"
|
41
|
-
"views_max"
|
42
|
-
"db_sum"
|
43
|
-
"db_max"
|
44
|
-
"queries_sum"
|
45
|
-
"queries_max"
|
46
|
-
"statuses"
|
39
|
+
"duration_sum" => rand(10000),
|
40
|
+
"duration_max" => rand(10000),
|
41
|
+
"views_sum" => rand(1000),
|
42
|
+
"views_max" => rand(1000),
|
43
|
+
"db_sum" => rand(8000),
|
44
|
+
"db_max" => rand(8000),
|
45
|
+
"queries_sum" => rand(100),
|
46
|
+
"queries_max" => rand(100),
|
47
|
+
"statuses" => {
|
47
48
|
"2xx" => rand(10),
|
48
49
|
"3xx" => rand(10),
|
49
50
|
"4xx" => rand(10),
|
@@ -51,7 +52,7 @@ class EZmetrics::Benchmark
|
|
51
52
|
"all" => rand(40)
|
52
53
|
}
|
53
54
|
}
|
54
|
-
redis.setex("ez-metrics:#{second}", seconds,
|
55
|
+
redis.setex("ez-metrics:#{second}", seconds, Oj.dump(payload))
|
55
56
|
end
|
56
57
|
nil
|
57
58
|
end
|
@@ -84,4 +85,4 @@ class EZmetrics::Benchmark
|
|
84
85
|
def print_footer
|
85
86
|
print "#{'─'*31}\n"
|
86
87
|
end
|
87
|
-
end
|
88
|
+
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: ezmetrics
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.0
|
4
|
+
version: 1.1.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Nicolae Rotaru
|
@@ -24,6 +24,34 @@ dependencies:
|
|
24
24
|
- - "~>"
|
25
25
|
- !ruby/object:Gem::Version
|
26
26
|
version: '4.0'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: hiredis
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: 0.6.3
|
34
|
+
type: :runtime
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: 0.6.3
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: oj
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - "~>"
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '3.10'
|
48
|
+
type: :runtime
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - "~>"
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '3.10'
|
27
55
|
- !ruby/object:Gem::Dependency
|
28
56
|
name: rspec
|
29
57
|
requirement: !ruby/object:Gem::Requirement
|
@@ -67,8 +95,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
67
95
|
- !ruby/object:Gem::Version
|
68
96
|
version: '0'
|
69
97
|
requirements: []
|
70
|
-
|
71
|
-
rubygems_version: 2.6.13
|
98
|
+
rubygems_version: 3.0.6
|
72
99
|
signing_key:
|
73
100
|
specification_version: 4
|
74
101
|
summary: Rails metrics aggregation tool.
|