request_metrics 0.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 +7 -0
- data/CHANGELOG.md +5 -0
- data/LICENSE.txt +21 -0
- data/README.md +241 -0
- data/Rakefile +8 -0
- data/lib/request_metrics/base.rb +89 -0
- data/lib/request_metrics/railtie.rb +13 -0
- data/lib/request_metrics/version.rb +5 -0
- data/lib/request_metrics.rb +17 -0
- data/sig/request_metrics.rbs +4 -0
- metadata +70 -0
checksums.yaml
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
---
|
|
2
|
+
SHA256:
|
|
3
|
+
metadata.gz: c84c65399cbb0e8e971274bfff55901eb2c6dbd9be6f57ec8d58513aef27ef82
|
|
4
|
+
data.tar.gz: bb78391705582bf316869b46d6c218782147aaef1b86ef7ecfa0d2c078dc4590
|
|
5
|
+
SHA512:
|
|
6
|
+
metadata.gz: daeae6fe180094f619ee6d847bcab51760d5cd194ed6f077ea6bfe4f339aafe97853fc49ada48784a22012feb5d646cd1892a1f0b23a2286f90616c1a498d0dd
|
|
7
|
+
data.tar.gz: 8ee55f06673430f59fdf3c6dba3bf20eb621d5af75b2ce41cd5dd9f9feb7a26e95e50e1261a3d675b2ed3645d1c2a445374501da07619a420ae922760e92a1b2
|
data/CHANGELOG.md
ADDED
data/LICENSE.txt
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
The MIT License (MIT)
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Elia Schito
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in
|
|
13
|
+
all copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
21
|
+
THE SOFTWARE.
|
data/README.md
ADDED
|
@@ -0,0 +1,241 @@
|
|
|
1
|
+
# RequestMetrics
|
|
2
|
+
|
|
3
|
+
Per-request metric tracking and structured log summaries for Rails controllers.
|
|
4
|
+
|
|
5
|
+
Subclass `RequestMetrics::Base`, declare counters with `metric_accessor`, implement `#log` to record each event, and Rails will append a summary to every `process_action` log line — zero boilerplate.
|
|
6
|
+
|
|
7
|
+
```
|
|
8
|
+
Completed 200 OK in 142ms (Views: 0.5ms | GQL: 87.3ms, 44 cost | Loop API: 31.1ms)
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Installation
|
|
12
|
+
|
|
13
|
+
Add to your Gemfile:
|
|
14
|
+
|
|
15
|
+
```ruby
|
|
16
|
+
gem "request_metrics"
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
No initializer needed. A Railtie installs all registered subclasses into `ActionController::Base` automatically.
|
|
20
|
+
|
|
21
|
+
## Usage
|
|
22
|
+
|
|
23
|
+
### 1. Subclass `RequestMetrics::Base`
|
|
24
|
+
|
|
25
|
+
```ruby
|
|
26
|
+
class MyServiceMetrics < RequestMetrics::Base
|
|
27
|
+
metric_accessor :my_service_runtime # declares counter + thread-safe accessors
|
|
28
|
+
|
|
29
|
+
# Called on each tracked event — add to the counter and log the line
|
|
30
|
+
def log(ms:, url:, status:)
|
|
31
|
+
add_my_service_runtime(ms)
|
|
32
|
+
name = color(" MyService (#{ms.round(1)}ms)", YELLOW, bold: true)
|
|
33
|
+
debug "#{name} #{url} (status: #{status})"
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
# Optional — return a string to append to the controller summary log line
|
|
37
|
+
def self.summary_log(payload)
|
|
38
|
+
ms = payload[:my_service_runtime] || 0
|
|
39
|
+
"MyService: #{ms.round(1)}ms" if ms > 0
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
### 2. Call `.log` from your HTTP client or wherever the event occurs
|
|
45
|
+
|
|
46
|
+
```ruby
|
|
47
|
+
ms = ActiveSupport::Benchmark.realtime(:float_millisecond) { response = do_request }
|
|
48
|
+
MyServiceMetrics.log(ms:, url:, status: response.code)
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
### 3. Filter noise from source location output
|
|
52
|
+
|
|
53
|
+
`verbose_query_logs` (default `true`) appends a `↳ app/...` caller hint below each log line. Add silencers to suppress framework internals:
|
|
54
|
+
|
|
55
|
+
```ruby
|
|
56
|
+
class MyServiceMetrics < RequestMetrics::Base
|
|
57
|
+
backtrace_cleaner.add_silencer { |line| line.include?("app/clients/") }
|
|
58
|
+
backtrace_cleaner.add_silencer { |line| line.include?("app/models/concerns/") }
|
|
59
|
+
# ...
|
|
60
|
+
end
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
---
|
|
64
|
+
|
|
65
|
+
## Real-world examples
|
|
66
|
+
|
|
67
|
+
These are the two metrics classes from a Rails + Shopify app.
|
|
68
|
+
|
|
69
|
+
### Loop API (HTTP client tracking)
|
|
70
|
+
|
|
71
|
+
Tracks every outbound call to the [Loop Subscriptions](https://loopsubscriptions.com/) API, including cached responses.
|
|
72
|
+
|
|
73
|
+
```ruby
|
|
74
|
+
class LoopControllerMetrics < RequestMetrics::Base
|
|
75
|
+
backtrace_cleaner.add_silencer { |line| line.include?(__FILE__) }
|
|
76
|
+
backtrace_cleaner.add_silencer { |line| line.include?("app/clients/") }
|
|
77
|
+
backtrace_cleaner.add_silencer { |line| line.include?("app/models/concerns/") }
|
|
78
|
+
backtrace_cleaner.add_silencer { |line| line.include?("config/initializers/") }
|
|
79
|
+
|
|
80
|
+
metric_accessor :loop_runtime
|
|
81
|
+
|
|
82
|
+
def log(method:, url:, ms:, status:, data: nil, cached: false)
|
|
83
|
+
add_loop_runtime(ms)
|
|
84
|
+
|
|
85
|
+
http_color =
|
|
86
|
+
case status.to_i
|
|
87
|
+
when 200..299 then GREEN
|
|
88
|
+
when 300..399 then CYAN
|
|
89
|
+
when 400..499 then YELLOW
|
|
90
|
+
when 500..599 then RED
|
|
91
|
+
else MAGENTA
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
name = color(" #{cached ? "CACHE " : ""}Loop API (#{ms.round(1)}ms)", YELLOW, bold: true)
|
|
95
|
+
request = color("#{method} #{url}", http_color, bold: true)
|
|
96
|
+
|
|
97
|
+
debug "#{name} #{request} #{data&.to_json} (status: #{status})"
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
def self.summary_log(payload)
|
|
101
|
+
ms = payload[:loop_runtime] || 0
|
|
102
|
+
"Loop API: #{ms.round(1)}ms" if ms > 0
|
|
103
|
+
end
|
|
104
|
+
end
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
Called from the HTTP client:
|
|
108
|
+
|
|
109
|
+
```ruby
|
|
110
|
+
ms = ActiveSupport::Benchmark.realtime(:float_millisecond) { perform.call }
|
|
111
|
+
LoopControllerMetrics.log(method: request.method, url: uri.to_s, ms:, status: response.code, data:)
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
Cached hits are logged with zero ms and `CACHE` prefix:
|
|
115
|
+
|
|
116
|
+
```ruby
|
|
117
|
+
LoopControllerMetrics.log(method: method.upcase, url:, ms: 0, status: 200, cached: true)
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
### Shopify GraphQL (API client patching)
|
|
121
|
+
|
|
122
|
+
Tracks every Shopify Admin API GraphQL call, including query cost. Patches the official `shopify_api` gem's client via `prepend`.
|
|
123
|
+
|
|
124
|
+
```ruby
|
|
125
|
+
class ShopifyGraphqlMetrics < RequestMetrics::Base
|
|
126
|
+
backtrace_cleaner.add_silencer { |line| line.include?(__FILE__) }
|
|
127
|
+
backtrace_cleaner.add_silencer { |line| line.include?("app/models/shop.rb") }
|
|
128
|
+
backtrace_cleaner.add_silencer { |line| line.include?("app/models/concerns/") }
|
|
129
|
+
backtrace_cleaner.add_silencer { |line| line.include?("config/initializers/") }
|
|
130
|
+
|
|
131
|
+
metric_accessor :graphql_runtime
|
|
132
|
+
metric_accessor :graphql_cost
|
|
133
|
+
|
|
134
|
+
def self.install!
|
|
135
|
+
super
|
|
136
|
+
require "shopify_api/clients/graphql/admin"
|
|
137
|
+
ShopifyAPI::Clients::Graphql::Client.prepend(ShopifyAPIClientLoggingPatch)
|
|
138
|
+
end
|
|
139
|
+
|
|
140
|
+
module ShopifyAPIClientLoggingPatch
|
|
141
|
+
def query(query:, variables: nil, headers: nil, tries: 1, response_as_struct: ShopifyAPI::Context.response_as_struct, debug: false)
|
|
142
|
+
response = nil
|
|
143
|
+
ms = ActiveSupport::Benchmark.realtime(:float_millisecond) { response = super }
|
|
144
|
+
cost = response.body.dig("extensions", "cost")
|
|
145
|
+
ShopifyGraphqlMetrics.log(query:, ms:, cost:, variables:)
|
|
146
|
+
response
|
|
147
|
+
end
|
|
148
|
+
end
|
|
149
|
+
|
|
150
|
+
def log(query:, ms:, cost:, variables:, cached: false)
|
|
151
|
+
add_graphql_runtime(ms)
|
|
152
|
+
add_graphql_cost(cost.dig("requestedQueryCost")) if cost
|
|
153
|
+
|
|
154
|
+
graphql_color =
|
|
155
|
+
case query
|
|
156
|
+
when /\A\s*mutation/i then GREEN
|
|
157
|
+
when /\A\s*query/i then BLUE
|
|
158
|
+
when /\A\s*subscription/i then CYAN
|
|
159
|
+
else MAGENTA
|
|
160
|
+
end
|
|
161
|
+
|
|
162
|
+
name = color(" #{cached ? "CACHE " : ""}GraphQL (#{ms.round(1)}ms)", YELLOW, bold: true)
|
|
163
|
+
colored_query = color(query.gsub(/\s+/, " ").strip, graphql_color, bold: true)
|
|
164
|
+
binds = variables.present? ? " #{variables.inspect}" : ""
|
|
165
|
+
cost_info = "\n ↳ cost: #{cost}" if cost
|
|
166
|
+
|
|
167
|
+
debug "#{name} #{colored_query}#{binds}#{cost_info}"
|
|
168
|
+
end
|
|
169
|
+
|
|
170
|
+
def self.summary_log(payload)
|
|
171
|
+
runtime = payload[:graphql_runtime]
|
|
172
|
+
cost = payload[:graphql_cost]
|
|
173
|
+
|
|
174
|
+
if runtime && runtime > 0
|
|
175
|
+
cost_info = cost && cost > 0 ? ", #{cost.round} cost" : ""
|
|
176
|
+
"GQL: #{runtime.round(1)}ms#{cost_info}"
|
|
177
|
+
end
|
|
178
|
+
end
|
|
179
|
+
end
|
|
180
|
+
```
|
|
181
|
+
|
|
182
|
+
Result in logs:
|
|
183
|
+
|
|
184
|
+
```
|
|
185
|
+
GraphQL (87.3ms) query GetSubscription { ... } { id: "gid://shopify/..." }
|
|
186
|
+
↳ cost: {"requestedQueryCost"=>44, ...}
|
|
187
|
+
↳ app/models/concerns/loop/subscription/persistence.rb:23:in `find'
|
|
188
|
+
|
|
189
|
+
Completed 200 OK in 142ms (Views: 0.5ms | GQL: 87.3ms, 44 cost | Loop API: 31.1ms)
|
|
190
|
+
```
|
|
191
|
+
|
|
192
|
+
---
|
|
193
|
+
|
|
194
|
+
## API reference
|
|
195
|
+
|
|
196
|
+
### `metric_accessor(name)`
|
|
197
|
+
|
|
198
|
+
Declares a per-request counter stored in a thread-local. Generates:
|
|
199
|
+
|
|
200
|
+
| Method | Description |
|
|
201
|
+
|---|---|
|
|
202
|
+
| `MyMetrics.my_metric` | Read current value (default: `0`) |
|
|
203
|
+
| `MyMetrics.my_metric = n` | Set value |
|
|
204
|
+
| `MyMetrics.add_my_metric(delta)` | Increment |
|
|
205
|
+
| `MyMetrics.reset_my_metric` | Return current value and reset to `0` |
|
|
206
|
+
|
|
207
|
+
Thread-local keys are namespaced by subclass name, so two subclasses can both declare `metric_accessor :runtime` without collision.
|
|
208
|
+
|
|
209
|
+
### `#log(**kwargs)` (instance, delegated to class)
|
|
210
|
+
|
|
211
|
+
Called per event. Must be implemented by subclasses. Raise `NotImplementedError` if not.
|
|
212
|
+
|
|
213
|
+
### `.summary_log(payload)` (class)
|
|
214
|
+
|
|
215
|
+
Called once per request after `process_action`. Return a `String` to append to the log summary, or `nil` to skip. Default implementation returns `nil`.
|
|
216
|
+
|
|
217
|
+
### `.install!` (class)
|
|
218
|
+
|
|
219
|
+
Called automatically by the Railtie. Can be overridden to do additional setup (e.g., patching a third-party client) — call `super` to preserve the `ActionController` hook.
|
|
220
|
+
|
|
221
|
+
### `backtrace_cleaner`
|
|
222
|
+
|
|
223
|
+
Each subclass gets its own `ActiveSupport::BacktraceCleaner` instance (empty by default). Add silencers to filter which stack frame appears in the `↳` hint.
|
|
224
|
+
|
|
225
|
+
### `verbose_query_logs`
|
|
226
|
+
|
|
227
|
+
Boolean (default: `true`). Set to `false` to suppress the `↳ source` hint entirely.
|
|
228
|
+
|
|
229
|
+
---
|
|
230
|
+
|
|
231
|
+
## Development
|
|
232
|
+
|
|
233
|
+
```bash
|
|
234
|
+
bin/setup # install dependencies
|
|
235
|
+
rake test # run tests
|
|
236
|
+
bin/console # interactive prompt
|
|
237
|
+
```
|
|
238
|
+
|
|
239
|
+
## License
|
|
240
|
+
|
|
241
|
+
MIT.
|
data/Rakefile
ADDED
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "active_support/log_subscriber"
|
|
4
|
+
require "active_support/backtrace_cleaner"
|
|
5
|
+
require "active_support/core_ext/class/attribute"
|
|
6
|
+
require "active_support/concern"
|
|
7
|
+
|
|
8
|
+
module RequestMetrics
|
|
9
|
+
class Base < ActiveSupport::LogSubscriber
|
|
10
|
+
class_attribute :backtrace_cleaner, default: ActiveSupport::BacktraceCleaner.new
|
|
11
|
+
class_attribute :verbose_query_logs, default: true
|
|
12
|
+
class_attribute :metrics, default: []
|
|
13
|
+
|
|
14
|
+
def self.metric_accessor(name)
|
|
15
|
+
metrics << name
|
|
16
|
+
|
|
17
|
+
subclass = self
|
|
18
|
+
key = :"#{subclass.object_id}/#{name}"
|
|
19
|
+
|
|
20
|
+
define_singleton_method(name) { Thread.current[key] ||= 0 }
|
|
21
|
+
define_singleton_method("#{name}=") { |value| Thread.current[key] = value }
|
|
22
|
+
define_singleton_method("reset_#{name}") { send(name).tap { send("#{name}=", 0) } }
|
|
23
|
+
define_singleton_method("add_#{name}") { |delta| send("#{name}=", send(name) + delta) }
|
|
24
|
+
|
|
25
|
+
define_method(name) { subclass.send(name) }
|
|
26
|
+
define_method("#{name}=") { |v| subclass.send("#{name}=", v) }
|
|
27
|
+
define_method("reset_#{name}") { subclass.send("reset_#{name}") }
|
|
28
|
+
define_method("add_#{name}") { |delta| subclass.send("add_#{name}", delta) }
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def self.inherited(subclass)
|
|
32
|
+
super
|
|
33
|
+
|
|
34
|
+
subclass.backtrace_cleaner = ActiveSupport::BacktraceCleaner.new
|
|
35
|
+
subclass.verbose_query_logs = verbose_query_logs
|
|
36
|
+
subclass.metrics = []
|
|
37
|
+
|
|
38
|
+
RequestMetrics.register(subclass)
|
|
39
|
+
|
|
40
|
+
controller_runtime_module = Module.new { extend ActiveSupport::Concern }
|
|
41
|
+
|
|
42
|
+
controller_runtime_module.class_methods do
|
|
43
|
+
define_method :log_process_action do |payload|
|
|
44
|
+
messages = super(payload)
|
|
45
|
+
subclass.summary_log(payload)&.then { messages << it }
|
|
46
|
+
messages
|
|
47
|
+
end
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
controller_runtime_module.define_method :append_info_to_payload do |payload|
|
|
51
|
+
super(payload)
|
|
52
|
+
subclass.metrics.each { |metric| payload[metric] = subclass.send("reset_#{metric}") }
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
subclass.const_set :ControllerRuntime, controller_runtime_module
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
def self.install!
|
|
59
|
+
runtime_module = const_get(:ControllerRuntime)
|
|
60
|
+
ActiveSupport.on_load(:action_controller) { include runtime_module }
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
def self.summary_log(payload)
|
|
64
|
+
nil
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
def log(**options)
|
|
68
|
+
raise NotImplementedError, "#{self.class} must implement #log"
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
singleton_class.delegate :log, to: :new
|
|
72
|
+
|
|
73
|
+
def debug(message)
|
|
74
|
+
logger.debug(message)
|
|
75
|
+
log_query_source if verbose_query_logs
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
private
|
|
79
|
+
|
|
80
|
+
def log_query_source
|
|
81
|
+
source = query_source_location
|
|
82
|
+
logger.debug(" ↳ #{source}") if source
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
def query_source_location
|
|
86
|
+
backtrace_cleaner.first_clean_frame
|
|
87
|
+
end
|
|
88
|
+
end
|
|
89
|
+
end
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "rails/railtie"
|
|
4
|
+
|
|
5
|
+
module RequestMetrics
|
|
6
|
+
class Railtie < Rails::Railtie
|
|
7
|
+
initializer "request_metrics.install" do
|
|
8
|
+
ActiveSupport.on_load(:action_controller) do
|
|
9
|
+
RequestMetrics.registry.each(&:install!)
|
|
10
|
+
end
|
|
11
|
+
end
|
|
12
|
+
end
|
|
13
|
+
end
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative "request_metrics/version"
|
|
4
|
+
require_relative "request_metrics/base"
|
|
5
|
+
require_relative "request_metrics/railtie" if defined?(Rails::Railtie)
|
|
6
|
+
|
|
7
|
+
module RequestMetrics
|
|
8
|
+
class << self
|
|
9
|
+
def registry
|
|
10
|
+
@registry ||= []
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def register(subclass)
|
|
14
|
+
registry << subclass
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
end
|
metadata
ADDED
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
|
2
|
+
name: request_metrics
|
|
3
|
+
version: !ruby/object:Gem::Version
|
|
4
|
+
version: 0.1.0
|
|
5
|
+
platform: ruby
|
|
6
|
+
authors:
|
|
7
|
+
- Elia Schito
|
|
8
|
+
bindir: exe
|
|
9
|
+
cert_chain: []
|
|
10
|
+
date: 1980-01-02 00:00:00.000000000 Z
|
|
11
|
+
dependencies:
|
|
12
|
+
- !ruby/object:Gem::Dependency
|
|
13
|
+
name: activesupport
|
|
14
|
+
requirement: !ruby/object:Gem::Requirement
|
|
15
|
+
requirements:
|
|
16
|
+
- - ">="
|
|
17
|
+
- !ruby/object:Gem::Version
|
|
18
|
+
version: '7.0'
|
|
19
|
+
type: :runtime
|
|
20
|
+
prerelease: false
|
|
21
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
22
|
+
requirements:
|
|
23
|
+
- - ">="
|
|
24
|
+
- !ruby/object:Gem::Version
|
|
25
|
+
version: '7.0'
|
|
26
|
+
description: |
|
|
27
|
+
RequestMetrics provides a base class for attaching per-request counters and
|
|
28
|
+
timing metrics to Rails controller log lines. Subclass RequestMetrics::Base,
|
|
29
|
+
declare metrics with metric_accessor, implement #log and .summary_log, and
|
|
30
|
+
the gem wires everything into ActionController via a Railtie automatically.
|
|
31
|
+
email:
|
|
32
|
+
- elia@schito.me
|
|
33
|
+
executables: []
|
|
34
|
+
extensions: []
|
|
35
|
+
extra_rdoc_files: []
|
|
36
|
+
files:
|
|
37
|
+
- CHANGELOG.md
|
|
38
|
+
- LICENSE.txt
|
|
39
|
+
- README.md
|
|
40
|
+
- Rakefile
|
|
41
|
+
- lib/request_metrics.rb
|
|
42
|
+
- lib/request_metrics/base.rb
|
|
43
|
+
- lib/request_metrics/railtie.rb
|
|
44
|
+
- lib/request_metrics/version.rb
|
|
45
|
+
- sig/request_metrics.rbs
|
|
46
|
+
homepage: https://github.com/nebulab/request_metrics
|
|
47
|
+
licenses:
|
|
48
|
+
- MIT
|
|
49
|
+
metadata:
|
|
50
|
+
homepage_uri: https://github.com/nebulab/request_metrics
|
|
51
|
+
source_code_uri: https://github.com/nebulab/request_metrics
|
|
52
|
+
changelog_uri: https://github.com/nebulab/request_metrics/blob/main/CHANGELOG.md
|
|
53
|
+
rdoc_options: []
|
|
54
|
+
require_paths:
|
|
55
|
+
- lib
|
|
56
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
|
57
|
+
requirements:
|
|
58
|
+
- - ">="
|
|
59
|
+
- !ruby/object:Gem::Version
|
|
60
|
+
version: 3.2.0
|
|
61
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
62
|
+
requirements:
|
|
63
|
+
- - ">="
|
|
64
|
+
- !ruby/object:Gem::Version
|
|
65
|
+
version: '0'
|
|
66
|
+
requirements: []
|
|
67
|
+
rubygems_version: 4.0.10
|
|
68
|
+
specification_version: 4
|
|
69
|
+
summary: Per-request metric tracking and log summaries for Rails controllers
|
|
70
|
+
test_files: []
|