Skip to content

Conversation

@grantbdev
Copy link
Contributor

Overview

Add redis instrumentation adapter. This is the first database client adapter, so I made it conform to those conventions as best I could understand. I was particularly uncertain on what the span names should be, but based on the spec guidelines I decided to go with the command name for single command requests and "pipeline" for a pipeline request. Let me know if there is anything that should be changed or added.

A lot of the formatting code is copied from dd-trace-rb. It was unclear to me whether in OpenTelemetry there are length limits on span attributes, so I kept the truncation behavior from dd-trace-rb let me know if the truncation limit should be changed or removed entirely.

Related

Copy link
Member

@mwear mwear left a comment

Choose a reason for hiding this comment

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

This is off to a good start. I have a few questions based on my first pass through and may have more when I have a chance to look more closely.

Comment on lines 49 to 53
# Override implementation (subclass) to determine per-connection
# span reporting rules.
def disable_span_reporting?(*_args)
false
end
Copy link
Member

Choose a reason for hiding this comment

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

I don't see how we have per-connection span reporting. Either this module is prepended to the redis client, or the no-op version is. We either get all spans, or no spans. We already have the ability to do this by installing the instrumentation (with c.use), or not installing the instrumentation. Correct me if I'm mistaken on this point.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

@mwear "per-connection" may be misleading, but the arguments provided to this method would allow someone to create their own patch that would could disable spans for certain methods, keys, values, etc. That may not be a use case that needs to be supported and could be simplified/removed, but I kept it for parity with the functionality of the HTTP client adapters so far.

Copy link
Member

Choose a reason for hiding this comment

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

I would err on the side of YAGNI at this stage in the project unless compelling use cases become apparent. My preference would be to remove it for now. That would also apply to the http client instrumentation

Copy link
Contributor Author

Choose a reason for hiding this comment

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

@mwear Should the ability to provide a custom patch/middleware for adapters still exist? It was only used in tests/examples for overriding this method, but I'm not sure if there is another use case or if it is desired for dependency injection.

@grantbdev
Copy link
Contributor Author

@mwear PR updated. I ported the tests of the ported utils. I would like more input on what more of the adapter should be tested.

@grantbdev
Copy link
Contributor Author

PR updated to add test assertions on the span names so it's easier for reviewers to see what it looks like.

Comment on lines +47 to +59
def client_attributes
host = options[:host]
port = options[:port]

{
'component' => 'redis',
'db.type' => 'redis',
'db.instance' => options[:db].to_s,
'db.url' => "redis://#{host}:#{port}",
'net.peer.name' => host,
'net.peer.port' => port
}
end
Copy link
Member

Choose a reason for hiding this comment

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

It looks like db is changeable at runtime, but is everything else going to be static data once the client is initialized? If so, can we memoize and freeze this data instead of making it each time? The db.name can be merged in with db.statement in call.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

is everything else going to be static data once the client is initialized?

@mwear I don't think so. https://github.com/redis/redis-rb#sentinel-support and https://github.com/redis/redis-rb#cluster-support seem to indicate to me that the port and even host can be different between requests. Using the example code I was able to see different hosts/ports for the spans using Sentinel. Unfortunately it does not appear that fakeredis which we are using for the tests supports Sentinel or clusters.

The db.name can be merged in with db.statement in call.

Can you explain this more?

Copy link
Member

Choose a reason for hiding this comment

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

I was just saying that if the config was static aside from db.name we could have a frozen hash and merge('db.name' => ..., 'db.statement') with it. It's a moot point given that config will change at runtime. Thanks for your research!

@grantbdev
Copy link
Contributor Author

@mwear Feedback addressed.

Something to consider: ddtrace's #trace automatically catches errors and sets the span status. I've started in-lining that logic, but it's something that may be good to add to #in_span.

@mwear
Copy link
Member

mwear commented Feb 12, 2020

We might want to change in_span automatically rescue, record the error, and reraise. I'll open an issue about this and we can discuss it at the SIG.

@mwear
Copy link
Member

mwear commented Feb 12, 2020

I'm not totally sure about the inlining, but everything else looks good to me. I created an issue with some questions / proposals around error handling: #181. I think we should discuss this at the SIG and determine what to do about the inlining there. Right now, to replicate what is happening in dd-trace would have to inline exception handling for every Tracer#in_span call, which is definitely not ideal.

Copy link
Member

@mwear mwear left a comment

Choose a reason for hiding this comment

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

I'm tentatively approving this pending the outcome of our discussion about recording errors to see if the inlining should stay or go. It's possible there will be some minor changes depending on what we decide, but otherwise, everything looks great!

module Patches
# Module to prepend to Redis::Client for instrumentation
module Client
def call(*args, &block)
Copy link
Contributor

Choose a reason for hiding this comment

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

The gem has a couple of other call_* methods: call_pipelined (note the difference from call_pipeline) and call_loop. Have you considered patching process instead? The upside is that it is a bottleneck method that is called on all call* paths. The downside is that errors are sometimes raised outside its scope, so they're harder to intercept.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

@fbogsany I did not consider those because dd-trace-rb does not patch those methods.

Copy link
Contributor

Choose a reason for hiding this comment

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

Copy link
Member

Choose a reason for hiding this comment

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

I made an issue to track improvements: #197.

@grantbdev
Copy link
Contributor Author

@mwear This PR (and my other adapter PRs) are rebased and the exception handling has been simplified.

@mwear
Copy link
Member

mwear commented Feb 27, 2020

Last call for comments on this. It'd be nice to merge this tomorrow after the SIG meeting.

Add `redis` instrumentation adapter
based on the adapter for `rest-client`
and the `dd-trace-rb` code for `redis`, including its utilites.

The `fakeredis` gem is used in the tests to have a fake server.

The Docker container for the example includes a real Redis server.

Related to #67
@mwear mwear merged commit ba8b7b6 into open-telemetry:master Feb 28, 2020
@grantbdev grantbdev deleted the gb/feature--redis-instrumentation--67 branch February 28, 2020 19:08
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.

3 participants