appsignal 4.6.0 → 4.7.0

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: f788b7bfb3d2b44efa664bc031df2a2af56085daef2ff224144d6b06e96912ea
4
- data.tar.gz: 8600017362cafa764b5ed3f8dbfc41e083b110bcc49374fc66a9a3583ca12f5a
3
+ metadata.gz: 882fa8b34594a9f3bf529528056c1578707ec0cd45f5ef1563933863e6690bc4
4
+ data.tar.gz: a0e19b771ec45cd1b6e734e7e04b6f26ca2bb9abc6b713fca7b752ec93f2f427
5
5
  SHA512:
6
- metadata.gz: a22051b87cae3d4f9d93f34b0cc41765feba84b7eccf8842c178954bf6ba0dbe6977222646c860f0afdf83a26b61ca493728255113455aa1fe49e151604cfc66
7
- data.tar.gz: 442959e2bb59a79878852cb1397b477b6100645f95a98a121ce0c83d6d8aea7cfb8d9e78a6ce8235d5482a625a3e4b19495b3da1ac0b3e9029ec0052801ae668
6
+ metadata.gz: 0aaa738024f11463a5731dc423891ce7bcc34b124ed5db021b6456ddbf4cd42b735e024c5cfba390aea82f6578d6070f17e7cd03cb70f51f1aa78172c34735aa
7
+ data.tar.gz: 20c7183bd8fbb5848c469fdd5b2103041fdd09f4e8e45caa81df31e539e4fc76eaf728b0c6de169043c9ede80c91694606fcaa0dd5fad77660a7b47b38a839a1
data/CHANGELOG.md CHANGED
@@ -1,5 +1,34 @@
1
1
  # AppSignal for Ruby gem Changelog
2
2
 
3
+ ## 4.7.0
4
+
5
+ _Published on 2025-08-29._
6
+
7
+ ### Added
8
+
9
+ - Add Sidekiq worker-level job status metric: `worker_job_count`. This new counter metric's `status` tag will be `processed` for each job that's processed and reports another counter with the `failure` status if the job encountered an error. (minor [fa9859af](https://github.com/appsignal/appsignal-ruby/commit/fa9859af3c82c34201cf68c80858596014fe9c34))
10
+
11
+ ### Fixed
12
+
13
+ - Support streaming bodies. AppSignal's Rack instrumentation now supports streaming bodies in responses, such as those produced by `Async::Cable`. This fixes an issue where AppSignal's Rack instrumentation would cause requests with streaming bodies to crash.
14
+
15
+ If you use our Rack instrumentation through a framework that is automatically instrumented by AppSignal, such as Rails, Hanami, Padrino or Sinatra, this fix is applied automatically.
16
+
17
+ If your application instruments Rack manually, you must remove the following line from your application's initial setup:
18
+
19
+ ```ruby
20
+ use Rack::Events, [Appsignal::Rack::EventHandler.new]
21
+ ```
22
+
23
+ And replace it with the following line:
24
+
25
+ ```ruby
26
+ use Appsignal::Rack::EventMiddleware
27
+ ```
28
+
29
+ (minor [c94315e3](https://github.com/appsignal/appsignal-ruby/commit/c94315e337801347620826504a24f44ba3ee2b53))
30
+ - Avoid instrumenting Rails when AppSignal is not active. If AppSignal is configured to start when the Rails application loads, rather than after it has initialised, only add Rails' instrumentation middlewares if AppSignal was actually started. (patch [0239a2c3](https://github.com/appsignal/appsignal-ruby/commit/0239a2c32d0835af00a4659cc7533465ef17f451))
31
+
3
32
  ## 4.6.0
4
33
 
5
34
  _Published on 2025-07-29._
data/CLAUDE.md CHANGED
@@ -142,6 +142,21 @@ rake extension:install
142
142
  cd ext && rake
143
143
  ```
144
144
 
145
+ ### Type signatures
146
+
147
+ The Ruby gem includes type signatures for better IDE support and static analysis:
148
+
149
+ - `sig/appsignal.rbi` - Sorbet type signatures
150
+ - `sig/appsignal.rbs` - RBS type signatures
151
+
152
+ To regenerate type signatures from YARD documentation:
153
+
154
+ ```bash
155
+ script/generate_signatures
156
+ ```
157
+
158
+ This script uses [sord](https://github.com/AaronC81/sord) to generate both RBI and RBS files from YARD comments in the source code.
159
+
145
160
  ## File organization
146
161
 
147
162
  ### Configuration files
@@ -28,11 +28,19 @@ module Appsignal
28
28
 
29
29
  def self.on_load(app)
30
30
  load_default_config
31
- Appsignal::Integrations::Railtie.add_instrumentation_middleware(app)
32
31
 
33
- return unless app.config.appsignal.start_at == :on_load
32
+ Appsignal::Integrations::Railtie.start if app.config.appsignal.start_at == :on_load
34
33
 
35
- Appsignal::Integrations::Railtie.start
34
+ # If AppSignal is supposed to start after initialization, we need to add the
35
+ # instrumentation middleware now, even if AppSignal may not actually start
36
+ # later, because the middleware stack will be frozen after initialization.
37
+ #
38
+ # Otherwise, only add the instrumentation middleware if AppSignal did actually
39
+ # start before this point, preventing the middleware from being added when
40
+ # AppSignal is not active.
41
+ return unless app.config.appsignal.start_at == :after_initialize || Appsignal.started?
42
+
43
+ add_instrumentation_middleware(app)
36
44
  end
37
45
 
38
46
  def self.after_initialize(app)
@@ -52,14 +60,15 @@ module Appsignal
52
60
 
53
61
  def self.start
54
62
  Appsignal.start
55
- initialize_error_reporter if Appsignal.started?
63
+ return unless Appsignal.started?
64
+
65
+ initialize_error_reporter
56
66
  end
57
67
 
58
68
  def self.add_instrumentation_middleware(app)
59
69
  app.middleware.insert(
60
70
  0,
61
- ::Rack::Events,
62
- [Appsignal::Rack::EventHandler.new]
71
+ ::Appsignal::Rack::EventMiddleware
63
72
  )
64
73
  app.middleware.insert_after(
65
74
  ActionDispatch::DebugExceptions,
@@ -66,8 +66,9 @@ module Appsignal
66
66
 
67
67
  def call(_worker, item, _queue, &block)
68
68
  job_status = nil
69
+ action_name = formatted_action_name(item)
69
70
  transaction = Appsignal::Transaction.create(Appsignal::Transaction::BACKGROUND_JOB)
70
- transaction.set_action_if_nil(formatted_action_name(item))
71
+ transaction.set_action_if_nil(action_name)
71
72
 
72
73
  formatted_metadata(item).each do |key, value|
73
74
  transaction.set_metadata key, value
@@ -93,14 +94,24 @@ module Appsignal
93
94
  Appsignal::Transaction.complete_current! unless exception
94
95
 
95
96
  queue = item["queue"] || "unknown"
97
+
96
98
  if job_status
97
99
  increment_counter "queue_job_count", 1,
98
100
  :queue => queue,
99
101
  :status => job_status
102
+ increment_counter "worker_job_count", 1,
103
+ :worker => action_name,
104
+ :queue => queue,
105
+ :status => job_status
100
106
  end
101
107
  increment_counter "queue_job_count", 1,
102
108
  :queue => queue,
103
109
  :status => :processed
110
+ increment_counter "worker_job_count", 1,
111
+ :worker => action_name,
112
+ :queue => queue,
113
+ :status => :processed
114
+
104
115
  end
105
116
  end
106
117
 
@@ -21,10 +21,7 @@ module Appsignal
21
21
  require "appsignal/rack/hanami_middleware"
22
22
 
23
23
  hanami_app_config = ::Hanami.app.config
24
- hanami_app_config.middleware.use(
25
- ::Rack::Events,
26
- [Appsignal::Rack::EventHandler.new]
27
- )
24
+ hanami_app_config.middleware.use(Appsignal::Rack::EventMiddleware)
28
25
  hanami_app_config.middleware.use(Appsignal::Rack::HanamiMiddleware)
29
26
 
30
27
  return unless Gem::Version.new(Hanami::VERSION) < Gem::Version.new("2.2.0")
@@ -18,7 +18,7 @@ module Appsignal
18
18
  Padrino::Application.prepend(Appsignal::Loaders::PadrinoLoader::PadrinoIntegration)
19
19
 
20
20
  Padrino.before_load do
21
- Padrino.use ::Rack::Events, [Appsignal::Rack::EventHandler.new]
21
+ Padrino.use Appsignal::Rack::EventMiddleware
22
22
  Padrino.use Appsignal::Rack::SinatraBaseInstrumentation,
23
23
  :instrument_event_name => "process_action.padrino"
24
24
  end
@@ -16,7 +16,7 @@ module Appsignal
16
16
  def on_start
17
17
  require "appsignal/rack/sinatra_instrumentation"
18
18
 
19
- ::Sinatra::Base.use(::Rack::Events, [Appsignal::Rack::EventHandler.new])
19
+ ::Sinatra::Base.use(Appsignal::Rack::EventMiddleware)
20
20
  ::Sinatra::Base.use(Appsignal::Rack::SinatraBaseInstrumentation)
21
21
  end
22
22
  end
@@ -2,10 +2,11 @@
2
2
 
3
3
  module Appsignal
4
4
  module Rack
5
- # Instrumentation middleware using Rack's Events module.
5
+ # Instrumentation event handler for `Rack::Events`.
6
6
  #
7
- # We recommend using this in combination with the
8
- # {InstrumentationMiddleware}.
7
+ # Using this middleware directly with `Rack::Events` is deprecated.
8
+ # We recommend using {EventMiddleware} instead, which is compatible with
9
+ # streaming bodies, in combination with the {InstrumentationMiddleware}.
9
10
  #
10
11
  # This middleware will report the response status code as the
11
12
  # `response_status` tag on the sample. It will also report the response
@@ -38,10 +39,12 @@ module Appsignal
38
39
 
39
40
  # @api private
40
41
  attr_reader :id
42
+ attr_writer :using_appsignal_rack_events_middleware
41
43
 
42
44
  # @api private
43
45
  def initialize
44
46
  @id = SecureRandom.uuid
47
+ @using_appsignal_rack_events_middleware = false
45
48
  end
46
49
 
47
50
  # @api private
@@ -51,6 +54,8 @@ module Appsignal
51
54
 
52
55
  # @api private
53
56
  def on_start(request, _response)
57
+ emit_warning_once
58
+
54
59
  return unless Appsignal.active?
55
60
 
56
61
  event_handler = self
@@ -152,6 +157,19 @@ module Appsignal
152
157
  namespace
153
158
  end
154
159
  end
160
+
161
+ def emit_warning_once
162
+ return if @using_appsignal_rack_events_middleware
163
+
164
+ Appsignal.internal_logger.warn <<~MSG
165
+ Rack::Events is not compatible with streaming bodies. Using `Appsignal::Rack::EventHandler`#{" "}
166
+ with `Rack::Events` will break streaming responses in your application and is deprecated.#{" "}
167
+ To silence this warning, use `Appsignal::Rack::EventMiddleware` instead, which is compatible#{" "}
168
+ with streaming bodies.#{" "}
169
+ See https://docs.appsignal.com/ruby/integrations/rack.html for more information.
170
+ MSG
171
+ @using_appsignal_rack_events_middleware = true
172
+ end
155
173
  end
156
174
  end
157
175
  end
@@ -0,0 +1,111 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Appsignal
4
+ module Rack
5
+ # Modified version of the {::Rack::Events} instrumentation
6
+ # middleware.
7
+ #
8
+ # We recommend using this instead of {::Rack::Events}, as it
9
+ # is compatible with streaming bodies.
10
+ #
11
+ # We do not recommend using this middleware directly, instead
12
+ # recommending the use of {EventMiddleware}, which is a
13
+ # convenience wrapper around this middleware that includes
14
+ # AppSignal's {EventHandler}.
15
+ #
16
+ # See the original implementation at:
17
+ # https://github.com/rack/rack/blob/8d3d7857fcd9e5df057a6c22458bab35b3a19c12/lib/rack/events.rb
18
+ class Events < ::Rack::Events
19
+ # A stub for {::Rack::Events::EventedBodyProxy}. It
20
+ # allows the same initialization arguments, but
21
+ # otherwise behaves identically to {::Rack::BodyProxy}.
22
+ #
23
+ # It does not implement `#each`, fixing an issue
24
+ # where the evented body proxy would break
25
+ # streaming responses by always responding to `#each`
26
+ # even if the proxied body did not implement it.
27
+ #
28
+ # Because it ignores the handlers passed to it and
29
+ # behaves like a normal body proxy, the `on_send`
30
+ # event on the handlers is never called.
31
+ class EventedBodyProxy < ::Rack::BodyProxy
32
+ def initialize(body, _request, _response, _handlers, &block)
33
+ super(body, &block)
34
+ end
35
+ end
36
+
37
+ # Notifies the AppSignal event handler that it's being
38
+ # used with the modified middleware, suppressing a
39
+ # deprecation warning.
40
+ def initialize(app, handlers = [])
41
+ super
42
+ handlers.each do |handler|
43
+ if handler.respond_to?(:using_appsignal_rack_events_middleware=)
44
+ handler.using_appsignal_rack_events_middleware = true
45
+ end
46
+ end
47
+ end
48
+
49
+ # The `call` method, exactly as implemented by {::Rack::Events},
50
+ # but redefined here so that it uses our {EventedBodyProxy}
51
+ # instead of the original {::Rack::Events::EventedBodyProxy}.
52
+ #
53
+ # This fixes streaming bodies, but it also means that the
54
+ # `on_send` event on the handlers is never called.
55
+ #
56
+ # See the original implementation at:
57
+ # https://github.com/rack/rack/blob/8d3d7857fcd9e5df057a6c22458bab35b3a19c12/lib/rack/events.rb#L111-L129
58
+ def call(env)
59
+ request = make_request env
60
+ on_start request, nil
61
+
62
+ begin
63
+ status, headers, body = @app.call request.env
64
+ response = make_response status, headers, body
65
+ on_commit request, response
66
+ rescue StandardError => e
67
+ on_error request, response, e
68
+ on_finish request, response
69
+ raise
70
+ end
71
+
72
+ body = EventedBodyProxy.new(body, request, response, @handlers) do
73
+ on_finish request, response
74
+ end
75
+ [response.status, response.headers, body]
76
+ end
77
+ end
78
+
79
+ # Instrumentation middleware using Rack's Events module.
80
+ #
81
+ # A convenience wrapper around our {Events} middleware,
82
+ # modified to be compatible with streaming bodies,
83
+ # that automatically includes AppSignal's {EventHandler}.
84
+ #
85
+ # We recommend using this in combination with the
86
+ # {InstrumentationMiddleware}.
87
+ #
88
+ # This middleware will report the response status code as the
89
+ # `response_status` tag on the sample. It will also report the response
90
+ # status as the `response_status` metric.
91
+ #
92
+ # This middleware will ensure the AppSignal transaction is always completed
93
+ # for every request.
94
+ #
95
+ # @example Add EventMiddleware to a Rack app
96
+ # # Add this middleware as the first middleware of an app
97
+ # use Appsignal::Rack::EventMiddleware
98
+ #
99
+ # # Then add the InstrumentationMiddleware
100
+ # use Appsignal::Rack::InstrumentationMiddleware
101
+ #
102
+ # @see https://docs.appsignal.com/ruby/integrations/rack.html
103
+ # Rack integration documentation.
104
+ # @api public
105
+ class EventMiddleware < Events
106
+ def initialize(app)
107
+ super(app, [Appsignal::Rack::EventHandler.new])
108
+ end
109
+ end
110
+ end
111
+ end
@@ -27,8 +27,8 @@ module Appsignal
27
27
  # require "appsignal"
28
28
  # # Configure and start AppSignal
29
29
  #
30
- # # Add the EventHandler first
31
- # use ::Rack::Events, [Appsignal::Rack::EventHandler.new]
30
+ # # Add the EventMiddleware first
31
+ # use Appsignal::Rack::EventMiddleware
32
32
  # # Add the instrumentation middleware second
33
33
  # use Appsignal::Rack::InstrumentationMiddleware
34
34
  #
@@ -2,5 +2,5 @@
2
2
 
3
3
  module Appsignal
4
4
  # @return [String]
5
- VERSION = "4.6.0"
5
+ VERSION = "4.7.0"
6
6
  end
data/lib/appsignal.rb CHANGED
@@ -643,6 +643,7 @@ require "appsignal/rack/body_wrapper"
643
643
  require "appsignal/rack/abstract_middleware"
644
644
  require "appsignal/rack/instrumentation_middleware"
645
645
  require "appsignal/rack/event_handler"
646
+ require "appsignal/rack/event_middleware"
646
647
  require "appsignal/integrations/railtie" if defined?(::Rails)
647
648
  require "appsignal/transaction"
648
649
  require "appsignal/version"
data/sig/appsignal.rbi CHANGED
@@ -8,7 +8,7 @@
8
8
  module Appsignal
9
9
  extend Appsignal::Helpers::Metrics
10
10
  extend Appsignal::Helpers::Instrumentation
11
- VERSION = T.let("4.5.17", T.untyped)
11
+ VERSION = T.let("4.7.0", T.untyped)
12
12
 
13
13
  class << self
14
14
  # The loaded AppSignal configuration.
metadata CHANGED
@@ -1,15 +1,16 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: appsignal
3
3
  version: !ruby/object:Gem::Version
4
- version: 4.6.0
4
+ version: 4.7.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Robert Beekman
8
8
  - Thijs Cadier
9
9
  - Tom de Bruijn
10
+ autorequire:
10
11
  bindir: bin
11
12
  cert_chain: []
12
- date: 2025-07-29 00:00:00.000000000 Z
13
+ date: 2025-08-29 00:00:00.000000000 Z
13
14
  dependencies:
14
15
  - !ruby/object:Gem::Dependency
15
16
  name: logger
@@ -279,6 +280,7 @@ files:
279
280
  - lib/appsignal/rack/abstract_middleware.rb
280
281
  - lib/appsignal/rack/body_wrapper.rb
281
282
  - lib/appsignal/rack/event_handler.rb
283
+ - lib/appsignal/rack/event_middleware.rb
282
284
  - lib/appsignal/rack/grape_middleware.rb
283
285
  - lib/appsignal/rack/hanami_middleware.rb
284
286
  - lib/appsignal/rack/instrumentation_middleware.rb
@@ -317,6 +319,7 @@ metadata:
317
319
  documentation_uri: https://docs.appsignal.com/ruby/
318
320
  homepage_uri: https://docs.appsignal.com/ruby/
319
321
  source_code_uri: https://github.com/appsignal/appsignal-ruby
322
+ post_install_message:
320
323
  rdoc_options: []
321
324
  require_paths:
322
325
  - lib
@@ -332,7 +335,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
332
335
  - !ruby/object:Gem::Version
333
336
  version: '0'
334
337
  requirements: []
335
- rubygems_version: 3.6.2
338
+ rubygems_version: 3.3.7
339
+ signing_key:
336
340
  specification_version: 4
337
341
  summary: Logs performance and exception data from your app to appsignal.com
338
342
  test_files: []