Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Use #prepend over #alias_method for Thread plugin #1018

Merged
merged 1 commit into from
Dec 9, 2020

Conversation

delner
Copy link
Contributor

@delner delner commented Dec 4, 2020

Description of the change

The Thread plugin uses alias_method rewrites to patch Thread behavior. This is destructive and doesn't play well with other patches (particularly from other libraries.) Instead, use prepend which non-destructively patches.

While alias_method was previously necessary for Ruby < 2.0 support, with that version support being dropped, prepend should be preferred.

Type of change

  • Bug fix (non-breaking change that fixes an issue)
  • New feature (non-breaking change that adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to not work as expected)

Related issues

(None)

Checklists

Development

  • Lint rules pass locally
  • The code changed/added as part of this pull request has been covered with tests
  • All tests related to the changed code pass in development

Code review

  • This pull request has a descriptive title and information useful to a reviewer. There may be a screenshot or screencast attached
  • "Ready for review" label attached to the PR and reviewers mentioned in a comment
  • Changes have been reviewed by at least one other engineer
  • Issue from task tracker has a link to this pull request

Copy link
Contributor Author

@delner delner left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just some notes for the code reviewer's consideration!

Thread.class_eval do
def initialize_with_rollbar(*args, &block)
module Rollbar
module ThreadPlugin
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would have named this Thread, however, many other parts of the codebase use Thread instead of ::Thread, so this causes a naming conflict. Rather than update all those files, I opted to choose a different name.

end
end

execute do
Thread.send(:prepend, Rollbar::ThreadPlugin) # rubocop:disable Lint/SendWithMixinArgument
Copy link
Contributor Author

@delner delner Dec 4, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Because Rollbar supports Ruby 2.0, you cannot do Thread.prepend, as the method is private in 2.0. Using send makes this compatible.


Rollbar.plugins.load!

describe Rollbar::ThreadPlugin do
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There was no spec specifically for this plugin, so I thought I'd add this to improve coverage.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you!

@delner
Copy link
Contributor Author

delner commented Dec 9, 2020

Hey @waltjones! Would you be the right guy to ask for a code review? (Saw you had done the most recent release, so thought I'd ask.) I think this one should be ready for a review from your team 😄

@waltjones
Copy link
Contributor

@delner Yes, happy to take a look at this.

Copy link
Contributor

@waltjones waltjones left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good, and thank you for the helpful comments.

@waltjones waltjones merged commit 310a9d1 into rollbar:master Dec 9, 2020
@GaurabAryal
Copy link

Hey @waltjones, I was wondering when the next build will be released with this fix included?

@waltjones
Copy link
Contributor

It'll be in the next release. There isn't a date set for that, but most likely early January.

ivoanjo added a commit to DataDog/dd-trace-rb that referenced this pull request Jan 6, 2021
Rollbar gem versions <= 3.1.1 have an incompatibility with ddtrace's
CPU profiling. This was ack'd and fixed upstream in
<rollbar/rollbar-gem#1018>.

This commit adds code to detect when customers are still using a legacy
version of rollbar, printing a warning to ask them to upgrade.

Note: Because the fixed version of rollbar has not yet been released,
the tests that validate that the warning is not shown on unpatched
versions are disabled and tagged with a FIXME.

See the "FIXME NEW ROLLBAR NEEDED" note in the setup_spec.rb for more
details on what's disabled and what steps we need to take once the
new version gets released.
ivoanjo added a commit to DataDog/dd-trace-rb that referenced this pull request Jan 6, 2021
Rollbar gem versions <= 3.1.1 have an incompatibility with ddtrace's
CPU profiling. This was ack'd and fixed upstream in
<rollbar/rollbar-gem#1018>.

This commit adds code to detect when customers are still using a legacy
version of rollbar, printing a warning to ask them to upgrade.

Note: Because the fixed version of rollbar has not yet been released,
the tests that validate that the warning is not shown on unpatched
versions are disabled and tagged with a FIXME.

See the "FIXME NEW ROLLBAR NEEDED" note in the setup_spec.rb for more
details on what's disabled and what steps we need to take once the
new version gets released.

First commit @ Datadog 🎉
ivoanjo added a commit to DataDog/dd-trace-rb that referenced this pull request Jan 6, 2021
Rollbar gem versions <= 3.1.1 have an incompatibility with ddtrace's
CPU profiling. This was ack'd and fixed upstream in
<rollbar/rollbar-gem#1018>.

This commit adds code to detect when customers are still using a legacy
version of rollbar, printing a warning to ask them to upgrade.

Note: Because the fixed version of rollbar has not yet been released,
the tests that validate that the warning is not shown on unpatched
versions are disabled and tagged with a FIXME.

See the "FIXME NEW ROLLBAR NEEDED" note in the setup_spec.rb for more
details on what's disabled and what steps we need to take once the
new version gets released.

First commit @ Datadog 🎉
ivoanjo added a commit to DataDog/dd-trace-rb that referenced this pull request Jan 6, 2021
Rollbar gem versions <= 3.1.1 have an incompatibility with ddtrace's
CPU profiling. This was ack'd and fixed upstream in
<rollbar/rollbar-gem#1018>.

This commit adds code to detect when customers are still using a legacy
version of rollbar, printing a warning to ask them to upgrade.

Note: Because the fixed version of rollbar has not yet been released,
the tests that validate that the warning is not shown on unpatched
versions are disabled and tagged with a FIXME.

See the "FIXME NEW ROLLBAR NEEDED" note in the setup_spec.rb for more
details on what's disabled and what steps we need to take once the
new version gets released.

First commit @ Datadog 🎉
@delner delner deleted the thread_prepend branch January 6, 2021 16:59
@mriddle
Copy link

mriddle commented Jan 21, 2021

@waltjones any update on the release? 🙂

@waltjones
Copy link
Contributor

@mriddle Not yet. Working to get a Rollbar.js release out any day now, and then will focus on rollbar-gem.

ivoanjo added a commit to DataDog/dd-trace-rb that referenced this pull request Feb 2, 2021
Rollbar gem versions <= 3.1.1 have an incompatibility with ddtrace's
CPU profiling. This was ack'd and fixed upstream in
<rollbar/rollbar-gem#1018>.

This commit adds code to detect when customers are still using a legacy
version of rollbar, printing a warning to ask them to upgrade.

Note: Because the fixed version of rollbar has not yet been released,
the tests that validate that the warning is not shown on unpatched
versions are disabled and tagged with a FIXME.

See the "FIXME NEW ROLLBAR NEEDED" note in the setup_spec.rb for more
details on what's disabled and what steps we need to take once the
new version gets released.

First commit @ Datadog 🎉
ivoanjo added a commit to DataDog/dd-trace-rb that referenced this pull request Feb 2, 2021
Rollbar gem versions <= 3.1.1 have an incompatibility with ddtrace's
CPU profiling. This was ack'd and fixed upstream in
<rollbar/rollbar-gem#1018>.

This commit adds code to detect when customers are still using a legacy
version of rollbar, printing a warning to ask them to upgrade.

Note: Because the fixed version of rollbar has not yet been released,
the tests that validate that the warning is not shown on unpatched
versions are disabled and tagged with a FIXME.

See the "FIXME NEW ROLLBAR NEEDED" note in the setup_spec.rb for more
details on what's disabled and what steps we need to take once the
new version gets released.

First commit @ Datadog 🎉
ivoanjo added a commit to DataDog/dd-trace-rb that referenced this pull request Feb 9, 2021
Rollbar gem versions <= 3.1.1 have an incompatibility with ddtrace's
CPU profiling. This was ack'd and fixed upstream in
<rollbar/rollbar-gem#1018>.

This commit adds code to detect when customers are still using a legacy
version of rollbar, printing a warning to ask them to upgrade.

Note: Because the fixed version of rollbar has not yet been released,
the tests that validate that the warning is not shown on unpatched
versions are disabled and tagged with a FIXME.

See the "FIXME NEW ROLLBAR NEEDED" note in the setup_spec.rb for more
details on what's disabled and what steps we need to take once the
new version gets released.

First commit @ Datadog 🎉
@waltjones
Copy link
Contributor

Released in v3.1.2. Apologies for the delay.

ivoanjo added a commit to DataDog/dd-trace-rb that referenced this pull request Feb 11, 2021
When I initially worked on #1300 ("Warn on incompatible rollbar
version") my understanding of the issue on rollbar/rollbar-gem#1018 was
incomplete and I did not realize that old rollbar versions, beyond
breaking datadog profiler's CPU time instrumentation, could actually
break the customer's application.

One of our private beta customers mentioned he had seen both the
warning but also had seen a stack trace:

```
[1] ! Unable to load application: SystemStackError: stack level too deep
/usr/local/bundle/gems/rollbar-3.1.1/lib/rollbar/plugins/thread.rb:5:in `initialize_with_rollbar': stack level too deep (SystemStackError)
	from /usr/local/bundle/gems/ddtrace-0.45.0.feature.profiling.109457/lib/ddtrace/profiling/ext/cthread.rb:47:in `initialize'
	from /usr/local/bundle/gems/rollbar-3.1.1/lib/rollbar/plugins/thread.rb:6:in `initialize_with_rollbar'
	from /usr/local/bundle/gems/ddtrace-0.45.0.feature.profiling.109457/lib/ddtrace/profiling/ext/cthread.rb:47:in `initialize'
```

This led me to try to reproduce this issue. I discovered that with

```ruby
ENV['DD_PROFILING_ENABLED'] = 'true'
require 'ddtrace/profiling/preload'

require 'rollbar'
Rollbar.configure do |c|
  c.access_token = "nope"
end

Thread.new { }.join
```

I could trigger the issue, and that the current behavior was that
the warning from #1300 would be printed, but then the application
would proceed to fail.

Having a bit more experience with the codebase now, I realize that
the correct place to put this check is in the CPU extension
 #unsupported_reason method, which will ensure the extension is
not loaded at all if an incompatible version of rollbar is around.

The resulting behavior is that even with an old rollbar version,
profiler will happily load and work; it will just omit the CPU
time profiling, similarly to how it behaves on other platforms where
for different reasons we don't support CPU time profiling.
@ivoanjo
Copy link

ivoanjo commented Feb 11, 2021

Thanks a lot for the effort @waltjones 👍 👍 👍

ivoanjo added a commit to DataDog/dd-trace-rb that referenced this pull request Mar 11, 2021
Rollbar gem versions <= 3.1.1 have an incompatibility with ddtrace's
CPU profiling. This was ack'd and fixed upstream in
<rollbar/rollbar-gem#1018>.

This commit adds code to detect when customers are still using a legacy
version of rollbar, printing a warning to ask them to upgrade.

Note: Because the fixed version of rollbar has not yet been released,
the tests that validate that the warning is not shown on unpatched
versions are disabled and tagged with a FIXME.

See the "FIXME NEW ROLLBAR NEEDED" note in the setup_spec.rb for more
details on what's disabled and what steps we need to take once the
new version gets released.

First commit @ Datadog 🎉
ivoanjo added a commit to DataDog/dd-trace-rb that referenced this pull request Mar 11, 2021
When I initially worked on #1300 ("Warn on incompatible rollbar
version") my understanding of the issue on rollbar/rollbar-gem#1018 was
incomplete and I did not realize that old rollbar versions, beyond
breaking datadog profiler's CPU time instrumentation, could actually
break the customer's application.

One of our private beta customers mentioned he had seen both the
warning but also had seen a stack trace:

```
[1] ! Unable to load application: SystemStackError: stack level too deep
/usr/local/bundle/gems/rollbar-3.1.1/lib/rollbar/plugins/thread.rb:5:in `initialize_with_rollbar': stack level too deep (SystemStackError)
	from /usr/local/bundle/gems/ddtrace-0.45.0.feature.profiling.109457/lib/ddtrace/profiling/ext/cthread.rb:47:in `initialize'
	from /usr/local/bundle/gems/rollbar-3.1.1/lib/rollbar/plugins/thread.rb:6:in `initialize_with_rollbar'
	from /usr/local/bundle/gems/ddtrace-0.45.0.feature.profiling.109457/lib/ddtrace/profiling/ext/cthread.rb:47:in `initialize'
```

This led me to try to reproduce this issue. I discovered that with

```ruby
ENV['DD_PROFILING_ENABLED'] = 'true'
require 'ddtrace/profiling/preload'

require 'rollbar'
Rollbar.configure do |c|
  c.access_token = "nope"
end

Thread.new { }.join
```

I could trigger the issue, and that the current behavior was that
the warning from #1300 would be printed, but then the application
would proceed to fail.

Having a bit more experience with the codebase now, I realize that
the correct place to put this check is in the CPU extension
 #unsupported_reason method, which will ensure the extension is
not loaded at all if an incompatible version of rollbar is around.

The resulting behavior is that even with an old rollbar version,
profiler will happily load and work; it will just omit the CPU
time profiling, similarly to how it behaves on other platforms where
for different reasons we don't support CPU time profiling.
ivoanjo added a commit to DataDog/dd-trace-rb that referenced this pull request Mar 16, 2021
Rollbar gem versions <= 3.1.1 have an incompatibility with ddtrace's
CPU profiling. This was ack'd and fixed upstream in
<rollbar/rollbar-gem#1018>.

This commit adds code to detect when customers are still using a legacy
version of rollbar, printing a warning to ask them to upgrade.

Note: Because the fixed version of rollbar has not yet been released,
the tests that validate that the warning is not shown on unpatched
versions are disabled and tagged with a FIXME.

See the "FIXME NEW ROLLBAR NEEDED" note in the setup_spec.rb for more
details on what's disabled and what steps we need to take once the
new version gets released.

First commit @ Datadog 🎉
ivoanjo added a commit to DataDog/dd-trace-rb that referenced this pull request Mar 16, 2021
When I initially worked on #1300 ("Warn on incompatible rollbar
version") my understanding of the issue on rollbar/rollbar-gem#1018 was
incomplete and I did not realize that old rollbar versions, beyond
breaking datadog profiler's CPU time instrumentation, could actually
break the customer's application.

One of our private beta customers mentioned he had seen both the
warning but also had seen a stack trace:

```
[1] ! Unable to load application: SystemStackError: stack level too deep
/usr/local/bundle/gems/rollbar-3.1.1/lib/rollbar/plugins/thread.rb:5:in `initialize_with_rollbar': stack level too deep (SystemStackError)
	from /usr/local/bundle/gems/ddtrace-0.45.0.feature.profiling.109457/lib/ddtrace/profiling/ext/cthread.rb:47:in `initialize'
	from /usr/local/bundle/gems/rollbar-3.1.1/lib/rollbar/plugins/thread.rb:6:in `initialize_with_rollbar'
	from /usr/local/bundle/gems/ddtrace-0.45.0.feature.profiling.109457/lib/ddtrace/profiling/ext/cthread.rb:47:in `initialize'
```

This led me to try to reproduce this issue. I discovered that with

```ruby
ENV['DD_PROFILING_ENABLED'] = 'true'
require 'ddtrace/profiling/preload'

require 'rollbar'
Rollbar.configure do |c|
  c.access_token = "nope"
end

Thread.new { }.join
```

I could trigger the issue, and that the current behavior was that
the warning from #1300 would be printed, but then the application
would proceed to fail.

Having a bit more experience with the codebase now, I realize that
the correct place to put this check is in the CPU extension
 #unsupported_reason method, which will ensure the extension is
not loaded at all if an incompatible version of rollbar is around.

The resulting behavior is that even with an old rollbar version,
profiler will happily load and work; it will just omit the CPU
time profiling, similarly to how it behaves on other platforms where
for different reasons we don't support CPU time profiling.
ivoanjo added a commit to DataDog/dd-trace-rb that referenced this pull request Mar 29, 2021
Rollbar gem versions <= 3.1.1 have an incompatibility with ddtrace's
CPU profiling. This was ack'd and fixed upstream in
<rollbar/rollbar-gem#1018>.

This commit adds code to detect when customers are still using a legacy
version of rollbar, printing a warning to ask them to upgrade.

Note: Because the fixed version of rollbar has not yet been released,
the tests that validate that the warning is not shown on unpatched
versions are disabled and tagged with a FIXME.

See the "FIXME NEW ROLLBAR NEEDED" note in the setup_spec.rb for more
details on what's disabled and what steps we need to take once the
new version gets released.

First commit @ Datadog 🎉
ivoanjo added a commit to DataDog/dd-trace-rb that referenced this pull request Mar 29, 2021
When I initially worked on #1300 ("Warn on incompatible rollbar
version") my understanding of the issue on rollbar/rollbar-gem#1018 was
incomplete and I did not realize that old rollbar versions, beyond
breaking datadog profiler's CPU time instrumentation, could actually
break the customer's application.

One of our private beta customers mentioned he had seen both the
warning but also had seen a stack trace:

```
[1] ! Unable to load application: SystemStackError: stack level too deep
/usr/local/bundle/gems/rollbar-3.1.1/lib/rollbar/plugins/thread.rb:5:in `initialize_with_rollbar': stack level too deep (SystemStackError)
	from /usr/local/bundle/gems/ddtrace-0.45.0.feature.profiling.109457/lib/ddtrace/profiling/ext/cthread.rb:47:in `initialize'
	from /usr/local/bundle/gems/rollbar-3.1.1/lib/rollbar/plugins/thread.rb:6:in `initialize_with_rollbar'
	from /usr/local/bundle/gems/ddtrace-0.45.0.feature.profiling.109457/lib/ddtrace/profiling/ext/cthread.rb:47:in `initialize'
```

This led me to try to reproduce this issue. I discovered that with

```ruby
ENV['DD_PROFILING_ENABLED'] = 'true'
require 'ddtrace/profiling/preload'

require 'rollbar'
Rollbar.configure do |c|
  c.access_token = "nope"
end

Thread.new { }.join
```

I could trigger the issue, and that the current behavior was that
the warning from #1300 would be printed, but then the application
would proceed to fail.

Having a bit more experience with the codebase now, I realize that
the correct place to put this check is in the CPU extension
 #unsupported_reason method, which will ensure the extension is
not loaded at all if an incompatible version of rollbar is around.

The resulting behavior is that even with an old rollbar version,
profiler will happily load and work; it will just omit the CPU
time profiling, similarly to how it behaves on other platforms where
for different reasons we don't support CPU time profiling.
ivoanjo added a commit to DataDog/dd-trace-rb that referenced this pull request Apr 12, 2021
Rollbar gem versions <= 3.1.1 have an incompatibility with ddtrace's
CPU profiling. This was ack'd and fixed upstream in
<rollbar/rollbar-gem#1018>.

This commit adds code to detect when customers are still using a legacy
version of rollbar, printing a warning to ask them to upgrade.

Note: Because the fixed version of rollbar has not yet been released,
the tests that validate that the warning is not shown on unpatched
versions are disabled and tagged with a FIXME.

See the "FIXME NEW ROLLBAR NEEDED" note in the setup_spec.rb for more
details on what's disabled and what steps we need to take once the
new version gets released.

First commit @ Datadog 🎉
ivoanjo added a commit to DataDog/dd-trace-rb that referenced this pull request Apr 12, 2021
When I initially worked on #1300 ("Warn on incompatible rollbar
version") my understanding of the issue on rollbar/rollbar-gem#1018 was
incomplete and I did not realize that old rollbar versions, beyond
breaking datadog profiler's CPU time instrumentation, could actually
break the customer's application.

One of our private beta customers mentioned he had seen both the
warning but also had seen a stack trace:

```
[1] ! Unable to load application: SystemStackError: stack level too deep
/usr/local/bundle/gems/rollbar-3.1.1/lib/rollbar/plugins/thread.rb:5:in `initialize_with_rollbar': stack level too deep (SystemStackError)
	from /usr/local/bundle/gems/ddtrace-0.45.0.feature.profiling.109457/lib/ddtrace/profiling/ext/cthread.rb:47:in `initialize'
	from /usr/local/bundle/gems/rollbar-3.1.1/lib/rollbar/plugins/thread.rb:6:in `initialize_with_rollbar'
	from /usr/local/bundle/gems/ddtrace-0.45.0.feature.profiling.109457/lib/ddtrace/profiling/ext/cthread.rb:47:in `initialize'
```

This led me to try to reproduce this issue. I discovered that with

```ruby
ENV['DD_PROFILING_ENABLED'] = 'true'
require 'ddtrace/profiling/preload'

require 'rollbar'
Rollbar.configure do |c|
  c.access_token = "nope"
end

Thread.new { }.join
```

I could trigger the issue, and that the current behavior was that
the warning from #1300 would be printed, but then the application
would proceed to fail.

Having a bit more experience with the codebase now, I realize that
the correct place to put this check is in the CPU extension
 #unsupported_reason method, which will ensure the extension is
not loaded at all if an incompatible version of rollbar is around.

The resulting behavior is that even with an old rollbar version,
profiler will happily load and work; it will just omit the CPU
time profiling, similarly to how it behaves on other platforms where
for different reasons we don't support CPU time profiling.
ivoanjo added a commit to DataDog/logging that referenced this pull request Jun 15, 2021
Directly modifying the `Thread` class leads to
`stack level too deep (SystemStackError)` if other gems have prepended
modules to `Thread`, see for instance:

* <rollbar/rollbar-gem#1018>
* <MiniProfiler/rack-mini-profiler#444>
* <https://github.com/DataDog/dd-trace-rb/blob/master/docs/GettingStarted.md#stack-level-too-deep>

This behavior can be triggered with the following example app
(NOTE: the issue is triggered only on Linux, as due to unrelated
reasons the ddtrace gem only adds the module to `Thread` on that OS):

```ruby
require 'bundler/inline'

gemfile do
  source 'http://rubygems.org'

  gem 'logging', '= 2.3.0', require: false
  gem 'ddtrace', '= 0.50.0', require: false
  gem 'google-protobuf'
end

require 'ddtrace'

Datadog.configure do |c|
  c.profiling.enabled = true
end

require 'logging'

Thread.new { }.join
```

By changing context inheritance to use a `prepend`, it becomes
compatible with all libraries that use this technique as well.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

5 participants