appsignal 3.11.0 → 3.12.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (75) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +109 -0
  3. data/Rakefile +1 -1
  4. data/lib/appsignal/cli/diagnose.rb +1 -1
  5. data/lib/appsignal/config.rb +150 -32
  6. data/lib/appsignal/demo.rb +1 -6
  7. data/lib/appsignal/integrations/grape.rb +7 -0
  8. data/lib/appsignal/integrations/hanami.rb +8 -43
  9. data/lib/appsignal/integrations/padrino.rb +8 -73
  10. data/lib/appsignal/integrations/railtie.rb +35 -13
  11. data/lib/appsignal/integrations/sinatra.rb +8 -19
  12. data/lib/appsignal/loaders/grape.rb +13 -0
  13. data/lib/appsignal/loaders/hanami.rb +40 -0
  14. data/lib/appsignal/loaders/padrino.rb +68 -0
  15. data/lib/appsignal/loaders/sinatra.rb +24 -0
  16. data/lib/appsignal/loaders.rb +92 -0
  17. data/lib/appsignal/rack/abstract_middleware.rb +2 -1
  18. data/lib/appsignal/rack/event_handler.rb +5 -5
  19. data/lib/appsignal/rack.rb +6 -0
  20. data/lib/appsignal/version.rb +1 -1
  21. data/lib/appsignal.rb +163 -9
  22. data/spec/lib/appsignal/cli/demo_spec.rb +0 -1
  23. data/spec/lib/appsignal/cli/diagnose/paths_spec.rb +1 -1
  24. data/spec/lib/appsignal/cli/diagnose_spec.rb +0 -1
  25. data/spec/lib/appsignal/config_spec.rb +153 -1
  26. data/spec/lib/appsignal/demo_spec.rb +1 -2
  27. data/spec/lib/appsignal/environment_spec.rb +4 -2
  28. data/spec/lib/appsignal/hooks/active_support_notifications_spec.rb +3 -6
  29. data/spec/lib/appsignal/hooks/activejob_spec.rb +3 -3
  30. data/spec/lib/appsignal/hooks/dry_monitor_spec.rb +4 -7
  31. data/spec/lib/appsignal/hooks/excon_spec.rb +3 -6
  32. data/spec/lib/appsignal/hooks/gvl_spec.rb +2 -2
  33. data/spec/lib/appsignal/hooks/http_spec.rb +1 -3
  34. data/spec/lib/appsignal/hooks/net_http_spec.rb +1 -1
  35. data/spec/lib/appsignal/hooks/redis_client_spec.rb +5 -8
  36. data/spec/lib/appsignal/hooks/redis_spec.rb +3 -6
  37. data/spec/lib/appsignal/hooks/resque_spec.rb +1 -1
  38. data/spec/lib/appsignal/hooks/sequel_spec.rb +3 -5
  39. data/spec/lib/appsignal/hooks/sidekiq_spec.rb +1 -1
  40. data/spec/lib/appsignal/hooks/webmachine_spec.rb +1 -1
  41. data/spec/lib/appsignal/integrations/delayed_job_plugin_spec.rb +2 -2
  42. data/spec/lib/appsignal/integrations/grape_spec.rb +36 -0
  43. data/spec/lib/appsignal/integrations/hanami_spec.rb +9 -178
  44. data/spec/lib/appsignal/integrations/http_spec.rb +1 -5
  45. data/spec/lib/appsignal/integrations/mongo_ruby_driver_spec.rb +4 -2
  46. data/spec/lib/appsignal/integrations/net_http_spec.rb +1 -1
  47. data/spec/lib/appsignal/integrations/object_spec.rb +1 -3
  48. data/spec/lib/appsignal/integrations/padrino_spec.rb +8 -330
  49. data/spec/lib/appsignal/integrations/railtie_spec.rb +275 -191
  50. data/spec/lib/appsignal/integrations/shoryuken_spec.rb +1 -1
  51. data/spec/lib/appsignal/integrations/sidekiq_spec.rb +11 -9
  52. data/spec/lib/appsignal/integrations/sinatra_spec.rb +9 -104
  53. data/spec/lib/appsignal/loaders/grape_spec.rb +12 -0
  54. data/spec/lib/appsignal/loaders/hanami_spec.rb +95 -0
  55. data/spec/lib/appsignal/loaders/padrino_spec.rb +277 -0
  56. data/spec/lib/appsignal/loaders/sinatra_spec.rb +47 -0
  57. data/spec/lib/appsignal/loaders_spec.rb +137 -0
  58. data/spec/lib/appsignal/probes/sidekiq_spec.rb +1 -1
  59. data/spec/lib/appsignal/probes_spec.rb +6 -5
  60. data/spec/lib/appsignal/rack/abstract_middleware_spec.rb +3 -2
  61. data/spec/lib/appsignal/rack/event_handler_spec.rb +33 -0
  62. data/spec/lib/appsignal/rack/generic_instrumentation_spec.rb +1 -1
  63. data/spec/lib/appsignal/rack/grape_middleware_spec.rb +2 -35
  64. data/spec/lib/appsignal/rack/hanami_middleware_spec.rb +1 -1
  65. data/spec/lib/appsignal/rack/sinatra_instrumentation_spec.rb +3 -3
  66. data/spec/lib/appsignal/span_spec.rb +1 -3
  67. data/spec/lib/appsignal/transaction_spec.rb +4 -2
  68. data/spec/lib/appsignal_spec.rb +278 -26
  69. data/spec/lib/puma/appsignal_spec.rb +0 -3
  70. data/spec/spec_helper.rb +5 -4
  71. data/spec/support/helpers/config_helpers.rb +2 -1
  72. data/spec/support/helpers/loader_helper.rb +21 -0
  73. data/spec/support/stubs/appsignal/loaders/loader_stub.rb +7 -0
  74. data/spec/support/testing.rb +46 -0
  75. metadata +15 -2
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 58edd9ab16d90269a61e7e485e51078b05b60b2192461408d415eafd8327fb04
4
- data.tar.gz: 92520f55157b13bbe61a98cbcc61901c3c016854a436bd4ae01ad9563d92bf9a
3
+ metadata.gz: c2cfb956b5058ae48109ce92cc65f4158f472797f531579e63aeb8398cb73044
4
+ data.tar.gz: 34ba16eb3b7c3b464e10fb9a8533d3b230cfb73550f6a804599e02b96fb909f1
5
5
  SHA512:
6
- metadata.gz: 502fd7ada9029f2ecacb0368e8bfe8128fa7792031f1c567f73c05e2381aa1fbc9f946bd7b574352e0114413c724cace05758854725130101122121200ceaaff
7
- data.tar.gz: 1d90ec5300a657522de4ec3298b3db22a60aadecafda35ffe38ffed72b1ae1d311e590a502ef6d002e99897f2d453e1b0c1d3c9f8569eebd9aa3d90610fce77e
6
+ metadata.gz: e374e9fc6cb686ec6297cb9f8025a6309f011dfc8fff3c22f32f8ddb9635e867dfd001e7058553a3f2d624bf68065e2efe2f69e73692d9b05195736992d6af63
7
+ data.tar.gz: e83be1622f1c5d86748bc3bb93912d79ac2dd66cb6bbe61106aee8965b3aced6c31bc5e25689f52bfa7cb01da9f10e50fb76c47de1934b93cb12b6db705bb661
data/CHANGELOG.md CHANGED
@@ -1,5 +1,114 @@
1
1
  # AppSignal for Ruby gem Changelog
2
2
 
3
+ ## 3.12.0
4
+
5
+ _Published on 2024-07-22._
6
+
7
+ ### Added
8
+
9
+ - Add a Rails configuration option to start AppSignal after Rails is initialized. By default, AppSignal will start before the Rails initializers are run. This way it is not possible to configure AppSignal in a Rails initializer using Ruby. To configure AppSignal in a Rails initializer, configure Rails to start AppSignal after it is initialized.
10
+
11
+ ```ruby
12
+ # config/application.rb
13
+
14
+ # ...
15
+
16
+ module MyApp
17
+ class Application < Rails::Application
18
+ # Add this line
19
+ config.appsignal.start_at = :after_initialize
20
+
21
+ # Other config
22
+ end
23
+ end
24
+ ```
25
+
26
+ Then, in the initializer:
27
+
28
+ ```ruby
29
+ # config/initializers/appsignal.rb
30
+
31
+ Appsignal.config = Appsignal::Config.new(
32
+ Rails.root,
33
+ Rails.env,
34
+ :ignore_actions => ["My action"]
35
+ )
36
+ ```
37
+
38
+ Be aware that when `start_at` is set to `after_initialize`, AppSignal will not track any errors that occur when the initializers are run and the app fails to start.
39
+
40
+ See [our Rails documentation](https://docs.appsignal.com/ruby/integrations/rails.html) for more information.
41
+
42
+ (minor [b84a6a36](https://github.com/appsignal/appsignal-ruby/commit/b84a6a3695259b365cde6f69165818a1e1b99197))
43
+ - Add a new method of configuring AppSignal: `Appsignal.configure`. This new method allows apps to configure AppSignal in Ruby.
44
+
45
+ ```ruby
46
+ # The environment will be auto detected
47
+ Appsignal.configure do |config|
48
+ config.activejob_report_errors = "discard"
49
+ config.sidekiq_report_errors = :discard
50
+ config.ignore_actions = ["My ignored action", "My other ignored action"]
51
+ config.request_headers << "MY_HTTP_HEADER"
52
+ config.send_params = true
53
+ config.enable_host_metrics = false
54
+ end
55
+
56
+ # Explicitly define which environment to start
57
+ Appsignal.configure(:production) do |config|
58
+ # Some config
59
+ end
60
+ ```
61
+
62
+ This new method can be used to update config in Ruby. We still recommend to use the `config/appsignal.yml` file to configure AppSignal whenever possible. Apps that use the `Appsignal.config = Appsignal::Config.new(...)` way of configuring AppSignal, should be updated to use the new `Appsignal.configure` method. The `Appsignal::Config.new` method would overwrite the given "initial config" with the config file's config and config read from environment variables. The `Appsignal.configure` method is leading. The config file, environment variables and `Appsignal.configure` methods can all be mixed.
63
+
64
+ See [our configuration guide](https://docs.appsignal.com/ruby/configuration.html) for more information.
65
+
66
+ (minor [ba60fff9](https://github.com/appsignal/appsignal-ruby/commit/ba60fff9fa5087c78e171a0608beba882e1a4c92))
67
+
68
+ ### Changed
69
+
70
+ - Update the Sinatra, Padrino, Grape and Hanami integration setup for applications. Before this change a "appsignal/integrations/sinatra" file would need to be required to load the AppSignal integration for Sinatra. Similar requires exist for other libraries. This has changed to a new integration load mechanism.
71
+
72
+ This new load mechanism makes starting AppSignal more predictable when loading multiple integrations, like those for Sinatra, Padrino, Grape and Hanami.
73
+
74
+ ```ruby
75
+ # Sinatra example
76
+ # Before
77
+ require "appsignal/integrations/sinatra"
78
+
79
+ # After
80
+ require "appsignal"
81
+
82
+ Appsignal.load(:sinatra)
83
+ Appsignal.start
84
+ ```
85
+
86
+ The `require "appsignal/integrations/sinatra"` will still work, but is deprecated in this release.
87
+
88
+ See the documentation for the specific libraries for the latest on how to integrate AppSignal.
89
+
90
+ - [Grape](https://docs.appsignal.com/ruby/integrations/grape.html)
91
+ - [Hanami](https://docs.appsignal.com/ruby/integrations/hanami.html)
92
+ - [Padrino](https://docs.appsignal.com/ruby/integrations/padrino.html)
93
+ - [Sinatra](https://docs.appsignal.com/ruby/integrations/sinatra.html)
94
+
95
+ When using a combination of the libraries listed above, read our [integration guide](https://docs.appsignal.com/ruby/instrumentation/integrating-appsignal.html) on how to load and configure AppSignal for multiple integrations at once.
96
+
97
+ (minor [35fff8cb](https://github.com/appsignal/appsignal-ruby/commit/35fff8cb135bf024b3bcf95e497af7dcc0a4cc02))
98
+ - Disable the AppSignal Rack EventHandler when AppSignal is not active. It would still trigger our instrumentation when AppSignal is not active. This reduces the instrumentation overhead when AppSignal is not active. (patch [03e7c1b2](https://github.com/appsignal/appsignal-ruby/commit/03e7c1b221caa00af1599ae94e1d4055835c94a7))
99
+
100
+ ### Deprecated
101
+
102
+ - Deprecate the `Appsignal.config = Appsignal::Config.new(...)` method of configuring AppSignal. See the changelog entry about `Appsignal.configure { ... }` for the new way to configure AppSignal in Ruby. (minor [ba60fff9](https://github.com/appsignal/appsignal-ruby/commit/ba60fff9fa5087c78e171a0608beba882e1a4c92))
103
+ - Deprecate the Hanami integration require: `require "appsignal/integrations/hanami"`. Use the new `Appsignal.load(:hanami)` method instead. Read our [Hanami docs](https://docs.appsignal.com/ruby/integrations/hanami.html) for more information. (patch)
104
+ - Deprecate the Padrino integration require: `require "appsignal/integrations/padrino"`. Use the new `Appsignal.load(:padrino)` method instead. Read our [Padrino docs](https://docs.appsignal.com/ruby/integrations/padrino.html) for more information. (patch)
105
+ - Deprecate the Sinatra integration require: `require "appsignal/integrations/sinatra"`. Use the new `Appsignal.load(:sinatra)` method instead. Read our [Sinatra docs](https://docs.appsignal.com/ruby/integrations/sinatra.html) for more information. (patch)
106
+ - Deprecate the Grape integration require: `require "appsignal/integrations/grape"`. Use the new `Appsignal.load(:grape)` method instead. Read our [Grape docs](https://docs.appsignal.com/ruby/integrations/grape.html) for more information. (patch)
107
+
108
+ ### Fixed
109
+
110
+ - Fix instrumentation events for response bodies appearing twice. When multiple instrumentation middleware were mounted in an application, it would create duplicate `process_response_body.rack` events. (patch [24b16517](https://github.com/appsignal/appsignal-ruby/commit/24b16517f3bf5e2911345d5d825a1febb3c7aed7))
111
+
3
112
  ## 3.11.0
4
113
 
5
114
  _Published on 2024-07-15._
data/Rakefile CHANGED
@@ -295,7 +295,7 @@ task :console do
295
295
  require "irb/completion"
296
296
  require "appsignal"
297
297
 
298
- Appsignal.config = Appsignal::Config.new(".", :console)
298
+ Appsignal.configure(:console)
299
299
 
300
300
  ARGV.clear
301
301
  IRB.start
@@ -194,7 +194,7 @@ module Appsignal
194
194
  initial_config[:log_path] = current_path.join("log")
195
195
  end
196
196
 
197
- Appsignal.config = Appsignal::Config.new(
197
+ Appsignal._config = Appsignal::Config.new(
198
198
  current_path,
199
199
  options.fetch(:environment, ENV.fetch("RACK_ENV", ENV.fetch("RAILS_ENV", nil))),
200
200
  initial_config
@@ -10,6 +10,16 @@ module Appsignal
10
10
  class Config
11
11
  include Appsignal::Utils::StdoutAndLoggerMessage
12
12
 
13
+ # @api private
14
+ def self.loader_defaults
15
+ @loader_defaults ||= []
16
+ end
17
+
18
+ # @api private
19
+ def self.add_loader_defaults(name, options)
20
+ loader_defaults << [name, options]
21
+ end
22
+
13
23
  # @api private
14
24
  DEFAULT_CONFIG = {
15
25
  :activejob_report_errors => "all",
@@ -162,24 +172,14 @@ module Appsignal
162
172
  # @return [Hash]
163
173
 
164
174
  # @api private
165
- attr_reader :root_path, :env, :config_hash, :system_config,
166
- :initial_config, :file_config, :env_config, :override_config
175
+ attr_accessor :root_path, :env, :config_hash
176
+ attr_reader :system_config, :initial_config, :file_config, :env_config,
177
+ :override_config, :dsl_config
167
178
  # @api private
168
179
  attr_accessor :logger
169
180
 
170
181
  # Initialize a new configuration object for AppSignal.
171
182
  #
172
- # If this is manually initialized, and not by {Appsignal.start}, it needs
173
- # to be assigned to the {Appsignal.config} attribute.
174
- #
175
- # @example
176
- # require "appsignal"
177
- # Appsignal.config = Appsignal::Config.new(
178
- # app_path,
179
- # "production"
180
- # )
181
- # Appsignal.start
182
- #
183
183
  # @param root_path [String] Root path of the app.
184
184
  # @param env [String] The environment to load when AppSignal is started. It
185
185
  # will look for an environment with this name in the `config/appsignal.yml`
@@ -193,55 +193,90 @@ module Appsignal
193
193
  # @param config_file [String] Custom config file location. Default
194
194
  # `config/appsignal.yml`.
195
195
  #
196
+ # @api private
196
197
  # @see https://docs.appsignal.com/ruby/configuration/
197
198
  # Configuration documentation
198
199
  # @see https://docs.appsignal.com/ruby/configuration/load-order.html
199
200
  # Configuration load order
200
201
  # @see https://docs.appsignal.com/ruby/instrumentation/integrating-appsignal.html
201
202
  # How to integrate AppSignal manually
202
- def initialize(
203
+ def initialize( # rubocop:disable Metrics/ParameterLists
203
204
  root_path,
204
- env,
205
+ initial_env,
205
206
  initial_config = {},
206
207
  logger = Appsignal.internal_logger,
207
- config_file = nil
208
+ config_file = nil,
209
+ load_on_new = true # rubocop:disable Style/OptionalBooleanParameter
208
210
  )
209
- @config_file_error = false
210
211
  @root_path = root_path
212
+ @config_file_error = false
211
213
  @config_file = config_file
212
214
  @logger = logger
213
215
  @valid = false
214
- @config_hash = DEFAULT_CONFIG.dup
215
- env_loaded_from_initial = env.to_s
216
- @env =
217
- if ENV.key?("APPSIGNAL_APP_ENV")
218
- env_loaded_from_env = ENV["APPSIGNAL_APP_ENV"]
219
- else
220
- env_loaded_from_initial
221
- end
216
+
217
+ @initial_env = initial_env
218
+ @env = initial_env.to_s
219
+ @config_hash = {}
220
+ @system_config = {}
221
+ @initial_config = initial_config
222
+ @file_config = {}
223
+ @env_config = {}
224
+ @override_config = {}
225
+ @dsl_config = {} # Can be set using `Appsignal.configure`
226
+
227
+ return unless load_on_new
228
+
229
+ # Determine starting environment
230
+ @env = ENV["APPSIGNAL_APP_ENV"] if ENV.key?("APPSIGNAL_APP_ENV")
231
+ load_config
232
+ validate
233
+ end
234
+
235
+ # @api private
236
+ def load_config
237
+ # Set defaults
238
+ # Deep duplicate each frozen default value
239
+ merge(DEFAULT_CONFIG.transform_values(&:dup))
222
240
 
223
241
  # Set config based on the system
224
242
  @system_config = detect_from_system
225
243
  merge(system_config)
226
- # Initial config
227
- @initial_config = initial_config
244
+
245
+ # Set defaults from loaders in reverse order so the first register
246
+ # loader's defaults overwrite all others
247
+ self.class.loader_defaults.reverse.each do |(_loader_name, loader_defaults)|
248
+ defaults = loader_defaults.compact.dup
249
+ # Overwrite root path
250
+ loader_path = defaults.delete(:root_path)
251
+ @root_path = loader_path if loader_path
252
+ # Overwrite env
253
+ loader_env = defaults.delete(:env)
254
+ @env = loader_env.to_s if loader_env
255
+ # Merge with the config loaded so far
256
+ merge(defaults)
257
+ end
258
+
228
259
  merge(initial_config)
260
+ # Track origin of env
261
+ @initial_config[:env] = @initial_env.to_s
262
+
229
263
  # Load the config file if it exists
230
264
  @file_config = load_from_disk || {}
231
265
  merge(file_config)
266
+
232
267
  # Load config from environment variables
233
268
  @env_config = load_from_environment
234
269
  merge(env_config)
270
+ # Track origin of env
271
+ env_loaded_from_env = ENV.fetch("APPSIGNAL_APP_ENV", nil)
272
+ @env_config[:env] = env_loaded_from_env if env_loaded_from_env
273
+
235
274
  # Load config overrides
236
275
  @override_config = determine_overrides
237
276
  merge(override_config)
277
+
238
278
  # Handle deprecated config options
239
279
  maintain_backwards_compatibility
240
- # Validate that we have a correct config
241
- validate
242
- # Track origin of env
243
- @initial_config[:env] = env_loaded_from_initial if env_loaded_from_initial
244
- @env_config[:env] = env_loaded_from_env if env_loaded_from_env
245
280
  end
246
281
 
247
282
  # @api private
@@ -254,6 +289,7 @@ module Appsignal
254
289
  end
255
290
  end
256
291
 
292
+ # @api private
257
293
  def [](key)
258
294
  config_hash[key]
259
295
  end
@@ -360,6 +396,12 @@ module Appsignal
360
396
  ENV["_APP_REVISION"] = config_hash[:revision].to_s
361
397
  end
362
398
 
399
+ # @api private
400
+ def merge_dsl_options(options)
401
+ @dsl_options = options
402
+ merge(options)
403
+ end
404
+
363
405
  # @api private
364
406
  def validate
365
407
  # Strip path from endpoint so we're backwards compatible with
@@ -546,5 +588,81 @@ module Appsignal
546
588
  value = ENV.fetch("APPSIGNAL_INACTIVE_ON_CONFIG_FILE_ERROR", false)
547
589
  ["1", "true"].include?(value)
548
590
  end
591
+
592
+ # @api private
593
+ class ConfigDSL
594
+ attr_reader :dsl_options
595
+
596
+ def initialize(config)
597
+ @config = config
598
+ @dsl_options = {}
599
+ end
600
+
601
+ def app_path
602
+ @config.root_path
603
+ end
604
+
605
+ def app_path=(path)
606
+ @config.root_path = path
607
+ end
608
+
609
+ def env
610
+ @config.env
611
+ end
612
+
613
+ Appsignal::Config::ENV_STRING_KEYS.each_value do |option|
614
+ define_method(option) do
615
+ fetch_option(option)
616
+ end
617
+
618
+ define_method("#{option}=") do |value|
619
+ update_option(option, value.to_s)
620
+ end
621
+ end
622
+
623
+ Appsignal::Config::ENV_BOOLEAN_KEYS.each_value do |option|
624
+ define_method(option) do
625
+ fetch_option(option)
626
+ end
627
+
628
+ define_method("#{option}=") do |value|
629
+ update_option(option, !!value)
630
+ end
631
+ end
632
+
633
+ Appsignal::Config::ENV_ARRAY_KEYS.each_value do |option|
634
+ define_method(option) do
635
+ fetch_option(option)
636
+ end
637
+
638
+ define_method("#{option}=") do |value|
639
+ update_option(option, value.to_a)
640
+ end
641
+ end
642
+
643
+ Appsignal::Config::ENV_FLOAT_KEYS.each_value do |option|
644
+ define_method(option) do
645
+ fetch_option(option)
646
+ end
647
+
648
+ define_method("#{option}=") do |value|
649
+ update_option(option, value.to_f)
650
+ end
651
+ end
652
+
653
+ private
654
+
655
+ def fetch_option(key)
656
+ if @dsl_options.key?(key)
657
+ @dsl_options[key]
658
+ else
659
+ @dsl_options[key] = @config[key].dup
660
+ end
661
+ end
662
+
663
+ def update_option(key, value)
664
+ @dsl_options[key] = value
665
+ end
666
+ end
549
667
  end
550
668
  end
@@ -6,12 +6,7 @@ module Appsignal
6
6
  # {Appsignal::Demo} is a way to send demonstration / test samples for a
7
7
  # exception and a performance issue.
8
8
  #
9
- # @example Loading config automatically
10
- # Appsignal::Demo.transmit
11
- #
12
- # @example With custom config
13
- # # If another configuration should be used, set it beforehand.
14
- # Appsignal.config = Appsignal::Config.new(Dir.pwd, "production")
9
+ # @example Send example transactions
15
10
  # Appsignal::Demo.transmit
16
11
  #
17
12
  # @since 2.0.0
@@ -3,6 +3,13 @@
3
3
  require "appsignal"
4
4
  require "appsignal/rack/grape_middleware"
5
5
 
6
+ Appsignal::Utils::StdoutAndLoggerMessage.warning(
7
+ "The 'require \"appsignal/integrations/grape\"' file require integration " \
8
+ "method is deprecated. " \
9
+ "Please follow the Grape setup guide in our docs for the new method: " \
10
+ "https://docs.appsignal.com/ruby/integrations/grape.html"
11
+ )
12
+
6
13
  Appsignal.internal_logger.debug("Loading Grape integration")
7
14
 
8
15
  module Appsignal
@@ -1,48 +1,13 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require "appsignal"
4
- require "appsignal/rack/hanami_middleware"
5
4
 
6
- module Appsignal
7
- module Integrations
8
- # @api private
9
- module HanamiPlugin
10
- def self.init
11
- Appsignal.internal_logger.debug("Loading Hanami integration")
5
+ Appsignal::Utils::StdoutAndLoggerMessage.warning(
6
+ "The 'require \"appsignal/integrations/hanami\"' file require integration " \
7
+ "method is deprecated. " \
8
+ "Please follow the Hanami setup guide in our docs for the new method: " \
9
+ "https://docs.appsignal.com/ruby/integrations/hanami.html"
10
+ )
12
11
 
13
- hanami_app_config = ::Hanami.app.config
14
-
15
- unless Appsignal.active?
16
- Appsignal.config = Appsignal::Config.new(
17
- hanami_app_config.root || Dir.pwd,
18
- hanami_app_config.env
19
- )
20
- Appsignal.start
21
- end
22
-
23
- return unless Appsignal.active?
24
-
25
- hanami_app_config.middleware.use(
26
- ::Rack::Events,
27
- [Appsignal::Rack::EventHandler.new]
28
- )
29
- hanami_app_config.middleware.use(Appsignal::Rack::HanamiMiddleware)
30
-
31
- ::Hanami::Action.prepend Appsignal::Integrations::HanamiIntegration
32
- end
33
- end
34
-
35
- # @api private
36
- module HanamiIntegration
37
- def call(env)
38
- super
39
- ensure
40
- transaction = env[::Appsignal::Rack::APPSIGNAL_TRANSACTION]
41
-
42
- transaction&.set_action_if_nil(self.class.name)
43
- end
44
- end
45
- end
46
- end
47
-
48
- Appsignal::Integrations::HanamiPlugin.init unless Appsignal.testing?
12
+ Appsignal.load(:hanami)
13
+ Appsignal.start
@@ -1,78 +1,13 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require "appsignal"
4
- require "appsignal/rack/sinatra_instrumentation"
5
4
 
6
- module Appsignal
7
- module Integrations
8
- # @api private
9
- module PadrinoPlugin
10
- def self.init
11
- Padrino::Application.prepend Appsignal::Integrations::PadrinoIntegration
5
+ Appsignal::Utils::StdoutAndLoggerMessage.warning(
6
+ "The 'require \"appsignal/integrations/padrino\"' file require integration " \
7
+ "method is deprecated. " \
8
+ "Please follow the Padrino setup guide in our docs for the new method: " \
9
+ "https://docs.appsignal.com/ruby/integrations/padrino.html"
10
+ )
12
11
 
13
- Padrino.before_load do
14
- Appsignal.internal_logger.debug("Loading Padrino (#{Padrino::VERSION}) integration")
15
-
16
- unless Appsignal.active?
17
- root = Padrino.mounted_root
18
- Appsignal.config = Appsignal::Config.new(root, Padrino.env)
19
- Appsignal.start
20
- end
21
-
22
- next unless Appsignal.active?
23
-
24
- Padrino.use ::Rack::Events, [Appsignal::Rack::EventHandler.new]
25
- Padrino.use Appsignal::Rack::SinatraBaseInstrumentation,
26
- :instrument_event_name => "process_action.padrino"
27
- end
28
- end
29
- end
30
- end
31
- end
32
-
33
- module Appsignal
34
- module Integrations
35
- # @api private
36
- module PadrinoIntegration
37
- def route!(base = settings, pass_block = nil)
38
- return super if !Appsignal.active? || env["sinatra.static_file"]
39
-
40
- begin
41
- super
42
- ensure
43
- transaction = Appsignal::Transaction.current
44
- transaction.set_action_if_nil(get_payload_action(request))
45
- end
46
- end
47
-
48
- private
49
-
50
- def get_payload_action(request)
51
- # Short-circuit is there's no request object to obtain information from
52
- return settings.name.to_s unless request
53
-
54
- # Newer versions expose the action / controller on the request class.
55
- # Newer versions also still expose a route_obj so we must prioritize the
56
- # action/fullpath methods.
57
- # The `request.action` and `request.controller` values are `nil` when a
58
- # endpoint is not found, `""` if not specified by the user.
59
- controller_name = request.controller if request.respond_to?(:controller)
60
- action_name = request.action if request.respond_to?(:action)
61
- action_name ||= ""
62
-
63
- return "#{settings.name}:#{controller_name}##{action_name}" unless action_name.empty?
64
-
65
- # Older versions of Padrino work with a route object
66
- if request.respond_to?(:route_obj) && request.route_obj
67
- return "#{settings.name}:#{request.route_obj.original_path}"
68
- end
69
-
70
- # Fall back to the application name if we haven't found an action name in
71
- # any previous methods.
72
- "#{settings.name}#unknown"
73
- end
74
- end
75
- end
76
- end
77
-
78
- Appsignal::Integrations::PadrinoPlugin.init
12
+ Appsignal.load(:padrino)
13
+ Appsignal.start
@@ -9,23 +9,49 @@ module Appsignal
9
9
  module Integrations
10
10
  # @api private
11
11
  class Railtie < ::Rails::Railtie
12
+ config.appsignal = ActiveSupport::OrderedOptions.new
13
+ config.appsignal.start_at = :on_load
14
+
15
+ # Run after the Rails framework is loaded
12
16
  initializer "appsignal.configure_rails_initialization" do |app|
13
- Appsignal::Integrations::Railtie.initialize_appsignal(app)
17
+ Appsignal::Integrations::Railtie.on_load(app)
18
+ end
19
+
20
+ # Run after the Rails app's initializers are run
21
+ config.after_initialize do |app|
22
+ Appsignal::Integrations::Railtie.after_initialize(app)
14
23
  end
15
24
 
16
25
  console do
17
26
  Appsignal::Probes.stop
18
27
  end
19
28
 
20
- def self.initialize_appsignal(app)
21
- # Load config
22
- Appsignal.config = Appsignal::Config.new(
23
- Rails.root,
24
- Rails.env,
25
- :name => Appsignal::Utils::RailsHelper.detected_rails_app_name,
26
- :log_path => Rails.root.join("log")
27
- )
29
+ def self.on_load(app)
30
+ Appsignal::Integrations::Railtie.add_instrumentation_middleware(app)
31
+
32
+ return unless app.config.appsignal.start_at == :on_load
33
+
34
+ Appsignal::Integrations::Railtie.start
35
+ end
36
+
37
+ def self.after_initialize(app)
38
+ Appsignal::Integrations::Railtie.start if app.config.appsignal.start_at == :after_initialize
39
+ end
28
40
 
41
+ def self.start
42
+ unless Appsignal.config
43
+ Appsignal._config = Appsignal::Config.new(
44
+ Rails.root,
45
+ Rails.env,
46
+ :name => Appsignal::Utils::RailsHelper.detected_rails_app_name,
47
+ :log_path => Rails.root.join("log")
48
+ )
49
+ end
50
+ Appsignal.start
51
+ initialize_error_reporter
52
+ end
53
+
54
+ def self.add_instrumentation_middleware(app)
29
55
  app.middleware.insert(
30
56
  0,
31
57
  ::Rack::Events,
@@ -35,10 +61,6 @@ module Appsignal
35
61
  ActionDispatch::DebugExceptions,
36
62
  Appsignal::Rack::RailsInstrumentation
37
63
  )
38
-
39
- Appsignal.start
40
-
41
- initialize_error_reporter
42
64
  end
43
65
 
44
66
  def self.initialize_error_reporter
@@ -1,24 +1,13 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require "appsignal"
4
- require "appsignal/rack/sinatra_instrumentation"
5
4
 
6
- Appsignal.internal_logger.debug("Loading Sinatra (#{Sinatra::VERSION}) integration")
5
+ Appsignal::Utils::StdoutAndLoggerMessage.warning(
6
+ "The 'require \"appsignal/integrations/sinatra\"' file require integration " \
7
+ "method is deprecated. " \
8
+ "Please follow the Sinatra setup guide in our docs for the new method: " \
9
+ "https://docs.appsignal.com/ruby/integrations/sinatra.html"
10
+ )
7
11
 
8
- unless Appsignal.active?
9
- app_settings = ::Sinatra::Application.settings
10
- Appsignal.config = Appsignal::Config.new(
11
- app_settings.root || Dir.pwd,
12
- app_settings.environment
13
- )
14
-
15
- Appsignal.start
16
- end
17
-
18
- if Appsignal.active?
19
- ::Sinatra::Base.use(
20
- ::Rack::Events,
21
- [Appsignal::Rack::EventHandler.new]
22
- )
23
- ::Sinatra::Base.use(Appsignal::Rack::SinatraBaseInstrumentation)
24
- end
12
+ Appsignal.load(:sinatra)
13
+ Appsignal.start