appsignal 4.0.3-java → 4.0.5-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 (42) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +51 -0
  3. data/ext/agent.rb +27 -27
  4. data/lib/appsignal/check_in/cron.rb +2 -34
  5. data/lib/appsignal/check_in/scheduler.rb +192 -0
  6. data/lib/appsignal/check_in.rb +18 -0
  7. data/lib/appsignal/cli/diagnose.rb +1 -1
  8. data/lib/appsignal/config.rb +7 -0
  9. data/lib/appsignal/hooks/at_exit.rb +3 -1
  10. data/lib/appsignal/hooks/puma.rb +5 -1
  11. data/lib/appsignal/integrations/puma.rb +45 -0
  12. data/lib/appsignal/rack/abstract_middleware.rb +3 -47
  13. data/lib/appsignal/rack/body_wrapper.rb +15 -0
  14. data/lib/appsignal/rack/event_handler.rb +2 -0
  15. data/lib/appsignal/rack/hanami_middleware.rb +5 -1
  16. data/lib/appsignal/rack.rb +68 -0
  17. data/lib/appsignal/transmitter.rb +30 -7
  18. data/lib/appsignal/utils/ndjson.rb +15 -0
  19. data/lib/appsignal/utils.rb +1 -0
  20. data/lib/appsignal/version.rb +1 -1
  21. data/lib/appsignal.rb +1 -0
  22. data/spec/lib/appsignal/check_in/cron_spec.rb +202 -0
  23. data/spec/lib/appsignal/check_in/scheduler_spec.rb +443 -0
  24. data/spec/lib/appsignal/config_spec.rb +13 -0
  25. data/spec/lib/appsignal/environment_spec.rb +1 -1
  26. data/spec/lib/appsignal/hooks/at_exit_spec.rb +22 -0
  27. data/spec/lib/appsignal/hooks/puma_spec.rb +31 -23
  28. data/spec/lib/appsignal/integrations/puma_spec.rb +150 -0
  29. data/spec/lib/appsignal/probes_spec.rb +1 -6
  30. data/spec/lib/appsignal/rack/abstract_middleware_spec.rb +41 -122
  31. data/spec/lib/appsignal/rack/body_wrapper_spec.rb +29 -21
  32. data/spec/lib/appsignal/rack_spec.rb +180 -0
  33. data/spec/lib/appsignal/transmitter_spec.rb +48 -2
  34. data/spec/lib/appsignal_spec.rb +5 -0
  35. data/spec/spec_helper.rb +0 -7
  36. data/spec/support/helpers/config_helpers.rb +2 -1
  37. data/spec/support/helpers/take_at_most_helper.rb +21 -0
  38. data/spec/support/matchers/contains_log.rb +10 -3
  39. data/spec/support/mocks/hash_like.rb +10 -0
  40. data/spec/support/mocks/puma_mock.rb +43 -0
  41. metadata +11 -3
  42. data/spec/lib/appsignal/check_in_spec.rb +0 -136
@@ -52,13 +52,41 @@ describe Appsignal::Transmitter do
52
52
  }
53
53
  ).to_return(:status => 200)
54
54
  end
55
- let(:response) { instance.transmit(:the => :payload) }
55
+
56
+ let(:response) { instance.transmit({ :the => :payload }) }
56
57
 
57
58
  it "returns Net::HTTP response" do
58
59
  expect(response).to be_kind_of(Net::HTTPResponse)
59
60
  expect(response.code).to eq "200"
60
61
  end
61
62
 
63
+ describe "with :ndjson format" do
64
+ before do
65
+ stub_request(:post, "https://push.appsignal.com/1/action").with(
66
+ :query => {
67
+ :api_key => "abc",
68
+ :environment => "production",
69
+ :gem_version => Appsignal::VERSION,
70
+ :hostname => config[:hostname],
71
+ :name => "TestApp"
72
+ },
73
+ :body => "{\"the\":\"payload\"}\n{\"part\":\"two\"}",
74
+ :headers => {
75
+ "Content-Type" => "application/x-ndjson; charset=UTF-8"
76
+ }
77
+ ).to_return(:status => 200)
78
+ end
79
+
80
+ let(:response) do
81
+ instance.transmit([{ :the => :payload }, { :part => :two }], :format => :ndjson)
82
+ end
83
+
84
+ it "returns Net::HTTP response" do
85
+ expect(response).to be_kind_of(Net::HTTPResponse)
86
+ expect(response.code).to eq "200"
87
+ end
88
+ end
89
+
62
90
  context "with ca_file_path config option set" do
63
91
  context "when file does not exist" do
64
92
  before do
@@ -106,7 +134,7 @@ describe Appsignal::Transmitter do
106
134
  end
107
135
 
108
136
  describe "#http_post" do
109
- subject { instance.send(:http_post, "the" => "payload") }
137
+ subject { instance.send(:http_post, { "the" => "payload" }, :format => :json) }
110
138
 
111
139
  it "sets the path" do
112
140
  expect(subject.path).to eq instance.uri.request_uri
@@ -115,6 +143,24 @@ describe Appsignal::Transmitter do
115
143
  it "sets the correct headers" do
116
144
  expect(subject["Content-Type"]).to eq "application/json; charset=UTF-8"
117
145
  end
146
+
147
+ it "serialises the payload to JSON" do
148
+ expect(subject.body).to eq "{\"the\":\"payload\"}"
149
+ end
150
+
151
+ describe "with :ndjson format" do
152
+ subject do
153
+ instance.send(:http_post, [{ "the" => "payload" }, { "part" => "two" }], :format => :ndjson)
154
+ end
155
+
156
+ it "sets the correct headers" do
157
+ expect(subject["Content-Type"]).to eq "application/x-ndjson; charset=UTF-8"
158
+ end
159
+
160
+ it "serialises the payload to NDJSON" do
161
+ expect(subject.body).to eq "{\"the\":\"payload\"}\n{\"part\":\"two\"}"
162
+ end
163
+ end
118
164
  end
119
165
 
120
166
  describe "#http_client" do
@@ -581,6 +581,11 @@ describe Appsignal do
581
581
  expect(Appsignal.active?).to be_falsy
582
582
  end
583
583
  end
584
+
585
+ it "calls stop on the check-in scheduler" do
586
+ expect(Appsignal::CheckIn.scheduler).to receive(:stop)
587
+ Appsignal.stop
588
+ end
584
589
  end
585
590
 
586
591
  describe ".started?" do
data/spec/spec_helper.rb CHANGED
@@ -168,13 +168,6 @@ RSpec.configure do |config|
168
168
  end
169
169
 
170
170
  def stop_minutely_probes
171
- thread =
172
- begin
173
- Appsignal::Probes.class_variable_get(:@@thread) # Fetch old thread
174
- rescue NameError
175
- nil
176
- end
177
171
  Appsignal::Probes.stop
178
- thread&.join # Wait for old thread to exit
179
172
  end
180
173
  end
@@ -46,7 +46,7 @@ module ConfigHelpers
46
46
  end
47
47
  module_function :build_config
48
48
 
49
- def start_agent(env: "production", options: {})
49
+ def start_agent(env: "production", options: {}, internal_logger: nil)
50
50
  env = "production" if env == :default
51
51
  env ||= "production"
52
52
  Appsignal.configure(env, :root_path => project_fixture_path) do |config|
@@ -55,6 +55,7 @@ module ConfigHelpers
55
55
  end
56
56
  end
57
57
  Appsignal.start
58
+ Appsignal.internal_logger = internal_logger if internal_logger
58
59
  end
59
60
 
60
61
  def clear_integration_env_vars!
@@ -0,0 +1,21 @@
1
+ module TakeAtMostHelper
2
+ # Assert that it takes at most a certain amount of time to run a block.
3
+ #
4
+ # @example
5
+ # # Assert that it takes at most 1 second to run the block
6
+ # take_at_most(1) { sleep 0.5 }
7
+ #
8
+ # @param time [Integer, Float] The maximum amount of time the block is allowed to
9
+ # run in seconds.
10
+ # @yield Block to run.
11
+ # @raise [StandardError] Raises error if the block takes longer than the
12
+ # specified time to run.
13
+ def take_at_most(time)
14
+ start = Time.now
15
+ yield
16
+ elapsed = Time.now - start
17
+ return if elapsed <= time
18
+
19
+ raise "Expected block to take at most #{time} seconds, but took #{elapsed}"
20
+ end
21
+ end
@@ -1,14 +1,21 @@
1
1
  RSpec::Matchers.define :contains_log do |level, message|
2
- expected_log_line = "[#{level.upcase}] #{message}"
2
+ log_level_prefix = level.upcase
3
3
 
4
4
  match do |actual|
5
- actual.include?(expected_log_line)
5
+ case message
6
+ when Regexp
7
+ /\[#{log_level_prefix}\] #{message}/.match?(actual)
8
+ else
9
+ expected_log_line = "[#{log_level_prefix}] #{message}"
10
+ actual.include?(expected_log_line)
11
+ end
6
12
  end
7
13
 
8
14
  failure_message do |actual|
9
15
  <<~MESSAGE
10
16
  Did not contain log line:
11
- #{expected_log_line}
17
+ Log level: #{log_level_prefix}
18
+ Message: #{message}
12
19
 
13
20
  Received logs:
14
21
  #{actual}
@@ -0,0 +1,10 @@
1
+ class HashLike < Hash
2
+ def initialize(value)
3
+ super
4
+ @value = value
5
+ end
6
+
7
+ def to_h
8
+ @value
9
+ end
10
+ end
@@ -0,0 +1,43 @@
1
+ class PumaMock
2
+ module MiniSSL
3
+ class SSLError < StandardError
4
+ def self.to_s
5
+ "Puma::MiniSSL::SSLError"
6
+ end
7
+ end
8
+ end
9
+
10
+ class HttpParserError < StandardError
11
+ def self.to_s
12
+ "Puma::HttpParserError"
13
+ end
14
+ end
15
+
16
+ class HttpParserError501 < StandardError
17
+ def self.to_s
18
+ "Puma::HttpParserError501"
19
+ end
20
+ end
21
+
22
+ def self.stats
23
+ end
24
+
25
+ def self.cli_config
26
+ @cli_config ||= CliConfig.new
27
+ end
28
+
29
+ class Server
30
+ end
31
+
32
+ module Const
33
+ VERSION = "6.0.0".freeze
34
+ end
35
+
36
+ class CliConfig
37
+ attr_accessor :options
38
+
39
+ def initialize
40
+ @options = {}
41
+ end
42
+ end
43
+ end
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: 4.0.3
4
+ version: 4.0.5
5
5
  platform: java
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-26 00:00:00.000000000 Z
13
+ date: 2024-09-02 00:00:00.000000000 Z
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
16
16
  name: rack
@@ -202,6 +202,7 @@ files:
202
202
  - lib/appsignal/capistrano.rb
203
203
  - lib/appsignal/check_in.rb
204
204
  - lib/appsignal/check_in/cron.rb
205
+ - lib/appsignal/check_in/scheduler.rb
205
206
  - lib/appsignal/cli.rb
206
207
  - lib/appsignal/cli/demo.rb
207
208
  - lib/appsignal/cli/diagnose.rb
@@ -267,6 +268,7 @@ files:
267
268
  - lib/appsignal/integrations/mongo_ruby_driver.rb
268
269
  - lib/appsignal/integrations/net_http.rb
269
270
  - lib/appsignal/integrations/object.rb
271
+ - lib/appsignal/integrations/puma.rb
270
272
  - lib/appsignal/integrations/que.rb
271
273
  - lib/appsignal/integrations/railtie.rb
272
274
  - lib/appsignal/integrations/rake.rb
@@ -309,6 +311,7 @@ files:
309
311
  - lib/appsignal/utils/integration_logger.rb
310
312
  - lib/appsignal/utils/integration_memory_logger.rb
311
313
  - lib/appsignal/utils/json.rb
314
+ - lib/appsignal/utils/ndjson.rb
312
315
  - lib/appsignal/utils/query_params_sanitizer.rb
313
316
  - lib/appsignal/utils/rails_helper.rb
314
317
  - lib/appsignal/utils/stdout_and_logger_message.rb
@@ -322,7 +325,8 @@ files:
322
325
  - spec/lib/appsignal/auth_check_spec.rb
323
326
  - spec/lib/appsignal/capistrano2_spec.rb
324
327
  - spec/lib/appsignal/capistrano3_spec.rb
325
- - spec/lib/appsignal/check_in_spec.rb
328
+ - spec/lib/appsignal/check_in/cron_spec.rb
329
+ - spec/lib/appsignal/check_in/scheduler_spec.rb
326
330
  - spec/lib/appsignal/cli/demo_spec.rb
327
331
  - spec/lib/appsignal/cli/diagnose/paths_spec.rb
328
332
  - spec/lib/appsignal/cli/diagnose/utils_spec.rb
@@ -384,6 +388,7 @@ files:
384
388
  - spec/lib/appsignal/integrations/mongo_ruby_driver_spec.rb
385
389
  - spec/lib/appsignal/integrations/net_http_spec.rb
386
390
  - spec/lib/appsignal/integrations/object_spec.rb
391
+ - spec/lib/appsignal/integrations/puma_spec.rb
387
392
  - spec/lib/appsignal/integrations/que_spec.rb
388
393
  - spec/lib/appsignal/integrations/railtie_spec.rb
389
394
  - spec/lib/appsignal/integrations/resque_spec.rb
@@ -450,6 +455,7 @@ files:
450
455
  - spec/support/helpers/rails_helper.rb
451
456
  - spec/support/helpers/std_streams_helper.rb
452
457
  - spec/support/helpers/system_helpers.rb
458
+ - spec/support/helpers/take_at_most_helper.rb
453
459
  - spec/support/helpers/time_helpers.rb
454
460
  - spec/support/helpers/transaction_helpers.rb
455
461
  - spec/support/helpers/wait_for_helper.rb
@@ -460,7 +466,9 @@ files:
460
466
  - spec/support/mocks/dummy_app.rb
461
467
  - spec/support/mocks/fake_gc_profiler.rb
462
468
  - spec/support/mocks/fake_gvl_tools.rb
469
+ - spec/support/mocks/hash_like.rb
463
470
  - spec/support/mocks/mock_probe.rb
471
+ - spec/support/mocks/puma_mock.rb
464
472
  - spec/support/shared_examples/instrument.rb
465
473
  - spec/support/stubs/appsignal/loaders/loader_stub.rb
466
474
  - spec/support/stubs/delayed_job.rb
@@ -1,136 +0,0 @@
1
- describe Appsignal::CheckIn::Cron do
2
- let(:config) { project_fixture_config }
3
- let(:cron_checkin) { described_class.new(:identifier => "cron-checkin-name") }
4
- let(:transmitter) { Appsignal::Transmitter.new("http://cron_checkins/", 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::CheckIn::Cron).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
- cron_checkin.start
18
- cron_checkin.finish
19
- end
20
- end
21
-
22
- describe "#start" do
23
- it "should send a cron check-in start" do
24
- expect(transmitter).to receive(:transmit).with(hash_including(
25
- :identifier => "cron-checkin-name",
26
- :kind => "start",
27
- :check_in_type => "cron"
28
- )).and_return(Net::HTTPResponse.new(nil, "200", nil))
29
-
30
- expect(Appsignal.internal_logger).to receive(:debug).with(
31
- "Transmitted cron check-in `cron-checkin-name` (#{cron_checkin.digest}) start event"
32
- )
33
- expect(Appsignal.internal_logger).not_to receive(:error)
34
-
35
- cron_checkin.start
36
- end
37
-
38
- it "should log an error if it fails" do
39
- expect(transmitter).to receive(:transmit).with(hash_including(
40
- :identifier => "cron-checkin-name",
41
- :kind => "start",
42
- :check_in_type => "cron"
43
- )).and_return(Net::HTTPResponse.new(nil, "499", nil))
44
-
45
- expect(Appsignal.internal_logger).not_to receive(:debug)
46
- expect(Appsignal.internal_logger).to receive(:error).with(
47
- "Failed to transmit cron check-in start event: status code was 499"
48
- )
49
-
50
- cron_checkin.start
51
- end
52
- end
53
-
54
- describe "#finish" do
55
- it "should send a cron check-in finish" do
56
- expect(transmitter).to receive(:transmit).with(hash_including(
57
- :identifier => "cron-checkin-name",
58
- :kind => "finish",
59
- :check_in_type => "cron"
60
- )).and_return(Net::HTTPResponse.new(nil, "200", nil))
61
-
62
- expect(Appsignal.internal_logger).to receive(:debug).with(
63
- "Transmitted cron check-in `cron-checkin-name` (#{cron_checkin.digest}) finish event"
64
- )
65
- expect(Appsignal.internal_logger).not_to receive(:error)
66
-
67
- cron_checkin.finish
68
- end
69
-
70
- it "should log an error if it fails" do
71
- expect(transmitter).to receive(:transmit).with(hash_including(
72
- :identifier => "cron-checkin-name",
73
- :kind => "finish",
74
- :check_in_type => "cron"
75
- )).and_return(Net::HTTPResponse.new(nil, "499", nil))
76
-
77
- expect(Appsignal.internal_logger).not_to receive(:debug)
78
- expect(Appsignal.internal_logger).to receive(:error).with(
79
- "Failed to transmit cron check-in finish event: status code was 499"
80
- )
81
-
82
- cron_checkin.finish
83
- end
84
- end
85
-
86
- describe ".cron" do
87
- describe "when a block is given" do
88
- it "should send a cron check-in start and finish and return the block output" do
89
- expect(transmitter).to receive(:transmit).with(hash_including(
90
- :kind => "start",
91
- :identifier => "cron-checkin-with-block",
92
- :check_in_type => "cron"
93
- )).and_return(nil)
94
-
95
- expect(transmitter).to receive(:transmit).with(hash_including(
96
- :kind => "finish",
97
- :identifier => "cron-checkin-with-block",
98
- :check_in_type => "cron"
99
- )).and_return(nil)
100
-
101
- output = Appsignal::CheckIn.cron("cron-checkin-with-block") { "output" }
102
- expect(output).to eq("output")
103
- end
104
-
105
- it "should not send a cron check-in finish event when an error is raised" do
106
- expect(transmitter).to receive(:transmit).with(hash_including(
107
- :kind => "start",
108
- :identifier => "cron-checkin-with-block",
109
- :check_in_type => "cron"
110
- )).and_return(nil)
111
-
112
- expect(transmitter).not_to receive(:transmit).with(hash_including(
113
- :kind => "finish",
114
- :identifier => "cron-checkin-with-block",
115
- :check_in_type => "cron"
116
- ))
117
-
118
- expect do
119
- Appsignal::CheckIn.cron("cron-checkin-with-block") { raise "error" }
120
- end.to raise_error(RuntimeError, "error")
121
- end
122
- end
123
-
124
- describe "when no block is given" do
125
- it "should only send a cron check-in finish event" do
126
- expect(transmitter).to receive(:transmit).with(hash_including(
127
- :kind => "finish",
128
- :identifier => "cron-checkin-without-block",
129
- :check_in_type => "cron"
130
- )).and_return(nil)
131
-
132
- Appsignal::CheckIn.cron("cron-checkin-without-block")
133
- end
134
- end
135
- end
136
- end