Skip to content

Commit 9a55ef9

Browse files
[AzureMonitorOpenTelemetryDistro] Read log related settings from IConfiguration (Azure#34647)
* Save work in progress. * Add comments * Changes from Blanch * Options.DefaultName * Remove unused method. * Modify try * Fix build * alignment
1 parent 268185d commit 9a55ef9

File tree

4 files changed

+88
-44
lines changed

4 files changed

+88
-44
lines changed

sdk/monitor/Azure.Monitor.OpenTelemetry/src/AzureMonitorImplementations.cs

Lines changed: 74 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,10 @@
55
using Azure.Monitor.OpenTelemetry.Exporter;
66
using Microsoft.Extensions.DependencyInjection;
77
using Microsoft.Extensions.Logging;
8+
using Microsoft.Extensions.Logging.Abstractions;
89
using Microsoft.Extensions.Options;
910
using OpenTelemetry.Extensions.AzureMonitor;
11+
using OpenTelemetry.Logs;
1012
using OpenTelemetry.Metrics;
1113
using OpenTelemetry.Trace;
1214

@@ -42,29 +44,26 @@ internal static IServiceCollection AddAzureMonitorWithAction(IServiceCollection
4244

4345
services.AddLogging(logging =>
4446
{
45-
AzureMonitorOptions logExporterOptions = new();
46-
if (configureAzureMonitor != null)
47+
logging.AddOpenTelemetry(builderOptions =>
4748
{
48-
configureAzureMonitor(logExporterOptions);
49-
}
49+
builderOptions.IncludeFormattedMessage = true;
50+
builderOptions.ParseStateValues = true;
51+
builderOptions.IncludeScopes = false;
52+
});
53+
});
5054

51-
if (logExporterOptions.EnableLogs)
52-
{
53-
logging.AddOpenTelemetry(builderOptions =>
55+
// Add AzureMonitorLogExporter to AzureMonitorOptions
56+
// once the service provider is available containing the final
57+
// AzureMonitorOptions.
58+
services.AddOptions<OpenTelemetryLoggerOptions>()
59+
.Configure<IOptionsMonitor<AzureMonitorOptions>>((loggingOptions, azureOptions) =>
5460
{
55-
builderOptions.IncludeFormattedMessage = true;
56-
builderOptions.ParseStateValues = true;
57-
builderOptions.IncludeScopes = false;
58-
// TODO: In the follow up PR remove the hard-coded value for AddAzureMonitorLogExporter.
59-
// Follow up PR includes the support for logging to read from DI.
60-
// builderOptions.AddAzureMonitorLogExporter(o => logExporterOptions.SetValueToExporterOptions(o));
61-
builderOptions.AddAzureMonitorLogExporter(o => o.ConnectionString = "InstrumentationKey=00000000-0000-0000-0000-000000000000");
61+
loggingOptions.AddAzureMonitorLogExporter(o => azureOptions.Get(Options.DefaultName).SetValueToExporterOptions(o));
6262
});
63-
}
64-
});
6563

6664
ServiceDescriptor? sdkTracerProviderServiceRegistration = null;
6765
ServiceDescriptor? sdkMeterProviderServiceRegistration = null;
66+
ServiceDescriptor? sdkLoggerProviderServiceRegistration = null;
6867

6968
foreach (var service in services)
7069
{
@@ -76,10 +75,19 @@ internal static IServiceCollection AddAzureMonitorWithAction(IServiceCollection
7675
{
7776
sdkMeterProviderServiceRegistration = service;
7877
}
78+
else if (service.ServiceType == typeof(ILoggerProvider))
79+
{
80+
var implementationFactory = service.ImplementationFactory;
81+
if (implementationFactory != null && implementationFactory.Method.DeclaringType.Assembly == typeof(OpenTelemetryLoggerProvider).Assembly)
82+
{
83+
sdkLoggerProviderServiceRegistration = service;
84+
}
85+
}
7986
}
8087

8188
if (sdkTracerProviderServiceRegistration?.ImplementationFactory == null ||
82-
sdkMeterProviderServiceRegistration?.ImplementationFactory == null)
89+
sdkMeterProviderServiceRegistration?.ImplementationFactory == null ||
90+
sdkLoggerProviderServiceRegistration?.ImplementationFactory == null)
8391
{
8492
throw new InvalidOperationException("OpenTelemetry SDK has changed its registration mechanism.");
8593
}
@@ -89,20 +97,31 @@ internal static IServiceCollection AddAzureMonitorWithAction(IServiceCollection
8997

9098
services.Remove(sdkTracerProviderServiceRegistration);
9199
services.Remove(sdkMeterProviderServiceRegistration);
100+
services.Remove(sdkLoggerProviderServiceRegistration);
101+
102+
// Register a configuration action so that when
103+
// AzureMonitorExporterOptions is requested it is populated from
104+
// AzureMonitorOptions.
105+
services
106+
.AddOptions<AzureMonitorExporterOptions>()
107+
.Configure<IOptionsMonitor<AzureMonitorOptions>>((exporterOptions, azureMonitorOptions) =>
108+
{
109+
azureMonitorOptions.Get(Options.DefaultName).SetValueToExporterOptions(exporterOptions);
110+
});
92111

93-
// Now we register our own services for TracerProvider & MeterProvider
94-
// so that we can return no-op versions when it isn't enabled.
112+
// Now we register our own services for TracerProvider,
113+
// MeterProvider, and LoggerProvider so that we can return no-op
114+
// versions when it isn't enabled.
95115

96116
services.AddSingleton(sp =>
97117
{
98-
var options = sp.GetRequiredService<IOptionsMonitor<AzureMonitorOptions>>().Get("");
118+
var options = sp.GetRequiredService<IOptionsMonitor<AzureMonitorOptions>>().Get(Options.DefaultName);
99119
if (!options.EnableTraces)
100120
{
101121
return new NoopTracerProvider();
102122
}
103123
else
104124
{
105-
options.SetValueToExporterOptions(sp);
106125
var sdkProviderWrapper = sp.GetRequiredService<SdkProviderWrapper>();
107126
sdkProviderWrapper.SdkTracerProvider = (TracerProvider)sdkTracerProviderServiceRegistration.ImplementationFactory(sp);
108127
return sdkProviderWrapper.SdkTracerProvider;
@@ -111,27 +130,57 @@ internal static IServiceCollection AddAzureMonitorWithAction(IServiceCollection
111130

112131
services.AddSingleton(sp =>
113132
{
114-
var options = sp.GetRequiredService<IOptionsMonitor<AzureMonitorOptions>>().Get("");
133+
var options = sp.GetRequiredService<IOptionsMonitor<AzureMonitorOptions>>().Get(Options.DefaultName);
115134
if (!options.EnableMetrics)
116135
{
117136
return new NoopMeterProvider();
118137
}
119138
else
120139
{
121-
options.SetValueToExporterOptions(sp);
122140
var sdkProviderWrapper = sp.GetRequiredService<SdkProviderWrapper>();
123141
sdkProviderWrapper.SdkMeterProvider = (MeterProvider)sdkMeterProviderServiceRegistration.ImplementationFactory(sp);
124142
return sdkProviderWrapper.SdkMeterProvider;
125143
}
126144
});
127145

146+
services.AddSingleton(sp =>
147+
{
148+
var options = sp.GetRequiredService<IOptionsMonitor<AzureMonitorOptions>>().Get(Options.DefaultName);
149+
if (!options.EnableLogs)
150+
{
151+
return new NoopLoggerProvider();
152+
}
153+
else
154+
{
155+
var sdkProviderWrapper = sp.GetRequiredService<SdkProviderWrapper>();
156+
sdkProviderWrapper.SdkLoggerProvider = (ILoggerProvider)sdkLoggerProviderServiceRegistration.ImplementationFactory(sp);
157+
return sdkProviderWrapper.SdkLoggerProvider;
158+
}
159+
});
160+
128161
// SdkProviderWrapper is here to make sure the SDK services get properly
129162
// shutdown when the service provider is disposed.
130163
services.AddSingleton<SdkProviderWrapper>();
131164

132165
return services;
133166
}
134167

168+
private sealed class NoopLoggerProvider : ILoggerProvider, ISupportExternalScope
169+
{
170+
public ILogger CreateLogger(string categoryName)
171+
{
172+
return NullLogger.Instance;
173+
}
174+
175+
public void Dispose()
176+
{
177+
}
178+
179+
public void SetScopeProvider(IExternalScopeProvider scopeProvider)
180+
{
181+
}
182+
}
183+
135184
private sealed class NoopTracerProvider : TracerProvider
136185
{
137186
}
@@ -144,11 +193,13 @@ private sealed class SdkProviderWrapper : IDisposable
144193
{
145194
public TracerProvider? SdkTracerProvider;
146195
public MeterProvider? SdkMeterProvider;
196+
public ILoggerProvider? SdkLoggerProvider;
147197

148198
public void Dispose()
149199
{
150200
this.SdkTracerProvider?.Dispose();
151201
this.SdkMeterProvider?.Dispose();
202+
this.SdkLoggerProvider?.Dispose();
152203
}
153204
}
154205
}

sdk/monitor/Azure.Monitor.OpenTelemetry/src/AzureMonitorOptions.cs

Lines changed: 1 addition & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,6 @@
66
using Azure.Core;
77
using Azure.Core.Pipeline;
88
using Azure.Monitor.OpenTelemetry.Exporter;
9-
using Microsoft.Extensions.DependencyInjection;
10-
using Microsoft.Extensions.Options;
11-
using System;
12-
using System.Net;
139

1410
namespace Azure.Monitor.OpenTelemetry
1511
{
@@ -64,7 +60,7 @@ public class AzureMonitorOptions
6460
// Used for testing purpose
6561
internal HttpPipelineTransport Transport;
6662

67-
internal AzureMonitorOptions Clone(AzureMonitorOptions options)
63+
internal void Clone(AzureMonitorOptions options)
6864
{
6965
if (options != null)
7066
{
@@ -76,14 +72,6 @@ internal AzureMonitorOptions Clone(AzureMonitorOptions options)
7672
StorageDirectory = options.StorageDirectory;
7773
Transport = options.Transport;
7874
}
79-
80-
return this;
81-
}
82-
83-
internal void SetValueToExporterOptions(IServiceProvider sp)
84-
{
85-
var exporterOptions = sp.GetRequiredService<IOptionsMonitor<AzureMonitorExporterOptions>>().Get("");
86-
SetValueToExporterOptions(exporterOptions);
8775
}
8876

8977
internal void SetValueToExporterOptions(AzureMonitorExporterOptions exporterOptions)

sdk/monitor/Azure.Monitor.OpenTelemetry/src/DefaultAzureMonitorOptions.cs

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -29,11 +29,18 @@ public void Configure(AzureMonitorOptions options)
2929
_configuration.GetSection(AzureMonitorSectionFromConfig).Bind(options);
3030
}
3131

32-
string connectionString = Environment.GetEnvironmentVariable(ConnectionStringEnvironmentVariable);
32+
try
33+
{
34+
string connectionString = Environment.GetEnvironmentVariable(ConnectionStringEnvironmentVariable);
3335

34-
if (!string.IsNullOrWhiteSpace(connectionString))
36+
if (!string.IsNullOrWhiteSpace(connectionString))
37+
{
38+
options.ConnectionString = connectionString;
39+
}
40+
}
41+
catch
3542
{
36-
options.ConnectionString = connectionString;
43+
// TODO: Log Error.
3744
}
3845
}
3946
}

sdk/monitor/Azure.Monitor.OpenTelemetry/tests/Azure.Monitor.OpenTelemetry.Demo/Program.cs

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -7,12 +7,11 @@
77
using Azure.Monitor.OpenTelemetry;
88
using Microsoft.AspNetCore.Builder;
99
using Microsoft.Extensions.Logging;
10-
using OpenTelemetry.Extensions.AzureMonitor;
11-
using OpenTelemetry.Trace;
1210

1311
var builder = WebApplication.CreateBuilder(args);
1412

1513
builder.Services.AddAzureMonitor();
14+
1615
/*
1716
builder.Services.AddAzureMonitor(o =>
1817
{
@@ -24,9 +23,8 @@
2423

2524
// To customize sampling, Set ApplicationInsightsSampler to desired sampling ratio and
2625
// configure with OpenTelemetryTracerProvider.
27-
// Please note that ConfigureOpenTelemetryTracerProvider should be called after
28-
// builder.Services.AddAzureMonitor().
29-
builder.Services.ConfigureOpenTelemetryTracerProvider((sp, builder) => builder.SetSampler(new ApplicationInsightsSampler(0.9F)));
26+
// Please note that ConfigureOpenTelemetryTracerProvider should be called after builder.Services.AddAzureMonitor().
27+
// builder.Services.ConfigureOpenTelemetryTracerProvider((sp, builder) => builder.SetSampler(new ApplicationInsightsSampler(0.9F)));
3028

3129
var app = builder.Build();
3230
app.MapGet("/", () =>

0 commit comments

Comments
 (0)