-
Notifications
You must be signed in to change notification settings - Fork 765
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
Add OpenTelemetry.Hosting #253
Conversation
@@ -52,7 +52,7 @@ private TracerShim(Trace.ITracer tracer) | |||
throw new ArgumentNullException(nameof(format)); | |||
} | |||
|
|||
if (carrier == default) |
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.
VS complained about this 🤷♂
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.
It's a bug (only in internal builds) being fixed.
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 ended up changing those lines to carrier == null (for now).
|
||
public Task StopAsync(CancellationToken cancellationToken) | ||
{ | ||
(this.collector as IDisposable)?.Dispose(); |
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.
Do this in dispose (implement IDisposable)
This still looks noisy: services.AddOpenTelemetry(telemetry =>
{
telemetry.AddCollector<RequestsCollector>(new RequestsCollectorOptions());
telemetry.AddCollector<DependenciesCollector>(new DependenciesCollectorOptions());
telemetry.SetTracer<Tracer, TraceConfig>();
telemetry.SetSpanExporter<ZipkinTraceExporter>(new ZipkinTraceExporterOptions { ServiceName = "my-service" });
}); Is there anyway to get it down to something like: services.AddOpenTelemetry(telemetry =>
{
telemetry.AddCollector<RequestsCollector>();
telemetry.AddCollector<DependenciesCollector>();
telemetry.SetTracer<Tracer, TraceConfig>();
telemetry.SetSpanExporter<ZipkinTraceExporter>(o => o.ServiceName = "my-service");
}); Going further, using extension methods for hide some of the wire up: services.AddOpenTelemetry(telemetry =>
{
telemetry.UseRequestsCollector();
telemetry.UseDependenciesCollector();
telemetry.SetTracer<Tracer, TraceConfig>(); // What is this?
telemetry.UseZipkin(o => o.ServiceName = "my-service");
}); |
It is different because an argument to services.AddOpenTelemetry(telemetry =>
{
telemetry.AddCollector<RequestsCollector>();
telemetry.AddCollector<DependenciesCollector>();
telemetry.SetTracer<Tracer, TraceConfig>();
telemetry.SetSpanExporter<ZipkinTraceExporter>(o => o.ServiceName = "my-service");
}); Types on all those constructors take the option objects e.g. RequestCollector.ctor(). Is there a way to make them optional so DI doesn't mind if there is no options object? services.AddOpenTelemetry(telemetry =>
{
telemetry.UseRequestsCollector();
telemetry.UseDependenciesCollector();
telemetry.SetTracer<Tracer, TraceConfig>(); // What is this?
telemetry.UseZipkin(o => o.ServiceName = "my-service");
}); Currently there is zero DI integration throughout the rest of the projects. It is POCO objects with values set via constructors. Extension methods are possible, just means making a choice about:
I'm guessing there is a design decision at the moment to avoid a dependency on |
First OT needs to decide if they want first-class non-DI tracer setup. Making DI the ultimate composition root would require classes to be designed in a very particular way making non-DI setup prohibitively hard (hello logging). You can imagine if they have a nice fist class API OpenTelemetry NO DIvar tracerBuilder = new TracerBuilder();
tracerBuilder.AddRequestCollector(o=> ...);
tracerBuilder.AddDependencyCollector(o=> ...);
tracerBuilder.AddZipkinExporter();
var tracer = tracerBuilder.Build();
await tracer.StartAsync(); // Starts exporters and collectors and whatever else needs explicit starting
Console.WriteLine("Yay");
await tracer.StopAsync(); OpenTelemetry + DIservices.AddOpenTelemetry(tracerBuilder=>
{
tracerBuilder.AddRequestCollector(o=> ...);
tracerBuilder.AddDependencyCollector(o=> ...);
tracerBuilder.AddZipkinExporter();
});
// tracerBuilder.Build(), StartAsync/StopAsync is handled for you |
/// <inheritdoc /> | ||
public override Task<ExportResult> ExportAsync(IEnumerable<Span> batch, CancellationToken cancellationToken) | ||
{ | ||
return Task.FromResult(ExportResult.Success); |
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.
BTW, I know we already have this problem in another place, would you mind caching task.fromresult - this is new Task every time
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.
It should be ValueTask 😄
if you can think of how to change TraceConfig to better suit DI scenarios - go for it. |
Great idea. OTel configuration is too complicated already and it's going to be even worse with #239. We need something to help configure it without DI too. It is nice to make DI work on top of the same configuration sugar. [Update] and it doesn't have to happen right now |
I like #253 (comment) I think the current approach of using DI to build types, but not integrating with DI, will always result in a bad user experience. The What I think you should end up with:
|
@JamesNK Thanks! I'll work on this in the next few days. |
* Rename AzureMonitor Extensions * Add CHANGELOG
Fixes #241
This PR adds a
OpenTelemetry.Hosting
package for improving integration between OpenTelemetry and DI (could also be namedOpenTelemetry.DependencyInjection
)I've kept the DI dependency isolated to this package. The user experience could be improved with strongly typed registration methods, e.g.
AddZipkin(options)
, but that would require either additional projects depending on DI, or more packages for DI integration, e.g.OpenTelemetry.Exporter.Zipkin.DependencyInjection
.To start collectors I have an
IHostedService
registered for each. It will automatically start and stop collectors, avoiding the current hack of users manually resolving services somewhere to ensure they are created. Generic host experts: It feels like I'm abusing what anIHostedService
is for to inject start and stop logic via DI. Let me know if there is a better way of doing this. @davidfowl @glennc @pakrymAfter:
Before: