diff --git a/examples/Console/TestRedis.cs b/examples/Console/TestRedis.cs index 666f504d038..068f95bf1c4 100644 --- a/examples/Console/TestRedis.cs +++ b/examples/Console/TestRedis.cs @@ -95,9 +95,7 @@ private static void DoWork(IDatabase db, ActivitySource activitySource) } catch (ArgumentOutOfRangeException e) { - // Set status upon error - activity.SetTag(SpanAttributeConstants.StatusCodeKey, (int)Status.Error.StatusCode); - activity.SetTag(SpanAttributeConstants.StatusDescriptionKey, e.ToString()); + activity.SetStatus(Status.Error.WithDescription(e.ToString())); } // Annotate our activity to capture metadata about our operation diff --git a/src/OpenTelemetry.Api/CHANGELOG.md b/src/OpenTelemetry.Api/CHANGELOG.md index 61769a5206a..4a489ec7fbd 100644 --- a/src/OpenTelemetry.Api/CHANGELOG.md +++ b/src/OpenTelemetry.Api/CHANGELOG.md @@ -2,6 +2,13 @@ ## Unreleased +* In order to align with the + [spec](https://github.com/open-telemetry/opentelemetry-specification/blob/master/specification/trace/api.md#set-status) + the `Status` (otel.status_code) tag (added on `Activity` using the `SetStatus` + extension) will now be set as the `Unset`, `Error`, or `Ok` string + representation instead of the `0`, `1`, or `2` integer representation. + ([#1579](https://github.com/open-telemetry/opentelemetry-dotnet/pull/1579)) + ## 1.0.0-rc1.1 Released 2020-Nov-17 diff --git a/src/OpenTelemetry.Api/Internal/ActivityHelperExtensions.cs b/src/OpenTelemetry.Api/Internal/ActivityHelperExtensions.cs index 2e97497e45f..48cc88636cc 100644 --- a/src/OpenTelemetry.Api/Internal/ActivityHelperExtensions.cs +++ b/src/OpenTelemetry.Api/Internal/ActivityHelperExtensions.cs @@ -14,7 +14,6 @@ // limitations under the License. // -using System; using System.Collections.Generic; using System.Diagnostics; using System.Reflection; @@ -34,10 +33,12 @@ internal static class ActivityHelperExtensions /// This extension provides a workaround to retrieve Status from special tags with key name otel.status_code and otel.status_description. /// /// Activity instance. - /// Activity execution status. + /// . + /// Status description. + /// if was found on the supplied Activity. [MethodImpl(MethodImplOptions.AggressiveInlining)] [System.Diagnostics.CodeAnalysis.SuppressMessage("Design", "CA1062:Validate arguments of public methods", Justification = "ActivityProcessor is hot path")] - public static Status GetStatusHelper(this Activity activity) + public static bool TryGetStatus(this Activity activity, out StatusCode statusCode, out string statusDescription) { Debug.Assert(activity != null, "Activity should not be null"); @@ -45,31 +46,16 @@ public static Status GetStatusHelper(this Activity activity) ActivityTagsEnumeratorFactory.Enumerate(activity, ref state); - if (!state.IsValid) + if (!state.StatusCode.HasValue) { - return default; + statusCode = default; + statusDescription = null; + return false; } - Status status; - if (state.StatusCode == StatusCode.Error) - { - status = Status.Error; - } - else if (state.StatusCode == StatusCode.Ok) - { - status = Status.Ok; - } - else - { - status = Status.Unset; - } - - if (!string.IsNullOrEmpty(state.StatusDescription)) - { - return status.WithDescription(state.StatusDescription); - } - - return status; + statusCode = state.StatusCode.Value; + statusDescription = state.StatusDescription; + return true; } /// @@ -193,9 +179,7 @@ public bool ForEach(KeyValuePair item) private struct ActivityStatusTagEnumerator : IActivityEnumerator> { - public bool IsValid; - - public StatusCode StatusCode; + public StatusCode? StatusCode; public string StatusDescription; @@ -204,15 +188,14 @@ public bool ForEach(KeyValuePair item) switch (item.Key) { case SpanAttributeConstants.StatusCodeKey: - this.StatusCode = (StatusCode)item.Value; - this.IsValid = this.StatusCode == StatusCode.Error || this.StatusCode == StatusCode.Ok || this.StatusCode == StatusCode.Unset; + this.StatusCode = StatusHelper.GetStatusCodeForStringName(item.Value as string); break; case SpanAttributeConstants.StatusDescriptionKey: this.StatusDescription = item.Value as string; break; } - return this.IsValid || this.StatusDescription == null; + return !this.StatusCode.HasValue || this.StatusDescription == null; } } diff --git a/src/OpenTelemetry.Api/Internal/SpanHelper.cs b/src/OpenTelemetry.Api/Internal/SpanHelper.cs index 61fdb983867..a1ab8786ce9 100644 --- a/src/OpenTelemetry.Api/Internal/SpanHelper.cs +++ b/src/OpenTelemetry.Api/Internal/SpanHelper.cs @@ -29,14 +29,12 @@ internal static class SpanHelper /// Resolved span for the Http status code. public static Status ResolveSpanStatusForHttpStatusCode(int httpStatusCode) { - var status = Status.Error; - if (httpStatusCode >= 100 && httpStatusCode <= 399) { - status = Status.Unset; + return Status.Unset; } - return status; + return Status.Error; } } } diff --git a/src/OpenTelemetry.Api/Internal/StatusHelper.cs b/src/OpenTelemetry.Api/Internal/StatusHelper.cs new file mode 100644 index 00000000000..b3ce9ac5845 --- /dev/null +++ b/src/OpenTelemetry.Api/Internal/StatusHelper.cs @@ -0,0 +1,58 @@ +// +// 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.Runtime.CompilerServices; +using OpenTelemetry.Trace; + +namespace OpenTelemetry.Internal +{ + internal static class StatusHelper + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static string GetStringNameForStatusCode(StatusCode statusCode) + { + return statusCode switch + { + /* + * Note: Order here does matter for perf. Unset is + * first because assumption is most spans will be + * Unset, then Error. Ok is not set by the SDK. + */ + StatusCode.Unset => "Unset", + StatusCode.Error => "Error", + StatusCode.Ok => "Ok", + _ => null, + }; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static StatusCode? GetStatusCodeForStringName(string statusCodeName) + { + return statusCodeName switch + { + /* + * Note: Order here does matter for perf. Unset is + * first because assumption is most spans will be + * Unset, then Error. Ok is not set by the SDK. + */ + "Unset" => StatusCode.Unset, + "Error" => StatusCode.Error, + "Ok" => StatusCode.Ok, + _ => (StatusCode?)null, + }; + } + } +} diff --git a/src/OpenTelemetry.Api/Trace/ActivityExtensions.cs b/src/OpenTelemetry.Api/Trace/ActivityExtensions.cs index 27ada2b6ad3..4f8e2b07287 100644 --- a/src/OpenTelemetry.Api/Trace/ActivityExtensions.cs +++ b/src/OpenTelemetry.Api/Trace/ActivityExtensions.cs @@ -40,7 +40,7 @@ public static void SetStatus(this Activity activity, Status status) { Debug.Assert(activity != null, "Activity should not be null"); - activity.SetTag(SpanAttributeConstants.StatusCodeKey, (int)status.StatusCode); + activity.SetTag(SpanAttributeConstants.StatusCodeKey, StatusHelper.GetStringNameForStatusCode(status.StatusCode)); activity.SetTag(SpanAttributeConstants.StatusDescriptionKey, status.Description); } @@ -55,7 +55,12 @@ public static void SetStatus(this Activity activity, Status status) [System.Diagnostics.CodeAnalysis.SuppressMessage("Design", "CA1062:Validate arguments of public methods", Justification = "ActivityProcessor is hot path")] public static Status GetStatus(this Activity activity) { - return activity.GetStatusHelper(); + if (!activity.TryGetStatus(out StatusCode statusCode, out string statusDescription)) + { + return Status.Unset; + } + + return new Status(statusCode, statusDescription); } /// diff --git a/src/OpenTelemetry.Exporter.Jaeger/CHANGELOG.md b/src/OpenTelemetry.Exporter.Jaeger/CHANGELOG.md index 40eb1acbe52..0655ac7d142 100644 --- a/src/OpenTelemetry.Exporter.Jaeger/CHANGELOG.md +++ b/src/OpenTelemetry.Exporter.Jaeger/CHANGELOG.md @@ -2,6 +2,9 @@ ## Unreleased +* Jaeger will now set the `error` tag when `otel.status_code` is set to `Error`. + ([#1579](https://github.com/open-telemetry/opentelemetry-dotnet/pull/1579)) + ## 1.0.0-rc1.1 Released 2020-Nov-17 diff --git a/src/OpenTelemetry.Exporter.Jaeger/Implementation/JaegerActivityExtensions.cs b/src/OpenTelemetry.Exporter.Jaeger/Implementation/JaegerActivityExtensions.cs index 03639312751..e78960f6a6b 100644 --- a/src/OpenTelemetry.Exporter.Jaeger/Implementation/JaegerActivityExtensions.cs +++ b/src/OpenTelemetry.Exporter.Jaeger/Implementation/JaegerActivityExtensions.cs @@ -255,6 +255,11 @@ private static void ProcessJaegerTag(ref TagEnumerationState state, string key, if (jaegerTag.VStr != null) { PeerServiceResolver.InspectTag(ref state, key, jaegerTag.VStr); + + if (key == SpanAttributeConstants.StatusCodeKey && jaegerTag.VStr == "Error") + { + PooledList.Add(ref state.Tags, new JaegerTag("error", JaegerTagType.BOOL, vBool: true)); + } } else if (jaegerTag.VLong.HasValue) { diff --git a/src/OpenTelemetry.Exporter.Jaeger/OpenTelemetry.Exporter.Jaeger.csproj b/src/OpenTelemetry.Exporter.Jaeger/OpenTelemetry.Exporter.Jaeger.csproj index 032b860fa59..e1d8845f9bf 100644 --- a/src/OpenTelemetry.Exporter.Jaeger/OpenTelemetry.Exporter.Jaeger.csproj +++ b/src/OpenTelemetry.Exporter.Jaeger/OpenTelemetry.Exporter.Jaeger.csproj @@ -15,6 +15,7 @@ + diff --git a/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/Implementation/ActivityExtensions.cs b/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/Implementation/ActivityExtensions.cs index b08805b8d87..ebbae69c270 100644 --- a/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/Implementation/ActivityExtensions.cs +++ b/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/Implementation/ActivityExtensions.cs @@ -239,7 +239,9 @@ internal static OtlpCommon.KeyValue ToOtlpAttribute(this KeyValuePair Tags; - public int? StatusCode; + public string StatusCode; public string StatusDescription; @@ -396,7 +398,7 @@ public bool ForEach(KeyValuePair activityTag) switch (key) { case SpanAttributeConstants.StatusCodeKey: - this.StatusCode = activityTag.Value as int?; + this.StatusCode = activityTag.Value as string; return true; case SpanAttributeConstants.StatusDescriptionKey: this.StatusDescription = activityTag.Value as string; diff --git a/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/OpenTelemetry.Exporter.OpenTelemetryProtocol.csproj b/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/OpenTelemetry.Exporter.OpenTelemetryProtocol.csproj index c6b00e0d914..e265339da42 100644 --- a/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/OpenTelemetry.Exporter.OpenTelemetryProtocol.csproj +++ b/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/OpenTelemetry.Exporter.OpenTelemetryProtocol.csproj @@ -15,6 +15,7 @@ + diff --git a/src/OpenTelemetry.Exporter.Zipkin/CHANGELOG.md b/src/OpenTelemetry.Exporter.Zipkin/CHANGELOG.md index 2d920ecfa24..1c53505034e 100644 --- a/src/OpenTelemetry.Exporter.Zipkin/CHANGELOG.md +++ b/src/OpenTelemetry.Exporter.Zipkin/CHANGELOG.md @@ -2,6 +2,9 @@ ## Unreleased +* Zipkin will now set the `error` tag when `otel.status_code` is set to `Error`. + ([#1579](https://github.com/open-telemetry/opentelemetry-dotnet/pull/1579)) + ## 1.0.0-rc1.1 Released 2020-Nov-17 diff --git a/src/OpenTelemetry.Exporter.Zipkin/Implementation/ZipkinActivityConversionExtensions.cs b/src/OpenTelemetry.Exporter.Zipkin/Implementation/ZipkinActivityConversionExtensions.cs index f759a510bf1..3851418d1cd 100644 --- a/src/OpenTelemetry.Exporter.Zipkin/Implementation/ZipkinActivityConversionExtensions.cs +++ b/src/OpenTelemetry.Exporter.Zipkin/Implementation/ZipkinActivityConversionExtensions.cs @@ -174,6 +174,11 @@ public bool ForEach(KeyValuePair activityTag) if (activityTag.Value is string strVal) { PeerServiceResolver.InspectTag(ref this, key, strVal); + + if (key == SpanAttributeConstants.StatusCodeKey && strVal == "Error") + { + PooledList>.Add(ref this.Tags, new KeyValuePair("error", "true")); + } } else if (activityTag.Value is int intVal && activityTag.Key == SemanticConventions.AttributeNetPeerPort) { diff --git a/src/OpenTelemetry.Exporter.Zipkin/OpenTelemetry.Exporter.Zipkin.csproj b/src/OpenTelemetry.Exporter.Zipkin/OpenTelemetry.Exporter.Zipkin.csproj index 4e39adbcc5e..4aef8c9eb68 100644 --- a/src/OpenTelemetry.Exporter.Zipkin/OpenTelemetry.Exporter.Zipkin.csproj +++ b/src/OpenTelemetry.Exporter.Zipkin/OpenTelemetry.Exporter.Zipkin.csproj @@ -10,6 +10,7 @@ + diff --git a/src/OpenTelemetry.Instrumentation.AspNet/Implementation/HttpInListener.cs b/src/OpenTelemetry.Instrumentation.AspNet/Implementation/HttpInListener.cs index b2f04522835..9685ecb46b3 100644 --- a/src/OpenTelemetry.Instrumentation.AspNet/Implementation/HttpInListener.cs +++ b/src/OpenTelemetry.Instrumentation.AspNet/Implementation/HttpInListener.cs @@ -180,8 +180,7 @@ public override void OnStopActivity(Activity activity, object payload) if (activityToEnrich.GetStatus().StatusCode == StatusCode.Unset) { - Status status = SpanHelper.ResolveSpanStatusForHttpStatusCode(response.StatusCode); - activityToEnrich.SetStatus(status); + activityToEnrich.SetStatus(SpanHelper.ResolveSpanStatusForHttpStatusCode(response.StatusCode)); } var routeData = context.Request.RequestContext.RouteData; diff --git a/src/OpenTelemetry.Instrumentation.AspNetCore/Implementation/HttpInListener.cs b/src/OpenTelemetry.Instrumentation.AspNetCore/Implementation/HttpInListener.cs index 11ff93e9858..a5a76c8edb2 100644 --- a/src/OpenTelemetry.Instrumentation.AspNetCore/Implementation/HttpInListener.cs +++ b/src/OpenTelemetry.Instrumentation.AspNetCore/Implementation/HttpInListener.cs @@ -171,13 +171,13 @@ public override void OnStopActivity(Activity activity, object payload) { if (activity.GetStatus().StatusCode == StatusCode.Unset) { - SetStatusFromHttpStatusCode(activity, response.StatusCode); + activity.SetStatus(SpanHelper.ResolveSpanStatusForHttpStatusCode(response.StatusCode)); } } #else if (activity.GetStatus().StatusCode == StatusCode.Unset) { - SetStatusFromHttpStatusCode(activity, response.StatusCode); + activity.SetStatus(SpanHelper.ResolveSpanStatusForHttpStatusCode(response.StatusCode)); } #endif @@ -304,13 +304,6 @@ private static string GetUri(HttpRequest request) return builder.ToString(); } - [MethodImpl(MethodImplOptions.AggressiveInlining)] - private static void SetStatusFromHttpStatusCode(Activity activity, int statusCode) - { - var status = SpanHelper.ResolveSpanStatusForHttpStatusCode(statusCode); - activity.SetStatus(status); - } - #if NETSTANDARD2_1 [MethodImpl(MethodImplOptions.AggressiveInlining)] private static bool TryGetGrpcMethod(Activity activity, out string grpcMethod) diff --git a/src/OpenTelemetry.Instrumentation.AspNetCore/OpenTelemetry.Instrumentation.AspNetCore.csproj b/src/OpenTelemetry.Instrumentation.AspNetCore/OpenTelemetry.Instrumentation.AspNetCore.csproj index d9d01184718..9c9c2f36e63 100644 --- a/src/OpenTelemetry.Instrumentation.AspNetCore/OpenTelemetry.Instrumentation.AspNetCore.csproj +++ b/src/OpenTelemetry.Instrumentation.AspNetCore/OpenTelemetry.Instrumentation.AspNetCore.csproj @@ -10,6 +10,7 @@ + diff --git a/src/OpenTelemetry.Instrumentation.GrpcNetClient/OpenTelemetry.Instrumentation.GrpcNetClient.csproj b/src/OpenTelemetry.Instrumentation.GrpcNetClient/OpenTelemetry.Instrumentation.GrpcNetClient.csproj index 9789ab34acd..68b596c9604 100644 --- a/src/OpenTelemetry.Instrumentation.GrpcNetClient/OpenTelemetry.Instrumentation.GrpcNetClient.csproj +++ b/src/OpenTelemetry.Instrumentation.GrpcNetClient/OpenTelemetry.Instrumentation.GrpcNetClient.csproj @@ -9,6 +9,7 @@ + diff --git a/src/OpenTelemetry.Instrumentation.Http/CHANGELOG.md b/src/OpenTelemetry.Instrumentation.Http/CHANGELOG.md index 8dd0e629f44..64c0ee18326 100644 --- a/src/OpenTelemetry.Instrumentation.Http/CHANGELOG.md +++ b/src/OpenTelemetry.Instrumentation.Http/CHANGELOG.md @@ -2,6 +2,10 @@ ## Unreleased +* `otel.status_description` tag will no longer be set to the http status + description/reason phrase for outgoing http spans. + ([#1579](https://github.com/open-telemetry/opentelemetry-dotnet/pull/1579)) + ## 1.0.0-rc1.1 Released 2020-Nov-17 diff --git a/src/OpenTelemetry.Instrumentation.Http/Implementation/HttpHandlerDiagnosticListener.cs b/src/OpenTelemetry.Instrumentation.Http/Implementation/HttpHandlerDiagnosticListener.cs index e728102bd45..0fcb8321390 100644 --- a/src/OpenTelemetry.Instrumentation.Http/Implementation/HttpHandlerDiagnosticListener.cs +++ b/src/OpenTelemetry.Instrumentation.Http/Implementation/HttpHandlerDiagnosticListener.cs @@ -149,10 +149,7 @@ public override void OnStopActivity(Activity activity, object payload) if (currentStatusCode == StatusCode.Unset) { - activity.SetStatus( - SpanHelper - .ResolveSpanStatusForHttpStatusCode((int)response.StatusCode) - .WithDescription(response.ReasonPhrase)); + activity.SetStatus(SpanHelper.ResolveSpanStatusForHttpStatusCode((int)response.StatusCode)); } try diff --git a/src/OpenTelemetry.Instrumentation.Http/Implementation/HttpWebRequestActivitySource.netfx.cs b/src/OpenTelemetry.Instrumentation.Http/Implementation/HttpWebRequestActivitySource.netfx.cs index 4657e860a83..1c669754fc4 100644 --- a/src/OpenTelemetry.Instrumentation.Http/Implementation/HttpWebRequestActivitySource.netfx.cs +++ b/src/OpenTelemetry.Instrumentation.Http/Implementation/HttpWebRequestActivitySource.netfx.cs @@ -122,10 +122,7 @@ private static void AddResponseTags(HttpWebResponse response, Activity activity) { activity.SetTag(SemanticConventions.AttributeHttpStatusCode, (int)response.StatusCode); - activity.SetStatus( - SpanHelper - .ResolveSpanStatusForHttpStatusCode((int)response.StatusCode) - .WithDescription(response.StatusDescription)); + activity.SetStatus(SpanHelper.ResolveSpanStatusForHttpStatusCode((int)response.StatusCode)); try { @@ -153,7 +150,7 @@ private static void AddExceptionTags(Exception exception, Activity activity) { activity.SetTag(SemanticConventions.AttributeHttpStatusCode, (int)response.StatusCode); - status = SpanHelper.ResolveSpanStatusForHttpStatusCode((int)response.StatusCode).WithDescription(response.StatusDescription); + status = SpanHelper.ResolveSpanStatusForHttpStatusCode((int)response.StatusCode); } else { diff --git a/test/OpenTelemetry.Exporter.Jaeger.Tests/Implementation/JaegerActivityConversionTest.cs b/test/OpenTelemetry.Exporter.Jaeger.Tests/Implementation/JaegerActivityConversionTest.cs index 2c83ce810ce..39f7b148a7f 100644 --- a/test/OpenTelemetry.Exporter.Jaeger.Tests/Implementation/JaegerActivityConversionTest.cs +++ b/test/OpenTelemetry.Exporter.Jaeger.Tests/Implementation/JaegerActivityConversionTest.cs @@ -19,6 +19,7 @@ using System.Linq; using OpenTelemetry.Exporter.Jaeger.Implementation; +using OpenTelemetry.Internal; using OpenTelemetry.Resources; using OpenTelemetry.Trace; using Xunit; @@ -434,6 +435,37 @@ public void JaegerActivityConverterTest_NullTagValueTest() Assert.DoesNotContain(jaegerSpan.Tags, t => t.Key == "nullTag"); } + [Theory] + [InlineData(StatusCode.Unset, false)] + [InlineData(StatusCode.Ok, false)] + [InlineData(StatusCode.Error, true)] + public void JaegerActivityConverterTest_Status_ErrorFlagTest(StatusCode statusCode, bool hasErrorFlag) + { + var status = statusCode switch + { + StatusCode.Unset => Status.Unset, + StatusCode.Ok => Status.Ok, + StatusCode.Error => Status.Error, + _ => throw new InvalidOperationException(), + }; + + // Arrange + var activity = CreateTestActivity(status: status); + + // Act + var jaegerSpan = activity.ToJaegerSpan(); + + // Assert + if (hasErrorFlag) + { + Assert.Contains(jaegerSpan.Tags, t => t.Key == "error" && t.VType == JaegerTagType.BOOL && (t.VBool ?? false)); + } + else + { + Assert.DoesNotContain(jaegerSpan.Tags, t => t.Key == "error"); + } + } + internal static Activity CreateTestActivity( bool setAttributes = true, Dictionary additionalAttributes = null, @@ -441,7 +473,8 @@ internal static Activity CreateTestActivity( bool addLinks = true, Resource resource = null, ActivityKind kind = ActivityKind.Client, - bool isRootSpan = false) + bool isRootSpan = false, + Status? status = null) { var startTimestamp = DateTime.UtcNow; var endTimestamp = startTimestamp.AddSeconds(60); @@ -523,6 +556,11 @@ internal static Activity CreateTestActivity( } } + if (status.HasValue) + { + activity.SetStatus(status.Value); + } + activity.SetEndTime(endTimestamp); activity.Stop(); diff --git a/test/OpenTelemetry.Exporter.Zipkin.Tests/Implementation/ZipkinActivityConversionTest.cs b/test/OpenTelemetry.Exporter.Zipkin.Tests/Implementation/ZipkinActivityConversionTest.cs index 4ff02a9d667..49fe736264c 100644 --- a/test/OpenTelemetry.Exporter.Zipkin.Tests/Implementation/ZipkinActivityConversionTest.cs +++ b/test/OpenTelemetry.Exporter.Zipkin.Tests/Implementation/ZipkinActivityConversionTest.cs @@ -14,8 +14,10 @@ // limitations under the License. // +using System; using System.Linq; using OpenTelemetry.Exporter.Zipkin.Implementation; +using OpenTelemetry.Trace; using Xunit; namespace OpenTelemetry.Exporter.Zipkin.Tests.Implementation @@ -84,5 +86,36 @@ public void ToZipkinSpan_NoEvents() Assert.Equal(activity.StartTimeUtc.ToEpochMicroseconds(), zipkinSpan.Timestamp); Assert.Equal((long)activity.Duration.TotalMilliseconds * 1000, zipkinSpan.Duration); } + + [Theory] + [InlineData(StatusCode.Unset, false)] + [InlineData(StatusCode.Ok, false)] + [InlineData(StatusCode.Error, true)] + public void ToZipkinSpan_Status_ErrorFlagTest(StatusCode statusCode, bool hasErrorFlag) + { + var status = statusCode switch + { + StatusCode.Unset => Status.Unset, + StatusCode.Ok => Status.Ok, + StatusCode.Error => Status.Error, + _ => throw new InvalidOperationException(), + }; + + // Arrange + var activity = ZipkinExporterTests.CreateTestActivity(status: status); + + // Act + var zipkinSpan = activity.ToZipkinSpan(DefaultZipkinEndpoint); + + // Assert + if (hasErrorFlag) + { + Assert.Contains(zipkinSpan.Tags.Value, t => t.Key == "error" && (string)t.Value == "true"); + } + else + { + Assert.DoesNotContain(zipkinSpan.Tags.Value, t => t.Key == "error"); + } + } } } diff --git a/test/OpenTelemetry.Exporter.Zipkin.Tests/ZipkinExporterTests.cs b/test/OpenTelemetry.Exporter.Zipkin.Tests/ZipkinExporterTests.cs index af9c9218b4a..85b28276524 100644 --- a/test/OpenTelemetry.Exporter.Zipkin.Tests/ZipkinExporterTests.cs +++ b/test/OpenTelemetry.Exporter.Zipkin.Tests/ZipkinExporterTests.cs @@ -204,7 +204,8 @@ internal static Activity CreateTestActivity( bool addEvents = true, bool addLinks = true, Resource resource = null, - ActivityKind kind = ActivityKind.Client) + ActivityKind kind = ActivityKind.Client, + Status? status = null) { var startTimestamp = DateTime.UtcNow; var endTimestamp = startTimestamp.AddSeconds(60); @@ -286,6 +287,11 @@ internal static Activity CreateTestActivity( } } + if (status.HasValue) + { + activity.SetStatus(status.Value); + } + activity.SetEndTime(endTimestamp); activity.Stop(); diff --git a/test/OpenTelemetry.Instrumentation.AspNet.Tests/OpenTelemetry.Instrumentation.AspNet.Tests.csproj b/test/OpenTelemetry.Instrumentation.AspNet.Tests/OpenTelemetry.Instrumentation.AspNet.Tests.csproj index 1d593462ce2..abaf2a1e27f 100644 --- a/test/OpenTelemetry.Instrumentation.AspNet.Tests/OpenTelemetry.Instrumentation.AspNet.Tests.csproj +++ b/test/OpenTelemetry.Instrumentation.AspNet.Tests/OpenTelemetry.Instrumentation.AspNet.Tests.csproj @@ -18,6 +18,7 @@ + diff --git a/test/OpenTelemetry.Instrumentation.Http.Tests/HttpClientTests.netcore31.cs b/test/OpenTelemetry.Instrumentation.Http.Tests/HttpClientTests.netcore31.cs index 3309497fa3c..21c1cc72a8b 100644 --- a/test/OpenTelemetry.Instrumentation.Http.Tests/HttpClientTests.netcore31.cs +++ b/test/OpenTelemetry.Instrumentation.Http.Tests/HttpClientTests.netcore31.cs @@ -96,17 +96,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() { - { (int)StatusCode.Ok, "OK" }, - { (int)StatusCode.Error, "ERROR" }, - { (int)StatusCode.Unset, "UNSET" }, + { "Ok", "OK" }, + { "Error", "ERROR" }, + { "Unset", "UNSET" }, }; // Assert.Equal(tc.SpanStatus, d[span.Status.CanonicalCode]); Assert.Equal( tc.SpanStatus, - d[(int)activity.GetTagValue(SpanAttributeConstants.StatusCodeKey)]); + d[activity.GetTagValue(SpanAttributeConstants.StatusCodeKey) as string]); if (tc.SpanStatusHasDescription.HasValue) { diff --git a/test/OpenTelemetry.Instrumentation.Http.Tests/HttpWebRequestActivitySourceTests.netfx.cs b/test/OpenTelemetry.Instrumentation.Http.Tests/HttpWebRequestActivitySourceTests.netfx.cs index 581d3bbd929..f6a944a63af 100644 --- a/test/OpenTelemetry.Instrumentation.Http.Tests/HttpWebRequestActivitySourceTests.netfx.cs +++ b/test/OpenTelemetry.Instrumentation.Http.Tests/HttpWebRequestActivitySourceTests.netfx.cs @@ -194,7 +194,7 @@ public async Task TestBasicReceiveAndResponseEvents(string method, string queryS Assert.True(eventRecords.Records.TryDequeue(out var stopEvent)); Assert.Equal("Stop", stopEvent.Key); - VerifyActivityStopTags(200, "OK", activity); + VerifyActivityStopTags(200, activity); } [Theory] @@ -374,7 +374,7 @@ public async Task TestBasicReceiveAndResponseWebRequestEvents(string method, int Assert.True(eventRecords.Records.TryDequeue(out var stopEvent)); Assert.Equal("Stop", stopEvent.Key); - VerifyActivityStopTags(200, "OK", activity); + VerifyActivityStopTags(200, activity); } [Fact] @@ -480,7 +480,7 @@ public async Task TestResponseWithoutContentEvents(string method) Assert.True(eventRecords.Records.TryDequeue(out var stopEvent)); Assert.Equal("Stop", stopEvent.Key); - VerifyActivityStopTags(204, "No Content", activity); + VerifyActivityStopTags(204, activity); } /// @@ -781,10 +781,9 @@ private static void VerifyActivityStartTags(string hostNameAndPort, string metho Assert.Equal(url, activity.GetTagValue(SemanticConventions.AttributeHttpUrl)); } - private static void VerifyActivityStopTags(int statusCode, string statusText, Activity activity) + private static void VerifyActivityStopTags(int statusCode, Activity activity) { Assert.Equal(statusCode, activity.GetTagValue(SemanticConventions.AttributeHttpStatusCode)); - Assert.Equal(statusText, activity.GetTagValue(SpanAttributeConstants.StatusDescriptionKey)); } private static void ActivityEnrichment(Activity activity, string method, object obj) diff --git a/test/OpenTelemetry.Instrumentation.Http.Tests/HttpWebRequestTests.netfx.cs b/test/OpenTelemetry.Instrumentation.Http.Tests/HttpWebRequestTests.netfx.cs index 744be8ca199..88d779d4119 100644 --- a/test/OpenTelemetry.Instrumentation.Http.Tests/HttpWebRequestTests.netfx.cs +++ b/test/OpenTelemetry.Instrumentation.Http.Tests/HttpWebRequestTests.netfx.cs @@ -88,11 +88,11 @@ public void HttpOutCallsAreCollectedSuccessfully(HttpTestData.HttpOutTestCase tc ValidateHttpWebRequestActivity(activity); Assert.Equal(tc.SpanName, activity.DisplayName); - var d = new Dictionary() + var d = new Dictionary() { - { (int)StatusCode.Ok, "OK" }, - { (int)StatusCode.Error, "ERROR" }, - { (int)StatusCode.Unset, "UNSET" }, + { "Ok", "OK" }, + { "Error", "ERROR" }, + { "Unset", "UNSET" }, }; tc.SpanAttributes = tc.SpanAttributes.ToDictionary( @@ -115,7 +115,7 @@ public void HttpOutCallsAreCollectedSuccessfully(HttpTestData.HttpOutTestCase tc { if (tag.Key == SpanAttributeConstants.StatusCodeKey) { - Assert.Equal(tc.SpanStatus, d[int.Parse(tagValue)]); + Assert.Equal(tc.SpanStatus, d[tagValue]); continue; } diff --git a/test/OpenTelemetry.Instrumentation.Http.Tests/OpenTelemetry.Instrumentation.Http.Tests.csproj b/test/OpenTelemetry.Instrumentation.Http.Tests/OpenTelemetry.Instrumentation.Http.Tests.csproj index af9840d1da7..dba457d6eac 100644 --- a/test/OpenTelemetry.Instrumentation.Http.Tests/OpenTelemetry.Instrumentation.Http.Tests.csproj +++ b/test/OpenTelemetry.Instrumentation.Http.Tests/OpenTelemetry.Instrumentation.Http.Tests.csproj @@ -13,6 +13,7 @@ + diff --git a/test/OpenTelemetry.Instrumentation.SqlClient.Tests/OpenTelemetry.Instrumentation.SqlClient.Tests.csproj b/test/OpenTelemetry.Instrumentation.SqlClient.Tests/OpenTelemetry.Instrumentation.SqlClient.Tests.csproj index a9e4eb179ea..c8b5f270519 100644 --- a/test/OpenTelemetry.Instrumentation.SqlClient.Tests/OpenTelemetry.Instrumentation.SqlClient.Tests.csproj +++ b/test/OpenTelemetry.Instrumentation.SqlClient.Tests/OpenTelemetry.Instrumentation.SqlClient.Tests.csproj @@ -8,6 +8,7 @@ + diff --git a/test/OpenTelemetry.Instrumentation.SqlClient.Tests/SqlClientTests.cs b/test/OpenTelemetry.Instrumentation.SqlClient.Tests/SqlClientTests.cs index a5591da751d..e1b7bf48b19 100644 --- a/test/OpenTelemetry.Instrumentation.SqlClient.Tests/SqlClientTests.cs +++ b/test/OpenTelemetry.Instrumentation.SqlClient.Tests/SqlClientTests.cs @@ -275,13 +275,13 @@ private static void VerifyActivityData( if (!isFailure) { - Assert.Equal((int)StatusCode.Unset, activity.GetTagValue(SpanAttributeConstants.StatusCodeKey)); - Assert.Null(activity.GetTagValue(SpanAttributeConstants.StatusDescriptionKey)); + Assert.Equal(Status.Unset, activity.GetStatus()); } else { - Assert.Equal((int)StatusCode.Error, activity.GetTagValue(SpanAttributeConstants.StatusCodeKey)); - Assert.NotNull(activity.GetTagValue(SpanAttributeConstants.StatusDescriptionKey)); + var status = activity.GetStatus(); + Assert.Equal(Status.Error.StatusCode, status.StatusCode); + Assert.NotNull(status.Description); } Assert.Equal(SqlClientDiagnosticListener.MicrosoftSqlServerDatabaseSystemName, activity.GetTagValue(SemanticConventions.AttributeDbSystem)); diff --git a/test/OpenTelemetry.Instrumentation.SqlClient.Tests/SqlEventSourceTests.netfx.cs b/test/OpenTelemetry.Instrumentation.SqlClient.Tests/SqlEventSourceTests.netfx.cs index 686f8728647..5f1bc0ad59b 100644 --- a/test/OpenTelemetry.Instrumentation.SqlClient.Tests/SqlEventSourceTests.netfx.cs +++ b/test/OpenTelemetry.Instrumentation.SqlClient.Tests/SqlEventSourceTests.netfx.cs @@ -229,12 +229,13 @@ private static void VerifyActivityData( if (!isFailure) { - Assert.Equal((int)StatusCode.Unset, activity.GetTagValue(SpanAttributeConstants.StatusCodeKey)); + Assert.Equal(Status.Unset, activity.GetStatus()); } else { - Assert.Equal((int)StatusCode.Error, activity.GetTagValue(SpanAttributeConstants.StatusCodeKey)); - Assert.NotNull(activity.GetTagValue(SpanAttributeConstants.StatusDescriptionKey)); + var status = activity.GetStatus(); + Assert.Equal(Status.Error.StatusCode, status.StatusCode); + Assert.NotNull(status.Description); } } diff --git a/test/OpenTelemetry.Instrumentation.StackExchangeRedis.Tests/OpenTelemetry.Instrumentation.StackExchangeRedis.Tests.csproj b/test/OpenTelemetry.Instrumentation.StackExchangeRedis.Tests/OpenTelemetry.Instrumentation.StackExchangeRedis.Tests.csproj index ae5be9844d2..7a1fa4dcf8c 100644 --- a/test/OpenTelemetry.Instrumentation.StackExchangeRedis.Tests/OpenTelemetry.Instrumentation.StackExchangeRedis.Tests.csproj +++ b/test/OpenTelemetry.Instrumentation.StackExchangeRedis.Tests/OpenTelemetry.Instrumentation.StackExchangeRedis.Tests.csproj @@ -9,6 +9,7 @@ + diff --git a/test/OpenTelemetry.Instrumentation.StackExchangeRedis.Tests/StackExchangeRedisCallsInstrumentationTests.cs b/test/OpenTelemetry.Instrumentation.StackExchangeRedis.Tests/StackExchangeRedisCallsInstrumentationTests.cs index ebdfbe9c9df..b63a9b4c6dd 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((int)StatusCode.Unset, activity.GetTagValue(SpanAttributeConstants.StatusCodeKey)); + Assert.Equal(Status.Unset, activity.GetStatus()); Assert.Equal("redis", activity.GetTagValue(SemanticConventions.AttributeDbSystem)); Assert.Equal(0, activity.GetTagValue(StackExchangeRedisCallsInstrumentation.RedisDatabaseIndexKeyName)); diff --git a/test/OpenTelemetry.Instrumentation.W3cTraceContext.Tests/OpenTelemetry.Instrumentation.W3cTraceContext.Tests.csproj b/test/OpenTelemetry.Instrumentation.W3cTraceContext.Tests/OpenTelemetry.Instrumentation.W3cTraceContext.Tests.csproj index c3e5868cc82..fe94d23092c 100644 --- a/test/OpenTelemetry.Instrumentation.W3cTraceContext.Tests/OpenTelemetry.Instrumentation.W3cTraceContext.Tests.csproj +++ b/test/OpenTelemetry.Instrumentation.W3cTraceContext.Tests/OpenTelemetry.Instrumentation.W3cTraceContext.Tests.csproj @@ -22,6 +22,7 @@ +