Issue #21923 has been reported by jacobcarlborg (Jacob Carlborg). ---------------------------------------- Feature #21923: DTrace USDT probe Ruby method arguments and return value https://bugs.ruby-lang.org/issues/21923 * Author: jacobcarlborg (Jacob Carlborg) * Status: Open ---------------------------------------- I'm interested in improving the DTrace USDT probes in Ruby. I would like to expose the Ruby method arguments and return value to the DTrace probes `(c)method-entry` and `(c)method-return`. This would be done by adding a fifth argument to the DTrace probes. For `method-entry` this would be the Ruby arguments the Ruby method is called with and for `method-return` it would be the Ruby return value the Ruby method returned. My idea is to serialize the arguments as a JSON array and pass that as a C string, containing the JSON data, to the USDT probes. On the DTrace side, there's a `json` function available that can be used to extract parts of the JSON structure using a simple query string, example: `json(copyinstr(arg4), "success.foo.bar[1].baz")`. Because the serialization can fail, the top level JSON member would be `success` or `error` indicating if the serialization was successful or not. Using JSON to pass data to a DTrace USDT probe has precedence in the form of a Rust crate [1], created by one of the original DTrace authors, that uses the same approach. I have a proof of concept implementing this. I would like to get some feedback on how to best implement this. I think the main challenge is how to implement this without any side effects. Ruby already has support for serializing to JSON, but that is implemented in a separate gem, using a C extension. The challenges I see are: * There shouldn't be any side effects when enabling DTrace probes, therefore directly using the gem is not a good alternative. It needs to load a dynamic library and new constants will become available to the Ruby code, if this gem is used. * The JSON serialization for DTrace needs to live in the Ruby VM and not in a separate gem. The question is then: should the JSON serialization for the gem and the DTrace probes be shared? Alternatively there could be an implementation of JSON serialization, for the gem, and a DTrace probe argument serialization, that happens to use JSON, but would be an implementation detail. * If the JSON serialization should be shared between DTrace probes and the gem, is there a mechanism to share code between the Ruby VM and a gem without publicly exposing it, i.e. to C extensions? Or would there need to be an official JSON API that other C extensions could use? * The current JSON implementation relies on exceptions. For DTrace, it would be better not to rely on exceptions. But I guess it would be possible to catch all exceptions. * The current JSON implementation will, except for the `JSON` class, expose some additional constants which should not happen when using DTrace. This will introduce side effects. This should be possible to handle by slightly modifying the implementation. * The current JSON serialization supports customizing the serialization by implementing the `to_json`/`as_json` methods. If serializing DTrace arguments with support for the `to_json`/`as_json` methods, the advantage is that this is already implemented by some third-party libraries. The disadvantage is that it could cause side effects. * When DTrace probes are enabled and serializing the DTrace probe arguments and some Ruby methods are called, it would be best if those weren't traced. Can a global variable be used to check if the Ruby VM already is currently serializing DTrace probe arguments? Or is an atomic or thread-local variable necessary? Or is there a better alternative to do this? [1] https://github.com/oxidecomputer/usdt -- https://bugs.ruby-lang.org/