appsignal 3.12.6 → 3.13.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: d54d86a604df3df8944cf99dcd63dfe9b337c829543f5d80ce5f6d507ff80dd9
4
- data.tar.gz: 39137b4064d8cd060ef32ce59ca7fe1e66066179673d44ef099af149908feb66
3
+ metadata.gz: 3908c76b33dae84dfbaaa42896c709c8ceaf8443dd3855c4811e660fd9da5df0
4
+ data.tar.gz: a5be1a3498ff49fe1e6de1d09abe81bb4d2ce2a5cc44a69e6fa45ebe9b9d8496
5
5
  SHA512:
6
- metadata.gz: e4073b5455f88773ea180fecd94bf79878d845241d2b614a5c3cf7d3485d9ea300962c838721f44b5ebeeb2cb8ebe9593056d74d0072f22a515ed8b075022740
7
- data.tar.gz: 666e8ff6f6ceb7526c40be3b6cd6b8082209181644fe2538ca3a587b2299a71330210dfaea59656075707a112addbf8f5e96cce224f24db7afb5bf10048812db
6
+ metadata.gz: 98b58eda188a7abce65a74ee3a8dbf3b7c59f6f7c9af28c7cc18181942d7ac9a886f5648f4425af78417d475739172b0ef925851f06307ba2e586d52d9763077
7
+ data.tar.gz: 8311cc2b6c88447565c87cc231c50e3aa0640905cef72f400cb1620057ae22ef779da497dac76287ec9404957684fe838fd6c6471d9fcc5081b5cde94e747f05
data/CHANGELOG.md CHANGED
@@ -1,5 +1,42 @@
1
1
  # AppSignal for Ruby gem Changelog
2
2
 
3
+ ## 3.13.0
4
+
5
+ _Published on 2024-08-14._
6
+
7
+ ### Changed
8
+
9
+ - Remove the HTTP gem's exception handling. Errors from the HTTP gem will no longer always be reported. The error will be reported only when an HTTP request is made in an instrumented context. This gives applications the opportunity to add their own custom exception handling.
10
+
11
+ ```ruby
12
+ begin
13
+ HTTP.get("https://appsignal.com/error")
14
+ rescue => error
15
+ # Either handle the error or report it to AppSignal
16
+ end
17
+ ```
18
+
19
+ (minor [2a452ff0](https://github.com/appsignal/appsignal-ruby/commit/2a452ff07e0b0938b1623fa8846af6ef37917ec2))
20
+ - Rename heartbeats to cron check-ins. Calls to `Appsignal.heartbeat` and `Appsignal::Heartbeat` should be replaced with calls to `Appsignal::CheckIn.cron` and `Appsignal::CheckIn::Cron`, for example:
21
+
22
+ ```ruby
23
+ # Before
24
+ Appsignal.heartbeat("do_something") do
25
+ do_something
26
+ end
27
+
28
+ # After
29
+ Appsignal::CheckIn.cron("do_something") do
30
+ do_something
31
+ end
32
+ ```
33
+
34
+ (patch [2f686cd0](https://github.com/appsignal/appsignal-ruby/commit/2f686cd00d5daa6e0854a8cacfe0e874a3a7c146))
35
+
36
+ ### Deprecated
37
+
38
+ - Calls to `Appsignal.heartbeat` and `Appsignal::Heartbeat` will emit a deprecation warning. (patch [2f686cd0](https://github.com/appsignal/appsignal-ruby/commit/2f686cd00d5daa6e0854a8cacfe0e874a3a7c146))
39
+
3
40
  ## 3.12.6
4
41
 
5
42
  _Published on 2024-08-05._
@@ -18,6 +55,7 @@ _Published on 2024-08-05._
18
55
  raise "some error"
19
56
  end
20
57
 
58
+ # After
21
59
  begin
22
60
  raise "some error"
23
61
  rescue => error
@@ -0,0 +1,80 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Appsignal
4
+ module CheckIn
5
+ class Cron
6
+ class << self
7
+ # @api private
8
+ def transmitter
9
+ @transmitter ||= Appsignal::Transmitter.new(
10
+ "#{Appsignal.config[:logging_endpoint]}/check_ins/json"
11
+ )
12
+ end
13
+
14
+ def emit_initializer_deprecation_warning
15
+ return if @initializer_deprecation_warning_emitted
16
+
17
+ callers = caller
18
+ Appsignal::Utils::StdoutAndLoggerMessage.warning(
19
+ "Passing a `name` keyword argument to `Appsignal::CheckIn::Cron.new` is deprecated. " \
20
+ "Please use the `identifier` keyword argument instead, " \
21
+ "in the following file and elsewhere, to remove this message.\n#{callers[2]}"
22
+ )
23
+ @initializer_deprecation_warning_emitted = true
24
+ end
25
+ end
26
+
27
+ # @api private
28
+ attr_reader :identifier, :digest
29
+
30
+ def initialize(identifier: nil, name: nil)
31
+ @identifier = identifier || name || raise(ArgumentError, "missing keyword: :identifier")
32
+ Cron.emit_initializer_deprecation_warning unless name.nil?
33
+ @digest = SecureRandom.hex(8)
34
+ end
35
+
36
+ def start
37
+ transmit_event("start")
38
+ end
39
+
40
+ def finish
41
+ transmit_event("finish")
42
+ end
43
+
44
+ private
45
+
46
+ def event(kind)
47
+ {
48
+ :identifier => @identifier,
49
+ :digest => @digest,
50
+ :kind => kind,
51
+ :timestamp => Time.now.utc.to_i,
52
+ :check_in_type => "cron"
53
+ }
54
+ end
55
+
56
+ def transmit_event(kind)
57
+ unless Appsignal.active?
58
+ Appsignal.internal_logger.debug(
59
+ "AppSignal not active, not transmitting cron check-in event"
60
+ )
61
+ return
62
+ end
63
+
64
+ response = self.class.transmitter.transmit(event(kind))
65
+
66
+ if response.code.to_i >= 200 && response.code.to_i < 300
67
+ Appsignal.internal_logger.debug(
68
+ "Transmitted cron check-in `#{identifier}` (#{digest}) #{kind} event"
69
+ )
70
+ else
71
+ Appsignal.internal_logger.error(
72
+ "Failed to transmit cron check-in #{kind} event: status code was #{response.code}"
73
+ )
74
+ end
75
+ rescue => e
76
+ Appsignal.internal_logger.error("Failed to transmit cron check-in #{kind} event: #{e}")
77
+ end
78
+ end
79
+ end
80
+ end
@@ -0,0 +1,46 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Appsignal
4
+ module CheckIn
5
+ class << self
6
+ # Track cron check-ins.
7
+ #
8
+ # Track the execution of certain processes by sending a cron check-in.
9
+ #
10
+ # To track the duration of a piece of code, pass a block to {.cron}
11
+ # to report both when the process starts, and when it finishes.
12
+ #
13
+ # If an exception is raised within the block, the finish event will not
14
+ # be reported, triggering a notification about the missing cron check-in.
15
+ # The exception will bubble outside of the cron check-in block.
16
+ #
17
+ # @example Send a cron check-in
18
+ # Appsignal::CheckIn.cron("send_invoices")
19
+ #
20
+ # @example Send a cron check-in with duration
21
+ # Appsignal::CheckIn.cron("send_invoices") do
22
+ # # your code
23
+ # end
24
+ #
25
+ # @param name [String] name of the cron check-in to report.
26
+ # @yield the block to monitor.
27
+ # @return [void]
28
+ # @since 3.13.0
29
+ # @see https://docs.appsignal.com/check-ins/cron
30
+ def cron(identifier)
31
+ cron = Appsignal::CheckIn::Cron.new(:identifier => identifier)
32
+ output = nil
33
+
34
+ if block_given?
35
+ cron.start
36
+ output = yield
37
+ end
38
+
39
+ cron.finish
40
+ output
41
+ end
42
+ end
43
+ end
44
+ end
45
+
46
+ require "appsignal/check_in/cron"
@@ -0,0 +1,20 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Appsignal
4
+ module Helpers
5
+ module Heartbeat
6
+ # @deprecated Use {Appsignal::CheckIn.cron} instead.
7
+ def heartbeat(name, &block)
8
+ unless @heartbeat_helper_deprecation_warning_emitted
9
+ callers = caller
10
+ Appsignal::Utils::StdoutAndLoggerMessage.warning \
11
+ "The helper Appsignal.heartbeat has been deprecated. " \
12
+ "Please update the helper call to Appsignal::CheckIn.cron " \
13
+ "in the following file and elsewhere to remove this message.\n#{callers.first}"
14
+ @heartbeat_helper_deprecation_warning_emitted = true
15
+ end
16
+ Appsignal::CheckIn.cron(name, &block)
17
+ end
18
+ end
19
+ end
20
+ end
@@ -300,7 +300,10 @@ module Appsignal
300
300
  # @see .send_error
301
301
  # @see https://docs.appsignal.com/ruby/instrumentation/integrating-appsignal.html
302
302
  # AppSignal integration guide
303
+ # @see https://docs.appsignal.com/ruby/instrumentation/exception-handling.html
304
+ # Exception handling guide
303
305
  #
306
+ # @deprecated Use `rescue => error` with {.report_error} instead.
304
307
  # @param tags [Hash, nil]
305
308
  # @param namespace [String] the namespace for this error.
306
309
  # @yield yields the given block.
@@ -8,13 +8,8 @@ module Appsignal
8
8
  parsed_request_uri = uri.is_a?(URI) ? uri : URI.parse(uri.to_s)
9
9
  request_uri = "#{parsed_request_uri.scheme}://#{parsed_request_uri.host}"
10
10
 
11
- begin
12
- Appsignal.instrument("request.http_rb", "#{verb.upcase} #{request_uri}") do
13
- super
14
- end
15
- rescue Exception => error # rubocop:disable Lint/RescueException
16
- Appsignal.set_error(error)
17
- raise error
11
+ Appsignal.instrument("request.http_rb", "#{verb.upcase} #{request_uri}") do
12
+ super
18
13
  end
19
14
  end
20
15
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Appsignal
4
- VERSION = "3.12.6"
4
+ VERSION = "3.13.0"
5
5
  end
data/lib/appsignal.rb CHANGED
@@ -6,7 +6,7 @@ require "stringio"
6
6
 
7
7
  require "appsignal/logger"
8
8
  require "appsignal/utils/stdout_and_logger_message"
9
- require "appsignal/helpers/heartbeats"
9
+ require "appsignal/helpers/heartbeat"
10
10
  require "appsignal/helpers/instrumentation"
11
11
  require "appsignal/helpers/metrics"
12
12
 
@@ -18,7 +18,7 @@ require "appsignal/helpers/metrics"
18
18
  # {Appsignal::Helpers::Metrics}) for ease of use.
19
19
  module Appsignal
20
20
  class << self
21
- include Helpers::Heartbeats
21
+ include Helpers::Heartbeat
22
22
  include Helpers::Instrumentation
23
23
  include Helpers::Metrics
24
24
 
@@ -461,6 +461,16 @@ module Appsignal
461
461
  "Please update the constant name to Appsignal::Probes " \
462
462
  "in the following file to remove this message.\n#{callers.first}"
463
463
  Appsignal::Probes
464
+ when :Heartbeat
465
+ unless @heartbeat_constant_deprecation_warning_emitted
466
+ callers = caller
467
+ Appsignal::Utils::StdoutAndLoggerMessage.warning \
468
+ "The constant Appsignal::Heartbeat has been deprecated. " \
469
+ "Please update the constant name to Appsignal::CheckIn::Cron " \
470
+ "in the following file and elsewhere to remove this message.\n#{callers.first}"
471
+ @heartbeat_constant_deprecation_warning_emitted = true
472
+ end
473
+ Appsignal::CheckIn::Cron
464
474
  else
465
475
  super
466
476
  end
@@ -489,4 +499,4 @@ require "appsignal/integrations/railtie" if defined?(::Rails)
489
499
  require "appsignal/transaction"
490
500
  require "appsignal/version"
491
501
  require "appsignal/transmitter"
492
- require "appsignal/heartbeat"
502
+ require "appsignal/check_in"
@@ -0,0 +1,342 @@
1
+ describe Appsignal::Heartbeat do
2
+ let(:err_stream) { std_stream }
3
+
4
+ after do
5
+ Appsignal.instance_variable_set(:@heartbeat_constant_deprecation_warning_emitted, false)
6
+ end
7
+
8
+ it "returns the Cron constant calling the Heartbeat constant" do
9
+ silence { expect(Appsignal::Heartbeat).to be(Appsignal::CheckIn::Cron) }
10
+ end
11
+
12
+ it "prints a deprecation warning to STDERR" do
13
+ capture_std_streams(std_stream, err_stream) do
14
+ expect(Appsignal::Heartbeat).to be(Appsignal::CheckIn::Cron)
15
+ end
16
+
17
+ expect(err_stream.read)
18
+ .to include("appsignal WARNING: The constant Appsignal::Heartbeat has been deprecated.")
19
+ end
20
+
21
+ it "does not print a deprecation warning to STDERR more than once" do
22
+ capture_std_streams(std_stream, err_stream) do
23
+ expect(Appsignal::Heartbeat).to be(Appsignal::CheckIn::Cron)
24
+ end
25
+
26
+ expect(err_stream.read)
27
+ .to include("appsignal WARNING: The constant Appsignal::Heartbeat has been deprecated.")
28
+
29
+ err_stream.truncate(0)
30
+
31
+ capture_std_streams(std_stream, err_stream) do
32
+ expect(Appsignal::Heartbeat).to be(Appsignal::CheckIn::Cron)
33
+ end
34
+
35
+ expect(err_stream.read)
36
+ .not_to include("appsignal WARNING: The constant Appsignal::Heartbeat has been deprecated.")
37
+ end
38
+
39
+ it "logs a warning" do
40
+ logs =
41
+ capture_logs do
42
+ silence do
43
+ expect(Appsignal::Heartbeat).to be(Appsignal::CheckIn::Cron)
44
+ end
45
+ end
46
+
47
+ expect(logs).to contains_log(
48
+ :warn,
49
+ "The constant Appsignal::Heartbeat has been deprecated."
50
+ )
51
+ end
52
+
53
+ it "does not log a warning more than once" do
54
+ logs =
55
+ capture_logs do
56
+ silence do
57
+ expect(Appsignal::Heartbeat).to be(Appsignal::CheckIn::Cron)
58
+ end
59
+ end
60
+
61
+ expect(logs).to contains_log(
62
+ :warn,
63
+ "The constant Appsignal::Heartbeat has been deprecated."
64
+ )
65
+
66
+ logs =
67
+ capture_logs do
68
+ silence do
69
+ expect(Appsignal::Heartbeat).to be(Appsignal::CheckIn::Cron)
70
+ end
71
+ end
72
+
73
+ expect(logs).not_to contains_log(
74
+ :warn,
75
+ "The constant Appsignal::Heartbeat has been deprecated."
76
+ )
77
+ end
78
+ end
79
+
80
+ describe "Appsignal.heartbeat" do
81
+ let(:err_stream) { std_stream }
82
+
83
+ before do
84
+ Appsignal.instance_variable_set(:@heartbeat_helper_deprecation_warning_emitted, false)
85
+ end
86
+
87
+ it "should forward the call to Appsignal::CheckIn.cron" do
88
+ expect(Appsignal::CheckIn).to receive(:cron).with("heartbeat-name")
89
+ expect do
90
+ Appsignal.heartbeat("heartbeat-name")
91
+ end.not_to raise_error
92
+
93
+ block = proc { 42 }
94
+ expect(Appsignal::CheckIn).to receive(:cron).with("heartbeat-name") do |&given_block|
95
+ expect(given_block).to be(block)
96
+ end.and_return("output")
97
+ expect(Appsignal.heartbeat("heartbeat-name", &block)).to eq("output")
98
+ end
99
+
100
+ it "prints a deprecation warning to STDERR" do
101
+ capture_std_streams(std_stream, err_stream) do
102
+ Appsignal.heartbeat("heartbeat-name")
103
+ end
104
+
105
+ expect(err_stream.read)
106
+ .to include("appsignal WARNING: The helper Appsignal.heartbeat has been deprecated.")
107
+ end
108
+
109
+ it "does not print a deprecation warning to STDERR more than once" do
110
+ capture_std_streams(std_stream, err_stream) do
111
+ Appsignal.heartbeat("heartbeat-name")
112
+ end
113
+
114
+ expect(err_stream.read)
115
+ .to include("appsignal WARNING: The helper Appsignal.heartbeat has been deprecated.")
116
+
117
+ err_stream.truncate(0)
118
+
119
+ capture_std_streams(std_stream, err_stream) do
120
+ Appsignal.heartbeat("heartbeat-name")
121
+ end
122
+
123
+ expect(err_stream.read)
124
+ .not_to include("appsignal WARNING: The helper Appsignal.heartbeat has been deprecated.")
125
+ end
126
+
127
+ it "logs a warning" do
128
+ logs =
129
+ capture_logs do
130
+ silence do
131
+ Appsignal.heartbeat("heartbeat-name")
132
+ end
133
+ end
134
+
135
+ expect(logs).to contains_log(
136
+ :warn,
137
+ "The helper Appsignal.heartbeat has been deprecated."
138
+ )
139
+ end
140
+
141
+ it "does not log a warning more than once" do
142
+ logs =
143
+ capture_logs do
144
+ silence do
145
+ Appsignal.heartbeat("heartbeat-name")
146
+ end
147
+ end
148
+
149
+ expect(logs).to contains_log(
150
+ :warn,
151
+ "The helper Appsignal.heartbeat has been deprecated."
152
+ )
153
+
154
+ logs =
155
+ capture_logs do
156
+ silence do
157
+ Appsignal.heartbeat("heartbeat-name")
158
+ end
159
+ end
160
+
161
+ expect(logs).not_to contains_log(
162
+ :warn,
163
+ "The helper Appsignal.heartbeat has been deprecated."
164
+ )
165
+ end
166
+ end
167
+
168
+ describe Appsignal::CheckIn::Cron do
169
+ let(:config) { project_fixture_config }
170
+ let(:cron_checkin) { described_class.new(:name => "cron-checkin-name") }
171
+ let(:transmitter) { Appsignal::Transmitter.new("http://cron_checkins/", config) }
172
+
173
+ before(:each) do
174
+ allow(Appsignal).to receive(:active?).and_return(true)
175
+ config.logger = Logger.new(StringIO.new)
176
+ allow(Appsignal::CheckIn::Cron).to receive(:transmitter).and_return(transmitter)
177
+ end
178
+
179
+ describe "when Appsignal is not active" do
180
+ it "should not transmit any events" do
181
+ allow(Appsignal).to receive(:active?).and_return(false)
182
+ expect(transmitter).not_to receive(:transmit)
183
+
184
+ cron_checkin.start
185
+ cron_checkin.finish
186
+ end
187
+ end
188
+
189
+ describe "#start" do
190
+ it "should send a cron check-in start" do
191
+ expect(transmitter).to receive(:transmit).with(hash_including(
192
+ :identifier => "cron-checkin-name",
193
+ :kind => "start",
194
+ :check_in_type => "cron"
195
+ )).and_return(Net::HTTPResponse.new(nil, "200", nil))
196
+
197
+ expect(Appsignal.internal_logger).to receive(:debug).with(
198
+ "Transmitted cron check-in `cron-checkin-name` (#{cron_checkin.digest}) start event"
199
+ )
200
+ expect(Appsignal.internal_logger).not_to receive(:error)
201
+
202
+ cron_checkin.start
203
+ end
204
+
205
+ it "should log an error if it fails" do
206
+ expect(transmitter).to receive(:transmit).with(hash_including(
207
+ :identifier => "cron-checkin-name",
208
+ :kind => "start",
209
+ :check_in_type => "cron"
210
+ )).and_return(Net::HTTPResponse.new(nil, "499", nil))
211
+
212
+ expect(Appsignal.internal_logger).not_to receive(:debug)
213
+ expect(Appsignal.internal_logger).to receive(:error).with(
214
+ "Failed to transmit cron check-in start event: status code was 499"
215
+ )
216
+
217
+ cron_checkin.start
218
+ end
219
+ end
220
+
221
+ describe "#finish" do
222
+ it "should send a cron check-in finish" do
223
+ expect(transmitter).to receive(:transmit).with(hash_including(
224
+ :identifier => "cron-checkin-name",
225
+ :kind => "finish",
226
+ :check_in_type => "cron"
227
+ )).and_return(Net::HTTPResponse.new(nil, "200", nil))
228
+
229
+ expect(Appsignal.internal_logger).to receive(:debug).with(
230
+ "Transmitted cron check-in `cron-checkin-name` (#{cron_checkin.digest}) finish event"
231
+ )
232
+ expect(Appsignal.internal_logger).not_to receive(:error)
233
+
234
+ cron_checkin.finish
235
+ end
236
+
237
+ it "should log an error if it fails" do
238
+ expect(transmitter).to receive(:transmit).with(hash_including(
239
+ :identifier => "cron-checkin-name",
240
+ :kind => "finish",
241
+ :check_in_type => "cron"
242
+ )).and_return(Net::HTTPResponse.new(nil, "499", nil))
243
+
244
+ expect(Appsignal.internal_logger).not_to receive(:debug)
245
+ expect(Appsignal.internal_logger).to receive(:error).with(
246
+ "Failed to transmit cron check-in finish event: status code was 499"
247
+ )
248
+
249
+ cron_checkin.finish
250
+ end
251
+ end
252
+
253
+ describe ".cron" do
254
+ describe "when a block is given" do
255
+ it "should send a cron check-in start and finish and return the block output" do
256
+ expect(transmitter).to receive(:transmit).with(hash_including(
257
+ :kind => "start",
258
+ :identifier => "cron-checkin-with-block",
259
+ :check_in_type => "cron"
260
+ )).and_return(nil)
261
+
262
+ expect(transmitter).to receive(:transmit).with(hash_including(
263
+ :kind => "finish",
264
+ :identifier => "cron-checkin-with-block",
265
+ :check_in_type => "cron"
266
+ )).and_return(nil)
267
+
268
+ output = Appsignal::CheckIn.cron("cron-checkin-with-block") { "output" }
269
+ expect(output).to eq("output")
270
+ end
271
+
272
+ it "should not send a cron check-in finish event when an error is raised" do
273
+ expect(transmitter).to receive(:transmit).with(hash_including(
274
+ :kind => "start",
275
+ :identifier => "cron-checkin-with-block",
276
+ :check_in_type => "cron"
277
+ )).and_return(nil)
278
+
279
+ expect(transmitter).not_to receive(:transmit).with(hash_including(
280
+ :kind => "finish",
281
+ :identifier => "cron-checkin-with-block",
282
+ :check_in_type => "cron"
283
+ ))
284
+
285
+ expect do
286
+ Appsignal::CheckIn.cron("cron-checkin-with-block") { raise "error" }
287
+ end.to raise_error(RuntimeError, "error")
288
+ end
289
+ end
290
+
291
+ describe "when no block is given" do
292
+ it "should only send a cron check-in finish event" do
293
+ expect(transmitter).to receive(:transmit).with(hash_including(
294
+ :kind => "finish",
295
+ :identifier => "cron-checkin-without-block",
296
+ :check_in_type => "cron"
297
+ )).and_return(nil)
298
+
299
+ Appsignal::CheckIn.cron("cron-checkin-without-block")
300
+ end
301
+ end
302
+ end
303
+
304
+ describe "#initialize" do
305
+ describe "when initialised with deprecated heartbeat keyword names" do
306
+ let(:err_stream) { std_stream }
307
+
308
+ after do
309
+ described_class.instance_variable_set(:@initializer_deprecation_warning_emitted, false)
310
+ end
311
+
312
+ it "can be initialised" do
313
+ cron_checkin = described_class.new(:name => "cron-checkin-name")
314
+ expect(cron_checkin.identifier).to eq("cron-checkin-name")
315
+ end
316
+
317
+ it "logs a deprecation warning" do
318
+ capture_std_streams(std_stream, err_stream) do
319
+ expect(described_class.new(:name => "cron-checkin-name"))
320
+ .to be_a(Appsignal::CheckIn::Cron)
321
+ end
322
+
323
+ expect(err_stream.read)
324
+ .to include(
325
+ "appsignal WARNING: Passing a `name` keyword argument to " \
326
+ "`Appsignal::CheckIn::Cron.new` is deprecated."
327
+ )
328
+ end
329
+ end
330
+
331
+ it "can be initialised with cron check-in keyword names" do
332
+ cron_checkin = described_class.new(:identifier => "cron-checkin-name")
333
+ expect(cron_checkin.identifier).to eq("cron-checkin-name")
334
+ end
335
+
336
+ it "raises an error when no identifier is given" do
337
+ expect do
338
+ described_class.new
339
+ end.to raise_error(ArgumentError, "missing keyword: :identifier")
340
+ end
341
+ end
342
+ end
@@ -67,27 +67,6 @@ if DependencyHelper.http_present?
67
67
  end
68
68
  end
69
69
 
70
- context "with an HTTP exception" do
71
- let(:error) { ExampleException.new("oh no!") }
72
-
73
- it "reports the exception and re-raises it" do
74
- stub_request(:get, "https://www.google.com").and_raise(error)
75
-
76
- expect do
77
- HTTP.get("https://www.google.com")
78
- end.to raise_error(ExampleException)
79
-
80
- expect(transaction).to have_namespace(Appsignal::Transaction::HTTP_REQUEST)
81
- expect(transaction).to include_event(
82
- "body" => "",
83
- "body_format" => Appsignal::EventFormatter::DEFAULT,
84
- "name" => "request.http_rb",
85
- "title" => "GET https://www.google.com"
86
- )
87
- expect(transaction).to have_error(error.class.name, error.message)
88
- end
89
- end
90
-
91
70
  context "with various URI objects" do
92
71
  it "parses an object responding to #to_s" do
93
72
  request_uri = Struct.new(:uri) do
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: appsignal
3
3
  version: !ruby/object:Gem::Version
4
- version: 3.12.6
4
+ version: 3.13.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Robert Beekman
@@ -10,7 +10,7 @@ authors:
10
10
  autorequire:
11
11
  bindir: bin
12
12
  cert_chain: []
13
- date: 2024-08-05 00:00:00.000000000 Z
13
+ date: 2024-08-14 00:00:00.000000000 Z
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
16
16
  name: rack
@@ -186,6 +186,8 @@ files:
186
186
  - lib/appsignal.rb
187
187
  - lib/appsignal/auth_check.rb
188
188
  - lib/appsignal/capistrano.rb
189
+ - lib/appsignal/check_in.rb
190
+ - lib/appsignal/check_in/cron.rb
189
191
  - lib/appsignal/cli.rb
190
192
  - lib/appsignal/cli/demo.rb
191
193
  - lib/appsignal/cli/diagnose.rb
@@ -209,8 +211,7 @@ files:
209
211
  - lib/appsignal/extension.rb
210
212
  - lib/appsignal/extension/jruby.rb
211
213
  - lib/appsignal/garbage_collection.rb
212
- - lib/appsignal/heartbeat.rb
213
- - lib/appsignal/helpers/heartbeats.rb
214
+ - lib/appsignal/helpers/heartbeat.rb
214
215
  - lib/appsignal/helpers/instrumentation.rb
215
216
  - lib/appsignal/helpers/metrics.rb
216
217
  - lib/appsignal/hooks.rb
@@ -312,6 +313,7 @@ files:
312
313
  - spec/lib/appsignal/auth_check_spec.rb
313
314
  - spec/lib/appsignal/capistrano2_spec.rb
314
315
  - spec/lib/appsignal/capistrano3_spec.rb
316
+ - spec/lib/appsignal/check_in_spec.rb
315
317
  - spec/lib/appsignal/cli/demo_spec.rb
316
318
  - spec/lib/appsignal/cli/diagnose/paths_spec.rb
317
319
  - spec/lib/appsignal/cli/diagnose/utils_spec.rb
@@ -336,7 +338,6 @@ files:
336
338
  - spec/lib/appsignal/extension_install_failure_spec.rb
337
339
  - spec/lib/appsignal/extension_spec.rb
338
340
  - spec/lib/appsignal/garbage_collection_spec.rb
339
- - spec/lib/appsignal/heartbeat_spec.rb
340
341
  - spec/lib/appsignal/hooks/action_cable_spec.rb
341
342
  - spec/lib/appsignal/hooks/action_mailer_spec.rb
342
343
  - spec/lib/appsignal/hooks/active_support_notifications/finish_with_state_shared_examples.rb
@@ -488,7 +489,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
488
489
  - !ruby/object:Gem::Version
489
490
  version: '0'
490
491
  requirements: []
491
- rubygems_version: 3.5.14
492
+ rubygems_version: 3.3.7
492
493
  signing_key:
493
494
  specification_version: 4
494
495
  summary: Logs performance and exception data from your app to appsignal.com
@@ -1,59 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Appsignal
4
- class Heartbeat
5
- class << self
6
- # @api private
7
- def transmitter
8
- @transmitter ||= Appsignal::Transmitter.new(
9
- "#{Appsignal.config[:logging_endpoint]}/heartbeats/json"
10
- )
11
- end
12
- end
13
-
14
- attr_reader :name, :id
15
-
16
- def initialize(name:)
17
- @name = name
18
- @id = SecureRandom.hex(8)
19
- end
20
-
21
- def start
22
- transmit_event("start")
23
- end
24
-
25
- def finish
26
- transmit_event("finish")
27
- end
28
-
29
- private
30
-
31
- def event(kind)
32
- {
33
- :name => name,
34
- :id => @id,
35
- :kind => kind,
36
- :timestamp => Time.now.utc.to_i
37
- }
38
- end
39
-
40
- def transmit_event(kind)
41
- unless Appsignal.active?
42
- Appsignal.internal_logger.debug("AppSignal not active, not transmitting heartbeat event")
43
- return
44
- end
45
-
46
- response = self.class.transmitter.transmit(event(kind))
47
-
48
- if response.code.to_i >= 200 && response.code.to_i < 300
49
- Appsignal.internal_logger.debug("Transmitted heartbeat `#{name}` (#{id}) #{kind} event")
50
- else
51
- Appsignal.internal_logger.error(
52
- "Failed to transmit heartbeat event: status code was #{response.code}"
53
- )
54
- end
55
- rescue => e
56
- Appsignal.internal_logger.error("Failed to transmit heartbeat event: #{e}")
57
- end
58
- end
59
- end
@@ -1,44 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Appsignal
4
- module Helpers
5
- module Heartbeats
6
- # Track heartbeats
7
- #
8
- # Track the execution of certain processes by sending a hearbeat.
9
- #
10
- # To track the duration of a piece of code, pass a block to {.heartbeat}
11
- # to report both when the process starts, and when it finishes.
12
- #
13
- # If an exception is raised within the block, the finish event will not
14
- # be reported, triggering a notification about the missing heartbeat. The
15
- # exception will bubble outside of the heartbeat block.
16
- #
17
- # @example Send a heartbeat
18
- # Appsignal.heartbeat("send_invoices")
19
- #
20
- # @example Send a heartbeat with duration
21
- # Appsignal.heartbeat("send_invoices") do
22
- # # your code
23
- # end
24
- #
25
- # @param name [String] name of the heartbeat to report.
26
- # @yield the block to monitor.
27
- # @return [void]
28
- # @since 3.7.0
29
- # @see https://docs.appsignal.com/heartbeats
30
- def heartbeat(name)
31
- heartbeat = Appsignal::Heartbeat.new(:name => name)
32
- output = nil
33
-
34
- if block_given?
35
- heartbeat.start
36
- output = yield
37
- end
38
-
39
- heartbeat.finish
40
- output
41
- end
42
- end
43
- end
44
- end
@@ -1,127 +0,0 @@
1
- describe Appsignal::Heartbeat do
2
- let(:config) { project_fixture_config }
3
- let(:heartbeat) { described_class.new(:name => "heartbeat-name") }
4
- let(:transmitter) { Appsignal::Transmitter.new("http://heartbeats/", config) }
5
-
6
- before(:each) do
7
- allow(Appsignal).to receive(:active?).and_return(true)
8
- config.logger = Logger.new(StringIO.new)
9
- allow(Appsignal::Heartbeat).to receive(:transmitter).and_return(transmitter)
10
- end
11
-
12
- describe "when Appsignal is not active" do
13
- it "should not transmit any events" do
14
- allow(Appsignal).to receive(:active?).and_return(false)
15
- expect(transmitter).not_to receive(:transmit)
16
-
17
- heartbeat.start
18
- heartbeat.finish
19
- end
20
- end
21
-
22
- describe "#start" do
23
- it "should send a heartbeat start" do
24
- expect(transmitter).to receive(:transmit).with(hash_including(
25
- :name => "heartbeat-name",
26
- :kind => "start"
27
- )).and_return(Net::HTTPResponse.new(nil, "200", nil))
28
-
29
- expect(Appsignal.internal_logger).to receive(:debug).with(
30
- "Transmitted heartbeat `heartbeat-name` (#{heartbeat.id}) start event"
31
- )
32
- expect(Appsignal.internal_logger).not_to receive(:error)
33
-
34
- heartbeat.start
35
- end
36
-
37
- it "should log an error if it fails" do
38
- expect(transmitter).to receive(:transmit).with(hash_including(
39
- :name => "heartbeat-name",
40
- :kind => "start"
41
- )).and_return(Net::HTTPResponse.new(nil, "499", nil))
42
-
43
- expect(Appsignal.internal_logger).not_to receive(:debug)
44
- expect(Appsignal.internal_logger).to receive(:error).with(
45
- "Failed to transmit heartbeat event: status code was 499"
46
- )
47
-
48
- heartbeat.start
49
- end
50
- end
51
-
52
- describe "#finish" do
53
- it "should send a heartbeat finish" do
54
- expect(transmitter).to receive(:transmit).with(hash_including(
55
- :name => "heartbeat-name",
56
- :kind => "finish"
57
- )).and_return(Net::HTTPResponse.new(nil, "200", nil))
58
-
59
- expect(Appsignal.internal_logger).to receive(:debug).with(
60
- "Transmitted heartbeat `heartbeat-name` (#{heartbeat.id}) finish event"
61
- )
62
- expect(Appsignal.internal_logger).not_to receive(:error)
63
-
64
- heartbeat.finish
65
- end
66
-
67
- it "should log an error if it fails" do
68
- expect(transmitter).to receive(:transmit).with(hash_including(
69
- :name => "heartbeat-name",
70
- :kind => "finish"
71
- )).and_return(Net::HTTPResponse.new(nil, "499", nil))
72
-
73
- expect(Appsignal.internal_logger).not_to receive(:debug)
74
- expect(Appsignal.internal_logger).to receive(:error).with(
75
- "Failed to transmit heartbeat event: status code was 499"
76
- )
77
-
78
- heartbeat.finish
79
- end
80
- end
81
-
82
- describe ".heartbeat" do
83
- describe "when a block is given" do
84
- it "should send a heartbeat start and finish and return the block output" do
85
- expect(transmitter).to receive(:transmit).with(hash_including(
86
- :kind => "start",
87
- :name => "heartbeat-with-block"
88
- )).and_return(nil)
89
-
90
- expect(transmitter).to receive(:transmit).with(hash_including(
91
- :kind => "finish",
92
- :name => "heartbeat-with-block"
93
- )).and_return(nil)
94
-
95
- output = Appsignal.heartbeat("heartbeat-with-block") { "output" }
96
- expect(output).to eq("output")
97
- end
98
-
99
- it "should not send a heartbeat finish event when an error is raised" do
100
- expect(transmitter).to receive(:transmit).with(hash_including(
101
- :kind => "start",
102
- :name => "heartbeat-with-block"
103
- )).and_return(nil)
104
-
105
- expect(transmitter).not_to receive(:transmit).with(hash_including(
106
- :kind => "finish",
107
- :name => "heartbeat-with-block"
108
- ))
109
-
110
- expect do
111
- Appsignal.heartbeat("heartbeat-with-block") { raise "error" }
112
- end.to raise_error(RuntimeError, "error")
113
- end
114
- end
115
-
116
- describe "when no block is given" do
117
- it "should only send a heartbeat finish event" do
118
- expect(transmitter).to receive(:transmit).with(hash_including(
119
- :kind => "finish",
120
- :name => "heartbeat-without-block"
121
- )).and_return(nil)
122
-
123
- Appsignal.heartbeat("heartbeat-without-block")
124
- end
125
- end
126
- end
127
- end