ezmetrics 1.0.6 → 1.1.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA1:
3
- metadata.gz: dc9e49c32e99f5d45f45ca6d3d467e53c09b8502
4
- data.tar.gz: ce9f340d9f70ddfd7aebbac487e2d1b4b094527f
2
+ SHA256:
3
+ metadata.gz: 5ba2e24bca76b2786c1264b779e72764e123094150855cae241d673505df95ad
4
+ data.tar.gz: 3c297b92a53c51b8b881fbbafb15929b9bac36eb53164c3faab37c2caa72db02
5
5
  SHA512:
6
- metadata.gz: 295ae4b987d80ec5feb6cbb21e0f5dee0ea6523d140e50840b5637b57c3263f712b5c798eed3c69794fb8618a5236e7f6005a1fee34f4e2f6e8812f97ab636e7
7
- data.tar.gz: 8c9523d1385036e83a1eaea18e275c91f2865c391ad60f50a2af76b865843338e1d4408e8f08f037c2af14ba552181f7a82e85be7ea5b7242755f2c4070fb418
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 *2017 Macbook Pro 2.9 GHz Intel Core i7 with 16 GB of RAM*:
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.11 |
146
- | 12 hours | 1.6 |
147
- | 24 hours | 3.5 |
225
+ | 1 hour | 0.05 |
226
+ | 12 hours | 0.66 |
227
+ | 24 hours | 1.83 |
228
+ | 48 hours | 4.06 |
@@ -1,7 +1,11 @@
1
- require "redis" unless defined?(Redis)
2
- require "json" unless defined?(JSON)
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 = JSON.parse(this_second_metrics)
29
+ @this_second_metrics = Oj.load(this_second_metrics)
26
30
 
27
- [:duration, :views, :db, :queries].each do |metrics_type|
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, JSON.generate(this_second_metrics))
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| JSON.parse(hash) }
64
+ @interval_metrics = redis.mget(interval_keys).compact.map { |hash| Oj.load(hash) }
61
65
 
62
- return empty_metrics_object unless interval_metrics.any?
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
- empty_metrics_object
71
+ {}
69
72
  end
70
73
 
71
74
  private
72
75
 
73
- attr_reader :redis, :interval_seconds, :interval_metrics, :requests, :storage_key,
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 formatted_error(error)
136
+ def default_options
98
137
  {
99
- error: error.class.name,
100
- message: error.message,
101
- backtrace: error.backtrace.reject { |line| line.match(/ruby|gems/) }
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 metrics_object
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
- duration: {
138
- avg: 0,
139
- max: 0
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"
@@ -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" => rand(10000),
39
- "duration_max" => rand(10000),
40
- "views_sum" => rand(1000),
41
- "views_max" => rand(1000),
42
- "db_sum" => rand(8000),
43
- "db_max" => rand(8000),
44
- "queries_sum" => rand(100),
45
- "queries_max" => rand(100),
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, JSON.generate(payload))
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.6
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
- rubyforge_project:
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.