appsignal 3.5.6 → 3.6.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 +36 -2
- data/ext/agent.rb +27 -27
- data/lib/appsignal/rack/body_wrapper.rb +161 -0
- data/lib/appsignal/rack/generic_instrumentation.rb +17 -4
- data/lib/appsignal/rack/rails_instrumentation.rb +15 -3
- data/lib/appsignal/rack/sinatra_instrumentation.rb +15 -3
- data/lib/appsignal/rack/streaming_listener.rb +26 -35
- data/lib/appsignal/version.rb +1 -1
- data/lib/appsignal.rb +1 -0
- data/resources/cacert.pem +321 -159
- data/spec/lib/appsignal/rack/body_wrapper_spec.rb +220 -0
- data/spec/lib/appsignal/rack/generic_instrumentation_spec.rb +3 -2
- data/spec/lib/appsignal/rack/rails_instrumentation_spec.rb +4 -2
- data/spec/lib/appsignal/rack/sinatra_instrumentation_spec.rb +3 -1
- data/spec/lib/appsignal/rack/streaming_listener_spec.rb +9 -53
- metadata +5 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 6402d39c536a0e4fe970163c92d3207cad1af89c279d0bec8494abf90844434c
|
4
|
+
data.tar.gz: c989b01ded89a0c2643ba5b4bb02d24b02012ee25383b451fee192eae59ab611
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 65908eb0b138011eccd79c0fe0de47f3c2b150bc333eb656fde66f541529fe1801d0404a6dadfc875cbbf53b442613970dabe221fc2ae52fafd55927bb408bc8
|
7
|
+
data.tar.gz: 2852aeb49f06d45606bc58a81c0e344b62326340aff7c81f363a2f081346b2147fd60eb7c38a0065c1dfed94ca4f148b1b866aafc6bada1734a4d1911746e07a
|
data/CHANGELOG.md
CHANGED
@@ -1,5 +1,39 @@
|
|
1
1
|
# AppSignal for Ruby gem Changelog
|
2
2
|
|
3
|
+
## 3.6.0
|
4
|
+
|
5
|
+
_Published on 2024-02-26._
|
6
|
+
|
7
|
+
### Added
|
8
|
+
|
9
|
+
- [9984156f](https://github.com/appsignal/appsignal-ruby/commit/9984156faea0a76cb0fe81594e1ddf40d55dabbe) minor - Add instrumentation for all Rack responses, including streaming responses. New `response_body_each.rack`, `response_body_call.rack` and `response_body_to_ary.rack` events will be shown in the event timeline. This will show how long it takes to complete responses, depending on the response implementation.
|
10
|
+
|
11
|
+
This Sinatra route with a streaming response will be better instrumented, for example:
|
12
|
+
|
13
|
+
```ruby
|
14
|
+
get "/stream" do
|
15
|
+
stream do |out|
|
16
|
+
sleep 1
|
17
|
+
out << "1"
|
18
|
+
sleep 1
|
19
|
+
out << "2"
|
20
|
+
sleep 1
|
21
|
+
out << "3"
|
22
|
+
end
|
23
|
+
end
|
24
|
+
```
|
25
|
+
- [e7706038](https://github.com/appsignal/appsignal-ruby/commit/e7706038d8b2f52ea90441cfa62d5ee867d893a2) patch - Add histogram support to the OpenTelemetry HTTP server. This allows OpenTelemetry-based instrumentations to report histogram data to AppSignal as distribution metrics.
|
26
|
+
|
27
|
+
### Changed
|
28
|
+
|
29
|
+
- [11220302](https://github.com/appsignal/appsignal-ruby/commit/112203023a58e53e607a9fd7d545044fa7d896d5) minor - **Breaking change**: Normalize CPU metrics for cgroups v1 systems. When we can detect how many CPUs are configured in the container's limits, we will normalize the CPU percentages to a maximum of 100%. This is a breaking change. Triggers for CPU percentages that are configured for a CPU percentage higher than 100% will no longer trigger after this update. Please configure triggers to a percentage with a maximum of 100% CPU percentage.
|
30
|
+
- [11220302](https://github.com/appsignal/appsignal-ruby/commit/112203023a58e53e607a9fd7d545044fa7d896d5) patch - Support fractional CPUs for cgroups v2 metrics. Previously a CPU count of 0.5 would be interpreted as 1 CPU. Now it will be correctly seen as half a CPU and calculate CPU percentages accordingly.
|
31
|
+
- [14aefc35](https://github.com/appsignal/appsignal-ruby/commit/14aefc3594b3f55a4c2ab14ba1259a4f10499467) patch - Update bundled trusted root certificates.
|
32
|
+
|
33
|
+
### Fixed
|
34
|
+
|
35
|
+
- [f2abbd6a](https://github.com/appsignal/appsignal-ruby/commit/f2abbd6aeb2230d79139cbdf82af98557bbe5b54) patch - Fix (sub)traces not being reported in their entirety when the OpenTelemetry exporter sends one trace in multiple export requests. This would be an issue for long running traces, that are exported in several requests.
|
36
|
+
|
3
37
|
## 3.5.6
|
4
38
|
|
5
39
|
### Changed
|
@@ -31,11 +65,11 @@ _Published on 2024-02-01._
|
|
31
65
|
|
32
66
|
### Deprecated
|
33
67
|
|
34
|
-
- [bb98744b](https://github.com/appsignal/appsignal-ruby/commit/bb98744b1b6d34db71b5f46279b1a9b26039bd0f) patch - Deprecate the `Appsignal.
|
68
|
+
- [bb98744b](https://github.com/appsignal/appsignal-ruby/commit/bb98744b1b6d34db71b5f46279b1a9b26039bd0f) patch - Deprecate the `Appsignal.set_host_gauge` and `Appsignal.set_process_gauge` helper methods in the Ruby gem. These methods would already log deprecation warnings in the `appsignal.log` file, but now also as a Ruby warning. These methods will be removed in the next major version. These methods already did not report any metrics, and still do not.
|
35
69
|
|
36
70
|
### Removed
|
37
71
|
|
38
|
-
- [1a863490](https://github.com/appsignal/appsignal-ruby/commit/1a863490046318b8cee5fff2ac341fb73065f252) patch - Remove the `
|
72
|
+
- [1a863490](https://github.com/appsignal/appsignal-ruby/commit/1a863490046318b8cee5fff2ac341fb73065f252) patch - Remove the `appsignal_set_host_gauge` and `appsignal_set_process_gauge` extension functions. These functions were already deprecated and did not report any metrics.
|
39
73
|
|
40
74
|
### Fixed
|
41
75
|
|
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.
|
9
|
+
"version" => "0.33.2",
|
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" => "
|
17
|
+
"checksum" => "0864691f001133fa479b34b00a682e76f374c40c161e7715756a3c036e3c8798",
|
18
18
|
"filename" => "appsignal-x86_64-darwin-all-static.tar.gz"
|
19
19
|
},
|
20
20
|
"dynamic" => {
|
21
|
-
"checksum" => "
|
21
|
+
"checksum" => "5141528c4293e4bd619107ae79afc8e07fdc8b33835899c5cf3f82ab3d31de8f",
|
22
22
|
"filename" => "appsignal-x86_64-darwin-all-dynamic.tar.gz"
|
23
23
|
}
|
24
24
|
},
|
25
25
|
"universal-darwin" => {
|
26
26
|
"static" => {
|
27
|
-
"checksum" => "
|
27
|
+
"checksum" => "0864691f001133fa479b34b00a682e76f374c40c161e7715756a3c036e3c8798",
|
28
28
|
"filename" => "appsignal-x86_64-darwin-all-static.tar.gz"
|
29
29
|
},
|
30
30
|
"dynamic" => {
|
31
|
-
"checksum" => "
|
31
|
+
"checksum" => "5141528c4293e4bd619107ae79afc8e07fdc8b33835899c5cf3f82ab3d31de8f",
|
32
32
|
"filename" => "appsignal-x86_64-darwin-all-dynamic.tar.gz"
|
33
33
|
}
|
34
34
|
},
|
35
35
|
"aarch64-darwin" => {
|
36
36
|
"static" => {
|
37
|
-
"checksum" => "
|
37
|
+
"checksum" => "13506e5911523e7107a8cb714e18b3bcb690f3eeef88bf9aff54777ba540fdc4",
|
38
38
|
"filename" => "appsignal-aarch64-darwin-all-static.tar.gz"
|
39
39
|
},
|
40
40
|
"dynamic" => {
|
41
|
-
"checksum" => "
|
41
|
+
"checksum" => "9d4deef17f42dc54981344a5af6b872e06dbd3d317be68b6abeb2403ffd65e23",
|
42
42
|
"filename" => "appsignal-aarch64-darwin-all-dynamic.tar.gz"
|
43
43
|
}
|
44
44
|
},
|
45
45
|
"arm64-darwin" => {
|
46
46
|
"static" => {
|
47
|
-
"checksum" => "
|
47
|
+
"checksum" => "13506e5911523e7107a8cb714e18b3bcb690f3eeef88bf9aff54777ba540fdc4",
|
48
48
|
"filename" => "appsignal-aarch64-darwin-all-static.tar.gz"
|
49
49
|
},
|
50
50
|
"dynamic" => {
|
51
|
-
"checksum" => "
|
51
|
+
"checksum" => "9d4deef17f42dc54981344a5af6b872e06dbd3d317be68b6abeb2403ffd65e23",
|
52
52
|
"filename" => "appsignal-aarch64-darwin-all-dynamic.tar.gz"
|
53
53
|
}
|
54
54
|
},
|
55
55
|
"arm-darwin" => {
|
56
56
|
"static" => {
|
57
|
-
"checksum" => "
|
57
|
+
"checksum" => "13506e5911523e7107a8cb714e18b3bcb690f3eeef88bf9aff54777ba540fdc4",
|
58
58
|
"filename" => "appsignal-aarch64-darwin-all-static.tar.gz"
|
59
59
|
},
|
60
60
|
"dynamic" => {
|
61
|
-
"checksum" => "
|
61
|
+
"checksum" => "9d4deef17f42dc54981344a5af6b872e06dbd3d317be68b6abeb2403ffd65e23",
|
62
62
|
"filename" => "appsignal-aarch64-darwin-all-dynamic.tar.gz"
|
63
63
|
}
|
64
64
|
},
|
65
65
|
"aarch64-linux" => {
|
66
66
|
"static" => {
|
67
|
-
"checksum" => "
|
67
|
+
"checksum" => "76702b5755d5bb45cc05df17dd38389b7e20e105a52324120a45ae1b481c7881",
|
68
68
|
"filename" => "appsignal-aarch64-linux-all-static.tar.gz"
|
69
69
|
},
|
70
70
|
"dynamic" => {
|
71
|
-
"checksum" => "
|
71
|
+
"checksum" => "bf518ce2cb4a9041fe819b6bf43e1bc793fe52b3e73527687d7812618c8e7407",
|
72
72
|
"filename" => "appsignal-aarch64-linux-all-dynamic.tar.gz"
|
73
73
|
}
|
74
74
|
},
|
75
75
|
"i686-linux" => {
|
76
76
|
"static" => {
|
77
|
-
"checksum" => "
|
77
|
+
"checksum" => "22cbda11a8d801d75e9394033f5cf28f0ddcff66a2138720f827441bdcf919c2",
|
78
78
|
"filename" => "appsignal-i686-linux-all-static.tar.gz"
|
79
79
|
},
|
80
80
|
"dynamic" => {
|
81
|
-
"checksum" => "
|
81
|
+
"checksum" => "157492663e434421499f9cc0b510178387c8968e53bdc6e216db374b86d5c3dc",
|
82
82
|
"filename" => "appsignal-i686-linux-all-dynamic.tar.gz"
|
83
83
|
}
|
84
84
|
},
|
85
85
|
"x86-linux" => {
|
86
86
|
"static" => {
|
87
|
-
"checksum" => "
|
87
|
+
"checksum" => "22cbda11a8d801d75e9394033f5cf28f0ddcff66a2138720f827441bdcf919c2",
|
88
88
|
"filename" => "appsignal-i686-linux-all-static.tar.gz"
|
89
89
|
},
|
90
90
|
"dynamic" => {
|
91
|
-
"checksum" => "
|
91
|
+
"checksum" => "157492663e434421499f9cc0b510178387c8968e53bdc6e216db374b86d5c3dc",
|
92
92
|
"filename" => "appsignal-i686-linux-all-dynamic.tar.gz"
|
93
93
|
}
|
94
94
|
},
|
95
95
|
"x86_64-linux" => {
|
96
96
|
"static" => {
|
97
|
-
"checksum" => "
|
97
|
+
"checksum" => "8ff0b1d7bf0cfc1c66e918545a9ab5c29be35c371cde48f64a01c725290599ed",
|
98
98
|
"filename" => "appsignal-x86_64-linux-all-static.tar.gz"
|
99
99
|
},
|
100
100
|
"dynamic" => {
|
101
|
-
"checksum" => "
|
101
|
+
"checksum" => "a186c18536c3b7ec4802e852a62154cc976dcb5f554c3d0d8472d5cd7131b02b",
|
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" => "
|
107
|
+
"checksum" => "a5e0af3e5e1ad908792e79c7c46b59119272e9836e5ea96791c78e3cb12ed132",
|
108
108
|
"filename" => "appsignal-x86_64-linux-musl-all-static.tar.gz"
|
109
109
|
},
|
110
110
|
"dynamic" => {
|
111
|
-
"checksum" => "
|
111
|
+
"checksum" => "17c108a83dff86b2531bf7f348481bb31ece53b4cc62615ca0a34332c0df2970",
|
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" => "
|
117
|
+
"checksum" => "92460560115d540a8140cbc360bd98beba8477e8a73eafd20ee611543b4528df",
|
118
118
|
"filename" => "appsignal-aarch64-linux-musl-all-static.tar.gz"
|
119
119
|
},
|
120
120
|
"dynamic" => {
|
121
|
-
"checksum" => "
|
121
|
+
"checksum" => "d4749b10a1803080e0b1b0d8f95ef9d1fef0aa694fa0fc405df97812937d8e7c",
|
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" => "
|
127
|
+
"checksum" => "8d8733c2adc0f750553be11b5e54fd614b13207be67863d95c57e4739021a92f",
|
128
128
|
"filename" => "appsignal-x86_64-freebsd-all-static.tar.gz"
|
129
129
|
},
|
130
130
|
"dynamic" => {
|
131
|
-
"checksum" => "
|
131
|
+
"checksum" => "8a9cbdc645b3833766458a252c2a8fefda76c62fceee8be795b286d65cc513c6",
|
132
132
|
"filename" => "appsignal-x86_64-freebsd-all-dynamic.tar.gz"
|
133
133
|
}
|
134
134
|
},
|
135
135
|
"amd64-freebsd" => {
|
136
136
|
"static" => {
|
137
|
-
"checksum" => "
|
137
|
+
"checksum" => "8d8733c2adc0f750553be11b5e54fd614b13207be67863d95c57e4739021a92f",
|
138
138
|
"filename" => "appsignal-x86_64-freebsd-all-static.tar.gz"
|
139
139
|
},
|
140
140
|
"dynamic" => {
|
141
|
-
"checksum" => "
|
141
|
+
"checksum" => "8a9cbdc645b3833766458a252c2a8fefda76c62fceee8be795b286d65cc513c6",
|
142
142
|
"filename" => "appsignal-x86_64-freebsd-all-dynamic.tar.gz"
|
143
143
|
}
|
144
144
|
}
|
@@ -0,0 +1,161 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Appsignal
|
4
|
+
# @api private
|
5
|
+
module Rack
|
6
|
+
class BodyWrapper
|
7
|
+
def self.wrap(original_body, appsignal_transaction)
|
8
|
+
# The logic of how Rack treats a response body differs based on which methods
|
9
|
+
# the body responds to. This means that to support the Rack 3.x spec in full
|
10
|
+
# we need to return a wrapper which matches the API of the wrapped body as closely
|
11
|
+
# as possible. Pick the wrapper from the most specific to the least specific.
|
12
|
+
# See https://github.com/rack/rack/blob/main/SPEC.rdoc#the-body-
|
13
|
+
#
|
14
|
+
# What is important is that our Body wrapper responds to the same methods Rack
|
15
|
+
# (or a webserver) would be checking and calling, and passes through that functionality
|
16
|
+
# to the original body. This can be done using delegation via i.e. SimpleDelegate
|
17
|
+
# but we also need "close" to get called correctly so that the Appsignal transaction
|
18
|
+
# gets completed - which will not happen, for example, when #to_ary gets called
|
19
|
+
# just on the delegated Rack body.
|
20
|
+
#
|
21
|
+
# This comment https://github.com/rails/rails/pull/49627#issuecomment-1769802573
|
22
|
+
# is of particular interest to understand why this has to be somewhat complicated.
|
23
|
+
if original_body.respond_to?(:to_path)
|
24
|
+
PathableBodyWrapper.new(original_body, appsignal_transaction)
|
25
|
+
elsif original_body.respond_to?(:to_ary)
|
26
|
+
ArrayableBodyWrapper.new(original_body, appsignal_transaction)
|
27
|
+
elsif !original_body.respond_to?(:each) && original_body.respond_to?(:call)
|
28
|
+
# This body only supports #call, so we must be running a Rack 3 application
|
29
|
+
# It is possible that a body exposes both `each` and `call` in the hopes of
|
30
|
+
# being backwards-compatible with both Rack 3.x and Rack 2.x, however
|
31
|
+
# this is not going to work since the SPEC says that if both are available,
|
32
|
+
# `each` should be used and `call` should be ignored.
|
33
|
+
# So for that case we can drop by to our default EnumerableBodyWrapper
|
34
|
+
CallableBodyWrapper.new(original_body, appsignal_transaction)
|
35
|
+
else
|
36
|
+
EnumerableBodyWrapper.new(original_body, appsignal_transaction)
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
def initialize(body, appsignal_transaction)
|
41
|
+
@body_already_closed = false
|
42
|
+
@body = body
|
43
|
+
@transaction = appsignal_transaction
|
44
|
+
end
|
45
|
+
|
46
|
+
# This must be present in all Rack bodies and will be called by the serving adapter
|
47
|
+
def close
|
48
|
+
# The @body_already_closed check is needed so that if `to_ary`
|
49
|
+
# of the body has already closed itself (as prescribed) we do not
|
50
|
+
# attempt to close it twice
|
51
|
+
if !@body_already_closed && @body.respond_to?(:close)
|
52
|
+
Appsignal.instrument("response_body_close.rack") { @body.close }
|
53
|
+
end
|
54
|
+
@body_already_closed = true
|
55
|
+
rescue Exception => error # rubocop:disable Lint/RescueException
|
56
|
+
@transaction.set_error(error)
|
57
|
+
raise error
|
58
|
+
ensure
|
59
|
+
complete_transaction!
|
60
|
+
end
|
61
|
+
|
62
|
+
def complete_transaction!
|
63
|
+
# We need to call the Transaction class method and not
|
64
|
+
# @transaction.complete because the transaction is still
|
65
|
+
# thread-local and it needs to remove itself from the
|
66
|
+
# thread variables correctly, which does not happen on
|
67
|
+
# Transaction#complete.
|
68
|
+
#
|
69
|
+
# In the future it would be a good idea to ensure
|
70
|
+
# that the current transaction is the same as @transaction,
|
71
|
+
# or allow @transaction to complete itself and remove
|
72
|
+
# itself from Thread.current
|
73
|
+
Appsignal::Transaction.complete_current!
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
# The standard Rack body wrapper which exposes "each" for iterating
|
78
|
+
# over the response body. This is supported across all 3 major Rack
|
79
|
+
# versions.
|
80
|
+
#
|
81
|
+
# @api private
|
82
|
+
class EnumerableBodyWrapper < BodyWrapper
|
83
|
+
def each(&blk)
|
84
|
+
# This is a workaround for the Rails bug when there was a bit too much
|
85
|
+
# eagerness in implementing to_ary, see:
|
86
|
+
# https://github.com/rails/rails/pull/44953
|
87
|
+
# https://github.com/rails/rails/pull/47092
|
88
|
+
# https://github.com/rails/rails/pull/49627
|
89
|
+
# https://github.com/rails/rails/issues/49588
|
90
|
+
# While the Rack SPEC does not mandate `each` to be callable
|
91
|
+
# in a blockless way it is still a good idea to have it in place.
|
92
|
+
return enum_for(:each) unless block_given?
|
93
|
+
|
94
|
+
Appsignal.instrument("process_response_body.rack", "Process Rack response body (#each)") do
|
95
|
+
@body.each(&blk)
|
96
|
+
end
|
97
|
+
rescue Exception => error # rubocop:disable Lint/RescueException
|
98
|
+
@transaction.set_error(error)
|
99
|
+
raise error
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
# The callable response bodies are a new Rack 3.x feature, and would not work
|
104
|
+
# with older Rack versions. They must not respond to `each` because
|
105
|
+
# "If it responds to each, you must call each and not call". This is why
|
106
|
+
# it inherits from BodyWrapper directly and not from EnumerableBodyWrapper
|
107
|
+
#
|
108
|
+
# @api private
|
109
|
+
class CallableBodyWrapper < BodyWrapper
|
110
|
+
def call(stream)
|
111
|
+
# `stream` will be closed by the app we are calling, no need for us
|
112
|
+
# to close it ourselves
|
113
|
+
Appsignal.instrument("process_response_body.rack", "Process Rack response body (#call)") do
|
114
|
+
@body.call(stream)
|
115
|
+
end
|
116
|
+
rescue Exception => error # rubocop:disable Lint/RescueException
|
117
|
+
@transaction.set_error(error)
|
118
|
+
raise error
|
119
|
+
end
|
120
|
+
end
|
121
|
+
|
122
|
+
# "to_ary" takes precedence over "each" and allows the response body
|
123
|
+
# to be read eagerly. If the body supports that method, it takes precedence
|
124
|
+
# over "each":
|
125
|
+
# "Middleware may call to_ary directly on the Body and return a new Body in its place"
|
126
|
+
# One could "fold" both the to_ary API and the each() API into one Body object, but
|
127
|
+
# to_ary must also call "close" after it executes - and in the Rails implementation
|
128
|
+
# this pecularity was not handled properly.
|
129
|
+
#
|
130
|
+
# @api private
|
131
|
+
class ArrayableBodyWrapper < EnumerableBodyWrapper
|
132
|
+
def to_ary
|
133
|
+
@body_already_closed = true
|
134
|
+
Appsignal.instrument(
|
135
|
+
"process_response_body.rack",
|
136
|
+
"Process Rack response body (#to_ary)"
|
137
|
+
) do
|
138
|
+
@body.to_ary
|
139
|
+
end
|
140
|
+
rescue Exception => error # rubocop:disable Lint/RescueException
|
141
|
+
@transaction.set_error(error)
|
142
|
+
raise error
|
143
|
+
ensure
|
144
|
+
# We do not call "close" on ourselves as the only action
|
145
|
+
# we need to complete is completing the transaction.
|
146
|
+
complete_transaction!
|
147
|
+
end
|
148
|
+
end
|
149
|
+
|
150
|
+
# Having "to_path" on a body allows Rack to serve out a static file, or to
|
151
|
+
# pass that file to the downstream webserver for sending using X-Sendfile
|
152
|
+
class PathableBodyWrapper < EnumerableBodyWrapper
|
153
|
+
def to_path
|
154
|
+
Appsignal.instrument("response_body_to_path.rack") { @body.to_path }
|
155
|
+
rescue Exception => error # rubocop:disable Lint/RescueException
|
156
|
+
@transaction.set_error(error)
|
157
|
+
raise error
|
158
|
+
end
|
159
|
+
end
|
160
|
+
end
|
161
|
+
end
|
@@ -16,7 +16,9 @@ module Appsignal
|
|
16
16
|
if Appsignal.active?
|
17
17
|
call_with_appsignal_monitoring(env)
|
18
18
|
else
|
19
|
-
|
19
|
+
nil_transaction = Appsignal::Transaction::NilTransaction.new
|
20
|
+
status, headers, obody = @app.call(env)
|
21
|
+
[status, headers, Appsignal::Rack::BodyWrapper.wrap(obody, nil_transaction)]
|
20
22
|
end
|
21
23
|
end
|
22
24
|
|
@@ -27,19 +29,30 @@ module Appsignal
|
|
27
29
|
Appsignal::Transaction::HTTP_REQUEST,
|
28
30
|
request
|
29
31
|
)
|
32
|
+
# We need to complete the transaction if there is an exception inside the `call`
|
33
|
+
# of the app. If there isn't one and the app returns us a Rack response triplet, we let
|
34
|
+
# the BodyWrapper complete the transaction when #close gets called on it
|
35
|
+
# (guaranteed by the webserver)
|
36
|
+
complete_transaction_without_body = false
|
30
37
|
begin
|
31
38
|
Appsignal.instrument("process_action.generic") do
|
32
|
-
@app.call(env)
|
39
|
+
status, headers, obody = @app.call(env)
|
40
|
+
[status, headers, Appsignal::Rack::BodyWrapper.wrap(obody, transaction)]
|
33
41
|
end
|
34
42
|
rescue Exception => error # rubocop:disable Lint/RescueException
|
35
43
|
transaction.set_error(error)
|
44
|
+
complete_transaction_without_body = true
|
36
45
|
raise error
|
37
46
|
ensure
|
38
|
-
|
47
|
+
default_action = env["appsignal.route"] || env["appsignal.action"] || "unknown"
|
48
|
+
transaction.set_action_if_nil(default_action)
|
39
49
|
transaction.set_metadata("path", request.path)
|
40
50
|
transaction.set_metadata("method", request.request_method)
|
41
51
|
transaction.set_http_or_background_queue_start
|
42
|
-
|
52
|
+
|
53
|
+
# Transaction gets completed when the body gets read out, except in cases when
|
54
|
+
# the app failed before returning us the Rack response triplet.
|
55
|
+
Appsignal::Transaction.complete_current! if complete_transaction_without_body
|
43
56
|
end
|
44
57
|
end
|
45
58
|
end
|
@@ -16,7 +16,9 @@ module Appsignal
|
|
16
16
|
if Appsignal.active?
|
17
17
|
call_with_appsignal_monitoring(env)
|
18
18
|
else
|
19
|
-
|
19
|
+
nil_transaction = Appsignal::Transaction::NilTransaction.new
|
20
|
+
status, headers, obody = @app.call(env)
|
21
|
+
[status, headers, Appsignal::Rack::BodyWrapper.wrap(obody, nil_transaction)]
|
20
22
|
end
|
21
23
|
end
|
22
24
|
|
@@ -28,10 +30,17 @@ module Appsignal
|
|
28
30
|
request,
|
29
31
|
:params_method => :filtered_parameters
|
30
32
|
)
|
33
|
+
# We need to complete the transaction if there is an exception exception inside the `call`
|
34
|
+
# of the app. If there isn't one and the app returns us a Rack response triplet, we let
|
35
|
+
# the BodyWrapper complete the transaction when #close gets called on it
|
36
|
+
# (guaranteed by the webserver)
|
37
|
+
complete_transaction_without_body = false
|
31
38
|
begin
|
32
|
-
@app.call(env)
|
39
|
+
status, headers, obody = @app.call(env)
|
40
|
+
[status, headers, Appsignal::Rack::BodyWrapper.wrap(obody, transaction)]
|
33
41
|
rescue Exception => error # rubocop:disable Lint/RescueException
|
34
42
|
transaction.set_error(error)
|
43
|
+
complete_transaction_without_body = true
|
35
44
|
raise error
|
36
45
|
ensure
|
37
46
|
controller = env["action_controller.instance"]
|
@@ -45,7 +54,10 @@ module Appsignal
|
|
45
54
|
rescue => error
|
46
55
|
Appsignal.internal_logger.error("Unable to report HTTP request method: '#{error}'")
|
47
56
|
end
|
48
|
-
|
57
|
+
|
58
|
+
# Transaction gets completed when the body gets read out, except in cases when
|
59
|
+
# the app failed before returning us the Rack response triplet.
|
60
|
+
Appsignal::Transaction.complete_current! if complete_transaction_without_body
|
49
61
|
end
|
50
62
|
end
|
51
63
|
|
@@ -42,7 +42,9 @@ module Appsignal
|
|
42
42
|
if Appsignal.active?
|
43
43
|
call_with_appsignal_monitoring(env)
|
44
44
|
else
|
45
|
-
|
45
|
+
nil_transaction = Appsignal::Transaction::NilTransaction.new
|
46
|
+
status, headers, obody = @app.call(env)
|
47
|
+
[status, headers, Appsignal::Rack::BodyWrapper.wrap(obody, nil_transaction)]
|
46
48
|
end
|
47
49
|
end
|
48
50
|
|
@@ -56,12 +58,19 @@ module Appsignal
|
|
56
58
|
request,
|
57
59
|
options
|
58
60
|
)
|
61
|
+
# We need to complete the transaction if there is an exception exception inside the `call`
|
62
|
+
# of the app. If there isn't one and the app returns us a Rack response triplet, we let
|
63
|
+
# the BodyWrapper complete the transaction when #close gets called on it
|
64
|
+
# (guaranteed by the webserver)
|
65
|
+
complete_transaction_without_body = false
|
59
66
|
begin
|
60
67
|
Appsignal.instrument("process_action.sinatra") do
|
61
|
-
@app.call(env)
|
68
|
+
status, headers, obody = @app.call(env)
|
69
|
+
[status, headers, Appsignal::Rack::BodyWrapper.wrap(obody, transaction)]
|
62
70
|
end
|
63
71
|
rescue Exception => error # rubocop:disable Lint/RescueException
|
64
72
|
transaction.set_error(error)
|
73
|
+
complete_transaction_without_body = true
|
65
74
|
raise error
|
66
75
|
ensure
|
67
76
|
# If raise_error is off versions of Sinatra don't raise errors, but store
|
@@ -73,7 +82,10 @@ module Appsignal
|
|
73
82
|
transaction.set_metadata("path", request.path)
|
74
83
|
transaction.set_metadata("method", request.request_method)
|
75
84
|
transaction.set_http_or_background_queue_start
|
76
|
-
|
85
|
+
|
86
|
+
# Transaction gets completed when the body gets read out, except in cases when
|
87
|
+
# the app failed before returning us the Rack response triplet.
|
88
|
+
Appsignal::Transaction.complete_current! if complete_transaction_without_body
|
77
89
|
end
|
78
90
|
end
|
79
91
|
|
@@ -16,7 +16,9 @@ module Appsignal
|
|
16
16
|
if Appsignal.active?
|
17
17
|
call_with_appsignal_monitoring(env)
|
18
18
|
else
|
19
|
-
|
19
|
+
nil_transaction = Appsignal::Transaction::NilTransaction.new
|
20
|
+
status, headers, obody = @app.call(env)
|
21
|
+
[status, headers, Appsignal::Rack::BodyWrapper.wrap(obody, nil_transaction)]
|
20
22
|
end
|
21
23
|
end
|
22
24
|
|
@@ -28,46 +30,35 @@ module Appsignal
|
|
28
30
|
request
|
29
31
|
)
|
30
32
|
|
33
|
+
# We need to complete the transaction if there is an exception exception inside the `call`
|
34
|
+
# of the app. If there isn't one and the app returns us a Rack response triplet, we let
|
35
|
+
# the BodyWrapper complete the transaction when #close gets called on it
|
36
|
+
# (guaranteed by the webserver)
|
37
|
+
complete_transaction_without_body = false
|
38
|
+
|
31
39
|
# Instrument a `process_action`, to set params/action name
|
32
|
-
|
40
|
+
begin
|
33
41
|
Appsignal.instrument("process_action.rack") do
|
34
|
-
@app.call(env)
|
35
|
-
|
36
|
-
transaction.set_error(e)
|
37
|
-
raise e
|
38
|
-
ensure
|
39
|
-
transaction.set_action_if_nil(env["appsignal.action"])
|
40
|
-
transaction.set_metadata("path", request.path)
|
41
|
-
transaction.set_metadata("method", request.request_method)
|
42
|
-
transaction.set_http_or_background_queue_start
|
42
|
+
status, headers, obody = @app.call(env)
|
43
|
+
[status, headers, Appsignal::Rack::BodyWrapper.wrap(obody, transaction)]
|
43
44
|
end
|
45
|
+
rescue Exception => error # rubocop:disable Lint/RescueException
|
46
|
+
transaction.set_error(error)
|
47
|
+
complete_transaction_without_body = true
|
48
|
+
raise error
|
49
|
+
ensure
|
50
|
+
transaction.set_action_if_nil(env["appsignal.action"])
|
51
|
+
transaction.set_metadata("path", request.path)
|
52
|
+
transaction.set_metadata("method", request.request_method)
|
53
|
+
transaction.set_http_or_background_queue_start
|
44
54
|
|
45
|
-
|
46
|
-
|
55
|
+
# Transaction gets completed when the body gets read out, except in cases when
|
56
|
+
# the app failed before returning us the Rack response triplet.
|
57
|
+
Appsignal::Transaction.complete_current! if complete_transaction_without_body
|
58
|
+
end
|
47
59
|
end
|
48
60
|
end
|
49
61
|
end
|
50
62
|
|
51
|
-
|
52
|
-
def initialize(stream, transaction)
|
53
|
-
@stream = stream
|
54
|
-
@transaction = transaction
|
55
|
-
end
|
56
|
-
|
57
|
-
def each(&block)
|
58
|
-
@stream.each(&block)
|
59
|
-
rescue Exception => e # rubocop:disable Lint/RescueException
|
60
|
-
@transaction.set_error(e)
|
61
|
-
raise e
|
62
|
-
end
|
63
|
-
|
64
|
-
def close
|
65
|
-
@stream.close if @stream.respond_to?(:close)
|
66
|
-
rescue Exception => e # rubocop:disable Lint/RescueException
|
67
|
-
@transaction.set_error(e)
|
68
|
-
raise e
|
69
|
-
ensure
|
70
|
-
Appsignal::Transaction.complete_current!
|
71
|
-
end
|
72
|
-
end
|
63
|
+
StreamWrapper = Rack::EnumerableBodyWrapper
|
73
64
|
end
|
data/lib/appsignal/version.rb
CHANGED
data/lib/appsignal.rb
CHANGED
@@ -305,5 +305,6 @@ require "appsignal/garbage_collection"
|
|
305
305
|
require "appsignal/integrations/railtie" if defined?(::Rails)
|
306
306
|
require "appsignal/transaction"
|
307
307
|
require "appsignal/version"
|
308
|
+
require "appsignal/rack/body_wrapper"
|
308
309
|
require "appsignal/rack/generic_instrumentation"
|
309
310
|
require "appsignal/transmitter"
|