app_profiler 0.2.1 → 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/middleware.rb +14 -5
- data/lib/app_profiler/parameters.rb +2 -1
- data/lib/app_profiler/railtie.rb +3 -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/version.rb +1 -1
- data/lib/app_profiler.rb +3 -0
- metadata +7 -3
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
|
@@ -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/railtie.rb
CHANGED
@@ -42,6 +42,9 @@ module AppProfiler
|
|
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
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
|
45
48
|
end
|
46
49
|
|
47
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/version.rb
CHANGED
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
|
@@ -62,6 +63,8 @@ module AppProfiler
|
|
62
63
|
mattr_reader :profile_enqueue_failure, default: nil
|
63
64
|
mattr_reader :after_process_queue, default: nil
|
64
65
|
mattr_accessor :forward_metadata_on_upload, default: false
|
66
|
+
mattr_accessor :profile_sampler_enabled, default: false
|
67
|
+
mattr_accessor :profile_sampler_config
|
65
68
|
|
66
69
|
class << self
|
67
70
|
def run(*args, backend: nil, **kwargs, &block)
|
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
|
@@ -13,7 +13,7 @@ authors:
|
|
13
13
|
autorequire:
|
14
14
|
bindir: bin
|
15
15
|
cert_chain: []
|
16
|
-
date: 2024-08-
|
16
|
+
date: 2024-08-26 00:00:00.000000000 Z
|
17
17
|
dependencies:
|
18
18
|
- !ruby/object:Gem::Dependency
|
19
19
|
name: activesupport
|
@@ -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
|
@@ -180,7 +184,7 @@ 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.
|
187
|
+
rubygems_version: 3.5.17
|
184
188
|
signing_key:
|
185
189
|
specification_version: 4
|
186
190
|
summary: Collect performance profiles for your Rails application.
|