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 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: []