app_profiler 0.2.0 → 0.2.2

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 1c36371d12c24dfed23e6e492b5c3912e01480bfd7a5973bf1f311a86adc86d3
4
- data.tar.gz: 1b78da495c55cee24ab6b0d6f8d8194ca6cfb27030de7a4ba90db37fa60e3988
3
+ metadata.gz: 15a1a7b3bd1e60dc10753ce4b8e4f2907461b09417aecde43fce3d4565d5f211
4
+ data.tar.gz: 811e16e5383f85f4e2aef6aaf50e832b8cf5714c2cacd730ce4f184c9d1f26c4
5
5
  SHA512:
6
- metadata.gz: bd4e66293f491f25caba2a352b509012344bdc6e04c880cb4c3d60d00f3dc38cab50b9c59cf0cbe14c36adc2591610bd004addc28521cf077b7d3b7c91585947
7
- data.tar.gz: 036c9de32a86b5e99e1d244fe1200aa3e0dabdf6d610d91c34aa6621bf8a194b9a769a8a9bae254432d2e2bfae67b137a1209c4214bb2c2ce774aa9db9bea907
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
- def self.name
20
- :stackprof
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
- def self.name
19
- :vernier
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 params.valid?
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: params.autoredirect,
44
- async: params.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
@@ -15,20 +15,22 @@ module AppProfiler
15
15
 
16
16
  delegate :[], to: :@data
17
17
 
18
- # This function should not be called if `StackProf.results` returns nil.
19
- def self.from_stackprof(data)
20
- options = INTERNAL_METADATA_KEYS.map { |key| [key, data[:metadata]&.delete(key)] }.to_h
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
- StackprofProfile.new(data, **options).tap do |profile|
23
- raise ArgumentError, "invalid profile data" unless profile.valid?
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
- def self.from_vernier(data)
28
- options = INTERNAL_METADATA_KEYS.map { |key| [key, data[:meta]&.delete(key)] }.to_h
28
+ def from_vernier(data)
29
+ options = INTERNAL_METADATA_KEYS.map { |key| [key, data[:meta]&.delete(key)] }.to_h
29
30
 
30
- VernierProfile.new(data, **options).tap do |profile|
31
- raise ArgumentError, "invalid profile data" unless profile.valid?
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
@@ -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|
@@ -8,6 +8,10 @@ module AppProfiler
8
8
  @request = request
9
9
  end
10
10
 
11
+ def path
12
+ @request.env["PATH_INFO"]
13
+ end
14
+
11
15
  def autoredirect
12
16
  query_param("autoredirect") || profile_header_param("autoredirect")
13
17
  end
@@ -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
@@ -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
- def self.upload(_profile)
10
- raise NotImplementedError
11
- end
9
+ class << self
10
+ def upload(_profile)
11
+ raise NotImplementedError
12
+ end
12
13
 
13
- def self.enqueue_upload(_profile)
14
- raise NotImplementedError
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
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module AppProfiler
4
- VERSION = "0.2.0"
4
+ VERSION = "0.2.2"
5
5
  end
@@ -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", "em", "b", "i", "p", "code", "pre", "tt", "samp", "kbd", "var", "sub",
13
- "sup", "dfn", "cite", "big", "small", "address", "hr", "br", "div", "span", "h1",
14
- "h2", "h3", "h4", "h5", "h6", "ul", "ol", "li", "dl", "dt", "dd", "abbr", "acronym",
15
- "a", "img", "blockquote", "del", "ins", "script",
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
- def self.id(file)
22
- file.basename.to_s.delete_suffix(".json")
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);
@@ -49,7 +49,7 @@ module AppProfiler
49
49
  exec("which", "yarn", silent: true) do
50
50
  raise(
51
51
  YarnError,
52
- <<~MSG.squish
52
+ <<~MSG.squish,
53
53
  `yarn` command not found.
54
54
  Please install `yarn` or make it available in PATH.
55
55
  MSG
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.0
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-06-18 00:00:00.000000000 Z
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.11
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: []