This is a bit of a corner case that occurred to me the other day, and I want to track it so that we don't forget about it.
TL;DR: The workaround for this is to reinstall ddtrace after changing libdatadog versions.
Current behaviour:
Because ddtrace compiles and links against libdatadog at installation time, it becomes "bound" to the libdatadog that was available at that time, and does not respect any changes that are made after that.
Consider this gems.rb file:
source 'https://rubygems.org'
gem 'google-protobuf'
gem 'ddtrace'
gem 'libdatadog', '= 0.7.0.1.0'
and a Ruby installation that has no libdatadog or ddtrace version installed:
root@c7311b47f69d:/app/libdatadog-detect-missing# gem uninstall libdatadog ddtrace
Gem 'libdatadog' is not installed
Gem 'ddtrace' is not installed
Now let's run bundle install:
root@c7311b47f69d:/app/libdatadog-detect-missing# bundle install
Fetching gem metadata from https://rubygems.org/...
Resolving dependencies...
Using bundler 2.3.6
Using debase-ruby_core_source 0.10.16
Using ffi 1.15.5
Using msgpack 1.5.6
Using google-protobuf 3.21.5 (x86_64-linux)
Using libddwaf 1.3.0.2.0 (x86_64-linux)
Fetching libdatadog 0.7.0.1.0 (x86_64-linux)
Installing libdatadog 0.7.0.1.0 (x86_64-linux)
Fetching ddtrace 1.3.0
Installing ddtrace 1.3.0 with native extensions
Bundle complete! 3 Gemfile dependencies, 8 gems now installed.
Use `bundle info [gemname]` to see where a bundled gem is installed.
At this point, ddtrace gets installed and links to libdatadog 0.7.0.1.0.
root@c7311b47f69d:/app/libdatadog-detect-missing# ldd /usr/local/bundle/gems/ddtrace-1.3.0/ext/ddtrace_profiling_native_extension/ddtrace_profiling_native_extension.2.7.3_x86_64-linux.so
linux-vdso.so.1 (0x00007fff51b8e000)
libruby.so.2.7 => /usr/local/lib/libruby.so.2.7 (0x00007f1942476000)
libddprof_ffi.so => /usr/local/bundle/gems/libdatadog-0.7.0.1.0-x86_64-linux/vendor/libdatadog-0.7.0/x86_64-linux/libdatadog-x86_64-unknown-linux-gnu/lib/pkgconfig/../../lib/libddprof_ffi.so (0x00007f19421c5000)
libm.so.6 => /lib/x86_64-linux-gnu/libm.so.6 (0x00007f1942038000)
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f1941e77000)
libz.so.1 => /lib/x86_64-linux-gnu/libz.so.1 (0x00007f1941c59000)
libpthread.so.0 => /lib/x86_64-linux-gnu/libpthread.so.0 (0x00007f1941c36000)
librt.so.1 => /lib/x86_64-linux-gnu/librt.so.1 (0x00007f1941c2c000)
libgmp.so.10 => /usr/lib/x86_64-linux-gnu/libgmp.so.10 (0x00007f1941ba9000)
libdl.so.2 => /lib/x86_64-linux-gnu/libdl.so.2 (0x00007f1941ba4000)
libcrypt.so.1 => /lib/x86_64-linux-gnu/libcrypt.so.1 (0x00007f1941b6a000)
/lib64/ld-linux-x86-64.so.2 (0x00007f1942833000)
libgcc_s.so.1 => /lib/x86_64-linux-gnu/libgcc_s.so.1 (0x00007f1941b50000)
But, let's say as a regular Ruby user, you pick a different version of libdatadog and run bundle install:
source 'https://rubygems.org'
gem 'google-protobuf'
gem 'ddtrace'
gem 'libdatadog', '= 0.7.0.1.1' # this was changed from 0.7.0.1.0 to 0.7.0.1.1
root@c7311b47f69d:/app/libdatadog-detect-missing# bundle install
Fetching gem metadata from https://rubygems.org/..
Resolving dependencies...
Using bundler 2.3.6
Using msgpack 1.5.6
Using ffi 1.15.5
Using google-protobuf 3.21.5 (x86_64-linux)
Using debase-ruby_core_source 0.10.16
Using libddwaf 1.3.0.2.0 (x86_64-linux)
Fetching libdatadog 0.7.0.1.1 (x86_64-linux) (was 0.7.0.1.0)
Installing libdatadog 0.7.0.1.1 (x86_64-linux) (was 0.7.0.1.0)
Using ddtrace 1.3.0
Bundle complete! 3 Gemfile dependencies, 8 gems now installed.
Use `bundle info [gemname]` to see where a bundled gem is installed.
Now asking for the version of libdatadog on the system will state that you're supposedly using 0.7.0.1.1:
root@c7311b47f69d:/app/libdatadog-detect-missing# bundle exec ruby -e "require 'libdatadog'; puts Libdatadog::VERSION"
0.7.0.1.1
but actually ddtrace is not using that version:
root@c7311b47f69d:/app/libdatadog-detect-missing# ldd /usr/local/bundle/gems/ddtrace-1.3.0/ext/ddtrace_profiling_native_extension/ddtrace_profiling_native_extension.2.7.3_x86_64-linux.so
linux-vdso.so.1 (0x00007ffc33deb000)
libruby.so.2.7 => /usr/local/lib/libruby.so.2.7 (0x00007f034211c000)
libddprof_ffi.so => /usr/local/bundle/gems/libdatadog-0.7.0.1.0-x86_64-linux/vendor/libdatadog-0.7.0/x86_64-linux/libdatadog-x86_64-unknown-linux-gnu/lib/pkgconfig/../../lib/libddprof_ffi.so (0x00007f0341e6b000)
libm.so.6 => /lib/x86_64-linux-gnu/libm.so.6 (0x00007f0341cde000)
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f0341b1d000)
libz.so.1 => /lib/x86_64-linux-gnu/libz.so.1 (0x00007f03418ff000)
libpthread.so.0 => /lib/x86_64-linux-gnu/libpthread.so.0 (0x00007f03418dc000)
librt.so.1 => /lib/x86_64-linux-gnu/librt.so.1 (0x00007f03418d2000)
libgmp.so.10 => /usr/lib/x86_64-linux-gnu/libgmp.so.10 (0x00007f034184f000)
libdl.so.2 => /lib/x86_64-linux-gnu/libdl.so.2 (0x00007f034184a000)
libcrypt.so.1 => /lib/x86_64-linux-gnu/libcrypt.so.1 (0x00007f0341810000)
/lib64/ld-linux-x86-64.so.2 (0x00007f03424d9000)
libgcc_s.so.1 => /lib/x86_64-linux-gnu/libgcc_s.so.1 (0x00007f03417f6000)
So you think you've upgraded/downgraded where in fact you haven't.
Further proof happens if you actually remove the old version:
root@c7311b47f69d:/app/libdatadog-detect-missing# gem uninstall libdatadog
Select gem to uninstall:
1. libdatadog-0.7.0.1.0-x86_64-linux
2. libdatadog-0.7.0.1.1-x86_64-linux
3. All versions
> 1
Successfully uninstalled libdatadog-0.7.0.1.0-x86_64-linux
root@c7311b47f69d:/app/libdatadog-detect-missing# DD_PROFILING_ENABLED=true bundle exec ddtracerb exec ruby -e "require 'libdatadog'; puts Libdatadog::VERSION"
W, [2022-08-25T09:27:43.103258 #337] WARN -- ddtrace: [ddtrace] Profiling was requested but is not supported, profiling disabled: There was an error loading the profiling native extension due to 'RuntimeError Failure to load ddtrace_profiling_native_extension.2.7.3_x86_64-linux due to libddprof_ffi.so: cannot open shared object file: No such file or directory' at '/usr/local/bundle/gems/ddtrace-1.3.0/lib/datadog/profiling/load_native_extension.rb:22:in `<top (required)>''
0.7.0.1.1
Bundler is still able to resolve a valid version BUT the profiler is broken since it's not actually using that version.
Since this only happens with libdatadog point releases, and we don't do those often, I doubt anyone's been bitten by this, but it's definitely a sharp edge that we should address.
Expected behaviour:
Ideally, the profiling native extension should automatically pick up and work with updated versions of libdatadog.
At minimum, it should a) detect that there's a mismatched libdatadog version; and b) provide a good error message stating what happened and how to fix it.
Steps to reproduce
(See above)
This is a bit of a corner case that occurred to me the other day, and I want to track it so that we don't forget about it.
TL;DR: The workaround for this is to reinstall
ddtraceafter changinglibdatadogversions.Current behaviour:
Because
ddtracecompiles and links againstlibdatadogat installation time, it becomes "bound" to thelibdatadogthat was available at that time, and does not respect any changes that are made after that.Consider this
gems.rbfile:and a Ruby installation that has no
libdatadogorddtraceversion installed:Now let's run
bundle install:At this point,
ddtracegets installed and links tolibdatadog0.7.0.1.0.But, let's say as a regular Ruby user, you pick a different version of libdatadog and run
bundle install:Now asking for the version of libdatadog on the system will state that you're supposedly using 0.7.0.1.1:
but actually
ddtraceis not using that version:So you think you've upgraded/downgraded where in fact you haven't.
Further proof happens if you actually remove the old version:
Bundler is still able to resolve a valid version BUT the profiler is broken since it's not actually using that version.
Since this only happens with libdatadog point releases, and we don't do those often, I doubt anyone's been bitten by this, but it's definitely a sharp edge that we should address.
Expected behaviour:
Ideally, the profiling native extension should automatically pick up and work with updated versions of libdatadog.
At minimum, it should a) detect that there's a mismatched libdatadog version; and b) provide a good error message stating what happened and how to fix it.
Steps to reproduce
(See above)