appsignal 3.9.2-java → 3.9.3-java

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.
Files changed (89) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/ci.yml +3135 -0
  3. data/.rubocop.yml +28 -20
  4. data/.rubocop_todo.yml +7 -33
  5. data/CHANGELOG.md +38 -0
  6. data/Rakefile +79 -64
  7. data/appsignal.gemspec +1 -1
  8. data/build_matrix.yml +109 -179
  9. data/ext/base.rb +1 -1
  10. data/gemfiles/hanami-2.1.gemfile +7 -0
  11. data/lib/appsignal/cli/diagnose.rb +1 -1
  12. data/lib/appsignal/config.rb +1 -1
  13. data/lib/appsignal/demo.rb +0 -1
  14. data/lib/appsignal/environment.rb +5 -1
  15. data/lib/appsignal/extension/jruby.rb +1 -1
  16. data/lib/appsignal/helpers/instrumentation.rb +1 -1
  17. data/lib/appsignal/integrations/grape.rb +19 -47
  18. data/lib/appsignal/integrations/hanami.rb +8 -7
  19. data/lib/appsignal/integrations/padrino.rb +46 -43
  20. data/lib/appsignal/integrations/railtie.rb +0 -3
  21. data/lib/appsignal/integrations/sinatra.rb +0 -1
  22. data/lib/appsignal/probes/gvl.rb +24 -2
  23. data/lib/appsignal/probes/sidekiq.rb +1 -1
  24. data/lib/appsignal/probes.rb +1 -1
  25. data/lib/appsignal/rack/abstract_middleware.rb +62 -28
  26. data/lib/appsignal/rack/event_handler.rb +12 -3
  27. data/lib/appsignal/rack/grape_middleware.rb +40 -0
  28. data/lib/appsignal/rack/hanami_middleware.rb +1 -11
  29. data/lib/appsignal/rack/rails_instrumentation.rb +14 -55
  30. data/lib/appsignal/utils/integration_memory_logger.rb +78 -0
  31. data/lib/appsignal/utils.rb +1 -0
  32. data/lib/appsignal/version.rb +1 -1
  33. data/lib/appsignal.rb +34 -33
  34. data/spec/.rubocop.yml +1 -1
  35. data/spec/lib/appsignal/cli/diagnose_spec.rb +1 -1
  36. data/spec/lib/appsignal/cli/install_spec.rb +3 -3
  37. data/spec/lib/appsignal/config_spec.rb +7 -5
  38. data/spec/lib/appsignal/demo_spec.rb +38 -41
  39. data/spec/lib/appsignal/hooks/action_cable_spec.rb +86 -167
  40. data/spec/lib/appsignal/hooks/active_support_notifications/finish_with_state_shared_examples.rb +8 -20
  41. data/spec/lib/appsignal/hooks/active_support_notifications/instrument_shared_examples.rb +38 -84
  42. data/spec/lib/appsignal/hooks/active_support_notifications/start_finish_shared_examples.rb +16 -37
  43. data/spec/lib/appsignal/hooks/active_support_notifications_spec.rb +4 -4
  44. data/spec/lib/appsignal/hooks/activejob_spec.rb +111 -200
  45. data/spec/lib/appsignal/hooks/delayed_job_spec.rb +54 -91
  46. data/spec/lib/appsignal/hooks/dry_monitor_spec.rb +14 -32
  47. data/spec/lib/appsignal/hooks/excon_spec.rb +8 -12
  48. data/spec/lib/appsignal/hooks/net_http_spec.rb +7 -42
  49. data/spec/lib/appsignal/hooks/rake_spec.rb +9 -19
  50. data/spec/lib/appsignal/hooks/redis_client_spec.rb +18 -30
  51. data/spec/lib/appsignal/hooks/redis_spec.rb +10 -16
  52. data/spec/lib/appsignal/hooks/resque_spec.rb +42 -62
  53. data/spec/lib/appsignal/hooks/shoryuken_spec.rb +33 -74
  54. data/spec/lib/appsignal/integrations/hanami_spec.rb +79 -21
  55. data/spec/lib/appsignal/integrations/http_spec.rb +12 -20
  56. data/spec/lib/appsignal/integrations/net_http_spec.rb +33 -0
  57. data/spec/lib/appsignal/integrations/object_spec.rb +29 -36
  58. data/spec/lib/appsignal/integrations/padrino_spec.rb +47 -70
  59. data/spec/lib/appsignal/integrations/que_spec.rb +43 -70
  60. data/spec/lib/appsignal/integrations/railtie_spec.rb +26 -67
  61. data/spec/lib/appsignal/integrations/sidekiq_spec.rb +86 -160
  62. data/spec/lib/appsignal/integrations/sinatra_spec.rb +0 -1
  63. data/spec/lib/appsignal/integrations/webmachine_spec.rb +28 -39
  64. data/spec/lib/appsignal/probes/gvl_spec.rb +80 -3
  65. data/spec/lib/appsignal/probes_spec.rb +7 -4
  66. data/spec/lib/appsignal/rack/abstract_middleware_spec.rb +215 -106
  67. data/spec/lib/appsignal/rack/event_handler_spec.rb +81 -78
  68. data/spec/lib/appsignal/rack/generic_instrumentation_spec.rb +2 -12
  69. data/spec/lib/appsignal/rack/grape_middleware_spec.rb +234 -0
  70. data/spec/lib/appsignal/rack/hanami_middleware_spec.rb +2 -16
  71. data/spec/lib/appsignal/rack/rails_instrumentation_spec.rb +67 -131
  72. data/spec/lib/appsignal/rack/sinatra_instrumentation_spec.rb +36 -44
  73. data/spec/lib/appsignal/rack/streaming_listener_spec.rb +68 -86
  74. data/spec/lib/appsignal/transaction_spec.rb +76 -90
  75. data/spec/lib/appsignal/utils/integration_memory_logger_spec.rb +163 -0
  76. data/spec/lib/appsignal_spec.rb +363 -342
  77. data/spec/support/helpers/dependency_helper.rb +6 -1
  78. data/spec/support/helpers/std_streams_helper.rb +1 -1
  79. data/spec/support/helpers/transaction_helpers.rb +8 -0
  80. data/spec/support/matchers/transaction.rb +185 -0
  81. data/spec/support/mocks/dummy_app.rb +20 -0
  82. data/spec/support/shared_examples/instrument.rb +17 -12
  83. data/spec/support/testing.rb +18 -9
  84. metadata +15 -10
  85. data/.semaphore/semaphore.yml +0 -2347
  86. data/script/lint_git +0 -22
  87. data/spec/lib/appsignal/integrations/grape_spec.rb +0 -239
  88. data/spec/support/matchers/be_completed.rb +0 -5
  89. /data/gemfiles/{hanami.gemfile → hanami-2.0.gemfile} +0 -0
@@ -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
@@ -3,9 +3,11 @@
3
3
  require "rack"
4
4
 
5
5
  module Appsignal
6
- # @api private
7
6
  module Rack
7
+ # @api private
8
8
  class AbstractMiddleware
9
+ DEFAULT_ERROR_REPORTING = :default
10
+
9
11
  def initialize(app, options = {})
10
12
  Appsignal.internal_logger.debug "Initializing #{self.class}"
11
13
  @app = app
@@ -13,6 +15,7 @@ module Appsignal
13
15
  @request_class = options.fetch(:request_class, ::Rack::Request)
14
16
  @params_method = options.fetch(:params_method, :params)
15
17
  @instrument_span_name = options.fetch(:instrument_span_name, "process.abstract")
18
+ @report_errors = options.fetch(:report_errors, DEFAULT_ERROR_REPORTING)
16
19
  end
17
20
 
18
21
  def call(env)
@@ -32,15 +35,31 @@ module Appsignal
32
35
  )
33
36
  end
34
37
 
35
- add_transaction_metadata_before(transaction, request)
36
- if wrapped_instrumentation
37
- instrument_wrapped_request(request, transaction)
38
- else
38
+ unless wrapped_instrumentation
39
39
  # Set transaction on the request environment so other nested
40
40
  # middleware can detect if there is parent instrumentation
41
41
  # middleware active.
42
42
  env[Appsignal::Rack::APPSIGNAL_TRANSACTION] = transaction
43
- instrument_request(request, transaction)
43
+ end
44
+
45
+ begin
46
+ add_transaction_metadata_before(transaction, request)
47
+ # Report errors if the :report_errors option is set to true or when
48
+ # there is no parent instrumentation that can rescue and report the error.
49
+ if @report_errors || !wrapped_instrumentation
50
+ instrument_app_call_with_exception_handling(
51
+ request.env,
52
+ transaction,
53
+ wrapped_instrumentation
54
+ )
55
+ else
56
+ instrument_app_call(request.env)
57
+ end
58
+ ensure
59
+ add_transaction_metadata_after(transaction, request)
60
+
61
+ # Complete transaction because this is the top instrumentation middleware.
62
+ Appsignal::Transaction.complete_current! unless wrapped_instrumentation
44
63
  end
45
64
  else
46
65
  @app.call(env)
@@ -56,35 +75,40 @@ module Appsignal
56
75
  # Either another {GenericInstrumentation} or {EventHandler} is higher in
57
76
  # the stack and will report the exception and complete the transaction.
58
77
  #
59
- # @see {#instrument_request}
60
- def instrument_wrapped_request(request, transaction)
61
- instrument_app_call(request.env)
62
- ensure
63
- add_transaction_metadata_after(transaction, request)
78
+ # @see {#instrument_app_call_with_exception_handling}
79
+ def instrument_app_call(env)
80
+ if @instrument_span_name
81
+ Appsignal.instrument(@instrument_span_name) do
82
+ @app.call(env)
83
+ end
84
+ else
85
+ @app.call(env)
86
+ end
64
87
  end
65
88
 
66
89
  # Instrument the request fully. This is used by the top instrumentation
67
90
  # middleware in the middleware stack. Unlike
68
- # {#instrument_wrapped_request} this will report any exceptions being
91
+ # {#instrument_app_call} this will report any exceptions being
69
92
  # raised.
70
93
  #
71
- # @see {#instrument_wrapped_request}
72
- def instrument_request(request, transaction)
73
- instrument_app_call(request.env)
94
+ # @see {#instrument_app_call}
95
+ def instrument_app_call_with_exception_handling(env, transaction, wrapped_instrumentation)
96
+ instrument_app_call(env)
74
97
  rescue Exception => error # rubocop:disable Lint/RescueException
75
- transaction.set_error(error)
98
+ report_errors =
99
+ if @report_errors == DEFAULT_ERROR_REPORTING
100
+ # If there's no parent transaction, report the error
101
+ !wrapped_instrumentation
102
+ elsif @report_errors.respond_to?(:call)
103
+ # If the @report_errors option is callable, call it with the
104
+ # request environment so it can determine if the error needs to be
105
+ # reported.
106
+ @report_errors.call(env)
107
+ else
108
+ @report_errors
109
+ end
110
+ transaction.set_error(error) if report_errors
76
111
  raise error
77
- ensure
78
- add_transaction_metadata_after(transaction, request)
79
-
80
- # Complete transaction because this is the top instrumentation middleware.
81
- Appsignal::Transaction.complete_current!
82
- end
83
-
84
- def instrument_app_call(env)
85
- Appsignal.instrument(@instrument_span_name) do
86
- @app.call(env)
87
- end
88
112
  end
89
113
 
90
114
  # Add metadata to the transaction based on the request environment.
@@ -101,7 +125,10 @@ module Appsignal
101
125
  request.env["appsignal.route"] || request.env["appsignal.action"]
102
126
  transaction.set_action_if_nil(default_action)
103
127
  transaction.set_metadata("path", request.path)
104
- transaction.set_metadata("method", request.request_method)
128
+
129
+ request_method = request_method_for(request)
130
+ transaction.set_metadata("method", request_method) if request_method
131
+
105
132
  transaction.set_params_if_nil(params_for(request))
106
133
  transaction.set_http_or_background_queue_start
107
134
  end
@@ -118,6 +145,13 @@ module Appsignal
118
145
  nil
119
146
  end
120
147
 
148
+ def request_method_for(request)
149
+ request.request_method
150
+ rescue => error
151
+ Appsignal.internal_logger.error("Unable to report HTTP request method: '#{error}'")
152
+ nil
153
+ end
154
+
121
155
  def request_for(env)
122
156
  @request_class.new(env)
123
157
  end
@@ -4,8 +4,10 @@ module Appsignal
4
4
  module Rack
5
5
  APPSIGNAL_TRANSACTION = "appsignal.transaction"
6
6
  APPSIGNAL_EVENT_HANDLER_ID = "appsignal.event_handler_id"
7
+ APPSIGNAL_EVENT_HANDLER_HAS_ERROR = "appsignal.event_handler.error"
7
8
  RACK_AFTER_REPLY = "rack.after_reply"
8
9
 
10
+ # @api private
9
11
  class EventHandler
10
12
  include ::Rack::Events::Abstract
11
13
 
@@ -70,6 +72,7 @@ module Appsignal
70
72
  transaction = request.env[APPSIGNAL_TRANSACTION]
71
73
  return unless transaction
72
74
 
75
+ request.env[APPSIGNAL_EVENT_HANDLER_HAS_ERROR] = true
73
76
  transaction.set_error(error)
74
77
  end
75
78
  end
@@ -83,12 +86,18 @@ module Appsignal
83
86
  self.class.safe_execution("Appsignal::Rack::EventHandler#on_finish") do
84
87
  transaction.finish_event("process_request.rack", "", "")
85
88
  transaction.set_http_or_background_queue_start
86
- if response
87
- transaction.set_tags(:response_status => response.status)
89
+ response_status =
90
+ if response
91
+ response.status
92
+ elsif request.env[APPSIGNAL_EVENT_HANDLER_HAS_ERROR] == true
93
+ 500
94
+ end
95
+ if response_status
96
+ transaction.set_tags(:response_status => response_status)
88
97
  Appsignal.increment_counter(
89
98
  :response_status,
90
99
  1,
91
- :status => response.status,
100
+ :status => response_status,
92
101
  :namespace => format_namespace(transaction.namespace)
93
102
  )
94
103
  end
@@ -0,0 +1,40 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Appsignal
4
+ module Rack
5
+ # @api private
6
+ class GrapeMiddleware < Appsignal::Rack::AbstractMiddleware
7
+ def initialize(app, options = {})
8
+ options[:instrument_span_name] = "process_request.grape"
9
+ options[:report_errors] = lambda { |env| !env["grape.skip_appsignal_error"] }
10
+ super
11
+ end
12
+
13
+ private
14
+
15
+ def add_transaction_metadata_after(transaction, request)
16
+ endpoint = request.env["api.endpoint"]
17
+ unless endpoint&.options
18
+ super
19
+ return
20
+ end
21
+
22
+ options = endpoint.options
23
+ request_method = options[:method].first.to_s.upcase
24
+ klass = options[:for]
25
+ namespace = endpoint.namespace
26
+ namespace = "" if namespace == "/"
27
+
28
+ path = options[:path].first.to_s
29
+ path = "/#{path}" if path[0] != "/"
30
+ path = "#{namespace}#{path}"
31
+
32
+ transaction.set_action_if_nil("#{request_method}::#{klass}##{path}")
33
+
34
+ super
35
+
36
+ transaction.set_metadata("path", path)
37
+ end
38
+ end
39
+ end
40
+ end
@@ -5,7 +5,6 @@ module Appsignal
5
5
  # @api private
6
6
  class HanamiMiddleware < AbstractMiddleware
7
7
  def initialize(app, options = {})
8
- options[:request_class] ||= ::Hanami::Action::Request
9
8
  options[:params_method] ||= :params
10
9
  options[:instrument_span_name] ||= "process_action.hanami"
11
10
  super
@@ -14,16 +13,7 @@ module Appsignal
14
13
  private
15
14
 
16
15
  def params_for(request)
17
- super&.to_h
18
- end
19
-
20
- def request_for(env)
21
- params = ::Hanami::Action.params_class.new(env)
22
- @request_class.new(
23
- :env => env,
24
- :params => params,
25
- :sessions_enabled => true
26
- )
16
+ ::Hanami::Action.params_class.new(request.env).to_h
27
17
  end
28
18
  end
29
19
  end
@@ -3,68 +3,27 @@
3
3
  require "rack"
4
4
 
5
5
  module Appsignal
6
- # @api private
7
6
  module Rack
8
- class RailsInstrumentation
7
+ # @api private
8
+ class RailsInstrumentation < Appsignal::Rack::AbstractMiddleware
9
9
  def initialize(app, options = {})
10
- Appsignal.internal_logger.debug "Initializing Appsignal::Rack::RailsInstrumentation"
11
- @app = app
12
- @options = options
10
+ options[:request_class] ||= ActionDispatch::Request
11
+ options[:params_method] ||= :filtered_parameters
12
+ options[:instrument_span_name] = nil
13
+ options[:report_errors] = true
14
+ super
13
15
  end
14
16
 
15
- def call(env)
16
- if Appsignal.active?
17
- call_with_appsignal_monitoring(env)
18
- else
19
- @app.call(env)
20
- end
21
- end
22
-
23
- def call_with_appsignal_monitoring(env)
24
- request = ActionDispatch::Request.new(env)
25
- transaction = env.fetch(
26
- Appsignal::Rack::APPSIGNAL_TRANSACTION,
27
- Appsignal::Transaction::NilTransaction.new
28
- )
17
+ private
29
18
 
30
- begin
31
- @app.call(env)
32
- rescue Exception => error # rubocop:disable Lint/RescueException
33
- transaction.set_error(error)
34
- raise error
35
- ensure
36
- controller = env["action_controller.instance"]
37
- if controller
38
- transaction.set_action_if_nil("#{controller.class}##{controller.action_name}")
39
- end
40
- transaction.set_params_if_nil(fetch_params(request))
41
- request_id = fetch_request_id(env)
42
- transaction.set_tags(:request_id => request_id) if request_id
43
- transaction.set_metadata("path", request.path)
44
- request_method = fetch_request_method(request)
45
- transaction.set_metadata("method", request_method) if request_method
46
- end
47
- end
19
+ def add_transaction_metadata_after(transaction, request)
20
+ controller = request.env["action_controller.instance"]
21
+ transaction.set_action_if_nil("#{controller.class}##{controller.action_name}") if controller
48
22
 
49
- def fetch_request_id(env)
50
- env["action_dispatch.request_id"]
51
- end
52
-
53
- def fetch_params(request)
54
- return unless request.respond_to?(:filtered_parameters)
55
-
56
- request.filtered_parameters
57
- rescue => error
58
- # Getting params from the request has been know to fail.
59
- Appsignal.internal_logger.debug "Exception while getting Rails params: #{error}"
60
- nil
61
- end
23
+ request_id = request.env["action_dispatch.request_id"]
24
+ transaction.set_tags(:request_id => request_id) if request_id
62
25
 
63
- def fetch_request_method(request)
64
- request.request_method
65
- rescue => error
66
- Appsignal.internal_logger.error("Unable to report HTTP request method: '#{error}'")
67
- nil
26
+ super
68
27
  end
69
28
  end
70
29
  end
@@ -0,0 +1,78 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "logger"
4
+
5
+ module Appsignal
6
+ module Utils
7
+ # @api private
8
+ class IntegrationMemoryLogger
9
+ LEVELS = {
10
+ Logger::DEBUG => :DEBUG,
11
+ Logger::INFO => :INFO,
12
+ Logger::WARN => :WARN,
13
+ Logger::ERROR => :ERROR,
14
+ Logger::FATAL => :FATAL,
15
+ Logger::UNKNOWN => :UNKNOWN
16
+ }.freeze
17
+
18
+ attr_accessor :formatter, :level
19
+
20
+ def add(severity, message, _progname = nil)
21
+ message = formatter.call(severity, Time.now, nil, message) if formatter
22
+ messages[severity] << message
23
+ end
24
+ alias log add
25
+
26
+ def debug(message)
27
+ add(:DEBUG, message)
28
+ end
29
+
30
+ def info(message)
31
+ add(:INFO, message)
32
+ end
33
+
34
+ def warn(message)
35
+ add(:WARN, message)
36
+ end
37
+
38
+ def seen_keys
39
+ @seen_keys ||= Set.new
40
+ end
41
+
42
+ def warn_once_then_debug(key, message)
43
+ if seen_keys.add?(key).nil?
44
+ debug message
45
+ else
46
+ warn message
47
+ end
48
+ end
49
+
50
+ def error(message)
51
+ add(:ERROR, message)
52
+ end
53
+
54
+ def fatal(message)
55
+ add(:FATAL, message)
56
+ end
57
+
58
+ def unknown(message)
59
+ add(:UNKNOWN, message)
60
+ end
61
+
62
+ def clear
63
+ messages.clear
64
+ end
65
+
66
+ def messages
67
+ @messages ||= Hash.new { |hash, key| hash[key] = [] }
68
+ end
69
+
70
+ def messages_for_level(level)
71
+ levels = LEVELS.select { |log_level| log_level >= level }.values
72
+ messages
73
+ .select { |log_level| levels.include?(log_level) }
74
+ .flat_map { |_level, message| message }
75
+ end
76
+ end
77
+ end
78
+ end
@@ -1,5 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require "appsignal/utils/integration_memory_logger"
3
4
  require "appsignal/utils/stdout_and_logger_message"
4
5
  require "appsignal/utils/data"
5
6
  require "appsignal/utils/hash_sanitizer"
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Appsignal
4
- VERSION = "3.9.2"
4
+ VERSION = "3.9.3"
5
5
  end
data/lib/appsignal.rb CHANGED
@@ -55,14 +55,15 @@ module Appsignal
55
55
  # directly.
56
56
  #
57
57
  # If no logger has been set, it will return a "in memory logger", using
58
- # `in_memory_log`. Once AppSignal is started (using {.start}) the
59
- # contents of the "in memory logger" is written to the new logger.
58
+ # {Utils::IntegrationMemoryLogger}. Once AppSignal is started (using
59
+ # {.start}) the contents of the "in memory logger" is written to the new
60
+ # logger.
60
61
  #
61
62
  # @note some classes may have options to set custom loggers. Their
62
63
  # defaults are pointed to this attribute.
63
64
  # @api private
64
65
  # @return [Logger]
65
- # @see start_logger
66
+ # @see start
66
67
  attr_writer :internal_logger
67
68
 
68
69
  # @api private
@@ -84,8 +85,6 @@ module Appsignal
84
85
  # AppSignal](https://docs.appsignal.com/ruby/instrumentation/integrating-appsignal.html)
85
86
  # guide.
86
87
  #
87
- # To start the logger see {.start_logger}.
88
- #
89
88
  # @example
90
89
  # Appsignal.start
91
90
  #
@@ -108,8 +107,9 @@ module Appsignal
108
107
  ENV["APPSIGNAL_APP_ENV"] || ENV["RAILS_ENV"] || ENV.fetch("RACK_ENV", nil)
109
108
  )
110
109
 
110
+ _start_logger
111
+
111
112
  if config.valid?
112
- internal_logger.level = config.log_level
113
113
  if config.active?
114
114
  internal_logger.info "Starting AppSignal #{Appsignal::VERSION} " \
115
115
  "(#{$PROGRAM_NAME}, Ruby #{RUBY_VERSION}, #{RUBY_PLATFORM})"
@@ -160,7 +160,7 @@ module Appsignal
160
160
  def forked
161
161
  return unless active?
162
162
 
163
- Appsignal.start_logger
163
+ Appsignal._start_logger
164
164
  internal_logger.debug("Forked process, resubscribing and restarting extension")
165
165
  Appsignal::Extension.start
166
166
  end
@@ -169,27 +169,15 @@ module Appsignal
169
169
  Appsignal::Extension.get_server_state(key)
170
170
  end
171
171
 
172
- # In memory internal logger used before any internal logger is started with
173
- # {.start_logger}.
174
- #
175
- # The contents of this logger are flushed to the logger in {.start_logger}.
176
- #
177
- # @api private
178
- # @return [StringIO]
179
- def in_memory_log
180
- if defined?(@in_memory_log) && @in_memory_log
181
- @in_memory_log
182
- else
183
- @in_memory_log = StringIO.new
184
- end
172
+ def in_memory_logger
173
+ @in_memory_logger ||=
174
+ Appsignal::Utils::IntegrationMemoryLogger.new.tap do |l|
175
+ l.formatter = log_formatter("appsignal")
176
+ end
185
177
  end
186
178
 
187
179
  def internal_logger
188
- @internal_logger ||=
189
- Appsignal::Utils::IntegrationLogger.new(in_memory_log).tap do |l|
190
- l.level = ::Logger::INFO
191
- l.formatter = log_formatter("appsignal")
192
- end
180
+ @internal_logger ||= in_memory_logger
193
181
  end
194
182
 
195
183
  # @api private
@@ -201,14 +189,26 @@ module Appsignal
201
189
  end
202
190
  end
203
191
 
192
+ # @deprecated Only {.start} has to be called.
193
+ # @return [void]
194
+ # @since 0.7.0
195
+ def start_logger
196
+ callers = caller
197
+ Appsignal::Utils::StdoutAndLoggerMessage.warning \
198
+ "Callng 'Appsignal.start_logger' is deprecated. " \
199
+ "The logger will be started when calling 'Appsignal.start'. " \
200
+ "Remove the 'Appsignal.start_logger' call in the following file to " \
201
+ "remove this message.\n#{callers.first}"
202
+ end
203
+
204
204
  # Start the AppSignal internal logger.
205
205
  #
206
206
  # Sets the log level and sets the logger. Uses a file-based logger or the
207
207
  # STDOUT-based logger. See the `:log` configuration option.
208
208
  #
209
+ # @api private
209
210
  # @return [void]
210
- # @since 0.7.0
211
- def start_logger
211
+ def _start_logger
212
212
  if config && config[:log] == "file" && config.log_file_path
213
213
  start_internal_file_logger(config.log_file_path)
214
214
  else
@@ -221,10 +221,11 @@ module Appsignal
221
221
  else
222
222
  Appsignal::Config::DEFAULT_LOG_LEVEL
223
223
  end
224
- return unless @in_memory_log
224
+ return unless @in_memory_logger
225
225
 
226
- internal_logger << @in_memory_log.string
227
- @in_memory_log = nil
226
+ messages = @in_memory_logger.messages_for_level(internal_logger.level)
227
+ internal_logger << messages.join
228
+ @in_memory_logger = nil
228
229
  end
229
230
 
230
231
  # Returns if the C-extension was loaded properly.
@@ -323,11 +324,11 @@ require "appsignal/hooks"
323
324
  require "appsignal/probes"
324
325
  require "appsignal/marker"
325
326
  require "appsignal/garbage_collection"
326
- require "appsignal/integrations/railtie" if defined?(::Rails)
327
- require "appsignal/transaction"
328
- require "appsignal/version"
329
327
  require "appsignal/rack/abstract_middleware"
330
328
  require "appsignal/rack/generic_instrumentation"
331
329
  require "appsignal/rack/event_handler"
330
+ require "appsignal/integrations/railtie" if defined?(::Rails)
331
+ require "appsignal/transaction"
332
+ require "appsignal/version"
332
333
  require "appsignal/transmitter"
333
334
  require "appsignal/heartbeat"
data/spec/.rubocop.yml CHANGED
@@ -3,5 +3,5 @@ inherit_from: ../.rubocop.yml
3
3
  Metrics/BlockLength:
4
4
  Enabled: false
5
5
 
6
- # Metrics/LineLength:
6
+ # Layout/LineLength:
7
7
  # Max: 100
@@ -1320,7 +1320,7 @@ describe Appsignal::CLI::Diagnose, :api_stub => true, :send_report => :yes_cli_i
1320
1320
  end
1321
1321
 
1322
1322
  it "transmits path data in report" do
1323
- mode = ENV["RUNNING_IN_CI"] ? "40775" : "40755"
1323
+ mode = "40755"
1324
1324
  expect(received_report["paths"]["root_path"]).to eq(
1325
1325
  "path" => root_path,
1326
1326
  "exists" => true,
@@ -155,7 +155,7 @@ describe Appsignal::CLI::Install do
155
155
  end
156
156
 
157
157
  it "requires an application name" do
158
- expect(output.scan(/Enter application name:/).length).to eq(2)
158
+ expect(output.scan("Enter application name:").length).to eq(2)
159
159
  end
160
160
  end
161
161
 
@@ -184,7 +184,7 @@ describe Appsignal::CLI::Install do
184
184
  run
185
185
 
186
186
  expect(output).to_not include "Adding AppSignal integration to Capfile"
187
- expect(File.read(capfile).scan(/appsignal/).count).to eq(1)
187
+ expect(File.read(capfile).scan("appsignal").count).to eq(1)
188
188
  end
189
189
  end
190
190
 
@@ -351,7 +351,7 @@ describe Appsignal::CLI::Install do
351
351
  choose_environment_config
352
352
  run
353
353
 
354
- expect(output.scan(/Choose app's display name:/).length).to eq(2)
354
+ expect(output.scan("Choose app's display name:").length).to eq(2)
355
355
  end
356
356
 
357
357
  context "with configuration using environment variables" do