-
Notifications
You must be signed in to change notification settings - Fork 309
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
[Instrumentation.StackExchangeRedis] Connection registration changes #1139
[Instrumentation.StackExchangeRedis] Connection registration changes #1139
Conversation
Codecov Report
Additional details and impacted files@@ Coverage Diff @@
## main #1139 +/- ##
==========================================
+ Coverage 72.13% 72.22% +0.08%
==========================================
Files 230 231 +1
Lines 8448 8474 +26
==========================================
+ Hits 6094 6120 +26
Misses 2354 2354
|
src/OpenTelemetry.Instrumentation.StackExchangeRedis/IConnectionRegistry.cs
Outdated
Show resolved
Hide resolved
src/OpenTelemetry.Instrumentation.StackExchangeRedis/TracerProviderBuilderExtensions.cs
Outdated
Show resolved
Hide resolved
There is no package owner for StackExchangeRedis. |
Co-authored-by: Robert Pająk <pellared@hotmail.com>
src/OpenTelemetry.Instrumentation.StackExchangeRedis/TracerProviderBuilderExtensions.cs
Outdated
Show resolved
Hide resolved
src/OpenTelemetry.Instrumentation.StackExchangeRedis/TracerProviderBuilderExtensions.cs
Outdated
Show resolved
Hide resolved
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The main question is why is necessary to return an instrumenter
, since it still has usability problems. Ideally one should be able to just use an extension method on the connection, something like connection.WithOpenTelemetryInstrumentation()
.
// Configure exporter to export traces to Zipkin | ||
using var tracerProvider = Sdk.CreateTracerProviderBuilder() | ||
.AddConsoleExporter() | ||
.AddRedisInstrumentation(connection, options => | ||
.AddRedisInstrumentation(out var instrumenter, options => |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Returning an object that is needed to instrument the connection is still an usability problem. Is that really required?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this is a minimal solution to the problem linked in description. Currently, some kind of reference to an instrumentation instance is required to instrument a connection.
{ | ||
// changing flush interval from 10s to 5s | ||
options.FlushInterval = TimeSpan.FromSeconds(5); | ||
}) | ||
.Build(); | ||
|
||
// Connect to the Redis server. The default port 6379 will be used. | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: remove blank line
src/OpenTelemetry.Instrumentation.StackExchangeRedis/CHANGELOG.md
Outdated
Show resolved
Hide resolved
Co-authored-by: Paulo Janotti <pjanotti@splunk.com>
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hey it looks like we already have IServiceProvider support in OpenTelemetry.Instrumentation.StackExchangeRedis. Couldn't you achieve essentially what this PR is seeking to enable by using IServiceCollection
\ IServiceProvider
?
Manual creation
using var provider = Sdk.CreateTracerProviderBuilder()
.ConfigureServices(services => services.AddSingleton<IConnectionMultiplexer>(sp => RedisHelper.InitializeConnection(sp)))
.AddRedisInstrumentation()
.Build();
Hosting creation
appBuilder.Services.AddSingleton<IConnectionMultiplexer>(sp => RedisHelper.InitializeConnection(sp));
appBuilder.Services.AddOpenTelemetry()
.WithTracing(builder => builder.AddRedisInstrumentation());
@CodeBlanch |
@lachmatt It is really up to the app. In that snippet I sent above I'm registering a factory for the connection into the service collection. So the connection won't actually be started until that factory is executed (when it is first requested from the |
@CodeBlanch let me check if I understand your suggestion. You propose adding a static method, In retrospect, it is not a good practice to pass instances created using the types from the targeted library in the extension methods for the OTel builders, see open-telemetry/opentelemetry-dotnet#1900 and open-telemetry/opentelemetry-dotnet#4347 (comment) A step further will be to mark the |
Not exactly. What I'm saying is this code is already hooked up to check the Let's take the example from the README showing the new API in use: using var tracerProvider = Sdk.CreateTracerProviderBuilder()
.AddRedisInstrumentation(out var connectionInstrumenter)
.AddConsoleExporter()
.Build();
// Connect to the server.
using var connection = ConnectionMultiplexer.Connect("localhost:6379");
connectionInstrumenter.Instrument(connection); Today you could do this to accomplish the same: using var tracerProvider = Sdk.CreateTracerProviderBuilder()
.ConfigureServices(services => services.AddSingleton(sp => ConnectionMultiplexer.Connect("localhost:6379")))
.AddRedisInstrumentation()
.AddConsoleExporter()
.Build(); A more useful real-world example would probably be more like... appBuilder.Services.AddSingleton(sp => {
var myRedisOptions = sp.GetRequiredService<IOptions<RedisOptions>>().Value;
return ConnectionMultiplexer.Connect(myRedisOptions.Endpoint);
});
appBuilder.Services.AddOpenTelemetry().WithTracing(builder => builder
.AddRedisInstrumentation()
.AddConsoleExporter()); |
Thanks, now I see what you are saying. This should satisfy many (most?) use cases since typical server applications are expected to be using an From my perspective, it still forces the call to |
Yeah, for me this will not work. I have several applications where I use a custom-made code to create different redis connections and we don't use a service provider. The major reason for this is because of many applications we migrated from very old dotnet versions. I would like to enable the instrumentation statically anywhere in my code and I really think this would be the best case scenario and work for all use cases... |
So with OTel .NET SDK there is always an I think if we want to add an extension point that is fine, but we should use the DI API(s) because they are more standard. I took a stab at what it might look like: https://github.com/open-telemetry/opentelemetry-dotnet-contrib/compare/main...CodeBlanch:stackexchangeredis-creation-api?expand=1 Using that design we can accomplish the example on this PR as... StackExchangeRedisInstrumentation? redisInstrumentation = null;
using var tracerProvider = Sdk.CreateTracerProviderBuilder()
.AddRedisInstrumentation()
.AddConsoleExporter()
.ConfigureServices(services => services.AddRedisInstrumentationCreatedAction(i => redisInstrumentation = i))
.Build();
// Connect to the server.
using var connection = ConnectionMultiplexer.Connect("localhost:6379");
redisInstrumentation?.AddConnection(connection); Now I know what you are thinking right now. That may seem more complex than what you already have on this PR. Maybe! But I'm not really that concerned with your "old" style of doing things (sorry 🤣). What I want to make sure is that new styles work really well. Old styles should also work, but can be ugly. What the new design allows us to do... builder.Services.AddOpenTelemetry();
builder.Services.AddMyRedisLibrary(); With some implementation like... public static class RedisExtensions
{
public static IServiceCollection AddMyRedisLibrary(this IServiceCollection services)
{
services.AddSingleton<IRedisConnectionManager, RedisConnectionManager>();
services.AddRedisInstrumentationCreatedAction((sp, name, instrumentation) =>
{
var redisConnectionManager = (RedisConnectionManager)sp.GetRequiredService<IRedisConnectionManager>();
redisConnectionManager.AddInstrumentation(name, instrumentation);
});
services.ConfigureOpenTelemetryTracerProvider(
(sp, builder) => builder.AddRedisInstrumentation());
return services;
}
}
public interface IRedisConnectionManager
{
IConnectionMultiplexer GetConnection(string name);
}
internal sealed class RedisConnectionManager : IRedisConnectionManager
{
private readonly Dictionary<string, StackExchangeRedisInstrumentation> instrumentation = new();
public IConnectionMultiplexer GetConnection(string name)
{
IConnectionMultiplexer connection = this.FindOrCreateConnectionForName(name);
if (this.instrumentation.TryGetValue(name, out var instrumentation))
{
instrumentation.AddConnection(connection);
}
else if (this.instrumentation.TryGetValue(string.Empty, out instrumentation))
{
instrumentation.AddConnection(connection);
}
return connection;
}
public void AddInstrumentation(
string name,
StackExchangeRedisInstrumentation instrumentation)
{
this.instrumentation.Add(name, instrumentation);
}
private IConnectionMultiplexer FindOrCreateConnectionForName(string name)
{
throw new NotImplementedException();
}
} Maybe that example is more compelling? Let me know what you think 😄 |
@CodeBlanch I don't think it is complex at all. If can make it static I think this should be enough..
I'm helping a team to instrument their applications, which happened to be kind old so they couldn't use the |
@CodeBlanch |
This PR was marked stale due to lack of activity. It will be closed in 7 days. |
Closed as inactive. Feel free to reopen if this PR is still being worked on. |
@CodeBlanch any update? |
Addresses open-telemetry/opentelemetry-dotnet#1900 (comment)
Changes
Add an ability to track connections created after tracer is initialized.
CHANGELOG.md
updated for non-trivial changes* [ ] Design discussion issue #* [ ] Changes in public API reviewed