rack_middleware_metrics 0.0.1 → 0.0.7
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 +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
|
+
[](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
|
-
[](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