dial 0.2.2 → 0.2.4
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/CHANGELOG.md +9 -0
- data/README.md +21 -0
- data/lib/dial/configuration.rb +37 -0
- data/lib/dial/constants.rb +3 -1
- data/lib/dial/middleware/panel.rb +14 -3
- data/lib/dial/middleware/ruby_stat.rb +1 -1
- data/lib/dial/middleware.rb +10 -6
- data/lib/dial/railtie.rb +15 -8
- data/lib/dial/version.rb +1 -1
- data/lib/dial.rb +2 -0
- metadata +3 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: c21506e3c567f79104e394c2ab2fc1c29d433ef9e9e27f201d8fe3e6bdc2227f
|
4
|
+
data.tar.gz: 5a8a65aa3fcdd52d59508ebac6bb12bfa156d6f577793f7c05ac8eb14d5409b3
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: c20d37444e2d186490ea5e75d30c2a6940d56adbff21c91d01a448d96b4b7b6baa0ead5da5305a1398dcd8e916f5a9dab60c2d0d101404a1377a998fe2d2d91c
|
7
|
+
data.tar.gz: 525eef47d8136c0c34ddc0c8460637370e87ea13d43c8d83e1c3b4c9dc992b192414f570a0258a9ffd16206a235611a5450982c3a9cf474f12552c16ef646613
|
data/CHANGELOG.md
CHANGED
@@ -1,5 +1,14 @@
|
|
1
1
|
## [Unreleased]
|
2
2
|
|
3
|
+
## [0.2.4] - 2025-03-03
|
4
|
+
|
5
|
+
- Add configuration option for setting script CSP nonce (thanks @matthaigh27)
|
6
|
+
|
7
|
+
## [0.2.3] - 2025-02-28
|
8
|
+
|
9
|
+
- Add configuration API
|
10
|
+
- Make default prosopite ignore queries case insensitive
|
11
|
+
|
3
12
|
## [0.2.2] - 2025-02-27
|
4
13
|
|
5
14
|
- Increase default vernier allocation interval from 200 to 20k
|
data/README.md
CHANGED
@@ -33,6 +33,27 @@ bundle install
|
|
33
33
|
mount Dial::Engine, at: "/" if Rails.env.development?
|
34
34
|
```
|
35
35
|
|
36
|
+
4. (Optional) Configure the gem in an initializer:
|
37
|
+
|
38
|
+
```ruby
|
39
|
+
# config/initializers/dial.rb
|
40
|
+
|
41
|
+
Dial.configure do |config|
|
42
|
+
config.vernier_interval = 100
|
43
|
+
config.vernier_allocation_interval = 10_000
|
44
|
+
config.prosopite_ignore_queries += [/pg_sleep/i]
|
45
|
+
end
|
46
|
+
```
|
47
|
+
|
48
|
+
### Options
|
49
|
+
|
50
|
+
Option | Description | Default
|
51
|
+
- | - | -
|
52
|
+
`vernier_interval` | Sets the `interval` option for vernier. | `200`
|
53
|
+
`vernier_allocation_interval` | Sets the `allocation_interval` option for vernier. | `20_000`
|
54
|
+
`prosopite_ignore_queries` | Sets the `ignore_queries` option for prosopite. | `[/schema_migrations/i]`
|
55
|
+
`content_security_policy_nonce` | Sets the content security policy nonce to use when inserting Dial's script. Can be a string, or a Proc which receives `env` and response `headers` as arguments and returns the nonce. | Rails generated nonce or `nil`
|
56
|
+
|
36
57
|
## Development
|
37
58
|
|
38
59
|
After checking out the repo, run `bin/setup` to install dependencies. Then, run `bundle exec rake test` to run the
|
@@ -0,0 +1,37 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Dial
|
4
|
+
def self.configure
|
5
|
+
yield _configuration
|
6
|
+
end
|
7
|
+
|
8
|
+
def self._configuration
|
9
|
+
@_configuration ||= Configuration.new
|
10
|
+
end
|
11
|
+
|
12
|
+
class Configuration
|
13
|
+
def initialize
|
14
|
+
@options = {
|
15
|
+
vernier_interval: VERNIER_INTERVAL,
|
16
|
+
vernier_allocation_interval: VERNIER_ALLOCATION_INTERVAL,
|
17
|
+
prosopite_ignore_queries: PROSOPITE_IGNORE_QUERIES,
|
18
|
+
content_security_policy_nonce: -> (env, _headers) { env[NONCE] || "" },
|
19
|
+
}
|
20
|
+
|
21
|
+
@options.keys.each do |key|
|
22
|
+
define_singleton_method key do
|
23
|
+
@options[key]
|
24
|
+
end
|
25
|
+
|
26
|
+
define_singleton_method "#{key}=" do |value|
|
27
|
+
@options[key] = value
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
def freeze
|
33
|
+
@options.freeze
|
34
|
+
super
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
data/lib/dial/constants.rb
CHANGED
@@ -1,6 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
require "rack"
|
4
|
+
require "action_dispatch"
|
4
5
|
|
5
6
|
require_relative "version"
|
6
7
|
|
@@ -10,6 +11,7 @@ module Dial
|
|
10
11
|
HTTP_ACCEPT = "HTTP_ACCEPT"
|
11
12
|
CONTENT_TYPE = ::Rack::CONTENT_TYPE
|
12
13
|
CONTENT_LENGTH = ::Rack::CONTENT_LENGTH
|
14
|
+
NONCE = ::ActionDispatch::ContentSecurityPolicy::Request::NONCE
|
13
15
|
REQUEST_TIMING = "dial_request_timing"
|
14
16
|
|
15
17
|
FILE_STALE_SECONDS = 60 * 60
|
@@ -18,7 +20,7 @@ module Dial
|
|
18
20
|
VERNIER_ALLOCATION_INTERVAL = 20_000
|
19
21
|
VERNIER_PROFILE_OUT_RELATIVE_DIRNAME = "tmp/dial/profiles"
|
20
22
|
|
21
|
-
PROSOPITE_IGNORE_QUERIES = [/schema_migrations/].freeze
|
23
|
+
PROSOPITE_IGNORE_QUERIES = [/schema_migrations/i].freeze
|
22
24
|
PROSOPITE_LOG_RELATIVE_DIRNAME = "log/dial"
|
23
25
|
PROSOPITE_LOG_FILENAME = "#{Util.uuid}_prosopite_#{PROGRAM_ID}.log".freeze
|
24
26
|
end
|
@@ -5,7 +5,7 @@ require "uri"
|
|
5
5
|
module Dial
|
6
6
|
class Panel
|
7
7
|
class << self
|
8
|
-
def html env, profile_out_filename, query_logs, ruby_vm_stat, gc_stat, gc_stat_heap, server_timing
|
8
|
+
def html env, headers, profile_out_filename, query_logs, ruby_vm_stat, gc_stat, gc_stat_heap, server_timing
|
9
9
|
<<~HTML
|
10
10
|
<style>#{style}</style>
|
11
11
|
|
@@ -69,7 +69,9 @@ module Dial
|
|
69
69
|
</div>
|
70
70
|
</div>
|
71
71
|
|
72
|
-
<script
|
72
|
+
<script nonce="#{configured_nonce env, headers}">
|
73
|
+
#{script}
|
74
|
+
</script>
|
73
75
|
HTML
|
74
76
|
end
|
75
77
|
|
@@ -171,7 +173,7 @@ module Dial
|
|
171
173
|
end
|
172
174
|
|
173
175
|
def formatted_rails_route_info env
|
174
|
-
|
176
|
+
begin
|
175
177
|
::Rails.application.routes.recognize_path env[::Rack::PATH_INFO], method: env[::Rack::REQUEST_METHOD]
|
176
178
|
rescue ::ActionController::RoutingError
|
177
179
|
{}
|
@@ -253,6 +255,15 @@ module Dial
|
|
253
255
|
HTML
|
254
256
|
end.join
|
255
257
|
end
|
258
|
+
|
259
|
+
def configured_nonce env, headers
|
260
|
+
config_nonce = Dial._configuration.content_security_policy_nonce
|
261
|
+
if config_nonce.instance_of? Proc
|
262
|
+
config_nonce.call env, headers
|
263
|
+
else
|
264
|
+
config_nonce
|
265
|
+
end
|
266
|
+
end
|
256
267
|
end
|
257
268
|
end
|
258
269
|
end
|
data/lib/dial/middleware.rb
CHANGED
@@ -28,7 +28,9 @@ module Dial
|
|
28
28
|
|
29
29
|
status, headers, rack_body, ruby_vm_stat, gc_stat, gc_stat_heap, vernier_result = nil
|
30
30
|
::Prosopite.scan do
|
31
|
-
vernier_result = ::Vernier.profile interval:
|
31
|
+
vernier_result = ::Vernier.profile interval: Dial._configuration.vernier_interval, \
|
32
|
+
allocation_interval: Dial._configuration.vernier_allocation_interval, \
|
33
|
+
hooks: [:memory_usage, :rails] do
|
32
34
|
ruby_vm_stat, gc_stat, gc_stat_heap = with_diffed_ruby_stats do
|
33
35
|
status, headers, rack_body = @app.call env
|
34
36
|
end
|
@@ -49,10 +51,12 @@ module Dial
|
|
49
51
|
body = String.new.tap do |str|
|
50
52
|
rack_body.each { |chunk| str << chunk }
|
51
53
|
rack_body.close if rack_body.respond_to? :close
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
54
|
+
|
55
|
+
str.sub! "</body>", <<~HTML
|
56
|
+
#{Panel.html env, headers, profile_out_filename, query_logs, ruby_vm_stat, gc_stat, gc_stat_heap, server_timing}
|
57
|
+
</body>
|
58
|
+
HTML
|
59
|
+
end
|
56
60
|
|
57
61
|
headers[CONTENT_LENGTH] = body.bytesize.to_s
|
58
62
|
|
@@ -84,7 +88,7 @@ module Dial
|
|
84
88
|
|
85
89
|
def clear_query_logs!
|
86
90
|
[].tap do |query_logs|
|
87
|
-
File.open
|
91
|
+
File.open "#{query_log_dir_pathname}/#{PROSOPITE_LOG_FILENAME}", "r+" do |file|
|
88
92
|
entry = section = count = nil
|
89
93
|
file.each_line do |line|
|
90
94
|
entry, section, count = process_query_log_line line, entry, section, count
|
data/lib/dial/railtie.rb
CHANGED
@@ -1,6 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
require "rails"
|
4
|
+
require "active_record"
|
4
5
|
require "prosopite"
|
5
6
|
|
6
7
|
require_relative "middleware"
|
@@ -8,25 +9,25 @@ require_relative "prosopite_logger"
|
|
8
9
|
|
9
10
|
module Dial
|
10
11
|
class Railtie < ::Rails::Railtie
|
11
|
-
initializer "dial.use_middleware" do |app|
|
12
|
+
initializer "dial.use_middleware", after: :load_config_initializers do |app|
|
12
13
|
app.middleware.insert_before 0, Middleware
|
13
14
|
end
|
14
15
|
|
15
|
-
initializer "dial.set_up_vernier" do |app|
|
16
|
+
initializer "dial.set_up_vernier", after: :load_config_initializers do |app|
|
16
17
|
app.config.after_initialize do
|
17
18
|
FileUtils.mkdir_p ::Rails.root.join VERNIER_PROFILE_OUT_RELATIVE_DIRNAME
|
18
19
|
end
|
19
20
|
end
|
20
21
|
|
21
|
-
initializer "dial.clean_up_vernier_profile_out_files" do |app|
|
22
|
+
initializer "dial.clean_up_vernier_profile_out_files", after: :load_config_initializers do |app|
|
22
23
|
stale_files("#{profile_out_dir_pathname}/*.json.gz").each do |profile_out_file|
|
23
24
|
File.delete profile_out_file rescue nil
|
24
25
|
end
|
25
26
|
end
|
26
27
|
|
27
|
-
initializer "dial.set_up_prosopite" do |app|
|
28
|
+
initializer "dial.set_up_prosopite", after: :load_config_initializers do |app|
|
28
29
|
app.config.after_initialize do
|
29
|
-
if ::ActiveRecord::Base.
|
30
|
+
if ::ActiveRecord::Base.configurations.configurations.any? { |config| config.adapter == "postgresql" }
|
30
31
|
require "pg_query"
|
31
32
|
end
|
32
33
|
|
@@ -34,17 +35,23 @@ module Dial
|
|
34
35
|
FileUtils.mkdir_p File.dirname prosopite_log_pathname
|
35
36
|
FileUtils.touch prosopite_log_pathname
|
36
37
|
::Prosopite.custom_logger = ProsopiteLogger.new prosopite_log_pathname
|
37
|
-
|
38
|
-
::Prosopite.ignore_queries = PROSOPITE_IGNORE_QUERIES
|
39
38
|
end
|
40
39
|
end
|
41
40
|
|
42
|
-
initializer "dial.clean_up_prosopite_log_files" do |app|
|
41
|
+
initializer "dial.clean_up_prosopite_log_files", after: :load_config_initializers do |app|
|
43
42
|
stale_files("#{query_log_dir_pathname}/*.log").each do |query_log_file|
|
44
43
|
File.delete query_log_file rescue nil
|
45
44
|
end
|
46
45
|
end
|
47
46
|
|
47
|
+
initializer "dial.setup", after: :load_config_initializers do |app|
|
48
|
+
app.config.after_initialize do
|
49
|
+
Dial._configuration.freeze
|
50
|
+
|
51
|
+
::Prosopite.ignore_queries = Dial._configuration.prosopite_ignore_queries
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
48
55
|
private
|
49
56
|
|
50
57
|
def stale_files glob_pattern
|
data/lib/dial/version.rb
CHANGED
data/lib/dial.rb
CHANGED
metadata
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: dial
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.2.
|
4
|
+
version: 0.2.4
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Joshua Young
|
8
8
|
bindir: bin
|
9
9
|
cert_chain: []
|
10
|
-
date: 2025-
|
10
|
+
date: 2025-03-03 00:00:00.000000000 Z
|
11
11
|
dependencies:
|
12
12
|
- !ruby/object:Gem::Dependency
|
13
13
|
name: railties
|
@@ -123,6 +123,7 @@ files:
|
|
123
123
|
- README.md
|
124
124
|
- dial.gemspec
|
125
125
|
- lib/dial.rb
|
126
|
+
- lib/dial/configuration.rb
|
126
127
|
- lib/dial/constants.rb
|
127
128
|
- lib/dial/engine.rb
|
128
129
|
- lib/dial/engine/routes.rb
|