Skip to content

Commit a9a46c6

Browse files
committed
Move our AgentBuilder to IOpenTelemetryBuilder
This is not yet released see open-telemetry/opentelemetry-dotnet#5265 for more background. For now we include a temporary copy with hacks to call internal bits. This allows AgentBuilder to be a native opentelemetry builder and we'd inherit all extension methods from the OpenTelemetry community
1 parent 37ad73e commit a9a46c6

File tree

16 files changed

+393
-378
lines changed

16 files changed

+393
-378
lines changed

Elastic.OpenTelemetry.sln.DotSettings

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -585,4 +585,6 @@ See the LICENSE file in the project root for more information</s:String>
585585
<s:Boolean x:Key="/Default/UserDictionary/Words/=Faas/@EntryIndexedValue">True</s:Boolean>
586586
<s:Boolean x:Key="/Default/UserDictionary/Words/=Instrumentations/@EntryIndexedValue">True</s:Boolean>
587587
<s:Boolean x:Key="/Default/UserDictionary/Words/=Mountinfo/@EntryIndexedValue">True</s:Boolean>
588-
<s:Boolean x:Key="/Default/UserDictionary/Words/=Nonsampled/@EntryIndexedValue">True</s:Boolean></wpf:ResourceDictionary>
588+
<s:Boolean x:Key="/Default/UserDictionary/Words/=Nonsampled/@EntryIndexedValue">True</s:Boolean>
589+
<s:Boolean x:Key="/Default/UserDictionary/Words/=otel/@EntryIndexedValue">True</s:Boolean>
590+
<s:Boolean x:Key="/Default/UserDictionary/Words/=Otlp/@EntryIndexedValue">True</s:Boolean></wpf:ResourceDictionary>

examples/Example.Elastic.OpenTelemetry.AspNetCore/Program.cs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,9 @@
99
// Add services to the container.
1010
builder.Services
1111
.AddHttpClient()
12-
.AddElasticOpenTelemetryForAspNetCore(HomeController.ActivitySourceName)
12+
.AddElasticOpenTelemetryForAspNetCore(HomeController.ActivitySourceName);
13+
14+
builder.Services
1315
.AddControllersWithViews();
1416

1517
var app = builder.Build();

examples/Example.Elastic.OpenTelemetry.Worker/Program.cs

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,27 @@
11
// Licensed to Elasticsearch B.V under one or more agreements.
22
// Elasticsearch B.V licenses this file to you under the Apache 2.0 License.
33
// See the LICENSE file in the project root for more information
4+
5+
using Elastic.OpenTelemetry;
46
using Example.Elastic.OpenTelemetry.Worker;
7+
using OpenTelemetry;
8+
using OpenTelemetry.Metrics;
9+
using OpenTelemetry.Resources;
10+
using OpenTelemetry.Trace;
511

612
var builder = Host.CreateApplicationBuilder(args);
713

8-
builder.Services.AddElasticOpenTelemetry(Worker.ActivitySourceName, "CustomMeter");
14+
/*
15+
* appBuilder.Services.AddOpenTelemetry()
16+
.ConfigureResource(builder => builder.AddService(serviceName: "MyService"))
17+
.WithTracing(builder => builder.AddConsoleExporter())
18+
.WithMetrics(builder => builder.AddConsoleExporter());
19+
*/
20+
21+
builder.Services.AddElasticOpenTelemetry(Worker.ActivitySourceName, "CustomMeter")
22+
.ConfigureResource(r => r.AddService(serviceName: "MyService"))
23+
.WithTracing(t => t.AddConsoleExporter())
24+
.WithMetrics(m => m.AddConsoleExporter());
925

1026
builder.Services.AddHostedService<Worker>();
1127

examples/Example.Elastic.OpenTelemetry/Usage.cs

Lines changed: 27 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -23,34 +23,36 @@ public static async Task BasicBuilderUsageAsync()
2323
// Build an agent by creating and using an agent builder, adding a single source (for traces and metrics) defined in this sample application.
2424
await using var agent = new AgentBuilder(ActivitySourceName).Build();
2525

26-
// Build an agent by creating and using an agent builder, adding a single source for the app just to the tracer.
27-
//using var agent = new AgentBuilder().AddTracerSource(ActivitySourceName).Build();
28-
2926
// This example adds the application activity source and fully customises the resource
30-
//using var agent = new AgentBuilder(ActivitySourceName)
31-
// .ConfigureTracer(b => b.Clear().AddService("CustomServiceName", serviceVersion: "2.2.2"))
32-
// .Build();
33-
34-
//using var agent = new AgentBuilder()
35-
// .AddTracerSource(ActivitySourceName) // Intentionally duplicating to test the effect
36-
// .ConfigureTracer(tpb => tpb
37-
// .ConfigureResource(rb => rb.AddService("TracerProviderBuilder", "3.3.3"))
38-
// .AddRedisInstrumentation() // This can currently only be achieved using this overload or adding Elastic processors to the TPB (as below)
39-
// .AddSource(ActivitySourceName)
40-
// .AddConsoleExporter())
41-
// .Build();
27+
await using var agent3 = new AgentBuilder(ActivitySourceName)
28+
.WithTracing(b => b.ConfigureResource(r => r.Clear().AddService("CustomServiceName", serviceVersion: "2.2.2")))
29+
.Build();
30+
31+
await using var agent4 = new AgentBuilder()
32+
.WithTracing(t => t
33+
.ConfigureResource(rb => rb.AddService("TracerProviderBuilder", "3.3.3"))
34+
.AddRedisInstrumentation() // This can currently only be achieved using this overload or adding Elastic processors to the TPB (as below)
35+
.AddSource(ActivitySourceName)
36+
.AddConsoleExporter()
37+
)
38+
.WithTracing(tpb => tpb
39+
.ConfigureResource(rb => rb.AddService("TracerProviderBuilder", "3.3.3"))
40+
.AddRedisInstrumentation() // This can currently only be achieved using this overload or adding Elastic processors to the TPB (as below)
41+
.AddSource(ActivitySourceName)
42+
.AddConsoleExporter())
43+
.Build();
4244

4345
//This is the most flexible approach for a consumer as they can include our processor(s) and exporter(s)
44-
//using var tracerProvider = Sdk.CreateTracerProviderBuilder()
45-
// .AddSource(ActivitySourceName)
46-
// .ConfigureResource(resource =>
47-
// resource.AddService(
48-
// serviceName: "OtelSdkApp",
49-
// serviceVersion: "1.0.0"))
50-
// .AddConsoleExporter()
51-
// .AddElasticProcessors()
52-
// .AddElasticOtlpExporter()
53-
// .Build();
46+
using var tracerProvider = Sdk.CreateTracerProviderBuilder()
47+
.AddSource(ActivitySourceName)
48+
.ConfigureResource(resource =>
49+
resource.AddService(
50+
serviceName: "OtelSdkApp",
51+
serviceVersion: "1.0.0"))
52+
.AddConsoleExporter()
53+
.AddElasticProcessors()
54+
//.AddElasticOtlpExporter()
55+
.Build();
5456

5557
await DoStuffAsync();
5658

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,20 @@
11
// Licensed to Elasticsearch B.V under one or more agreements.
22
// Elasticsearch B.V licenses this file to you under the Apache 2.0 License.
33
// See the LICENSE file in the project root for more information
4+
5+
using OpenTelemetry;
46
using OpenTelemetry.Trace;
57

68
namespace Elastic.OpenTelemetry.AspNetCore;
79

810
/// <summary>
9-
///
11+
///
1012
/// </summary>
1113
public static class AgentBuilderExtensions
1214
{
1315
/// <summary>
14-
///
16+
///
1517
/// </summary>
1618
/// <param name="agentBuilder"></param>
17-
public static AgentBuilder AddAspNetCore(this AgentBuilder agentBuilder) => agentBuilder.ConfigureTracer(tpb => tpb.AddAspNetCoreInstrumentation());
19+
public static IOpenTelemetryBuilder AddAspNetCore(this AgentBuilder agentBuilder) => agentBuilder.WithTracing(tpb => tpb.AddAspNetCoreInstrumentation());
1820
}

src/Elastic.OpenTelemetry.AspNetCore/ServiceCollectionExtensions.cs

Lines changed: 5 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
// See the LICENSE file in the project root for more information
44
using Elastic.OpenTelemetry;
55
using Elastic.OpenTelemetry.AspNetCore;
6+
using OpenTelemetry;
67
using OpenTelemetry.Trace;
78

89
namespace Microsoft.Extensions.DependencyInjection;
@@ -17,24 +18,15 @@ public static class ServiceCollectionExtensions
1718
/// </summary>
1819
/// <param name="serviceCollection">TODO</param>
1920
/// <returns>TODO</returns>
20-
public static IServiceCollection AddElasticOpenTelemetryForAspNetCore(this IServiceCollection serviceCollection) =>
21-
new AgentBuilder().AddAspNetCore().Register(serviceCollection);
21+
public static IOpenTelemetryBuilder AddElasticOpenTelemetryForAspNetCore(this IServiceCollection serviceCollection) =>
22+
new AgentBuilder(services: serviceCollection).AddAspNetCore();
2223

2324
/// <summary>
2425
/// TODO
2526
/// </summary>
2627
/// <param name="serviceCollection"></param>
2728
/// <param name="activitySourceNames"></param>
2829
/// <returns></returns>
29-
public static IServiceCollection AddElasticOpenTelemetryForAspNetCore(this IServiceCollection serviceCollection, params string[] activitySourceNames) =>
30-
new AgentBuilder(activitySourceNames).AddAspNetCore().Register(serviceCollection);
31-
32-
/// <summary>
33-
/// TODO
34-
/// </summary>
35-
/// <param name="serviceCollection"></param>
36-
/// <param name="configureTracerProvider"></param>
37-
/// <returns></returns>
38-
public static IServiceCollection AddElasticOpenTelemetryForAspNetCore(this IServiceCollection serviceCollection, Action<TracerProviderBuilder> configureTracerProvider) =>
39-
new AgentBuilder().AddAspNetCore().ConfigureTracer(configureTracerProvider).Register(serviceCollection);
30+
public static IOpenTelemetryBuilder AddElasticOpenTelemetryForAspNetCore(this IServiceCollection serviceCollection, params string[] activitySourceNames) =>
31+
new AgentBuilder(null, serviceCollection, activitySourceNames).AddAspNetCore();
4032
}
Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
// Licensed to Elasticsearch B.V under one or more agreements.
2+
// Elasticsearch B.V licenses this file to you under the Apache 2.0 License.
3+
// See the LICENSE file in the project root for more information
4+
5+
using Elastic.OpenTelemetry.Diagnostics;
6+
using Elastic.OpenTelemetry.Diagnostics.Logging;
7+
using Microsoft.Extensions.DependencyInjection;
8+
using Microsoft.Extensions.Logging;
9+
using OpenTelemetry;
10+
using OpenTelemetry.Exporter;
11+
using OpenTelemetry.Metrics;
12+
using OpenTelemetry.Trace;
13+
14+
namespace Elastic.OpenTelemetry;
15+
16+
/// <summary> TODO </summary>
17+
public static class OpenTelemetryBuilderExtensions
18+
{
19+
/// <summary>
20+
/// Build an instance of <see cref="IAgent"/>.
21+
/// </summary>
22+
/// <returns>A new instance of <see cref="IAgent"/>.</returns>
23+
public static IAgent Build(this IOpenTelemetryBuilder builder, ILogger? logger = null, IServiceProvider? serviceProvider = null)
24+
{
25+
// this happens if someone calls Build() while using IServiceCollection and AddOpenTelemetry() and NOT Add*Elastic*OpenTelemetry()
26+
// we treat this a NOOP
27+
// NOTE for AddElasticOpenTelemetry(this IServiceCollection services) calling Build() manually is NOT required.
28+
if (builder is not AgentBuilder agentBuilder)
29+
return new EmptyAgent();
30+
31+
var log = agentBuilder.Logger;
32+
33+
log.SetAdditionalLogger(logger);
34+
35+
var otelBuilder = agentBuilder.Services.AddOpenTelemetry();
36+
otelBuilder
37+
.WithTracing(tracing =>
38+
{
39+
if (!agentBuilder.SkipOtlpRegistration)
40+
tracing.AddOtlpExporter(agentBuilder.OtlpExporterName, agentBuilder.OtlpExporterConfiguration);
41+
log.LogAgentBuilderBuiltTracerProvider();
42+
})
43+
.WithMetrics(metrics =>
44+
{
45+
if (!agentBuilder.SkipOtlpRegistration)
46+
{
47+
metrics.AddOtlpExporter(agentBuilder.OtlpExporterName, o =>
48+
{
49+
o.ExportProcessorType = ExportProcessorType.Simple;
50+
o.Protocol = OtlpExportProtocol.HttpProtobuf;
51+
});
52+
}
53+
log.LogAgentBuilderBuiltMeterProvider();
54+
});
55+
56+
var sp = serviceProvider ?? agentBuilder.Services.BuildServiceProvider();
57+
var tracerProvider = sp.GetService<TracerProvider>()!;
58+
var meterProvider = sp.GetService<MeterProvider>()!;
59+
60+
var agent = new ElasticAgent(log, agentBuilder.EventListener, tracerProvider, meterProvider);
61+
log.LogAgentBuilderBuiltAgent();
62+
return agent;
63+
}
64+
}
65+
66+
internal class EmptyAgent : IAgent
67+
{
68+
public void Dispose() { }
69+
70+
public ValueTask DisposeAsync() => ValueTask.CompletedTask;
71+
}
72+
73+
internal class ElasticAgent(
74+
AgentCompositeLogger logger,
75+
LoggingEventListener loggingEventListener,
76+
TracerProvider tracerProvider,
77+
MeterProvider meterProvider
78+
) : IAgent
79+
{
80+
public void Dispose()
81+
{
82+
tracerProvider.Dispose();
83+
meterProvider.Dispose();
84+
loggingEventListener.Dispose();
85+
logger.Dispose();
86+
}
87+
88+
public async ValueTask DisposeAsync()
89+
{
90+
tracerProvider.Dispose();
91+
meterProvider.Dispose();
92+
await loggingEventListener.DisposeAsync().ConfigureAwait(false);
93+
await logger.DisposeAsync().ConfigureAwait(false);
94+
}
95+
}
96+

0 commit comments

Comments
 (0)