[WcfClient] validate span attributes (#2743)

validate span attributes

Co-authored-by: Chris Ventura <45495992+nrcventura@users.noreply.github.com>
This commit is contained in:
Mateusz Łach 2023-07-11 19:40:28 +02:00 committed by GitHub
parent 818aa7e332
commit 9324d3d058
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 96 additions and 20 deletions

View File

@ -0,0 +1,63 @@
// <copyright file="WcfClientInstrumentation.cs" company="OpenTelemetry Authors">
// 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.
// </copyright>
#if NETFRAMEWORK
using OpenTelemetry.Proto.Common.V1;
using OpenTelemetry.Proto.Trace.V1;
namespace IntegrationTests;
internal static class WcfClientInstrumentation
{
public const string NetTcpBindingMessageVersion = "Soap12 (http://www.w3.org/2003/05/soap-envelope) Addressing10 (http://www.w3.org/2005/08/addressing)";
public const string HttpBindingMessageVersion = "Soap11 (http://schemas.xmlsoap.org/soap/envelope/) AddressingNone (http://schemas.microsoft.com/ws/2005/05/addressing/none)";
public const string NetTcpChannelScheme = "net.tcp";
public const string HttpChannelScheme = "http";
public static bool ValidateBasicSpanExpectations(
Span span,
string expectedChannelScheme,
string expectedChannelPath,
string expectedPeerName,
int expectedPeerPort,
string expectedMessageVersion)
{
var attributes = span.Attributes;
var rpcSystem = ExtractAttribute(attributes, "rpc.system");
var rpcService = ExtractAttribute(attributes, "rpc.service");
var rpcMethod = ExtractAttribute(attributes, "rpc.method");
var soapMessageVersion = ExtractAttribute(attributes, "soap.message_version");
var netPeerPort = ExtractAttribute(attributes, "net.peer.port");
var netPeerName = ExtractAttribute(attributes, "net.peer.name");
var channelSchemeTag = ExtractAttribute(attributes, "wcf.channel.scheme");
var channelPath = ExtractAttribute(attributes, "wcf.channel.path");
return span.Kind == Span.Types.SpanKind.Client &&
rpcSystem.Value.StringValue == "dotnet_wcf" &&
rpcService.Value.StringValue == "http://opentelemetry.io/StatusService" &&
rpcMethod.Value.StringValue == "Ping" &&
netPeerName.Value.StringValue == expectedPeerName &&
netPeerPort.Value.IntValue == expectedPeerPort &&
channelSchemeTag.Value.StringValue == expectedChannelScheme &&
soapMessageVersion.Value.StringValue == expectedMessageVersion &&
channelPath.Value.StringValue == expectedChannelPath;
}
private static KeyValue ExtractAttribute(IEnumerable<KeyValue> attributes, string key)
{
return attributes.Single(kv => kv.Key == key);
}
}
#endif

View File

@ -27,6 +27,8 @@ namespace IntegrationTests;
public class WcfIISTests : TestHelper
{
private const string ExpectedChannelPath = "/StatusService.svc";
private const string ExpectedPeerName = "localhost";
private readonly Dictionary<string, string> _environmentVariables = new();
public WcfIISTests(ITestOutputHelper output)
@ -49,25 +51,25 @@ public class WcfIISTests : TestHelper
SetExporter(collector);
using var fwPort = FirewallHelper.OpenWinPort(collector.Port, Output);
var netTcpPort = TcpPortProvider.GetOpenPort();
var httpPort = TcpPortProvider.GetOpenPort();
collector.Expect("OpenTelemetry.Instrumentation.Wcf", span => span.Kind == Span.Types.SpanKind.Server && span.ParentSpanId != ByteString.Empty, "Server 1");
collector.Expect("OpenTelemetry.AutoInstrumentation.Wcf", span => span.Kind == Span.Types.SpanKind.Client, "Client 1");
collector.Expect("OpenTelemetry.AutoInstrumentation.Wcf", span => WcfClientInstrumentation.ValidateBasicSpanExpectations(span, WcfClientInstrumentation.NetTcpChannelScheme, ExpectedChannelPath, ExpectedPeerName, netTcpPort, WcfClientInstrumentation.NetTcpBindingMessageVersion), "Client 1");
collector.Expect("OpenTelemetry.Instrumentation.Wcf", span => span.Kind == Span.Types.SpanKind.Server && span.ParentSpanId != ByteString.Empty, "Server 2");
collector.Expect("OpenTelemetry.AutoInstrumentation.Wcf", span => span.Kind == Span.Types.SpanKind.Client, "Client 2");
collector.Expect("OpenTelemetry.AutoInstrumentation.Wcf", span => WcfClientInstrumentation.ValidateBasicSpanExpectations(span, WcfClientInstrumentation.NetTcpChannelScheme, ExpectedChannelPath, ExpectedPeerName, netTcpPort, WcfClientInstrumentation.NetTcpBindingMessageVersion), "Client 2");
collector.Expect("OpenTelemetry.Instrumentation.Wcf", span => span.Kind == Span.Types.SpanKind.Server && span.ParentSpanId != ByteString.Empty, "Server 3");
collector.Expect("OpenTelemetry.AutoInstrumentation.Wcf", span => span.Kind == Span.Types.SpanKind.Client, "Client 3");
collector.Expect("OpenTelemetry.AutoInstrumentation.Wcf", span => WcfClientInstrumentation.ValidateBasicSpanExpectations(span, WcfClientInstrumentation.NetTcpChannelScheme, ExpectedChannelPath, ExpectedPeerName, netTcpPort, WcfClientInstrumentation.NetTcpBindingMessageVersion), "Client 3");
collector.Expect("OpenTelemetry.Instrumentation.Wcf", span => span.Kind == Span.Types.SpanKind.Server && span.ParentSpanId != ByteString.Empty, "Server 4");
collector.Expect("OpenTelemetry.AutoInstrumentation.Wcf", span => span.Kind == Span.Types.SpanKind.Client, "Client 4");
collector.Expect("OpenTelemetry.AutoInstrumentation.Wcf", span => WcfClientInstrumentation.ValidateBasicSpanExpectations(span, WcfClientInstrumentation.HttpChannelScheme, ExpectedChannelPath, ExpectedPeerName, httpPort, WcfClientInstrumentation.HttpBindingMessageVersion), "Client 4");
collector.Expect("OpenTelemetry.Instrumentation.Wcf", span => span.Kind == Span.Types.SpanKind.Server && span.ParentSpanId != ByteString.Empty, "Server 5");
collector.Expect("OpenTelemetry.AutoInstrumentation.Wcf", span => span.Kind == Span.Types.SpanKind.Client, "Client 5");
collector.Expect("OpenTelemetry.AutoInstrumentation.Wcf", span => WcfClientInstrumentation.ValidateBasicSpanExpectations(span, WcfClientInstrumentation.HttpChannelScheme, ExpectedChannelPath, ExpectedPeerName, httpPort, WcfClientInstrumentation.HttpBindingMessageVersion), "Client 5");
collector.Expect("OpenTelemetry.Instrumentation.Wcf", span => span.Kind == Span.Types.SpanKind.Server && span.ParentSpanId != ByteString.Empty, "Server 6");
collector.Expect("OpenTelemetry.AutoInstrumentation.Wcf", span => span.Kind == Span.Types.SpanKind.Client, "Client 6");
collector.Expect("OpenTelemetry.AutoInstrumentation.Wcf", span => WcfClientInstrumentation.ValidateBasicSpanExpectations(span, WcfClientInstrumentation.HttpChannelScheme, ExpectedChannelPath, ExpectedPeerName, httpPort, WcfClientInstrumentation.HttpBindingMessageVersion), "Client 6");
var collectorUrl = $"http://{DockerNetworkHelper.IntegrationTestsGateway}:{collector.Port}";
_environmentVariables["OTEL_EXPORTER_OTLP_ENDPOINT"] = collectorUrl;
var netTcpPort = TcpPortProvider.GetOpenPort();
var httpPort = TcpPortProvider.GetOpenPort();
await using var container = await StartContainerAsync(netTcpPort, httpPort);
RunTestApplication(new TestSettings
@ -94,7 +96,7 @@ public class WcfIISTests : TestHelper
var builder = new ContainerBuilder()
.WithImage(imageName)
.WithCleanUp(cleanUp: true)
.WithName($"{imageName}")
.WithName(imageName)
.WithNetwork(networkName)
.WithPortBinding(netTcpPort, 808)
.WithPortBinding(httpPort, 80)

View File

@ -16,7 +16,9 @@
#if NETFRAMEWORK
using Google.Protobuf;
using Google.Protobuf.Collections;
using IntegrationTests.Helpers;
using OpenTelemetry.Proto.Common.V1;
using OpenTelemetry.Proto.Trace.V1;
using Xunit.Abstractions;
@ -24,6 +26,11 @@ namespace IntegrationTests;
public class WcfNetFrameworkTests : WcfTestsBase
{
private const int NetTcpPort = 9090;
private const int HttpPort = 9009;
private const string ExpectedChannelPath = "/Telemetry";
private const string ExpectedPeerName = "127.0.0.1";
public WcfNetFrameworkTests(ITestOutputHelper output)
: base("Wcf.Client.NetFramework", output)
{
@ -34,19 +41,18 @@ public class WcfNetFrameworkTests : WcfTestsBase
public async Task SubmitsTraces()
{
using var collector = await SubmitsTracesInternal(string.Empty);
// TODO: better assertions including tags and hierarchy - https://github.com/open-telemetry/opentelemetry-dotnet-instrumentation/issues/2662
collector.Expect("OpenTelemetry.Instrumentation.Wcf", span => span.Kind == Span.Types.SpanKind.Server && span.ParentSpanId != ByteString.Empty, "Server 1");
collector.Expect("OpenTelemetry.AutoInstrumentation.Wcf", span => span.Kind == Span.Types.SpanKind.Client, "Client 1");
collector.Expect("OpenTelemetry.AutoInstrumentation.Wcf", span => WcfClientInstrumentation.ValidateBasicSpanExpectations(span, WcfClientInstrumentation.NetTcpChannelScheme, ExpectedChannelPath, ExpectedPeerName, NetTcpPort, WcfClientInstrumentation.NetTcpBindingMessageVersion), "Client 1");
collector.Expect("OpenTelemetry.Instrumentation.Wcf", span => span.Kind == Span.Types.SpanKind.Server && span.ParentSpanId != ByteString.Empty, "Server 2");
collector.Expect("OpenTelemetry.AutoInstrumentation.Wcf", span => span.Kind == Span.Types.SpanKind.Client, "Client 2");
collector.Expect("OpenTelemetry.AutoInstrumentation.Wcf", span => WcfClientInstrumentation.ValidateBasicSpanExpectations(span, WcfClientInstrumentation.NetTcpChannelScheme, ExpectedChannelPath, ExpectedPeerName, NetTcpPort, WcfClientInstrumentation.NetTcpBindingMessageVersion), "Client 2");
collector.Expect("OpenTelemetry.Instrumentation.Wcf", span => span.Kind == Span.Types.SpanKind.Server && span.ParentSpanId != ByteString.Empty, "Server 3");
collector.Expect("OpenTelemetry.AutoInstrumentation.Wcf", span => span.Kind == Span.Types.SpanKind.Client, "Client 3");
collector.Expect("OpenTelemetry.AutoInstrumentation.Wcf", span => WcfClientInstrumentation.ValidateBasicSpanExpectations(span, WcfClientInstrumentation.NetTcpChannelScheme, ExpectedChannelPath, ExpectedPeerName, NetTcpPort, WcfClientInstrumentation.NetTcpBindingMessageVersion), "Client 3");
collector.Expect("OpenTelemetry.Instrumentation.Wcf", span => span.Kind == Span.Types.SpanKind.Server && span.ParentSpanId != ByteString.Empty, "Server 4");
collector.Expect("OpenTelemetry.AutoInstrumentation.Wcf", span => span.Kind == Span.Types.SpanKind.Client, "Client 4");
collector.Expect("OpenTelemetry.AutoInstrumentation.Wcf", span => WcfClientInstrumentation.ValidateBasicSpanExpectations(span, WcfClientInstrumentation.HttpChannelScheme, ExpectedChannelPath, ExpectedPeerName, HttpPort, WcfClientInstrumentation.HttpBindingMessageVersion), "Client 4");
collector.Expect("OpenTelemetry.Instrumentation.Wcf", span => span.Kind == Span.Types.SpanKind.Server && span.ParentSpanId != ByteString.Empty, "Server 5");
collector.Expect("OpenTelemetry.AutoInstrumentation.Wcf", span => span.Kind == Span.Types.SpanKind.Client, "Client 5");
collector.Expect("OpenTelemetry.AutoInstrumentation.Wcf", span => WcfClientInstrumentation.ValidateBasicSpanExpectations(span, WcfClientInstrumentation.HttpChannelScheme, ExpectedChannelPath, ExpectedPeerName, HttpPort, WcfClientInstrumentation.HttpBindingMessageVersion), "Client 5");
collector.Expect("OpenTelemetry.Instrumentation.Wcf", span => span.Kind == Span.Types.SpanKind.Server && span.ParentSpanId != ByteString.Empty, "Server 6");
collector.Expect("OpenTelemetry.AutoInstrumentation.Wcf", span => span.Kind == Span.Types.SpanKind.Client, "Client 6");
collector.Expect("OpenTelemetry.AutoInstrumentation.Wcf", span => WcfClientInstrumentation.ValidateBasicSpanExpectations(span, WcfClientInstrumentation.HttpChannelScheme, ExpectedChannelPath, ExpectedPeerName, HttpPort, WcfClientInstrumentation.HttpBindingMessageVersion), "Client 6");
collector.AssertExpectations();
}
@ -58,9 +64,9 @@ public class WcfNetFrameworkTests : WcfTestsBase
using var collector = new MockSpansCollector(Output);
SetExporter(collector);
collector.Expect("OpenTelemetry.AutoInstrumentation.Wcf", span => span.Kind == Span.Types.SpanKind.Client && span.Status.Code == Status.Types.StatusCode.Error, "Client 1");
collector.Expect("OpenTelemetry.AutoInstrumentation.Wcf", span => span.Kind == Span.Types.SpanKind.Client && span.Status.Code == Status.Types.StatusCode.Error, "Client 2");
collector.Expect("OpenTelemetry.AutoInstrumentation.Wcf", span => span.Kind == Span.Types.SpanKind.Client && span.Status.Code == Status.Types.StatusCode.Error, "Client 3");
collector.Expect("OpenTelemetry.AutoInstrumentation.Wcf", span => ValidateErrorSpanExpectations(span), "Client 1");
collector.Expect("OpenTelemetry.AutoInstrumentation.Wcf", span => ValidateErrorSpanExpectations(span), "Client 2");
collector.Expect("OpenTelemetry.AutoInstrumentation.Wcf", span => ValidateErrorSpanExpectations(span), "Client 3");
RunTestApplication(new TestSettings
{
@ -69,6 +75,11 @@ public class WcfNetFrameworkTests : WcfTestsBase
collector.AssertExpectations();
}
private static bool ValidateErrorSpanExpectations(Span span)
{
return WcfClientInstrumentation.ValidateBasicSpanExpectations(span, WcfClientInstrumentation.HttpChannelScheme, ExpectedChannelPath, ExpectedPeerName, HttpPort, WcfClientInstrumentation.HttpBindingMessageVersion) && span.Status.Code == Status.Types.StatusCode.Error;
}
}
#endif