appsignal 3.9.2-java → 3.10.0-java

Sign up to get free protection for your applications and to get access to all the features.
Files changed (105) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/ci.yml +3138 -0
  3. data/.rubocop.yml +28 -20
  4. data/.rubocop_todo.yml +7 -33
  5. data/CHANGELOG.md +130 -0
  6. data/README.md +0 -1
  7. data/Rakefile +80 -65
  8. data/appsignal.gemspec +1 -1
  9. data/build_matrix.yml +112 -184
  10. data/ext/base.rb +1 -1
  11. data/gemfiles/hanami-2.1.gemfile +7 -0
  12. data/gemfiles/webmachine1.gemfile +5 -4
  13. data/lib/appsignal/cli/diagnose.rb +1 -1
  14. data/lib/appsignal/config.rb +5 -1
  15. data/lib/appsignal/demo.rb +0 -1
  16. data/lib/appsignal/environment.rb +11 -2
  17. data/lib/appsignal/extension/jruby.rb +1 -1
  18. data/lib/appsignal/helpers/instrumentation.rb +164 -2
  19. data/lib/appsignal/hooks/active_job.rb +1 -6
  20. data/lib/appsignal/integrations/grape.rb +19 -47
  21. data/lib/appsignal/integrations/hanami.rb +8 -7
  22. data/lib/appsignal/integrations/padrino.rb +51 -52
  23. data/lib/appsignal/integrations/railtie.rb +0 -3
  24. data/lib/appsignal/integrations/rake.rb +46 -12
  25. data/lib/appsignal/integrations/sidekiq.rb +1 -11
  26. data/lib/appsignal/integrations/sinatra.rb +0 -1
  27. data/lib/appsignal/integrations/webmachine.rb +15 -9
  28. data/lib/appsignal/probes/gvl.rb +24 -2
  29. data/lib/appsignal/probes/sidekiq.rb +1 -1
  30. data/lib/appsignal/probes.rb +1 -1
  31. data/lib/appsignal/rack/abstract_middleware.rb +104 -33
  32. data/lib/appsignal/rack/body_wrapper.rb +143 -0
  33. data/lib/appsignal/rack/event_handler.rb +12 -3
  34. data/lib/appsignal/rack/generic_instrumentation.rb +5 -4
  35. data/lib/appsignal/rack/grape_middleware.rb +40 -0
  36. data/lib/appsignal/rack/hanami_middleware.rb +2 -12
  37. data/lib/appsignal/rack/instrumentation_middleware.rb +62 -0
  38. data/lib/appsignal/rack/rails_instrumentation.rb +14 -57
  39. data/lib/appsignal/rack/sinatra_instrumentation.rb +1 -3
  40. data/lib/appsignal/rack/streaming_listener.rb +13 -59
  41. data/lib/appsignal/rack.rb +31 -0
  42. data/lib/appsignal/transaction.rb +50 -8
  43. data/lib/appsignal/utils/integration_memory_logger.rb +78 -0
  44. data/lib/appsignal/utils.rb +1 -0
  45. data/lib/appsignal/version.rb +1 -1
  46. data/lib/appsignal.rb +36 -33
  47. data/spec/.rubocop.yml +1 -1
  48. data/spec/lib/appsignal/cli/diagnose_spec.rb +1 -1
  49. data/spec/lib/appsignal/cli/install_spec.rb +3 -3
  50. data/spec/lib/appsignal/config_spec.rb +8 -5
  51. data/spec/lib/appsignal/demo_spec.rb +38 -41
  52. data/spec/lib/appsignal/hooks/action_cable_spec.rb +86 -167
  53. data/spec/lib/appsignal/hooks/active_support_notifications/finish_with_state_shared_examples.rb +8 -20
  54. data/spec/lib/appsignal/hooks/active_support_notifications/instrument_shared_examples.rb +38 -84
  55. data/spec/lib/appsignal/hooks/active_support_notifications/start_finish_shared_examples.rb +16 -37
  56. data/spec/lib/appsignal/hooks/active_support_notifications_spec.rb +4 -4
  57. data/spec/lib/appsignal/hooks/activejob_spec.rb +111 -200
  58. data/spec/lib/appsignal/hooks/delayed_job_spec.rb +54 -91
  59. data/spec/lib/appsignal/hooks/dry_monitor_spec.rb +14 -32
  60. data/spec/lib/appsignal/hooks/excon_spec.rb +8 -12
  61. data/spec/lib/appsignal/hooks/net_http_spec.rb +7 -42
  62. data/spec/lib/appsignal/hooks/rake_spec.rb +107 -34
  63. data/spec/lib/appsignal/hooks/redis_client_spec.rb +18 -30
  64. data/spec/lib/appsignal/hooks/redis_spec.rb +10 -16
  65. data/spec/lib/appsignal/hooks/resque_spec.rb +42 -62
  66. data/spec/lib/appsignal/hooks/shoryuken_spec.rb +33 -74
  67. data/spec/lib/appsignal/integrations/hanami_spec.rb +79 -21
  68. data/spec/lib/appsignal/integrations/http_spec.rb +12 -20
  69. data/spec/lib/appsignal/integrations/net_http_spec.rb +33 -0
  70. data/spec/lib/appsignal/integrations/object_spec.rb +29 -36
  71. data/spec/lib/appsignal/integrations/padrino_spec.rb +190 -163
  72. data/spec/lib/appsignal/integrations/que_spec.rb +43 -70
  73. data/spec/lib/appsignal/integrations/railtie_spec.rb +26 -67
  74. data/spec/lib/appsignal/integrations/sidekiq_spec.rb +86 -160
  75. data/spec/lib/appsignal/integrations/sinatra_spec.rb +10 -3
  76. data/spec/lib/appsignal/integrations/webmachine_spec.rb +77 -40
  77. data/spec/lib/appsignal/probes/gvl_spec.rb +80 -3
  78. data/spec/lib/appsignal/probes_spec.rb +7 -4
  79. data/spec/lib/appsignal/rack/abstract_middleware_spec.rb +302 -105
  80. data/spec/lib/appsignal/rack/body_wrapper_spec.rb +263 -0
  81. data/spec/lib/appsignal/rack/event_handler_spec.rb +81 -78
  82. data/spec/lib/appsignal/rack/generic_instrumentation_spec.rb +70 -27
  83. data/spec/lib/appsignal/rack/grape_middleware_spec.rb +234 -0
  84. data/spec/lib/appsignal/rack/hanami_middleware_spec.rb +2 -16
  85. data/spec/lib/appsignal/rack/instrumentation_middleware_spec.rb +38 -0
  86. data/spec/lib/appsignal/rack/rails_instrumentation_spec.rb +67 -131
  87. data/spec/lib/appsignal/rack/sinatra_instrumentation_spec.rb +36 -44
  88. data/spec/lib/appsignal/rack/streaming_listener_spec.rb +44 -139
  89. data/spec/lib/appsignal/transaction_spec.rb +239 -94
  90. data/spec/lib/appsignal/utils/integration_memory_logger_spec.rb +163 -0
  91. data/spec/lib/appsignal_spec.rb +556 -344
  92. data/spec/support/helpers/dependency_helper.rb +6 -1
  93. data/spec/support/helpers/std_streams_helper.rb +1 -1
  94. data/spec/support/helpers/transaction_helpers.rb +8 -0
  95. data/spec/support/matchers/transaction.rb +185 -0
  96. data/spec/support/mocks/dummy_app.rb +20 -0
  97. data/spec/support/shared_examples/instrument.rb +17 -12
  98. data/spec/support/testing.rb +18 -9
  99. metadata +20 -11
  100. data/.semaphore/semaphore.yml +0 -2347
  101. data/script/lint_git +0 -22
  102. data/spec/lib/appsignal/integrations/grape_spec.rb +0 -239
  103. data/spec/support/matchers/be_completed.rb +0 -5
  104. data/support/check_versions +0 -22
  105. /data/gemfiles/{hanami.gemfile → hanami-2.0.gemfile} +0 -0
@@ -2,7 +2,7 @@
2
2
 
3
3
  module Appsignal
4
4
  module Helpers
5
- module Instrumentation # rubocop:disable Metrics/ModuleLength
5
+ module Instrumentation
6
6
  include Appsignal::Utils::StdoutAndLoggerMessage
7
7
 
8
8
  # Creates an AppSignal transaction for the given block.
@@ -195,6 +195,7 @@ module Appsignal
195
195
  # used to send the error.
196
196
  # @return [void]
197
197
  #
198
+ # @see Transaction#report_error
198
199
  # @see https://docs.appsignal.com/ruby/instrumentation/exception-handling.html
199
200
  # Exception handling guide
200
201
  # @see https://docs.appsignal.com/ruby/instrumentation/tagging.html
@@ -294,6 +295,7 @@ module Appsignal
294
295
  # @return [void]
295
296
  #
296
297
  # @see Transaction#set_error
298
+ # @see Transaction#report_error
297
299
  # @see https://docs.appsignal.com/ruby/instrumentation/exception-handling.html
298
300
  # Exception handling guide
299
301
  # @since 0.6.6
@@ -334,6 +336,74 @@ module Appsignal
334
336
  alias :set_exception :set_error
335
337
  alias :add_exception :set_error
336
338
 
339
+ # Report an error.
340
+ #
341
+ # If a transaction is currently active, it will report the error on the
342
+ # current transaction. If no transaction is active, it will report the
343
+ # error on a new transaction.
344
+ #
345
+ # **Note**: If AppSignal is not active, no error is reported.
346
+ #
347
+ # **Note**: If the given exception argument is not an Exception subclass,
348
+ # it will not be reported.
349
+ #
350
+ # @example
351
+ # class SomeController < ApplicationController
352
+ # def create
353
+ # # Do something that breaks
354
+ # rescue => error
355
+ # Appsignal.report_error(error)
356
+ # end
357
+ # end
358
+ #
359
+ # @example Add more metadata to transaction
360
+ # Appsignal.report_error(error) do |transaction|
361
+ # transaction.set_namespace("my_namespace")
362
+ # transaction.set_action("my_action_name")
363
+ # transaction.set_params(:search_query => params[:search_query])
364
+ # transaction.set_tags(:key => "value")
365
+ # end
366
+ #
367
+ # @param exception [Exception] The error to add to the current
368
+ # transaction.
369
+ # @yield [transaction] yields block to allow modification of the
370
+ # transaction.
371
+ # @yieldparam transaction [Transaction] yields the AppSignal transaction
372
+ # used to report the error.
373
+ # @return [void]
374
+ #
375
+ # @see https://docs.appsignal.com/ruby/instrumentation/exception-handling.html
376
+ # Exception handling guide
377
+ # @since 3.10.0
378
+ def report_error(exception)
379
+ unless exception.is_a?(Exception)
380
+ internal_logger.error "Appsignal.report_error: Cannot set error. " \
381
+ "The given value is not an exception: #{exception.inspect}"
382
+ return
383
+ end
384
+ return unless active?
385
+
386
+ has_parent_transaction = Appsignal::Transaction.current?
387
+ transaction =
388
+ if has_parent_transaction
389
+ Appsignal::Transaction.current
390
+ else
391
+ Appsignal::Transaction.new(
392
+ SecureRandom.uuid,
393
+ Appsignal::Transaction::HTTP_REQUEST,
394
+ Appsignal::Transaction::GenericRequest.new({})
395
+ )
396
+ end
397
+
398
+ transaction.set_error(exception)
399
+ yield transaction if block_given?
400
+
401
+ return if has_parent_transaction
402
+
403
+ transaction.complete
404
+ end
405
+ alias :report_exception :report_error
406
+
337
407
  # Set a custom action name for the current transaction.
338
408
  #
339
409
  # When using an integration such as the Rails or Sinatra AppSignal will
@@ -404,13 +474,44 @@ module Appsignal
404
474
  Appsignal::Transaction.current.set_namespace(namespace)
405
475
  end
406
476
 
477
+ # Set custom data on the current transaction.
478
+ #
479
+ # Add extra information about the request or background that cannot be
480
+ # expressed in tags, like nested data structures.
481
+ #
482
+ # When this method is called multiple times, it will overwrite the
483
+ # previously set value.
484
+ #
485
+ # @example
486
+ # Appsignal.set_custom_data(:user => { :locale => "en" })
487
+ # Appsignal.set_custom_data([
488
+ # "array with data",
489
+ # :options => { :verbose => true }
490
+ # ])
491
+ #
492
+ # @since 3.10.0
493
+ # @see Transaction#set_custom_data
494
+ # @see https://docs.appsignal.com/guides/custom-data/sample-data.html
495
+ # Sample data guide
496
+ # @param data [Hash/Array]
497
+ # @return [void]
498
+ def set_custom_data(data)
499
+ return unless active?
500
+ return unless Appsignal::Transaction.current?
501
+
502
+ transaction = Appsignal::Transaction.current
503
+ transaction.set_custom_data(data)
504
+ end
505
+
407
506
  # Set tags on the current transaction.
408
507
  #
409
508
  # Tags are extra bits of information that are added to transaction and
410
509
  # appear on sample details pages on AppSignal.com.
411
510
  #
511
+ # When this method is called multiple times, it will merge the tags.
512
+ #
412
513
  # @example
413
- # Appsignal.tag_request(:locale => "en")
514
+ # Appsignal.tag_request(:locale => "en", :user_id => 1)
414
515
  # Appsignal.tag_request("locale" => "en")
415
516
  # Appsignal.tag_request("user_id" => 1)
416
517
  #
@@ -445,6 +546,67 @@ module Appsignal
445
546
  transaction.set_tags(tags)
446
547
  end
447
548
  alias :tag_job :tag_request
549
+ alias :set_tags :tag_request
550
+
551
+ # Set parameters on the current transaction.
552
+ #
553
+ # Parameters are automatically set by most of our integrations. It should
554
+ # not be necessary to call this method unless you want to report
555
+ # different parameters.
556
+ #
557
+ # To filter parameters, see our parameter filtering guide.
558
+ #
559
+ # When this method is called multiple times, it will overwrite the
560
+ # previously set value.
561
+ #
562
+ # When no parameters are set this way, the transaction will look for
563
+ # parameters in its request environment.
564
+ #
565
+ # A block can be given to this method to defer the fetching and parsing
566
+ # of the parameters until and only when the transaction is sampled.
567
+ #
568
+ # When both the `params` and a block is given to this method, the
569
+ # `params` argument is leading and the block will _not_ be called.
570
+ #
571
+ # @example Set parameters
572
+ # Appsignal.set_params("param1" => "value1")
573
+ #
574
+ # @example Calling `set_params` multiple times will only keep the last call
575
+ # Appsignal.set_params("param1" => "value1")
576
+ # Appsignal.set_params("param2" => "value2")
577
+ # # The parameters are: { "param2" => "value2" }
578
+ #
579
+ # @example Calling `set_params` with a block
580
+ # Appsignal.set_params do
581
+ # # Some slow code to parse parameters
582
+ # JSON.parse('{"param1": "value1"}')
583
+ # end
584
+ # # The parameters are: { "param1" => "value1" }
585
+ #
586
+ # @example Calling `set_params` with a parameter and a block
587
+ # Appsignal.set_params("argument" => "argument value") do
588
+ # # Some slow code to parse parameters
589
+ # JSON.parse('{"param1": "value1"}')
590
+ # end
591
+ # # The parameters are: { "argument" => "argument value" }
592
+ #
593
+ # @since 3.10.0
594
+ # @param params [Hash] The parameters to set on the transaction.
595
+ # @yield This block is called when the transaction is sampled. The block's
596
+ # return value will become the new parameters.
597
+ # @see https://docs.appsignal.com/guides/custom-data/sample-data.html
598
+ # Sample data guide
599
+ # @see https://docs.appsignal.com/guides/filter-data/filter-parameters.html
600
+ # Parameter filtering guide
601
+ # @see Transaction#set_params
602
+ # @return [void]
603
+ def set_params(params = nil, &block)
604
+ return unless active?
605
+ return unless Appsignal::Transaction.current?
606
+
607
+ transaction = Appsignal::Transaction.current
608
+ transaction.set_params(params, &block)
609
+ end
448
610
 
449
611
  # Add breadcrumbs to the transaction.
450
612
  #
@@ -62,12 +62,7 @@ module Appsignal
62
62
  end
63
63
 
64
64
  if transaction
65
- transaction.set_params_if_nil(
66
- Appsignal::Utils::HashSanitizer.sanitize(
67
- job["arguments"],
68
- Appsignal.config[:filter_parameters]
69
- )
70
- )
65
+ transaction.set_params_if_nil(job["arguments"])
71
66
 
72
67
  transaction_tags = ActiveJobHelpers.transaction_tags_for(job)
73
68
  transaction_tags["active_job_id"] = job["job_id"]
@@ -1,55 +1,27 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require "appsignal"
4
+ require "appsignal/rack/grape_middleware"
5
+
6
+ Appsignal.internal_logger.debug("Loading Grape integration")
7
+
3
8
  module Appsignal
4
- # @todo Move to sub-namespace
5
9
  # @api private
6
10
  module Grape
7
- class Middleware < ::Grape::Middleware::Base
8
- def call(env)
9
- if Appsignal.active?
10
- call_with_appsignal_monitoring(env)
11
- else
12
- app.call(env)
13
- end
14
- end
15
-
16
- def call_with_appsignal_monitoring(env)
17
- request = ::Rack::Request.new(env)
18
- transaction = Appsignal::Transaction.create(
19
- SecureRandom.uuid,
20
- Appsignal::Transaction::HTTP_REQUEST,
21
- request
22
- )
23
- begin
24
- app.call(env)
25
- rescue Exception => error # rubocop:disable Lint/RescueException
26
- # Do not set error if "grape.skip_appsignal_error" is set to `true`.
27
- transaction.set_error(error) unless env["grape.skip_appsignal_error"]
28
- raise error
29
- ensure
30
- request_method = request.request_method.to_s.upcase
31
- path = request.path # Path without namespaces
32
- endpoint = env["api.endpoint"]
33
-
34
- if endpoint&.options
35
- options = endpoint.options
36
- request_method = options[:method].first.to_s.upcase
37
- klass = options[:for]
38
- namespace = endpoint.namespace
39
- namespace = "" if namespace == "/"
40
-
41
- path = options[:path].first.to_s
42
- path = "/#{path}" if path[0] != "/"
43
- path = "#{namespace}#{path}"
44
-
45
- transaction.set_action_if_nil("#{request_method}::#{klass}##{path}")
46
- end
47
-
48
- transaction.set_http_or_background_queue_start
49
- transaction.set_metadata("path", path)
50
- transaction.set_metadata("method", request_method)
51
- Appsignal::Transaction.complete_current!
52
- end
11
+ # Alias constants that have moved with a warning message that points to the
12
+ # place to update the reference.
13
+ def self.const_missing(name)
14
+ case name
15
+ when :Middleware
16
+ callers = caller
17
+ Appsignal::Utils::StdoutAndLoggerMessage.warning \
18
+ "The constant Appsignal::Grape::Middleware has been deprecated. " \
19
+ "Please update the constant name to " \
20
+ "Appsignal::Rack::GrapeMiddleware in the following file to " \
21
+ "remove this message.\n#{callers.first}"
22
+ Appsignal::Rack::GrapeMiddleware
23
+ else
24
+ super
53
25
  end
54
26
  end
55
27
  end
@@ -11,13 +11,14 @@ module Appsignal
11
11
  Appsignal.internal_logger.debug("Loading Hanami integration")
12
12
 
13
13
  hanami_app_config = ::Hanami.app.config
14
- Appsignal.config = Appsignal::Config.new(
15
- hanami_app_config.root || Dir.pwd,
16
- hanami_app_config.env
17
- )
18
14
 
19
- Appsignal.start_logger
20
- Appsignal.start
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
21
22
 
22
23
  return unless Appsignal.active?
23
24
 
@@ -44,4 +45,4 @@ module Appsignal
44
45
  end
45
46
  end
46
47
 
47
- Appsignal::Integrations::HanamiPlugin.init
48
+ Appsignal::Integrations::HanamiPlugin.init unless Appsignal.testing?
@@ -1,79 +1,78 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require "appsignal"
4
+ require "appsignal/rack/sinatra_instrumentation"
4
5
 
5
6
  module Appsignal
6
7
  module Integrations
7
8
  # @api private
8
9
  module PadrinoPlugin
9
10
  def self.init
10
- Appsignal.internal_logger.debug("Loading Padrino (#{Padrino::VERSION}) integration")
11
+ Padrino::Application.prepend Appsignal::Integrations::PadrinoIntegration
11
12
 
12
- root = Padrino.mounted_root
13
- Appsignal.config = Appsignal::Config.new(root, Padrino.env)
13
+ Padrino.before_load do
14
+ Appsignal.internal_logger.debug("Loading Padrino (#{Padrino::VERSION}) integration")
14
15
 
15
- Appsignal.start_logger
16
- Appsignal.start
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
17
28
  end
18
29
  end
19
30
  end
20
31
  end
21
32
 
22
- module Appsignal::Integrations::PadrinoIntegration
23
- def route!(base = settings, pass_block = nil)
24
- return super if !Appsignal.active? || env["sinatra.static_file"]
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"]
25
39
 
26
- transaction = Appsignal::Transaction.create(
27
- SecureRandom.uuid,
28
- Appsignal::Transaction::HTTP_REQUEST,
29
- request
30
- )
31
- begin
32
- Appsignal.instrument("process_action.padrino") do
33
- super
40
+ begin
41
+ super
42
+ ensure
43
+ transaction = Appsignal::Transaction.current
44
+ transaction.set_action_if_nil(get_payload_action(request))
45
+ end
34
46
  end
35
- rescue Exception => error # rubocop:disable Lint/RescueException
36
- transaction.set_error(error)
37
- raise error
38
- ensure
39
- transaction.set_action_if_nil(get_payload_action(request))
40
- transaction.set_metadata("path", request.path)
41
- transaction.set_metadata("method", request.request_method)
42
- transaction.set_http_or_background_queue_start
43
- Appsignal::Transaction.complete_current!
44
- end
45
- end
46
47
 
47
- private
48
+ private
48
49
 
49
- def get_payload_action(request)
50
- # Short-circut is there's no request object to obtain information from
51
- return settings.name.to_s unless request
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
52
53
 
53
- # Newer versions expose the action / controller on the request class.
54
- # Newer versions also still expose a route_obj so we must prioritize the
55
- # action/fullpath methods.
56
- # The `request.action` and `request.controller` values are `nil` when a
57
- # endpoint is not found, `""` if not specified by the user.
58
- controller_name = request.controller if request.respond_to?(:controller)
59
- action_name = request.action if request.respond_to?(:action)
60
- action_name ||= ""
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 ||= ""
61
62
 
62
- return "#{settings.name}:#{controller_name}##{action_name}" unless action_name.empty?
63
+ return "#{settings.name}:#{controller_name}##{action_name}" unless action_name.empty?
63
64
 
64
- # Older versions of Padrino work with a route object
65
- if request.respond_to?(:route_obj) && request.route_obj
66
- return "#{settings.name}:#{request.route_obj.original_path}"
67
- end
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
68
69
 
69
- # Fall back to the application name if we haven't found an action name in
70
- # any previous methods.
71
- "#{settings.name}#unknown"
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
72
75
  end
73
76
  end
74
77
 
75
- Padrino::Application.prepend Appsignal::Integrations::PadrinoIntegration
76
-
77
- Padrino.after_load do
78
- Appsignal::Integrations::PadrinoPlugin.init
79
- end
78
+ Appsignal::Integrations::PadrinoPlugin.init
@@ -26,9 +26,6 @@ module Appsignal
26
26
  :log_path => Rails.root.join("log")
27
27
  )
28
28
 
29
- # Start logger
30
- Appsignal.start_logger
31
-
32
29
  app.middleware.insert(
33
30
  0,
34
31
  ::Rack::Events,
@@ -2,26 +2,60 @@
2
2
 
3
3
  module Appsignal
4
4
  module Integrations
5
+ # @api private
5
6
  module RakeIntegration
6
7
  def execute(*args)
7
- super
8
+ transaction =
9
+ if Appsignal.config[:enable_rake_performance_instrumentation]
10
+ Appsignal::Integrations::RakeIntegrationHelper.register_at_exit_hook
11
+ _appsignal_create_transaction
12
+ end
13
+
14
+ Appsignal.instrument "task.rake" do
15
+ super
16
+ end
8
17
  rescue Exception => error # rubocop:disable Lint/RescueException
9
- # Format given arguments and cast to hash if possible
10
- params, _ = args
11
- params = params.to_hash if params.respond_to?(:to_hash)
18
+ Appsignal::Integrations::RakeIntegrationHelper.register_at_exit_hook
19
+ transaction ||= _appsignal_create_transaction
20
+ transaction.set_error(error)
21
+ raise error
22
+ ensure
23
+ if transaction
24
+ # Format given arguments and cast to hash if possible
25
+ params, _ = args
26
+ params = params.to_hash if params.respond_to?(:to_hash)
27
+ transaction.set_params_if_nil(params)
28
+ transaction.set_action(name)
29
+ transaction.complete
30
+ end
31
+ end
12
32
 
13
- transaction = Appsignal::Transaction.create(
33
+ private
34
+
35
+ def _appsignal_create_transaction
36
+ Appsignal::Transaction.create(
14
37
  SecureRandom.uuid,
15
38
  Appsignal::Transaction::BACKGROUND_JOB,
16
- Appsignal::Transaction::GenericRequest.new(
17
- :params => params
18
- )
39
+ Appsignal::Transaction::GenericRequest.new({})
19
40
  )
20
- transaction.set_action(name)
21
- transaction.set_error(error)
22
- transaction.complete
41
+ end
42
+ end
43
+
44
+ # @api private
45
+ module RakeIntegrationHelper
46
+ # Register an `at_exit` hook when a task is executed. This will stop
47
+ # AppSignal when _all_ tasks are executed and Rake exits.
48
+ def self.register_at_exit_hook
49
+ return if @register_at_exit_hook
50
+
51
+ Kernel.at_exit(&method(:at_exit_hook))
52
+
53
+ @register_at_exit_hook = true
54
+ end
55
+
56
+ # The at_exit hook itself
57
+ def self.at_exit_hook
23
58
  Appsignal.stop("rake")
24
- raise error
25
59
  end
26
60
  end
27
61
  end
@@ -83,7 +83,7 @@ module Appsignal
83
83
  raise exception
84
84
  ensure
85
85
  if transaction
86
- transaction.set_params_if_nil(filtered_arguments(item))
86
+ transaction.set_params_if_nil(parse_arguments(item))
87
87
  transaction.set_http_or_background_queue_start
88
88
  Appsignal::Transaction.complete_current! unless exception
89
89
 
@@ -115,16 +115,6 @@ module Appsignal
115
115
  "#{sidekiq_action_name}#perform"
116
116
  end
117
117
 
118
- def filtered_arguments(job)
119
- arguments = parse_arguments(job)
120
- return unless arguments
121
-
122
- Appsignal::Utils::HashSanitizer.sanitize(
123
- arguments,
124
- Appsignal.config[:filter_parameters]
125
- )
126
- end
127
-
128
118
  def formatted_metadata(item)
129
119
  {}.tap do |hash|
130
120
  (item || {}).each do |key, value|
@@ -12,7 +12,6 @@ unless Appsignal.active?
12
12
  app_settings.environment
13
13
  )
14
14
 
15
- Appsignal.start_logger
16
15
  Appsignal.start
17
16
  end
18
17
 
@@ -5,20 +5,26 @@ module Appsignal
5
5
  # @api private
6
6
  module WebmachineIntegration
7
7
  def run
8
- transaction = Appsignal::Transaction.create(
9
- SecureRandom.uuid,
10
- Appsignal::Transaction::HTTP_REQUEST,
11
- request,
12
- :params_method => :query
13
- )
14
-
15
- transaction.set_action_if_nil("#{resource.class.name}##{request.method}")
8
+ has_parent_transaction = Appsignal::Transaction.current?
9
+ transaction =
10
+ if has_parent_transaction
11
+ Appsignal::Transaction.current
12
+ else
13
+ Appsignal::Transaction.create(
14
+ SecureRandom.uuid,
15
+ Appsignal::Transaction::HTTP_REQUEST,
16
+ request
17
+ )
18
+ end
16
19
 
17
20
  Appsignal.instrument("process_action.webmachine") do
18
21
  super
19
22
  end
23
+ ensure
24
+ transaction.set_action_if_nil("#{resource.class.name}##{request.method}")
25
+ transaction.set_params_if_nil(request.query)
20
26
 
21
- Appsignal::Transaction.complete_current!
27
+ Appsignal::Transaction.complete_current! unless has_parent_transaction
22
28
  end
23
29
 
24
30
  private
@@ -25,6 +25,11 @@ module Appsignal
25
25
  Appsignal.internal_logger.debug("Initializing GVL probe")
26
26
  @appsignal = appsignal
27
27
  @gvl_tools = gvl_tools
28
+
29
+ # Store the process name and ID at initialization time
30
+ # to avoid picking up changes to the process name at runtime
31
+ @process_name = File.basename($PROGRAM_NAME).split.first || "[unknown process]"
32
+ @process_id = Process.pid
28
33
  end
29
34
 
30
35
  def call
@@ -39,13 +44,30 @@ module Appsignal
39
44
  gauge_delta :gvl_global_timer, monotonic_time_ns do |time_delta_ns|
40
45
  if time_delta_ns > 0
41
46
  time_delta_ms = time_delta_ns / 1_000_000
42
- set_gauge_with_hostname("gvl_global_timer", time_delta_ms)
47
+ set_gauges_with_hostname_and_process(
48
+ "gvl_global_timer",
49
+ time_delta_ms
50
+ )
43
51
  end
44
52
  end
45
53
  end
46
54
 
47
55
  def probe_waiting_threads
48
- set_gauge_with_hostname("gvl_waiting_threads", @gvl_tools::WaitingThreads.count)
56
+ set_gauges_with_hostname_and_process(
57
+ "gvl_waiting_threads",
58
+ @gvl_tools::WaitingThreads.count
59
+ )
60
+ end
61
+
62
+ def set_gauges_with_hostname_and_process(name, value)
63
+ set_gauge_with_hostname(name, value, {
64
+ :process_name => @process_name,
65
+ :process_id => @process_id
66
+ })
67
+
68
+ # Also set the gauge without the process name and ID for
69
+ # compatibility with existing automated dashboards
70
+ set_gauge_with_hostname(name, value)
49
71
  end
50
72
  end
51
73
  end
@@ -47,7 +47,7 @@ module Appsignal
47
47
  # @api private
48
48
  def self.dependencies_present?
49
49
  return true if sidekiq7_and_greater?
50
- return unless defined?(::Redis::VERSION) # Sidekiq <= 6
50
+ return false unless defined?(::Redis::VERSION) # Sidekiq <= 6
51
51
 
52
52
  Gem::Version.new(::Redis::VERSION) >= Gem::Version.new("3.3.5")
53
53
  end
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Appsignal
4
- module Probes # rubocop:disable Metrics/ModuleLength
4
+ module Probes
5
5
  ITERATION_IN_SECONDS = 60
6
6
 
7
7
  class ProbeCollection