1818using System . Web ;
1919using OpenTelemetry . Instrumentation . AspNet ;
2020#endif
21+ using System . Runtime . CompilerServices ;
2122using System . Text . RegularExpressions ;
2223using AWS . Distro . OpenTelemetry . AutoInstrumentation . Logging ;
2324using AWS . Distro . OpenTelemetry . Exporter . Xray . Udp ;
@@ -129,7 +130,7 @@ public void TracerProviderInitialized(TracerProvider tracerProvider)
129130
130131 MeterProvider provider = Sdk . CreateMeterProviderBuilder ( )
131132 . AddReader ( metricReader )
132- . ConfigureResource ( builder => this . ResourceBuilderCustomizer ( builder ) )
133+ . ConfigureResource ( builder => this . ResourceBuilderCustomizer ( builder , tracerProvider . GetResource ( ) ) )
133134 . AddMeter ( "AwsSpanMetricsProcessor" )
134135 . AddView ( instrument =>
135136 {
@@ -194,7 +195,12 @@ public TracerProviderBuilder BeforeConfigureTracerProvider(TracerProviderBuilder
194195 {
195196 if ( this . IsApplicationSignalsEnabled ( ) )
196197 {
197- var resourceBuilder = this . ResourceBuilderCustomizer ( ResourceBuilder . CreateDefault ( ) ) ;
198+ var resourceBuilder = ResourceBuilder
199+ . CreateEmpty ( ) // Don't use CreateDefault because it puts service name unknown by default.
200+ . AddEnvironmentVariableDetector ( )
201+ . AddTelemetrySdk ( ) ;
202+
203+ resourceBuilder = this . ResourceBuilderCustomizer ( resourceBuilder ) ;
198204 var resource = resourceBuilder . Build ( ) ;
199205 var processor = AwsMetricAttributesSpanProcessorBuilder . Create ( resource ) . Build ( ) ;
200206 builder . AddProcessor ( processor ) ;
@@ -214,7 +220,12 @@ public TracerProviderBuilder BeforeConfigureTracerProvider(TracerProviderBuilder
214220 /// <returns>Returns configured builder</returns>
215221 public TracerProviderBuilder AfterConfigureTracerProvider ( TracerProviderBuilder builder )
216222 {
217- var resourceBuilder = this . ResourceBuilderCustomizer ( ResourceBuilder . CreateDefault ( ) ) ;
223+ var resourceBuilder = ResourceBuilder
224+ . CreateEmpty ( ) // Don't use CreateDefault because it puts service name unknown by default.
225+ . AddEnvironmentVariableDetector ( )
226+ . AddTelemetrySdk ( ) ;
227+
228+ resourceBuilder = this . ResourceBuilderCustomizer ( resourceBuilder ) ;
218229 var resource = resourceBuilder . Build ( ) ;
219230 this . sampler = SamplerUtil . GetSampler ( resource ) ;
220231
@@ -516,14 +527,29 @@ private bool IsApplicationSignalsRuntimeEnabled()
516527 ! "false" . Equals ( System . Environment . GetEnvironmentVariable ( ApplicationSignalsRuntimeEnabledConfig ) ) ;
517528 }
518529
519- private ResourceBuilder ResourceBuilderCustomizer ( ResourceBuilder builder )
530+ private ResourceBuilder ResourceBuilderCustomizer ( ResourceBuilder builder , Resource ? existingResource = null )
520531 {
532+ // base case: If there is an already existing resource passed as a parameter, we will copy
533+ // those resource attributes into the resource builder.
534+ if ( existingResource != null )
535+ {
536+ builder . AddAttributes ( existingResource . Attributes ) ;
537+ }
538+
521539 builder . AddAttributes ( DistroAttributes ) ;
522540 var resource = builder . Build ( ) ;
541+ if ( ! resource . Attributes . Any ( kvp => kvp . Key == ResourceSemanticConventions . AttributeServiceName ) )
542+ {
543+ // service.name was not configured yet use the fallback.
544+ Logger . Log ( LogLevel . Warning , "No valid service name provided. Using fallback logic of using assembly name!" ) ;
545+ builder . AddAttributes ( new Dictionary < string , object > { { ResourceSemanticConventions . AttributeServiceName , this . GetFallbackServiceName ( ) } } ) ;
546+ }
547+
548+ // Incase the above logic failed to get assembly or process name for any reason
523549 var serviceName = ( string ? ) resource . Attributes . FirstOrDefault ( attr => attr . Key == ResourceSemanticConventions . AttributeServiceName ) . Value ;
524550 if ( serviceName == null || serviceName . StartsWith ( OtelUnknownServicePrefix ) )
525551 {
526- Logger . Log ( LogLevel . Warning , "No valid service name provided. ") ;
552+ Logger . Log ( LogLevel . Warning , $ "Fallback logic failed. Using { AwsSpanProcessingUtil . UnknownService } as service name! ") ;
527553 serviceName = AwsSpanProcessingUtil . UnknownService ;
528554 }
529555
@@ -628,4 +654,43 @@ private int GetTracesOtlpTimeout()
628654
629655 return DefaultOtlpTracesTimeoutMilli ;
630656 }
657+
658+ private string GetFallbackServiceName ( )
659+ {
660+ try
661+ {
662+ #if NETFRAMEWORK
663+ // System.Web.dll is only available on .NET Framework
664+ if ( System . Web . Hosting . HostingEnvironment . IsHosted )
665+ {
666+ // if this app is an ASP.NET application, return "SiteName/ApplicationVirtualPath".
667+ // note that ApplicationVirtualPath includes a leading slash.
668+ return ( System . Web . Hosting . HostingEnvironment . SiteName + System . Web . Hosting . HostingEnvironment . ApplicationVirtualPath ) . TrimEnd ( '/' ) ;
669+ }
670+ #endif
671+ return Assembly . GetEntryAssembly ( ) ? . GetName ( ) . Name ?? this . GetCurrentProcessName ( ) ;
672+ }
673+ catch
674+ {
675+ return OtelUnknownServicePrefix ;
676+ }
677+ }
678+
679+ /// <summary>
680+ /// <para>Wrapper around <see cref="Process.GetCurrentProcess"/> and <see cref="Process.ProcessName"/></para>
681+ /// <para>
682+ /// On .NET Framework the <see cref="Process"/> class is guarded by a
683+ /// LinkDemand for FullTrust, so partial trust callers will throw an exception.
684+ /// This exception is thrown when the caller method is being JIT compiled, NOT
685+ /// when Process.GetCurrentProcess is called, so this wrapper method allows
686+ /// us to catch the exception.
687+ /// </para>
688+ /// </summary>
689+ /// <returns>Returns the name of the current process.</returns>
690+ [ MethodImpl ( MethodImplOptions . NoInlining ) ]
691+ private string GetCurrentProcessName ( )
692+ {
693+ using var currentProcess = Process . GetCurrentProcess ( ) ;
694+ return currentProcess . ProcessName ;
695+ }
631696}
0 commit comments