Skip to content

Commit 7d70e9d

Browse files
authored
Updated service.name resource attribute logic in Plugin (#219)
1 parent 46065fb commit 7d70e9d

File tree

2 files changed

+72
-8
lines changed

2 files changed

+72
-8
lines changed

src/AWS.Distro.OpenTelemetry.AutoInstrumentation/Plugin.cs

Lines changed: 70 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
using System.Web;
1919
using OpenTelemetry.Instrumentation.AspNet;
2020
#endif
21+
using System.Runtime.CompilerServices;
2122
using System.Text.RegularExpressions;
2223
using AWS.Distro.OpenTelemetry.AutoInstrumentation.Logging;
2324
using 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
}

test/contract-tests/tests/test/amazon/misc/unknown_service_name_test.py

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,5 @@ def get_application_otel_resource_attributes(self) -> str:
1515
pairlist.append(key + "=" + value)
1616
return ",".join(pairlist)
1717

18-
# TODO: metric service.name is set correctly, but span service.name is being set to AppSignals.NetCore.
19-
# def test_service(self) -> None:
20-
# self.do_test_resource_attributes("unknown_service:dotnet")
18+
def test_service(self) -> None:
19+
self.do_test_resource_attributes("AppSignals.NetCore")

0 commit comments

Comments
 (0)