5
5
using Azure . Monitor . OpenTelemetry . Exporter ;
6
6
using Microsoft . Extensions . DependencyInjection ;
7
7
using Microsoft . Extensions . Logging ;
8
+ using Microsoft . Extensions . Logging . Abstractions ;
8
9
using Microsoft . Extensions . Options ;
9
10
using OpenTelemetry . Extensions . AzureMonitor ;
11
+ using OpenTelemetry . Logs ;
10
12
using OpenTelemetry . Metrics ;
11
13
using OpenTelemetry . Trace ;
12
14
@@ -42,29 +44,26 @@ internal static IServiceCollection AddAzureMonitorWithAction(IServiceCollection
42
44
43
45
services . AddLogging ( logging =>
44
46
{
45
- AzureMonitorOptions logExporterOptions = new ( ) ;
46
- if ( configureAzureMonitor != null )
47
+ logging . AddOpenTelemetry ( builderOptions =>
47
48
{
48
- configureAzureMonitor ( logExporterOptions ) ;
49
- }
49
+ builderOptions . IncludeFormattedMessage = true ;
50
+ builderOptions . ParseStateValues = true ;
51
+ builderOptions . IncludeScopes = false ;
52
+ } ) ;
53
+ } ) ;
50
54
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 ) =>
54
60
{
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 ) ) ;
62
62
} ) ;
63
- }
64
- } ) ;
65
63
66
64
ServiceDescriptor ? sdkTracerProviderServiceRegistration = null ;
67
65
ServiceDescriptor ? sdkMeterProviderServiceRegistration = null ;
66
+ ServiceDescriptor ? sdkLoggerProviderServiceRegistration = null ;
68
67
69
68
foreach ( var service in services )
70
69
{
@@ -76,10 +75,19 @@ internal static IServiceCollection AddAzureMonitorWithAction(IServiceCollection
76
75
{
77
76
sdkMeterProviderServiceRegistration = service ;
78
77
}
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
+ }
79
86
}
80
87
81
88
if ( sdkTracerProviderServiceRegistration ? . ImplementationFactory == null ||
82
- sdkMeterProviderServiceRegistration ? . ImplementationFactory == null )
89
+ sdkMeterProviderServiceRegistration ? . ImplementationFactory == null ||
90
+ sdkLoggerProviderServiceRegistration ? . ImplementationFactory == null )
83
91
{
84
92
throw new InvalidOperationException ( "OpenTelemetry SDK has changed its registration mechanism." ) ;
85
93
}
@@ -89,20 +97,31 @@ internal static IServiceCollection AddAzureMonitorWithAction(IServiceCollection
89
97
90
98
services . Remove ( sdkTracerProviderServiceRegistration ) ;
91
99
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
+ } ) ;
92
111
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.
95
115
96
116
services . AddSingleton ( sp =>
97
117
{
98
- var options = sp . GetRequiredService < IOptionsMonitor < AzureMonitorOptions > > ( ) . Get ( "" ) ;
118
+ var options = sp . GetRequiredService < IOptionsMonitor < AzureMonitorOptions > > ( ) . Get ( Options . DefaultName ) ;
99
119
if ( ! options . EnableTraces )
100
120
{
101
121
return new NoopTracerProvider ( ) ;
102
122
}
103
123
else
104
124
{
105
- options . SetValueToExporterOptions ( sp ) ;
106
125
var sdkProviderWrapper = sp . GetRequiredService < SdkProviderWrapper > ( ) ;
107
126
sdkProviderWrapper . SdkTracerProvider = ( TracerProvider ) sdkTracerProviderServiceRegistration . ImplementationFactory ( sp ) ;
108
127
return sdkProviderWrapper . SdkTracerProvider ;
@@ -111,27 +130,57 @@ internal static IServiceCollection AddAzureMonitorWithAction(IServiceCollection
111
130
112
131
services . AddSingleton ( sp =>
113
132
{
114
- var options = sp . GetRequiredService < IOptionsMonitor < AzureMonitorOptions > > ( ) . Get ( "" ) ;
133
+ var options = sp . GetRequiredService < IOptionsMonitor < AzureMonitorOptions > > ( ) . Get ( Options . DefaultName ) ;
115
134
if ( ! options . EnableMetrics )
116
135
{
117
136
return new NoopMeterProvider ( ) ;
118
137
}
119
138
else
120
139
{
121
- options . SetValueToExporterOptions ( sp ) ;
122
140
var sdkProviderWrapper = sp . GetRequiredService < SdkProviderWrapper > ( ) ;
123
141
sdkProviderWrapper . SdkMeterProvider = ( MeterProvider ) sdkMeterProviderServiceRegistration . ImplementationFactory ( sp ) ;
124
142
return sdkProviderWrapper . SdkMeterProvider ;
125
143
}
126
144
} ) ;
127
145
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
+
128
161
// SdkProviderWrapper is here to make sure the SDK services get properly
129
162
// shutdown when the service provider is disposed.
130
163
services . AddSingleton < SdkProviderWrapper > ( ) ;
131
164
132
165
return services ;
133
166
}
134
167
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
+
135
184
private sealed class NoopTracerProvider : TracerProvider
136
185
{
137
186
}
@@ -144,11 +193,13 @@ private sealed class SdkProviderWrapper : IDisposable
144
193
{
145
194
public TracerProvider ? SdkTracerProvider ;
146
195
public MeterProvider ? SdkMeterProvider ;
196
+ public ILoggerProvider ? SdkLoggerProvider ;
147
197
148
198
public void Dispose ( )
149
199
{
150
200
this . SdkTracerProvider ? . Dispose ( ) ;
151
201
this . SdkMeterProvider ? . Dispose ( ) ;
202
+ this . SdkLoggerProvider ? . Dispose ( ) ;
152
203
}
153
204
}
154
205
}
0 commit comments