appsignal 3.7.0 → 3.7.2

Sign up to get free protection for your applications and to get access to all the features.
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.2",
9
+ "version" => "0.35.5",
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" => "4a01803fae744971e2da08a325acb88a5f79bf44cbde03456652affb91fa0817",
17
+ "checksum" => "3985b53b2a2814d44737182890e6fbe31b4b88361025140477a598e0e41fd948",
18
18
  "filename" => "appsignal-x86_64-darwin-all-static.tar.gz"
19
19
  },
20
20
  "dynamic" => {
21
- "checksum" => "843f6bfd798b7ae829c4a169f249a5576f01eb102755e1851f2901d4ddfff1b0",
21
+ "checksum" => "d135e2daf5c041a4ce7a7ab720cfd977fbae8375a007995e33a96558d3635792",
22
22
  "filename" => "appsignal-x86_64-darwin-all-dynamic.tar.gz"
23
23
  }
24
24
  },
25
25
  "universal-darwin" => {
26
26
  "static" => {
27
- "checksum" => "4a01803fae744971e2da08a325acb88a5f79bf44cbde03456652affb91fa0817",
27
+ "checksum" => "3985b53b2a2814d44737182890e6fbe31b4b88361025140477a598e0e41fd948",
28
28
  "filename" => "appsignal-x86_64-darwin-all-static.tar.gz"
29
29
  },
30
30
  "dynamic" => {
31
- "checksum" => "843f6bfd798b7ae829c4a169f249a5576f01eb102755e1851f2901d4ddfff1b0",
31
+ "checksum" => "d135e2daf5c041a4ce7a7ab720cfd977fbae8375a007995e33a96558d3635792",
32
32
  "filename" => "appsignal-x86_64-darwin-all-dynamic.tar.gz"
33
33
  }
34
34
  },
35
35
  "aarch64-darwin" => {
36
36
  "static" => {
37
- "checksum" => "c80fa534a0f34d0056102ed5ec21cb558b714b17dc2a91f62fabdb992acc8a54",
37
+ "checksum" => "79d22436bfe32dab4661f2a4149c6ab34c71e810c5d808ee3e60cd9f8a1395e4",
38
38
  "filename" => "appsignal-aarch64-darwin-all-static.tar.gz"
39
39
  },
40
40
  "dynamic" => {
41
- "checksum" => "53139766b4a6459f6db2ef0e9175ab7828652594f32a885fe0d650bdd1748719",
41
+ "checksum" => "2c49c8f24a9dd8f9d55c28015b3e1096180807e7b13d4a9cd8ed30f58bc6612f",
42
42
  "filename" => "appsignal-aarch64-darwin-all-dynamic.tar.gz"
43
43
  }
44
44
  },
45
45
  "arm64-darwin" => {
46
46
  "static" => {
47
- "checksum" => "c80fa534a0f34d0056102ed5ec21cb558b714b17dc2a91f62fabdb992acc8a54",
47
+ "checksum" => "79d22436bfe32dab4661f2a4149c6ab34c71e810c5d808ee3e60cd9f8a1395e4",
48
48
  "filename" => "appsignal-aarch64-darwin-all-static.tar.gz"
49
49
  },
50
50
  "dynamic" => {
51
- "checksum" => "53139766b4a6459f6db2ef0e9175ab7828652594f32a885fe0d650bdd1748719",
51
+ "checksum" => "2c49c8f24a9dd8f9d55c28015b3e1096180807e7b13d4a9cd8ed30f58bc6612f",
52
52
  "filename" => "appsignal-aarch64-darwin-all-dynamic.tar.gz"
53
53
  }
54
54
  },
55
55
  "arm-darwin" => {
56
56
  "static" => {
57
- "checksum" => "c80fa534a0f34d0056102ed5ec21cb558b714b17dc2a91f62fabdb992acc8a54",
57
+ "checksum" => "79d22436bfe32dab4661f2a4149c6ab34c71e810c5d808ee3e60cd9f8a1395e4",
58
58
  "filename" => "appsignal-aarch64-darwin-all-static.tar.gz"
59
59
  },
60
60
  "dynamic" => {
61
- "checksum" => "53139766b4a6459f6db2ef0e9175ab7828652594f32a885fe0d650bdd1748719",
61
+ "checksum" => "2c49c8f24a9dd8f9d55c28015b3e1096180807e7b13d4a9cd8ed30f58bc6612f",
62
62
  "filename" => "appsignal-aarch64-darwin-all-dynamic.tar.gz"
63
63
  }
64
64
  },
65
65
  "aarch64-linux" => {
66
66
  "static" => {
67
- "checksum" => "71236975f40316d67c2b0e797814d52a49df8c5941375c0aed81c6870d82f299",
67
+ "checksum" => "4a54587bb61f59d0b60032b2e0c1d14d2e726e20af049353c2ff279d07dd3028",
68
68
  "filename" => "appsignal-aarch64-linux-all-static.tar.gz"
69
69
  },
70
70
  "dynamic" => {
71
- "checksum" => "b9dffb56bbf0f1fe5538e914c9a0124c10390ce88077351b1e47cb93efbce1e5",
71
+ "checksum" => "aa2d011c538ce547c87110e7c8e49a24597d60ea2d1418032fc3db06267efba2",
72
72
  "filename" => "appsignal-aarch64-linux-all-dynamic.tar.gz"
73
73
  }
74
74
  },
75
75
  "i686-linux" => {
76
76
  "static" => {
77
- "checksum" => "00ab0d029ede31225b2d134cdfab1e2c75e15e96229ef9e89ac14f51b8329988",
77
+ "checksum" => "01e2237029c3af23cc6f348fb63f65a92b8caf8f4731b78d014bb4001559aad5",
78
78
  "filename" => "appsignal-i686-linux-all-static.tar.gz"
79
79
  },
80
80
  "dynamic" => {
81
- "checksum" => "8a6aba576fc1c9ba419758e49d6d5fc9ffd636f983e160a7595871f09f382e9b",
81
+ "checksum" => "c1043ac92b000a406d9afb77b6ec1d3ab6cfffd63c218a720c11daa3edb7fd1f",
82
82
  "filename" => "appsignal-i686-linux-all-dynamic.tar.gz"
83
83
  }
84
84
  },
85
85
  "x86-linux" => {
86
86
  "static" => {
87
- "checksum" => "00ab0d029ede31225b2d134cdfab1e2c75e15e96229ef9e89ac14f51b8329988",
87
+ "checksum" => "01e2237029c3af23cc6f348fb63f65a92b8caf8f4731b78d014bb4001559aad5",
88
88
  "filename" => "appsignal-i686-linux-all-static.tar.gz"
89
89
  },
90
90
  "dynamic" => {
91
- "checksum" => "8a6aba576fc1c9ba419758e49d6d5fc9ffd636f983e160a7595871f09f382e9b",
91
+ "checksum" => "c1043ac92b000a406d9afb77b6ec1d3ab6cfffd63c218a720c11daa3edb7fd1f",
92
92
  "filename" => "appsignal-i686-linux-all-dynamic.tar.gz"
93
93
  }
94
94
  },
95
95
  "x86_64-linux" => {
96
96
  "static" => {
97
- "checksum" => "2e96245f692f47ee8fd12cca92b620baf79845ec920fb19b38612dd1cb051961",
97
+ "checksum" => "beae1db2c122eb579f1ccb450177b0c64d65569d774efc7a1ee72c42d3382d39",
98
98
  "filename" => "appsignal-x86_64-linux-all-static.tar.gz"
99
99
  },
100
100
  "dynamic" => {
101
- "checksum" => "c64e9903bddf0478ab9bbc316ce8ab46c0998173c922312fee527045e91554ad",
101
+ "checksum" => "67650f59d2ea9c99cde7dfe44da65a506522a3cdccabe697931d89ebaea96d18",
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" => "a99ebcdf993cd740dc556de9fba6e7ce1c802704c290c4d8b842cb4dc971473a",
107
+ "checksum" => "521c4486d10cdafa1f72103cc439d6f0e4f549f1522c4473bf43dc487ec42436",
108
108
  "filename" => "appsignal-x86_64-linux-musl-all-static.tar.gz"
109
109
  },
110
110
  "dynamic" => {
111
- "checksum" => "bfb583eebc82c2ae22f904a423df5af3cbf899225ffd8a3f96d0158985aa6e7c",
111
+ "checksum" => "0a94fcee8eb1f8fd06fce3eacffbcf9f2a52f5cde040796e19a589176525db4b",
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" => "874542de2899dc7ef6d286f1cb719614877651c6cafc9f5ae73d37d1aa0e61da",
117
+ "checksum" => "c29aab31f4ca59efb1483f48c0cb3c27d799347b81655a28f24c146b55aa7db6",
118
118
  "filename" => "appsignal-aarch64-linux-musl-all-static.tar.gz"
119
119
  },
120
120
  "dynamic" => {
121
- "checksum" => "02f895487486732bce4cbbed251275a3fc4830a4e890c592f2e95559a5ca11d5",
121
+ "checksum" => "4b77ea0c1f50ada6e5f6ed693002e56db1e34e0e9d5fdb4ac80fc52fd51099b8",
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" => "f30c529ed4fffe4f0668bcb59881061b22050813d9d10acf5a4bf03f4547a51b",
127
+ "checksum" => "a3598e9df1b6b5970aabbbccbe4e77c2372d2320cd87bfa20f32fca53b8505e4",
128
128
  "filename" => "appsignal-x86_64-freebsd-all-static.tar.gz"
129
129
  },
130
130
  "dynamic" => {
131
- "checksum" => "da6f4e31097ab2315b5bbffa8752284e40b535f4900057dc273a7bc7a23ac1ac",
131
+ "checksum" => "4cbfd5e16776c8ea4308ee7f3a096c5cc137f2506f8a05d9c8504e3483fcd8ac",
132
132
  "filename" => "appsignal-x86_64-freebsd-all-dynamic.tar.gz"
133
133
  }
134
134
  },
135
135
  "amd64-freebsd" => {
136
136
  "static" => {
137
- "checksum" => "f30c529ed4fffe4f0668bcb59881061b22050813d9d10acf5a4bf03f4547a51b",
137
+ "checksum" => "a3598e9df1b6b5970aabbbccbe4e77c2372d2320cd87bfa20f32fca53b8505e4",
138
138
  "filename" => "appsignal-x86_64-freebsd-all-static.tar.gz"
139
139
  },
140
140
  "dynamic" => {
141
- "checksum" => "da6f4e31097ab2315b5bbffa8752284e40b535f4900057dc273a7bc7a23ac1ac",
141
+ "checksum" => "4cbfd5e16776c8ea4308ee7f3a096c5cc137f2506f8a05d9c8504e3483fcd8ac",
142
142
  "filename" => "appsignal-x86_64-freebsd-all-dynamic.tar.gz"
143
143
  }
144
144
  }
data/ext/base.rb CHANGED
@@ -190,6 +190,9 @@ def store_download_version_on_report
190
190
  end
191
191
 
192
192
  def http_proxy
193
+ proxy = try_http_proxy_value(ENV.fetch("APPSIGNAL_HTTP_PROXY", nil))
194
+ return [proxy, nil] if proxy
195
+
193
196
  proxy, error =
194
197
  begin
195
198
  [try_http_proxy_value(Gem.configuration[:http_proxy]), nil]
@@ -8,7 +8,7 @@ require "tmpdir"
8
8
 
9
9
  module Appsignal
10
10
  class Config
11
- include Appsignal::Utils::DeprecationMessage
11
+ include Appsignal::Utils::StdoutAndLoggerMessage
12
12
 
13
13
  DEFAULT_CONFIG = {
14
14
  :activejob_report_errors => "all",
@@ -320,20 +320,29 @@ module Appsignal
320
320
  end
321
321
 
322
322
  def log_file_path
323
+ return @log_file_path if defined? @log_file_path
324
+
323
325
  path = config_hash[:log_path] || (root_path && File.join(root_path, "log"))
324
- return File.join(File.realpath(path), "appsignal.log") if path && File.writable?(path)
326
+ if path && File.writable?(path)
327
+ @log_file_path = File.join(File.realpath(path), "appsignal.log")
328
+ return @log_file_path
329
+ end
325
330
 
326
331
  system_tmp_dir = self.class.system_tmp_dir
327
332
  if File.writable? system_tmp_dir
328
333
  $stdout.puts "appsignal: Unable to log to '#{path}'. Logging to " \
329
- "'#{system_tmp_dir}' instead. Please check the " \
330
- "permissions for the application's (log) directory."
331
- File.join(system_tmp_dir, "appsignal.log")
334
+ "'#{system_tmp_dir}' instead. " \
335
+ "Please check the permissions for the application's (log) " \
336
+ "directory."
337
+ @log_file_path = File.join(system_tmp_dir, "appsignal.log")
332
338
  else
333
339
  $stdout.puts "appsignal: Unable to log to '#{path}' or the " \
334
340
  "'#{system_tmp_dir}' fallback. Please check the permissions " \
335
341
  "for the application's (log) directory."
342
+ @log_file_path = nil
336
343
  end
344
+
345
+ @log_file_path
337
346
  end
338
347
 
339
348
  def valid?
@@ -476,7 +485,7 @@ module Appsignal
476
485
  def maintain_backwards_compatibility
477
486
  return unless config_hash.key?(:working_dir_path)
478
487
 
479
- deprecation_message \
488
+ stdout_and_logger_warning \
480
489
  "The `working_dir_path` option is deprecated, please use " \
481
490
  "`working_directory_path` instead and specify the " \
482
491
  "full path to the working directory",
@@ -542,7 +551,7 @@ module Appsignal
542
551
  config[:send_session_data] = true # Set default value
543
552
  end
544
553
  else
545
- deprecation_message "The `skip_session_data` config option is " \
554
+ stdout_and_logger_warning "The `skip_session_data` config option is " \
546
555
  "deprecated. Please use `send_session_data` instead.",
547
556
  logger
548
557
  # Not configured by user
@@ -14,8 +14,6 @@ module Appsignal
14
14
  # @api private
15
15
  class EventFormatter
16
16
  class << self
17
- include Appsignal::Utils::DeprecationMessage
18
-
19
17
  def formatters
20
18
  @formatters ||= {}
21
19
  end
@@ -3,7 +3,7 @@
3
3
  module Appsignal
4
4
  module Helpers
5
5
  module Instrumentation # rubocop:disable Metrics/ModuleLength
6
- include Appsignal::Utils::DeprecationMessage
6
+ include Appsignal::Utils::StdoutAndLoggerMessage
7
7
 
8
8
  # Creates an AppSignal transaction for the given block.
9
9
  #
@@ -207,7 +207,7 @@ module Appsignal
207
207
  )
208
208
  if tags
209
209
  call_location = caller(1..1).first
210
- deprecation_message \
210
+ stdout_and_logger_warning \
211
211
  "The tags argument for `Appsignal.send_error` is deprecated. " \
212
212
  "Please use the block method to set tags instead.\n\n" \
213
213
  " Appsignal.send_error(error) do |transaction|\n" \
@@ -217,7 +217,7 @@ module Appsignal
217
217
  end
218
218
  if namespace
219
219
  call_location = caller(1..1).first
220
- deprecation_message \
220
+ stdout_and_logger_warning \
221
221
  "The namespace argument for `Appsignal.send_error` is deprecated. " \
222
222
  "Please use the block method to set the namespace instead.\n\n" \
223
223
  " Appsignal.send_error(error) do |transaction|\n" \
@@ -300,7 +300,7 @@ module Appsignal
300
300
  def set_error(exception, tags = nil, namespace = nil)
301
301
  if tags
302
302
  call_location = caller(1..1).first
303
- deprecation_message \
303
+ stdout_and_logger_warning \
304
304
  "The tags argument for `Appsignal.set_error` is deprecated. " \
305
305
  "Please use the block method to set tags instead.\n\n" \
306
306
  " Appsignal.set_error(error) do |transaction|\n" \
@@ -310,7 +310,7 @@ module Appsignal
310
310
  end
311
311
  if namespace
312
312
  call_location = caller(1..1).first
313
- deprecation_message \
313
+ stdout_and_logger_warning \
314
314
  "The namespace argument for `Appsignal.set_error` is deprecated. " \
315
315
  "Please use the block method to set the namespace instead.\n\n" \
316
316
  " Appsignal.set_error(error) do |transaction|\n" \
@@ -15,7 +15,7 @@ module Appsignal
15
15
  end
16
16
 
17
17
  def set_host_gauge(_key, _value)
18
- Appsignal::Utils::DeprecationMessage.message \
18
+ Appsignal::Utils::StdoutAndLoggerMessage.warning \
19
19
  "The `set_host_gauge` method has been deprecated. " \
20
20
  "Calling this method has no effect. " \
21
21
  "Please remove method call in the following file to remove " \
@@ -23,7 +23,7 @@ module Appsignal
23
23
  end
24
24
 
25
25
  def set_process_gauge(_key, _value)
26
- Appsignal::Utils::DeprecationMessage.message \
26
+ Appsignal::Utils::StdoutAndLoggerMessage.warning \
27
27
  "The `set_process_gauge` method has been deprecated. " \
28
28
  "Calling this method has no effect. " \
29
29
  "Please remove method call in the following file to remove " \
@@ -16,7 +16,7 @@ module Appsignal
16
16
  end
17
17
 
18
18
  def install
19
- Appsignal::Minutely.probes.register :gvl, Appsignal::Probes::GvlProbe
19
+ Appsignal::Probes.register :gvl, Appsignal::Probes::GvlProbe
20
20
  ::GVLTools::GlobalTimer.enable if Appsignal.config[:enable_gvl_global_timer]
21
21
  ::GVLTools::WaitingThreads.enable if Appsignal.config[:enable_gvl_waiting_threads]
22
22
  end
@@ -11,7 +11,7 @@ module Appsignal
11
11
  end
12
12
 
13
13
  def install
14
- Appsignal::Minutely.probes.register :mri, Appsignal::Probes::MriProbe
14
+ Appsignal::Probes.register :mri, Appsignal::Probes::MriProbe
15
15
  end
16
16
  end
17
17
  end
@@ -11,7 +11,7 @@ module Appsignal
11
11
 
12
12
  def install
13
13
  require "appsignal/integrations/sidekiq"
14
- Appsignal::Minutely.probes.register :sidekiq, Appsignal::Probes::SidekiqProbe
14
+ Appsignal::Probes.register :sidekiq, Appsignal::Probes::SidekiqProbe
15
15
 
16
16
  ::Sidekiq.configure_server do |config|
17
17
  config.error_handlers <<
@@ -76,7 +76,7 @@ module Appsignal
76
76
  when :SidekiqPlugin
77
77
  require "appsignal/integrations/sidekiq"
78
78
  callers = caller
79
- Appsignal::Utils::DeprecationMessage.message \
79
+ Appsignal::Utils::StdoutAndLoggerMessage.warning \
80
80
  "The constant Appsignal::Hooks::SidekiqPlugin has been deprecated. " \
81
81
  "Please update the constant name to Appsignal::Integrations::SidekiqMiddleware " \
82
82
  "in the following file to remove this message.\n#{callers.first}"
@@ -14,7 +14,7 @@ module Appsignal
14
14
  end
15
15
 
16
16
  console do
17
- Appsignal::Minutely.stop
17
+ Appsignal::Probes.stop
18
18
  end
19
19
 
20
20
  def self.initialize_appsignal(app)
@@ -2,6 +2,274 @@
2
2
 
3
3
  module Appsignal
4
4
  module Probes
5
+ class ProbeCollection
6
+ def initialize
7
+ @probes = {}
8
+ end
9
+
10
+ # @return [Integer] Number of probes that are registered.
11
+ def count
12
+ probes.count
13
+ end
14
+
15
+ # Clears all probes from the list.
16
+ # @return [void]
17
+ def clear
18
+ probes.clear
19
+ end
20
+
21
+ # Fetch a probe using its name.
22
+ # @param key [Symbol/String] The name of the probe to fetch.
23
+ # @return [Object] Returns the registered probe.
24
+ def [](key)
25
+ probes[key]
26
+ end
27
+
28
+ # @deprecated Use {Appsignal::Probes.register} instead.
29
+ def register(name, probe)
30
+ Appsignal::Utils::StdoutAndLoggerMessage.warning(
31
+ "The method 'Appsignal::Probes.probes.register' is deprecated. " \
32
+ "Use 'Appsignal::Probes.register' instead."
33
+ )
34
+ Appsignal::Probes.register(name, probe)
35
+ end
36
+
37
+ # @api private
38
+ def internal_register(name, probe)
39
+ if probes.key?(name)
40
+ logger.debug "A probe with the name `#{name}` is already " \
41
+ "registered. Overwriting the entry with the new probe."
42
+ end
43
+ probes[name] = probe
44
+ end
45
+
46
+ # @api private
47
+ def unregister(name)
48
+ probes.delete(name)
49
+ end
50
+
51
+ # @api private
52
+ def each(&block)
53
+ probes.each(&block)
54
+ end
55
+
56
+ private
57
+
58
+ attr_reader :probes
59
+
60
+ def logger
61
+ Appsignal.internal_logger
62
+ end
63
+ end
64
+
65
+ class << self
66
+ # @api private
67
+ def mutex
68
+ @mutex ||= Thread::Mutex.new
69
+ end
70
+
71
+ # @see ProbeCollection
72
+ # @return [ProbeCollection] Returns list of probes.
73
+ def probes
74
+ @probes ||= ProbeCollection.new
75
+ end
76
+
77
+ # Register a new minutely probe.
78
+ #
79
+ # Supported probe types are:
80
+ #
81
+ # - Lambda - A lambda is an object that listens to a `call` method call.
82
+ # This `call` method is called every minute.
83
+ # - Class - A class object is an object that listens to a `new` and
84
+ # `call` method call. The `new` method is called when the minutely
85
+ # probe thread is started to initialize all probes. This allows probes
86
+ # to load dependencies once beforehand. Their `call` method is called
87
+ # every minute.
88
+ # - Class instance - A class instance object is an object that listens to
89
+ # a `call` method call. The `call` method is called every minute.
90
+ #
91
+ # @example Register a new probe
92
+ # Appsignal::Probes.register :my_probe, lambda {}
93
+ #
94
+ # @example Overwrite an existing registered probe
95
+ # Appsignal::Probes.register :my_probe, lambda {}
96
+ # Appsignal::Probes.register :my_probe, lambda { puts "hello" }
97
+ #
98
+ # @example Add a lambda as a probe
99
+ # Appsignal::Probes.register :my_probe, lambda { puts "hello" }
100
+ # # "hello" # printed every minute
101
+ #
102
+ # @example Add a probe instance
103
+ # class MyProbe
104
+ # def initialize
105
+ # puts "started"
106
+ # end
107
+ #
108
+ # def call
109
+ # puts "called"
110
+ # end
111
+ # end
112
+ #
113
+ # Appsignal::Probes.register :my_probe, MyProbe.new
114
+ # # "started" # printed immediately
115
+ # # "called" # printed every minute
116
+ #
117
+ # @example Add a probe class
118
+ # class MyProbe
119
+ # def initialize
120
+ # # Add things that only need to be done on start up for this probe
121
+ # require "some/library/dependency"
122
+ # @cache = {} # initialize a local cache variable
123
+ # puts "started"
124
+ # end
125
+ #
126
+ # def call
127
+ # puts "called"
128
+ # end
129
+ # end
130
+ #
131
+ # Appsignal::Probes.register :my_probe, MyProbe
132
+ # Appsignal::Probes.start # This is called for you
133
+ # # "started" # Printed on Appsignal::Probes.start
134
+ # # "called" # Repeated every minute
135
+ #
136
+ # @param name [Symbol/String] Name of the probe. Can be used with
137
+ # {ProbeCollection#[]}. This name will be used in errors in the log and
138
+ # allows overwriting of probes by registering new ones with the same
139
+ # name.
140
+ # @param probe [Object] Any object that listens to the `call` method will
141
+ # be used as a probe.
142
+ # @return [void]
143
+ def register(name, probe)
144
+ probes.internal_register(name, probe)
145
+
146
+ initialize_probe(name, probe) if started?
147
+ end
148
+
149
+ # Unregister a probe that's registered with {register}.
150
+ # Can also be used to unregister automatically registered probes by the
151
+ # gem.
152
+ #
153
+ # @example Unregister probes
154
+ # # First register a probe
155
+ # Appsignal::Probes.register :my_probe, lambda {}
156
+ #
157
+ # # Then unregister a probe if needed
158
+ # Appsignal::Probes.unregister :my_probe
159
+ #
160
+ # @param name [Symbol/String] Name of the probe used to {register} the
161
+ # probe.
162
+ # @return [void]
163
+ def unregister(name)
164
+ probes.unregister(name)
165
+
166
+ uninitialize_probe(name)
167
+ end
168
+
169
+ # @api private
170
+ def start
171
+ stop
172
+ @started = true
173
+ @thread = Thread.new do
174
+ # Advise multi-threaded app servers to ignore this thread
175
+ # for the purposes of fork safety warnings
176
+ if Thread.current.respond_to?(:thread_variable_set)
177
+ Thread.current.thread_variable_set(:fork_safe, true)
178
+ end
179
+
180
+ sleep initial_wait_time
181
+ initialize_probes
182
+ loop do
183
+ logger = Appsignal.internal_logger
184
+ mutex.synchronize do
185
+ logger.debug("Gathering minutely metrics with #{probe_instances.count} probes")
186
+ probe_instances.each do |name, probe|
187
+ logger.debug("Gathering minutely metrics with '#{name}' probe")
188
+ probe.call
189
+ rescue => ex
190
+ logger.error "Error in minutely probe '#{name}': #{ex}"
191
+ logger.debug ex.backtrace.join("\n")
192
+ end
193
+ end
194
+ sleep wait_time
195
+ end
196
+ end
197
+ end
198
+
199
+ # Returns if the probes thread has been started. If the value is false or
200
+ # nil, it has not been started yet.
201
+ #
202
+ # @return [Boolean, nil]
203
+ def started?
204
+ @started
205
+ end
206
+
207
+ # Stop the minutely probes mechanism. Stop the thread and clear all probe
208
+ # instances.
209
+ def stop
210
+ defined?(@thread) && @thread.kill
211
+ @started = false
212
+ probe_instances.clear
213
+ end
214
+
215
+ # @api private
216
+ def wait_time
217
+ 60 - Time.now.sec
218
+ end
219
+
220
+ private
221
+
222
+ def initial_wait_time
223
+ remaining_seconds = 60 - Time.now.sec
224
+ return remaining_seconds if remaining_seconds > 30
225
+
226
+ remaining_seconds + 60
227
+ end
228
+
229
+ def initialize_probes
230
+ probes.each do |name, probe|
231
+ initialize_probe(name, probe)
232
+ end
233
+ end
234
+
235
+ def initialize_probe(name, probe)
236
+ if probe.respond_to? :new
237
+ instance = probe.new
238
+ klass = probe
239
+ else
240
+ instance = probe
241
+ klass = instance.class
242
+ end
243
+ unless dependencies_present?(klass)
244
+ Appsignal.internal_logger.debug "Skipping '#{name}' probe, " \
245
+ "#{klass}.dependency_present? returned falsy"
246
+ return
247
+ end
248
+ mutex.synchronize do
249
+ probe_instances[name] = instance
250
+ end
251
+ rescue => error
252
+ logger = Appsignal.internal_logger
253
+ logger.error "Error while initializing minutely probe '#{name}': #{error}"
254
+ logger.debug error.backtrace.join("\n")
255
+ end
256
+
257
+ def uninitialize_probe(name)
258
+ mutex.synchronize do
259
+ probe_instances.delete(name)
260
+ end
261
+ end
262
+
263
+ def dependencies_present?(probe)
264
+ return true unless probe.respond_to? :dependencies_present?
265
+
266
+ probe.dependencies_present?
267
+ end
268
+
269
+ def probe_instances
270
+ @probe_instances ||= {}
271
+ end
272
+ end
5
273
  end
6
274
  end
7
275
 
@@ -0,0 +1,17 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Appsignal
4
+ module Utils
5
+ # @api private
6
+ module StdoutAndLoggerMessage
7
+ def self.warning(message, logger = Appsignal.internal_logger)
8
+ Kernel.warn "appsignal WARNING: #{message}"
9
+ logger.warn message
10
+ end
11
+
12
+ def stdout_and_logger_warning(message, logger = Appsignal.internal_logger)
13
+ Appsignal::Utils::StdoutAndLoggerMessage.warning(message, logger)
14
+ end
15
+ end
16
+ end
17
+ end
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "appsignal/utils/deprecation_message"
3
+ require "appsignal/utils/stdout_and_logger_message"
4
4
  require "appsignal/utils/data"
5
5
  require "appsignal/utils/hash_sanitizer"
6
6
  require "appsignal/utils/integration_logger"
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Appsignal
4
- VERSION = "3.7.0"
4
+ VERSION = "3.7.2"
5
5
  end