appsignal 4.1.3 → 4.2.0

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: 8a441bb8864121c2d1270a87f385ad98d6942e02705d640b02e39ecd4f4f429d
4
- data.tar.gz: bffc65fe34303b5396b2d08df716022897dcdb98c36a627d7a63fe389210568f
3
+ metadata.gz: 83c3f6a3607f3e28d1b95b790b1eec081673e596db8ed02a868bc31eb54fe884
4
+ data.tar.gz: a2f57f3c3604fb05953949114cf2e3a315c0ab61af40c0d50ee59a2a0c23a87a
5
5
  SHA512:
6
- metadata.gz: 8fb41c8fef25b7c9d16a7cbae97c974abab53c754baedc1336e74064139f4c7e286c9ef5c1bf0fef386482f82199327f6576345dbe416cf10c4b200ec698ecd8
7
- data.tar.gz: de587e5a60a63385ff740cccc6bef444e3bf18abb9fb3580af2f5a16f70cd58bd64897e2b0e79851c6c1ed68658b219c25c7b54eb129b8c40ad3a87d7bd348ea
6
+ metadata.gz: 108fd4431a1fd08f619ff084b8304dddd25bfc1cadf218265bdc12f7dc3e7609a551daa2b6e1a9c433dcdca5a51bccf5c916be12700bdd880b03aca422d03ca0
7
+ data.tar.gz: 1243f5f9894c7c7750bbd991a4e9dc7b6b8c5d80f4fd68e77798cccb97b41dc7efd7039e4e3176178f9fda0804c67643f2770098d34ff8c4105f8005320a6799
data/CHANGELOG.md CHANGED
@@ -1,5 +1,126 @@
1
1
  # AppSignal for Ruby gem Changelog
2
2
 
3
+ ## 4.2.0
4
+
5
+ _Published on 2024-11-13._
6
+
7
+ ### Added
8
+
9
+ - Add `config/appsignal.rb` config file support. When a `config/appsignal.rb` file is present in the app, the Ruby gem will automatically load it when `Appsignal.start` is called.
10
+
11
+ The `config/appsignal.rb` config file is a replacement for the `config/appsignal.yml` config file. When both files are present, only the `config/appsignal.rb` config file is loaded when the configuration file is automatically loaded by AppSignal when the configuration file is automatically loaded by AppSignal.
12
+
13
+ Example `config/appsignal.rb` config file:
14
+
15
+ ```ruby
16
+ # config/appsignal.rb
17
+ Appsignal.configure do |config|
18
+ config.name = "My app name"
19
+ end
20
+ ```
21
+
22
+ To configure different option values for environments in the `config/appsignal.rb` config file, use if-statements:
23
+
24
+ ```ruby
25
+ # config/appsignal.rb
26
+ Appsignal.configure do |config|
27
+ config.name = "My app name"
28
+ if config.env == "production"
29
+ config.ignore_actions << "My production action"
30
+ end
31
+ if config.env == "staging"
32
+ config.ignore_actions << "My staging action"
33
+ end
34
+ end
35
+ ```
36
+
37
+ (minor [f81248bc](https://github.com/appsignal/appsignal-ruby/commit/f81248bc9c557197a0dd123c6d5958f21c11af9d), [48d16c7a](https://github.com/appsignal/appsignal-ruby/commit/48d16c7ab4dbc35ac3d56ecf042ca165d609bb64))
38
+ - Add the `config/appsignal.rb` Ruby config file method to installer, `appsignal install`. (patch [0d2e2bde](https://github.com/appsignal/appsignal-ruby/commit/0d2e2bde5da510f0d339673cdcdb9f79030acf59))
39
+ - Add `Appsignal.set_empty_params!` helper method. This helper method can be used to unset parameters on a transaction and to prevent the Appsignal instrumentation from adding parameters to a transaction.
40
+
41
+ Example usage:
42
+
43
+ ```ruby
44
+ class PaymentsController < ApplicationController
45
+ def create
46
+ Appsignal.set_empty_params!
47
+
48
+ # Do things with sensitive parameters
49
+ end
50
+ end
51
+ ```
52
+
53
+ When `Appsignal.add_params` is called afterward, the "empty parameters" state is cleared and any AppSignal instrumentation (if called afterward) will also add parameters again.
54
+
55
+ ```ruby
56
+ # Example: Unset parameters when set
57
+ Appsignal.add_params("abc" => "def")
58
+ # Parameters: { "abc" => "def" }
59
+ Appsignal.set_empty_params!
60
+ # Parameters: {}
61
+
62
+ # Example: When AppSignal instrumentation sets parameters:
63
+ Appsignal.set_empty_params!
64
+ # Parameters: {}
65
+ # Pseudo example code:
66
+ Appsignal::Instrumentation::SomeLibrary.new.add_params("xyz" => "...")
67
+ # Parameters: {}
68
+
69
+ # Example: Set parameters after them being unset previously
70
+ Appsignal.set_empty_params!
71
+ # Parameters: {}
72
+ Appsignal.add_params("abc" => "def")
73
+ # Parameters: { "abc" => "def" }
74
+ ```
75
+
76
+ (patch [20a8050e](https://github.com/appsignal/appsignal-ruby/commit/20a8050e63605f08e9377dda84b3a422810dd49a), [23627cd7](https://github.com/appsignal/appsignal-ruby/commit/23627cd7e7c2b2939c43701228e77aa14eae5c68))
77
+ - Add `Appsignal.configure` context `env?` helper method. Check if the loaded environment matches the given environment using the `.env?(:env_name)` helper.
78
+
79
+ Example:
80
+
81
+ ```ruby
82
+ Appsignal.configure do |config|
83
+ # Symbols work as the argument
84
+ if config.env?(:production)
85
+ config.ignore_actions << "My production action"
86
+ end
87
+
88
+ # Strings also work as the argument
89
+ if config.env?("staging")
90
+ config.ignore_actions << "My staging action"
91
+ end
92
+ end
93
+ ```
94
+
95
+ (patch [8b234cae](https://github.com/appsignal/appsignal-ruby/commit/8b234caee4c29f9550c4dc77d02ebd21f8dbfa30))
96
+ - Allow for default attributes to be given when initialising a `Logger` instance:
97
+
98
+ ```ruby
99
+ order_logger = Appsignal::Logger.new("app", attributes: { order_id: 123 })
100
+ ```
101
+
102
+ All log lines reported by this logger will contain the given attribute. Attributes given when reporting the log line will be merged with the default attributes for the logger, with those in the log line taking priority.
103
+
104
+ (patch [27e05af6](https://github.com/appsignal/appsignal-ruby/commit/27e05af6cb1e1ebca1fd6e8038da290f42db2bdb), [8be7c791](https://github.com/appsignal/appsignal-ruby/commit/8be7c7912eea4d3df74f1ca8808b7d6e8802f550))
105
+
106
+ ### Changed
107
+
108
+ - Read the Hanami Action name without metaprogramming in Hanami 2.2 and newer. This makes our instrumentation more stable whenever something changes in future Hanami releases. (patch [c6848504](https://github.com/appsignal/appsignal-ruby/commit/c68485043feee13a49400f57c9a77d48f670f0f2))
109
+ - Ignore these Hanami errors by default:
110
+
111
+ - Hanami::Router::NotAllowedError (for example: sending a GET request to POST endpoint)
112
+ - Hanami::Router::NotFoundError
113
+
114
+ They are usually errors you don't want to be notified about, so we ignore them by default now.
115
+
116
+ Customize the `ignore_errors` config option to continue receiving these errors.
117
+
118
+ (patch [f1500987](https://github.com/appsignal/appsignal-ruby/commit/f1500987b7b73ab2873202ea7301f2cfb19acdc7))
119
+
120
+ ### Fixed
121
+
122
+ - Fix request parameter reporting for Hanami 2.2. (patch [ca22ed54](https://github.com/appsignal/appsignal-ruby/commit/ca22ed54de513773c5ee387f28ad98ee8f301627))
123
+
3
124
  ## 4.1.3
4
125
 
5
126
  _Published on 2024-11-07._
data/build_matrix.yml CHANGED
@@ -85,6 +85,7 @@ matrix:
85
85
  - "rails-7.0"
86
86
  - "rails-7.1"
87
87
  - "rails-7.2"
88
+ - "rails-8.0"
88
89
 
89
90
  ruby:
90
91
  - ruby: "3.3.4"
@@ -120,6 +121,12 @@ matrix:
120
121
  - "3.2.5"
121
122
  - "3.1.6"
122
123
  - "3.0.7"
124
+ - gem: "hanami-2.2"
125
+ only:
126
+ ruby:
127
+ - "3.3.4"
128
+ - "3.2.5"
129
+ - "3.1.6"
123
130
  - gem: "http5"
124
131
  - gem: "padrino"
125
132
  - gem: "psych-3"
@@ -179,6 +186,11 @@ matrix:
179
186
  - "3.2.5"
180
187
  - "3.1.6"
181
188
  - "jruby-9.4.7.0"
189
+ - gem: "rails-8.0"
190
+ only:
191
+ ruby:
192
+ - "3.3.4"
193
+ - "3.2.5"
182
194
  - gem: "sequel"
183
195
  - gem: "sinatra"
184
196
  - gem: "webmachine2"
@@ -188,15 +188,16 @@ module Appsignal
188
188
  end
189
189
 
190
190
  def configure_appsignal(options)
191
+ env_option = options.fetch(:environment, nil)
191
192
  # Try and load the Rails app, if any.
192
193
  # This will configure AppSignal through the config file or an
193
194
  # initializer.
194
- require_rails_app_if_present
195
+ require_rails_app_if_present(env_option)
195
196
 
196
- # If no config was found by loading the app, load with the defaults.
197
- Appsignal.configure(options.fetch(:environment, nil))
198
- Appsignal.config.write_to_environment
197
+ # No config loaded yet, try loading as normal
198
+ Appsignal._load_config!(env_option) unless Appsignal.config
199
199
  Appsignal._start_logger
200
+ Appsignal.config.write_to_environment
200
201
  Appsignal.internal_logger.info("Starting AppSignal diagnose")
201
202
  end
202
203
 
@@ -631,9 +632,12 @@ module Appsignal
631
632
  puts "\n"
632
633
  end
633
634
 
634
- def require_rails_app_if_present
635
+ def require_rails_app_if_present(env_option)
635
636
  return unless rails_present?
636
637
 
638
+ # Set the environment given as an option to the diagnose CLI so the
639
+ # Rails app uses it when loaded.
640
+ ENV["_APPSIGNAL_CONFIG_FILE_ENV"] = env_option
637
641
  # Mark app as Rails app
638
642
  data[:app][:rails] = true
639
643
  # Manually require the railtie, because it wasn't loaded when the CLI
@@ -649,6 +653,8 @@ module Appsignal
649
653
  puts error.backtrace
650
654
  data[:app][:load_error] =
651
655
  "#{error.class}: #{error.message}\n#{error.backtrace.join("\n")}"
656
+ ensure
657
+ ENV.delete("_APPSIGNAL_CONFIG_FILE_ENV")
652
658
  end
653
659
 
654
660
  def rails_present?
@@ -229,35 +229,49 @@ module Appsignal
229
229
  done_notice
230
230
  end
231
231
 
232
- def configure(config, environments, name_overwritten)
232
+ def configure(config, environments, name_overwritten) # rubocop:disable Metrics/AbcSize
233
233
  install_for_capistrano
234
234
 
235
235
  ENV["APPSIGNAL_APP_ENV"] = "development"
236
236
 
237
237
  puts "How do you want to configure AppSignal?"
238
- puts " (1) a config file"
239
- puts " (2) environment variables"
238
+ puts " (1) a Ruby config file"
239
+ puts " (2) a YAML config file (legacy)"
240
+ puts " (3) environment variables"
240
241
  puts
241
242
  puts " See our docs for information on the different configuration methods: "
242
243
  puts " https://docs.appsignal.com/ruby/configuration.html"
243
244
  puts
244
- loop do
245
- print " Choose (1/2): "
245
+ loop do # rubocop:disable Metrics/BlockLength
246
+ print " Choose (1-3): "
246
247
  case ask_for_input
247
248
  when "1"
248
249
  puts
249
- print "Writing config file"
250
+ print "Writing Ruby config file"
250
251
  periods
251
252
  puts
252
- puts colorize " Config file written to config/appsignal.yml", :green
253
- write_config_file(
253
+ write_ruby_config_file(
254
254
  :push_api_key => config[:push_api_key],
255
255
  :app_name => config[:name],
256
256
  :environments => environments
257
257
  )
258
+ puts colorize " Config file written to config/appsignal.rb", :green
258
259
  puts
259
260
  break
260
261
  when "2"
262
+ puts
263
+ print "Writing YAML config file"
264
+ periods
265
+ puts
266
+ write_yaml_config_file(
267
+ :push_api_key => config[:push_api_key],
268
+ :app_name => config[:name],
269
+ :environments => environments
270
+ )
271
+ puts colorize " Config file written to config/appsignal.yml", :green
272
+ puts
273
+ break
274
+ when "3"
261
275
  ENV["APPSIGNAL_ACTIVE"] = "true"
262
276
  ENV["APPSIGNAL_PUSH_API_KEY"] = config[:push_api_key]
263
277
  ENV["APPSIGNAL_APP_NAME"] = config[:name]
@@ -325,17 +339,37 @@ module Appsignal
325
339
  ).map { |o| File.basename(o, ".rb") }.sort - EXCLUDED_ENVIRONMENTS
326
340
  end
327
341
 
328
- def write_config_file(data)
329
- filename = File.join(
342
+ def write_ruby_config_file(data)
343
+ template = File.join(
344
+ File.dirname(__FILE__),
345
+ "../../../resources/appsignal.rb.erb"
346
+ )
347
+ write_config_file(
348
+ template,
349
+ File.join(Dir.pwd, "config/appsignal.rb"),
350
+ data
351
+ )
352
+ end
353
+
354
+ def write_yaml_config_file(data)
355
+ template = File.join(
330
356
  File.dirname(__FILE__),
331
357
  "../../../resources/appsignal.yml.erb"
332
358
  )
333
- file_contents = File.read(filename)
359
+ write_config_file(
360
+ template,
361
+ File.join(Dir.pwd, "config/appsignal.yml"),
362
+ data
363
+ )
364
+ end
365
+
366
+ def write_config_file(template_path, path, data)
367
+ file_contents = File.read(template_path)
334
368
  template = ERB.new(file_contents, :trim_mode => "-")
335
369
  config = template.result(OpenStruct.new(data).instance_eval { binding })
336
370
 
337
371
  FileUtils.mkdir_p(File.join(Dir.pwd, "config"))
338
- File.write(File.join(Dir.pwd, "config/appsignal.yml"), config)
372
+ File.write(path, config)
339
373
  end
340
374
 
341
375
  def new_config
@@ -35,6 +35,7 @@ module Appsignal
35
35
  def self.determine_env(initial_env = nil)
36
36
  [
37
37
  initial_env,
38
+ ENV.fetch("_APPSIGNAL_CONFIG_FILE_ENV", nil), # PRIVATE ENV var used by the diagnose CLI
38
39
  ENV.fetch("APPSIGNAL_APP_ENV", nil),
39
40
  ENV.fetch("RAILS_ENV", nil),
40
41
  ENV.fetch("RACK_ENV", nil)
@@ -53,6 +54,9 @@ module Appsignal
53
54
  # Determine which root path AppSignal should initialize with.
54
55
  # @api private
55
56
  def self.determine_root_path
57
+ app_path_env_var = ENV.fetch("APPSIGNAL_APP_PATH", nil)
58
+ return app_path_env_var if app_path_env_var
59
+
56
60
  loader_defaults.reverse.each do |loader_defaults|
57
61
  root_path = loader_defaults[:root_path]
58
62
  return root_path if root_path
@@ -61,6 +65,26 @@ module Appsignal
61
65
  Dir.pwd
62
66
  end
63
67
 
68
+ # @api private
69
+ class Context
70
+ DSL_FILENAME = "config/appsignal.rb"
71
+
72
+ attr_reader :env, :root_path
73
+
74
+ def initialize(env: nil, root_path: nil)
75
+ @env = env
76
+ @root_path = root_path
77
+ end
78
+
79
+ def dsl_config_file
80
+ File.join(root_path, DSL_FILENAME)
81
+ end
82
+
83
+ def dsl_config_file?
84
+ File.exist?(dsl_config_file)
85
+ end
86
+ end
87
+
64
88
  # @api private
65
89
  DEFAULT_CONFIG = {
66
90
  :activejob_report_errors => "all",
@@ -213,8 +237,10 @@ module Appsignal
213
237
  # How to integrate AppSignal manually
214
238
  def initialize(
215
239
  root_path,
216
- env
240
+ env,
241
+ load_yaml_file: true
217
242
  )
243
+ @load_yaml_file = load_yaml_file
218
244
  @root_path = root_path.to_s
219
245
  @config_file_error = false
220
246
  @config_file = config_file
@@ -269,8 +295,20 @@ module Appsignal
269
295
  @initial_config[:env] = @env
270
296
 
271
297
  # Load the config file if it exists
272
- @file_config = load_from_disk || {}
273
- merge(file_config)
298
+ if @load_yaml_file
299
+ @file_config = load_from_disk || {}
300
+ merge(file_config)
301
+ elsif yml_config_file?
302
+ # When in a `config/appsignal.rb` file and it detects a
303
+ # `config/appsignal.yml` file.
304
+ # Only logged and printed on `Appsignal.start`.
305
+ message = "Both a Ruby and YAML configuration file are found. " \
306
+ "The `config/appsignal.yml` file is ignored when the " \
307
+ "config is loaded from `config/appsignal.rb`. Move all config to " \
308
+ "the `config/appsignal.rb` file and remove the " \
309
+ "`config/appsignal.yml` file."
310
+ Appsignal::Utils::StdoutAndLoggerMessage.warning(message)
311
+ end
274
312
 
275
313
  # Load config from environment variables
276
314
  @env_config = load_from_environment
@@ -435,6 +473,13 @@ module Appsignal
435
473
  config_hash.transform_values(&:freeze)
436
474
  end
437
475
 
476
+ # @api private
477
+ def yml_config_file?
478
+ return false unless config_file
479
+
480
+ File.exist?(config_file)
481
+ end
482
+
438
483
  private
439
484
 
440
485
  def logger
@@ -458,7 +503,7 @@ module Appsignal
458
503
  end
459
504
 
460
505
  def load_from_disk
461
- return if !config_file || !File.exist?(config_file)
506
+ return unless yml_config_file?
462
507
 
463
508
  read_options = YAML::VERSION >= "4.0.0" ? { :aliases => true } : {}
464
509
  configurations = YAML.load(ERB.new(File.read(config_file)).result, **read_options)
@@ -564,6 +609,15 @@ module Appsignal
564
609
  @config.env
565
610
  end
566
611
 
612
+ # Returns true if the given environment name matches the loaded
613
+ # environment name.
614
+ #
615
+ # @param given_env [String, Symbol]
616
+ # @return [TrueClass, FalseClass]
617
+ def env?(given_env)
618
+ env == given_env.to_s
619
+ end
620
+
567
621
  def activate_if_environment(*envs)
568
622
  self.active = envs.map(&:to_s).include?(env)
569
623
  end
@@ -80,7 +80,7 @@ module Appsignal
80
80
 
81
81
  # Logging methods
82
82
  attach_function :appsignal_log,
83
- [:appsignal_string, :int32, :appsignal_string, :pointer],
83
+ [:appsignal_string, :int32, :int32, :appsignal_string, :pointer],
84
84
  :void
85
85
 
86
86
  # Transaction methods
@@ -273,10 +273,11 @@ module Appsignal
273
273
  make_ruby_string state if state[:len] > 0
274
274
  end
275
275
 
276
- def log(group, level, message, attributes)
276
+ def log(group, level, format, message, attributes)
277
277
  appsignal_log(
278
278
  make_appsignal_string(group),
279
279
  level,
280
+ format,
280
281
  make_appsignal_string(message),
281
282
  attributes.pointer
282
283
  )
@@ -556,11 +556,20 @@ module Appsignal
556
556
 
557
557
  # Mark the parameters sample data to be set as an empty value.
558
558
  #
559
- # @api private
560
- # @since 4.0.0
559
+ # Use this helper to unset request parameters / background job arguments
560
+ # and not report any for this transaction.
561
+ #
562
+ # If parameters would normally be added by AppSignal instrumentations of
563
+ # libraries, these parameters will not be added to the Transaction.
564
+ #
565
+ # Calling {#add_params} after this helper will add new parameters to the
566
+ # transaction.
567
+ #
568
+ # @since 4.2.0
561
569
  # @return [void]
562
570
  #
563
- # @see Helpers::Instrumentation#set_empty_params!
571
+ # @see Transaction#set_empty_params!
572
+ # @see Transaction#set_params_if_nil
564
573
  def set_empty_params!
565
574
  return unless active?
566
575
  return unless Appsignal::Transaction.current?
@@ -9,7 +9,11 @@ module Appsignal
9
9
  hanami_app_config = ::Hanami.app.config
10
10
  register_config_defaults(
11
11
  :root_path => hanami_app_config.root.to_s,
12
- :env => hanami_app_config.env
12
+ :env => hanami_app_config.env,
13
+ :ignore_errors => [
14
+ "Hanami::Router::NotAllowedError",
15
+ "Hanami::Router::NotFoundError"
16
+ ]
13
17
  )
14
18
  end
15
19
 
@@ -23,9 +27,12 @@ module Appsignal
23
27
  )
24
28
  hanami_app_config.middleware.use(Appsignal::Rack::HanamiMiddleware)
25
29
 
30
+ return unless Gem::Version.new(Hanami::VERSION) < Gem::Version.new("2.2.0")
31
+
26
32
  ::Hanami::Action.prepend Appsignal::Loaders::HanamiLoader::HanamiIntegration
27
33
  end
28
34
 
35
+ # Legacy instrumentation to set the action name in Hanami apps older than Hanami 2.2
29
36
  module HanamiIntegration
30
37
  def call(env)
31
38
  super
@@ -25,15 +25,18 @@ module Appsignal
25
25
  # Create a new logger instance
26
26
  #
27
27
  # @param group Name of the group for this logger.
28
- # @param level Log level to filter with
28
+ # @param level Minimum log level to report. Log lines below this level will be ignored.
29
+ # @param format Format to use to parse log line attributes.
30
+ # @param attributes Default attributes for all log lines.
29
31
  # @return [void]
30
- def initialize(group, level: INFO, format: PLAINTEXT)
32
+ def initialize(group, level: INFO, format: PLAINTEXT, attributes: {})
31
33
  raise TypeError, "group must be a string" unless group.is_a? String
32
34
 
33
35
  @group = group
34
36
  @level = level
35
37
  @format = format
36
38
  @mutex = Mutex.new
39
+ @default_attributes = attributes
37
40
  end
38
41
 
39
42
  # We support the various methods in the Ruby
@@ -156,8 +159,10 @@ module Appsignal
156
159
 
157
160
  private
158
161
 
162
+ attr_reader :default_attributes
163
+
159
164
  def add_with_attributes(severity, message, group, attributes)
160
- Thread.current[:appsignal_logger_attributes] = attributes
165
+ Thread.current[:appsignal_logger_attributes] = default_attributes.merge(attributes)
161
166
  add(severity, message, group)
162
167
  ensure
163
168
  Thread.current[:appsignal_logger_attributes] = nil
@@ -12,12 +12,25 @@ module Appsignal
12
12
 
13
13
  private
14
14
 
15
+ HANAMI_ACTION_INSTANCE = "hanami.action_instance"
16
+ ROUTER_PARAMS = "router.params"
17
+
15
18
  def add_transaction_metadata_after(transaction, request)
19
+ action_name = fetch_hanami_action(request.env)
20
+ transaction.set_action_if_nil(action_name) if action_name
16
21
  transaction.add_params { params_for(request) }
17
22
  end
18
23
 
19
24
  def params_for(request)
20
- ::Hanami::Action.params_class.new(request.env).to_h
25
+ request.env.fetch(ROUTER_PARAMS, nil)
26
+ end
27
+
28
+ def fetch_hanami_action(env)
29
+ # This env key is available in Hanami 2.2+
30
+ action_instance = env.fetch(HANAMI_ACTION_INSTANCE, nil)
31
+ return unless action_instance
32
+
33
+ action_instance.class.name
21
34
  end
22
35
  end
23
36
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Appsignal
4
- VERSION = "4.1.3"
4
+ VERSION = "4.2.0"
5
5
  end
data/lib/appsignal.rb CHANGED
@@ -103,6 +103,13 @@ module Appsignal
103
103
  return
104
104
  end
105
105
 
106
+ if config_file_context?
107
+ internal_logger.warn(
108
+ "Ignoring call to Appsignal.start in config file context."
109
+ )
110
+ return
111
+ end
112
+
106
113
  unless extension_loaded?
107
114
  internal_logger.info("Not starting AppSignal, extension is not loaded")
108
115
  return
@@ -110,9 +117,7 @@ module Appsignal
110
117
 
111
118
  internal_logger.debug("Loading AppSignal gem")
112
119
 
113
- @config ||= Config.new(Config.determine_root_path, Config.determine_env)
114
- @config.validate
115
-
120
+ _load_config!
116
121
  _start_logger
117
122
 
118
123
  if config.valid?
@@ -142,6 +147,41 @@ module Appsignal
142
147
  end
143
148
  end
144
149
 
150
+ # PRIVATE METHOD. DO NOT USE.
151
+ #
152
+ # @param env_var [String, NilClass] Used by diagnose CLI to pass through
153
+ # the environment CLI option value.
154
+ # @api private
155
+ def _load_config!(env_param = nil)
156
+ context = Appsignal::Config::Context.new(
157
+ :env => Config.determine_env(env_param),
158
+ :root_path => Config.determine_root_path
159
+ )
160
+ # If there's a config/appsignal.rb file
161
+ if context.dsl_config_file?
162
+ if config
163
+ # When calling `Appsignal.configure` from an app, not the
164
+ # `config/appsignal.rb` file, with also a Ruby config file present.
165
+ message = "The `Appsignal.configure` helper is called from within an " \
166
+ "app while a `#{context.dsl_config_file}` file is present. " \
167
+ "The `config/appsignal.rb` file is ignored when the " \
168
+ "config is loaded with `Appsignal.configure` from within an app. " \
169
+ "We recommend moving all config to the `config/appsignal.rb` file " \
170
+ "or the `Appsignal.configure` helper in the app."
171
+ Appsignal::Utils::StdoutAndLoggerMessage.warning(message)
172
+ else
173
+ # Load it when no config is present
174
+ load_dsl_config_file(context.dsl_config_file, env_param)
175
+ end
176
+ else
177
+ # Load config if no config file was found and no config is present yet
178
+ # This will load the config/appsignal.yml file automatically
179
+ @config ||= Config.new(context.root_path, context.env)
180
+ end
181
+ # Validate the config, if present
182
+ config&.validate
183
+ end
184
+
145
185
  # Stop AppSignal's agent.
146
186
  #
147
187
  # Stops the AppSignal agent. Call this before the end of your program to
@@ -222,7 +262,7 @@ module Appsignal
222
262
  # # Or for the environment given as an argument
223
263
  # Appsignal.configure(:production)
224
264
  #
225
- # @param env [String, Symbol] The environment to load.
265
+ # @param env_param [String, Symbol] The environment to load.
226
266
  # @param root_path [String] The path to look the `config/appsignal.yml` config file in.
227
267
  # Defaults to the current working directory.
228
268
  # @yield [Config] Gives the {Config} instance to the block.
@@ -244,10 +284,28 @@ module Appsignal
244
284
  else
245
285
  @config = Config.new(
246
286
  root_path_param || Config.determine_root_path,
247
- Config.determine_env(env_param)
287
+ Config.determine_env(env_param),
288
+ # If in the context of an `config/appsignal.rb` config file, do not
289
+ # load the `config/appsignal.yml` file.
290
+ # The `.rb` file is a replacement for the `.yml` file so it shouldn't
291
+ # load both.
292
+ :load_yaml_file => !config_file_context?
248
293
  )
249
294
  end
250
295
 
296
+ # When calling `Appsignal.configure` from a Rails initializer and a YAML
297
+ # file is present. We will not load the YAML file in the future.
298
+ if !config_file_context? && config.yml_config_file?
299
+ message = "The `Appsignal.configure` helper is called while a " \
300
+ "`config/appsignal.yml` file is present. In future versions the " \
301
+ "`config/appsignal.yml` file will be ignored when loading the " \
302
+ "config. We recommend moving all config to the " \
303
+ "`config/appsignal.rb` file, or the `Appsignal.configure` helper " \
304
+ "in Rails initializer file, and remove the " \
305
+ "`config/appsignal.yml` file."
306
+ Appsignal::Utils::StdoutAndLoggerMessage.warning(message)
307
+ end
308
+
251
309
  config_dsl = Appsignal::Config::ConfigDSL.new(config)
252
310
  return unless block_given?
253
311
 
@@ -397,6 +455,11 @@ module Appsignal
397
455
  config&.active? && extension_loaded?
398
456
  end
399
457
 
458
+ # @api private
459
+ def dsl_config_file_loaded?
460
+ defined?(@dsl_config_file_loaded) ? true : false
461
+ end
462
+
400
463
  private
401
464
 
402
465
  def params_match_loaded_config?(env_param, root_path_param)
@@ -408,6 +471,52 @@ module Appsignal
408
471
  (root_path_param.nil? || config.root_path == root_path_param)
409
472
  end
410
473
 
474
+ # Load the `config/appsignal.rb` config file, if present.
475
+ #
476
+ # If the config file has already been loaded once and it's trying to be
477
+ # loaded more than once, which should never happen, it will not do
478
+ # anything.
479
+ def load_dsl_config_file(path, env_param = nil)
480
+ return if defined?(@dsl_config_file_loaded)
481
+
482
+ begin
483
+ ENV["_APPSIGNAL_CONFIG_FILE_CONTEXT"] = "true"
484
+ ENV["_APPSIGNAL_CONFIG_FILE_ENV"] = env_param if env_param
485
+ @dsl_config_file_loaded = true
486
+ require path
487
+ rescue => error
488
+ @config_file_error = error
489
+ message = "Not starting AppSignal because an error occurred while " \
490
+ "loading the AppSignal config file.\n" \
491
+ "File: #{path.inspect}\n" \
492
+ "#{error.class.name}: #{error}"
493
+ Kernel.warn "appsignal ERROR: #{message}"
494
+ internal_logger.error "#{message}\n#{error.backtrace.join("\n")}"
495
+ ensure
496
+ unless Appsignal.config
497
+ # Ensure _a config object_ is present, even if something went wrong
498
+ # loading it or the file is empty. In this config file context, see
499
+ # the context env vars, it will intentionally not load the YAML file.
500
+ Appsignal.configure
501
+
502
+ # Disable if no config was loaded from the file but it is present
503
+ config[:active] = false
504
+ end
505
+
506
+ # Disable on config file error
507
+ config[:active] = false if defined?(@config_file_error)
508
+
509
+ ENV.delete("_APPSIGNAL_CONFIG_FILE_CONTEXT")
510
+ ENV.delete("_APPSIGNAL_CONFIG_FILE_ENV")
511
+ end
512
+ end
513
+
514
+ # Returns true if we're currently in the `config/appsignal.rb` file
515
+ # context.
516
+ def config_file_context?
517
+ ENV.fetch("_APPSIGNAL_CONFIG_FILE_CONTEXT", nil) == "true"
518
+ end
519
+
411
520
  def start_internal_stdout_logger
412
521
  @internal_logger = Appsignal::Utils::IntegrationLogger.new($stdout)
413
522
  internal_logger.formatter = log_formatter("appsignal")
@@ -0,0 +1,22 @@
1
+ # AppSignal Ruby gem configuration
2
+ # Visit our documentation for a list of all available configuration options.
3
+ # https://docs.appsignal.com/ruby/configuration/options.html
4
+ Appsignal.configure do |config|
5
+ config.activate_if_environment(<%= environments.map(&:inspect).join(", ") %>)
6
+ config.name = <%= app_name.inspect %>
7
+ # The application's Push API key
8
+ # We recommend removing this line and setting this option with the
9
+ # APPSIGNAL_PUSH_API_KEY environment variable instead.
10
+ # https://docs.appsignal.com/ruby/configuration/options.html#option-push_api_key
11
+ config.push_api_key = "<%= push_api_key %>"
12
+
13
+ # Configure actions that should not be monitored by AppSignal.
14
+ # For more information see our docs:
15
+ # https://docs.appsignal.com/ruby/configuration/ignore-actions.html
16
+ # config.ignore_actions << "ApplicationController#isup"
17
+
18
+ # Configure errors that should not be recorded by AppSignal.
19
+ # For more information see our docs:
20
+ # https://docs.appsignal.com/ruby/configuration/ignore-errors.html
21
+ # config.ignore_errors << "MyCustomError"
22
+ end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: appsignal
3
3
  version: !ruby/object:Gem::Version
4
- version: 4.1.3
4
+ version: 4.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Robert Beekman
@@ -10,7 +10,7 @@ authors:
10
10
  autorequire:
11
11
  bindir: bin
12
12
  cert_chain: []
13
- date: 2024-11-07 00:00:00.000000000 Z
13
+ date: 2024-11-13 00:00:00.000000000 Z
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
16
16
  name: logger
@@ -284,6 +284,7 @@ files:
284
284
  - lib/appsignal/version.rb
285
285
  - lib/puma/plugin/appsignal.rb
286
286
  - lib/sequel/extensions/appsignal_integration.rb
287
+ - resources/appsignal.rb.erb
287
288
  - resources/appsignal.yml.erb
288
289
  - resources/cacert.pem
289
290
  homepage: https://github.com/appsignal/appsignal-ruby