From 009d63e3e380715fb2c5049b1b3537547129913a Mon Sep 17 00:00:00 2001 From: Eddy Nakamura Date: Mon, 28 Sep 2020 21:25:11 -0300 Subject: [PATCH 1/4] Updating Status based on the new spec commenting OtlpTrace.Status.Type check fixing test undoing change to statuscanonicalcode fixing tests reiley's comments SetStatus now saves enum instead of string fixing changes after conversion fixing redis tests from http spec, if 1xx,2xx,3xx => unset, otherwise error. from rpc spec, if ok => unset, otherwise error. fixing sql tests fixing redis tests --- examples/Console/TestRedis.cs | 2 +- .../Trace/ActivityExtensions.cs | 20 ++- src/OpenTelemetry.Api/Trace/SpanHelper.cs | 128 ++--------------- src/OpenTelemetry.Api/Trace/Status.cs | 134 ++---------------- .../OpenTelemetry.Api/Trace/StatusCode.cs | 28 ++-- .../Implementation/ActivityExtensions.cs | 2 +- .../GrpcTagHelper.cs | 2 +- .../HttpHandlerDiagnosticListener.cs | 8 +- .../HttpWebRequestActivitySource.netfx.cs | 19 +-- .../SqlClientDiagnosticListener.cs | 4 +- .../SqlEventSourceListener.netfx.cs | 4 +- .../RedisProfilerEntryToActivityConverter.cs | 2 +- .../SpanBuilderShim.cs | 2 +- .../SpanShim.cs | 2 +- .../OtlpExporterTest.cs | 8 +- .../HttpInListenerTests.cs | 2 +- ...stsCollectionsIsAccordingToTheSpecTests.cs | 2 +- .../GrpcTagHelperTests.cs | 2 +- .../GrpcTests.client.cs | 2 +- .../GrpcTests.server.cs | 2 +- .../HttpClientTests.netcore31.cs | 26 +--- .../HttpWebRequestTests.netfx.cs | 26 +--- .../http-out-test-cases.json | 36 ++--- .../SqlClientTests.cs | 4 +- .../SqlEventSourceTests.netfx.cs | 4 +- ...kExchangeRedisCallsInstrumentationTests.cs | 2 +- .../SpanBuilderShimTests.cs | 4 +- .../SpanShimTests.cs | 4 +- .../Trace/ActivityExtensionsTest.cs | 10 +- test/OpenTelemetry.Tests/Trace/StatusTest.cs | 34 ++--- 30 files changed, 148 insertions(+), 377 deletions(-) rename test/OpenTelemetry.Tests/Utils/CanonicalCodeExtensions.cs => src/OpenTelemetry.Api/Trace/StatusCode.cs (54%) diff --git a/examples/Console/TestRedis.cs b/examples/Console/TestRedis.cs index 2951e99a55f..666f504d038 100644 --- a/examples/Console/TestRedis.cs +++ b/examples/Console/TestRedis.cs @@ -96,7 +96,7 @@ private static void DoWork(IDatabase db, ActivitySource activitySource) catch (ArgumentOutOfRangeException e) { // Set status upon error - activity.SetTag(SpanAttributeConstants.StatusCodeKey, SpanHelper.GetCachedCanonicalCodeString(Status.Internal.CanonicalCode)); + activity.SetTag(SpanAttributeConstants.StatusCodeKey, (int)Status.Error.StatusCode); activity.SetTag(SpanAttributeConstants.StatusDescriptionKey, e.ToString()); } diff --git a/src/OpenTelemetry.Api/Trace/ActivityExtensions.cs b/src/OpenTelemetry.Api/Trace/ActivityExtensions.cs index 8ad2875161e..4a75f468b7c 100644 --- a/src/OpenTelemetry.Api/Trace/ActivityExtensions.cs +++ b/src/OpenTelemetry.Api/Trace/ActivityExtensions.cs @@ -42,7 +42,7 @@ public static void SetStatus(this Activity activity, Status status) { Debug.Assert(activity != null, "Activity should not be null"); - activity.SetTag(SpanAttributeConstants.StatusCodeKey, SpanHelper.GetCachedCanonicalCodeString(status.CanonicalCode)); + activity.SetTag(SpanAttributeConstants.StatusCodeKey, (int)status.StatusCode); if (!string.IsNullOrEmpty(status.Description)) { activity.SetTag(SpanAttributeConstants.StatusDescriptionKey, status.Description); @@ -66,9 +66,14 @@ public static Status GetStatus(this Activity activity) ActivityTagsEnumeratorFactory.Enumerate(activity, ref state); - var status = SpanHelper.ResolveCanonicalCodeToStatus(state.StatusCode); + if (!state.IsValid) + { + return default; + } - if (status.IsValid && !string.IsNullOrEmpty(state.StatusDescription)) + var status = new Status(state.StatusCode); + + if (!string.IsNullOrEmpty(state.StatusDescription)) { return status.WithDescription(state.StatusDescription); } @@ -224,7 +229,9 @@ public bool ForEach(KeyValuePair item) private struct ActivityStatusTagEnumerator : IActivityEnumerator> { - public string StatusCode { get; private set; } + public bool IsValid { get; private set; } + + public StatusCode StatusCode { get; private set; } public string StatusDescription { get; private set; } @@ -233,14 +240,15 @@ public bool ForEach(KeyValuePair item) switch (item.Key) { case SpanAttributeConstants.StatusCodeKey: - this.StatusCode = item.Value as string; + this.StatusCode = (StatusCode)item.Value; + this.IsValid = Enum.IsDefined(typeof(StatusCode), item.Value); break; case SpanAttributeConstants.StatusDescriptionKey: this.StatusDescription = item.Value as string; break; } - return this.StatusCode == null || this.StatusDescription == null; + return this.IsValid || this.StatusDescription == null; } } diff --git a/src/OpenTelemetry.Api/Trace/SpanHelper.cs b/src/OpenTelemetry.Api/Trace/SpanHelper.cs index ef9fc411e5c..33d4363a1fb 100644 --- a/src/OpenTelemetry.Api/Trace/SpanHelper.cs +++ b/src/OpenTelemetry.Api/Trace/SpanHelper.cs @@ -14,9 +14,6 @@ // limitations under the License. // -using System; -using System.Collections.Generic; - namespace OpenTelemetry.Trace { /// @@ -24,93 +21,22 @@ namespace OpenTelemetry.Trace /// public static class SpanHelper { -#pragma warning disable CA1805 // Do not initialize unnecessarily - private static readonly Status DefaultStatus = default; -#pragma warning restore CA1805 // Do not initialize unnecessarily - private static readonly Dictionary StatusCanonicalCodeToStringCache = new Dictionary() - { - [StatusCanonicalCode.Ok] = StatusCanonicalCode.Ok.ToString(), - [StatusCanonicalCode.Cancelled] = StatusCanonicalCode.Cancelled.ToString(), - [StatusCanonicalCode.Unknown] = StatusCanonicalCode.Unknown.ToString(), - [StatusCanonicalCode.InvalidArgument] = StatusCanonicalCode.InvalidArgument.ToString(), - [StatusCanonicalCode.DeadlineExceeded] = StatusCanonicalCode.DeadlineExceeded.ToString(), - [StatusCanonicalCode.NotFound] = StatusCanonicalCode.NotFound.ToString(), - [StatusCanonicalCode.AlreadyExists] = StatusCanonicalCode.AlreadyExists.ToString(), - [StatusCanonicalCode.PermissionDenied] = StatusCanonicalCode.PermissionDenied.ToString(), - [StatusCanonicalCode.ResourceExhausted] = StatusCanonicalCode.ResourceExhausted.ToString(), - [StatusCanonicalCode.FailedPrecondition] = StatusCanonicalCode.FailedPrecondition.ToString(), - [StatusCanonicalCode.Aborted] = StatusCanonicalCode.Aborted.ToString(), - [StatusCanonicalCode.OutOfRange] = StatusCanonicalCode.OutOfRange.ToString(), - [StatusCanonicalCode.Unimplemented] = StatusCanonicalCode.Unimplemented.ToString(), - [StatusCanonicalCode.Internal] = StatusCanonicalCode.Internal.ToString(), - [StatusCanonicalCode.Unavailable] = StatusCanonicalCode.Unavailable.ToString(), - [StatusCanonicalCode.DataLoss] = StatusCanonicalCode.DataLoss.ToString(), - [StatusCanonicalCode.Unauthenticated] = StatusCanonicalCode.Unauthenticated.ToString(), - }; - - /// - /// Helper method that returns the string version of a using a cache to save on allocations. - /// - /// . - /// String version of the supplied . - public static string GetCachedCanonicalCodeString(StatusCanonicalCode statusCanonicalCode) - { - if (!StatusCanonicalCodeToStringCache.TryGetValue(statusCanonicalCode, out string canonicalCode)) - { - return statusCanonicalCode.ToString(); - } - - return canonicalCode; - } - /// /// Helper method that populates span properties from http status code according - /// to https://github.com/open-telemetry/opentelemetry-specification/blob/2316771e7e0ca3bfe9b2286d13e3a41ded6b8858/specification/data-http.md. + /// to https://github.com/open-telemetry/opentelemetry-specification/blob/master/specification/trace/semantic_conventions/http.md#status. /// /// Http status code. /// Resolved span for the Http status code. public static Status ResolveSpanStatusForHttpStatusCode(int httpStatusCode) { - var newStatus = Status.Unknown; + var status = Status.Error; if (httpStatusCode >= 100 && httpStatusCode <= 399) { - newStatus = Status.Ok; - } - else if (httpStatusCode == 400) - { - newStatus = Status.InvalidArgument; - } - else if (httpStatusCode == 401) - { - newStatus = Status.Unauthenticated; - } - else if (httpStatusCode == 403) - { - newStatus = Status.PermissionDenied; - } - else if (httpStatusCode == 404) - { - newStatus = Status.NotFound; - } - else if (httpStatusCode == 429) - { - newStatus = Status.ResourceExhausted; - } - else if (httpStatusCode == 501) - { - newStatus = Status.Unimplemented; - } - else if (httpStatusCode == 503) - { - newStatus = Status.Unavailable; - } - else if (httpStatusCode == 504) - { - newStatus = Status.DeadlineExceeded; + status = Status.Unset; } - return newStatus; + return status; } /// @@ -121,51 +47,17 @@ public static Status ResolveSpanStatusForHttpStatusCode(int httpStatusCode) /// Resolved span for the Grpc status code. public static Status ResolveSpanStatusForGrpcStatusCode(int statusCode) { - var newStatus = Status.Unknown; + var status = Status.Error; if (typeof(StatusCanonicalCode).IsEnumDefined(statusCode)) { - newStatus = new Status((StatusCanonicalCode)statusCode); + status = ((StatusCanonicalCode)statusCode) switch + { + StatusCanonicalCode.Ok => Status.Unset, + _ => Status.Error, + }; } - return newStatus; - } - - /// - /// Helper method that returns Status from to save on allocations. - /// - /// . - /// Resolved span for the Canonical status code. - public static Status ResolveCanonicalCodeToStatus(string statusCanonicalCode) - { - bool success = Enum.TryParse(statusCanonicalCode, out StatusCanonicalCode canonicalCode); - - if (!success) - { - return DefaultStatus; - } - - var status = canonicalCode switch - { - StatusCanonicalCode.Cancelled => Status.Cancelled, - StatusCanonicalCode.Unknown => Status.Unknown, - StatusCanonicalCode.InvalidArgument => Status.InvalidArgument, - StatusCanonicalCode.DeadlineExceeded => Status.DeadlineExceeded, - StatusCanonicalCode.NotFound => Status.NotFound, - StatusCanonicalCode.AlreadyExists => Status.AlreadyExists, - StatusCanonicalCode.PermissionDenied => Status.PermissionDenied, - StatusCanonicalCode.ResourceExhausted => Status.ResourceExhausted, - StatusCanonicalCode.FailedPrecondition => Status.FailedPrecondition, - StatusCanonicalCode.Aborted => Status.Aborted, - StatusCanonicalCode.OutOfRange => Status.OutOfRange, - StatusCanonicalCode.Unimplemented => Status.Unimplemented, - StatusCanonicalCode.Internal => Status.Internal, - StatusCanonicalCode.Unavailable => Status.Unavailable, - StatusCanonicalCode.DataLoss => Status.DataLoss, - StatusCanonicalCode.Unauthenticated => Status.Unauthenticated, - _ => Status.Ok, - }; - return status; } } diff --git a/src/OpenTelemetry.Api/Trace/Status.cs b/src/OpenTelemetry.Api/Trace/Status.cs index 090f0760adc..80f6f96be0b 100644 --- a/src/OpenTelemetry.Api/Trace/Status.cs +++ b/src/OpenTelemetry.Api/Trace/Status.cs @@ -24,127 +24,21 @@ namespace OpenTelemetry.Trace /// /// The operation completed successfully. /// - public static readonly Status Ok = new Status(StatusCanonicalCode.Ok); + public static readonly Status Ok = new Status(StatusCode.Ok); /// - /// The operation was cancelled (typically by the caller). + /// The default status. /// - public static readonly Status Cancelled = new Status(StatusCanonicalCode.Cancelled); + public static readonly Status Unset = new Status(StatusCode.Unset); /// - /// Unknown error. An example of where this error may be returned is if a Status value received - /// from another address space belongs to an error-space that is not known in this address space. - /// Also errors raised by APIs that do not return enough error information may be converted to - /// this error. + /// The operation contains an error. /// - public static readonly Status Unknown = new Status(StatusCanonicalCode.Unknown); + public static readonly Status Error = new Status(StatusCode.Error); - /// - /// Client specified an invalid argument. Note that this differs from FAILED_PRECONDITION. - /// INVALID_ARGUMENT indicates arguments that are problematic regardless of the state of the - /// system (e.g., a malformed file name). - /// - public static readonly Status InvalidArgument = new Status(StatusCanonicalCode.InvalidArgument); - - /// - /// Deadline expired before operation could complete. For operations that change the state of the - /// system, this error may be returned even if the operation has completed successfully. For - /// example, a successful response from a server could have been delayed long enough for the - /// deadline to expire. - /// - public static readonly Status DeadlineExceeded = new Status(StatusCanonicalCode.DeadlineExceeded); - - /// - /// Some requested entity (e.g., file or directory) was not found. - /// - public static readonly Status NotFound = new Status(StatusCanonicalCode.NotFound); - - /// - /// Some entity that we attempted to create (e.g., file or directory) already exists. - /// - public static readonly Status AlreadyExists = new Status(StatusCanonicalCode.AlreadyExists); - - /// - /// The caller does not have permission to execute the specified operation. PERMISSION_DENIED - /// must not be used for rejections caused by exhausting some resource (use RESOURCE_EXHAUSTED - /// instead for those errors). PERMISSION_DENIED must not be used if the caller cannot be - /// identified (use UNAUTHENTICATED instead for those errors). - /// - public static readonly Status PermissionDenied = new Status(StatusCanonicalCode.PermissionDenied); - - /// - /// The request does not have valid authentication credentials for the operation. - /// - public static readonly Status Unauthenticated = new Status(StatusCanonicalCode.Unauthenticated); - - /// - /// Some resource has been exhausted, perhaps a per-user quota, or perhaps the entire file system - /// is out of space. - /// - public static readonly Status ResourceExhausted = new Status(StatusCanonicalCode.ResourceExhausted); - - /// - /// Operation was rejected because the system is not in a state required for the operation's - /// execution. For example, directory to be deleted may be non-empty, an rmdir operation is - /// applied to a non-directory, etc. - /// A litmus test that may help a service implementor in deciding between FAILED_PRECONDITION, - /// ABORTED, and UNAVAILABLE: (a) Use UNAVAILABLE if the client can retry just the failing call. - /// (b) Use ABORTED if the client should retry at a higher-level (e.g., restarting a - /// read-modify-write sequence). (c) Use FAILED_PRECONDITION if the client should not retry until - /// the system state has been explicitly fixed. E.g., if an "rmdir" fails because the directory - /// is non-empty, FAILED_PRECONDITION should be returned since the client should not retry unless - /// they have first fixed up the directory by deleting files from it. - /// - public static readonly Status FailedPrecondition = new Status(StatusCanonicalCode.FailedPrecondition); - - /// - /// The operation was aborted, typically due to a concurrency issue like sequencer check - /// failures, transaction aborts, etc. - /// - public static readonly Status Aborted = new Status(StatusCanonicalCode.Aborted); - - /// - /// Operation was attempted past the valid range. E.g., seeking or reading past end of file. - /// - /// Unlike INVALID_ARGUMENT, this error indicates a problem that may be fixed if the system - /// state changes. For example, a 32-bit file system will generate INVALID_ARGUMENT if asked to - /// read at an offset that is not in the range [0,2^32-1], but it will generate OUT_OF_RANGE if - /// asked to read from an offset past the current file size. - /// - /// There is a fair bit of overlap between FAILED_PRECONDITION and OUT_OF_RANGE. We recommend - /// using OUT_OF_RANGE (the more specific error) when it applies so that callers who are - /// iterating through a space can easily look for an OUT_OF_RANGE error to detect when they are - /// done. - /// - public static readonly Status OutOfRange = new Status(StatusCanonicalCode.OutOfRange); - - /// - /// Operation is not implemented or not supported/enabled in this service. - /// - public static readonly Status Unimplemented = new Status(StatusCanonicalCode.Unimplemented); - - /// - /// Internal errors. Means some invariants expected by underlying system has been broken. If you - /// see one of these errors, something is very broken. - /// - public static readonly Status Internal = new Status(StatusCanonicalCode.Internal); - - /// - /// The service is currently unavailable. This is a most likely a transient condition and may be - /// corrected by retrying with a backoff. - /// - /// See litmus test above for deciding between FAILED_PRECONDITION, ABORTED, and UNAVAILABLE. - /// - public static readonly Status Unavailable = new Status(StatusCanonicalCode.Unavailable); - - /// - /// Unrecoverable data loss or corruption. - /// - public static readonly Status DataLoss = new Status(StatusCanonicalCode.DataLoss); - - internal Status(StatusCanonicalCode statusCanonicalCode, string description = null) + internal Status(StatusCode statusCode, string description = null) { - this.CanonicalCode = statusCanonicalCode; + this.StatusCode = statusCode; this.Description = description; this.IsValid = true; } @@ -158,7 +52,7 @@ internal Status(StatusCanonicalCode statusCanonicalCode, string description = nu /// /// Gets the canonical code from this status. /// - public StatusCanonicalCode CanonicalCode { get; } + public StatusCode StatusCode { get; } /// /// Gets the status description. @@ -168,7 +62,7 @@ internal Status(StatusCanonicalCode statusCanonicalCode, string description = nu /// /// Gets a value indicating whether span completed successfully. /// - public bool IsOk => this.CanonicalCode == StatusCanonicalCode.Ok; + public bool IsOk => this.StatusCode == StatusCode.Ok; /// /// Compare two for equality. @@ -196,7 +90,7 @@ public Status WithDescription(string description) return this; } - return new Status(this.CanonicalCode, description); + return new Status(this.StatusCode, description); } /// @@ -208,14 +102,14 @@ public override bool Equals(object obj) } var that = (Status)obj; - return this.IsValid == that.IsValid && this.CanonicalCode == that.CanonicalCode && this.Description == that.Description; + return this.IsValid == that.IsValid && this.StatusCode == that.StatusCode && this.Description == that.Description; } /// public override int GetHashCode() { var result = 1; - result = (31 * result) + this.CanonicalCode.GetHashCode(); + result = (31 * result) + this.StatusCode.GetHashCode(); result = (31 * result) + (this.Description?.GetHashCode() ?? 0); return result; } @@ -225,7 +119,7 @@ public override string ToString() { return nameof(Status) + "{" - + nameof(this.CanonicalCode) + "=" + this.CanonicalCode + ", " + + nameof(this.StatusCode) + "=" + this.StatusCode + ", " + nameof(this.Description) + "=" + this.Description + "}"; } @@ -233,7 +127,7 @@ public override string ToString() /// public bool Equals(Status other) { - return this.IsValid == other.IsValid && this.CanonicalCode == other.CanonicalCode && this.Description == other.Description; + return this.IsValid == other.IsValid && this.StatusCode == other.StatusCode && this.Description == other.Description; } } } diff --git a/test/OpenTelemetry.Tests/Utils/CanonicalCodeExtensions.cs b/src/OpenTelemetry.Api/Trace/StatusCode.cs similarity index 54% rename from test/OpenTelemetry.Tests/Utils/CanonicalCodeExtensions.cs rename to src/OpenTelemetry.Api/Trace/StatusCode.cs index b6fb14a82de..b0cd3e5ac1e 100644 --- a/test/OpenTelemetry.Tests/Utils/CanonicalCodeExtensions.cs +++ b/src/OpenTelemetry.Api/Trace/StatusCode.cs @@ -1,4 +1,4 @@ -// +// // Copyright The OpenTelemetry Authors // // Licensed under the Apache License, Version 2.0 (the "License"); @@ -13,15 +13,27 @@ // See the License for the specific language governing permissions and // limitations under the License. // -using OpenTelemetry.Trace; -namespace OpenTelemetry.Utils +namespace OpenTelemetry.Trace { - internal static class CanonicalCodeExtensions + /// + /// Canonical result code of span execution. + /// + public enum StatusCode { - public static Status ToStatus(this StatusCanonicalCode code) - { - return new Status(code); - } + /// + /// The default status. + /// + Unset = 0, + + /// + /// The operation contains an error. + /// + Error = 1, + + /// + /// The operation completed successfully. + /// + Ok = 2, } } diff --git a/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/Implementation/ActivityExtensions.cs b/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/Implementation/ActivityExtensions.cs index e2479527231..250d08d2c0b 100644 --- a/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/Implementation/ActivityExtensions.cs +++ b/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/Implementation/ActivityExtensions.cs @@ -145,7 +145,7 @@ private static OtlpTrace.Status ToOtlpStatus(Status status) var otlpStatus = new Opentelemetry.Proto.Trace.V1.Status { // The numerical values of the two enumerations match, a simple cast is enough. - Code = (OtlpTrace.Status.Types.StatusCode)status.CanonicalCode, + Code = (OtlpTrace.Status.Types.StatusCode)status.StatusCode, }; if (!string.IsNullOrEmpty(status.Description)) diff --git a/src/OpenTelemetry.Instrumentation.GrpcNetClient/GrpcTagHelper.cs b/src/OpenTelemetry.Instrumentation.GrpcNetClient/GrpcTagHelper.cs index 6be3f1f76fc..77cd8686844 100644 --- a/src/OpenTelemetry.Instrumentation.GrpcNetClient/GrpcTagHelper.cs +++ b/src/OpenTelemetry.Instrumentation.GrpcNetClient/GrpcTagHelper.cs @@ -37,7 +37,7 @@ public static string GetGrpcMethodFromActivity(Activity activity) public static Status GetGrpcStatusCodeFromActivity(Activity activity) { - var status = Status.Unknown; + var status = Status.Unset; var grpcStatusCodeTag = activity.GetTagValue(GrpcStatusCodeTagName); if (int.TryParse(grpcStatusCodeTag as string, out var statusCode)) diff --git a/src/OpenTelemetry.Instrumentation.Http/Implementation/HttpHandlerDiagnosticListener.cs b/src/OpenTelemetry.Instrumentation.Http/Implementation/HttpHandlerDiagnosticListener.cs index cc307838829..6e9213cb974 100644 --- a/src/OpenTelemetry.Instrumentation.Http/Implementation/HttpHandlerDiagnosticListener.cs +++ b/src/OpenTelemetry.Instrumentation.Http/Implementation/HttpHandlerDiagnosticListener.cs @@ -137,12 +137,12 @@ public override void OnStopActivity(Activity activity, object payload) { if (requestTaskStatus == TaskStatus.Canceled) { - activity.SetStatus(Status.Cancelled); + activity.SetStatus(Status.Error); } else if (requestTaskStatus != TaskStatus.Faulted) { // Faults are handled in OnException and should already have a span.Status of Unknown w/ Description. - activity.SetStatus(Status.Unknown); + activity.SetStatus(Status.Error); } } @@ -195,14 +195,14 @@ public override void OnException(Activity activity, object payload) switch (exception.SocketErrorCode) { case SocketError.HostNotFound: - activity.SetStatus(Status.InvalidArgument.WithDescription(exc.Message)); + activity.SetStatus(Status.Error.WithDescription(exc.Message)); return; } } if (exc.InnerException != null) { - activity.SetStatus(Status.Unknown.WithDescription(exc.Message)); + activity.SetStatus(Status.Error.WithDescription(exc.Message)); } } } diff --git a/src/OpenTelemetry.Instrumentation.Http/Implementation/HttpWebRequestActivitySource.netfx.cs b/src/OpenTelemetry.Instrumentation.Http/Implementation/HttpWebRequestActivitySource.netfx.cs index 1221f09eb52..29eab31b312 100644 --- a/src/OpenTelemetry.Instrumentation.Http/Implementation/HttpWebRequestActivitySource.netfx.cs +++ b/src/OpenTelemetry.Instrumentation.Http/Implementation/HttpWebRequestActivitySource.netfx.cs @@ -154,35 +154,26 @@ private static void AddExceptionTags(Exception exception, Activity activity) switch (wexc.Status) { case WebExceptionStatus.Timeout: - status = Status.DeadlineExceeded; - break; - case WebExceptionStatus.NameResolutionFailure: - status = Status.InvalidArgument.WithDescription(exception.Message); + case WebExceptionStatus.RequestCanceled: + status = Status.Error; break; case WebExceptionStatus.SendFailure: case WebExceptionStatus.ConnectFailure: case WebExceptionStatus.SecureChannelFailure: case WebExceptionStatus.TrustFailure: - status = Status.FailedPrecondition.WithDescription(exception.Message); - break; case WebExceptionStatus.ServerProtocolViolation: - status = Status.Unimplemented.WithDescription(exception.Message); - break; - case WebExceptionStatus.RequestCanceled: - status = Status.Cancelled; - break; case WebExceptionStatus.MessageLengthLimitExceeded: - status = Status.ResourceExhausted.WithDescription(exception.Message); + status = Status.Error.WithDescription(exception.Message); break; default: - status = Status.Unknown.WithDescription(exception.Message); + status = Status.Error.WithDescription(exception.Message); break; } } } else { - status = Status.Unknown.WithDescription(exception.Message); + status = Status.Error.WithDescription(exception.Message); } activity.SetStatus(status); diff --git a/src/OpenTelemetry.Instrumentation.SqlClient/Implementation/SqlClientDiagnosticListener.cs b/src/OpenTelemetry.Instrumentation.SqlClient/Implementation/SqlClientDiagnosticListener.cs index 9cf58bea0a4..485e0ee3a72 100644 --- a/src/OpenTelemetry.Instrumentation.SqlClient/Implementation/SqlClientDiagnosticListener.cs +++ b/src/OpenTelemetry.Instrumentation.SqlClient/Implementation/SqlClientDiagnosticListener.cs @@ -155,7 +155,7 @@ public override void OnCustom(string name, Activity activity, object payload) { if (activity.IsAllDataRequested) { - activity.SetStatus(Status.Ok); + activity.SetStatus(Status.Unset); } } finally @@ -185,7 +185,7 @@ public override void OnCustom(string name, Activity activity, object payload) { if (this.exceptionFetcher.Fetch(payload) is Exception exception) { - activity.SetStatus(Status.Unknown.WithDescription(exception.Message)); + activity.SetStatus(Status.Error.WithDescription(exception.Message)); } else { diff --git a/src/OpenTelemetry.Instrumentation.SqlClient/Implementation/SqlEventSourceListener.netfx.cs b/src/OpenTelemetry.Instrumentation.SqlClient/Implementation/SqlEventSourceListener.netfx.cs index b969aaff5de..0e1570f1525 100644 --- a/src/OpenTelemetry.Instrumentation.SqlClient/Implementation/SqlEventSourceListener.netfx.cs +++ b/src/OpenTelemetry.Instrumentation.SqlClient/Implementation/SqlEventSourceListener.netfx.cs @@ -163,11 +163,11 @@ private void OnEndExecute(EventWrittenEventArgs eventData) } else if ((compositeState & 0b010) == 0b010) { - activity.SetStatus(Status.Unknown.WithDescription($"SqlExceptionNumber {eventData.Payload[2]} thrown.")); + activity.SetStatus(Status.Error.WithDescription($"SqlExceptionNumber {eventData.Payload[2]} thrown.")); } else { - activity.SetStatus(Status.Unknown.WithDescription("Unknown Sql failure.")); + activity.SetStatus(Status.Error.WithDescription("Unknown Sql failure.")); } } } diff --git a/src/OpenTelemetry.Instrumentation.StackExchangeRedis/Implementation/RedisProfilerEntryToActivityConverter.cs b/src/OpenTelemetry.Instrumentation.StackExchangeRedis/Implementation/RedisProfilerEntryToActivityConverter.cs index 78bcda69b26..86ffbfa4b1c 100644 --- a/src/OpenTelemetry.Instrumentation.StackExchangeRedis/Implementation/RedisProfilerEntryToActivityConverter.cs +++ b/src/OpenTelemetry.Instrumentation.StackExchangeRedis/Implementation/RedisProfilerEntryToActivityConverter.cs @@ -57,7 +57,7 @@ public static Activity ProfilerCommandToActivity(Activity parentActivity, IProfi // Total: // command.ElapsedTime; // 00:00:32.4988020 - activity.SetStatus(Status.Ok); + activity.SetStatus(Status.Unset); activity.SetTag(SemanticConventions.AttributeDbSystem, "redis"); activity.SetTag(StackExchangeRedisCallsInstrumentation.RedisFlagsKeyName, command.Flags.ToString()); diff --git a/src/OpenTelemetry.Shims.OpenTracing/SpanBuilderShim.cs b/src/OpenTelemetry.Shims.OpenTracing/SpanBuilderShim.cs index 12caa0740fd..4dfef20cc99 100644 --- a/src/OpenTelemetry.Shims.OpenTracing/SpanBuilderShim.cs +++ b/src/OpenTelemetry.Shims.OpenTracing/SpanBuilderShim.cs @@ -191,7 +191,7 @@ public ISpan Start() if (this.error) { - span.SetStatus(Trace.Status.Unknown); + span.SetStatus(Trace.Status.Error); } return new SpanShim(span); diff --git a/src/OpenTelemetry.Shims.OpenTracing/SpanShim.cs b/src/OpenTelemetry.Shims.OpenTracing/SpanShim.cs index 00dce07fec6..6effe7ed577 100644 --- a/src/OpenTelemetry.Shims.OpenTracing/SpanShim.cs +++ b/src/OpenTelemetry.Shims.OpenTracing/SpanShim.cs @@ -206,7 +206,7 @@ public string GetBaggageItem(string key) // see https://opentracing.io/specification/conventions/ if (global::OpenTracing.Tag.Tags.Error.Key.Equals(key, StringComparison.Ordinal)) { - this.Span.SetStatus(value ? Trace.Status.Unknown : Trace.Status.Ok); + this.Span.SetStatus(value ? Trace.Status.Error : Trace.Status.Ok); } else { diff --git a/test/OpenTelemetry.Exporter.OpenTelemetryProtocol.Tests/OtlpExporterTest.cs b/test/OpenTelemetry.Exporter.OpenTelemetryProtocol.Tests/OtlpExporterTest.cs index 3cb0d37bc6d..9b8440afcf3 100644 --- a/test/OpenTelemetry.Exporter.OpenTelemetryProtocol.Tests/OtlpExporterTest.cs +++ b/test/OpenTelemetry.Exporter.OpenTelemetryProtocol.Tests/OtlpExporterTest.cs @@ -202,7 +202,7 @@ public void ToOtlpSpanTest() rootActivity.Context, links: childLinks); - childActivity.SetStatus(Status.NotFound); + childActivity.SetStatus(Status.Error); var childEvents = new List { new ActivityEvent("e0"), new ActivityEvent("e1", default, new ActivityTagsCollection(attributes)) }; childActivity.AddEvent(childEvents[0]); @@ -219,8 +219,10 @@ public void ToOtlpSpanTest() Assert.Equal(OtlpTrace.Span.Types.SpanKind.Client, otlpSpan.Kind); Assert.Equal(traceId, otlpSpan.TraceId); Assert.Equal(parentId, otlpSpan.ParentSpanId); - Assert.Equal(OtlpTrace.Status.Types.StatusCode.NotFound, otlpSpan.Status.Code); - Assert.Equal(Status.NotFound.Description ?? string.Empty, otlpSpan.Status.Message); + + // Assert.Equal(OtlpTrace.Status.Types.StatusCode.NotFound, otlpSpan.Status.Code); + + Assert.Equal(Status.Error.Description ?? string.Empty, otlpSpan.Status.Message); Assert.Empty(otlpSpan.Attributes); Assert.Equal(childEvents.Count, otlpSpan.Events.Count); diff --git a/test/OpenTelemetry.Instrumentation.AspNet.Tests/HttpInListenerTests.cs b/test/OpenTelemetry.Instrumentation.AspNet.Tests/HttpInListenerTests.cs index 4d0f0bcb79a..26988eb7f4d 100644 --- a/test/OpenTelemetry.Instrumentation.AspNet.Tests/HttpInListenerTests.cs +++ b/test/OpenTelemetry.Instrumentation.AspNet.Tests/HttpInListenerTests.cs @@ -215,7 +215,7 @@ public void AspNetRequestsAreCollectedSuccessfully( Assert.True(span.Duration != TimeSpan.Zero); Assert.Equal(200, span.GetTagValue(SemanticConventions.AttributeHttpStatusCode)); - Assert.Equal("Ok", span.GetTagValue(SpanAttributeConstants.StatusCodeKey)); + Assert.Equal((int)StatusCode.Unset, span.GetTagValue(SpanAttributeConstants.StatusCodeKey)); Assert.Equal("OK", span.GetTagValue(SpanAttributeConstants.StatusDescriptionKey)); var expectedUri = new Uri(url); diff --git a/test/OpenTelemetry.Instrumentation.AspNetCore.Tests/IncomingRequestsCollectionsIsAccordingToTheSpecTests.cs b/test/OpenTelemetry.Instrumentation.AspNetCore.Tests/IncomingRequestsCollectionsIsAccordingToTheSpecTests.cs index 802d43009ce..8408961544c 100644 --- a/test/OpenTelemetry.Instrumentation.AspNetCore.Tests/IncomingRequestsCollectionsIsAccordingToTheSpecTests.cs +++ b/test/OpenTelemetry.Instrumentation.AspNetCore.Tests/IncomingRequestsCollectionsIsAccordingToTheSpecTests.cs @@ -105,7 +105,7 @@ public async Task SuccessfulTemplateControllerCallGeneratesASpan( Assert.Equal(statusCode, activity.GetTagValue(SemanticConventions.AttributeHttpStatusCode)); Status status = SpanHelper.ResolveSpanStatusForHttpStatusCode(statusCode); - Assert.Equal(SpanHelper.GetCachedCanonicalCodeString(status.CanonicalCode), activity.GetTagValue(SpanAttributeConstants.StatusCodeKey)); + Assert.Equal((int)status.StatusCode, activity.GetTagValue(SpanAttributeConstants.StatusCodeKey)); this.ValidateTagValue(activity, SpanAttributeConstants.StatusDescriptionKey, reasonPhrase); this.ValidateTagValue(activity, SemanticConventions.AttributeHttpUserAgent, userAgent); } diff --git a/test/OpenTelemetry.Instrumentation.Grpc.Tests/GrpcTagHelperTests.cs b/test/OpenTelemetry.Instrumentation.Grpc.Tests/GrpcTagHelperTests.cs index 6ecb5f09ca0..5a9c4281fe4 100644 --- a/test/OpenTelemetry.Instrumentation.Grpc.Tests/GrpcTagHelperTests.cs +++ b/test/OpenTelemetry.Instrumentation.Grpc.Tests/GrpcTagHelperTests.cs @@ -57,7 +57,7 @@ public void GrpcTagHelper_GetGrpcStatusCodeFromActivity() var statusCode = GrpcTagHelper.GetGrpcStatusCodeFromActivity(activity); - Assert.Equal(StatusCanonicalCode.Ok, statusCode.CanonicalCode); + Assert.Equal(StatusCode.Unset, statusCode.StatusCode); } } } diff --git a/test/OpenTelemetry.Instrumentation.Grpc.Tests/GrpcTests.client.cs b/test/OpenTelemetry.Instrumentation.Grpc.Tests/GrpcTests.client.cs index 48a0f5aea5e..1357d09dd0c 100644 --- a/test/OpenTelemetry.Instrumentation.Grpc.Tests/GrpcTests.client.cs +++ b/test/OpenTelemetry.Instrumentation.Grpc.Tests/GrpcTests.client.cs @@ -92,7 +92,7 @@ public void GrpcClientCallsAreCollectedSuccessfully(string baseAddress, bool sho } Assert.Equal(uri.Port, activity.GetTagValue(SemanticConventions.AttributeNetPeerPort)); - Assert.Equal(Status.Ok, activity.GetStatus()); + Assert.Equal(Status.Unset, activity.GetStatus()); Assert.Equal(expectedResource, activity.GetResource()); // Tags added by the library then removed from the instrumentation diff --git a/test/OpenTelemetry.Instrumentation.Grpc.Tests/GrpcTests.server.cs b/test/OpenTelemetry.Instrumentation.Grpc.Tests/GrpcTests.server.cs index c399eb285db..befd435c229 100644 --- a/test/OpenTelemetry.Instrumentation.Grpc.Tests/GrpcTests.server.cs +++ b/test/OpenTelemetry.Instrumentation.Grpc.Tests/GrpcTests.server.cs @@ -60,7 +60,7 @@ public void GrpcAspNetCoreInstrumentationAddsCorrectAttributes() Assert.Equal("SayHello", activity.GetTagValue(SemanticConventions.AttributeRpcMethod)); Assert.Contains(activity.GetTagValue(SemanticConventions.AttributeNetPeerIp), clientLoopbackAddresses); Assert.NotEqual(0, activity.GetTagValue(SemanticConventions.AttributeNetPeerPort)); - Assert.Equal(Status.Ok, activity.GetStatus()); + Assert.Equal(Status.Unset, activity.GetStatus()); // The following are http.* attributes that are also included on the span for the gRPC invocation. Assert.Equal($"localhost:{this.fixture.Port}", activity.GetTagValue(SemanticConventions.AttributeHttpHost)); diff --git a/test/OpenTelemetry.Instrumentation.Http.Tests/HttpClientTests.netcore31.cs b/test/OpenTelemetry.Instrumentation.Http.Tests/HttpClientTests.netcore31.cs index bb4ee606e7f..2f75d8d6144 100644 --- a/test/OpenTelemetry.Instrumentation.Http.Tests/HttpClientTests.netcore31.cs +++ b/test/OpenTelemetry.Instrumentation.Http.Tests/HttpClientTests.netcore31.cs @@ -98,31 +98,17 @@ public async Task HttpOutCallsAreCollectedSuccessfullyAsync(HttpTestData.HttpOut Assert.Equal(ActivityKind.Client, activity.Kind); Assert.Equal(tc.SpanName, activity.DisplayName); - var d = new Dictionary() + var d = new Dictionary() { - { "Ok", "OK" }, - { "Cancelled", "CANCELLED" }, - { "Unknown", "UNKNOWN" }, - { "InvalidArgument", "INVALID_ARGUMENT" }, - { "DeadlineExceeded", "DEADLINE_EXCEEDED" }, - { "NotFound", "NOT_FOUND" }, - { "AlreadyExists", "ALREADY_EXISTS" }, - { "PermissionDenied", "PERMISSION_DENIED" }, - { "ResourceExhausted", "RESOURCE_EXHAUSTED" }, - { "FailedPrecondition", "FAILED_PRECONDITION" }, - { "Aborted", "ABORTED" }, - { "OutOfRange", "OUT_OF_RANGE" }, - { "Unimplemented", "UNIMPLEMENTED" }, - { "Internal", "INTERNAL" }, - { "Unavailable", "UNAVAILABLE" }, - { "DataLoss", "DATA_LOSS" }, - { "Unauthenticated", "UNAUTHENTICATED" }, + { (int)StatusCode.Ok, "OK" }, + { (int)StatusCode.Error, "ERROR" }, + { (int)StatusCode.Unset, "UNSET" }, }; // Assert.Equal(tc.SpanStatus, d[span.Status.CanonicalCode]); Assert.Equal( tc.SpanStatus, - d[activity.GetTagValue(SpanAttributeConstants.StatusCodeKey) as string]); + d[(int)activity.GetTagValue(SpanAttributeConstants.StatusCodeKey)]); if (tc.SpanStatusHasDescription.HasValue) { @@ -155,7 +141,7 @@ public async Task DebugIndividualTestAsync() ""url"": ""http://{host}:{port}/"", ""responseCode"": 399, ""spanName"": ""HTTP GET"", - ""spanStatus"": ""OK"", + ""spanStatus"": ""UNSET"", ""spanKind"": ""Client"", ""spanAttributes"": { ""http.method"": ""GET"", diff --git a/test/OpenTelemetry.Instrumentation.Http.Tests/HttpWebRequestTests.netfx.cs b/test/OpenTelemetry.Instrumentation.Http.Tests/HttpWebRequestTests.netfx.cs index 309e4d8ea60..b161282f7f7 100644 --- a/test/OpenTelemetry.Instrumentation.Http.Tests/HttpWebRequestTests.netfx.cs +++ b/test/OpenTelemetry.Instrumentation.Http.Tests/HttpWebRequestTests.netfx.cs @@ -87,25 +87,11 @@ public void HttpOutCallsAreCollectedSuccessfullyAsync(HttpTestData.HttpOutTestCa ValidateHttpWebRequestActivity(activity, expectedResource, tc.ResponseExpected); Assert.Equal(tc.SpanName, activity.DisplayName); - var d = new Dictionary() + var d = new Dictionary() { - { StatusCanonicalCode.Ok.ToString(), "OK" }, - { StatusCanonicalCode.Cancelled.ToString(), "CANCELLED" }, - { StatusCanonicalCode.Unknown.ToString(), "UNKNOWN" }, - { StatusCanonicalCode.InvalidArgument.ToString(), "INVALID_ARGUMENT" }, - { StatusCanonicalCode.DeadlineExceeded.ToString(), "DEADLINE_EXCEEDED" }, - { StatusCanonicalCode.NotFound.ToString(), "NOT_FOUND" }, - { StatusCanonicalCode.AlreadyExists.ToString(), "ALREADY_EXISTS" }, - { StatusCanonicalCode.PermissionDenied.ToString(), "PERMISSION_DENIED" }, - { StatusCanonicalCode.ResourceExhausted.ToString(), "RESOURCE_EXHAUSTED" }, - { StatusCanonicalCode.FailedPrecondition.ToString(), "FAILED_PRECONDITION" }, - { StatusCanonicalCode.Aborted.ToString(), "ABORTED" }, - { StatusCanonicalCode.OutOfRange.ToString(), "OUT_OF_RANGE" }, - { StatusCanonicalCode.Unimplemented.ToString(), "UNIMPLEMENTED" }, - { StatusCanonicalCode.Internal.ToString(), "INTERNAL" }, - { StatusCanonicalCode.Unavailable.ToString(), "UNAVAILABLE" }, - { StatusCanonicalCode.DataLoss.ToString(), "DATA_LOSS" }, - { StatusCanonicalCode.Unauthenticated.ToString(), "UNAUTHENTICATED" }, + { (int)StatusCode.Ok, "OK" }, + { (int)StatusCode.Error, "ERROR" }, + { (int)StatusCode.Unset, "UNSET" }, }; tc.SpanAttributes = tc.SpanAttributes.ToDictionary( @@ -128,7 +114,7 @@ public void HttpOutCallsAreCollectedSuccessfullyAsync(HttpTestData.HttpOutTestCa { if (tag.Key == SpanAttributeConstants.StatusCodeKey) { - Assert.Equal(tc.SpanStatus, d[tagValue]); + Assert.Equal(tc.SpanStatus, d[int.Parse(tagValue)]); continue; } @@ -160,7 +146,7 @@ public void DebugIndividualTestAsync() ""url"": ""http://{host}:{port}/"", ""responseCode"": 200, ""spanName"": ""HTTP GET"", - ""spanStatus"": ""OK"", + ""spanStatus"": ""UNSET"", ""spanKind"": ""Client"", ""setHttpFlavor"": true, ""spanAttributes"": { diff --git a/test/OpenTelemetry.Instrumentation.Http.Tests/http-out-test-cases.json b/test/OpenTelemetry.Instrumentation.Http.Tests/http-out-test-cases.json index 0b41a9bb4d8..af392536287 100644 --- a/test/OpenTelemetry.Instrumentation.Http.Tests/http-out-test-cases.json +++ b/test/OpenTelemetry.Instrumentation.Http.Tests/http-out-test-cases.json @@ -4,7 +4,7 @@ "method": "GET", "url": "http://{host}:{port}/", "spanName": "HTTP GET", - "spanStatus": "OK", + "spanStatus": "UNSET", "responseExpected": true, "spanAttributes": { "http.method": "GET", @@ -18,7 +18,7 @@ "method": "POST", "url": "http://{host}:{port}/", "spanName": "HTTP POST", - "spanStatus": "OK", + "spanStatus": "UNSET", "responseExpected": true, "spanAttributes": { "http.method": "POST", @@ -33,7 +33,7 @@ "url": "http://{host}:{port}/path/to/resource/", "responseCode": 200, "spanName": "HTTP GET", - "spanStatus": "OK", + "spanStatus": "UNSET", "responseExpected": true, "spanAttributes": { "http.method": "GET", @@ -47,7 +47,7 @@ "method": "GET", "url": "https://sdlfaldfjalkdfjlkajdflkajlsdjf.sdlkjafsdjfalfadslkf.com/", "spanName": "HTTP GET", - "spanStatus": "INVALID_ARGUMENT", + "spanStatus": "ERROR", "spanStatusHasDescription": true, "responseExpected" : false, "spanAttributes": { @@ -62,7 +62,7 @@ "url": "http://{host}:{port}/", "responseCode": 200, "spanName": "HTTP GET", - "spanStatus": "OK", + "spanStatus": "UNSET", "responseExpected": true, "spanAttributes": { "http.method": "GET", @@ -77,7 +77,7 @@ "url": "http://{host}:{port}/", "responseCode": 200, "spanName": "HTTP GET", - "spanStatus": "OK", + "spanStatus": "UNSET", "responseExpected": true, "spanAttributes": { "http.method": "GET", @@ -92,7 +92,7 @@ "url": "http://{host}:{port}/", "responseCode": 399, "spanName": "HTTP GET", - "spanStatus": "OK", + "spanStatus": "UNSET", "responseExpected": true, "spanAttributes": { "http.method": "GET", @@ -107,7 +107,7 @@ "url": "http://{host}:{port}/", "responseCode": 400, "spanName": "HTTP GET", - "spanStatus": "INVALID_ARGUMENT", + "spanStatus": "ERROR", "responseExpected": true, "spanAttributes": { "http.method": "GET", @@ -122,7 +122,7 @@ "url": "http://{host}:{port}/", "responseCode": 401, "spanName": "HTTP GET", - "spanStatus": "UNAUTHENTICATED", + "spanStatus": "ERROR", "responseExpected": true, "spanAttributes": { "http.method": "GET", @@ -137,7 +137,7 @@ "url": "http://{host}:{port}/", "responseCode": 403, "spanName": "HTTP GET", - "spanStatus": "PERMISSION_DENIED", + "spanStatus": "ERROR", "responseExpected": true, "spanAttributes": { "http.method": "GET", @@ -152,7 +152,7 @@ "url": "http://{host}:{port}/", "responseCode": 404, "spanName": "HTTP GET", - "spanStatus": "NOT_FOUND", + "spanStatus": "ERROR", "responseExpected": true, "spanAttributes": { "http.method": "GET", @@ -167,7 +167,7 @@ "url": "http://{host}:{port}/", "responseCode": 429, "spanName": "HTTP GET", - "spanStatus": "RESOURCE_EXHAUSTED", + "spanStatus": "ERROR", "responseExpected": true, "spanAttributes": { "http.method": "GET", @@ -182,7 +182,7 @@ "url": "http://{host}:{port}/", "responseCode": 501, "spanName": "HTTP GET", - "spanStatus": "UNIMPLEMENTED", + "spanStatus": "ERROR", "responseExpected": true, "spanAttributes": { "http.method": "GET", @@ -197,7 +197,7 @@ "url": "http://{host}:{port}/", "responseCode": 503, "spanName": "HTTP GET", - "spanStatus": "UNAVAILABLE", + "spanStatus": "ERROR", "responseExpected": true, "spanAttributes": { "http.method": "GET", @@ -212,7 +212,7 @@ "url": "http://{host}:{port}/", "responseCode": 504, "spanName": "HTTP GET", - "spanStatus": "DEADLINE_EXCEEDED", + "spanStatus": "ERROR", "responseExpected": true, "spanAttributes": { "http.method": "GET", @@ -227,7 +227,7 @@ "url": "http://{host}:{port}/", "responseCode": 600, "spanName": "HTTP GET", - "spanStatus": "UNKNOWN", + "spanStatus": "ERROR", "responseExpected": true, "spanAttributes": { "http.method": "GET", @@ -242,7 +242,7 @@ "url": "http://{host}:{port}/", "responseCode": 200, "spanName": "HTTP GET", - "spanStatus": "OK", + "spanStatus": "UNSET", "responseExpected": true, "setHttpFlavor": true, "spanAttributes": { @@ -253,4 +253,4 @@ "http.url": "http://{host}:{port}/" } } -] \ No newline at end of file +] diff --git a/test/OpenTelemetry.Instrumentation.SqlClient.Tests/SqlClientTests.cs b/test/OpenTelemetry.Instrumentation.SqlClient.Tests/SqlClientTests.cs index b22872d1a17..8c08ffc1426 100644 --- a/test/OpenTelemetry.Instrumentation.SqlClient.Tests/SqlClientTests.cs +++ b/test/OpenTelemetry.Instrumentation.SqlClient.Tests/SqlClientTests.cs @@ -275,12 +275,12 @@ private static void VerifyActivityData( if (!isFailure) { - Assert.Equal("Ok", activity.GetTagValue(SpanAttributeConstants.StatusCodeKey)); + Assert.Equal((int)StatusCode.Unset, activity.GetTagValue(SpanAttributeConstants.StatusCodeKey)); Assert.Null(activity.GetTagValue(SpanAttributeConstants.StatusDescriptionKey)); } else { - Assert.Equal("Unknown", activity.GetTagValue(SpanAttributeConstants.StatusCodeKey)); + Assert.Equal((int)StatusCode.Error, activity.GetTagValue(SpanAttributeConstants.StatusCodeKey)); Assert.NotNull(activity.GetTagValue(SpanAttributeConstants.StatusDescriptionKey)); } diff --git a/test/OpenTelemetry.Instrumentation.SqlClient.Tests/SqlEventSourceTests.netfx.cs b/test/OpenTelemetry.Instrumentation.SqlClient.Tests/SqlEventSourceTests.netfx.cs index d67b556e523..af2f4e5bdd6 100644 --- a/test/OpenTelemetry.Instrumentation.SqlClient.Tests/SqlEventSourceTests.netfx.cs +++ b/test/OpenTelemetry.Instrumentation.SqlClient.Tests/SqlEventSourceTests.netfx.cs @@ -229,11 +229,11 @@ private static void VerifyActivityData( if (!isFailure) { - Assert.Equal("Ok", activity.GetTagValue(SpanAttributeConstants.StatusCodeKey)); + Assert.Equal((int)StatusCode.Unset, activity.GetTagValue(SpanAttributeConstants.StatusCodeKey)); } else { - Assert.Equal("Unknown", activity.GetTagValue(SpanAttributeConstants.StatusCodeKey)); + Assert.Equal((int)StatusCode.Error, activity.GetTagValue(SpanAttributeConstants.StatusCodeKey)); Assert.NotNull(activity.GetTagValue(SpanAttributeConstants.StatusDescriptionKey)); } } diff --git a/test/OpenTelemetry.Instrumentation.StackExchangeRedis.Tests/StackExchangeRedisCallsInstrumentationTests.cs b/test/OpenTelemetry.Instrumentation.StackExchangeRedis.Tests/StackExchangeRedisCallsInstrumentationTests.cs index fe8a6ed8cfd..00baf867f75 100644 --- a/test/OpenTelemetry.Instrumentation.StackExchangeRedis.Tests/StackExchangeRedisCallsInstrumentationTests.cs +++ b/test/OpenTelemetry.Instrumentation.StackExchangeRedis.Tests/StackExchangeRedisCallsInstrumentationTests.cs @@ -180,7 +180,7 @@ private static void VerifyActivityData(Activity activity, bool isSet, EndPoint e Assert.Equal("GET", activity.GetTagValue(SemanticConventions.AttributeDbStatement)); } - Assert.Equal(SpanHelper.GetCachedCanonicalCodeString(StatusCanonicalCode.Ok), activity.GetTagValue(SpanAttributeConstants.StatusCodeKey)); + Assert.Equal((int)StatusCode.Unset, activity.GetTagValue(SpanAttributeConstants.StatusCodeKey)); Assert.Equal("redis", activity.GetTagValue(SemanticConventions.AttributeDbSystem)); Assert.Equal(0, activity.GetTagValue(StackExchangeRedisCallsInstrumentation.RedisDatabaseIndexKeyName)); diff --git a/test/OpenTelemetry.Shims.OpenTracing.Tests/SpanBuilderShimTests.cs b/test/OpenTelemetry.Shims.OpenTracing.Tests/SpanBuilderShimTests.cs index f77b7a97cea..8ee3a9d85d9 100644 --- a/test/OpenTelemetry.Shims.OpenTracing.Tests/SpanBuilderShimTests.cs +++ b/test/OpenTelemetry.Shims.OpenTracing.Tests/SpanBuilderShimTests.cs @@ -247,7 +247,7 @@ public void WithTag_KeyIsErrorStringValue() var spanShim = (SpanShim)shim.Start(); // Span status should be set - Assert.Equal(Status.Unknown, spanShim.Span.Activity.GetStatus()); + Assert.Equal(Status.Error, spanShim.Span.Activity.GetStatus()); } [Fact] @@ -293,7 +293,7 @@ public void WithTag_KeyIsErrorBoolValue() var spanShim = (SpanShim)shim.Start(); // Span status should be set - Assert.Equal(Status.Unknown, spanShim.Span.Activity.GetStatus()); + Assert.Equal(Status.Error, spanShim.Span.Activity.GetStatus()); } [Fact] diff --git a/test/OpenTelemetry.Shims.OpenTracing.Tests/SpanShimTests.cs b/test/OpenTelemetry.Shims.OpenTracing.Tests/SpanShimTests.cs index 3c87c14a70f..eba243588f6 100644 --- a/test/OpenTelemetry.Shims.OpenTracing.Tests/SpanShimTests.cs +++ b/test/OpenTelemetry.Shims.OpenTracing.Tests/SpanShimTests.cs @@ -231,7 +231,7 @@ public void SetTagBoolValue() Assert.True((bool)shim.Span.Activity.TagObjects.First().Value); // A boolean tag named "error" is a special case that must be checked - Assert.Equal(Status.Unknown, shim.Span.Activity.GetStatus()); + Assert.Equal(Status.Error, shim.Span.Activity.GetStatus()); shim.SetTag(global::OpenTracing.Tag.Tags.Error.Key, false); Assert.Equal(Status.Ok, shim.Span.Activity.GetStatus()); @@ -282,7 +282,7 @@ public void SetTagBooleanTagValue() Assert.True((bool)shim.Span.Activity.TagObjects.First().Value); // A boolean tag named "error" is a special case that must be checked - Assert.Equal(Status.Unknown, shim.Span.Activity.GetStatus()); + Assert.Equal(Status.Error, shim.Span.Activity.GetStatus()); shim.SetTag(global::OpenTracing.Tag.Tags.Error.Key, false); Assert.Equal(Status.Ok, shim.Span.Activity.GetStatus()); diff --git a/test/OpenTelemetry.Tests/Trace/ActivityExtensionsTest.cs b/test/OpenTelemetry.Tests/Trace/ActivityExtensionsTest.cs index a7cbfd43ca1..87fc165b9af 100644 --- a/test/OpenTelemetry.Tests/Trace/ActivityExtensionsTest.cs +++ b/test/OpenTelemetry.Tests/Trace/ActivityExtensionsTest.cs @@ -51,11 +51,11 @@ public void SetStatusWithDescription() using var source = new ActivitySource(ActivitySourceName); using var activity = source.StartActivity(ActivityName); - activity.SetStatus(Status.NotFound.WithDescription("Not Found")); + activity.SetStatus(Status.Error.WithDescription("Not Found")); activity?.Stop(); var status = activity.GetStatus(); - Assert.Equal(StatusCanonicalCode.NotFound, status.CanonicalCode); + Assert.Equal(StatusCode.Error, status.StatusCode); Assert.Equal("Not Found", status.Description); } @@ -68,10 +68,10 @@ public void SetCancelledStatus() using var source = new ActivitySource(ActivitySourceName); using var activity = source.StartActivity(ActivityName); - activity.SetStatus(Status.Cancelled); + activity.SetStatus(Status.Error); activity?.Stop(); - Assert.True(activity.GetStatus().CanonicalCode.Equals(Status.Cancelled.CanonicalCode)); + Assert.True(activity.GetStatus().StatusCode.Equals(Status.Error.StatusCode)); } [Fact] @@ -97,7 +97,7 @@ public void LastSetStatusWins() using var source = new ActivitySource(ActivitySourceName); using var activity = source.StartActivity(ActivityName); - activity.SetStatus(Status.Cancelled); + activity.SetStatus(Status.Error); activity.SetStatus(Status.Ok); activity?.Stop(); diff --git a/test/OpenTelemetry.Tests/Trace/StatusTest.cs b/test/OpenTelemetry.Tests/Trace/StatusTest.cs index 9fe8162bf13..fed1f735186 100644 --- a/test/OpenTelemetry.Tests/Trace/StatusTest.cs +++ b/test/OpenTelemetry.Tests/Trace/StatusTest.cs @@ -22,7 +22,7 @@ public class StatusTest [Fact] public void Status_Ok() { - Assert.Equal(StatusCanonicalCode.Ok, Status.Ok.CanonicalCode); + Assert.Equal(StatusCode.Ok, Status.Ok.StatusCode); Assert.Null(Status.Ok.Description); Assert.True(Status.Ok.IsOk); } @@ -30,8 +30,8 @@ public void Status_Ok() [Fact] public void CreateStatus_WithDescription() { - var status = Status.Unknown.WithDescription("This is an error."); - Assert.Equal(StatusCanonicalCode.Unknown, status.CanonicalCode); + var status = Status.Error.WithDescription("This is an error."); + Assert.Equal(StatusCode.Error, status.StatusCode); Assert.Equal("This is an error.", status.Description); Assert.False(status.IsOk); } @@ -39,9 +39,9 @@ public void CreateStatus_WithDescription() [Fact] public void Equality() { - var status1 = new Status(StatusCanonicalCode.Ok); - var status2 = new Status(StatusCanonicalCode.Ok); - object status3 = new Status(StatusCanonicalCode.Ok); + var status1 = new Status(StatusCode.Ok); + var status2 = new Status(StatusCode.Ok); + object status3 = new Status(StatusCode.Ok); Assert.Equal(status1, status2); Assert.True(status1 == status2); @@ -51,8 +51,8 @@ public void Equality() [Fact] public void Equality_WithDescription() { - var status1 = new Status(StatusCanonicalCode.Unknown, "error"); - var status2 = new Status(StatusCanonicalCode.Unknown, "error"); + var status1 = new Status(StatusCode.Error, "error"); + var status2 = new Status(StatusCode.Error, "error"); Assert.Equal(status1, status2); Assert.True(status1 == status2); @@ -61,8 +61,8 @@ public void Equality_WithDescription() [Fact] public void Not_Equality() { - var status1 = new Status(StatusCanonicalCode.Ok); - var status2 = new Status(StatusCanonicalCode.Unknown); + var status1 = new Status(StatusCode.Ok); + var status2 = new Status(StatusCode.Error); object notStatus = 1; Assert.NotEqual(status1, status2); @@ -73,8 +73,8 @@ public void Not_Equality() [Fact] public void Not_Equality_WithDescription1() { - var status1 = new Status(StatusCanonicalCode.Ok, "ok"); - var status2 = new Status(StatusCanonicalCode.Unknown, "error"); + var status1 = new Status(StatusCode.Ok, "ok"); + var status2 = new Status(StatusCode.Error, "error"); Assert.NotEqual(status1, status2); Assert.True(status1 != status2); @@ -83,8 +83,8 @@ public void Not_Equality_WithDescription1() [Fact] public void Not_Equality_WithDescription2() { - var status1 = new Status(StatusCanonicalCode.Ok); - var status2 = new Status(StatusCanonicalCode.Unknown, "error"); + var status1 = new Status(StatusCode.Ok); + var status2 = new Status(StatusCode.Error, "error"); Assert.NotEqual(status1, status2); Assert.True(status1 != status2); @@ -93,14 +93,14 @@ public void Not_Equality_WithDescription2() [Fact] public void TestToString() { - var status = new Status(StatusCanonicalCode.Ok); - Assert.Equal($"Status{{CanonicalCode={status.CanonicalCode}, Description={status.Description}}}", status.ToString()); + var status = new Status(StatusCode.Ok); + Assert.Equal($"Status{{StatusCode={status.StatusCode}, Description={status.Description}}}", status.ToString()); } [Fact] public void TestGetHashCode() { - var status = new Status(StatusCanonicalCode.Ok); + var status = new Status(StatusCode.Ok); Assert.NotEqual(0, status.GetHashCode()); } } From 74d864602da0813fec35baabe5a4f33d6c1a9ab8 Mon Sep 17 00:00:00 2001 From: Eddy Nakamura Date: Mon, 12 Oct 2020 08:35:39 -0300 Subject: [PATCH 2/4] fixing sqlclient framework tests --- .../Implementation/SqlEventSourceListener.netfx.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/OpenTelemetry.Instrumentation.SqlClient/Implementation/SqlEventSourceListener.netfx.cs b/src/OpenTelemetry.Instrumentation.SqlClient/Implementation/SqlEventSourceListener.netfx.cs index 0e1570f1525..25e0971d582 100644 --- a/src/OpenTelemetry.Instrumentation.SqlClient/Implementation/SqlEventSourceListener.netfx.cs +++ b/src/OpenTelemetry.Instrumentation.SqlClient/Implementation/SqlEventSourceListener.netfx.cs @@ -159,7 +159,7 @@ private void OnEndExecute(EventWrittenEventArgs eventData) int compositeState = (int)eventData.Payload[1]; if ((compositeState & 0b001) == 0b001) { - activity.SetStatus(Status.Ok); + activity.SetStatus(Status.Unset); } else if ((compositeState & 0b010) == 0b010) { From bbb76e2308965d489fde18ee13916d1d7b894f53 Mon Sep 17 00:00:00 2001 From: Eddy Nakamura Date: Tue, 13 Oct 2020 07:40:02 -0300 Subject: [PATCH 3/4] adding benchmark to status --- .../Trace/ActivityExtensions.cs | 7 ++- test/Benchmarks/Trace/StatusCodeBenchmark.cs | 60 +++++++++++++++++++ 2 files changed, 66 insertions(+), 1 deletion(-) create mode 100644 test/Benchmarks/Trace/StatusCodeBenchmark.cs diff --git a/src/OpenTelemetry.Api/Trace/ActivityExtensions.cs b/src/OpenTelemetry.Api/Trace/ActivityExtensions.cs index 4a75f468b7c..82e56400200 100644 --- a/src/OpenTelemetry.Api/Trace/ActivityExtensions.cs +++ b/src/OpenTelemetry.Api/Trace/ActivityExtensions.cs @@ -229,6 +229,11 @@ public bool ForEach(KeyValuePair item) private struct ActivityStatusTagEnumerator : IActivityEnumerator> { + private static readonly HashSet Hashes = new HashSet + { + StatusCode.Ok, StatusCode.Error, StatusCode.Unset, + }; + public bool IsValid { get; private set; } public StatusCode StatusCode { get; private set; } @@ -241,7 +246,7 @@ public bool ForEach(KeyValuePair item) { case SpanAttributeConstants.StatusCodeKey: this.StatusCode = (StatusCode)item.Value; - this.IsValid = Enum.IsDefined(typeof(StatusCode), item.Value); + this.IsValid = Hashes.Contains(this.StatusCode); break; case SpanAttributeConstants.StatusDescriptionKey: this.StatusDescription = item.Value as string; diff --git a/test/Benchmarks/Trace/StatusCodeBenchmark.cs b/test/Benchmarks/Trace/StatusCodeBenchmark.cs new file mode 100644 index 00000000000..de6672c857e --- /dev/null +++ b/test/Benchmarks/Trace/StatusCodeBenchmark.cs @@ -0,0 +1,60 @@ +// +// Copyright The OpenTelemetry Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +using System; +using System.Collections.Generic; +using BenchmarkDotNet.Attributes; +using OpenTelemetry.Trace; + +namespace Benchmarks.Trace +{ + [MemoryDiagnoser] + public class StatusCodeBenchmark + { + private static readonly HashSet Hashes = new HashSet + { + StatusCode.Ok, StatusCode.Error, StatusCode.Unset, + }; + + [Benchmark] + public void HashSetCheck() + { + object obj = 1; + Hashes.Contains((StatusCode)obj); + } + + [Benchmark] + public void HashSetCheckDoesNotExist() + { + object obj = 100; + Hashes.Contains((StatusCode)obj); + } + + [Benchmark] + public void EnumDefinedCheck() + { + object obj = 1; + Enum.IsDefined(typeof(StatusCode), obj); + } + + [Benchmark] + public void EnumDefinedCheckDoesNotExist() + { + object obj = 100; + Enum.IsDefined(typeof(StatusCode), obj); + } + } +} From 7a0157053d3e12d765496393805e0e002c6c280f Mon Sep 17 00:00:00 2001 From: Eddy Nakamura Date: Tue, 13 Oct 2020 13:37:45 -0300 Subject: [PATCH 4/4] changing from hashset to simple if, readding statuscode for grpc --- .../Trace/ActivityExtensions.cs | 7 +-- .../Implementation/HttpInListener.cs | 3 - .../GrpcClientDiagnosticListener.cs | 3 - test/Benchmarks/Trace/StatusCodeBenchmark.cs | 60 ------------------- .../GrpcTests.client.cs | 2 +- .../GrpcTests.server.cs | 2 +- 6 files changed, 3 insertions(+), 74 deletions(-) delete mode 100644 test/Benchmarks/Trace/StatusCodeBenchmark.cs diff --git a/src/OpenTelemetry.Api/Trace/ActivityExtensions.cs b/src/OpenTelemetry.Api/Trace/ActivityExtensions.cs index 82e56400200..5ab1739d0cd 100644 --- a/src/OpenTelemetry.Api/Trace/ActivityExtensions.cs +++ b/src/OpenTelemetry.Api/Trace/ActivityExtensions.cs @@ -229,11 +229,6 @@ public bool ForEach(KeyValuePair item) private struct ActivityStatusTagEnumerator : IActivityEnumerator> { - private static readonly HashSet Hashes = new HashSet - { - StatusCode.Ok, StatusCode.Error, StatusCode.Unset, - }; - public bool IsValid { get; private set; } public StatusCode StatusCode { get; private set; } @@ -246,7 +241,7 @@ public bool ForEach(KeyValuePair item) { case SpanAttributeConstants.StatusCodeKey: this.StatusCode = (StatusCode)item.Value; - this.IsValid = Hashes.Contains(this.StatusCode); + this.IsValid = this.StatusCode == StatusCode.Error || this.StatusCode == StatusCode.Ok || this.StatusCode == StatusCode.Unset; break; case SpanAttributeConstants.StatusDescriptionKey: this.StatusDescription = item.Value as string; diff --git a/src/OpenTelemetry.Instrumentation.AspNetCore/Implementation/HttpInListener.cs b/src/OpenTelemetry.Instrumentation.AspNetCore/Implementation/HttpInListener.cs index 4d2b35004ed..453671bb74d 100644 --- a/src/OpenTelemetry.Instrumentation.AspNetCore/Implementation/HttpInListener.cs +++ b/src/OpenTelemetry.Instrumentation.AspNetCore/Implementation/HttpInListener.cs @@ -289,9 +289,6 @@ private static void AddGrpcAttributes(Activity activity, string grpcMethod, Http activity.SetTag(SemanticConventions.AttributeNetPeerIp, context.Connection.RemoteIpAddress.ToString()); activity.SetTag(SemanticConventions.AttributeNetPeerPort, context.Connection.RemotePort); activity.SetStatus(GrpcTagHelper.GetGrpcStatusCodeFromActivity(activity)); - - // Remove the grpc.method tag added by the gRPC .NET library - activity.SetTag(GrpcTagHelper.GrpcStatusCodeTagName, null); } } } diff --git a/src/OpenTelemetry.Instrumentation.GrpcNetClient/Implementation/GrpcClientDiagnosticListener.cs b/src/OpenTelemetry.Instrumentation.GrpcNetClient/Implementation/GrpcClientDiagnosticListener.cs index a41862524ce..4b59c88cdd6 100644 --- a/src/OpenTelemetry.Instrumentation.GrpcNetClient/Implementation/GrpcClientDiagnosticListener.cs +++ b/src/OpenTelemetry.Instrumentation.GrpcNetClient/Implementation/GrpcClientDiagnosticListener.cs @@ -100,9 +100,6 @@ public override void OnStopActivity(Activity activity, object payload) if (activity.IsAllDataRequested) { activity.SetStatus(GrpcTagHelper.GetGrpcStatusCodeFromActivity(activity)); - - // Remove the grpc.status_code tag added by the gRPC .NET library - activity.SetTag(GrpcTagHelper.GrpcStatusCodeTagName, null); } this.activitySource.Stop(activity); diff --git a/test/Benchmarks/Trace/StatusCodeBenchmark.cs b/test/Benchmarks/Trace/StatusCodeBenchmark.cs deleted file mode 100644 index de6672c857e..00000000000 --- a/test/Benchmarks/Trace/StatusCodeBenchmark.cs +++ /dev/null @@ -1,60 +0,0 @@ -// -// Copyright The OpenTelemetry Authors -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// - -using System; -using System.Collections.Generic; -using BenchmarkDotNet.Attributes; -using OpenTelemetry.Trace; - -namespace Benchmarks.Trace -{ - [MemoryDiagnoser] - public class StatusCodeBenchmark - { - private static readonly HashSet Hashes = new HashSet - { - StatusCode.Ok, StatusCode.Error, StatusCode.Unset, - }; - - [Benchmark] - public void HashSetCheck() - { - object obj = 1; - Hashes.Contains((StatusCode)obj); - } - - [Benchmark] - public void HashSetCheckDoesNotExist() - { - object obj = 100; - Hashes.Contains((StatusCode)obj); - } - - [Benchmark] - public void EnumDefinedCheck() - { - object obj = 1; - Enum.IsDefined(typeof(StatusCode), obj); - } - - [Benchmark] - public void EnumDefinedCheckDoesNotExist() - { - object obj = 100; - Enum.IsDefined(typeof(StatusCode), obj); - } - } -} diff --git a/test/OpenTelemetry.Instrumentation.Grpc.Tests/GrpcTests.client.cs b/test/OpenTelemetry.Instrumentation.Grpc.Tests/GrpcTests.client.cs index 1357d09dd0c..6f17092053b 100644 --- a/test/OpenTelemetry.Instrumentation.Grpc.Tests/GrpcTests.client.cs +++ b/test/OpenTelemetry.Instrumentation.Grpc.Tests/GrpcTests.client.cs @@ -97,7 +97,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.NotNull(activity.GetTagValue(GrpcTagHelper.GrpcStatusCodeTagName)); } [Theory] diff --git a/test/OpenTelemetry.Instrumentation.Grpc.Tests/GrpcTests.server.cs b/test/OpenTelemetry.Instrumentation.Grpc.Tests/GrpcTests.server.cs index befd435c229..d4703c9bfb9 100644 --- a/test/OpenTelemetry.Instrumentation.Grpc.Tests/GrpcTests.server.cs +++ b/test/OpenTelemetry.Instrumentation.Grpc.Tests/GrpcTests.server.cs @@ -71,7 +71,7 @@ public void GrpcAspNetCoreInstrumentationAddsCorrectAttributes() // Tags added by the library then removed from the instrumentation Assert.Null(activity.GetTagValue(GrpcTagHelper.GrpcMethodTagName)); - Assert.Null(activity.GetTagValue(GrpcTagHelper.GrpcStatusCodeTagName)); + Assert.NotNull(activity.GetTagValue(GrpcTagHelper.GrpcStatusCodeTagName)); } private static void WaitForProcessorInvocations(Mock> spanProcessor, int invocationCount)