appsignal 4.0.3-java → 4.0.5-java
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
|