appsignal 3.7.5 → 3.8.1

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: 01c402441faf18659ecff6becf0b7ae9db255825cc873edd5bf2ccc3aaa62c6b
4
- data.tar.gz: 3b9e4c29a62c073f8c9395c26f26dcfc4496af5ca9352193f04983d11bca9476
3
+ metadata.gz: f68ce83624657d12b65c203950c7a92681d621bc9f5644fcc61d4123417e8e93
4
+ data.tar.gz: ecda706a29b6aea7d52d3620cebb984495c85937acf561a596826fd57c457095
5
5
  SHA512:
6
- metadata.gz: 3c1994c27480cbc29310b88c81ad09534885cf3acd43b7d2439921cf54c2f252023b44e0bf40c0f4b6fa4145fc86f2ba9ff36feca8357874576e928c75bec3e4
7
- data.tar.gz: 2d77c4799ba521b3832ebba0d632a70774d767a92e694cfa23a6e82c4c25c05556f5ebad03e571e09d1ce34be234ac7ede1ae3df601247b23cb4df7ccadfe5a9
6
+ metadata.gz: 9ec9d7754da4808d85efd335d8e9c00bca8f0e2c16f7a4a9246b9bd9d679519c7550202c1d2f809c786e117cde31c76c8c3405664b9878b9b8c61724a05dca14
7
+ data.tar.gz: 955a45291f05e0df7456ae7bef0c7d9be55824b764429a6fffd72985ee252dcf83893e824a610d086c82c0050ae14bb6ddebc6baaf600946c1d50ce55a3ae4d7
@@ -0,0 +1,62 @@
1
+ name: "Create release from tag"
2
+
3
+ on:
4
+ push:
5
+ tags:
6
+ - "v**"
7
+
8
+ permissions:
9
+ contents: write
10
+ actions: write
11
+
12
+ jobs:
13
+ release:
14
+ name: "Create release"
15
+ runs-on: ubuntu-latest
16
+ env:
17
+ PACKAGE_NAME: "Ruby gem"
18
+ CHANGELOG_CATEGORY: "Ruby"
19
+ CHANGELOG_LINK: "https://github.com/appsignal/appsignal-ruby/blob/main/CHANGELOG.md"
20
+ steps:
21
+ - name: Checkout repository at tag
22
+ uses: actions/checkout@v4
23
+ with:
24
+ ref: "${{ github.ref }}"
25
+
26
+ - name: Get tag name
27
+ run: |
28
+ echo "TAG_NAME=${GITHUB_REF#refs/tags/}" >> $GITHUB_ENV
29
+
30
+ - name: Get changelog contents from tag
31
+ run: |
32
+ # Use sed to remove everything after "-----BEGIN PGP SIGNATURE-----" if it's present
33
+ # and also always remove the last line of the git show output
34
+ git show --format=oneline --no-color --no-patch "${{ env.TAG_NAME }}" \
35
+ | sed '1,2d' \
36
+ | sed '$d' \
37
+ | sed '/-----BEGIN PGP SIGNATURE-----/,$d' \
38
+ > CHANGELOG_TEXT.txt
39
+
40
+ echo "" >> CHANGELOG_TEXT.txt
41
+ echo "" >> CHANGELOG_TEXT.txt
42
+
43
+ TAG_NAME_FOR_LINK=$(echo "${{ env.TAG_NAME }}" | sed 's/^v//' | tr -d '.')
44
+ echo "View the [$PACKAGE_NAME ${{ env.TAG_NAME }} changelog]($CHANGELOG_LINK#$TAG_NAME_FOR_LINK) for more information." >> CHANGELOG_TEXT.txt
45
+
46
+ - name: Submit changelog entry
47
+ run: |
48
+ # Prepare JSON payload using jq to ensure proper escaping
49
+ payload=$(jq -n \
50
+ --arg title "$PACKAGE_NAME ${{ env.TAG_NAME }}" \
51
+ --arg category "$CHANGELOG_CATEGORY" \
52
+ --arg version "$(echo "${{ env.TAG_NAME }}" | sed 's/^v//')" \
53
+ --arg changelog "$(cat CHANGELOG_TEXT.txt)" \
54
+ --arg assignee "${{ github.actor }}" \
55
+ '{ref: "main", inputs: {title: $title, category: $category, version: $version, changelog: $changelog, assignee: $assignee}}')
56
+
57
+ curl -X POST \
58
+ -H "Authorization: token ${{ secrets.INTEGRATIONS_CHANGELOG_TOKEN }}" \
59
+ -H "Accept: application/vnd.github+json" \
60
+ --fail-with-body \
61
+ https://api.github.com/repos/appsignal/appsignal.com/actions/workflows/102125282/dispatches \
62
+ -d "$payload"
data/CHANGELOG.md CHANGED
@@ -1,5 +1,42 @@
1
1
  # AppSignal for Ruby gem Changelog
2
2
 
3
+ ## 3.8.1
4
+
5
+ _Published on 2024-06-17._
6
+
7
+ ### Added
8
+
9
+ - [5459a021](https://github.com/appsignal/appsignal-ruby/commit/5459a021d7d4bbbd09a0dcbdf5f3af7bf861b6f5) patch - Report the response status for Rails requests as the `response_status` tag on samples, e.g. 200, 301, 500. This tag is visible on the sample detail page.
10
+
11
+ The response status is also reported as the `response_status` metric.
12
+
13
+ ## 3.8.0
14
+
15
+ _Published on 2024-06-17._
16
+
17
+ ### Changed
18
+
19
+ - [ca53b043](https://github.com/appsignal/appsignal-ruby/commit/ca53b04360ae123498640d043ee7ba74efc4b295) minor - Report the time spent in Rails middleware as part of the request duration. The AppSignal Rack middleware is now higher in the middleware stack and reports more time of the request to give insights in how long other middleware took. This is reported under the new `process_request.rack` event in the event timeline.
20
+
21
+ ### Fixed
22
+
23
+ - [37fbae5a](https://github.com/appsignal/appsignal-ruby/commit/37fbae5a0f1a4e964baceb21837e5d5f0cf903c0) patch - Fix ArgumentError being raised on Ruby logger and Rails.logger error calls. This fixes the error from being raised from within the AppSignal Ruby gem.
24
+ Please do not use this for error reporting. We recommend using our error reporting feature instead to be notified of new errors. Read more on [exception handling in Ruby with our Ruby gem](https://docs.appsignal.com/ruby/instrumentation/exception-handling.html).
25
+
26
+ ```ruby
27
+ # No longer raises an error
28
+ Rails.logger.error StandardError.new("StandardError log message")
29
+ ```
30
+
31
+ ## 3.7.6
32
+
33
+ _Published on 2024-06-11._
34
+
35
+ ### Changed
36
+
37
+ - [704a7d29](https://github.com/appsignal/appsignal-ruby/commit/704a7d29ae428f93549000a2c606bff948040c96) patch - When the minutely probes thread takes more than 60 seconds to run all the registered probes, log an error. This helps find issues with the metrics reported by the probes not being accurately reported for every minute.
38
+ - [5f4cc8be](https://github.com/appsignal/appsignal-ruby/commit/5f4cc8beb0ad88a0a58265d990626a7ee39fddd3) patch - Internal agent changes for the Ruby gem.
39
+
3
40
  ## 3.7.5
4
41
 
5
42
  _Published on 2024-05-14._
data/ext/agent.rb CHANGED
@@ -6,7 +6,7 @@
6
6
  # Modifications to this file will be overwritten with the next agent release.
7
7
 
8
8
  APPSIGNAL_AGENT_CONFIG = {
9
- "version" => "0.35.10",
9
+ "version" => "0.35.12",
10
10
  "mirrors" => [
11
11
  "https://appsignal-agent-releases.global.ssl.fastly.net",
12
12
  "https://d135dj0rjqvssy.cloudfront.net"
@@ -14,131 +14,131 @@ APPSIGNAL_AGENT_CONFIG = {
14
14
  "triples" => {
15
15
  "x86_64-darwin" => {
16
16
  "static" => {
17
- "checksum" => "8bdf6b162e03c5f63bc06f2d49ae789bb14e111636524ed78262bd543587a971",
17
+ "checksum" => "61210c40be70e0616a356d06040961b096e2d47332021a52f3779912a9fe0e4c",
18
18
  "filename" => "appsignal-x86_64-darwin-all-static.tar.gz"
19
19
  },
20
20
  "dynamic" => {
21
- "checksum" => "92535e45232d5fe2eb7b9ff2f731115de566144390cd281449acd5c3a570ebb5",
21
+ "checksum" => "dd165289445c80e4dcc148ea09c613b23b001c90ad885aef1de08db65ab5bf1c",
22
22
  "filename" => "appsignal-x86_64-darwin-all-dynamic.tar.gz"
23
23
  }
24
24
  },
25
25
  "universal-darwin" => {
26
26
  "static" => {
27
- "checksum" => "8bdf6b162e03c5f63bc06f2d49ae789bb14e111636524ed78262bd543587a971",
27
+ "checksum" => "61210c40be70e0616a356d06040961b096e2d47332021a52f3779912a9fe0e4c",
28
28
  "filename" => "appsignal-x86_64-darwin-all-static.tar.gz"
29
29
  },
30
30
  "dynamic" => {
31
- "checksum" => "92535e45232d5fe2eb7b9ff2f731115de566144390cd281449acd5c3a570ebb5",
31
+ "checksum" => "dd165289445c80e4dcc148ea09c613b23b001c90ad885aef1de08db65ab5bf1c",
32
32
  "filename" => "appsignal-x86_64-darwin-all-dynamic.tar.gz"
33
33
  }
34
34
  },
35
35
  "aarch64-darwin" => {
36
36
  "static" => {
37
- "checksum" => "c6453bb54a68cdb0b42864747b328e60a14b5b99921f11757de03db42041bed2",
37
+ "checksum" => "9b97c42561450f9af9ae63816d32b8db69be6f2745226f63d6eada4369c68a20",
38
38
  "filename" => "appsignal-aarch64-darwin-all-static.tar.gz"
39
39
  },
40
40
  "dynamic" => {
41
- "checksum" => "920fa90c131752a40287b55356cd2360e17417753087b74dbf63c339f04dacc9",
41
+ "checksum" => "0c81959ab5de3c98c70b7e308826d7deee8e208ee47b7637d505b0a1d70af8c4",
42
42
  "filename" => "appsignal-aarch64-darwin-all-dynamic.tar.gz"
43
43
  }
44
44
  },
45
45
  "arm64-darwin" => {
46
46
  "static" => {
47
- "checksum" => "c6453bb54a68cdb0b42864747b328e60a14b5b99921f11757de03db42041bed2",
47
+ "checksum" => "9b97c42561450f9af9ae63816d32b8db69be6f2745226f63d6eada4369c68a20",
48
48
  "filename" => "appsignal-aarch64-darwin-all-static.tar.gz"
49
49
  },
50
50
  "dynamic" => {
51
- "checksum" => "920fa90c131752a40287b55356cd2360e17417753087b74dbf63c339f04dacc9",
51
+ "checksum" => "0c81959ab5de3c98c70b7e308826d7deee8e208ee47b7637d505b0a1d70af8c4",
52
52
  "filename" => "appsignal-aarch64-darwin-all-dynamic.tar.gz"
53
53
  }
54
54
  },
55
55
  "arm-darwin" => {
56
56
  "static" => {
57
- "checksum" => "c6453bb54a68cdb0b42864747b328e60a14b5b99921f11757de03db42041bed2",
57
+ "checksum" => "9b97c42561450f9af9ae63816d32b8db69be6f2745226f63d6eada4369c68a20",
58
58
  "filename" => "appsignal-aarch64-darwin-all-static.tar.gz"
59
59
  },
60
60
  "dynamic" => {
61
- "checksum" => "920fa90c131752a40287b55356cd2360e17417753087b74dbf63c339f04dacc9",
61
+ "checksum" => "0c81959ab5de3c98c70b7e308826d7deee8e208ee47b7637d505b0a1d70af8c4",
62
62
  "filename" => "appsignal-aarch64-darwin-all-dynamic.tar.gz"
63
63
  }
64
64
  },
65
65
  "aarch64-linux" => {
66
66
  "static" => {
67
- "checksum" => "4e90ec4bce1e632316a26fdaf03ccd8773bf7a9615eb7a1739c8c53f3fa5221a",
67
+ "checksum" => "358db07cfa85d6bd048bd2bb05fc9607d4fe0d4396fd023d658e945e4a675fba",
68
68
  "filename" => "appsignal-aarch64-linux-all-static.tar.gz"
69
69
  },
70
70
  "dynamic" => {
71
- "checksum" => "d4e5811ab29f801c59caafe445a06c686245666459a45a28240c2db7395abf27",
71
+ "checksum" => "9e76651d52f78882ab126d94a8af61794d1ce0cdffa6dd01a3e032599a1b2796",
72
72
  "filename" => "appsignal-aarch64-linux-all-dynamic.tar.gz"
73
73
  }
74
74
  },
75
75
  "i686-linux" => {
76
76
  "static" => {
77
- "checksum" => "f5bcb9f732cb5af53a5de2f2c916156bdd6677c0e563ddafd23f09576440dfdc",
77
+ "checksum" => "315bf1fc5d9c97b6f26e61f5e39919e0ba425b1d96ea6243cdb2f650487c407e",
78
78
  "filename" => "appsignal-i686-linux-all-static.tar.gz"
79
79
  },
80
80
  "dynamic" => {
81
- "checksum" => "52bf105113a3dbe1e9527c0c733edd3ee05788e340bd41577ed38878df6748f0",
81
+ "checksum" => "8cf0b5e6ef70a7758b98457012bfebb7964acb2d47648f3817c9f32a70bc0ab1",
82
82
  "filename" => "appsignal-i686-linux-all-dynamic.tar.gz"
83
83
  }
84
84
  },
85
85
  "x86-linux" => {
86
86
  "static" => {
87
- "checksum" => "f5bcb9f732cb5af53a5de2f2c916156bdd6677c0e563ddafd23f09576440dfdc",
87
+ "checksum" => "315bf1fc5d9c97b6f26e61f5e39919e0ba425b1d96ea6243cdb2f650487c407e",
88
88
  "filename" => "appsignal-i686-linux-all-static.tar.gz"
89
89
  },
90
90
  "dynamic" => {
91
- "checksum" => "52bf105113a3dbe1e9527c0c733edd3ee05788e340bd41577ed38878df6748f0",
91
+ "checksum" => "8cf0b5e6ef70a7758b98457012bfebb7964acb2d47648f3817c9f32a70bc0ab1",
92
92
  "filename" => "appsignal-i686-linux-all-dynamic.tar.gz"
93
93
  }
94
94
  },
95
95
  "x86_64-linux" => {
96
96
  "static" => {
97
- "checksum" => "6faa14f508f7c27b65d912eedb31f7808e1e2fb1dcaa077db2426c321e1f5c65",
97
+ "checksum" => "3fe42df2a52706c23f967b8421ac816fa37a38998bd24b1d6aafd59a324b23ff",
98
98
  "filename" => "appsignal-x86_64-linux-all-static.tar.gz"
99
99
  },
100
100
  "dynamic" => {
101
- "checksum" => "0981839a288dc2ab6d024bae79789a20f5cadce55c4cbcade925066b83028b65",
101
+ "checksum" => "8781f0a4c4810229f19000ebb882b7d8e5e0440ffcf8e5ffea7d68d082be8e69",
102
102
  "filename" => "appsignal-x86_64-linux-all-dynamic.tar.gz"
103
103
  }
104
104
  },
105
105
  "x86_64-linux-musl" => {
106
106
  "static" => {
107
- "checksum" => "8f54b734e56eae7867b5474c7ad4d79e049fd4063202e1b80989795708354e49",
107
+ "checksum" => "1fe0ed0c0ca51eccd4c2ec3bb94bb1834bae19bc2c185b67c3f940f704abe9fc",
108
108
  "filename" => "appsignal-x86_64-linux-musl-all-static.tar.gz"
109
109
  },
110
110
  "dynamic" => {
111
- "checksum" => "01df4f408e2c0f83204bedfe33e132bfdc6c4a9dcff6581bacf30df45140a49e",
111
+ "checksum" => "f241f905555e17178a72b217dc373ead33daa97757e100b895f2d1318e4dce0d",
112
112
  "filename" => "appsignal-x86_64-linux-musl-all-dynamic.tar.gz"
113
113
  }
114
114
  },
115
115
  "aarch64-linux-musl" => {
116
116
  "static" => {
117
- "checksum" => "b3d247d632e3465b2233dd8bb2e977f248f14286ca870e9bd7b855b550ba1c00",
117
+ "checksum" => "5027782008872f8091608cc5531a6dd90f0652e9ebb0404f7e86eb73f0807ba0",
118
118
  "filename" => "appsignal-aarch64-linux-musl-all-static.tar.gz"
119
119
  },
120
120
  "dynamic" => {
121
- "checksum" => "52d4a422bcf3a9bbbb6119abae21f6b1d1191309103bcfb90a1f786b1af64a71",
121
+ "checksum" => "ae3147790f25cef200142f61eb6ce1f8b3ac5fa2647ad7a4234f1bbb976bde98",
122
122
  "filename" => "appsignal-aarch64-linux-musl-all-dynamic.tar.gz"
123
123
  }
124
124
  },
125
125
  "x86_64-freebsd" => {
126
126
  "static" => {
127
- "checksum" => "1cce550eac963e2edf405e551a613ffd15ae69e4b817b6155b8a5783a9fa9b7f",
127
+ "checksum" => "1337268caaddd66bb170298968d50d76cc66f17e808c46a677ba00d1b78eb317",
128
128
  "filename" => "appsignal-x86_64-freebsd-all-static.tar.gz"
129
129
  },
130
130
  "dynamic" => {
131
- "checksum" => "ea67b696f806127ac7e59d3dd02a5ca47de1526455b957bad4fd69d9b08913fe",
131
+ "checksum" => "2b93af244d1d214b59c2657677bf96445f67cade2fa1bfd6cda78c8bec75cbca",
132
132
  "filename" => "appsignal-x86_64-freebsd-all-dynamic.tar.gz"
133
133
  }
134
134
  },
135
135
  "amd64-freebsd" => {
136
136
  "static" => {
137
- "checksum" => "1cce550eac963e2edf405e551a613ffd15ae69e4b817b6155b8a5783a9fa9b7f",
137
+ "checksum" => "1337268caaddd66bb170298968d50d76cc66f17e808c46a677ba00d1b78eb317",
138
138
  "filename" => "appsignal-x86_64-freebsd-all-static.tar.gz"
139
139
  },
140
140
  "dynamic" => {
141
- "checksum" => "ea67b696f806127ac7e59d3dd02a5ca47de1526455b957bad4fd69d9b08913fe",
141
+ "checksum" => "2b93af244d1d214b59c2657677bf96445f67cade2fa1bfd6cda78c8bec75cbca",
142
142
  "filename" => "appsignal-x86_64-freebsd-all-dynamic.tar.gz"
143
143
  }
144
144
  }
@@ -1,6 +1,5 @@
1
- source 'https://rubygems.org'
1
+ source "https://rubygems.org"
2
2
 
3
- gem 'grape'
4
- gem 'activesupport', '~> 4.2'
3
+ gem "grape"
5
4
 
6
- gemspec :path => '../'
5
+ gemspec :path => "../"
@@ -3,6 +3,7 @@
3
3
  module Appsignal
4
4
  class Heartbeat
5
5
  class << self
6
+ # @api private
6
7
  def transmitter
7
8
  @transmitter ||= Appsignal::Transmitter.new(
8
9
  "#{Appsignal.config[:logging_endpoint]}/heartbeats/json"
@@ -55,17 +56,4 @@ module Appsignal
55
56
  Appsignal.internal_logger.error("Failed to transmit heartbeat event: #{e}")
56
57
  end
57
58
  end
58
-
59
- def self.heartbeat(name)
60
- heartbeat = Appsignal::Heartbeat.new(:name => name)
61
- output = nil
62
-
63
- if block_given?
64
- heartbeat.start
65
- output = yield
66
- end
67
-
68
- heartbeat.finish
69
- output
70
- end
71
59
  end
@@ -0,0 +1,44 @@
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
@@ -29,6 +29,11 @@ module Appsignal
29
29
  # Start logger
30
30
  Appsignal.start_logger
31
31
 
32
+ app.middleware.insert(
33
+ 0,
34
+ ::Rack::Events,
35
+ [Appsignal::Rack::EventHandler.new]
36
+ )
32
37
  app.middleware.insert_after(
33
38
  ActionDispatch::DebugExceptions,
34
39
  Appsignal::Rack::RailsInstrumentation
@@ -53,6 +53,13 @@ module Appsignal
53
53
 
54
54
  message = formatter.call(severity, Time.now, group, message) if formatter
55
55
 
56
+ unless message.is_a?(String)
57
+ Appsignal.internal_logger.warn(
58
+ "Logger message was ignored, because it was not a String: #{message.inspect}"
59
+ )
60
+ return
61
+ end
62
+
56
63
  Appsignal::Extension.log(
57
64
  group,
58
65
  SEVERITY_MAP.fetch(severity, 0),
@@ -112,6 +119,8 @@ module Appsignal
112
119
  message = yield if message.nil? && block_given?
113
120
  return if message.nil?
114
121
 
122
+ message = "#{message.class}: #{message.message}" if message.is_a?(Exception)
123
+
115
124
  add_with_attributes(ERROR, message, @group, attributes)
116
125
  end
117
126
 
@@ -1,7 +1,9 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Appsignal
4
- module Probes
4
+ module Probes # rubocop:disable Metrics/ModuleLength
5
+ ITERATION_IN_SECONDS = 60
6
+
5
7
  class ProbeCollection
6
8
  def initialize
7
9
  @probes = {}
@@ -180,6 +182,7 @@ module Appsignal
180
182
  sleep initial_wait_time
181
183
  initialize_probes
182
184
  loop do
185
+ start_time = Time.now
183
186
  logger = Appsignal.internal_logger
184
187
  mutex.synchronize do
185
188
  logger.debug("Gathering minutely metrics with #{probe_instances.count} probes")
@@ -191,6 +194,15 @@ module Appsignal
191
194
  logger.debug ex.backtrace.join("\n")
192
195
  end
193
196
  end
197
+ end_time = Time.now
198
+ duration = end_time - start_time
199
+ if duration >= ITERATION_IN_SECONDS
200
+ logger.error(
201
+ "The minutely probes took more than 60 seconds. " \
202
+ "The probes should not take this long as metrics will not " \
203
+ "be accurately reported."
204
+ )
205
+ end
194
206
  sleep wait_time
195
207
  end
196
208
  end
@@ -214,16 +226,16 @@ module Appsignal
214
226
 
215
227
  # @api private
216
228
  def wait_time
217
- 60 - Time.now.sec
229
+ ITERATION_IN_SECONDS - Time.now.sec
218
230
  end
219
231
 
220
232
  private
221
233
 
222
234
  def initial_wait_time
223
- remaining_seconds = 60 - Time.now.sec
235
+ remaining_seconds = ITERATION_IN_SECONDS - Time.now.sec
224
236
  return remaining_seconds if remaining_seconds > 30
225
237
 
226
- remaining_seconds + 60
238
+ remaining_seconds + ITERATION_IN_SECONDS
227
239
  end
228
240
 
229
241
  def initialize_probes
@@ -0,0 +1,90 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Appsignal
4
+ module Rack
5
+ APPSIGNAL_TRANSACTION = "appsignal.transaction"
6
+ RACK_AFTER_REPLY = "rack.after_reply"
7
+
8
+ class EventHandler
9
+ include ::Rack::Events::Abstract
10
+
11
+ def self.safe_execution(name)
12
+ yield
13
+ rescue => e
14
+ Appsignal.internal_logger.error(
15
+ "Error occurred in #{name}: #{e.class}: #{e}: #{e.backtrace}"
16
+ )
17
+ end
18
+
19
+ def on_start(request, _response)
20
+ self.class.safe_execution("Appsignal::Rack::EventHandler#on_start") do
21
+ transaction = Appsignal::Transaction.create(
22
+ SecureRandom.uuid,
23
+ Appsignal::Transaction::HTTP_REQUEST,
24
+ request
25
+ )
26
+ request.env[APPSIGNAL_TRANSACTION] = transaction
27
+
28
+ request.env[RACK_AFTER_REPLY] ||= []
29
+ request.env[RACK_AFTER_REPLY] << proc do
30
+ Appsignal::Rack::EventHandler
31
+ .safe_execution("Appsignal::Rack::EventHandler's after_reply") do
32
+ transaction.finish_event("process_request.rack", "", "")
33
+ transaction.set_http_or_background_queue_start
34
+
35
+ # Make sure the current transaction is always closed when the request
36
+ # is finished. This is a fallback for in case the `on_finish`
37
+ # callback is not called. This is supported by servers like Puma and
38
+ # Unicorn.
39
+ #
40
+ # The EventHandler.on_finish callback should be called first, this is
41
+ # just a fallback if that doesn't get called.
42
+ Appsignal::Transaction.complete_current!
43
+ end
44
+ end
45
+ transaction.start_event
46
+ end
47
+ end
48
+
49
+ def on_error(request, _response, error)
50
+ self.class.safe_execution("Appsignal::Rack::EventHandler#on_error") do
51
+ transaction = request.env[APPSIGNAL_TRANSACTION]
52
+ return unless transaction
53
+
54
+ transaction.set_error(error)
55
+ end
56
+ end
57
+
58
+ def on_finish(request, response)
59
+ self.class.safe_execution("Appsignal::Rack::EventHandler#on_finish") do
60
+ transaction = request.env[APPSIGNAL_TRANSACTION]
61
+ return unless transaction
62
+
63
+ transaction.finish_event("process_request.rack", "", "")
64
+ transaction.set_tags(:response_status => response.status)
65
+ transaction.set_http_or_background_queue_start
66
+ Appsignal.increment_counter(
67
+ :response_status,
68
+ 1,
69
+ :status => response.status,
70
+ :namespace => format_namespace(transaction.namespace)
71
+ )
72
+
73
+ # Make sure the current transaction is always closed when the request
74
+ # is finished
75
+ Appsignal::Transaction.complete_current!
76
+ end
77
+ end
78
+
79
+ private
80
+
81
+ def format_namespace(namespace)
82
+ if namespace == Appsignal::Transaction::HTTP_REQUEST
83
+ :web
84
+ else
85
+ namespace
86
+ end
87
+ end
88
+ end
89
+ end
90
+ end
@@ -22,13 +22,14 @@ module Appsignal
22
22
 
23
23
  def call_with_appsignal_monitoring(env)
24
24
  request = ActionDispatch::Request.new(env)
25
- transaction = Appsignal::Transaction.create(
26
- request_id(env),
27
- Appsignal::Transaction::HTTP_REQUEST,
28
- request,
29
- :params_method => :filtered_parameters
25
+ transaction = env.fetch(
26
+ Appsignal::Rack::APPSIGNAL_TRANSACTION,
27
+ Appsignal::Transaction::NilTransaction.new
30
28
  )
29
+
31
30
  begin
31
+ transaction.params = fetch_params(request)
32
+
32
33
  @app.call(env)
33
34
  rescue Exception => error # rubocop:disable Lint/RescueException
34
35
  transaction.set_error(error)
@@ -38,19 +39,33 @@ module Appsignal
38
39
  if controller
39
40
  transaction.set_action_if_nil("#{controller.class}##{controller.action_name}")
40
41
  end
41
- transaction.set_http_or_background_queue_start
42
+ request_id = fetch_request_id(env)
43
+ transaction.set_tags(:request_id => request_id) if request_id
42
44
  transaction.set_metadata("path", request.path)
43
- begin
44
- transaction.set_metadata("method", request.request_method)
45
- rescue => error
46
- Appsignal.internal_logger.error("Unable to report HTTP request method: '#{error}'")
47
- end
48
- Appsignal::Transaction.complete_current!
45
+ request_method = fetch_request_method(request)
46
+ transaction.set_metadata("method", request_method) if request_method
49
47
  end
50
48
  end
51
49
 
52
- def request_id(env)
53
- env["action_dispatch.request_id"] || SecureRandom.uuid
50
+ def fetch_request_id(env)
51
+ env["action_dispatch.request_id"]
52
+ end
53
+
54
+ def fetch_params(request)
55
+ return unless request.respond_to?(:filtered_parameters)
56
+
57
+ request.filtered_parameters
58
+ rescue => error
59
+ # Getting params from the request has been know to fail.
60
+ Appsignal.internal_logger.debug "Exception while getting Rails params: #{error}"
61
+ nil
62
+ end
63
+
64
+ def fetch_request_method(request)
65
+ request.request_method
66
+ rescue => error
67
+ Appsignal.internal_logger.error("Unable to report HTTP request method: '#{error}'")
68
+ nil
54
69
  end
55
70
  end
56
71
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Appsignal
4
- VERSION = "3.7.5"
4
+ VERSION = "3.8.1"
5
5
  end
data/lib/appsignal.rb CHANGED
@@ -6,6 +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
10
  require "appsignal/helpers/instrumentation"
10
11
  require "appsignal/helpers/metrics"
11
12
 
@@ -17,6 +18,7 @@ require "appsignal/helpers/metrics"
17
18
  # {Appsignal::Helpers::Metrics}) for ease of use.
18
19
  module Appsignal
19
20
  class << self
21
+ include Helpers::Heartbeats
20
22
  include Helpers::Instrumentation
21
23
  include Helpers::Metrics
22
24
 
@@ -95,11 +97,11 @@ module Appsignal
95
97
  # @since 0.7.0
96
98
  def start
97
99
  unless extension_loaded?
98
- internal_logger.info("Not starting appsignal, extension is not loaded")
100
+ internal_logger.info("Not starting AppSignal, extension is not loaded")
99
101
  return
100
102
  end
101
103
 
102
- internal_logger.debug("Starting appsignal")
104
+ internal_logger.debug("Loading AppSignal gem")
103
105
 
104
106
  @config ||= Config.new(
105
107
  Dir.pwd,
@@ -325,5 +327,6 @@ require "appsignal/integrations/railtie" if defined?(::Rails)
325
327
  require "appsignal/transaction"
326
328
  require "appsignal/version"
327
329
  require "appsignal/rack/generic_instrumentation"
330
+ require "appsignal/rack/event_handler"
328
331
  require "appsignal/transmitter"
329
332
  require "appsignal/heartbeat"
@@ -1,6 +1,12 @@
1
1
  describe Appsignal::Logger do
2
+ let(:log_stream) { StringIO.new }
3
+ let(:logs) { log_contents(log_stream) }
2
4
  let(:logger) { Appsignal::Logger.new("group", :level => ::Logger::DEBUG) }
3
5
 
6
+ before do
7
+ Appsignal.internal_logger = test_logger(log_stream)
8
+ end
9
+
4
10
  it "should not create a logger with a nil group" do
5
11
  expect do
6
12
  Appsignal::Logger.new(nil)
@@ -14,6 +20,19 @@ describe Appsignal::Logger do
14
20
  logger.add(::Logger::INFO, "Log message")
15
21
  end
16
22
 
23
+ it "does not log a message that's not a String" do
24
+ expect(Appsignal::Extension).to_not receive(:log)
25
+ logger.add(::Logger::INFO, 123)
26
+ logger.add(::Logger::INFO, {})
27
+ logger.add(::Logger::INFO, [])
28
+ expect(logs)
29
+ .to contains_log(:warn, "Logger message was ignored, because it was not a String: 123")
30
+ expect(logs)
31
+ .to contains_log(:warn, "Logger message was ignored, because it was not a String: []")
32
+ expect(logs)
33
+ .to contains_log(:warn, "Logger message was ignored, because it was not a String: {}")
34
+ end
35
+
17
36
  it "should log with a block" do
18
37
  expect(Appsignal::Extension).to receive(:log)
19
38
  .with("group", 3, 0, "Log message", instance_of(Appsignal::Extension::Data))
@@ -162,4 +181,25 @@ describe Appsignal::Logger do
162
181
  end
163
182
  end
164
183
  end
184
+
185
+ describe "#error with exception object" do
186
+ it "logs the exception class and its message" do
187
+ error =
188
+ begin
189
+ raise ExampleStandardError, "oh no!"
190
+ rescue => e
191
+ # This makes the exception include a backtrace, so we can assert it's NOT included
192
+ e
193
+ end
194
+ expect(Appsignal::Extension).to receive(:log)
195
+ .with(
196
+ "group",
197
+ 6,
198
+ 0,
199
+ "ExampleStandardError: oh no!",
200
+ instance_of(Appsignal::Extension::Data)
201
+ )
202
+ logger.error(error)
203
+ end
204
+ end
165
205
  end
@@ -215,6 +215,29 @@ describe Appsignal::Probes do
215
215
  end
216
216
  end
217
217
 
218
+ context "with a probe that takes 60 seconds" do
219
+ it "logs an error and continues calling the probes every <wait_time>" do
220
+ stub_const("Appsignal::Probes::ITERATION_IN_SECONDS", 0.2)
221
+ calls = 0
222
+ probe = lambda do
223
+ calls += 1
224
+ sleep 0.2
225
+ end
226
+ Appsignal::Probes.register :my_probe, probe
227
+ Appsignal::Probes.register :other_probe, lambda {}
228
+ Appsignal::Probes.start
229
+
230
+ wait_for("enough probe calls") { calls >= 2 }
231
+
232
+ expect(log).to contains_log(
233
+ :error,
234
+ "The minutely probes took more than 60 seconds. " \
235
+ "The probes should not take this long as metrics will not " \
236
+ "be accurately reported."
237
+ )
238
+ end
239
+ end
240
+
218
241
  it "ensures only one minutely probes thread is active at a time" do
219
242
  alive_thread_counter = proc { Thread.list.reject { |t| t.status == "dead" }.length }
220
243
  probe = MockProbe.new
@@ -240,10 +263,6 @@ describe Appsignal::Probes do
240
263
  end
241
264
 
242
265
  context "with thread already started" do
243
- before do
244
- allow(Appsignal::Probes).to receive(:initial_wait_time).and_return(0.00001)
245
- end
246
-
247
266
  it "auto starts probes added after the thread is started" do
248
267
  Appsignal::Probes.start
249
268
  wait_for("Probes thread to start") { Appsignal::Probes.started? }
@@ -290,7 +309,7 @@ describe Appsignal::Probes do
290
309
 
291
310
  describe ".stop" do
292
311
  before do
293
- allow(Appsignal::Probes).to receive(:initial_wait_time).and_return(0.001)
312
+ speed_up_tests!
294
313
  end
295
314
 
296
315
  it "stops the minutely thread" do
@@ -0,0 +1,218 @@
1
+ describe Appsignal::Rack::EventHandler do
2
+ let(:queue_start_time) { fixed_time * 1_000 }
3
+ let(:env) do
4
+ {
5
+ "HTTP_X_REQUEST_START" => "t=#{queue_start_time.to_i}", # in milliseconds
6
+ "REQUEST_METHOD" => "GET",
7
+ "PATH_INFO" => "/path"
8
+ }
9
+ end
10
+ let(:request) { Rack::Request.new(env) }
11
+ let(:response) { nil }
12
+ let(:log_stream) { StringIO.new }
13
+ let(:log) { log_contents(log_stream) }
14
+ before do
15
+ start_agent
16
+ Appsignal.internal_logger = test_logger(log_stream)
17
+ end
18
+ around { |example| keep_transactions { example.run } }
19
+
20
+ def on_start
21
+ described_class.new.on_start(request, response)
22
+ end
23
+
24
+ describe "#on_start" do
25
+ it "creates a new transaction" do
26
+ expect { on_start }.to change { created_transactions.length }.by(1)
27
+
28
+ transaction = last_transaction
29
+ expect(transaction.to_h).to include(
30
+ "id" => kind_of(String),
31
+ "namespace" => Appsignal::Transaction::HTTP_REQUEST
32
+ )
33
+
34
+ expect(Appsignal::Transaction.current).to eq(last_transaction)
35
+ end
36
+
37
+ it "registers transaction on the request environment" do
38
+ on_start
39
+
40
+ expect(request.env[Appsignal::Rack::APPSIGNAL_TRANSACTION])
41
+ .to eq(last_transaction)
42
+ end
43
+
44
+ it "registers an rack.after_reply callback that completes the transaction" do
45
+ request.env[Appsignal::Rack::RACK_AFTER_REPLY] = []
46
+ expect do
47
+ on_start
48
+ end.to change { request.env[Appsignal::Rack::RACK_AFTER_REPLY].length }.by(1)
49
+
50
+ expect(Appsignal::Transaction.current).to eq(last_transaction)
51
+
52
+ callback = request.env[Appsignal::Rack::RACK_AFTER_REPLY].first
53
+ callback.call
54
+
55
+ expect(Appsignal::Transaction.current).to be_kind_of(Appsignal::Transaction::NilTransaction)
56
+
57
+ expect(last_transaction.ext.queue_start).to eq(queue_start_time)
58
+ end
59
+
60
+ it "logs errors from rack.after_reply callbacks" do
61
+ on_start
62
+
63
+ expect(request.env[Appsignal::Rack::APPSIGNAL_TRANSACTION])
64
+ .to receive(:finish_event)
65
+ .and_raise(ExampleStandardError, "oh no")
66
+ callback = request.env[Appsignal::Rack::RACK_AFTER_REPLY].first
67
+ callback.call
68
+
69
+ expect(log).to contains_log(
70
+ :error,
71
+ "Error occurred in Appsignal::Rack::EventHandler's after_reply: ExampleStandardError: oh no"
72
+ )
73
+ end
74
+
75
+ it "logs an error in case of an error" do
76
+ expect(Appsignal::Transaction)
77
+ .to receive(:create).and_raise(ExampleStandardError, "oh no")
78
+
79
+ on_start
80
+
81
+ expect(log).to contains_log(
82
+ :error,
83
+ "Error occurred in Appsignal::Rack::EventHandler#on_start: ExampleStandardError: oh no"
84
+ )
85
+ end
86
+ end
87
+
88
+ describe "#on_error" do
89
+ def on_error(error)
90
+ described_class.new.on_error(request, response, error)
91
+ end
92
+
93
+ it "reports the error" do
94
+ on_start
95
+ on_error(ExampleStandardError.new("the error"))
96
+
97
+ expect(last_transaction.to_h).to include(
98
+ "error" => {
99
+ "name" => "ExampleStandardError",
100
+ "message" => "the error",
101
+ "backtrace" => kind_of(String)
102
+ }
103
+ )
104
+ end
105
+
106
+ it "logs an error in case of an internal error" do
107
+ on_start
108
+
109
+ expect(request.env[Appsignal::Rack::APPSIGNAL_TRANSACTION])
110
+ .to receive(:set_error).and_raise(ExampleStandardError, "oh no")
111
+
112
+ on_error(ExampleStandardError.new("the error"))
113
+
114
+ expect(log).to contains_log(
115
+ :error,
116
+ "Error occurred in Appsignal::Rack::EventHandler#on_error: ExampleStandardError: oh no"
117
+ )
118
+ end
119
+ end
120
+
121
+ describe "#on_finish" do
122
+ let(:response) { Rack::Events::BufferedResponse.new(200, {}, ["body"]) }
123
+
124
+ def on_finish
125
+ described_class.new.on_finish(request, response)
126
+ end
127
+
128
+ it "doesn't do anything without a transaction" do
129
+ on_start
130
+
131
+ request.env[Appsignal::Rack::APPSIGNAL_TRANSACTION] = nil
132
+
133
+ on_finish
134
+
135
+ expect(last_transaction.to_h).to include(
136
+ "action" => nil,
137
+ "sample_data" => {},
138
+ "events" => []
139
+ )
140
+ end
141
+
142
+ it "completes the transaction" do
143
+ on_start
144
+ on_finish
145
+
146
+ expect(last_transaction.to_h).to include(
147
+ # The action is not set on purpose, as we can't set a normalized route
148
+ # It requires the app to set an action name
149
+ "action" => nil,
150
+ "sample_data" => hash_including(
151
+ "environment" => {
152
+ "REQUEST_METHOD" => "GET",
153
+ "PATH_INFO" => "/path"
154
+ }
155
+ )
156
+ )
157
+ expect(last_transaction.ext.queue_start).to eq(queue_start_time)
158
+ end
159
+
160
+ it "doesn't set the action name if already set" do
161
+ on_start
162
+ last_transaction.set_action("My action")
163
+ on_finish
164
+
165
+ expect(last_transaction.to_h).to include(
166
+ "action" => "My action"
167
+ )
168
+ end
169
+
170
+ it "finishes the process_request.rack event" do
171
+ on_start
172
+ on_finish
173
+
174
+ expect(last_transaction.to_h).to include(
175
+ "events" => [
176
+ hash_including(
177
+ "name" => "process_request.rack",
178
+ "title" => "",
179
+ "body" => "",
180
+ "body_format" => Appsignal::EventFormatter::DEFAULT
181
+ )
182
+ ]
183
+ )
184
+ end
185
+
186
+ it "sets the response status as a tag" do
187
+ on_start
188
+ on_finish
189
+
190
+ expect(last_transaction.to_h).to include(
191
+ "sample_data" => hash_including(
192
+ "tags" => { "response_status" => 200 }
193
+ )
194
+ )
195
+ end
196
+
197
+ it "increments the response status counter for response status" do
198
+ expect(Appsignal).to receive(:increment_counter)
199
+ .with(:response_status, 1, :status => 200, :namespace => :web)
200
+
201
+ on_start
202
+ on_finish
203
+ end
204
+
205
+ it "logs an error in case of an error" do
206
+ expect(Appsignal::Transaction)
207
+ .to receive(:complete_current!).and_raise(ExampleStandardError, "oh no")
208
+
209
+ on_start
210
+ on_finish
211
+
212
+ expect(log).to contains_log(
213
+ :error,
214
+ "Error occurred in Appsignal::Rack::EventHandler#on_finish: ExampleStandardError: oh no"
215
+ )
216
+ end
217
+ end
218
+ end
@@ -1,14 +1,21 @@
1
1
  if DependencyHelper.rails_present?
2
- class MockController
3
- end
4
-
5
2
  describe Appsignal::Rack::RailsInstrumentation do
3
+ class MockController; end
4
+
6
5
  let(:log) { StringIO.new }
7
6
  before do
8
7
  start_agent
9
8
  Appsignal.internal_logger = test_logger(log)
10
9
  end
11
10
 
11
+ let(:transaction) do
12
+ Appsignal::Transaction.new(
13
+ "transaction_id",
14
+ Appsignal::Transaction::HTTP_REQUEST,
15
+ Rack::Request.new(env)
16
+ )
17
+ end
18
+ let(:app) { double(:call => true) }
12
19
  let(:params) do
13
20
  {
14
21
  "controller" => "blog_posts",
@@ -19,12 +26,11 @@ if DependencyHelper.rails_present?
19
26
  }
20
27
  end
21
28
  let(:env_extra) { {} }
22
- let(:app) { double(:call => true) }
23
29
  let(:env) do
24
30
  http_request_env_with_data({
25
31
  :params => params,
26
32
  :with_queue_start => true,
27
- "action_dispatch.request_id" => "1",
33
+ "action_dispatch.request_id" => "request_id123",
28
34
  "action_dispatch.parameter_filter" => [:my_custom_param, :password],
29
35
  "action_controller.instance" => double(
30
36
  :class => MockController,
@@ -34,6 +40,9 @@ if DependencyHelper.rails_present?
34
40
  end
35
41
  let(:middleware) { Appsignal::Rack::RailsInstrumentation.new(app, {}) }
36
42
  around { |example| keep_transactions { example.run } }
43
+ before do
44
+ env[Appsignal::Rack::APPSIGNAL_TRANSACTION] = transaction
45
+ end
37
46
 
38
47
  describe "#call" do
39
48
  before do
@@ -43,7 +52,7 @@ if DependencyHelper.rails_present?
43
52
  context "when appsignal is active" do
44
53
  before { allow(Appsignal).to receive(:active?).and_return(true) }
45
54
 
46
- it "should call with monitoring" do
55
+ it "calls with monitoring" do
47
56
  expect(middleware).to receive(:call_with_appsignal_monitoring).with(env)
48
57
  end
49
58
  end
@@ -51,11 +60,11 @@ if DependencyHelper.rails_present?
51
60
  context "when appsignal is not active" do
52
61
  before { allow(Appsignal).to receive(:active?).and_return(false) }
53
62
 
54
- it "should not call with monitoring" do
63
+ it "does not call with monitoring" do
55
64
  expect(middleware).to_not receive(:call_with_appsignal_monitoring)
56
65
  end
57
66
 
58
- it "should call the app" do
67
+ it "calls the app" do
59
68
  expect(app).to receive(:call).with(env)
60
69
  end
61
70
  end
@@ -66,36 +75,34 @@ if DependencyHelper.rails_present?
66
75
  describe "#call_with_appsignal_monitoring" do
67
76
  def run
68
77
  middleware.call(env)
78
+ last_transaction.complete # Manually close transaction to set sample data
69
79
  end
70
80
 
71
81
  it "calls the wrapped app" do
72
- run
82
+ expect { run }.to_not(change { created_transactions.length })
73
83
  expect(app).to have_received(:call).with(env)
74
84
  end
75
85
 
76
- it "creates one transaction with metadata" do
86
+ it "sets request metadata on the transaction" do
77
87
  run
78
88
 
79
- expect(created_transactions.length).to eq(1)
80
- transaction_hash = last_transaction.to_h
81
- expect(transaction_hash).to include(
89
+ expect(last_transaction.to_h).to include(
82
90
  "namespace" => Appsignal::Transaction::HTTP_REQUEST,
83
91
  "action" => "MockController#index",
84
92
  "metadata" => hash_including(
85
93
  "method" => "GET",
86
94
  "path" => "/blog"
95
+ ),
96
+ "sample_data" => hash_including(
97
+ "tags" => { "request_id" => "request_id123" }
87
98
  )
88
99
  )
89
- expect(last_transaction.ext.queue_start).to eq(
90
- fixed_time * 1_000.0
91
- )
92
100
  end
93
101
 
94
- it "filter parameters in Rails" do
102
+ it "reports Rails filter parameters" do
95
103
  run
96
104
 
97
- transaction_hash = last_transaction.to_h
98
- expect(transaction_hash).to include(
105
+ expect(last_transaction.to_h).to include(
99
106
  "sample_data" => hash_including(
100
107
  "params" => params.merge(
101
108
  "my_custom_param" => "[FILTERED]",
@@ -105,6 +112,26 @@ if DependencyHelper.rails_present?
105
112
  )
106
113
  end
107
114
 
115
+ context "with custom params" do
116
+ let(:app) do
117
+ lambda do |env|
118
+ env[Appsignal::Rack::APPSIGNAL_TRANSACTION].params = { "custom_param" => "yes" }
119
+ end
120
+ end
121
+
122
+ it "allows custom params to be set" do
123
+ run
124
+
125
+ expect(last_transaction.to_h).to include(
126
+ "sample_data" => hash_including(
127
+ "params" => {
128
+ "custom_param" => "yes"
129
+ }
130
+ )
131
+ )
132
+ end
133
+ end
134
+
108
135
  context "with an invalid HTTP request method" do
109
136
  let(:env_extra) { { :request_method => "FOO", "REQUEST_METHOD" => "FOO" } }
110
137
 
@@ -113,8 +140,8 @@ if DependencyHelper.rails_present?
113
140
 
114
141
  transaction_hash = last_transaction.to_h
115
142
  expect(transaction_hash["metadata"]).to_not have_key("method")
116
- expect(log_contents(log)).to contains_log(:error,
117
- "Unable to report HTTP request method: '")
143
+ expect(log_contents(log))
144
+ .to contains_log(:error, "Unable to report HTTP request method: '")
118
145
  end
119
146
  end
120
147
 
@@ -137,25 +164,32 @@ if DependencyHelper.rails_present?
137
164
  )
138
165
  end
139
166
  end
140
- end
141
167
 
142
- describe "#request_id" do
143
- subject { middleware.request_id(env) }
168
+ context "with a request path that's not a route" do
169
+ let(:env_extra) do
170
+ {
171
+ :path => "/unknown-route",
172
+ "action_controller.instance" => nil
173
+ }
174
+ end
144
175
 
145
- context "with request id present" do
146
- let(:env) { { "action_dispatch.request_id" => "id" } }
176
+ it "doesn't set an action name" do
177
+ run
147
178
 
148
- it "returns the present id" do
149
- is_expected.to eq "id"
179
+ expect(last_transaction.to_h).to include(
180
+ "action" => nil
181
+ )
150
182
  end
151
183
  end
184
+ end
152
185
 
153
- context "with request id not present" do
154
- let(:env) { {} }
186
+ describe "#fetch_request_id" do
187
+ subject { middleware.fetch_request_id(env) }
155
188
 
156
- it "sets a new id" do
157
- expect(subject.length).to eq 36
158
- end
189
+ let(:env) { { "action_dispatch.request_id" => "id" } }
190
+
191
+ it "returns the action dispatch id" do
192
+ is_expected.to eq "id"
159
193
  end
160
194
  end
161
195
  end
@@ -719,7 +719,6 @@ describe Appsignal::Transaction do
719
719
 
720
720
  sample_data = transaction.to_h["sample_data"]
721
721
  expect(sample_data["environment"]).to include(
722
- "CONTENT_LENGTH" => "0",
723
722
  "REQUEST_METHOD" => "GET",
724
723
  "SERVER_NAME" => "example.org",
725
724
  "SERVER_PORT" => "80",
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.7.5
4
+ version: 3.8.1
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-05-14 00:00:00.000000000 Z
13
+ date: 2024-06-17 00:00:00.000000000 Z
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
16
16
  name: rack
@@ -135,6 +135,7 @@ extra_rdoc_files: []
135
135
  files:
136
136
  - ".github/ISSUE_TEMPLATE/bug_report.md"
137
137
  - ".github/ISSUE_TEMPLATE/chore.md"
138
+ - ".github/workflows/create_release_from_tag.yml"
138
139
  - ".gitignore"
139
140
  - ".gitmodules"
140
141
  - ".rspec"
@@ -208,6 +209,7 @@ files:
208
209
  - lib/appsignal/extension/jruby.rb
209
210
  - lib/appsignal/garbage_collection.rb
210
211
  - lib/appsignal/heartbeat.rb
212
+ - lib/appsignal/helpers/heartbeats.rb
211
213
  - lib/appsignal/helpers/instrumentation.rb
212
214
  - lib/appsignal/helpers/metrics.rb
213
215
  - lib/appsignal/hooks.rb
@@ -269,6 +271,7 @@ files:
269
271
  - lib/appsignal/probes/helpers.rb
270
272
  - lib/appsignal/probes/mri.rb
271
273
  - lib/appsignal/probes/sidekiq.rb
274
+ - lib/appsignal/rack/event_handler.rb
272
275
  - lib/appsignal/rack/generic_instrumentation.rb
273
276
  - lib/appsignal/rack/rails_instrumentation.rb
274
277
  - lib/appsignal/rack/sinatra_instrumentation.rb
@@ -369,6 +372,7 @@ files:
369
372
  - spec/lib/appsignal/probes/mri_spec.rb
370
373
  - spec/lib/appsignal/probes/sidekiq_spec.rb
371
374
  - spec/lib/appsignal/probes_spec.rb
375
+ - spec/lib/appsignal/rack/event_handler_spec.rb
372
376
  - spec/lib/appsignal/rack/generic_instrumentation_spec.rb
373
377
  - spec/lib/appsignal/rack/rails_instrumentation_spec.rb
374
378
  - spec/lib/appsignal/rack/sinatra_instrumentation_spec.rb
@@ -454,7 +458,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
454
458
  - !ruby/object:Gem::Version
455
459
  version: '0'
456
460
  requirements: []
457
- rubygems_version: 3.3.7
461
+ rubygems_version: 3.5.11
458
462
  signing_key:
459
463
  specification_version: 4
460
464
  summary: Logs performance and exception data from your app to appsignal.com