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 +4 -4
- data/CHANGELOG.md +38 -0
- data/lib/appsignal/check_in/cron.rb +80 -0
- data/lib/appsignal/check_in.rb +46 -0
- data/lib/appsignal/helpers/heartbeat.rb +20 -0
- data/lib/appsignal/helpers/instrumentation.rb +3 -0
- data/lib/appsignal/integrations/http.rb +2 -7
- data/lib/appsignal/version.rb +1 -1
- data/lib/appsignal.rb +13 -3
- data/spec/lib/appsignal/check_in_spec.rb +342 -0
- data/spec/lib/appsignal/integrations/http_spec.rb +0 -21
- metadata +7 -6
- data/lib/appsignal/heartbeat.rb +0 -59
- data/lib/appsignal/helpers/heartbeats.rb +0 -44
- data/spec/lib/appsignal/heartbeat_spec.rb +0 -127
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 3908c76b33dae84dfbaaa42896c709c8ceaf8443dd3855c4811e660fd9da5df0
|
4
|
+
data.tar.gz: a5be1a3498ff49fe1e6de1d09abe81bb4d2ce2a5cc44a69e6fa45ebe9b9d8496
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
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
|
-
|
12
|
-
|
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
|
data/lib/appsignal/version.rb
CHANGED
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/
|
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::
|
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/
|
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.
|
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-
|
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.
|
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
|
data/lib/appsignal/heartbeat.rb
DELETED
@@ -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
|