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

Convert mysql2 integration to Datadog::Instrumentation API #1657

Draft
wants to merge 1 commit into
base: master
Choose a base branch
from

Conversation

delner
Copy link
Contributor

@delner delner commented Aug 20, 2021

This pull request converts the Mysql2 integration over to the datadog-instrumentation API. The changes to this library are entirely internal and do not affect user implementation, or trace data.

Work in progress prototype: DO NOT MERGE!

This is intended to be a proof-of-concept in the development of the new instrumentation API. Some things we may want to take into consideration before merging this:

  1. Is the instrumentation API sufficient for the needs of this integration? Does the API need to be altered in any way?
  2. Should we add a layer within ddtrace that makes the implementation of the API a little more friendly/specific to tracing? (We may only understand the usage patterns better after we convert more integrations and observe the overlap.)
  3. Does this PR need to be broken into smaller pieces? (Especially if we add more code related to the above point?)
  4. Is there any significant performance impact?

@delner delner added integrations Involves tracing integrations do-not-merge/WIP Not ready for merge dev/refactor Involves refactoring existing components labels Aug 20, 2021
@delner delner self-assigned this Aug 20, 2021
@@ -61,6 +61,8 @@ end
# @see https://github.com/DataDog/dogstatsd-ruby/issues/182
gem 'dogstatsd-ruby', '>= 3.3.0', '!= 5.0.0', '!= 5.0.1', '!= 5.1.0'
gem 'opentracing', '>= 0.4.1'
# TODO: Promote this to ddtrace.gemspec. (Or contrib package? Only used by contrib.)
Copy link
Contributor

Choose a reason for hiding this comment

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

Should we? In my opinion this kind of "small base building block" functionality could live in a separate package without much effort. In my mind it would quickly reach stable status and then receive mostly bug fixes, which users can receive effortlessly with semver.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

In my opinion this kind of "small base building block" functionality could live in a separate package without much effort.

Can you clarify what you mean? In order to use this gem we need to add it to the gemspec, otherwise user applications won't import it and the integration won't work, right?

@lloeki
Copy link
Contributor

lloeki commented Aug 30, 2021

This looks nice to me as a first validation step. It will get better with the tracer instrumentation DSL we talked about though, which we should probably wait for before merging so as not to have yet another way to do things, since it's not time sensitive.

Copy link
Member

@ivoanjo ivoanjo left a comment

Choose a reason for hiding this comment

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

Left a few notes :)

Comment on lines -30 to +37
Contrib::Analytics.set_sample_rate(span, analytics_sample_rate) if analytics_enabled?
if Datadog.configuration[:mysql2][:analytics_enabled]
Contrib::Analytics.set_sample_rate(span, Datadog.configuration[:mysql2][:analytics_sample_rate])
end
Copy link
Member

Choose a reason for hiding this comment

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

Not sure if it's "in scope", but have you considered taking this opportunity to move the configuration to be supplied as part of the env, rather than being global state that is accessed directly?

This is similar to how above we use datadog_pin.tracer rather than Datadog.tracer to get the correct tracer instance.

Comment on lines +48 to +49
def get_client(env)
return unless env[:self].instance_of?(::Mysql2::Client)
Copy link
Member

Choose a reason for hiding this comment

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

Should this be is_a?, rather than instance_of? to avoid coupling on the exact class, allowing some flexibility if we get a subclass? (see also https://stackoverflow.com/questions/3893278/ruby-kind-of-vs-instance-of-vs-is-a )

::Mysql2::Client.include(Instrumentation)
# ::Mysql2::Client.include(Instrumentation::Client)

Datadog::Instrumentation::Hook['Mysql2::Client#query'].add do
Copy link
Member

Choose a reason for hiding this comment

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

Would it make sense to use the class name directly here? E.g. Hook[Mysql2::Client, '#query']?

Copy link
Contributor

Choose a reason for hiding this comment

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

This would cause an exception if the constant does not exist (e.g the gem is not in the bundle). Hook handles that internally and add (+install IIRC) becomes NOOP.

Copy link
Member

Choose a reason for hiding this comment

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

Yes...ish. The current way that dd-trace-rb does it is that there's a separate check for that in integration.rb:

Gem.loaded_specs['mysql2'] && Gem.loaded_specs['mysql2'].version

which is why the old code referenced the constant directly.

Using it as a string is good if we could get rid of that separate file, otherwise, we already get the validation for free.

stack.call(trace_env)
end
end
end.install
Copy link
Member

Choose a reason for hiding this comment

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

Is it common to use Hook without performing install immediately afterwards? E.g. would it make sense to make this the default behavior?

Copy link
Contributor

Choose a reason for hiding this comment

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

It has been the case in the past, adding multiple hooks on the same hookpoint in different locations, then installing in another part of the lifecycle.

Copy link
Contributor

@lloeki lloeki Sep 2, 2021

Choose a reason for hiding this comment

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

I think this would be largely solved with the upcoming tracer instrumentation API (being drafted by David), which sits atop of Hook.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
dev/refactor Involves refactoring existing components do-not-merge/WIP Not ready for merge integrations Involves tracing integrations
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants