Skip to content
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ namespace OpenTelemetry.Instrumentation.AspNetCore;
/// </summary>
internal sealed class AspNetCoreInstrumentation : IDisposable
{
internal static readonly Version SemanticConventionsVersion = new(1, 40, 0);
internal static readonly Version SemanticConventionsVersion = new(1, 42, 0);

private static readonly HashSet<string> DiagnosticSourceEvents =
[
Expand Down
4 changes: 4 additions & 0 deletions src/OpenTelemetry.Instrumentation.AspNetCore/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,10 @@
of the Semantic Conventions for RPC/gRPC.
([#4370](https://github.com/open-telemetry/opentelemetry-dotnet-contrib/pull/4370))

* Update Semantic Conventions for RPC/gRPC to version
[1.42.0](https://github.com/open-telemetry/semantic-conventions/blob/v1.42.0/docs/rpc/README.md).
([#4508](https://github.com/open-telemetry/opentelemetry-dotnet-contrib/pull/4508))

## 1.15.2

Released 2026-Apr-21
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
// Copyright The OpenTelemetry Authors
// SPDX-License-Identifier: Apache-2.0

using System.Collections.Concurrent;
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System.Globalization;
Expand Down Expand Up @@ -46,10 +45,6 @@ internal class HttpInListener : ListenerHandler
private static readonly PropertyFetcher<Exception> ExceptionPropertyFetcher = new("Exception");
private static readonly object CreatedByInstrumentationMarker = new();

// Caches the display name, rpc.service, and rpc.method derived from the raw gRPC method string.
// The set of distinct gRPC method strings is bounded by the number of gRPC endpoints in the app.
private static readonly GrpcMethodDetailsCache GrpcMethodCache = new();
Comment thread
martincostello marked this conversation as resolved.

private readonly AspNetCoreTraceInstrumentationOptions options;
private readonly bool nativeAspNetCoreOpenTelemetryEnabled;

Expand Down Expand Up @@ -293,15 +288,12 @@ public void OnStopActivity(Activity activity, object? payload)
}
}

if (grpcMethod is { Length: > 0 })
{
AddGrpcAttributes(
activity,
grpcMethod,
context,
grpcStatusCode,
hasGrpcStatusCode);
}
AddGrpcAttributes(
activity,
grpcMethod,
context,
grpcStatusCode,
hasGrpcStatusCode);
}

if (activity.Status == ActivityStatusCode.Unset)
Expand Down Expand Up @@ -389,16 +381,15 @@ static bool TryFetchException(object? payload, [NotNullWhen(true)] out Exception
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static void AddGrpcAttributes(
Activity activity,
string grpcMethod,
string? grpcMethod,
HttpContext context,
int grpcStatusCode,
bool validStatusCode)
{
var details = GrpcMethodCache.Get(grpcMethod);

// See the specs for semantic conventions.
// https://github.com/open-telemetry/semantic-conventions/blob/v1.41.0/docs/rpc/rpc-spans.md
activity.SetTag(SemanticConventions.AttributeRpcSystemName, GrpcTagHelper.RpcSystemGrpc);
// https://github.com/open-telemetry/semantic-conventions/blob/v1.42.0/docs/rpc/rpc-spans.md
GrpcTagHelper.SetGrpcSystemName(activity);
GrpcTagHelper.SetGrpcMethodAndDisplayNameFromActivity(activity, grpcMethod);

if (context.Connection.RemoteIpAddress != null)
{
Expand All @@ -414,30 +405,8 @@ private static void AddGrpcAttributes(
activity.SetStatus(spanStatus);
}

// https://github.com/open-telemetry/semantic-conventions/blob/v1.41.0/docs/rpc/grpc.md
if (details.IsParsed)
{
// The RPC semantic conventions indicate the span name should be rpc.method
// when it is available and not "_OTHER".
activity.DisplayName = details.DisplayName;

// rpc.method is the fully-qualified logical method name, e.g. "package.Service/Method".
activity.SetTag(SemanticConventions.AttributeRpcMethod, details.DisplayName);
}
else
{
// The RPC semantic conventions indicate the span name should be rpc.system.name
// when rpc.method is "_OTHER".
activity.DisplayName = GrpcTagHelper.RpcSystemGrpc;

// The method is not in the expected service/method form, so it is treated as unrecognized:
// rpc.method is set to "_OTHER" and the original value is preserved in rpc.method_original.
activity.SetTag(SemanticConventions.AttributeRpcMethod, GrpcTagHelper.RpcMethodOther);
activity.SetTag(SemanticConventions.AttributeRpcMethodOriginal, grpcMethod);
}

// The grpc.method tag has now been mapped to rpc.method, so the source tag can be removed.
// See https://github.com/open-telemetry/semantic-conventions/blob/v1.41.0/docs/non-normative/compatibility/grpc.md#attribute-mapping
// See https://github.com/open-telemetry/semantic-conventions/blob/v1.42.0/docs/non-normative/compatibility/grpc.md#attribute-mapping
activity.SetTag(GrpcTagHelper.GrpcMethodTagName, null);
activity.SetTag(GrpcTagHelper.GrpcTargetTagName, null);

Expand Down Expand Up @@ -494,48 +463,4 @@ private static bool IsGrpcRequest(Activity activity, [NotNullWhen(true)] out str
grpcMethod = GrpcTagHelper.GetGrpcMethodFromActivity(activity);
return !string.IsNullOrEmpty(grpcMethod);
}

private readonly struct GrpcMethodDetails
{
public GrpcMethodDetails(string displayName, string? rpcService, string? rpcMethod, bool isParsed)
{
this.DisplayName = displayName;
this.RpcService = rpcService;
this.RpcMethod = rpcMethod;
this.IsParsed = isParsed;
}

public readonly string DisplayName { get; }

public readonly string? RpcService { get; }

public readonly string? RpcMethod { get; }

public readonly bool IsParsed { get; }
}

private sealed class GrpcMethodDetailsCache
{
private const int MaxCacheSize = 512;
private readonly ConcurrentDictionary<string, GrpcMethodDetails> cache = new();

public GrpcMethodDetails Get(string grpcMethod)
{
if (this.cache.TryGetValue(grpcMethod, out var details))
{
return details;
}

// If the cache has reached its maximum size, just create a value without caching
return this.cache.Count >= MaxCacheSize ? Create(grpcMethod) : this.cache.GetOrAdd(grpcMethod, Create);
}

private static GrpcMethodDetails Create(string method)
{
var displayName = method.Length > 0 && method[0] == '/' ? method.Substring(1) : method;
var isParsed = GrpcTagHelper.TryParseRpcServiceAndRpcMethod(method, out var serviceName, out var methodName);

return new(displayName, isParsed ? serviceName : null, isParsed ? methodName : null, isParsed);
}
}
}
5 changes: 3 additions & 2 deletions src/OpenTelemetry.Instrumentation.GrpcCore/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,9 @@

## Unreleased

* **BREAKING**: Update to version 1.41.0 of the Semantic Conventions.
([#4338](https://github.com/open-telemetry/opentelemetry-dotnet-contrib/pull/4338))
* **BREAKING**: Update to version 1.42.0 of the Semantic Conventions.
([#4338](https://github.com/open-telemetry/opentelemetry-dotnet-contrib/pull/4338),
[#4508](https://github.com/open-telemetry/opentelemetry-dotnet-contrib/pull/4508))

* Add instrumentation scope version and schema URL to traces.
([#4338](https://github.com/open-telemetry/opentelemetry-dotnet-contrib/pull/4338))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ internal static class GrpcCoreInstrumentation
/// <summary>
/// Gets the version of the RPC Semantic Conventions used by the instrumentation.
/// </summary>
internal static readonly Version SemanticConventionsVersion = new(1, 41, 0);
internal static readonly Version SemanticConventionsVersion = new(1, 42, 0);

/// <summary>
/// Gets the activity source for the instrumentation.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,11 @@
</ItemGroup>

<ItemGroup>
<Compile Include="$(RepoRoot)\src\Shared\ActivityHelperExtensions.cs" Link="Includes\ActivityHelperExtensions.cs" />
<Compile Include="$(RepoRoot)\src\Shared\ActivitySourceFactory.cs" Link="Includes\ActivitySourceFactory.cs" />
<Compile Include="$(RepoRoot)\src\Shared\AssemblyVersionExtensions.cs" Link="Includes\AssemblyVersionExtensions.cs" />
<Compile Include="$(RepoRoot)\src\Shared\GrpcStatusCanonicalCode.cs" Link="Includes\GrpcStatusCanonicalCode.cs" />
<Compile Include="$(RepoRoot)\src\Shared\GrpcTagHelper.cs" Link="Includes\GrpcTagHelper.cs" />
<Compile Include="$(RepoRoot)\src\Shared\Guard.cs" Link="Includes\Guard.cs" />
<Compile Include="$(RepoRoot)\src\Shared\SemanticConventions.cs" Link="Includes\SemanticConventions.cs" />
</ItemGroup>
Expand Down
23 changes: 4 additions & 19 deletions src/OpenTelemetry.Instrumentation.GrpcCore/RpcScope.cs
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ protected RpcScope(
bool recordException)
{
this.host = host;
this.FullServiceName = fullServiceName?.TrimStart('/') ?? "unknownservice/unknownmethod";
this.FullServiceName = fullServiceName?.Trim('/') ?? "unknownservice/unknownmethod";
this.recordMessageEvents = recordMessageEvents;
this.recordException = recordException;
}
Expand Down Expand Up @@ -175,28 +175,13 @@ protected void SetActivity(Activity? activity)
return;
}

// Assign some reasonable defaults
var rpcService = this.FullServiceName;
var rpcMethod = this.FullServiceName;

// Split the full service name by the slash
var parts = this.FullServiceName.Split('/');
if (parts.Length == 2)
{
rpcService = parts[0];
rpcMethod = parts[1];
}

this.activity.SetTag(SemanticConventions.AttributeRpcSystemName, "grpc");
this.activity.SetTag(SemanticConventions.AttributeRpcService, rpcService);
this.activity.SetTag(SemanticConventions.AttributeRpcMethod, rpcMethod);
GrpcTagHelper.SetGrpcSystemName(this.activity);
GrpcTagHelper.SetGrpcMethodAndDisplayNameFromActivity(this.activity, this.FullServiceName);

if (this.host is { Length: > 0 } host)
{
TrySetServerAttributes(this.activity, host);
}

this.activity.DisplayName = rpcMethod.Trim('/');
}

private static void TrySetServerAttributes(Activity activity, string host)
Expand Down Expand Up @@ -227,7 +212,7 @@ private void StopActivity(int statusCode, bool markAsCompleted = true)
return;
}

this.activity.SetTag(SemanticConventions.AttributeRpcResponseStatusCode, statusCode);
this.activity.SetTag(SemanticConventions.AttributeRpcResponseStatusCode, GrpcTagHelper.GetGrpcStatusCodeName(statusCode));
this.activity.Stop();
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,9 @@

## Unreleased

* **BREAKING**: Update to version 1.41.0 of the Semantic Conventions.
([#4338](https://github.com/open-telemetry/opentelemetry-dotnet-contrib/pull/4338))
* **BREAKING**: Update to version 1.42.0 of the Semantic Conventions.
([#4338](https://github.com/open-telemetry/opentelemetry-dotnet-contrib/pull/4338),
[#4508](https://github.com/open-telemetry/opentelemetry-dotnet-contrib/pull/4508))

* Add instrumentation scope version and schema URL to traces.
([#4338](https://github.com/open-telemetry/opentelemetry-dotnet-contrib/pull/4338))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ namespace OpenTelemetry.Instrumentation.GrpcNetClient.Implementation;

internal sealed class GrpcClientDiagnosticListener : ListenerHandler
{
internal static readonly Version SemanticConventionsVersion = new(1, 41, 0);
internal static readonly Version SemanticConventionsVersion = new(1, 42, 0);
internal static readonly ActivitySource ActivitySource = ActivitySourceFactory.Create<GrpcClientDiagnosticListener>(SemanticConventionsVersion);

private const string OnStartEvent = "Grpc.Net.Client.GrpcOut.Start";
Expand Down Expand Up @@ -107,23 +107,8 @@ public void OnStartActivity(Activity activity, object? payload)
ActivityInstrumentationHelper.SetActivitySourceProperty(activity, ActivitySource);
ActivityInstrumentationHelper.SetKindProperty(activity, ActivityKind.Client);

var grpcMethod = GrpcTagHelper.GetGrpcMethodFromActivity(activity);

activity.DisplayName = grpcMethod?.Trim('/') ?? GrpcTagHelper.RpcSystemGrpc;

if (grpcMethod != null)
{
if (GrpcTagHelper.TryParseRpcServiceAndRpcMethod(grpcMethod, out var rpcService, out var rpcMethod))
{
activity.SetTag(SemanticConventions.AttributeRpcService, rpcService);
activity.SetTag(SemanticConventions.AttributeRpcMethod, rpcMethod);

// Remove the grpc.method tag added by the gRPC .NET library
activity.SetTag(GrpcTagHelper.GrpcMethodTagName, null);
}
}

activity.SetTag(SemanticConventions.AttributeRpcSystemName, GrpcTagHelper.RpcSystemGrpc);
GrpcTagHelper.SetGrpcSystemName(activity);
GrpcTagHelper.SetGrpcMethodAndDisplayNameFromActivity(activity);

var requestUri = request.RequestUri;

Expand Down Expand Up @@ -180,7 +165,7 @@ public void OnStopActivity(Activity activity, object? payload)
activity.SetStatus(GrpcTagHelper.ResolveSpanStatusForGrpcStatusCodeOnClient(status));
}

activity.SetTag(SemanticConventions.AttributeRpcResponseStatusCode, status);
activity.SetTag(SemanticConventions.AttributeRpcResponseStatusCode, GrpcTagHelper.GetGrpcStatusCodeName(status));
}

// Remove the grpc.status_code tag added by the gRPC .NET library
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,8 @@
<Compile Include="$(RepoRoot)\src\Shared\DiagnosticSourceListener.cs" Link="Includes\DiagnosticSourceListener.cs" />
<Compile Include="$(RepoRoot)\src\Shared\DiagnosticSourceSubscriber.cs" Link="Includes\DiagnosticSourceSubscriber.cs" />
<Compile Include="$(RepoRoot)\src\Shared\ExceptionExtensions.cs" Link="Includes\ExceptionExtensions.cs" />
<Compile Include="$(RepoRoot)\src\Shared\GrpcTagHelper.cs" Link="Includes\GrpcTagHelper.cs" />
<Compile Include="$(RepoRoot)\src\Shared\GrpcStatusCanonicalCode.cs" Link="Includes\GrpcStatusCanonicalCode.cs" />
<Compile Include="$(RepoRoot)\src\Shared\GrpcTagHelper.cs" Link="Includes\GrpcTagHelper.cs" />
<Compile Include="$(RepoRoot)\src\Shared\Guard.cs" Link="Includes\Guard.cs" />
<Compile Include="$(RepoRoot)\src\Shared\HttpRequestMessageContextPropagation.cs" Link="Includes\HttpRequestMessageContextPropagation.cs" />
<Compile Include="$(RepoRoot)\src\Shared\ListenerHandler.cs" Link="Includes\ListenerHandler.cs" />
Expand Down
Loading
Loading