plain_apm 0.8.2 → 0.8.4

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: e2b710d576d9940ab2def7718d734c7b4665ca27b1c92de976e2dbdbe27df7c3
4
- data.tar.gz: 1c25404189e867c88edfdb4f98b089ae99a731961a6ee44f154bd718d246e60f
3
+ metadata.gz: ff5ddab9e3475ec09d7ef20f6bc5c6ae64ffa0e3ffa946d84def56c33eb41cde
4
+ data.tar.gz: '085a3004d655b642bbd63b295ce7c41531d2264709820b8f9ab35e31bdfe987d'
5
5
  SHA512:
6
- metadata.gz: 0f043623e89b5dd6fc2c725151a61b161cf59be1e29ef73fd9e47faec8e3007b93f52a7a33ee7fd351040f1ae111e73bee34d4ef7db73b48b949948f4a252d20
7
- data.tar.gz: a42e2dfd3bbae6eda795c9526af4ecb4cb33d61f052ba8815ec922a207aaa1a4ccdb9249c810665404bda8958220b9c6960fed6064aa28575021ead810d205cd
6
+ metadata.gz: 960c5aad1354d5cc97e43d537807afeac46cdb41db125e9a832447912d2d7b0934041c8e39965bd7f8727fe9d7e4b9600250ce9c687559bfb02347afe90205b4
7
+ data.tar.gz: 7985afc06387dbfca63c0a69665516ebb3d54cdf88cd4532fba427d03594ab9e0e65c7a4dab08b9e1c1f63d912fb68afad22c62f7348b87d5f09c38ef146c117
data/README.md CHANGED
@@ -13,11 +13,38 @@ gem 'plain_apm'
13
13
 
14
14
  And then execute:
15
15
 
16
- $ bundle install
16
+ bundle install
17
17
 
18
18
  Or install it yourself as:
19
19
 
20
- $ gem install plain_apm
20
+ gem install plain_apm
21
+
22
+ ### Ractor and TracePoint issues on Ruby 3.0
23
+
24
+ PlainAPM extension to track object allocation on a per-thread basis is
25
+ built on top of Ruby's TracePoint API.
26
+
27
+ However, Rubies 3.0, 3.1, 3.2 and 3.3 as of January 2024 contain bugs
28
+ which, when Tracepoints are used in together with Ractors, can cause
29
+ crashes or inconsistent tracing results.
30
+
31
+ Build process for the native extension contains checks for presence of
32
+ these bugs and disables object allocation tracing accordingly.
33
+
34
+ If you are sure your app is not using Ractors, you can override this by
35
+ installing plain_apm with --enable-object-tracing-override flag:
36
+
37
+ gem install plain_apm -- --enable-object-tracing-override
38
+
39
+ When using bundler, you can configure it to pass this flag to the gem
40
+ install by running:
41
+
42
+ bundle config set --global build.plain_apm --enable-object-tracing-override
43
+
44
+ See also:
45
+
46
+ - https://bugs.ruby-lang.org/issues/18464
47
+ - https://bugs.ruby-lang.org/issues/19112
21
48
 
22
49
  ## Usage
23
50
 
@@ -0,0 +1,8 @@
1
+ exit 0 if !defined?(Ractor)
2
+
3
+ require "objspace"
4
+
5
+ ObjectSpace.trace_object_allocations do
6
+ r = Ractor.new { 10 }
7
+ r.take
8
+ end
@@ -0,0 +1,33 @@
1
+ exit 0 if !defined?(Ractor)
2
+
3
+ # This affects all tracepoints, including internal ones
4
+
5
+ def hello
6
+ "world"
7
+ end
8
+
9
+ traced_calls = 0
10
+
11
+ # Enable tracing
12
+ tracepoint = TracePoint.trace(:call) do |tp|
13
+ traced_calls += 1 if tp.callee_id == :hello
14
+ end
15
+
16
+ 5.times { hello }
17
+
18
+ # Create a ractor and let it be garbage collected
19
+ r = Ractor.new { 10 }
20
+ r.take
21
+ r_id = r.object_id
22
+ r = nil
23
+
24
+ until (ObjectSpace._id2ref(r_id) rescue nil).nil?
25
+ GC.start
26
+ end
27
+
28
+ # Trigger extra calls to be traced, w/ Ractor enabled, they won't be.
29
+ 5.times { hello }
30
+
31
+ tracepoint.disable
32
+
33
+ exit traced_calls == 10 ? 0 : 1
@@ -1,6 +1,84 @@
1
1
  require "mkmf"
2
2
 
3
- have_header("ruby/ruby.h") or missing("ruby/ruby.h")
4
- have_header("ruby/debug.h") or missing("ruby/debug.h")
3
+ def abort_on_missing_ruby_header(name)
4
+ abort(
5
+ <<-MSG
6
+
7
+ PlainAPM extension needs #{name} Ruby library header to compile.
8
+
9
+ If Ruby is installed from a package on your system, please ensure the
10
+ corresponding Ruby development package is installed as well.
11
+
12
+ E.g. on Debian/Ubuntu, this would be achieved by running
13
+
14
+ sudo apt install ruby-dev
15
+
16
+ on CentOS/Fedora, run
17
+
18
+ sudo yum install ruby-devel
19
+
20
+ etc...
21
+ MSG
22
+ )
23
+ end
24
+
25
+ def warn_on_ruby_ractor_bugs
26
+ warn(
27
+ <<-MSG
28
+
29
+ PlainAPM extension to track object allocation on a per-thread basis is
30
+ built on top of Ruby's TracePoint API.
31
+
32
+ However, the currently running Ruby version contains bugs which,
33
+ when Tracepoints are used in together with Ractors, can cause
34
+ crashes or inconsistent tracing results.
35
+
36
+ Per-thread object allocation tracing will be disabled.
37
+
38
+ If you are sure your app is not using Ractors, you can override this by
39
+ installing plain_apm with --enable-object-tracing-override flag:
40
+
41
+ gem install plain_apm -- --enable-object-tracing-override
42
+
43
+ When using bundler, you can configure it to pass this flag to the gem
44
+ install by running:
45
+
46
+ bundle config set --global build.plain_apm --enable-object-tracing-override
47
+
48
+ See also:
49
+
50
+ https://bugs.ruby-lang.org/issues/18464
51
+ https://bugs.ruby-lang.org/issues/19112
52
+
53
+ MSG
54
+ )
55
+ end
56
+
57
+ def try_ruby(file)
58
+ system("ruby", "-W0", File.join(__dir__, file), [:out, :err] => File::NULL)
59
+ end
60
+
61
+ def enable_object_tracing
62
+ $defs.push("-DOBJECT_TRACING_ENABLED") unless $defs.include? "-DOBJECT_TRACING_ENABLED"
63
+ end
64
+
65
+ %w(
66
+ ruby/ruby.h
67
+ ruby/debug.h
68
+ ).each do |header|
69
+ have_header(header) or abort_on_missing_ruby_header(header)
70
+ end
71
+
72
+ if enable_config("object-tracing-override", false)
73
+ enable_object_tracing
74
+ else
75
+ bugs = %w(bug18464.rb bug19112).count { |f| !try_ruby(f) }
76
+
77
+ if bugs.zero?
78
+ enable_object_tracing
79
+ else
80
+ warn_on_ruby_ractor_bugs
81
+ end
82
+ end
5
83
 
6
84
  create_makefile("object_tracing")
@@ -1,25 +1,56 @@
1
1
  #include <ruby/ruby.h>
2
2
  #include <ruby/debug.h>
3
3
 
4
+ static VALUE rb_mPlainApm = Qnil;
5
+ static VALUE rb_mObjTracing = Qnil;
6
+
4
7
  static __thread uint64_t allocated_objects = 0;
5
8
 
6
- static VALUE rb_mPlainApm;
7
- static VALUE rb_mObjTracing;
8
-
9
- static VALUE total_thread_allocated_objects(VALUE self) {
10
- return ULL2NUM(allocated_objects);
11
- }
9
+ #ifdef OBJECT_TRACING_ENABLED
10
+ static int object_tracing_active = 0;
12
11
 
13
12
  static void track_thread_allocated_objects(VALUE tpval, void *data) {
14
13
  allocated_objects++;
15
14
  }
15
+ #endif
16
+
17
+ static VALUE total_thread_allocated_objects(VALUE self) {
18
+ return ULL2NUM(allocated_objects);
19
+ }
16
20
 
17
21
  void Init_object_tracing(void) {
18
22
  rb_mPlainApm = rb_define_module("PlainApm");
23
+ rb_gc_register_address(&rb_mPlainApm);
24
+
19
25
  rb_mObjTracing = rb_define_module_under(rb_mPlainApm, "ObjectTracing");
26
+ rb_gc_register_address(&rb_mObjTracing);
20
27
 
21
28
  rb_define_singleton_method(rb_mObjTracing, "total_thread_allocated_objects", total_thread_allocated_objects, 0);
22
29
 
30
+ #ifdef OBJECT_TRACING_ENABLED
31
+ /* Ensure the tracepoint is attached only once. */
32
+ if (object_tracing_active) { return; }
33
+
34
+ object_tracing_active = 1;
35
+
36
+ /* Object allocation tracing is impacted by these bugs:
37
+ *
38
+ * https://bugs.ruby-lang.org/issues/19112 in Rubies 3.x.x
39
+ * https://bugs.ruby-lang.org/issues/18464 in Rubies 3.0, 3.1, and 3.2
40
+ *
41
+ * According to
42
+ *
43
+ * https://www.ruby-lang.org/en/downloads/branches/
44
+ *
45
+ * 3.0 goes out of maintenance mid 2024. The latter bug was backported to the
46
+ * other branches.
47
+ *
48
+ * For the former, there's https://github.com/ruby/ruby/pull/7184 open,
49
+ * unmerged as of Dec 2023.
50
+ *
51
+ */
52
+
23
53
  VALUE tpval = rb_tracepoint_new(0, RUBY_INTERNAL_EVENT_NEWOBJ, track_thread_allocated_objects, NULL);
24
54
  rb_tracepoint_enable(tpval);
55
+ #endif
25
56
  }
@@ -118,7 +118,7 @@ module PlainApm
118
118
  # or is generated by the trace_id middleware).
119
119
  # It can also carry user inserted app data.
120
120
  if defined?(PlainApm::Extensions::Context)
121
- PlainApm::Extensions::Context.current
121
+ PlainApm::Extensions::Context.current.transform_keys(&:to_s)
122
122
  else
123
123
  {}
124
124
  end
@@ -12,7 +12,7 @@ module PlainApm
12
12
  def serialize
13
13
  trace_id = PlainApm::Extensions::Context.trace_id || SecureRandom.uuid
14
14
  # Rails wasn't preserving the nano-time, this has now been fixed
15
- # upstream in #39698 and scheduled for Rails 7.1.
15
+ # upstream in #39698 and fixed in Rails 7.1.
16
16
  super.update("trace_id" => trace_id, "enqueued_at" => Time.now.utc.iso8601(9))
17
17
  end
18
18
 
@@ -22,12 +22,12 @@ module PlainApm
22
22
  status, headers, body = @app.call(env)
23
23
 
24
24
  body = if defined?(::Rack::BodyProxy)
25
- ::Rack::BodyProxy.new(body) do
26
- Context.clear!
27
- end
28
- else
29
- body
30
- end
25
+ ::Rack::BodyProxy.new(body) do
26
+ Context.clear!
27
+ end
28
+ else
29
+ body
30
+ end
31
31
 
32
32
  processed = true
33
33
 
@@ -6,6 +6,13 @@
6
6
  # https://github.com/steveklabnik/request_store/
7
7
  #
8
8
  # See LICENSE.txt in the current directory for the license.
9
+
10
+ begin
11
+ require "rails/railtie"
12
+ rescue LoadError
13
+ nil
14
+ end
15
+
9
16
  module PlainApm
10
17
  module Extensions
11
18
  module Context
@@ -1,5 +1,11 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ begin
4
+ require "rails/railtie"
5
+ rescue LoadError
6
+ nil
7
+ end
8
+
3
9
  module PlainApm
4
10
  module Extensions
5
11
  module Exceptions
@@ -1,3 +1,11 @@
1
+ # frozen_string_literal: true
2
+
3
+ begin
4
+ require "rails/railtie"
5
+ rescue LoadError
6
+ nil
7
+ end
8
+
1
9
  module PlainApm
2
10
  module Extensions
3
11
  module ThreadAllocations
@@ -49,11 +49,19 @@ module PlainApm
49
49
  private
50
50
 
51
51
  def enqueued_at(job)
52
- Time.parse(job.enqueued_at).to_f if job.enqueued_at
52
+ if job.enqueued_at
53
+ if job.enqueued_at.is_a?(Time)
54
+ job.enqueued_at.iso8601(9)
55
+ else
56
+ Time.parse(job.enqueued_at).iso8601(9)
57
+ end
58
+ end
53
59
  end
54
60
 
55
61
  def dequeued_at(job)
56
- Time.parse(job.dequeued_at).to_f if job.respond_to?(:dequeued_at) && job.dequeued_at
62
+ if job.respond_to?(:dequeued_at) && job.dequeued_at
63
+ Time.parse(job.dequeued_at).iso8601(9)
64
+ end
57
65
  end
58
66
  end
59
67
  end
@@ -1,5 +1,12 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ begin
4
+ require "active_support"
5
+ require "active_support/notifications"
6
+ rescue LoadError
7
+ nil
8
+ end
9
+
3
10
  module PlainApm
4
11
  module Hooks
5
12
  class ActiveSupportSubscriber
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module PlainApm
4
- VERSION = "0.8.2"
4
+ VERSION = "0.8.4"
5
5
  end
data/lib/plain_apm.rb CHANGED
@@ -51,6 +51,12 @@ module PlainApm
51
51
  @@agent ||= Agent.instance
52
52
  end
53
53
 
54
+ begin
55
+ require "rails/railtie"
56
+ rescue LoadError
57
+ nil
58
+ end
59
+
54
60
  # after_initialize allows reading settings from ENV on app start.
55
61
  if defined?(Rails::Railtie)
56
62
  class Railtie < Rails::Railtie
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: plain_apm
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.8.2
4
+ version: 0.8.4
5
5
  platform: ruby
6
6
  authors:
7
7
  - PlainAPM Team
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2023-12-28 00:00:00.000000000 Z
11
+ date: 2024-01-01 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: minitest
@@ -92,6 +92,8 @@ files:
92
92
  - Gemfile
93
93
  - LICENSE.txt
94
94
  - README.md
95
+ - ext/object_tracing/bug18464.rb
96
+ - ext/object_tracing/bug19112.rb
95
97
  - ext/object_tracing/extconf.rb
96
98
  - ext/object_tracing/object_tracing.c
97
99
  - lib/plain_apm.rb
@@ -130,7 +132,11 @@ metadata:
130
132
  source_code_uri: https://github.com/plainapm/plainapm-ruby
131
133
  changelog_uri: https://github.com/plainapm/plainapm-ruby/blob/main/CHANGELOG.md
132
134
  github_repo: git@github.com:plainapm/plainapm-ruby.git
133
- post_install_message:
135
+ post_install_message: "\n PlainAPM object tracing is affected by Ractor related
136
+ bugs,\n so it is not enabled by default on Ruby 3.\n\n If you are sure
137
+ your app does not use Ractors, this can be overridden by\n installing the gem
138
+ with --enable-object-tracing-override flag.\n\n Please see https://github.com/plainapm/plainapm-ruby/#installation
139
+ for\n more details.\n "
134
140
  rdoc_options: []
135
141
  require_paths:
136
142
  - lib
@@ -138,7 +144,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
138
144
  requirements:
139
145
  - - ">="
140
146
  - !ruby/object:Gem::Version
141
- version: '2.6'
147
+ version: '2.7'
142
148
  required_rubygems_version: !ruby/object:Gem::Requirement
143
149
  requirements:
144
150
  - - ">="