rack_middleware_metrics 0.0.1 → 0.0.7
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +78 -37
- data/lib/md5_gen.rb +31 -15
- data/lib/rack_middleware_metrics.rb +1 -1
- data/lib/rack_middleware_metrics/railtie.rb +4 -1
- data/lib/rack_middleware_metrics/reporter.rb +44 -5
- data/lib/rack_middleware_metrics/version.rb +1 -1
- data/lib/tasks/helix_runtime.rake +6 -2
- metadata +3 -5
- data/.~lock.GIST_API.odt# +0 -1
- data/lib/md5_ruby_ext.rb +0 -10
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: d25a76b74595b845fd92fffd63b0cc1b383f78642ee834ceb85b7add4a4945d9
|
4
|
+
data.tar.gz: 9691ccdcb57e694c0702ff9037ea830ecf057060dca2400e7fd76078b55e5be9
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 072aa309b1d14e2bd6ec960fe04777d4a29be2733536777779d25671ad5d827ccc7dad95f3db115a55f9d4b6f7907f6437c4f957f603125746227998891cf639
|
7
|
+
data.tar.gz: 82c42fada205c45dc77a7ce6a525294fc2986c248ec865d32eb7abf00e6e0368c994bfc38f7726c9e3aa48e419d317ca0c2d42223cf1cf5b914dceb98daac4df
|
data/README.md
CHANGED
@@ -1,54 +1,95 @@
|
|
1
|
+
[![Build Status](https://travis-ci.com/reedjosh/RackMiddlewareMetrics.svg?branch=main)](https://travis-ci.com/reedjosh/RackMiddlewareMetrics)
|
1
2
|
# Metrics Reporter
|
2
3
|
A minimalist Application Performance Monitoring (APM) library for Ruby on Rails.
|
3
4
|
|
4
|
-
[![Build Status](https://travis-ci.com/reedjosh/RackMiddlewareMetrics.svg?branch=main)](https://travis-ci.com/reedjosh/RackMiddlewareMetrics)
|
5
|
-
|
6
|
-
Reports:
|
7
|
-
- The time that the request enters the middleware.
|
8
|
-
- The time that it leaves the middleware.
|
9
|
-
- Request path
|
10
|
-
- The request's parameter list.
|
11
|
-
- MD5 hash value of the rendered output.
|
12
|
-
- Current thread and process ids.
|
13
5
|
|
14
|
-
|
6
|
+
The middleware generates a CSV file with the followinfg fields (no header):
|
7
|
+
- Request Time: the timestamp when the request enters the middleware
|
8
|
+
- Response Time: the timestamp when the response leaves the middleware
|
9
|
+
- Elapsed Time: the time betwen request and response
|
10
|
+
- Path: the URI of the request
|
11
|
+
- Params: a semi-colon delimited list of GET parameters
|
12
|
+
- Thread ID: the thread ID of the current request
|
13
|
+
- Process ID: the process ID of the current request
|
14
|
+
- MD5: the hash value of the response body
|
15
15
|
|
16
16
|
The location and name of the file are configurable by the user.
|
17
17
|
|
18
|
-
|
18
|
+
Optionally: Does MD5 calculation in Rust if native extention is built.
|
19
19
|
|
20
|
-
|
20
|
+
## Getting Started
|
21
21
|
|
22
|
-
|
22
|
+
[Yard Docs](https://rubydoc.info/github/reedjosh/RackMiddlewareMetrics)
|
23
23
|
|
24
|
+
### Installation
|
25
|
+
Install from [ruby gems](https://rubygems.org/gems/rack_middleware_metrics)
|
24
26
|
|
25
|
-
|
26
|
-
TODO: Add the Gem to an open source Ruby on Rails project (RedMine, Discourse, etc) and generate
|
27
|
-
a performance metrics CSV file.
|
27
|
+
`bundle add rack_middleware_metrics`
|
28
28
|
|
29
|
-
|
29
|
+
### Non-rails Setup
|
30
|
+
See [example](https://github.com/reedjosh/RackMiddlewareMetrics/blob/main/example/thin_rack_app.rb) for setup with rack directly.
|
31
|
+
```ruby
|
32
|
+
class RackApp
|
33
|
+
def self.call _env
|
34
|
+
[200, { some_header: 'a value' }, ['Hi!']]
|
35
|
+
end
|
36
|
+
end
|
30
37
|
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
38
|
+
app =
|
39
|
+
Rack::Builder.app do
|
40
|
+
use(RackMiddlewareMetrics::Reporter, logpath: 'some_metrics_filepath.csv')
|
41
|
+
run(RackApp)
|
42
|
+
end
|
43
|
+
|
44
|
+
handler = Rack::Handler::Thin
|
45
|
+
handler.run(app, Port: 8082)
|
46
|
+
```
|
47
|
+
|
48
|
+
### Rails setup.
|
49
|
+
The middleware is automatically registered with Rails. But to configure the logpath add:
|
50
|
+
``` ruby
|
51
|
+
config.rack_middleware_metrics.logpath = Rails.root / 'some_metrics_filepath.csv'
|
52
|
+
```
|
53
|
+
to `config/environments/*.rb`
|
54
|
+
|
55
|
+
## Example Output from Redmine Rails Project
|
56
|
+
|
57
|
+
| Start | End | Duration(S) | URI | Params | Thread | PID | MD5 |
|
58
|
+
|-------------------------|-------------------------|-------------|------------------------------|----------------------|--------------|-----|---------------------------------|
|
59
|
+
|2020-10-27 13:32:46 -0700|2020-10-27 13:32:47 -0700| 0.698014072 |http://localhost:3000/ | |55890640 |18581|1724d0f493f9ed2e191d9aeb49df0f4c |
|
60
|
+
|2020-10-27 13:33:07 -0700|2020-10-27 13:33:07 -0700| 0.02697148 |http://localhost:3000/ | |70368509891620|18581|80eabd1e0373408b0a40b08b0eec6c3f |
|
61
|
+
|2020-10-28 09:40:16 -0700|2020-10-28 09:40:16 -0700| 0.717337538 |http://localhost:3000/ | |55777940 |16173|89ab1d3fcc2d9dcdef4a50d79e9dcaff |
|
62
|
+
|2020-10-28 09:40:41 -0700|2020-10-28 09:40:41 -0700| 0.103701273 |http://localhost:3000/projects| |55777940 |16173|d2ddd9efc455f83cb24060e6593d6c6c |
|
63
|
+
|2020-10-28 09:41:44 -0700|2020-10-28 09:41:44 -0700| 0.051811471 |http://localhost:3000/projects|blah=funk |70368510966560|16173|eb2dacf2043e866a9e8925e53d471e6f |
|
64
|
+
|2020-10-28 09:44:02 -0700|2020-10-28 09:44:03 -0700| 0.831327261 |http://localhost:3000/projects|blah=funk;blah2=2funky|55777780 |17355|40895fa7af099cae3f48b27f149beb30 |
|
65
|
+
|
66
|
+
|
67
|
+
## Development
|
68
|
+
|
69
|
+
CI/CD is managed via [Travis CI](https://travis-ci.com/github/reedjosh/RackMiddlewareMetrics).
|
70
|
+
|
71
|
+
### Build and Test Manually
|
72
|
+
Build via:
|
73
|
+
|
74
|
+
`bundler install --path=vendor`
|
75
|
+
|
76
|
+
Run spec via:
|
77
|
+
|
78
|
+
`./bin/rspec`
|
79
|
+
|
80
|
+
### Build the Rust Extension
|
81
|
+
Install Rust if not present.
|
82
|
+
|
83
|
+
`curl https://sh.rustup.rs -sSf | sh -s -- -y`
|
84
|
+
|
85
|
+
`source $HOME/.cargo/env`
|
40
86
|
|
41
|
-
|
42
|
-
Almost Done: generate the MD5 hash in Rust using Helix
|
43
|
-
Flesh out further: Write unit tests in RSpec.
|
44
|
-
Done: Add Travis CI.
|
45
|
-
Partially: Write a README that explains what you built and how to use it.
|
87
|
+
Build extension.
|
46
88
|
|
47
|
-
|
48
|
-
- Write idiomatic and well-tested ruby code in a gem.
|
49
|
-
- Make sharable among many Ruby on Rails projects even with MD5 generation in rust.
|
50
|
-
- Use rvm/Travis to test many ruby versions.
|
89
|
+
`./bin/rake build`
|
51
90
|
|
52
|
-
###
|
53
|
-
|
91
|
+
### PRs and Testing
|
92
|
+
A pull request will trigger builds for each of the Ruby versions supported against Ubuntu Xenial.
|
54
93
|
|
94
|
+
### Release
|
95
|
+
Releases from Travis are triggered whenever a commit to the main branch is tagged. Spec tests must pass for release to occur.
|
data/lib/md5_gen.rb
CHANGED
@@ -1,25 +1,41 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
# lib/md5_gen.rb
|
4
|
-
#
|
5
|
-
# Provide md5 compute function that either uses native extention or Ruby digest lib.
|
6
4
|
require 'helix_runtime'
|
7
5
|
require('digest/md5')
|
8
6
|
|
7
|
+
begin
|
8
|
+
require('md5_ruby_ext/native')
|
9
|
+
EXT_LOADED = true
|
10
|
+
rescue LoadError
|
11
|
+
warn('Unable to load md5_ruby_ext/native. Falling back to Ruby digest/md5. ' \
|
12
|
+
'Please run `rake build` to build native extension.')
|
13
|
+
EXT_LOADED = false
|
14
|
+
end
|
15
|
+
|
16
|
+
# Provides md5 compute function that either uses native extention or Ruby digest lib.
|
9
17
|
module MD5Gen
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
18
|
+
# Define the underlying_compute_method based upon whether the rust extention is loaded.
|
19
|
+
class << self
|
20
|
+
if EXT_LOADED
|
21
|
+
define_method(:underlying_compute_method) do |body|
|
22
|
+
MRubyExt.compute(body)
|
23
|
+
# Can only work on UTF-8 strings atm. Helix limitation.
|
24
|
+
rescue TypeError
|
25
|
+
Digest::MD5.hexdigest(body)
|
26
|
+
end
|
27
|
+
else
|
28
|
+
define_method(:underlying_compute_method) do |body|
|
29
|
+
Digest::MD5.hexdigest(body)
|
30
|
+
end
|
23
31
|
end
|
24
32
|
end
|
33
|
+
|
34
|
+
# Convert body string to MD5 hash.
|
35
|
+
#
|
36
|
+
# @param body [String] the body to be hashed.
|
37
|
+
# @return [String] the hash of the body.
|
38
|
+
def self.compute body
|
39
|
+
underlying_compute_method(body)
|
40
|
+
end
|
25
41
|
end
|
@@ -6,6 +6,6 @@ require 'rack_middleware_metrics/reporter'
|
|
6
6
|
|
7
7
|
require 'rack_middleware_metrics/railtie' if defined?(Rails)
|
8
8
|
|
9
|
+
# A minimalist Application Performance Monitoring (APM) library for Ruby on Rails.
|
9
10
|
module RackMiddlewareMetrics
|
10
|
-
class Error < StandardError; end
|
11
11
|
end
|
@@ -2,7 +2,7 @@
|
|
2
2
|
|
3
3
|
# lib/rack_middleware_metrics/railtie.rb
|
4
4
|
module RackMiddlewareMetrics
|
5
|
-
# Rails
|
5
|
+
# Rails railtie plugin. Adds configuration, startup, and md5 ext build task.
|
6
6
|
class Railtie < Rails::Railtie
|
7
7
|
config.rack_middleware_metrics = ActiveSupport::OrderedOptions.new
|
8
8
|
initializer 'rack_middleware_metrics.configure_rails_initialization' do |app|
|
@@ -10,5 +10,8 @@ module RackMiddlewareMetrics
|
|
10
10
|
config.rack_middleware_metrics.fetch(:logpath, Rails.root / 'rack_metrics.csv')
|
11
11
|
app.middleware.use(Reporter, config.rack_middleware_metrics)
|
12
12
|
end
|
13
|
+
rake_tasks do
|
14
|
+
load(Pathname(__FILE__).parent.parent / 'tasks/helix_runtime.rake')
|
15
|
+
end
|
13
16
|
end
|
14
17
|
end
|
@@ -6,11 +6,19 @@
|
|
6
6
|
require 'time'
|
7
7
|
require 'rack'
|
8
8
|
require 'md5_gen'
|
9
|
+
require 'uri'
|
10
|
+
require 'csv'
|
9
11
|
|
10
|
-
# The main Gem...
|
11
12
|
module RackMiddlewareMetrics
|
12
13
|
# The metrics reporter middleware.
|
13
14
|
class Reporter
|
15
|
+
# Initialize the reporter middleware.
|
16
|
+
#
|
17
|
+
# @param app [rack::RackApp] the app to add metrics reporting to.
|
18
|
+
# @param *args [Array<any>, nil] arguments to pass through to the app.
|
19
|
+
# A hash passed as the final argument will be used as config options--of which :logpath
|
20
|
+
# can be used to specify the metrics reporter logpath.
|
21
|
+
# @returns [Reporter] a new instance of Reporter.
|
14
22
|
def initialize app, *args
|
15
23
|
@app = app
|
16
24
|
|
@@ -19,28 +27,59 @@ module RackMiddlewareMetrics
|
|
19
27
|
@logpath = Pathname.new(options.fetch(:logpath, 'rack_metrics.csv'))
|
20
28
|
end
|
21
29
|
|
30
|
+
# Converts data from rack env object to uri.
|
31
|
+
#
|
32
|
+
# @param env [rack::ENV] the request env.
|
33
|
+
# @return [String] the uri.
|
22
34
|
def uri_from env
|
23
35
|
"#{ env['rack.url_scheme'] }://#{ env['SERVER_NAME'] }"\
|
24
36
|
":#{ env['SERVER_PORT'] }#{ env['PATH_INFO'] }"
|
25
37
|
end
|
26
38
|
|
39
|
+
# Converts data from rack env object to semicolon delimited parameters.
|
40
|
+
# Original semicolons escaped with %3B the ASCII equivalent.
|
41
|
+
# See https://www.december.com/html/spec/esccodes.html for more details.
|
42
|
+
#
|
43
|
+
# @param env [rack::ENV] the request env.
|
44
|
+
# @return [String] semicolon delimited parameters..
|
45
|
+
def params_from env
|
46
|
+
params = Hash[URI.decode_www_form(env['QUERY_STRING'])]
|
47
|
+
params = params.map { |key, val| "#{ key }=#{ val }" }
|
48
|
+
params.map { |param| param.gsub(';', '%3B') }.join(';')
|
49
|
+
end
|
50
|
+
|
51
|
+
# Run the request--call next step in middleware/server chain with added timing.
|
52
|
+
#
|
53
|
+
# @param env [rack::ENV] the request env.
|
54
|
+
# @return [Array<Array<Objects>>] the response objects: [status, headers, body] plus
|
55
|
+
# added timing such that the final form is:
|
56
|
+
# [[status, headers, body], [start_time, end_time, duration]]
|
27
57
|
def timed_call env
|
28
58
|
start_time = Time.now
|
29
59
|
response = @app.call(env)
|
30
60
|
end_time = Time.now
|
31
|
-
duration =
|
61
|
+
duration = end_time - start_time
|
32
62
|
[*response, [start_time, end_time, duration]]
|
33
63
|
end
|
34
64
|
|
65
|
+
# Run the request--call next step in middleware/server chain with added timing.
|
66
|
+
#
|
67
|
+
# @param data [Array<objects>] metrics data to append to logfile.
|
68
|
+
# @return [void]
|
35
69
|
def append_data data
|
36
|
-
|
37
|
-
|
70
|
+
CSV.open(@logpath, 'a') do |csv|
|
71
|
+
csv << data
|
72
|
+
end
|
38
73
|
end
|
39
74
|
|
75
|
+
# Main middleware entry and exit point. Logs metrics as specified.
|
76
|
+
#
|
77
|
+
# @param env [rack::ENV] the request env.
|
78
|
+
# @return [Array<objects>] of the form: [status, headers, body]
|
40
79
|
def call env
|
41
80
|
status, headers, body, timing = timed_call(env)
|
42
81
|
|
43
|
-
query_params = env
|
82
|
+
query_params = params_from(env)
|
44
83
|
uri = uri_from(env)
|
45
84
|
thread_id = Thread.current.object_id
|
46
85
|
process_id = Process.pid
|
@@ -1,6 +1,10 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
# lib/tasks/helix_runtime.rake
|
2
4
|
require 'helix_runtime/build_task'
|
3
5
|
|
4
|
-
|
6
|
+
Dir.chdir(Pathname(__FILE__).parent) do
|
7
|
+
HelixRuntime::BuildTask.new
|
5
8
|
|
6
|
-
task default: :build
|
9
|
+
task default: :build
|
10
|
+
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: rack_middleware_metrics
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.7
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- reedjosh
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2020-
|
11
|
+
date: 2020-11-02 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: helix_runtime
|
@@ -66,7 +66,6 @@ files:
|
|
66
66
|
- ".rubocop.yml"
|
67
67
|
- ".solargraph.yml"
|
68
68
|
- ".travis.yml"
|
69
|
-
- ".~lock.GIST_API.odt#"
|
70
69
|
- Cargo.lock
|
71
70
|
- Cargo.toml
|
72
71
|
- Gemfile
|
@@ -99,7 +98,6 @@ files:
|
|
99
98
|
- example/.keep
|
100
99
|
- example/thin_rack_app.rb
|
101
100
|
- lib/md5_gen.rb
|
102
|
-
- lib/md5_ruby_ext.rb
|
103
101
|
- lib/rack_middleware_metrics.rb
|
104
102
|
- lib/rack_middleware_metrics/railtie.rb
|
105
103
|
- lib/rack_middleware_metrics/reporter.rb
|
@@ -129,7 +127,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
129
127
|
- !ruby/object:Gem::Version
|
130
128
|
version: '0'
|
131
129
|
requirements: []
|
132
|
-
rubygems_version: 3.0.
|
130
|
+
rubygems_version: 3.0.8
|
133
131
|
signing_key:
|
134
132
|
specification_version: 4
|
135
133
|
summary: A rack based middleware that does fun/silly metrics reporting.
|
data/.~lock.GIST_API.odt#
DELETED
@@ -1 +0,0 @@
|
|
1
|
-
,jreed,jayr.localdomain,14.07.2017 13:50,file:///home/jreed/.config/libreoffice/4;
|
data/lib/md5_ruby_ext.rb
DELETED