appsignal 4.0.3-java → 4.0.5-java
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +51 -0
- data/ext/agent.rb +27 -27
- data/lib/appsignal/check_in/cron.rb +2 -34
- data/lib/appsignal/check_in/scheduler.rb +192 -0
- data/lib/appsignal/check_in.rb +18 -0
- data/lib/appsignal/cli/diagnose.rb +1 -1
- data/lib/appsignal/config.rb +7 -0
- data/lib/appsignal/hooks/at_exit.rb +3 -1
- data/lib/appsignal/hooks/puma.rb +5 -1
- data/lib/appsignal/integrations/puma.rb +45 -0
- data/lib/appsignal/rack/abstract_middleware.rb +3 -47
- data/lib/appsignal/rack/body_wrapper.rb +15 -0
- data/lib/appsignal/rack/event_handler.rb +2 -0
- data/lib/appsignal/rack/hanami_middleware.rb +5 -1
- data/lib/appsignal/rack.rb +68 -0
- data/lib/appsignal/transmitter.rb +30 -7
- data/lib/appsignal/utils/ndjson.rb +15 -0
- data/lib/appsignal/utils.rb +1 -0
- data/lib/appsignal/version.rb +1 -1
- data/lib/appsignal.rb +1 -0
- data/spec/lib/appsignal/check_in/cron_spec.rb +202 -0
- data/spec/lib/appsignal/check_in/scheduler_spec.rb +443 -0
- data/spec/lib/appsignal/config_spec.rb +13 -0
- data/spec/lib/appsignal/environment_spec.rb +1 -1
- data/spec/lib/appsignal/hooks/at_exit_spec.rb +22 -0
- data/spec/lib/appsignal/hooks/puma_spec.rb +31 -23
- data/spec/lib/appsignal/integrations/puma_spec.rb +150 -0
- data/spec/lib/appsignal/probes_spec.rb +1 -6
- data/spec/lib/appsignal/rack/abstract_middleware_spec.rb +41 -122
- data/spec/lib/appsignal/rack/body_wrapper_spec.rb +29 -21
- data/spec/lib/appsignal/rack_spec.rb +180 -0
- data/spec/lib/appsignal/transmitter_spec.rb +48 -2
- data/spec/lib/appsignal_spec.rb +5 -0
- data/spec/spec_helper.rb +0 -7
- data/spec/support/helpers/config_helpers.rb +2 -1
- data/spec/support/helpers/take_at_most_helper.rb +21 -0
- data/spec/support/matchers/contains_log.rb +10 -3
- data/spec/support/mocks/hash_like.rb +10 -0
- data/spec/support/mocks/puma_mock.rb +43 -0
- metadata +11 -3
- data/spec/lib/appsignal/check_in_spec.rb +0 -136
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 265860dc1cb9e7ef2035d4dcc288d6789d14b6d656c6812ab26f69fc6e3d9e2e
|
4
|
+
data.tar.gz: 702e3e82530b79db9d8b26519d14cb9664d728a12f3d6c5999b63bfbda022fd1
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 8e5589a001f66450dd0c2f7250134be2813bcab36a9c4576886cc3997206109e8e6ae53fbd60fb8924ffa9e34bddd225617a92dfec6b442e6565bc2ea3433d53
|
7
|
+
data.tar.gz: bf73768bfbbc2db0c042cb84ddc185362707f7b0b622d0565ce7a5142ddd0479daea6e76d7d87d9b7542ff01929b7a24cf566ca9036e3bd66a5fb0f2de1e622a
|
data/CHANGELOG.md
CHANGED
@@ -1,5 +1,56 @@
|
|
1
1
|
# AppSignal for Ruby gem Changelog
|
2
2
|
|
3
|
+
## 4.0.5
|
4
|
+
|
5
|
+
_Published on 2024-09-02._
|
6
|
+
|
7
|
+
### Added
|
8
|
+
|
9
|
+
- Report Puma low-level errors using the `lowlevel_error` reporter. This will report errors previously not caught by our instrumentation middleware. (patch [70cc21f4](https://github.com/appsignal/appsignal-ruby/commit/70cc21f49e19faa9fd2d12a051620cd48e036dcb))
|
10
|
+
|
11
|
+
### Changed
|
12
|
+
|
13
|
+
- Log a warning when loader defaults are added after AppSignal has already been configured.
|
14
|
+
|
15
|
+
```ruby
|
16
|
+
# Bad
|
17
|
+
Appsignal.configure # or Appsignal.start
|
18
|
+
Appsignal.load(:sinatra)
|
19
|
+
|
20
|
+
# Good
|
21
|
+
Appsignal.load(:sinatra)
|
22
|
+
Appsignal.configure # or Appsignal.start
|
23
|
+
```
|
24
|
+
|
25
|
+
(patch [0997dd9c](https://github.com/appsignal/appsignal-ruby/commit/0997dd9c0430123a697b8100785f5676163e20ef))
|
26
|
+
- Rename the `path` and `method` transaction metadata to `request_path` and `request_method` to make it more clear what context this metadata is from. The `path` and `method` metadata will continue to be reported until the next major/minor version. (patch [fa314b5f](https://github.com/appsignal/appsignal-ruby/commit/fa314b5fb6fdfbf3e9746df377b0145cde0cfa36))
|
27
|
+
- Internal change to how OpenTelemetry metrics are sent. (patch [e66d1d70](https://github.com/appsignal/appsignal-ruby/commit/e66d1d702d5010cb5b8084ba790b24d9e70a9e08))
|
28
|
+
|
29
|
+
### Removed
|
30
|
+
|
31
|
+
- Drop support for Puma version 2 and lower. (patch [4fab861c](https://github.com/appsignal/appsignal-ruby/commit/4fab861cae74b08aa71bf64e1b134ae4b1df1dff))
|
32
|
+
|
33
|
+
### Fixed
|
34
|
+
|
35
|
+
- Fix the error log message about our `at_exit` hook reporting no error on process exit when the process exits without an error. (patch [b71f3966](https://github.com/appsignal/appsignal-ruby/commit/b71f39661e9b05c10fa78b821ba0e45bde0c941b))
|
36
|
+
|
37
|
+
## 4.0.4
|
38
|
+
|
39
|
+
_Published on 2024-08-29._
|
40
|
+
|
41
|
+
### Changed
|
42
|
+
|
43
|
+
- Send check-ins concurrently. When calling `Appsignal::CheckIn.cron`, instead of blocking the current thread while the check-in events are sent, schedule them to be sent in a separate thread.
|
44
|
+
|
45
|
+
When shutting down your application manually, call `Appsignal.stop` to block until all scheduled check-ins have been sent.
|
46
|
+
|
47
|
+
(patch [46d4ca74](https://github.com/appsignal/appsignal-ruby/commit/46d4ca74f4c188cc011653ed23969ad7ec770812))
|
48
|
+
|
49
|
+
### Fixed
|
50
|
+
|
51
|
+
- Make our Rack BodyWrapper behave like a Rack BodyProxy. If a method doesn't exist on our BodyWrapper class, but it does exist on the body, behave like the Rack BodyProxy and call the method on the wrapped body. (patch [e2376305](https://github.com/appsignal/appsignal-ruby/commit/e23763058a3fb980f1054e9c1eaf7e0f25f75666))
|
52
|
+
- Do not report `SignalException` errors from our `at_exit` error reporter. (patch [3ba3ce31](https://github.com/appsignal/appsignal-ruby/commit/3ba3ce31ee3f3e84665c9f2f18d488c689cff6c2))
|
53
|
+
|
3
54
|
## 4.0.3
|
4
55
|
|
5
56
|
_Published on 2024-08-26._
|
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.
|
9
|
+
"version" => "0.35.22",
|
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" => "024cef88b24032d7187488c00682f92095da406d80ae642ac858e6318b840ad6",
|
18
18
|
"filename" => "appsignal-x86_64-darwin-all-static.tar.gz"
|
19
19
|
},
|
20
20
|
"dynamic" => {
|
21
|
-
"checksum" => "
|
21
|
+
"checksum" => "ddddf86a951fe57f50e351a449df65d2c6428d703581b8ef5922fad23a688f1d",
|
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" => "024cef88b24032d7187488c00682f92095da406d80ae642ac858e6318b840ad6",
|
28
28
|
"filename" => "appsignal-x86_64-darwin-all-static.tar.gz"
|
29
29
|
},
|
30
30
|
"dynamic" => {
|
31
|
-
"checksum" => "
|
31
|
+
"checksum" => "ddddf86a951fe57f50e351a449df65d2c6428d703581b8ef5922fad23a688f1d",
|
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" => "b8dfebd77322a1f66e0f0acf1717c2583189016e9749286f61956a3ebbc1a16a",
|
38
38
|
"filename" => "appsignal-aarch64-darwin-all-static.tar.gz"
|
39
39
|
},
|
40
40
|
"dynamic" => {
|
41
|
-
"checksum" => "
|
41
|
+
"checksum" => "d94ae45a9fa69566a30aaacf9f65bdf21b5d0d2a5990e4ba8f98dedc5956f62f",
|
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" => "b8dfebd77322a1f66e0f0acf1717c2583189016e9749286f61956a3ebbc1a16a",
|
48
48
|
"filename" => "appsignal-aarch64-darwin-all-static.tar.gz"
|
49
49
|
},
|
50
50
|
"dynamic" => {
|
51
|
-
"checksum" => "
|
51
|
+
"checksum" => "d94ae45a9fa69566a30aaacf9f65bdf21b5d0d2a5990e4ba8f98dedc5956f62f",
|
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" => "b8dfebd77322a1f66e0f0acf1717c2583189016e9749286f61956a3ebbc1a16a",
|
58
58
|
"filename" => "appsignal-aarch64-darwin-all-static.tar.gz"
|
59
59
|
},
|
60
60
|
"dynamic" => {
|
61
|
-
"checksum" => "
|
61
|
+
"checksum" => "d94ae45a9fa69566a30aaacf9f65bdf21b5d0d2a5990e4ba8f98dedc5956f62f",
|
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" => "1f21e14f31b9b91f5ce3da0dcb91224bc9f4a0d834ada75e87f396ca9838cf59",
|
68
68
|
"filename" => "appsignal-aarch64-linux-all-static.tar.gz"
|
69
69
|
},
|
70
70
|
"dynamic" => {
|
71
|
-
"checksum" => "
|
71
|
+
"checksum" => "cf81cabcd216cf41d55ad2ad50f5eccfc1b3edc0dc78159973f3c0687f5ad86d",
|
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" => "6111532d1958f9bbbdbea9104c509636d7b6d311090c609a0c134b68e6ef0dd6",
|
78
78
|
"filename" => "appsignal-i686-linux-all-static.tar.gz"
|
79
79
|
},
|
80
80
|
"dynamic" => {
|
81
|
-
"checksum" => "
|
81
|
+
"checksum" => "705fd88f0e2a4370766f64c93d123476d37f169190550cc3a2c85d34ce1b1893",
|
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" => "6111532d1958f9bbbdbea9104c509636d7b6d311090c609a0c134b68e6ef0dd6",
|
88
88
|
"filename" => "appsignal-i686-linux-all-static.tar.gz"
|
89
89
|
},
|
90
90
|
"dynamic" => {
|
91
|
-
"checksum" => "
|
91
|
+
"checksum" => "705fd88f0e2a4370766f64c93d123476d37f169190550cc3a2c85d34ce1b1893",
|
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" => "9e325faf63b7fe9b9804b4e8ce4bac7deefa6c47aec47faf47d90133d44dbaa5",
|
98
98
|
"filename" => "appsignal-x86_64-linux-all-static.tar.gz"
|
99
99
|
},
|
100
100
|
"dynamic" => {
|
101
|
-
"checksum" => "
|
101
|
+
"checksum" => "11bac70bee7e620b31a26a01093a0c9ef01f7eb7508ac0c0a0eae27973cc643f",
|
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" => "a76de00904eb40a61a7e68082cb06379aa13f61ec0d25ead828fd2ba022f9be9",
|
108
108
|
"filename" => "appsignal-x86_64-linux-musl-all-static.tar.gz"
|
109
109
|
},
|
110
110
|
"dynamic" => {
|
111
|
-
"checksum" => "
|
111
|
+
"checksum" => "b7b34ed9243059259a5fa10daa65adb6c4748e8b9715f64e6e559f88aa7aec03",
|
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" => "2e197b99b7052357e466a7d93450d87cbdc07d0e5749630e98adcf7c7fad8936",
|
118
118
|
"filename" => "appsignal-aarch64-linux-musl-all-static.tar.gz"
|
119
119
|
},
|
120
120
|
"dynamic" => {
|
121
|
-
"checksum" => "
|
121
|
+
"checksum" => "ace9ab040e4c412f9d6c0b7d2209388e81f40882f8719a67cc30c60e0bdc50ed",
|
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" => "0c263f693ba5c06373b9fb4062f14d2b6bf1ff33bc0d737abcccc77bab66a634",
|
128
128
|
"filename" => "appsignal-x86_64-freebsd-all-static.tar.gz"
|
129
129
|
},
|
130
130
|
"dynamic" => {
|
131
|
-
"checksum" => "
|
131
|
+
"checksum" => "7545a50f4d127da466e87d9504df4911ed9f8b0ec67b86023e08f8a58ea2b8c2",
|
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" => "0c263f693ba5c06373b9fb4062f14d2b6bf1ff33bc0d737abcccc77bab66a634",
|
138
138
|
"filename" => "appsignal-x86_64-freebsd-all-static.tar.gz"
|
139
139
|
},
|
140
140
|
"dynamic" => {
|
141
|
-
"checksum" => "
|
141
|
+
"checksum" => "7545a50f4d127da466e87d9504df4911ed9f8b0ec67b86023e08f8a58ea2b8c2",
|
142
142
|
"filename" => "appsignal-x86_64-freebsd-all-dynamic.tar.gz"
|
143
143
|
}
|
144
144
|
}
|
@@ -3,15 +3,6 @@
|
|
3
3
|
module Appsignal
|
4
4
|
module CheckIn
|
5
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
|
-
end
|
14
|
-
|
15
6
|
# @api private
|
16
7
|
attr_reader :identifier, :digest
|
17
8
|
|
@@ -21,11 +12,11 @@ module Appsignal
|
|
21
12
|
end
|
22
13
|
|
23
14
|
def start
|
24
|
-
|
15
|
+
CheckIn.scheduler.schedule(event("start"))
|
25
16
|
end
|
26
17
|
|
27
18
|
def finish
|
28
|
-
|
19
|
+
CheckIn.scheduler.schedule(event("finish"))
|
29
20
|
end
|
30
21
|
|
31
22
|
private
|
@@ -39,29 +30,6 @@ module Appsignal
|
|
39
30
|
:check_in_type => "cron"
|
40
31
|
}
|
41
32
|
end
|
42
|
-
|
43
|
-
def transmit_event(kind)
|
44
|
-
unless Appsignal.active?
|
45
|
-
Appsignal.internal_logger.debug(
|
46
|
-
"AppSignal not active, not transmitting cron check-in event"
|
47
|
-
)
|
48
|
-
return
|
49
|
-
end
|
50
|
-
|
51
|
-
response = self.class.transmitter.transmit(event(kind))
|
52
|
-
|
53
|
-
if response.code.to_i >= 200 && response.code.to_i < 300
|
54
|
-
Appsignal.internal_logger.debug(
|
55
|
-
"Transmitted cron check-in `#{identifier}` (#{digest}) #{kind} event"
|
56
|
-
)
|
57
|
-
else
|
58
|
-
Appsignal.internal_logger.error(
|
59
|
-
"Failed to transmit cron check-in #{kind} event: status code was #{response.code}"
|
60
|
-
)
|
61
|
-
end
|
62
|
-
rescue => e
|
63
|
-
Appsignal.internal_logger.error("Failed to transmit cron check-in #{kind} event: #{e}")
|
64
|
-
end
|
65
33
|
end
|
66
34
|
end
|
67
35
|
end
|
@@ -0,0 +1,192 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Appsignal
|
4
|
+
module CheckIn
|
5
|
+
class Scheduler
|
6
|
+
INITIAL_DEBOUNCE_SECONDS = 0.1
|
7
|
+
BETWEEN_TRANSMISSIONS_DEBOUNCE_SECONDS = 10
|
8
|
+
|
9
|
+
def initialize
|
10
|
+
# The mutex is used to synchronize access to the events array, the
|
11
|
+
# waker thread and the main thread, as well as queue writes
|
12
|
+
# (which depend on the events array) and closes (so they do not
|
13
|
+
# happen at the same time that an event is added to the scheduler)
|
14
|
+
@mutex = Mutex.new
|
15
|
+
# The transmitter thread will be started when an event is first added.
|
16
|
+
@thread = nil
|
17
|
+
@queue = Thread::Queue.new
|
18
|
+
# Scheduled events that have not been sent to the transmitter thread
|
19
|
+
# yet. A copy of this array is pushed to the queue by the waker thread
|
20
|
+
# after it has awaited the debounce period.
|
21
|
+
@events = []
|
22
|
+
# The waker thread is used to schedule debounces. It will be started
|
23
|
+
# when an event is first added.
|
24
|
+
@waker = nil
|
25
|
+
# For internal testing purposes.
|
26
|
+
@transmitted = 0
|
27
|
+
end
|
28
|
+
|
29
|
+
def schedule(event)
|
30
|
+
unless Appsignal.active?
|
31
|
+
Appsignal.internal_logger.debug(
|
32
|
+
"Cannot transmit #{describe([event])}: AppSignal is not active"
|
33
|
+
)
|
34
|
+
return
|
35
|
+
end
|
36
|
+
|
37
|
+
@mutex.synchronize do
|
38
|
+
if @queue.closed?
|
39
|
+
Appsignal.internal_logger.debug(
|
40
|
+
"Cannot transmit #{describe([event])}: AppSignal is stopped"
|
41
|
+
)
|
42
|
+
return
|
43
|
+
end
|
44
|
+
add_event(event)
|
45
|
+
# If we're not already waiting to be awakened from a scheduled
|
46
|
+
# debounce, schedule a short debounce, which will push the events
|
47
|
+
# to the queue and schedule a long debounce.
|
48
|
+
start_waker(INITIAL_DEBOUNCE_SECONDS) if @waker.nil?
|
49
|
+
|
50
|
+
Appsignal.internal_logger.debug(
|
51
|
+
"Scheduling #{describe([event])} to be transmitted"
|
52
|
+
)
|
53
|
+
|
54
|
+
# Make sure to start the thread after an event has been added.
|
55
|
+
@thread ||= Thread.new(&method(:run))
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
def stop
|
60
|
+
@mutex.synchronize do
|
61
|
+
# Flush all events before closing the queue.
|
62
|
+
push_events
|
63
|
+
rescue ClosedQueueError
|
64
|
+
# The queue is already closed (by a previous call to `#stop`)
|
65
|
+
# so it is not possible to push events to it anymore.
|
66
|
+
ensure
|
67
|
+
# Ensure calling `#stop` closes the queue and kills
|
68
|
+
# the waker thread, disallowing any further events from being
|
69
|
+
# scheduled with `#schedule`.
|
70
|
+
stop_waker
|
71
|
+
@queue.close
|
72
|
+
|
73
|
+
# Block until the thread has finished.
|
74
|
+
@thread&.join
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
# @api private
|
79
|
+
# For internal testing purposes.
|
80
|
+
attr_reader :thread, :waker, :queue, :events, :transmitted
|
81
|
+
|
82
|
+
private
|
83
|
+
|
84
|
+
def run
|
85
|
+
loop do
|
86
|
+
events = @queue.pop
|
87
|
+
break if events.nil?
|
88
|
+
|
89
|
+
transmit(events)
|
90
|
+
@transmitted += 1
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
def transmit(events)
|
95
|
+
description = describe(events)
|
96
|
+
|
97
|
+
begin
|
98
|
+
response = CheckIn.transmitter.transmit(events, :format => :ndjson)
|
99
|
+
|
100
|
+
if (200...300).include?(response.code.to_i)
|
101
|
+
Appsignal.internal_logger.debug(
|
102
|
+
"Transmitted #{description}"
|
103
|
+
)
|
104
|
+
else
|
105
|
+
Appsignal.internal_logger.error(
|
106
|
+
"Failed to transmit #{description}: #{response.code} status code"
|
107
|
+
)
|
108
|
+
end
|
109
|
+
rescue => e
|
110
|
+
Appsignal.internal_logger.error("Failed to transmit #{description}: #{e.message}")
|
111
|
+
end
|
112
|
+
end
|
113
|
+
|
114
|
+
def describe(events)
|
115
|
+
if events.empty?
|
116
|
+
# This shouldn't happen.
|
117
|
+
"no check-in events"
|
118
|
+
elsif events.length > 1
|
119
|
+
"#{events.length} check-in events"
|
120
|
+
else
|
121
|
+
event = events.first
|
122
|
+
if event[:check_in_type] == "cron"
|
123
|
+
"cron check-in `#{event[:identifier] || "unknown"}` " \
|
124
|
+
"#{event[:kind] || "unknown"} event (digest #{event[:digest] || "unknown"})" \
|
125
|
+
else
|
126
|
+
"unknown check-in event"
|
127
|
+
end
|
128
|
+
end
|
129
|
+
end
|
130
|
+
|
131
|
+
# Must be called from within a `@mutex.synchronize` block.
|
132
|
+
def add_event(event)
|
133
|
+
# Remove redundant events, keeping the newly added one, which
|
134
|
+
# should be the one with the most recent timestamp.
|
135
|
+
if event[:check_in_type] == "cron"
|
136
|
+
# Remove any existing cron check-in event with the same identifier,
|
137
|
+
# digest and kind as the one we're adding.
|
138
|
+
@events.reject! do |existing_event|
|
139
|
+
next unless existing_event[:identifier] == event[:identifier] &&
|
140
|
+
existing_event[:digest] == event[:digest] &&
|
141
|
+
existing_event[:kind] == event[:kind] &&
|
142
|
+
existing_event[:check_in_type] == "cron"
|
143
|
+
|
144
|
+
Appsignal.internal_logger.debug(
|
145
|
+
"Replacing previously scheduled #{describe([existing_event])}"
|
146
|
+
)
|
147
|
+
|
148
|
+
true
|
149
|
+
end
|
150
|
+
end
|
151
|
+
|
152
|
+
@events << event
|
153
|
+
end
|
154
|
+
|
155
|
+
# Must be called from within a `@mutex.synchronize` block.
|
156
|
+
def start_waker(debounce)
|
157
|
+
stop_waker
|
158
|
+
|
159
|
+
@waker = Thread.new do
|
160
|
+
sleep(debounce)
|
161
|
+
|
162
|
+
@mutex.synchronize do
|
163
|
+
# Make sure this waker doesn't get killed, so it can push
|
164
|
+
# events and schedule a new waker.
|
165
|
+
@waker = nil
|
166
|
+
push_events
|
167
|
+
end
|
168
|
+
end
|
169
|
+
end
|
170
|
+
|
171
|
+
# Must be called from within a `@mutex.synchronize` block.
|
172
|
+
def stop_waker
|
173
|
+
@waker&.kill
|
174
|
+
@waker&.join
|
175
|
+
@waker = nil
|
176
|
+
end
|
177
|
+
|
178
|
+
# Must be called from within a `@mutex.synchronize` block.
|
179
|
+
def push_events
|
180
|
+
return if @events.empty?
|
181
|
+
|
182
|
+
# Push a copy of the events to the queue, and clear the events array.
|
183
|
+
# This ensures that `@events` always contains events that have not
|
184
|
+
# yet been pushed to the queue.
|
185
|
+
@queue.push(@events.dup)
|
186
|
+
@events.clear
|
187
|
+
|
188
|
+
start_waker(BETWEEN_TRANSMISSIONS_DEBOUNCE_SECONDS)
|
189
|
+
end
|
190
|
+
end
|
191
|
+
end
|
192
|
+
end
|
data/lib/appsignal/check_in.rb
CHANGED
@@ -39,8 +39,26 @@ module Appsignal
|
|
39
39
|
cron.finish
|
40
40
|
output
|
41
41
|
end
|
42
|
+
|
43
|
+
# @api private
|
44
|
+
def transmitter
|
45
|
+
@transmitter ||= Transmitter.new(
|
46
|
+
"#{Appsignal.config[:logging_endpoint]}/check_ins/json"
|
47
|
+
)
|
48
|
+
end
|
49
|
+
|
50
|
+
# @api private
|
51
|
+
def scheduler
|
52
|
+
@scheduler ||= Scheduler.new
|
53
|
+
end
|
54
|
+
|
55
|
+
# @api private
|
56
|
+
def stop
|
57
|
+
scheduler&.stop
|
58
|
+
end
|
42
59
|
end
|
43
60
|
end
|
44
61
|
end
|
45
62
|
|
63
|
+
require "appsignal/check_in/scheduler"
|
46
64
|
require "appsignal/check_in/cron"
|
@@ -150,7 +150,7 @@ module Appsignal
|
|
150
150
|
ENV.fetch("APPSIGNAL_DIAGNOSE_ENDPOINT", DIAGNOSE_ENDPOINT),
|
151
151
|
Appsignal.config
|
152
152
|
)
|
153
|
-
response = transmitter.transmit(:diagnose => data)
|
153
|
+
response = transmitter.transmit({ :diagnose => data })
|
154
154
|
|
155
155
|
unless response.code == "200"
|
156
156
|
puts " Error: Something went wrong while submitting the report " \
|
data/lib/appsignal/config.rb
CHANGED
@@ -15,6 +15,13 @@ module Appsignal
|
|
15
15
|
|
16
16
|
# @api private
|
17
17
|
def self.add_loader_defaults(name, env: nil, root_path: nil, **options)
|
18
|
+
if Appsignal.config
|
19
|
+
Appsignal.internal_logger.warn(
|
20
|
+
"The config defaults from the '#{name}' loader are ignored since " \
|
21
|
+
"the AppSignal config has already been initialized."
|
22
|
+
)
|
23
|
+
end
|
24
|
+
|
18
25
|
loader_defaults << {
|
19
26
|
:name => name,
|
20
27
|
:env => env,
|
@@ -24,6 +24,7 @@ module Appsignal
|
|
24
24
|
class AtExitCallback
|
25
25
|
def self.call
|
26
26
|
error = $! # rubocop:disable Style/SpecialGlobalVars
|
27
|
+
return unless error
|
27
28
|
return if ignored_error?(error)
|
28
29
|
return if Appsignal::Transaction.last_errors.include?(error)
|
29
30
|
|
@@ -35,7 +36,8 @@ module Appsignal
|
|
35
36
|
|
36
37
|
IGNORED_ERRORS = [
|
37
38
|
# Normal exits from the application we do not need to report
|
38
|
-
SystemExit
|
39
|
+
SystemExit,
|
40
|
+
SignalException
|
39
41
|
].freeze
|
40
42
|
|
41
43
|
def self.ignored_error?(error)
|
data/lib/appsignal/hooks/puma.rb
CHANGED
@@ -7,10 +7,14 @@ module Appsignal
|
|
7
7
|
register :puma
|
8
8
|
|
9
9
|
def dependencies_present?
|
10
|
-
defined?(::Puma)
|
10
|
+
defined?(::Puma) &&
|
11
|
+
Gem::Version.new(Puma::Const::VERSION) >= Gem::Version.new("3.0.0")
|
11
12
|
end
|
12
13
|
|
13
14
|
def install
|
15
|
+
require "appsignal/integrations/puma"
|
16
|
+
::Puma::Server.prepend(Appsignal::Integrations::PumaServer)
|
17
|
+
|
14
18
|
return unless defined?(::Puma::Cluster)
|
15
19
|
|
16
20
|
# For clustered mode with multiple workers
|
@@ -0,0 +1,45 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Appsignal
|
4
|
+
module Integrations
|
5
|
+
# @api private
|
6
|
+
module PumaServer
|
7
|
+
def lowlevel_error(error, env, response_status = 500)
|
8
|
+
response =
|
9
|
+
if method(:lowlevel_error).super_method.arity.abs == 3 # Puma >= 5
|
10
|
+
super
|
11
|
+
else # Puma <= 4
|
12
|
+
super(error, env)
|
13
|
+
end
|
14
|
+
|
15
|
+
unless PumaServerHelper.ignored_error?(error)
|
16
|
+
Appsignal.report_error(error) do |transaction|
|
17
|
+
Appsignal::Rack::ApplyRackRequest
|
18
|
+
.new(::Rack::Request.new(env))
|
19
|
+
.apply_to(transaction)
|
20
|
+
transaction.add_tags(
|
21
|
+
:reported_by => :puma_lowlevel_error,
|
22
|
+
:response_status => response_status
|
23
|
+
)
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
response
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
module PumaServerHelper
|
32
|
+
IGNORED_ERRORS = [
|
33
|
+
# Ignore internal Puma Client IO errors
|
34
|
+
# https://github.com/puma/puma/blob/9ee922d28e1fffd02c1d5480a9e13376f92f46a3/lib/puma/server.rb#L536-L544
|
35
|
+
"Puma::MiniSSL::SSLError",
|
36
|
+
"Puma::HttpParserError",
|
37
|
+
"Puma::HttpParserError501"
|
38
|
+
].freeze
|
39
|
+
|
40
|
+
def self.ignored_error?(error)
|
41
|
+
IGNORED_ERRORS.include?(error.class.to_s)
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|