appsignal 3.9.2-java → 3.10.0-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 (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
@@ -1,73 +1,27 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ Appsignal::Utils::StdoutAndLoggerMessage.warning \
4
+ "The constant Appsignal::Rack::StreamingListener has been deprecated. " \
5
+ "Please update the constant name to " \
6
+ "Appsignal::Rack::InstrumentationMiddleware."
7
+
3
8
  module Appsignal
4
9
  module Rack
5
- # Appsignal module that tracks exceptions in Streaming rack responses.
10
+ # Instrumentation middleware that tracks exceptions in streaming Rack
11
+ # responses.
6
12
  #
7
13
  # @api private
8
- class StreamingListener
14
+ class StreamingListener < AbstractMiddleware
9
15
  def initialize(app, options = {})
10
- Appsignal.internal_logger.debug "Initializing Appsignal::Rack::StreamingListener"
11
- @app = app
12
- @options = options
13
- end
14
-
15
- def call(env)
16
- if Appsignal.active?
17
- call_with_appsignal_monitoring(env)
18
- else
19
- @app.call(env)
20
- end
16
+ options[:instrument_event_name] ||= "process_streaming_request.rack"
17
+ super
21
18
  end
22
19
 
23
- def call_with_appsignal_monitoring(env)
24
- request = ::Rack::Request.new(env)
25
- transaction = Appsignal::Transaction.create(
26
- SecureRandom.uuid,
27
- Appsignal::Transaction::HTTP_REQUEST,
28
- request
29
- )
20
+ def add_transaction_metadata_after(transaction, request)
21
+ transaction.set_action_if_nil(request.env["appsignal.action"])
30
22
 
31
- # Instrument a `process_action`, to set params/action name
32
- status, headers, body =
33
- Appsignal.instrument("process_action.rack") do
34
- @app.call(env)
35
- rescue Exception => e # rubocop:disable Lint/RescueException
36
- transaction.set_error(e)
37
- raise e
38
- ensure
39
- transaction.set_action_if_nil(env["appsignal.action"])
40
- transaction.set_metadata("path", request.path)
41
- transaction.set_metadata("method", request.request_method)
42
- transaction.set_http_or_background_queue_start
43
- end
44
-
45
- # Wrap the result body with our StreamWrapper
46
- [status, headers, StreamWrapper.new(body, transaction)]
23
+ super
47
24
  end
48
25
  end
49
26
  end
50
-
51
- class StreamWrapper
52
- def initialize(stream, transaction)
53
- @stream = stream
54
- @transaction = transaction
55
- end
56
-
57
- def each(&block)
58
- @stream.each(&block)
59
- rescue Exception => e # rubocop:disable Lint/RescueException
60
- @transaction.set_error(e)
61
- raise e
62
- end
63
-
64
- def close
65
- @stream.close if @stream.respond_to?(:close)
66
- rescue Exception => e # rubocop:disable Lint/RescueException
67
- @transaction.set_error(e)
68
- raise e
69
- ensure
70
- Appsignal::Transaction.complete_current!
71
- end
72
- end
73
27
  end
@@ -0,0 +1,31 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Appsignal
4
+ # @api private
5
+ module Rack
6
+ # Alias constants that have moved with a warning message that points to the
7
+ # place to update the reference.
8
+ def self.const_missing(name)
9
+ case name
10
+ when :GenericInstrumentation
11
+ require "appsignal/rack/generic_instrumentation"
12
+
13
+ callers = caller
14
+ Appsignal::Utils::StdoutAndLoggerMessage.warning \
15
+ "The constant Appsignal::Rack::GenericInstrumentation has been deprecated. " \
16
+ "Please use the new Appsignal::Rack::InstrumentationMiddleware middleware. " \
17
+ "This new middleware does not default the action name to 'unknown'. " \
18
+ "Set the action name for the endpoint using the Appsignal.set_action helper. " \
19
+ "Read our Rack docs for more information " \
20
+ "https://docs.appsignal.com/ruby/integrations/rack.html " \
21
+ "Update the constant name to " \
22
+ "Appsignal::Rack::InstrumentationMiddleware in the following file to " \
23
+ "remove this message.\n#{callers.first}"
24
+ # Return the alias so it can't ever get stuck in a recursive loop
25
+ Appsignal::Rack::GenericInstrumentationAlias
26
+ else
27
+ super
28
+ end
29
+ end
30
+ end
31
+ end
@@ -74,7 +74,7 @@ module Appsignal
74
74
  end
75
75
 
76
76
  attr_reader :ext, :transaction_id, :action, :namespace, :request, :paused, :tags, :options,
77
- :discarded, :breadcrumbs
77
+ :discarded, :breadcrumbs, :custom_data
78
78
 
79
79
  def initialize(transaction_id, namespace, request, options = {})
80
80
  @transaction_id = transaction_id
@@ -84,10 +84,12 @@ module Appsignal
84
84
  @paused = false
85
85
  @discarded = false
86
86
  @tags = {}
87
+ @custom_data = nil
87
88
  @breadcrumbs = []
88
89
  @store = Hash.new({})
89
90
  @options = options
90
91
  @options[:params_method] ||= :params
92
+ @params = nil
91
93
 
92
94
  @ext = Appsignal::Extension.start_transaction(
93
95
  @transaction_id,
@@ -139,9 +141,13 @@ module Appsignal
139
141
  end
140
142
 
141
143
  def params
142
- return @params if defined?(@params)
144
+ parameters = @params || request_params
143
145
 
144
- request_params
146
+ if parameters.respond_to? :call
147
+ parameters.call
148
+ else
149
+ parameters
150
+ end
145
151
  end
146
152
 
147
153
  # Set parameters on the transaction.
@@ -152,9 +158,17 @@ module Appsignal
152
158
  # The parameters set using {#set_params} are leading over those extracted
153
159
  # from a request's environment.
154
160
  #
161
+ # When both the `given_params` and a block is given to this method, the
162
+ # `given_params` argument is leading and the block will _not_ be called.
163
+ #
164
+ # @since 3.9.1
155
165
  # @param given_params [Hash] The parameters to set on the transaction.
166
+ # @yield This block is called when the transaction is sampled. The block's
167
+ # return value will become the new parameters.
156
168
  # @return [void]
157
- def set_params(given_params)
169
+ # @see {Helpers::Instrumentation#set_params}
170
+ def set_params(given_params = nil, &block)
171
+ @params = block if block
158
172
  @params = given_params if given_params
159
173
  end
160
174
 
@@ -172,14 +186,20 @@ module Appsignal
172
186
  # When no parameters are set this way, the transaction will look for
173
187
  # parameters on the {#request} environment.
174
188
  #
189
+ # @since 3.9.1
175
190
  # @param given_params [Hash] The parameters to set on the transaction if none are already set.
191
+ # @yield This block is called when the transaction is sampled. The block's
192
+ # return value will become the new parameters.
176
193
  # @return [void]
177
- def set_params_if_nil(given_params)
178
- set_params(given_params) unless @params
194
+ # @see {Helpers::Instrumentation#set_params_if_nil}
195
+ def set_params_if_nil(given_params = nil, &block)
196
+ set_params(given_params, &block) unless @params
179
197
  end
180
198
 
181
199
  # Set tags on the transaction.
182
200
  #
201
+ # When this method is called multiple times, it will merge the tags.
202
+ #
183
203
  # @param given_tags [Hash] Collection of tags.
184
204
  # @option given_tags [String, Symbol, Integer] :any
185
205
  # The name of the tag as a Symbol.
@@ -187,13 +207,34 @@ module Appsignal
187
207
  # The name of the tag as a String.
188
208
  # @return [void]
189
209
  #
190
- # @see Appsignal.tag_request
210
+ # @see Helpers::Instrumentation#tag_request
191
211
  # @see https://docs.appsignal.com/ruby/instrumentation/tagging.html
192
212
  # Tagging guide
193
213
  def set_tags(given_tags = {})
194
214
  @tags.merge!(given_tags)
195
215
  end
196
216
 
217
+ # Set custom data on the transaction.
218
+ #
219
+ # When this method is called multiple times, it will overwrite the
220
+ # previously set value.
221
+ #
222
+ # @since 3.10.0
223
+ # @see Appsignal.set_custom_data
224
+ # @see https://docs.appsignal.com/guides/custom-data/sample-data.html
225
+ # Sample data guide
226
+ # @param data [Hash/Array]
227
+ # @return [void]
228
+ def set_custom_data(data)
229
+ case data
230
+ when Array, Hash
231
+ @custom_data = data
232
+ else
233
+ Appsignal.internal_logger
234
+ .error("set_custom_data: Unsupported data type #{data.class} received.")
235
+ end
236
+ end
237
+
197
238
  # Add breadcrumbs to the transaction.
198
239
  #
199
240
  # @param category [String] category of breadcrumb
@@ -376,7 +417,8 @@ module Appsignal
376
417
  :session_data => sanitized_session_data,
377
418
  :metadata => sanitized_metadata,
378
419
  :tags => sanitized_tags,
379
- :breadcrumbs => breadcrumbs
420
+ :breadcrumbs => breadcrumbs,
421
+ :custom_data => custom_data
380
422
  }.each do |key, data|
381
423
  set_sample_data(key, data)
382
424
  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.10.0"
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,13 @@ require "appsignal/hooks"
323
324
  require "appsignal/probes"
324
325
  require "appsignal/marker"
325
326
  require "appsignal/garbage_collection"
327
+ require "appsignal/rack"
328
+ require "appsignal/rack/body_wrapper"
329
+ require "appsignal/rack/abstract_middleware"
330
+ require "appsignal/rack/instrumentation_middleware"
331
+ require "appsignal/rack/event_handler"
326
332
  require "appsignal/integrations/railtie" if defined?(::Rails)
327
333
  require "appsignal/transaction"
328
334
  require "appsignal/version"
329
- require "appsignal/rack/abstract_middleware"
330
- require "appsignal/rack/generic_instrumentation"
331
- require "appsignal/rack/event_handler"
332
335
  require "appsignal/transmitter"
333
336
  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
@@ -165,6 +165,7 @@ describe Appsignal::Config do
165
165
  :enable_statsd => true,
166
166
  :enable_nginx_metrics => false,
167
167
  :enable_rails_error_reporter => true,
168
+ :enable_rake_performance_instrumentation => false,
168
169
  :endpoint => "https://push.appsignal.com",
169
170
  :files_world_accessible => true,
170
171
  :filter_metadata => [],
@@ -385,6 +386,8 @@ describe Appsignal::Config do
385
386
 
386
387
  context "without the selected env" do
387
388
  let(:config) { project_fixture_config("nonsense") }
389
+ let(:log_stream) { std_stream }
390
+ let(:log) { log_contents(log_stream) }
388
391
 
389
392
  it "is not valid or active" do
390
393
  expect(config.valid?).to be_falsy
@@ -392,11 +395,11 @@ describe Appsignal::Config do
392
395
  end
393
396
 
394
397
  it "logs an error" do
395
- expect_any_instance_of(Logger).to receive(:error).once
396
- .with("Not loading from config file: config for 'nonsense' not found")
397
- expect_any_instance_of(Logger).to receive(:error).once
398
- .with("Push API key not set after loading config")
399
- config
398
+ use_logger_with(log_stream) { config }
399
+ expect(log)
400
+ .to contains_log(:error, "Not loading from config file: config for 'nonsense' not found")
401
+ expect(log)
402
+ .to contains_log(:error, "Push API key not set after loading config")
400
403
  end
401
404
  end
402
405
  end
@@ -32,56 +32,53 @@ describe Appsignal::Demo do
32
32
  end
33
33
 
34
34
  describe ".create_example_error_request" do
35
- let!(:error_transaction) { http_request_transaction }
36
- let(:config) { project_fixture_config("production") }
37
- before do
38
- Appsignal.config = config
39
- expect(Appsignal::Transaction).to receive(:new).with(
40
- kind_of(String),
41
- Appsignal::Transaction::HTTP_REQUEST,
42
- kind_of(::Rack::Request),
43
- kind_of(Hash)
44
- ).and_return(error_transaction)
45
- end
46
- subject { described_class.send(:create_example_error_request) }
35
+ before { start_agent }
36
+ around { |example| keep_transactions { example.run } }
47
37
 
48
38
  it "sets an error" do
49
- expect(error_transaction).to receive(:set_error).with(kind_of(described_class::TestError))
50
- expect(error_transaction).to receive(:set_metadata).with("path", "/hello")
51
- expect(error_transaction).to receive(:set_metadata).with("method", "GET")
52
- expect(error_transaction).to receive(:set_metadata).with("demo_sample", "true")
53
- expect(error_transaction).to receive(:complete)
54
- subject
39
+ described_class.send(:create_example_error_request)
40
+
41
+ transaction = last_transaction
42
+ expect(transaction).to have_id
43
+ expect(transaction).to have_namespace(Appsignal::Transaction::HTTP_REQUEST)
44
+ expect(transaction).to have_action("DemoController#hello")
45
+ expect(transaction).to have_error(
46
+ "Appsignal::Demo::TestError",
47
+ "Hello world! This is an error used for demonstration purposes."
48
+ )
49
+ expect(transaction).to include_metadata(
50
+ "path" => "/hello",
51
+ "method" => "GET",
52
+ "demo_sample" => "true"
53
+ )
54
+ expect(transaction).to be_completed
55
55
  end
56
56
  end
57
57
 
58
58
  describe ".create_example_performance_request" do
59
- let!(:performance_transaction) { http_request_transaction }
60
- let(:config) { project_fixture_config("production") }
61
- before do
62
- Appsignal.config = config
63
- expect(Appsignal::Transaction).to receive(:new).with(
64
- kind_of(String),
65
- Appsignal::Transaction::HTTP_REQUEST,
66
- kind_of(::Rack::Request),
67
- kind_of(Hash)
68
- ).and_return(performance_transaction)
69
- end
70
- subject { described_class.send(:create_example_performance_request) }
59
+ before { start_agent }
60
+ around { |example| keep_transactions { example.run } }
71
61
 
72
62
  it "sends a performance sample" do
73
- expect(performance_transaction).to receive(:start_event)
74
- expect(performance_transaction).to receive(:finish_event).with(
75
- "action_view.render",
76
- "Render hello.html.erb",
77
- "<h1>Hello world!</h1>",
78
- Appsignal::EventFormatter::DEFAULT
63
+ described_class.send(:create_example_performance_request)
64
+
65
+ transaction = last_transaction
66
+ expect(transaction).to have_id
67
+ expect(transaction).to have_namespace(Appsignal::Transaction::HTTP_REQUEST)
68
+ expect(transaction).to have_action("DemoController#hello")
69
+ expect(transaction).to_not have_error
70
+ expect(transaction).to include_metadata(
71
+ "path" => "/hello",
72
+ "method" => "GET",
73
+ "demo_sample" => "true"
74
+ )
75
+ expect(transaction).to include_event(
76
+ "name" => "action_view.render",
77
+ "title" => "Render hello.html.erb",
78
+ "body" => "<h1>Hello world!</h1>",
79
+ "body_format" => Appsignal::EventFormatter::DEFAULT
79
80
  )
80
- expect(performance_transaction).to receive(:set_metadata).with("path", "/hello")
81
- expect(performance_transaction).to receive(:set_metadata).with("method", "GET")
82
- expect(performance_transaction).to receive(:set_metadata).with("demo_sample", "true")
83
- expect(performance_transaction).to receive(:complete)
84
- subject
81
+ expect(transaction).to be_completed
85
82
  end
86
83
  end
87
84
  end