Skip to content
Closed
Show file tree
Hide file tree
Changes from all 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 @@ -391,7 +391,7 @@ private static void AddGrpcAttributes(Activity activity, string grpcMethod, Http
// https://github.com/open-telemetry/semantic-conventions/blob/main/docs/rpc/rpc-spans.md#span-name
activity.DisplayName = details.DisplayName;

activity.SetTag(SemanticConventions.AttributeRpcSystem, GrpcTagHelper.RpcSystemGrpc);
activity.SetTag(SemanticConventions.AttributeRpcSystemName, GrpcTagHelper.RpcSystemGrpc);

// see the spec https://github.com/open-telemetry/semantic-conventions/blob/v1.23.0/docs/rpc/rpc-spans.md

Expand All @@ -409,8 +409,7 @@ private static void AddGrpcAttributes(Activity activity, string grpcMethod, Http

if (details.IsParsed)
{
activity.SetTag(SemanticConventions.AttributeRpcService, details.RpcService);
activity.SetTag(SemanticConventions.AttributeRpcMethod, details.RpcMethod);
activity.SetTag(SemanticConventions.AttributeRpcMethod, details.DisplayName);

// Remove the grpc.method tag added by the gRPC .NET library
activity.SetTag(GrpcTagHelper.GrpcMethodTagName, null);
Expand All @@ -420,8 +419,8 @@ private static void AddGrpcAttributes(Activity activity, string grpcMethod, Http

if (validStatusCode)
{
// setting rpc.grpc.status_code
activity.SetTag(SemanticConventions.AttributeRpcGrpcStatusCode, grpcStatusCode);
// setting rpc.response.status_code
activity.SetTag(SemanticConventions.AttributeRpcResponseStatusCode, GrpcTagHelper.ConvertStatusCodeToString(grpcStatusCode));
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,12 @@
</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\Guard.cs" Link="Includes\Guard.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\SemanticConventions.cs" Link="Includes\SemanticConventions.cs" />
</ItemGroup>

Expand Down
2 changes: 1 addition & 1 deletion src/OpenTelemetry.Instrumentation.GrpcCore/RpcScope.cs
Original file line number Diff line number Diff line change
Expand Up @@ -216,7 +216,7 @@ private void StopActivity(int statusCode, bool markAsCompleted = true)
return;
}

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

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -176,7 +176,7 @@ public void OnStopActivity(Activity activity, object? payload)
activity.SetStatus(GrpcTagHelper.ResolveSpanStatusForGrpcStatusCodeOnClient(status));
}

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

// Remove the grpc.status_code tag added by the gRPC .NET library
Expand Down
25 changes: 25 additions & 0 deletions src/Shared/GrpcTagHelper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,31 @@ public static bool TryGetGrpcStatusCodeFromActivity(Activity activity, out int s
int.TryParse(grpcStatusCodeTag as string, NumberStyles.None, CultureInfo.InvariantCulture, out statusCode);
}

public static string ConvertStatusCodeToString(int statusCode)
{
return (GrpcStatusCanonicalCode)statusCode switch
{
GrpcStatusCanonicalCode.Ok => "OK",
GrpcStatusCanonicalCode.Cancelled => "CANCELLED",
GrpcStatusCanonicalCode.Unknown => "UNKNOWN",
GrpcStatusCanonicalCode.InvalidArgument => "INVALID_ARGUMENT",
GrpcStatusCanonicalCode.DeadlineExceeded => "DEADLINE_EXCEEDED",
GrpcStatusCanonicalCode.NotFound => "NOT_FOUND",
GrpcStatusCanonicalCode.AlreadyExists => "ALREADY_EXISTS",
GrpcStatusCanonicalCode.PermissionDenied => "PERMISSION_DENIED",
GrpcStatusCanonicalCode.ResourceExhausted => "RESOURCE_EXHAUSTED",
GrpcStatusCanonicalCode.FailedPrecondition => "FAILED_PRECONDITION",
GrpcStatusCanonicalCode.Aborted => "ABORTED",
GrpcStatusCanonicalCode.OutOfRange => "OUT_OF_RANGE",
GrpcStatusCanonicalCode.Unimplemented => "UNIMPLEMENTED",
GrpcStatusCanonicalCode.Internal => "INTERNAL",
GrpcStatusCanonicalCode.Unavailable => "UNAVAILABLE",
GrpcStatusCanonicalCode.DataLoss => "DATA_LOSS",
GrpcStatusCanonicalCode.Unauthenticated => "UNAUTHENTICATED",
_ => "UNKNOWN",
};
}

public static bool TryParseRpcServiceAndRpcMethod(string grpcMethod, out string rpcService, out string rpcMethod)
{
var span = grpcMethod.AsSpan();
Expand Down
32 changes: 29 additions & 3 deletions test/OpenTelemetry.Contrib.Shared.Tests/GrpcTagHelperTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -45,10 +45,10 @@ public void GrpcTagHelper_GetGrpcStatusCodeFromActivity()
Assert.True(validConversion);

var statusCode = GrpcTagHelper.ResolveSpanStatusForGrpcStatusCodeOnClient(status);
activity.SetTag(SemanticConventions.AttributeRpcGrpcStatusCode, status);
activity.SetTag(SemanticConventions.AttributeRpcResponseStatusCode, GrpcTagHelper.ConvertStatusCodeToString(status));

Assert.Equal(ActivityStatusCode.Unset, statusCode);
Assert.Equal(status, activity.GetTagValue(SemanticConventions.AttributeRpcGrpcStatusCode));
Assert.Equal(GrpcTagHelper.ConvertStatusCodeToString(status), activity.GetTagValue(SemanticConventions.AttributeRpcResponseStatusCode));
}

[Theory]
Expand Down Expand Up @@ -103,6 +103,32 @@ public void GrpcTagHelper_ResolveSpanStatusForGrpcStatusCodeOnServer(int grpcSta
Assert.Equal(expectedActivityStatusCode, result);
}

[Theory]
[InlineData(0, "OK")] // Ok
[InlineData(-1, "UNKNOWN")] // Invalid negative status code
[InlineData(1, "CANCELLED")] // Cancelled
[InlineData(2, "UNKNOWN")] // Unknown
[InlineData(3, "INVALID_ARGUMENT")] // InvalidArgument
[InlineData(4, "DEADLINE_EXCEEDED")] // DeadlineExceeded
[InlineData(5, "NOT_FOUND")] // NotFound
[InlineData(6, "ALREADY_EXISTS")] // AlreadyExists
[InlineData(7, "PERMISSION_DENIED")] // PermissionDenied
[InlineData(8, "RESOURCE_EXHAUSTED")] // ResourceExhausted
[InlineData(9, "FAILED_PRECONDITION")] // FailedPrecondition
[InlineData(10, "ABORTED")] // Aborted
[InlineData(11, "OUT_OF_RANGE")] // OutOfRange
[InlineData(12, "UNIMPLEMENTED")] // Unimplemented
[InlineData(13, "INTERNAL")] // Internal
[InlineData(14, "UNAVAILABLE")] // Unavailable
[InlineData(15, "DATA_LOSS")] // DataLoss
[InlineData(16, "UNAUTHENTICATED")] // Unauthenticated
[InlineData(99, "UNKNOWN")] // Unknown status code
public void GrpcTagHelper_ConvertStatusCodeToString(int grpcStatusCode, string expectedStatusCode)
{
var result = GrpcTagHelper.ConvertStatusCodeToString(grpcStatusCode);
Assert.Equal(expectedStatusCode, result);
}

[Fact]
public void GrpcTagHelper_GetGrpcStatusCodeFromEmptyActivity()
{
Expand All @@ -111,6 +137,6 @@ public void GrpcTagHelper_GetGrpcStatusCodeFromEmptyActivity()
var validConversion = GrpcTagHelper.TryGetGrpcStatusCodeFromActivity(activity, out var status);
Assert.False(validConversion);
Assert.Equal(-1, status);
Assert.Null(activity.GetTagValue(SemanticConventions.AttributeRpcGrpcStatusCode));
Assert.Null(activity.GetTagValue(SemanticConventions.AttributeRpcResponseStatusCode));
}
}
16 changes: 8 additions & 8 deletions test/OpenTelemetry.Instrumentation.AspNetCore.Tests/GrpcTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -31,10 +31,10 @@ public void OnStopActivityAddsGrpcAttributesForParsedMethodAndValidStatusCode()
AssertTag(activity, SemanticConventions.AttributeClientAddress, "127.0.0.1");
AssertTag(activity, SemanticConventions.AttributeClientPort, 4317);
AssertTag(activity, SemanticConventions.AttributeHttpResponseStatusCode, 200);
AssertTag(activity, SemanticConventions.AttributeRpcGrpcStatusCode, 13);
AssertTag(activity, SemanticConventions.AttributeRpcMethod, "Method");
AssertTag(activity, SemanticConventions.AttributeRpcService, "package.Service");
AssertTag(activity, SemanticConventions.AttributeRpcSystem, "grpc");
AssertTag(activity, SemanticConventions.AttributeRpcResponseStatusCode, "INTERNAL");
AssertTag(activity, SemanticConventions.AttributeRpcMethod, "package.Service/Method");
AssertTag(activity, SemanticConventions.AttributeRpcService, null);
AssertTag(activity, SemanticConventions.AttributeRpcSystemName, "grpc");
}

[Fact]
Expand All @@ -56,10 +56,10 @@ public void OnStopActivityPreservesGrpcTagsWhenMethodCannotBeParsedAndStatusIsIn
AssertTag(activity, GrpcTagHelper.GrpcStatusCodeTagName, "invalid");
AssertTag(activity, SemanticConventions.AttributeClientAddress, null);
AssertTag(activity, SemanticConventions.AttributeClientPort, 4317);
AssertTag(activity, SemanticConventions.AttributeRpcGrpcStatusCode, null);
AssertTag(activity, SemanticConventions.AttributeRpcResponseStatusCode, null);
AssertTag(activity, SemanticConventions.AttributeRpcMethod, null);
AssertTag(activity, SemanticConventions.AttributeRpcService, null);
AssertTag(activity, SemanticConventions.AttributeRpcSystem, "grpc");
AssertTag(activity, SemanticConventions.AttributeRpcSystemName, "grpc");
}

[Fact]
Expand All @@ -79,8 +79,8 @@ public void OnStopActivityIgnoresEmptyGrpcMethodTag()

AssertTag(activity, GrpcTagHelper.GrpcMethodTagName, string.Empty);
AssertTag(activity, GrpcTagHelper.GrpcStatusCodeTagName, "13");
AssertTag(activity, SemanticConventions.AttributeRpcGrpcStatusCode, null);
AssertTag(activity, SemanticConventions.AttributeRpcSystem, null);
AssertTag(activity, SemanticConventions.AttributeRpcResponseStatusCode, null);
AssertTag(activity, SemanticConventions.AttributeRpcSystemName, null);
}

private static void AssertTag(Activity activity, string name, object? expected) =>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -344,6 +344,7 @@ internal static void ValidateCommonActivityTags(
Assert.True(activity.IsStopped, "The activity has not been stopped.");

var expectedRpcMethod = $"OpenTelemetry.Instrumentation.GrpcCore.Tests.Foobar/{expectedMethodName}";
var expectedResponseStatusCode = GrpcTagHelper.ConvertStatusCodeToString((int)expectedStatusCode);

Assert.Equal(expectedRpcMethod, activity.DisplayName);

Expand All @@ -352,7 +353,7 @@ internal static void ValidateCommonActivityTags(
Assert.Contains(activity.TagObjects, t => t.Key == SemanticConventions.AttributeRpcSystemName && (string?)t.Value == "grpc");
Assert.DoesNotContain(activity.TagObjects, t => t.Key == SemanticConventions.AttributeRpcService);
Assert.Contains(activity.TagObjects, t => t.Key == SemanticConventions.AttributeRpcMethod && (string?)t.Value == expectedRpcMethod);
Assert.Contains(activity.TagObjects, t => t.Key == SemanticConventions.AttributeRpcResponseStatusCode && (int?)t.Value == (int)expectedStatusCode);
Assert.Contains(activity.TagObjects, t => t.Key == SemanticConventions.AttributeRpcResponseStatusCode && (string?)t.Value == expectedResponseStatusCode);

// Cancelled is not an error.
if (expectedStatusCode is not StatusCode.OK and not StatusCode.Cancelled)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@ public void GrpcClientCallsAreCollectedSuccessfully(string baseAddress, bool sho
// Tags added by the library then removed from the instrumentation
Assert.Null(activity.GetTagValue(GrpcTagHelper.GrpcMethodTagName));
Assert.Null(activity.GetTagValue(GrpcTagHelper.GrpcStatusCodeTagName));
Assert.Equal(0, activity.GetTagValue(SemanticConventions.AttributeRpcResponseStatusCode));
Assert.Equal("OK", activity.GetTagValue(SemanticConventions.AttributeRpcResponseStatusCode));

if (shouldEnrich)
{
Expand Down Expand Up @@ -146,7 +146,7 @@ public void GrpcAndHttpClientInstrumentationIsInvoked(bool shouldEnrich)

ValidateGrpcActivity(grpcSpan);
Assert.Equal($"greet.Greeter/SayHello", grpcSpan.DisplayName);
Assert.Equal(0, grpcSpan.GetTagValue(SemanticConventions.AttributeRpcResponseStatusCode));
Assert.Equal("OK", grpcSpan.GetTagValue(SemanticConventions.AttributeRpcResponseStatusCode));
Assert.Equal("POST", httpSpan.DisplayName);
Assert.Equal(grpcSpan.SpanId, httpSpan.ParentSpanId);

Expand Down Expand Up @@ -199,19 +199,19 @@ public void GrpcAndHttpClientInstrumentationWithSuppressInstrumentation()

ValidateGrpcActivity(grpcSpan1);
Assert.Equal($"greet.Greeter/SayHello", grpcSpan1.DisplayName);
Assert.Equal(0, grpcSpan1.GetTagValue(SemanticConventions.AttributeRpcResponseStatusCode));
Assert.Equal("OK", grpcSpan1.GetTagValue(SemanticConventions.AttributeRpcResponseStatusCode));

ValidateGrpcActivity(grpcSpan2);
Assert.Equal($"greet.Greeter/SayHello", grpcSpan2.DisplayName);
Assert.Equal(0, grpcSpan2.GetTagValue(SemanticConventions.AttributeRpcResponseStatusCode));
Assert.Equal("OK", grpcSpan2.GetTagValue(SemanticConventions.AttributeRpcResponseStatusCode));

ValidateGrpcActivity(grpcSpan3);
Assert.Equal($"greet.Greeter/SayHello", grpcSpan3.DisplayName);
Assert.Equal(0, grpcSpan3.GetTagValue(SemanticConventions.AttributeRpcResponseStatusCode));
Assert.Equal("OK", grpcSpan3.GetTagValue(SemanticConventions.AttributeRpcResponseStatusCode));

ValidateGrpcActivity(grpcSpan4);
Assert.Equal($"greet.Greeter/SayHello", grpcSpan4.DisplayName);
Assert.Equal(0, grpcSpan4.GetTagValue(SemanticConventions.AttributeRpcResponseStatusCode));
Assert.Equal("OK", grpcSpan4.GetTagValue(SemanticConventions.AttributeRpcResponseStatusCode));
}

#if NET
Expand Down Expand Up @@ -267,7 +267,7 @@ public void GrpcPropagatesContextWithSuppressInstrumentationOptionSetToTrue()
Assert.Equal($"POST /greet.Greeter/SayHello", serverActivity.DisplayName);
Assert.Equal(clientActivity.TraceId, serverActivity.TraceId);
Assert.Equal(clientActivity.SpanId, serverActivity.ParentSpanId);
Assert.Equal(0, clientActivity.GetTagValue(SemanticConventions.AttributeRpcGrpcStatusCode));
Assert.Equal("OK", clientActivity.GetTagValue(SemanticConventions.AttributeRpcResponseStatusCode));
Assert.Equal("customValue", serverActivity.GetCustomProperty("customField") as string);
}
finally
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -76,17 +76,19 @@ public void GrpcAspNetCoreInstrumentationAddsCorrectAttributes(string? enableGrp

if (enableGrpcAspNetCoreSupport != null && enableGrpcAspNetCoreSupport.Equals("true", StringComparison.OrdinalIgnoreCase))
{
Assert.Equal("grpc", activity.GetTagValue(SemanticConventions.AttributeRpcSystem));
Assert.Equal("greet.Greeter", activity.GetTagValue(SemanticConventions.AttributeRpcService));
Assert.Equal("SayHello", activity.GetTagValue(SemanticConventions.AttributeRpcMethod));
Assert.Equal("greet.Greeter/SayHello", activity.DisplayName);
Assert.Equal("grpc", activity.GetTagValue(SemanticConventions.AttributeRpcSystemName));
Assert.Null(activity.GetTagValue(SemanticConventions.AttributeRpcService));
Assert.Equal("greet.Greeter/SayHello", activity.GetTagValue(SemanticConventions.AttributeRpcMethod));
Assert.Contains(activity.GetTagValue(SemanticConventions.AttributeClientAddress), clientLoopbackAddresses);
Assert.NotEqual(0, activity.GetTagValue(SemanticConventions.AttributeClientPort));
Assert.Null(activity.GetTagValue(GrpcTagHelper.GrpcMethodTagName));
Assert.Null(activity.GetTagValue(GrpcTagHelper.GrpcStatusCodeTagName));
Assert.Equal(0, activity.GetTagValue(SemanticConventions.AttributeRpcGrpcStatusCode));
Assert.Equal("OK", activity.GetTagValue(SemanticConventions.AttributeRpcResponseStatusCode));
}
else
{
Assert.Equal("POST /greet.Greeter/SayHello", activity.DisplayName);
Assert.NotNull(activity.GetTagValue(GrpcTagHelper.GrpcMethodTagName));
Assert.NotNull(activity.GetTagValue(GrpcTagHelper.GrpcStatusCodeTagName));
}
Expand Down Expand Up @@ -154,17 +156,19 @@ public void GrpcAspNetCoreInstrumentationAddsCorrectAttributesWhenItCreatesNewAc

if (enableGrpcAspNetCoreSupport != null && enableGrpcAspNetCoreSupport.Equals("true", StringComparison.OrdinalIgnoreCase))
{
Assert.Equal("greet.Greeter/SayHello", activity.DisplayName);
Assert.Equal("grpc", activity.GetTagValue(SemanticConventions.AttributeRpcSystemName));
Assert.Equal("greet.Greeter", activity.GetTagValue(SemanticConventions.AttributeRpcService));
Assert.Equal("SayHello", activity.GetTagValue(SemanticConventions.AttributeRpcMethod));
Assert.Null(activity.GetTagValue(SemanticConventions.AttributeRpcService));
Assert.Equal("greet.Greeter/SayHello", activity.GetTagValue(SemanticConventions.AttributeRpcMethod));
Assert.Contains(activity.GetTagValue(SemanticConventions.AttributeNetPeerIp), clientLoopbackAddresses);
Assert.NotEqual(0, activity.GetTagValue(SemanticConventions.AttributeNetPeerPort));
Assert.Null(activity.GetTagValue(GrpcTagHelper.GrpcMethodTagName));
Assert.Null(activity.GetTagValue(GrpcTagHelper.GrpcStatusCodeTagName));
Assert.Equal(0, activity.GetTagValue(SemanticConventions.AttributeRpcResponseStatusCode));
Assert.Equal("OK", activity.GetTagValue(SemanticConventions.AttributeRpcResponseStatusCode));
}
else
{
{
Assert.Equal("POST /greet.Greeter/SayHello", activity.DisplayName);
Assert.NotNull(activity.GetTagValue(GrpcTagHelper.GrpcMethodTagName));
Assert.NotNull(activity.GetTagValue(GrpcTagHelper.GrpcStatusCodeTagName));
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@
<PackageReference Include="OpenTelemetry.Api" />
<PackageReference Include="OpenTelemetry.Exporter.InMemory" />
<PackageReference Include="OpenTelemetry.Extensions.Propagators" />
<PackageReference Include="OpenTelemetry.Instrumentation.AspNetCore" Condition="'$([MSBuild]::GetTargetFrameworkIdentifier(`$(TargetFramework)`))' == '.NETCoreApp'" />
<PackageReference Include="OpenTelemetry.Instrumentation.Http" />
</ItemGroup>

Expand All @@ -28,6 +27,7 @@

<ItemGroup>
<ProjectReference Include="$(RepoRoot)\src\OpenTelemetry.Instrumentation.GrpcNetClient\OpenTelemetry.Instrumentation.GrpcNetClient.csproj" />
<ProjectReference Include="$(RepoRoot)\src\OpenTelemetry.Instrumentation.AspNetCore\OpenTelemetry.Instrumentation.AspNetCore.csproj" Condition="'$([MSBuild]::GetTargetFrameworkIdentifier(`$(TargetFramework)`))' == '.NETCoreApp'" />
</ItemGroup>

<ItemGroup>
Expand Down