appsignal 3.3.7 → 3.3.9

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 82b7849d736275523577d925d000a5eae8a1c371922c61b9ea124202612ca121
4
- data.tar.gz: 77177fc406fe073de5917b1829bc88f820ebfe941af8e1183be083d99d1735d6
3
+ metadata.gz: 762febba3d00911209c9fd4d6d7c1f55aa89ad38437df3da0fa5b36a00008c7b
4
+ data.tar.gz: 5cccb7e02b50707e3093025679cd48168379ed2300d855e851eb71d62095f4ff
5
5
  SHA512:
6
- metadata.gz: e431ab41f88aa1c67acf8ad2dd63fe7e79c1e9ca9b0e6ca219da97a1c8a114d7929007e55ffad403b48ddd985324bf7274477f0a085619e3d9d4f2a37f3e17ad
7
- data.tar.gz: 79e3ead1f689f0f9dd1a2b207b5051ec92fffbbd270349aa407d56a0c69669e48f3a1fc681f59ee93d445d92224129e207981a1e84d019f44b7df8b425c8c673
6
+ metadata.gz: eb3286752fa4a191175612ebb66ea1c8333c29ac74548d510a857aa1bce668d678a255bc995ac979e3f5fff424e9f39fb3883c0e9a835a496b15416b1d3efd5a
7
+ data.tar.gz: bb15b922ac0460bd0d58d7c5dcf50e95665be21bfc35af5d1a2d8ca400f78c2857fcc0d78f806568927607f55edffc5891c7b536c0554e48abbf90b41a7cc5fd
@@ -846,7 +846,7 @@ blocks:
846
846
  value: latest
847
847
  commands:
848
848
  - "./support/bundler_wrapper exec rake test"
849
- - name: Ruby 2.6.9 for webmachine
849
+ - name: Ruby 2.6.9 for webmachine1
850
850
  env_vars:
851
851
  - *2
852
852
  - *3
@@ -855,9 +855,27 @@ blocks:
855
855
  - name: RUBY_VERSION
856
856
  value: 2.6.9
857
857
  - name: GEMSET
858
- value: webmachine
858
+ value: webmachine1
859
859
  - name: BUNDLE_GEMFILE
860
- value: gemfiles/webmachine.gemfile
860
+ value: gemfiles/webmachine1.gemfile
861
+ - name: _RUBYGEMS_VERSION
862
+ value: latest
863
+ - name: _BUNDLER_VERSION
864
+ value: latest
865
+ commands:
866
+ - "./support/bundler_wrapper exec rake test"
867
+ - name: Ruby 2.6.9 for webmachine2
868
+ env_vars:
869
+ - *2
870
+ - *3
871
+ - *4
872
+ - *5
873
+ - name: RUBY_VERSION
874
+ value: 2.6.9
875
+ - name: GEMSET
876
+ value: webmachine2
877
+ - name: BUNDLE_GEMFILE
878
+ value: gemfiles/webmachine2.gemfile
861
879
  - name: _RUBYGEMS_VERSION
862
880
  value: latest
863
881
  - name: _BUNDLER_VERSION
@@ -1239,7 +1257,25 @@ blocks:
1239
1257
  value: latest
1240
1258
  commands:
1241
1259
  - "./support/bundler_wrapper exec rake test"
1242
- - name: Ruby 2.7.7 for webmachine
1260
+ - name: Ruby 2.7.7 for webmachine1
1261
+ env_vars:
1262
+ - *2
1263
+ - *3
1264
+ - *4
1265
+ - *5
1266
+ - name: RUBY_VERSION
1267
+ value: 2.7.7
1268
+ - name: GEMSET
1269
+ value: webmachine1
1270
+ - name: BUNDLE_GEMFILE
1271
+ value: gemfiles/webmachine1.gemfile
1272
+ - name: _RUBYGEMS_VERSION
1273
+ value: latest
1274
+ - name: _BUNDLER_VERSION
1275
+ value: latest
1276
+ commands:
1277
+ - "./support/bundler_wrapper exec rake test"
1278
+ - name: Ruby 2.7.7 for webmachine2
1243
1279
  env_vars:
1244
1280
  - *2
1245
1281
  - *3
@@ -1248,9 +1284,9 @@ blocks:
1248
1284
  - name: RUBY_VERSION
1249
1285
  value: 2.7.7
1250
1286
  - name: GEMSET
1251
- value: webmachine
1287
+ value: webmachine2
1252
1288
  - name: BUNDLE_GEMFILE
1253
- value: gemfiles/webmachine.gemfile
1289
+ value: gemfiles/webmachine2.gemfile
1254
1290
  - name: _RUBYGEMS_VERSION
1255
1291
  value: latest
1256
1292
  - name: _BUNDLER_VERSION
@@ -1596,7 +1632,7 @@ blocks:
1596
1632
  value: latest
1597
1633
  commands:
1598
1634
  - "./support/bundler_wrapper exec rake test"
1599
- - name: Ruby 3.0.5 for webmachine
1635
+ - name: Ruby 3.0.5 for webmachine1
1600
1636
  env_vars:
1601
1637
  - *2
1602
1638
  - *3
@@ -1605,9 +1641,27 @@ blocks:
1605
1641
  - name: RUBY_VERSION
1606
1642
  value: 3.0.5
1607
1643
  - name: GEMSET
1608
- value: webmachine
1644
+ value: webmachine1
1609
1645
  - name: BUNDLE_GEMFILE
1610
- value: gemfiles/webmachine.gemfile
1646
+ value: gemfiles/webmachine1.gemfile
1647
+ - name: _RUBYGEMS_VERSION
1648
+ value: latest
1649
+ - name: _BUNDLER_VERSION
1650
+ value: latest
1651
+ commands:
1652
+ - "./support/bundler_wrapper exec rake test"
1653
+ - name: Ruby 3.0.5 for webmachine2
1654
+ env_vars:
1655
+ - *2
1656
+ - *3
1657
+ - *4
1658
+ - *5
1659
+ - name: RUBY_VERSION
1660
+ value: 3.0.5
1661
+ - name: GEMSET
1662
+ value: webmachine2
1663
+ - name: BUNDLE_GEMFILE
1664
+ value: gemfiles/webmachine2.gemfile
1611
1665
  - name: _RUBYGEMS_VERSION
1612
1666
  value: latest
1613
1667
  - name: _BUNDLER_VERSION
@@ -1935,7 +1989,7 @@ blocks:
1935
1989
  value: latest
1936
1990
  commands:
1937
1991
  - "./support/bundler_wrapper exec rake test"
1938
- - name: Ruby 3.1.3 for webmachine
1992
+ - name: Ruby 3.1.3 for webmachine1
1939
1993
  env_vars:
1940
1994
  - *2
1941
1995
  - *3
@@ -1944,9 +1998,27 @@ blocks:
1944
1998
  - name: RUBY_VERSION
1945
1999
  value: 3.1.3
1946
2000
  - name: GEMSET
1947
- value: webmachine
2001
+ value: webmachine1
1948
2002
  - name: BUNDLE_GEMFILE
1949
- value: gemfiles/webmachine.gemfile
2003
+ value: gemfiles/webmachine1.gemfile
2004
+ - name: _RUBYGEMS_VERSION
2005
+ value: latest
2006
+ - name: _BUNDLER_VERSION
2007
+ value: latest
2008
+ commands:
2009
+ - "./support/bundler_wrapper exec rake test"
2010
+ - name: Ruby 3.1.3 for webmachine2
2011
+ env_vars:
2012
+ - *2
2013
+ - *3
2014
+ - *4
2015
+ - *5
2016
+ - name: RUBY_VERSION
2017
+ value: 3.1.3
2018
+ - name: GEMSET
2019
+ value: webmachine2
2020
+ - name: BUNDLE_GEMFILE
2021
+ value: gemfiles/webmachine2.gemfile
1950
2022
  - name: _RUBYGEMS_VERSION
1951
2023
  value: latest
1952
2024
  - name: _BUNDLER_VERSION
@@ -2274,7 +2346,25 @@ blocks:
2274
2346
  value: latest
2275
2347
  commands:
2276
2348
  - "./support/bundler_wrapper exec rake test"
2277
- - name: Ruby 3.2.1 for webmachine
2349
+ - name: Ruby 3.2.1 for webmachine1
2350
+ env_vars:
2351
+ - *2
2352
+ - *3
2353
+ - *4
2354
+ - *5
2355
+ - name: RUBY_VERSION
2356
+ value: 3.2.1
2357
+ - name: GEMSET
2358
+ value: webmachine1
2359
+ - name: BUNDLE_GEMFILE
2360
+ value: gemfiles/webmachine1.gemfile
2361
+ - name: _RUBYGEMS_VERSION
2362
+ value: latest
2363
+ - name: _BUNDLER_VERSION
2364
+ value: latest
2365
+ commands:
2366
+ - "./support/bundler_wrapper exec rake test"
2367
+ - name: Ruby 3.2.1 for webmachine2
2278
2368
  env_vars:
2279
2369
  - *2
2280
2370
  - *3
@@ -2283,9 +2373,9 @@ blocks:
2283
2373
  - name: RUBY_VERSION
2284
2374
  value: 3.2.1
2285
2375
  - name: GEMSET
2286
- value: webmachine
2376
+ value: webmachine2
2287
2377
  - name: BUNDLE_GEMFILE
2288
- value: gemfiles/webmachine.gemfile
2378
+ value: gemfiles/webmachine2.gemfile
2289
2379
  - name: _RUBYGEMS_VERSION
2290
2380
  value: latest
2291
2381
  - name: _BUNDLER_VERSION
data/CHANGELOG.md CHANGED
@@ -1,10 +1,28 @@
1
1
  # AppSignal for Ruby gem Changelog
2
2
 
3
+ ## 3.3.9
4
+
5
+ ### Fixed
6
+
7
+ - [a6db61b9](https://github.com/appsignal/appsignal-ruby/commit/a6db61b9a14a5a3b4ba89c99d35229bcdee98f94) patch - Fixed an error when using our Logging feature with Ruby's default logger formatter.
8
+
9
+ ## 3.3.8
10
+
11
+ ### Added
12
+
13
+ - [2fc6ba85](https://github.com/appsignal/appsignal-ruby/commit/2fc6ba85be1e0cabc2bb8fb26469ad47d1c60243) patch - Support "warning" value for `log_level` config option. This option was documented, but wasn't accepted and fell back on the "info" log level if used. Now it works to configure it to the "warn"/"warning" log level.
14
+ - [c04f7783](https://github.com/appsignal/appsignal-ruby/commit/c04f778332048aeaad9f75c131247caa29e504fa) patch - Add global VM lock metrics. If the `gvltools` library is installed, AppSignal for Ruby will report metrics on the global VM lock and the number of waiting threads in your application.
15
+
3
16
  ## 3.3.7
4
17
 
18
+ ### Added
19
+
20
+ - [a815b298](https://github.com/appsignal/appsignal-ruby/commit/a815b29826a84f430384e7e735f79c8c312f1abf) patch - Support cgroups v2. Used by newer Docker engines to report host metrics. Upgrade if you receive no host metrics for Docker containers.
21
+
5
22
  ### Changed
6
23
 
7
24
  - [8e67159e](https://github.com/appsignal/appsignal-ruby/commit/8e67159e2a57d3b697a07fadd8eb0e0234db9124) patch - Configure AppSignal with the RACK_ENV or RAILS_ENV environment variable in diagnose CLI, if present. Makes it easier to run the diagnose CLI in production, without having to always specify the environment with the `--environment` CLI option.
25
+ - [a815b298](https://github.com/appsignal/appsignal-ruby/commit/a815b29826a84f430384e7e735f79c8c312f1abf) patch - Allow transaction events to have a duration up to 48 hours before being discarded.
8
26
 
9
27
  ### Fixed
10
28
 
data/build_matrix.yml CHANGED
@@ -339,4 +339,5 @@ matrix:
339
339
  - "2.6.9"
340
340
  - "2.7.7"
341
341
  - gem: "sinatra"
342
- - gem: "webmachine"
342
+ - gem: "webmachine1"
343
+ - gem: "webmachine2"
@@ -1,6 +1,6 @@
1
1
  source 'https://rubygems.org'
2
2
 
3
- gem 'webmachine'
3
+ gem 'webmachine', '~> 1.6'
4
4
  gem 'webrick'
5
5
 
6
6
  gemspec :path => '../'
@@ -0,0 +1,6 @@
1
+ source "https://rubygems.org"
2
+
3
+ gem "webmachine", "~> 2.0"
4
+ gem "webrick"
5
+
6
+ gemspec :path => "../"
@@ -19,6 +19,8 @@ module Appsignal
19
19
  :enable_minutely_probes => true,
20
20
  :enable_statsd => true,
21
21
  :enable_nginx_metrics => false,
22
+ :enable_gvl_global_timer => true,
23
+ :enable_gvl_waiting_threads => true,
22
24
  :endpoint => "https://push.appsignal.com",
23
25
  :files_world_accessible => true,
24
26
  :filter_parameters => [],
@@ -53,6 +55,7 @@ module Appsignal
53
55
  LOG_LEVEL_MAP = {
54
56
  "error" => ::Logger::ERROR,
55
57
  "warn" => ::Logger::WARN,
58
+ "warning" => ::Logger::WARN,
56
59
  "info" => ::Logger::INFO,
57
60
  "debug" => ::Logger::DEBUG,
58
61
  "trace" => ::Logger::DEBUG
@@ -69,6 +72,8 @@ module Appsignal
69
72
  "APPSIGNAL_ENABLE_MINUTELY_PROBES" => :enable_minutely_probes,
70
73
  "APPSIGNAL_ENABLE_STATSD" => :enable_statsd,
71
74
  "APPSIGNAL_ENABLE_NGINX_METRICS" => :enable_nginx_metrics,
75
+ "APPSIGNAL_ENABLE_GVL_GLOBAL_TIMER" => :enable_gvl_global_timer,
76
+ "APPSIGNAL_ENABLE_GVL_WAITING_THREADS" => :enable_gvl_waiting_threads,
72
77
  "APPSIGNAL_FILES_WORLD_ACCESSIBLE" => :files_world_accessible,
73
78
  "APPSIGNAL_FILTER_PARAMETERS" => :filter_parameters,
74
79
  "APPSIGNAL_FILTER_SESSION_DATA" => :filter_session_data,
@@ -123,6 +128,8 @@ module Appsignal
123
128
  APPSIGNAL_ENABLE_MINUTELY_PROBES
124
129
  APPSIGNAL_ENABLE_STATSD
125
130
  APPSIGNAL_ENABLE_NGINX_METRICS
131
+ APPSIGNAL_ENABLE_GVL_GLOBAL_TIMER
132
+ APPSIGNAL_ENABLE_GVL_WAITING_THREADS
126
133
  APPSIGNAL_FILES_WORLD_ACCESSIBLE
127
134
  APPSIGNAL_INSTRUMENT_HTTP_RB
128
135
  APPSIGNAL_INSTRUMENT_NET_HTTP
@@ -0,0 +1,22 @@
1
+ module Appsignal
2
+ class Hooks
3
+ # @api private
4
+ class GvlHook < Appsignal::Hooks::Hook
5
+ register :gvl
6
+
7
+ def dependencies_present?
8
+ return false if Appsignal::System.jruby?
9
+ require "gvltools"
10
+ Appsignal.config && Appsignal::Probes::GvlProbe.dependencies_present?
11
+ rescue LoadError
12
+ false
13
+ end
14
+
15
+ def install
16
+ Appsignal::Minutely.probes.register :gvl, Appsignal::Probes::GvlProbe
17
+ ::GVLTools::GlobalTimer.enable if Appsignal.config[:enable_gvl_global_timer]
18
+ ::GVLTools::WaitingThreads.enable if Appsignal.config[:enable_gvl_waiting_threads]
19
+ end
20
+ end
21
+ end
22
+ end
@@ -94,6 +94,7 @@ require "appsignal/hooks/active_job"
94
94
  require "appsignal/hooks/active_support_notifications"
95
95
  require "appsignal/hooks/celluloid"
96
96
  require "appsignal/hooks/delayed_job"
97
+ require "appsignal/hooks/gvl"
97
98
  require "appsignal/hooks/http"
98
99
  require "appsignal/hooks/mri"
99
100
  require "appsignal/hooks/net_http"
@@ -9,6 +9,13 @@ module Appsignal
9
9
  PLAINTEXT = 0
10
10
  LOGFMT = 1
11
11
  JSON = 2
12
+ SEVERITY_MAP = {
13
+ DEBUG => 2,
14
+ INFO => 3,
15
+ WARN => 5,
16
+ ERROR => 6,
17
+ FATAL => 7
18
+ }.freeze
12
19
 
13
20
  # Create a new logger instance
14
21
  #
@@ -25,7 +32,7 @@ module Appsignal
25
32
  # We support the various methods in the Ruby
26
33
  # logger class by supplying this method.
27
34
  # @api private
28
- def add(severity, message = nil, group = nil) # rubocop:disable Metrics/CyclomaticComplexity
35
+ def add(severity, message = nil, group = nil)
29
36
  severity ||= UNKNOWN
30
37
  return true if severity < level
31
38
  group = @group if group.nil?
@@ -38,24 +45,11 @@ module Appsignal
38
45
  end
39
46
  end
40
47
  return if message.nil?
41
- message = formatter.call(severity, 0, group, message) if formatter
42
- severity_number = case severity
43
- when DEBUG
44
- 2
45
- when INFO
46
- 3
47
- when WARN
48
- 5
49
- when ERROR
50
- 6
51
- when FATAL
52
- 7
53
- else
54
- 0
55
- end
48
+ message = formatter.call(severity, Time.now, group, message) if formatter
49
+
56
50
  Appsignal::Extension.log(
57
51
  group,
58
- severity_number,
52
+ SEVERITY_MAP.fetch(severity, 0),
59
53
  @format,
60
54
  message,
61
55
  Appsignal::Utils::Data.generate({})
@@ -71,7 +65,7 @@ module Appsignal
71
65
  return if DEBUG < level
72
66
  message = yield if message.nil? && block_given?
73
67
  return if message.nil?
74
- message = formatter.call(DEBUG, 0, @group, message) if formatter
68
+ message = formatter.call(DEBUG, Time.now, @group, message) if formatter
75
69
  Appsignal::Extension.log(
76
70
  @group,
77
71
  2,
@@ -89,7 +83,7 @@ module Appsignal
89
83
  return if INFO < level
90
84
  message = yield if message.nil? && block_given?
91
85
  return if message.nil?
92
- message = formatter.call(INFO, 0, @group, message) if formatter
86
+ message = formatter.call(INFO, Time.now, @group, message) if formatter
93
87
  Appsignal::Extension.log(
94
88
  @group,
95
89
  3,
@@ -107,7 +101,7 @@ module Appsignal
107
101
  return if WARN < level
108
102
  message = yield if message.nil? && block_given?
109
103
  return if message.nil?
110
- message = formatter.call(WARN, 0, @group, message) if formatter
104
+ message = formatter.call(WARN, Time.now, @group, message) if formatter
111
105
  Appsignal::Extension.log(
112
106
  @group,
113
107
  5,
@@ -125,7 +119,7 @@ module Appsignal
125
119
  return if ERROR < level
126
120
  message = yield if message.nil? && block_given?
127
121
  return if message.nil?
128
- message = formatter.call(ERROR, 0, @group, message) if formatter
122
+ message = formatter.call(ERROR, Time.now, @group, message) if formatter
129
123
  Appsignal::Extension.log(
130
124
  @group,
131
125
  6,
@@ -143,7 +137,7 @@ module Appsignal
143
137
  return if FATAL < level
144
138
  message = yield if message.nil? && block_given?
145
139
  return if message.nil?
146
- message = formatter.call(FATAL, 0, @group, message) if formatter
140
+ message = formatter.call(FATAL, Time.now, @group, message) if formatter
147
141
  Appsignal::Extension.log(
148
142
  @group,
149
143
  7,
@@ -0,0 +1,47 @@
1
+ module Appsignal
2
+ module Probes
3
+ class GvlProbe
4
+ include Helpers
5
+
6
+ # @api private
7
+ def self.dependencies_present?
8
+ defined?(::GVLTools) && gvltools_0_2_or_newer? && ruby_3_2_or_newer? && !Appsignal::System.jruby?
9
+ end
10
+
11
+ # @api private
12
+ def self.gvltools_0_2_or_newer?
13
+ Gem::Version.new(::GVLTools::VERSION) >= Gem::Version.new("0.2.0")
14
+ end
15
+
16
+ # @api private
17
+ def self.ruby_3_2_or_newer?
18
+ Gem::Version.new(RUBY_VERSION) >= Gem::Version.new("3.2.0")
19
+ end
20
+
21
+ def initialize(appsignal: Appsignal, gvl_tools: ::GVLTools)
22
+ Appsignal.logger.debug("Initializing GVL probe")
23
+ @appsignal = appsignal
24
+ @gvl_tools = gvl_tools
25
+ end
26
+
27
+ def call
28
+ probe_global_timer if @gvl_tools::GlobalTimer.enabled?
29
+ probe_waiting_threads if @gvl_tools::WaitingThreads.enabled?
30
+ end
31
+
32
+ private
33
+
34
+ def probe_global_timer
35
+ monotonic_time_ns = @gvl_tools::GlobalTimer.monotonic_time
36
+ gauge_delta :gvl_global_timer, monotonic_time_ns do |time_delta_ns|
37
+ time_delta_ms = time_delta_ns / 1_000_000
38
+ set_gauge_with_hostname("gvl_global_timer", time_delta_ms)
39
+ end
40
+ end
41
+
42
+ def probe_waiting_threads
43
+ set_gauge_with_hostname("gvl_waiting_threads", @gvl_tools::WaitingThreads.count)
44
+ end
45
+ end
46
+ end
47
+ end
@@ -37,6 +37,27 @@ module Appsignal
37
37
 
38
38
  yield value - previous_value
39
39
  end
40
+
41
+ def hostname
42
+ return @hostname if defined?(@hostname)
43
+
44
+ config = @appsignal.config
45
+ @hostname =
46
+ if config[:hostname]
47
+ config[:hostname]
48
+ else
49
+ # Auto detect hostname as fallback. May be inaccurate.
50
+ Socket.gethostname
51
+ end
52
+ Appsignal.logger.debug "Probe helper: Using hostname config " \
53
+ "option '#{@hostname.inspect}' as hostname"
54
+
55
+ @hostname
56
+ end
57
+
58
+ def set_gauge_with_hostname(metric, value, tags = {})
59
+ @appsignal.set_gauge(metric, value, { :hostname => hostname }.merge(tags))
60
+ end
40
61
  end
41
62
  end
42
63
  end
@@ -20,7 +20,7 @@ module Appsignal
20
20
 
21
21
  constant_cache_invalidations = stat[:constant_cache_invalidations]
22
22
  if constant_cache_invalidations
23
- set_gauge(
23
+ set_gauge_with_hostname(
24
24
  "ruby_vm",
25
25
  constant_cache_invalidations,
26
26
  :metric => :constant_cache_invalidations
@@ -29,7 +29,7 @@ module Appsignal
29
29
 
30
30
  constant_cache_misses = stat[:constant_cache_misses]
31
31
  if constant_cache_misses
32
- set_gauge(
32
+ set_gauge_with_hostname(
33
33
  "ruby_vm",
34
34
  constant_cache_misses,
35
35
  :metric => :constant_cache_misses
@@ -38,23 +38,23 @@ module Appsignal
38
38
 
39
39
  class_serial = stat[:class_serial]
40
40
  if class_serial
41
- set_gauge("ruby_vm", class_serial, :metric => :class_serial)
41
+ set_gauge_with_hostname("ruby_vm", class_serial, :metric => :class_serial)
42
42
  end
43
43
 
44
44
  global_constant_state =
45
45
  stat[:constant_cache] ? stat[:constant_cache].values.sum : stat[:global_constant_state]
46
46
  if global_constant_state
47
- set_gauge(
47
+ set_gauge_with_hostname(
48
48
  "ruby_vm",
49
49
  global_constant_state,
50
50
  :metric => :global_constant_state
51
51
  )
52
52
  end
53
53
 
54
- set_gauge("thread_count", Thread.list.size)
54
+ set_gauge_with_hostname("thread_count", Thread.list.size)
55
55
  if Appsignal::GarbageCollection.enabled?
56
56
  gauge_delta(:gc_time, @gc_profiler.total_time) do |gc_time|
57
- set_gauge("gc_time", gc_time) if gc_time > 0
57
+ set_gauge_with_hostname("gc_time", gc_time) if gc_time > 0
58
58
  end
59
59
  end
60
60
 
@@ -63,44 +63,21 @@ module Appsignal
63
63
  :allocated_objects,
64
64
  gc_stats[:total_allocated_objects] || gc_stats[:total_allocated_object]
65
65
  ) do |allocated_objects|
66
- set_gauge("allocated_objects", allocated_objects)
66
+ set_gauge_with_hostname("allocated_objects", allocated_objects)
67
67
  end
68
68
 
69
69
  gauge_delta(:gc_count, GC.count) do |gc_count|
70
- set_gauge("gc_count", gc_count, :metric => :gc_count)
70
+ set_gauge_with_hostname("gc_count", gc_count, :metric => :gc_count)
71
71
  end
72
72
  gauge_delta(:minor_gc_count, gc_stats[:minor_gc_count]) do |minor_gc_count|
73
- set_gauge("gc_count", minor_gc_count, :metric => :minor_gc_count)
73
+ set_gauge_with_hostname("gc_count", minor_gc_count, :metric => :minor_gc_count)
74
74
  end
75
75
  gauge_delta(:major_gc_count, gc_stats[:major_gc_count]) do |major_gc_count|
76
- set_gauge("gc_count", major_gc_count, :metric => :major_gc_count)
76
+ set_gauge_with_hostname("gc_count", major_gc_count, :metric => :major_gc_count)
77
77
  end
78
78
 
79
- set_gauge("heap_slots", gc_stats[:heap_live_slots] || gc_stats[:heap_live_slot], :metric => :heap_live)
80
- set_gauge("heap_slots", gc_stats[:heap_free_slots] || gc_stats[:heap_free_slot], :metric => :heap_free)
81
- end
82
-
83
- private
84
-
85
- def set_gauge(metric, value, tags = {})
86
- @appsignal.set_gauge(metric, value, { :hostname => hostname }.merge(tags))
87
- end
88
-
89
- def hostname
90
- return @hostname if defined?(@hostname)
91
-
92
- config = @appsignal.config
93
- @hostname =
94
- if config[:hostname]
95
- config[:hostname]
96
- else
97
- # Auto detect hostname as fallback. May be inaccurate.
98
- Socket.gethostname
99
- end
100
- Appsignal.logger.debug "MRI probe: Using hostname config " \
101
- "option '#{@hostname.inspect}' as hostname"
102
-
103
- @hostname
79
+ set_gauge_with_hostname("heap_slots", gc_stats[:heap_live_slots] || gc_stats[:heap_live_slot], :metric => :heap_live)
80
+ set_gauge_with_hostname("heap_slots", gc_stats[:heap_free_slots] || gc_stats[:heap_free_slot], :metric => :heap_free)
104
81
  end
105
82
  end
106
83
  end
@@ -4,5 +4,6 @@ module Appsignal
4
4
  end
5
5
 
6
6
  require "appsignal/probes/helpers"
7
+ require "appsignal/probes/gvl"
7
8
  require "appsignal/probes/mri"
8
9
  require "appsignal/probes/sidekiq"
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Appsignal
4
- VERSION = "3.3.7".freeze
4
+ VERSION = "3.3.9".freeze
5
5
  end
@@ -156,6 +156,8 @@ describe Appsignal::Config do
156
156
  :debug => false,
157
157
  :dns_servers => [],
158
158
  :enable_allocation_tracking => true,
159
+ :enable_gvl_global_timer => true,
160
+ :enable_gvl_waiting_threads => true,
159
161
  :enable_host_metrics => true,
160
162
  :enable_minutely_probes => true,
161
163
  :enable_statsd => true,
@@ -0,0 +1,140 @@
1
+ describe Appsignal::Hooks::GvlHook do
2
+ if DependencyHelper.running_jruby?
3
+ context "running JRuby" do
4
+ it "does not attempt to require GVLTools" do
5
+ expect_any_instance_of(described_class).not_to receive(:require).with("gvltools")
6
+ expect(described_class.new.dependencies_present?).to be_falsy
7
+ end
8
+ end
9
+ else
10
+ before(:context) do
11
+ Appsignal.config = project_fixture_config
12
+ end
13
+
14
+ def expect_gvltools_require
15
+ expect_any_instance_of(described_class).to receive(:require).with("gvltools").and_return(true)
16
+ end
17
+
18
+ context "without GVLTools" do
19
+ describe "#dependencies_present?" do
20
+ context "if requiring gvltools fails" do
21
+ it "is false" do
22
+ expect(described_class.new.dependencies_present?).to be_falsy
23
+ end
24
+ end
25
+
26
+ it "is false" do
27
+ expect_gvltools_require
28
+ expect(described_class.new.dependencies_present?).to be_falsy
29
+ end
30
+ end
31
+ end
32
+
33
+ context "with old versions of GVLTools" do
34
+ before(:context) do
35
+ module GVLTools
36
+ VERSION = "0.1.0".freeze
37
+ end
38
+ end
39
+
40
+ after(:context) { Object.send(:remove_const, :GVLTools) }
41
+
42
+ before(:each) { expect_gvltools_require }
43
+
44
+ describe "#dependencies_present?" do
45
+ it "is false" do
46
+ expect(described_class.new.dependencies_present?).to be_falsy
47
+ end
48
+ end
49
+ end
50
+
51
+ context "with new versions of GVLTools" do
52
+ before(:context) do
53
+ module GVLTools
54
+ VERSION = "0.2.0".freeze
55
+
56
+ module GlobalTimer
57
+ def self.enable
58
+ end
59
+ end
60
+
61
+ module WaitingThreads
62
+ def self.enable
63
+ end
64
+ end
65
+ end
66
+ end
67
+
68
+ after(:context) { Object.send(:remove_const, :GVLTools) }
69
+
70
+ describe "#dependencies_present?" do
71
+ before(:each) { expect_gvltools_require }
72
+
73
+ if DependencyHelper.ruby_3_2_or_newer?
74
+ it "is true" do
75
+ expect(described_class.new.dependencies_present?).to be_truthy
76
+ end
77
+ else
78
+ it "is false" do
79
+ expect(described_class.new.dependencies_present?).to be_falsy
80
+ end
81
+ end
82
+ end
83
+
84
+ if DependencyHelper.ruby_3_2_or_newer?
85
+ describe "Appsignal::Hooks.load_hooks" do
86
+ before(:each) { expect_gvltools_require }
87
+
88
+ # After installing a hook once, it is marked as already installed,
89
+ # and subsequent calls to `load_hooks` silently do nothing.
90
+ # Because of this, only one of the tests for the installation uses
91
+ # `load_hooks`, while the rest call the `install` method directly.
92
+
93
+ it "is added to minutely probes" do
94
+ Appsignal::Hooks.load_hooks
95
+
96
+ expect(Appsignal::Minutely.probes[:gvl]).to be Appsignal::Probes::GvlProbe
97
+ end
98
+ end
99
+ end
100
+
101
+ describe "#install" do
102
+ context "with enable_gvl_global_timer" do
103
+ it "enables the GVL global timer" do
104
+ Appsignal.config[:enable_gvl_global_timer] = true
105
+ expect(::GVLTools::GlobalTimer).to receive(:enable)
106
+
107
+ described_class.new.install
108
+ end
109
+ end
110
+
111
+ context "without enable_gvl_global_timer" do
112
+ it "does not enable the GVL global timer" do
113
+ Appsignal.config[:enable_gvl_global_timer] = false
114
+ expect(::GVLTools::GlobalTimer).not_to receive(:enable)
115
+
116
+ described_class.new.install
117
+ end
118
+ end
119
+
120
+ context "with enable_gvl_waiting_threads" do
121
+ it "enables the GVL waiting threads" do
122
+ Appsignal.config[:enable_gvl_global_timer] = true
123
+ expect(::GVLTools::WaitingThreads).to receive(:enable)
124
+
125
+ described_class.new.install
126
+ end
127
+ end
128
+
129
+ context "without enable_gvl_waiting_threads" do
130
+ it "does not enable the GVL waiting threads" do
131
+ Appsignal.config[:enable_gvl_waiting_threads] = false
132
+ expect(::GVLTools::WaitingThreads).not_to receive(:enable)
133
+
134
+ described_class.new.install
135
+ end
136
+ end
137
+ end
138
+ end
139
+ end
140
+ end
@@ -115,14 +115,29 @@ describe Appsignal::Logger do
115
115
 
116
116
  context "with a formatter set" do
117
117
  before do
118
- logger.formatter = proc do |_level, _timestamp, _appname, message|
119
- "formatted: '#{message}'"
118
+ Timecop.freeze(Time.local(2023))
119
+ logger.formatter = logger.formatter = proc do |_level, timestamp, _appname, message|
120
+ # This line replicates the behaviour of the Ruby default Logger::Formatter
121
+ # which expects a timestamp object as a second argument
122
+ # https://github.com/ruby/ruby/blob/master/lib/logger/formatter.rb#L15-L17
123
+ time = timestamp.strftime("%Y-%m-%dT%H:%M:%S.%6N")
124
+ "formatted: #{time} '#{message}'"
120
125
  end
121
126
  end
122
127
 
128
+ after do
129
+ Timecop.return
130
+ end
131
+
123
132
  it "should log with a level, message and group" do
124
133
  expect(Appsignal::Extension).to receive(:log)
125
- .with("group", method[1], 0, "formatted: 'Log message'", instance_of(Appsignal::Extension::Data))
134
+ .with(
135
+ "group",
136
+ method[1],
137
+ 0,
138
+ "formatted: 2023-01-01T00:00:00.000000 'Log message'",
139
+ instance_of(Appsignal::Extension::Data)
140
+ )
126
141
  logger.send(method[0], "Log message")
127
142
  end
128
143
  end
@@ -0,0 +1,39 @@
1
+ describe Appsignal::Probes::GvlProbe do
2
+ let(:appsignal_mock) { AppsignalMock.new(:hostname => hostname) }
3
+ let(:probe) { described_class.new(:appsignal => appsignal_mock, :gvl_tools => FakeGVLTools) }
4
+
5
+ let(:hostname) { "some-host" }
6
+
7
+ after(:each) { FakeGVLTools.reset }
8
+
9
+ context "with global timer enabled" do
10
+ before(:each) { FakeGVLTools::GlobalTimer.enabled = true }
11
+
12
+ it "gauges the global timer delta" do
13
+ FakeGVLTools::GlobalTimer.monotonic_time = 100_000_000
14
+ probe.call
15
+
16
+ expect(appsignal_mock.gauges).to be_empty
17
+
18
+ FakeGVLTools::GlobalTimer.monotonic_time = 300_000_000
19
+ probe.call
20
+
21
+ expect(appsignal_mock.gauges).to eq [
22
+ ["gvl_global_timer", 200, { :hostname => hostname }]
23
+ ]
24
+ end
25
+ end
26
+
27
+ context "with waiting threads enabled" do
28
+ before(:each) { FakeGVLTools::WaitingThreads.enabled = true }
29
+
30
+ it "gauges the waiting threads count" do
31
+ FakeGVLTools::WaitingThreads.count = 3
32
+ probe.call
33
+
34
+ expect(appsignal_mock.gauges).to eq [
35
+ ["gvl_waiting_threads", 3, { :hostname => hostname }]
36
+ ]
37
+ end
38
+ end
39
+ end
@@ -1,22 +1,3 @@
1
- class AppsignalMock
2
- attr_reader :gauges
3
-
4
- def initialize(hostname: nil)
5
- @hostname = hostname
6
- @gauges = []
7
- end
8
-
9
- def config
10
- ConfigHelpers.project_fixture_config.tap do |conf|
11
- conf[:hostname] = @hostname if @hostname
12
- end
13
- end
14
-
15
- def set_gauge(*args) # rubocop:disable Naming/AccessorMethodName
16
- @gauges << args
17
- end
18
- end
19
-
20
1
  describe Appsignal::Probes::MriProbe do
21
2
  let(:appsignal_mock) { AppsignalMock.new(:hostname => hostname) }
22
3
  let(:gc_profiler_mock) { instance_double("Appsignal::GarbageCollectionProfiler") }
@@ -0,0 +1,18 @@
1
+ class AppsignalMock
2
+ attr_reader :gauges
3
+
4
+ def initialize(hostname: nil)
5
+ @hostname = hostname
6
+ @gauges = []
7
+ end
8
+
9
+ def config
10
+ ConfigHelpers.project_fixture_config.tap do |conf|
11
+ conf[:hostname] = @hostname if @hostname
12
+ end
13
+ end
14
+
15
+ def set_gauge(*args) # rubocop:disable Naming/AccessorMethodName
16
+ @gauges << args
17
+ end
18
+ end
@@ -0,0 +1,36 @@
1
+ module FakeGVLTools
2
+ def self.reset
3
+ self::GlobalTimer.enabled = false
4
+ self::GlobalTimer.monotonic_time = 0
5
+ self::WaitingThreads.enabled = false
6
+ self::WaitingThreads.count = 0
7
+ end
8
+
9
+ module GlobalTimer
10
+ @enabled = false
11
+ @monotonic_time = 0
12
+
13
+ class << self
14
+ attr_writer :enabled
15
+ attr_accessor :monotonic_time
16
+
17
+ def enabled?
18
+ @enabled
19
+ end
20
+ end
21
+ end
22
+
23
+ module WaitingThreads
24
+ @enabled = false
25
+ @count = 0
26
+
27
+ class << self
28
+ attr_writer :enabled
29
+ attr_accessor :count
30
+
31
+ def enabled?
32
+ @enabled
33
+ end
34
+ end
35
+ end
36
+ end
metadata CHANGED
@@ -1,16 +1,16 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: appsignal
3
3
  version: !ruby/object:Gem::Version
4
- version: 3.3.7
4
+ version: 3.3.9
5
5
  platform: ruby
6
6
  authors:
7
7
  - Robert Beekman
8
8
  - Thijs Cadier
9
9
  - Tom de Bruijn
10
- autorequire:
10
+ autorequire:
11
11
  bindir: bin
12
12
  cert_chain: []
13
- date: 2023-03-09 00:00:00.000000000 Z
13
+ date: 2023-03-31 00:00:00.000000000 Z
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
16
16
  name: rack
@@ -182,7 +182,8 @@ files:
182
182
  - gemfiles/sequel-435.gemfile
183
183
  - gemfiles/sequel.gemfile
184
184
  - gemfiles/sinatra.gemfile
185
- - gemfiles/webmachine.gemfile
185
+ - gemfiles/webmachine1.gemfile
186
+ - gemfiles/webmachine2.gemfile
186
187
  - lib/appsignal.rb
187
188
  - lib/appsignal/auth_check.rb
188
189
  - lib/appsignal/capistrano.rb
@@ -218,6 +219,7 @@ files:
218
219
  - lib/appsignal/hooks/data_mapper.rb
219
220
  - lib/appsignal/hooks/delayed_job.rb
220
221
  - lib/appsignal/hooks/excon.rb
222
+ - lib/appsignal/hooks/gvl.rb
221
223
  - lib/appsignal/hooks/http.rb
222
224
  - lib/appsignal/hooks/mongo_ruby_driver.rb
223
225
  - lib/appsignal/hooks/mri.rb
@@ -260,6 +262,7 @@ files:
260
262
  - lib/appsignal/marker.rb
261
263
  - lib/appsignal/minutely.rb
262
264
  - lib/appsignal/probes.rb
265
+ - lib/appsignal/probes/gvl.rb
263
266
  - lib/appsignal/probes/helpers.rb
264
267
  - lib/appsignal/probes/mri.rb
265
268
  - lib/appsignal/probes/sidekiq.rb
@@ -323,6 +326,7 @@ files:
323
326
  - spec/lib/appsignal/hooks/data_mapper_spec.rb
324
327
  - spec/lib/appsignal/hooks/delayed_job_spec.rb
325
328
  - spec/lib/appsignal/hooks/excon_spec.rb
329
+ - spec/lib/appsignal/hooks/gvl_spec.rb
326
330
  - spec/lib/appsignal/hooks/http_spec.rb
327
331
  - spec/lib/appsignal/hooks/mongo_ruby_driver_spec.rb
328
332
  - spec/lib/appsignal/hooks/mri_spec.rb
@@ -354,6 +358,7 @@ files:
354
358
  - spec/lib/appsignal/logger_spec.rb
355
359
  - spec/lib/appsignal/marker_spec.rb
356
360
  - spec/lib/appsignal/minutely_spec.rb
361
+ - spec/lib/appsignal/probes/gvl_spec.rb
357
362
  - spec/lib/appsignal/probes/mri_spec.rb
358
363
  - spec/lib/appsignal/probes/sidekiq_spec.rb
359
364
  - spec/lib/appsignal/rack/generic_instrumentation_spec.rb
@@ -402,7 +407,9 @@ files:
402
407
  - spec/support/matchers/be_completed.rb
403
408
  - spec/support/matchers/contains_log.rb
404
409
  - spec/support/matchers/have_colorized_text.rb
410
+ - spec/support/mocks/appsignal_mock.rb
405
411
  - spec/support/mocks/fake_gc_profiler.rb
412
+ - spec/support/mocks/fake_gvl_tools.rb
406
413
  - spec/support/mocks/mock_probe.rb
407
414
  - spec/support/rails/my_app.rb
408
415
  - spec/support/shared_examples/instrument.rb
@@ -422,7 +429,7 @@ metadata:
422
429
  documentation_uri: https://docs.appsignal.com/ruby/
423
430
  homepage_uri: https://docs.appsignal.com/ruby/
424
431
  source_code_uri: https://github.com/appsignal/appsignal-ruby
425
- post_install_message:
432
+ post_install_message:
426
433
  rdoc_options: []
427
434
  require_paths:
428
435
  - lib
@@ -438,8 +445,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
438
445
  - !ruby/object:Gem::Version
439
446
  version: '0'
440
447
  requirements: []
441
- rubygems_version: 3.1.6
442
- signing_key:
448
+ rubygems_version: 3.1.4
449
+ signing_key:
443
450
  specification_version: 4
444
451
  summary: Logs performance and exception data from your app to appsignal.com
445
452
  test_files:
@@ -480,6 +487,7 @@ test_files:
480
487
  - spec/lib/appsignal/hooks/data_mapper_spec.rb
481
488
  - spec/lib/appsignal/hooks/delayed_job_spec.rb
482
489
  - spec/lib/appsignal/hooks/excon_spec.rb
490
+ - spec/lib/appsignal/hooks/gvl_spec.rb
483
491
  - spec/lib/appsignal/hooks/http_spec.rb
484
492
  - spec/lib/appsignal/hooks/mongo_ruby_driver_spec.rb
485
493
  - spec/lib/appsignal/hooks/mri_spec.rb
@@ -511,6 +519,7 @@ test_files:
511
519
  - spec/lib/appsignal/logger_spec.rb
512
520
  - spec/lib/appsignal/marker_spec.rb
513
521
  - spec/lib/appsignal/minutely_spec.rb
522
+ - spec/lib/appsignal/probes/gvl_spec.rb
514
523
  - spec/lib/appsignal/probes/mri_spec.rb
515
524
  - spec/lib/appsignal/probes/sidekiq_spec.rb
516
525
  - spec/lib/appsignal/rack/generic_instrumentation_spec.rb
@@ -559,7 +568,9 @@ test_files:
559
568
  - spec/support/matchers/be_completed.rb
560
569
  - spec/support/matchers/contains_log.rb
561
570
  - spec/support/matchers/have_colorized_text.rb
571
+ - spec/support/mocks/appsignal_mock.rb
562
572
  - spec/support/mocks/fake_gc_profiler.rb
573
+ - spec/support/mocks/fake_gvl_tools.rb
563
574
  - spec/support/mocks/mock_probe.rb
564
575
  - spec/support/rails/my_app.rb
565
576
  - spec/support/shared_examples/instrument.rb