app_profiler 0.2.0 → 0.2.2
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/lib/app_profiler/backend/base_backend.rb +4 -4
- data/lib/app_profiler/backend/stackprof_backend.rb +6 -4
- data/lib/app_profiler/backend/vernier_backend.rb +6 -4
- data/lib/app_profiler/middleware/upload_action.rb +1 -1
- data/lib/app_profiler/middleware.rb +14 -5
- data/lib/app_profiler/parameters.rb +2 -1
- data/lib/app_profiler/profile.rb +18 -12
- data/lib/app_profiler/railtie.rb +4 -0
- data/lib/app_profiler/request_parameters.rb +4 -0
- data/lib/app_profiler/sampler/config.rb +39 -0
- data/lib/app_profiler/sampler/stackprof_config.rb +52 -0
- data/lib/app_profiler/sampler/vernier_config.rb +44 -0
- data/lib/app_profiler/sampler.rb +60 -0
- data/lib/app_profiler/server.rb +2 -2
- data/lib/app_profiler/storage/base_storage.rb +7 -5
- data/lib/app_profiler/storage/google_cloud_storage.rb +5 -0
- data/lib/app_profiler/version.rb +1 -1
- data/lib/app_profiler/viewer/speedscope_remote_viewer/base_middleware.rb +47 -7
- data/lib/app_profiler/viewer/speedscope_remote_viewer/middleware.rb +2 -2
- data/lib/app_profiler/yarn/command.rb +1 -1
- data/lib/app_profiler.rb +5 -1
- metadata +11 -7
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 15a1a7b3bd1e60dc10753ce4b8e4f2907461b09417aecde43fce3d4565d5f211
|
4
|
+
data.tar.gz: 811e16e5383f85f4e2aef6aaf50e832b8cf5714c2cacd730ce4f184c9d1f26c4
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 6b6cd68d552a8ac41eebef2cec56ac8e1917c1e321c759297649a62d6c03a3ce7c6ffa06bee820320f62ac4abdde8b8fa26f539508841ea9440d7231160534a8
|
7
|
+
data.tar.gz: c320d9e84ceca4834b7c5400dd46cef4ce3f04a7e49530b4381461f1ccb91b91da9cdc2e6eff86202b218efc1ef96754a5f8b40e7bbe433d73f2b3486ea86522
|
@@ -3,10 +3,6 @@
|
|
3
3
|
module AppProfiler
|
4
4
|
module Backend
|
5
5
|
class BaseBackend
|
6
|
-
def self.name
|
7
|
-
raise NotImplementedError
|
8
|
-
end
|
9
|
-
|
10
6
|
def run(params = {}, &block)
|
11
7
|
raise NotImplementedError
|
12
8
|
end
|
@@ -31,6 +27,10 @@ module AppProfiler
|
|
31
27
|
def run_lock
|
32
28
|
@run_lock ||= Mutex.new
|
33
29
|
end
|
30
|
+
|
31
|
+
def name
|
32
|
+
raise NotImplementedError
|
33
|
+
end
|
34
34
|
end
|
35
35
|
|
36
36
|
protected
|
@@ -16,8 +16,10 @@ module AppProfiler
|
|
16
16
|
:object,
|
17
17
|
].freeze
|
18
18
|
|
19
|
-
|
20
|
-
|
19
|
+
class << self
|
20
|
+
def name
|
21
|
+
:stackprof
|
22
|
+
end
|
21
23
|
end
|
22
24
|
|
23
25
|
def run(params = {})
|
@@ -44,7 +46,7 @@ module AppProfiler
|
|
44
46
|
StackProf.start(**DEFAULTS, **params)
|
45
47
|
rescue => error
|
46
48
|
AppProfiler.logger.info(
|
47
|
-
"[Profiler] failed to start the profiler error_class=#{error.class} error_message=#{error.message}"
|
49
|
+
"[Profiler] failed to start the profiler error_class=#{error.class} error_message=#{error.message}",
|
48
50
|
)
|
49
51
|
release_run_lock
|
50
52
|
# This is a boolean instead of nil because StackProf#start returns a
|
@@ -66,7 +68,7 @@ module AppProfiler
|
|
66
68
|
BaseProfile.from_stackprof(stackprof_profile)
|
67
69
|
rescue => error
|
68
70
|
AppProfiler.logger.info(
|
69
|
-
"[Profiler] failed to obtain the profile error_class=#{error.class} error_message=#{error.message}"
|
71
|
+
"[Profiler] failed to obtain the profile error_class=#{error.class} error_message=#{error.message}",
|
70
72
|
)
|
71
73
|
nil
|
72
74
|
end
|
@@ -15,8 +15,10 @@ module AppProfiler
|
|
15
15
|
:retained,
|
16
16
|
].freeze
|
17
17
|
|
18
|
-
|
19
|
-
|
18
|
+
class << self
|
19
|
+
def name
|
20
|
+
:vernier
|
21
|
+
end
|
20
22
|
end
|
21
23
|
|
22
24
|
def run(params = {})
|
@@ -48,7 +50,7 @@ module AppProfiler
|
|
48
50
|
@collector.start
|
49
51
|
rescue => error
|
50
52
|
AppProfiler.logger.info(
|
51
|
-
"[Profiler] failed to start the profiler error_class=#{error.class} error_message=#{error.message}"
|
53
|
+
"[Profiler] failed to start the profiler error_class=#{error.class} error_message=#{error.message}",
|
52
54
|
)
|
53
55
|
release_run_lock
|
54
56
|
# This is a boolean instead of nil to be consistent with the stackprof backend behaviour
|
@@ -83,7 +85,7 @@ module AppProfiler
|
|
83
85
|
BaseProfile.from_vernier(data)
|
84
86
|
rescue => error
|
85
87
|
AppProfiler.logger.info(
|
86
|
-
"[Profiler] failed to obtain the profile error_class=#{error.class} error_message=#{error.message}"
|
88
|
+
"[Profiler] failed to obtain the profile error_class=#{error.class} error_message=#{error.message}",
|
87
89
|
)
|
88
90
|
nil
|
89
91
|
end
|
@@ -14,7 +14,7 @@ module AppProfiler
|
|
14
14
|
append_headers(
|
15
15
|
response,
|
16
16
|
upload: profile_upload,
|
17
|
-
autoredirect: autoredirect.nil? ? AppProfiler.autoredirect : autoredirect
|
17
|
+
autoredirect: autoredirect.nil? ? AppProfiler.autoredirect : autoredirect,
|
18
18
|
) if response
|
19
19
|
end
|
20
20
|
end
|
@@ -4,6 +4,7 @@ require "rack"
|
|
4
4
|
require "app_profiler/middleware/base_action"
|
5
5
|
require "app_profiler/middleware/upload_action"
|
6
6
|
require "app_profiler/middleware/view_action"
|
7
|
+
require "app_profiler/sampler/config"
|
7
8
|
|
8
9
|
module AppProfiler
|
9
10
|
class Middleware
|
@@ -24,11 +25,11 @@ module AppProfiler
|
|
24
25
|
|
25
26
|
def profile(env, params)
|
26
27
|
response = nil
|
28
|
+
app_profiler_params = profile_params(params)
|
27
29
|
|
28
|
-
return yield unless
|
29
|
-
|
30
|
-
params_hash = params.to_h
|
30
|
+
return yield unless app_profiler_params
|
31
31
|
|
32
|
+
params_hash = app_profiler_params.to_h
|
32
33
|
return yield unless before_profile(env, params_hash)
|
33
34
|
|
34
35
|
profile = AppProfiler.run(**params_hash) do
|
@@ -40,13 +41,21 @@ module AppProfiler
|
|
40
41
|
action.call(
|
41
42
|
profile,
|
42
43
|
response: response,
|
43
|
-
autoredirect:
|
44
|
-
async:
|
44
|
+
autoredirect: app_profiler_params.autoredirect,
|
45
|
+
async: app_profiler_params.async,
|
45
46
|
)
|
46
47
|
|
47
48
|
response
|
48
49
|
end
|
49
50
|
|
51
|
+
def profile_params(params)
|
52
|
+
return params if params.valid?
|
53
|
+
|
54
|
+
return unless AppProfiler.profile_sampler_enabled
|
55
|
+
|
56
|
+
AppProfiler::Sampler.profile_params(params, AppProfiler.profile_sampler_config)
|
57
|
+
end
|
58
|
+
|
50
59
|
def before_profile(_env, _params)
|
51
60
|
true
|
52
61
|
end
|
@@ -7,7 +7,7 @@ module AppProfiler
|
|
7
7
|
DEFAULT_INTERVALS = { "cpu" => 1000, "wall" => 1000, "object" => 2000, "retained" => 0 }.freeze
|
8
8
|
MIN_INTERVALS = { "cpu" => 200, "wall" => 200, "object" => 400, "retained" => 0 }.freeze
|
9
9
|
|
10
|
-
attr_reader :autoredirect, :async, :backend
|
10
|
+
attr_reader :mode, :autoredirect, :async, :backend
|
11
11
|
|
12
12
|
def initialize(mode: :wall, interval: nil, ignore_gc: false, autoredirect: false,
|
13
13
|
async: false, backend: nil, metadata: {})
|
@@ -31,6 +31,7 @@ module AppProfiler
|
|
31
31
|
ignore_gc: @ignore_gc,
|
32
32
|
metadata: @metadata,
|
33
33
|
backend: @backend,
|
34
|
+
async: @async,
|
34
35
|
}
|
35
36
|
end
|
36
37
|
end
|
data/lib/app_profiler/profile.rb
CHANGED
@@ -15,20 +15,22 @@ module AppProfiler
|
|
15
15
|
|
16
16
|
delegate :[], to: :@data
|
17
17
|
|
18
|
-
|
19
|
-
|
20
|
-
|
18
|
+
class << self
|
19
|
+
# This function should not be called if `StackProf.results` returns nil.
|
20
|
+
def from_stackprof(data)
|
21
|
+
options = INTERNAL_METADATA_KEYS.map { |key| [key, data[:metadata]&.delete(key)] }.to_h
|
21
22
|
|
22
|
-
|
23
|
-
|
23
|
+
StackprofProfile.new(data, **options).tap do |profile|
|
24
|
+
raise ArgumentError, "invalid profile data" unless profile.valid?
|
25
|
+
end
|
24
26
|
end
|
25
|
-
end
|
26
27
|
|
27
|
-
|
28
|
-
|
28
|
+
def from_vernier(data)
|
29
|
+
options = INTERNAL_METADATA_KEYS.map { |key| [key, data[:meta]&.delete(key)] }.to_h
|
29
30
|
|
30
|
-
|
31
|
-
|
31
|
+
VernierProfile.new(data, **options).tap do |profile|
|
32
|
+
raise ArgumentError, "invalid profile data" unless profile.valid?
|
33
|
+
end
|
32
34
|
end
|
33
35
|
end
|
34
36
|
|
@@ -44,7 +46,7 @@ module AppProfiler
|
|
44
46
|
AppProfiler.storage.upload(self).tap do |upload|
|
45
47
|
if upload && defined?(upload.url)
|
46
48
|
AppProfiler.logger.info(
|
47
|
-
<<~INFO.squish
|
49
|
+
<<~INFO.squish,
|
48
50
|
[Profiler] data uploaded:
|
49
51
|
profile_url=#{upload.url}
|
50
52
|
profile_viewer_url=#{AppProfiler.profile_url(upload)}
|
@@ -54,7 +56,7 @@ module AppProfiler
|
|
54
56
|
end
|
55
57
|
rescue => error
|
56
58
|
AppProfiler.logger.info(
|
57
|
-
"[Profiler] failed to upload profile error_class=#{error.class} error_message=#{error.message}"
|
59
|
+
"[Profiler] failed to upload profile error_class=#{error.class} error_message=#{error.message}",
|
58
60
|
)
|
59
61
|
nil
|
60
62
|
end
|
@@ -78,6 +80,10 @@ module AppProfiler
|
|
78
80
|
@data
|
79
81
|
end
|
80
82
|
|
83
|
+
def metadata
|
84
|
+
@data[:metadata]
|
85
|
+
end
|
86
|
+
|
81
87
|
def mode
|
82
88
|
raise NotImplementedError
|
83
89
|
end
|
data/lib/app_profiler/railtie.rb
CHANGED
@@ -41,6 +41,10 @@ module AppProfiler
|
|
41
41
|
AppProfiler.profile_enqueue_failure = app.config.app_profiler.profile_enqueue_failure
|
42
42
|
AppProfiler.after_process_queue = app.config.app_profiler.after_process_queue
|
43
43
|
AppProfiler.backend = app.config.app_profiler.profiler_backend || :stackprof
|
44
|
+
AppProfiler.forward_metadata_on_upload = app.config.app_profiler.forward_metadata_on_upload || false
|
45
|
+
AppProfiler.profile_sampler_enabled = app.config.app_profiler.profile_sampler_enabled || false
|
46
|
+
AppProfiler.profile_sampler_config = app.config.app_profiler.profile_sampler_config ||
|
47
|
+
AppProfiler::Sampler::Config.new
|
44
48
|
end
|
45
49
|
|
46
50
|
initializer "app_profiler.add_middleware" do |app|
|
@@ -0,0 +1,39 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "app_profiler/sampler/stackprof_config"
|
4
|
+
require "app_profiler/sampler/vernier_config"
|
5
|
+
module AppProfiler
|
6
|
+
module Sampler
|
7
|
+
class Config
|
8
|
+
attr_reader :sample_rate, :paths, :cpu_interval, :backends_probability
|
9
|
+
|
10
|
+
SAMPLE_RATE = 0.001 # 0.1%
|
11
|
+
PATHS = ["/"]
|
12
|
+
BACKEND_PROBABILITES = { stackprof: 1.0, vernier: 0.0 }
|
13
|
+
@backends = {}
|
14
|
+
|
15
|
+
def initialize(sample_rate: SAMPLE_RATE,
|
16
|
+
paths: PATHS,
|
17
|
+
backends_probability: BACKEND_PROBABILITES,
|
18
|
+
backends_config: {
|
19
|
+
stackprof: StackprofConfig.new,
|
20
|
+
})
|
21
|
+
|
22
|
+
if sample_rate < 0.0 || sample_rate > 1.0
|
23
|
+
raise ArgumentError, "sample_rate must be between 0 and 1"
|
24
|
+
end
|
25
|
+
|
26
|
+
raise ArgumentError, "mode probabilities must sum to 1" unless backends_probability.values.sum == 1.0
|
27
|
+
|
28
|
+
@sample_rate = sample_rate
|
29
|
+
@paths = paths
|
30
|
+
@backends_config = backends_config
|
31
|
+
@backends_probability = backends_probability
|
32
|
+
end
|
33
|
+
|
34
|
+
def get_backend_config(backend_name)
|
35
|
+
@backends_config[backend_name]
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
@@ -0,0 +1,52 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module AppProfiler
|
4
|
+
module Sampler
|
5
|
+
class StackprofConfig
|
6
|
+
attr_reader :modes_probability
|
7
|
+
|
8
|
+
# Default values
|
9
|
+
WALL_INTERVAL = 5000
|
10
|
+
CPU_INTERVAL = 5000
|
11
|
+
OBJECT_INTERVAL = 1000
|
12
|
+
|
13
|
+
WALL_MODE_PROBABILITY = 0.8
|
14
|
+
CPU_MODE_PROBABILITY = 0.1
|
15
|
+
OBJECT_MODE_PROBABILITY = 0.1
|
16
|
+
|
17
|
+
def initialize(
|
18
|
+
wall_interval: WALL_INTERVAL,
|
19
|
+
cpu_interval: CPU_INTERVAL,
|
20
|
+
object_interval: OBJECT_INTERVAL,
|
21
|
+
wall_mode_probability: WALL_MODE_PROBABILITY,
|
22
|
+
cpu_mode_probability: CPU_MODE_PROBABILITY,
|
23
|
+
object_mode_probability: OBJECT_MODE_PROBABILITY
|
24
|
+
)
|
25
|
+
if wall_mode_probability + cpu_mode_probability + object_mode_probability != 1.0
|
26
|
+
raise ArgumentError, "mode probabilities must sum to 1"
|
27
|
+
end
|
28
|
+
|
29
|
+
@modes_probability = {}
|
30
|
+
@modes_interval = {}
|
31
|
+
|
32
|
+
AppProfiler::Backend::StackprofBackend::AVAILABLE_MODES.each do |mode|
|
33
|
+
case mode
|
34
|
+
when :wall
|
35
|
+
@modes_probability[mode] = wall_mode_probability
|
36
|
+
@modes_interval[mode] = wall_interval
|
37
|
+
when :cpu
|
38
|
+
@modes_probability[mode] = cpu_mode_probability
|
39
|
+
@modes_interval[mode] = cpu_interval
|
40
|
+
when :object
|
41
|
+
@modes_probability[mode] = object_mode_probability
|
42
|
+
@modes_interval[mode] = object_interval
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
def interval_for(mode)
|
48
|
+
@modes_interval[mode]
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
@@ -0,0 +1,44 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module AppProfiler
|
4
|
+
module Sampler
|
5
|
+
class VernierConfig
|
6
|
+
attr_reader :modes_probability
|
7
|
+
|
8
|
+
WALL_INTERVAL = 5000
|
9
|
+
RETAINED_INTERVAL = 5000
|
10
|
+
|
11
|
+
WALL_MODE_PROBABILITY = 1.0
|
12
|
+
RETAINED_MODE_PROBABILITY = 0.0
|
13
|
+
|
14
|
+
def initialize(
|
15
|
+
wall_interval: WALL_INTERVAL,
|
16
|
+
retained_interval: RETAINED_INTERVAL,
|
17
|
+
wall_mode_probability: WALL_MODE_PROBABILITY,
|
18
|
+
retained_mode_probability: RETAINED_MODE_PROBABILITY
|
19
|
+
)
|
20
|
+
if wall_mode_probability + retained_mode_probability != 1.0
|
21
|
+
raise ArgumentError, "mode probabilities must sum to 1"
|
22
|
+
end
|
23
|
+
|
24
|
+
@modes_probability = {}
|
25
|
+
@modes_interval = {}
|
26
|
+
|
27
|
+
AppProfiler::Backend::VernierBackend::AVAILABLE_MODES.each do |mode|
|
28
|
+
case mode
|
29
|
+
when :wall
|
30
|
+
@modes_probability[mode] = wall_mode_probability
|
31
|
+
@modes_interval[mode] = wall_interval
|
32
|
+
when :retained
|
33
|
+
@modes_probability[mode] = retained_mode_probability
|
34
|
+
@modes_interval[mode] = retained_interval
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
def interval_for(mode)
|
40
|
+
@modes_interval[mode]
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
@@ -0,0 +1,60 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "app_profiler/sampler/config"
|
4
|
+
module AppProfiler
|
5
|
+
module Sampler
|
6
|
+
class << self
|
7
|
+
def profile_params(request, config)
|
8
|
+
random = Kernel.rand
|
9
|
+
return unless sample?(random, config, request)
|
10
|
+
|
11
|
+
get_profile_params(config, random)
|
12
|
+
end
|
13
|
+
|
14
|
+
private
|
15
|
+
|
16
|
+
def sample?(random, config, request)
|
17
|
+
return false if random > config.sample_rate
|
18
|
+
|
19
|
+
path = request.path
|
20
|
+
return false unless config.paths.any? { |p| path.match?(p) }
|
21
|
+
|
22
|
+
true
|
23
|
+
end
|
24
|
+
|
25
|
+
def get_profile_params(config, random)
|
26
|
+
backend_name = select_random(config.backends_probability, random)
|
27
|
+
backend_config = config.get_backend_config(backend_name)
|
28
|
+
|
29
|
+
mode = select_random(backend_config.modes_probability, random)
|
30
|
+
interval = backend_config.interval_for(mode)
|
31
|
+
|
32
|
+
AppProfiler::Parameters.new(
|
33
|
+
backend: backend_name,
|
34
|
+
mode: mode,
|
35
|
+
async: true,
|
36
|
+
interval: interval,
|
37
|
+
)
|
38
|
+
end
|
39
|
+
|
40
|
+
# Given options with probabilities, select one based on range.
|
41
|
+
# For example, given options {a: 0.1, b: 0.2, c: 0.7} and random 0.5,
|
42
|
+
# it will return :c
|
43
|
+
# Assumes all probabilities sum to 1
|
44
|
+
|
45
|
+
def select_random(options, random)
|
46
|
+
current = 0
|
47
|
+
options = options.sort_by do |_, probability|
|
48
|
+
probability
|
49
|
+
end
|
50
|
+
|
51
|
+
options.each do |o, probabilty|
|
52
|
+
current += probabilty
|
53
|
+
if random <= current
|
54
|
+
return o
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
data/lib/app_profiler/server.rb
CHANGED
@@ -280,7 +280,7 @@ module AppProfiler
|
|
280
280
|
@listen_thread = nil
|
281
281
|
|
282
282
|
@logger.info(
|
283
|
-
"[AppProfiler::Server] listening on addr=#{@transport.socket.addr}"
|
283
|
+
"[AppProfiler::Server] listening on addr=#{@transport.socket.addr}",
|
284
284
|
)
|
285
285
|
@pid = Process.pid
|
286
286
|
end
|
@@ -342,7 +342,7 @@ module AppProfiler
|
|
342
342
|
end
|
343
343
|
rescue => e
|
344
344
|
@logger.error(
|
345
|
-
"[AppProfiler::Server] exception #{e} responding to request #{request}: #{e.message}"
|
345
|
+
"[AppProfiler::Server] exception #{e} responding to request #{request}: #{e.message}",
|
346
346
|
)
|
347
347
|
ensure
|
348
348
|
session.close
|
@@ -6,12 +6,14 @@ module AppProfiler
|
|
6
6
|
class_attribute :bucket_name, default: "profiles"
|
7
7
|
class_attribute :credentials, default: {}
|
8
8
|
|
9
|
-
|
10
|
-
|
11
|
-
|
9
|
+
class << self
|
10
|
+
def upload(_profile)
|
11
|
+
raise NotImplementedError
|
12
|
+
end
|
12
13
|
|
13
|
-
|
14
|
-
|
14
|
+
def enqueue_upload(_profile)
|
15
|
+
raise NotImplementedError
|
16
|
+
end
|
15
17
|
end
|
16
18
|
end
|
17
19
|
end
|
@@ -15,6 +15,10 @@ module AppProfiler
|
|
15
15
|
def upload(profile, _params = {})
|
16
16
|
file = profile.file.open
|
17
17
|
|
18
|
+
metadata = if AppProfiler.forward_metadata_on_upload && profile.metadata.present?
|
19
|
+
profile.metadata
|
20
|
+
end
|
21
|
+
|
18
22
|
ActiveSupport::Notifications.instrument(
|
19
23
|
"gcs_upload.app_profiler",
|
20
24
|
file_size: file.size,
|
@@ -24,6 +28,7 @@ module AppProfiler
|
|
24
28
|
gcs_filename(profile),
|
25
29
|
content_type: "application/json",
|
26
30
|
content_encoding: "gzip",
|
31
|
+
metadata: metadata,
|
27
32
|
)
|
28
33
|
ensure
|
29
34
|
profile.file.unlink
|
data/lib/app_profiler/version.rb
CHANGED
@@ -9,17 +9,57 @@ module AppProfiler
|
|
9
9
|
class BaseMiddleware
|
10
10
|
class Sanitizer < Rails::HTML::Sanitizer.best_supported_vendor.safe_list_sanitizer
|
11
11
|
self.allowed_tags = Set.new([
|
12
|
-
"strong",
|
13
|
-
"
|
14
|
-
"
|
15
|
-
"
|
12
|
+
"strong",
|
13
|
+
"em",
|
14
|
+
"b",
|
15
|
+
"i",
|
16
|
+
"p",
|
17
|
+
"code",
|
18
|
+
"pre",
|
19
|
+
"tt",
|
20
|
+
"samp",
|
21
|
+
"kbd",
|
22
|
+
"var",
|
23
|
+
"sub",
|
24
|
+
"sup",
|
25
|
+
"dfn",
|
26
|
+
"cite",
|
27
|
+
"big",
|
28
|
+
"small",
|
29
|
+
"address",
|
30
|
+
"hr",
|
31
|
+
"br",
|
32
|
+
"div",
|
33
|
+
"span",
|
34
|
+
"h1",
|
35
|
+
"h2",
|
36
|
+
"h3",
|
37
|
+
"h4",
|
38
|
+
"h5",
|
39
|
+
"h6",
|
40
|
+
"ul",
|
41
|
+
"ol",
|
42
|
+
"li",
|
43
|
+
"dl",
|
44
|
+
"dt",
|
45
|
+
"dd",
|
46
|
+
"abbr",
|
47
|
+
"acronym",
|
48
|
+
"a",
|
49
|
+
"img",
|
50
|
+
"blockquote",
|
51
|
+
"del",
|
52
|
+
"ins",
|
53
|
+
"script",
|
16
54
|
])
|
17
55
|
end
|
18
56
|
|
19
57
|
private_constant(:Sanitizer)
|
20
58
|
|
21
|
-
|
22
|
-
file
|
59
|
+
class << self
|
60
|
+
def id(file)
|
61
|
+
file.basename.to_s.delete_suffix(".json")
|
62
|
+
end
|
23
63
|
end
|
24
64
|
|
25
65
|
def initialize(app)
|
@@ -87,7 +127,7 @@ module AppProfiler
|
|
87
127
|
</p>
|
88
128
|
HTML
|
89
129
|
end
|
90
|
-
end
|
130
|
+
end,
|
91
131
|
)
|
92
132
|
end
|
93
133
|
|
@@ -12,7 +12,7 @@ module AppProfiler
|
|
12
12
|
def initialize(app)
|
13
13
|
super
|
14
14
|
@speedscope = Rack::File.new(
|
15
|
-
File.join(AppProfiler.root, "node_modules/speedscope/dist/release")
|
15
|
+
File.join(AppProfiler.root, "node_modules/speedscope/dist/release"),
|
16
16
|
)
|
17
17
|
end
|
18
18
|
|
@@ -33,7 +33,7 @@ module AppProfiler
|
|
33
33
|
end || raise(ArgumentError)
|
34
34
|
|
35
35
|
render(
|
36
|
-
<<~HTML
|
36
|
+
<<~HTML,
|
37
37
|
<script type="text/javascript">
|
38
38
|
var graph = #{profile.read};
|
39
39
|
var json = JSON.stringify(graph);
|
data/lib/app_profiler.rb
CHANGED
@@ -38,6 +38,7 @@ module AppProfiler
|
|
38
38
|
require "app_profiler/profile"
|
39
39
|
require "app_profiler/backend"
|
40
40
|
require "app_profiler/server"
|
41
|
+
require "app_profiler/sampler"
|
41
42
|
|
42
43
|
mattr_accessor :logger, default: Logger.new($stdout)
|
43
44
|
mattr_accessor :root
|
@@ -61,6 +62,9 @@ module AppProfiler
|
|
61
62
|
mattr_reader :profile_enqueue_success, default: nil
|
62
63
|
mattr_reader :profile_enqueue_failure, default: nil
|
63
64
|
mattr_reader :after_process_queue, default: nil
|
65
|
+
mattr_accessor :forward_metadata_on_upload, default: false
|
66
|
+
mattr_accessor :profile_sampler_enabled, default: false
|
67
|
+
mattr_accessor :profile_sampler_config
|
64
68
|
|
65
69
|
class << self
|
66
70
|
def run(*args, backend: nil, **kwargs, &block)
|
@@ -70,7 +74,7 @@ module AppProfiler
|
|
70
74
|
profiler.run(*args, **kwargs, &block)
|
71
75
|
rescue BackendError => e
|
72
76
|
logger.error(
|
73
|
-
"[AppProfiler.run] exception #{e} configuring backend #{backend}: #{e.message}"
|
77
|
+
"[AppProfiler.run] exception #{e} configuring backend #{backend}: #{e.message}",
|
74
78
|
)
|
75
79
|
yield
|
76
80
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: app_profiler
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.2.
|
4
|
+
version: 0.2.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Gannon McGibbon
|
@@ -10,10 +10,10 @@ authors:
|
|
10
10
|
- Jon Simpson
|
11
11
|
- Kevin Jalbert
|
12
12
|
- Scott Francis
|
13
|
-
autorequire:
|
13
|
+
autorequire:
|
14
14
|
bindir: bin
|
15
15
|
cert_chain: []
|
16
|
-
date: 2024-
|
16
|
+
date: 2024-08-26 00:00:00.000000000 Z
|
17
17
|
dependencies:
|
18
18
|
- !ruby/object:Gem::Dependency
|
19
19
|
name: activesupport
|
@@ -127,7 +127,7 @@ dependencies:
|
|
127
127
|
- - ">="
|
128
128
|
- !ruby/object:Gem::Version
|
129
129
|
version: '0'
|
130
|
-
description:
|
130
|
+
description:
|
131
131
|
email:
|
132
132
|
- gems@shopify.com
|
133
133
|
executables: []
|
@@ -149,6 +149,10 @@ files:
|
|
149
149
|
- lib/app_profiler/profile/vernier.rb
|
150
150
|
- lib/app_profiler/railtie.rb
|
151
151
|
- lib/app_profiler/request_parameters.rb
|
152
|
+
- lib/app_profiler/sampler.rb
|
153
|
+
- lib/app_profiler/sampler/config.rb
|
154
|
+
- lib/app_profiler/sampler/stackprof_config.rb
|
155
|
+
- lib/app_profiler/sampler/vernier_config.rb
|
152
156
|
- lib/app_profiler/server.rb
|
153
157
|
- lib/app_profiler/storage/base_storage.rb
|
154
158
|
- lib/app_profiler/storage/file_storage.rb
|
@@ -165,7 +169,7 @@ homepage: https://github.com/Shopify/app_profiler
|
|
165
169
|
licenses: []
|
166
170
|
metadata:
|
167
171
|
allowed_push_host: https://rubygems.org
|
168
|
-
post_install_message:
|
172
|
+
post_install_message:
|
169
173
|
rdoc_options: []
|
170
174
|
require_paths:
|
171
175
|
- lib
|
@@ -180,8 +184,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
180
184
|
- !ruby/object:Gem::Version
|
181
185
|
version: '0'
|
182
186
|
requirements: []
|
183
|
-
rubygems_version: 3.5.
|
184
|
-
signing_key:
|
187
|
+
rubygems_version: 3.5.17
|
188
|
+
signing_key:
|
185
189
|
specification_version: 4
|
186
190
|
summary: Collect performance profiles for your Rails application.
|
187
191
|
test_files: []
|