@@ -32,6 +32,30 @@ public static void AddOtlpEnvironment(IResource resource, IConfiguration configu
3232 // Add annotation to mark this resource as having OTLP exporter configured
3333 resource . Annotations . Add ( new OtlpExporterAnnotation ( ) ) ;
3434
35+ RegisterOtlpEnvironment ( resource , configuration , environment ) ;
36+ }
37+
38+ /// <summary>
39+ /// Configures OpenTelemetry in projects using environment variables.
40+ /// </summary>
41+ /// <param name="resource">The resource to add annotations to.</param>
42+ /// <param name="configuration">The configuration to use for the OTLP exporter endpoint URL.</param>
43+ /// <param name="environment">The host environment to check if the application is running in development mode.</param>
44+ /// <param name="protocol">The protocol to use for the OTLP exporter. If not set, it will try gRPC then Http.</param>
45+ public static void AddOtlpEnvironment ( IResource resource , IConfiguration configuration , IHostEnvironment environment , OtlpProtocol protocol )
46+ {
47+ ArgumentNullException . ThrowIfNull ( resource ) ;
48+ ArgumentNullException . ThrowIfNull ( configuration ) ;
49+ ArgumentNullException . ThrowIfNull ( environment ) ;
50+
51+ // Add annotation to mark this resource as having OTLP exporter configured
52+ resource . Annotations . Add ( new OtlpExporterAnnotation { RequiredProtocol = protocol } ) ;
53+
54+ RegisterOtlpEnvironment ( resource , configuration , environment ) ;
55+ }
56+
57+ private static void RegisterOtlpEnvironment ( IResource resource , IConfiguration configuration , IHostEnvironment environment )
58+ {
3559 // Configure OpenTelemetry in projects using environment variables.
3660 // https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/configuration/sdk-environment-variables.md
3761
@@ -43,26 +67,13 @@ public static void AddOtlpEnvironment(IResource resource, IConfiguration configu
4367 return ;
4468 }
4569
46- var dashboardOtlpGrpcUrl = configuration . GetString ( KnownConfigNames . DashboardOtlpGrpcEndpointUrl , KnownConfigNames . Legacy . DashboardOtlpGrpcEndpointUrl ) ;
47- var dashboardOtlpHttpUrl = configuration . GetString ( KnownConfigNames . DashboardOtlpHttpEndpointUrl , KnownConfigNames . Legacy . DashboardOtlpHttpEndpointUrl ) ;
48-
49- // The dashboard can support OTLP/gRPC and OTLP/HTTP endpoints at the same time, but it can
50- // only tell resources about one of the endpoints via environment variables.
51- // If both OTLP/gRPC and OTLP/HTTP are available then prefer gRPC.
52- if ( dashboardOtlpGrpcUrl != null )
53- {
54- SetOtelEndpointAndProtocol ( context . EnvironmentVariables , dashboardOtlpGrpcUrl , "grpc" ) ;
55- }
56- else if ( dashboardOtlpHttpUrl != null )
57- {
58- SetOtelEndpointAndProtocol ( context . EnvironmentVariables , dashboardOtlpHttpUrl , "http/protobuf" ) ;
59- }
60- else
70+ if ( ! resource . TryGetLastAnnotation < OtlpExporterAnnotation > ( out var otlpExporterAnnotation ) )
6171 {
62- // No endpoints provided to host. Use default value for URL.
63- SetOtelEndpointAndProtocol ( context . EnvironmentVariables , DashboardOtlpUrlDefaultValue , "grpc" ) ;
72+ return ;
6473 }
6574
75+ SetOtelEndpointAndProtocol ( context , configuration , otlpExporterAnnotation ) ;
76+
6677 // Set the service name and instance id to the resource name and UID. Values are injected by DCP.
6778 var dcpDependencyCheckService = context . ExecutionContext . ServiceProvider . GetRequiredService < IDcpDependencyCheckService > ( ) ;
6879 var dcpInfo = await dcpDependencyCheckService . GetDcpInfoAsync ( cancellationToken : context . CancellationToken ) . ConfigureAwait ( false ) ;
@@ -91,6 +102,42 @@ public static void AddOtlpEnvironment(IResource resource, IConfiguration configu
91102 }
92103 } ) ) ;
93104
105+ static void SetOtelEndpointAndProtocol ( EnvironmentCallbackContext context , IConfiguration configuration , OtlpExporterAnnotation otlpExporterAnnotation )
106+ {
107+ var dashboardOtlpGrpcUrl = configuration . GetString ( KnownConfigNames . DashboardOtlpGrpcEndpointUrl , KnownConfigNames . Legacy . DashboardOtlpGrpcEndpointUrl ) ;
108+ var dashboardOtlpHttpUrl = configuration . GetString ( KnownConfigNames . DashboardOtlpHttpEndpointUrl , KnownConfigNames . Legacy . DashboardOtlpHttpEndpointUrl ) ;
109+
110+ // Check if a specific protocol is required by the annotation
111+ if ( otlpExporterAnnotation . RequiredProtocol is OtlpProtocol . Grpc )
112+ {
113+ SetOtelEndpointAndProtocol ( context . EnvironmentVariables , dashboardOtlpGrpcUrl ?? DashboardOtlpUrlDefaultValue , "grpc" ) ;
114+ }
115+ else if ( otlpExporterAnnotation . RequiredProtocol is OtlpProtocol . HttpProtobuf )
116+ {
117+ SetOtelEndpointAndProtocol ( context . EnvironmentVariables , dashboardOtlpHttpUrl ?? throw new InvalidOperationException ( "OtlpExporter is configured to require http/protobuf, but no endpoint was configured for ASPIRE_DASHBOARD_OTLP_HTTP_ENDPOINT_URL" ) , "http/protobuf" ) ;
118+ }
119+ else
120+ {
121+ // No specific protocol required, use the existing preference logic
122+ // The dashboard can support OTLP/gRPC and OTLP/HTTP endpoints at the same time, but it can
123+ // only tell resources about one of the endpoints via environment variables.
124+ // If both OTLP/gRPC and OTLP/HTTP are available then prefer gRPC.
125+ if ( dashboardOtlpGrpcUrl is not null )
126+ {
127+ SetOtelEndpointAndProtocol ( context . EnvironmentVariables , dashboardOtlpGrpcUrl , "grpc" ) ;
128+ }
129+ else if ( dashboardOtlpHttpUrl is not null )
130+ {
131+ SetOtelEndpointAndProtocol ( context . EnvironmentVariables , dashboardOtlpHttpUrl , "http/protobuf" ) ;
132+ }
133+ else
134+ {
135+ // No endpoints provided to host. Use default value for URL.
136+ SetOtelEndpointAndProtocol ( context . EnvironmentVariables , DashboardOtlpUrlDefaultValue , "grpc" ) ;
137+ }
138+ }
139+ }
140+
94141 static void SetOtelEndpointAndProtocol ( Dictionary < string , object > environmentVariables , string url , string protocol )
95142 {
96143 environmentVariables [ "OTEL_EXPORTER_OTLP_ENDPOINT" ] = new HostUrl ( url ) ;
@@ -112,7 +159,26 @@ public static IResourceBuilder<T> WithOtlpExporter<T>(this IResourceBuilder<T> b
112159 ArgumentNullException . ThrowIfNull ( builder ) ;
113160
114161 AddOtlpEnvironment ( builder . Resource , builder . ApplicationBuilder . Configuration , builder . ApplicationBuilder . Environment ) ;
115-
162+
163+ return builder ;
164+ }
165+
166+ /// <summary>
167+ /// Injects the appropriate environment variables to allow the resource to enable sending telemetry to the dashboard.
168+ /// 1. It sets the OTLP endpoint to the value of the ASPIRE_DASHBOARD_OTLP_ENDPOINT_URL environment variable.
169+ /// 2. It sets the service name and instance id to the resource name and UID. Values are injected by the orchestrator.
170+ /// 3. It sets a small batch schedule delay in development. This reduces the delay that OTLP exporter waits to sends telemetry and makes the dashboard telemetry pages responsive.
171+ /// </summary>
172+ /// <typeparam name="T">The resource type.</typeparam>
173+ /// <param name="builder">The resource builder.</param>
174+ /// <param name="protocol">The protocol to use for the OTLP exporter. If not set, it will try gRPC then Http.</param>
175+ /// <returns>The <see cref="IResourceBuilder{T}"/>.</returns>
176+ public static IResourceBuilder < T > WithOtlpExporter < T > ( this IResourceBuilder < T > builder , OtlpProtocol protocol ) where T : IResourceWithEnvironment
177+ {
178+ ArgumentNullException . ThrowIfNull ( builder ) ;
179+
180+ AddOtlpEnvironment ( builder . Resource , builder . ApplicationBuilder . Configuration , builder . ApplicationBuilder . Environment , protocol ) ;
181+
116182 return builder ;
117183 }
118184}
0 commit comments