From 3fd52b34c86ab796ce1ce626d3d5cf85541996a7 Mon Sep 17 00:00:00 2001 From: Yevhenii Solomchenko Date: Tue, 12 Nov 2024 14:26:36 +0100 Subject: [PATCH 1/3] wp --- .../Kafka/KafkaInstrumentation.cs | 26 ++++++++------- .../Instrumentations/MessagingAttributes.cs | 32 +++++++++++++------ .../RabbitMq6/RabbitMqInstrumentation.cs | 26 +++++++++------ 3 files changed, 55 insertions(+), 29 deletions(-) diff --git a/src/OpenTelemetry.AutoInstrumentation/Instrumentations/Kafka/KafkaInstrumentation.cs b/src/OpenTelemetry.AutoInstrumentation/Instrumentations/Kafka/KafkaInstrumentation.cs index f0d774f8e4..2d56931b76 100644 --- a/src/OpenTelemetry.AutoInstrumentation/Instrumentations/Kafka/KafkaInstrumentation.cs +++ b/src/OpenTelemetry.AutoInstrumentation/Instrumentations/Kafka/KafkaInstrumentation.cs @@ -22,10 +22,10 @@ internal static class KafkaInstrumentation string? spanName = null; if (!string.IsNullOrEmpty(consumeResult.Topic)) { - spanName = $"{consumeResult.Topic} {MessagingAttributes.Values.ReceiveOperationName}"; + spanName = $"{MessagingAttributes.Values.Kafka.PollOperationName} {consumeResult.Topic}"; } - spanName ??= MessagingAttributes.Values.ReceiveOperationName; + spanName ??= MessagingAttributes.Values.Kafka.PollOperationName; var activityLinks = propagatedContext.Value.ActivityContext.IsValid() ? new[] { new ActivityLink(propagatedContext.Value.ActivityContext) } @@ -41,7 +41,8 @@ internal static class KafkaInstrumentation { SetCommonAttributes( activity, - MessagingAttributes.Values.ReceiveOperationName, + MessagingAttributes.Values.ReceiveOperation, + MessagingAttributes.Values.Kafka.PollOperationName, consumeResult.Topic, consumeResult.Partition, consumeResult.Message?.Key, @@ -51,7 +52,7 @@ internal static class KafkaInstrumentation if (ConsumerCache.TryGet(consumer, out var groupId)) { - activity.SetTag(MessagingAttributes.Keys.Kafka.ConsumerGroupId, groupId); + activity.SetTag(MessagingAttributes.Keys.MessagingConsumerGroupName, groupId); } } @@ -69,16 +70,17 @@ internal static class KafkaInstrumentation string? spanName = null; if (!string.IsNullOrEmpty(partition.Topic)) { - spanName = $"{partition.Topic} {MessagingAttributes.Values.PublishOperationName}"; + spanName = $"{MessagingAttributes.Values.SendOperation} {partition.Topic}"; } - spanName ??= MessagingAttributes.Values.PublishOperationName; + spanName ??= MessagingAttributes.Values.SendOperation; var activity = Source.StartActivity(name: spanName, ActivityKind.Producer); if (activity is not null && activity.IsAllDataRequested) { SetCommonAttributes( activity, - MessagingAttributes.Values.PublishOperationName, + MessagingAttributes.Values.SendOperation, + MessagingAttributes.Values.SendOperation, partition.Topic, partition.Partition, message.Key, @@ -103,7 +105,7 @@ public static void InjectContext(TMessage message, Ac public static void SetDeliveryResults(Activity activity, IDeliveryResult deliveryResult) { // Set the final partition message was delivered to. - activity.SetTag(MessagingAttributes.Keys.Kafka.Partition, deliveryResult.Partition.Value); + activity.SetTag(MessagingAttributes.Keys.Partition, deliveryResult.Partition.Value); activity.SetTag( MessagingAttributes.Keys.Kafka.PartitionOffset, @@ -123,13 +125,15 @@ public static void SetDeliveryResults(Activity activity, IDeliveryResult deliver private static void SetCommonAttributes( Activity activity, string operationName, + string operationType, string? topic, Partition? partition, object? key, INamedClient? client) { - activity.SetTag(MessagingAttributes.Keys.MessagingOperation, operationName); - activity.SetTag(MessagingAttributes.Keys.MessagingSystem, MessagingAttributes.Values.KafkaMessagingSystemName); + activity.SetTag(MessagingAttributes.Keys.MessagingOperationName, operationName); + activity.SetTag(MessagingAttributes.Keys.MessagingOperationType, operationType); + activity.SetTag(MessagingAttributes.Keys.MessagingSystem, MessagingAttributes.Values.Kafka.MessagingSystemName); if (!string.IsNullOrEmpty(topic)) { activity.SetTag(MessagingAttributes.Keys.DestinationName, topic); @@ -151,7 +155,7 @@ private static void SetCommonAttributes( if (partition is not null) { - activity.SetTag(MessagingAttributes.Keys.Kafka.Partition, partition.Value.Value); + activity.SetTag(MessagingAttributes.Keys.Partition, partition.Value.Value); } } diff --git a/src/OpenTelemetry.AutoInstrumentation/Instrumentations/MessagingAttributes.cs b/src/OpenTelemetry.AutoInstrumentation/Instrumentations/MessagingAttributes.cs index dabda090f2..a070c2e8db 100644 --- a/src/OpenTelemetry.AutoInstrumentation/Instrumentations/MessagingAttributes.cs +++ b/src/OpenTelemetry.AutoInstrumentation/Instrumentations/MessagingAttributes.cs @@ -3,24 +3,25 @@ namespace OpenTelemetry.AutoInstrumentation.Instrumentations; -// https://github.com/open-telemetry/semantic-conventions/blob/v1.23.0/docs/messaging/messaging-spans.md#messaging-attributes +// https://github.com/open-telemetry/semantic-conventions/blob/v1.28.0/docs/messaging/messaging-spans.md#messaging-attributes internal static class MessagingAttributes { internal static class Keys { public const string MessagingSystem = "messaging.system"; - public const string MessagingOperation = "messaging.operation"; + public const string MessagingOperationName = "messaging.operation.name"; + public const string MessagingOperationType = "messaging.operation.type"; + public const string MessagingConsumerGroupName = "messaging.consumer.group.name"; public const string DestinationName = "messaging.destination.name"; public const string ClientId = "messaging.client_id"; public const string MessageBodySize = "messaging.message.body.size"; public const string MessageId = "messaging.message.id"; public const string ConversationId = "messaging.message.conversation_id"; + public const string Partition = "messaging.destination.partition.id"; - // https://github.com/open-telemetry/semantic-conventions/blob/v1.23.0/docs/messaging/kafka.md#span-attributes + // https://github.com/open-telemetry/semantic-conventions/blob/v1.28.0/docs/messaging/kafka.md#span-attributes internal static class Kafka { - public const string ConsumerGroupId = "messaging.kafka.consumer.group"; - public const string Partition = "messaging.kafka.destination.partition"; public const string MessageKey = "messaging.kafka.message.key"; public const string PartitionOffset = "messaging.kafka.message.offset"; public const string IsTombstone = "messaging.kafka.message.tombstone"; @@ -35,15 +36,28 @@ internal static class RabbitMq internal static class Values { - public const string KafkaMessagingSystemName = "kafka"; - public const string PublishOperationName = "publish"; - public const string ReceiveOperationName = "receive"; - public const string DeliverOperationName = "deliver"; + public const string SendOperation = "send"; + public const string ReceiveOperation = "receive"; + public const string ProcessOperation = "process"; + + internal static class Kafka + { + public const string MessagingSystemName = "kafka"; + + public const string CommitOperationName = "commit"; + public const string PublishOperationName = "commit"; + public const string PollOperationName = "poll"; + public const string ConsumeOperationName = "consume"; + } internal static class RabbitMq { public const string MessagingSystemName = "rabbitmq"; public const string DefaultExchangeName = "amq.default"; + + public const string CommitOperationName = "ack"; + public const string PollOperationName = "nack"; + public const string ConsumeOperationName = "reject"; } } } diff --git a/src/OpenTelemetry.AutoInstrumentation/Instrumentations/RabbitMq6/RabbitMqInstrumentation.cs b/src/OpenTelemetry.AutoInstrumentation/Instrumentations/RabbitMq6/RabbitMqInstrumentation.cs index b37fa72f5c..aa9febdea9 100644 --- a/src/OpenTelemetry.AutoInstrumentation/Instrumentations/RabbitMq6/RabbitMqInstrumentation.cs +++ b/src/OpenTelemetry.AutoInstrumentation/Instrumentations/RabbitMq6/RabbitMqInstrumentation.cs @@ -23,7 +23,8 @@ internal static class RabbitMqInstrumentation var connection = instance.Session?.Connection; return StartConsume( result.BasicProperties?.Headers, - MessagingAttributes.Values.ReceiveOperationName, + MessagingAttributes.Values.ReceiveOperation, + MessagingAttributes.Values.ReceiveOperation, result.Exchange, result.RoutingKey, result.DeliveryTag, @@ -54,7 +55,8 @@ internal static class RabbitMqInstrumentation return StartConsume( headers, - MessagingAttributes.Values.DeliverOperationName, + MessagingAttributes.Values.RabbitMq.ConsumeOperationName, + MessagingAttributes.Values.ProcessOperation, exchange, routingKey, deliveryTag, @@ -67,7 +69,7 @@ internal static class RabbitMqInstrumentation where TBasicProperties : IBasicProperties where TModel : IModelBase { - var name = GetActivityName(routingKey, MessagingAttributes.Values.PublishOperationName); + var name = GetActivityName(MessagingAttributes.Values.SendOperation, routingKey); var activity = Source.StartActivity(name, ActivityKind.Producer); if (activity is not null && basicProperties.Instance is not null) { @@ -83,7 +85,8 @@ internal static class RabbitMqInstrumentation exchange, routingKey, bodyLength, - MessagingAttributes.Values.PublishOperationName, + MessagingAttributes.Values.SendOperation, + MessagingAttributes.Values.SendOperation, connection?.Endpoint?.HostName, connection?.Endpoint?.Port, connection?.RemoteEndPoint); @@ -92,14 +95,15 @@ internal static class RabbitMqInstrumentation return activity; } - private static string GetActivityName(string? routingKey, string operationType) + private static string GetActivityName(string operationName, string? routingKey) { - return string.IsNullOrEmpty(routingKey) ? operationType : $"{routingKey} {operationType}"; + return string.IsNullOrEmpty(routingKey) ? operationName : $"{operationName} {routingKey}"; } private static Activity? StartConsume( IDictionary? headers, string consumeOperationName, + string consumeOperationType, string? exchange, string? routingKey, ulong deliveryTag, @@ -117,7 +121,7 @@ private static string GetActivityName(string? routingKey, string operationType) ? new[] { new ActivityLink(propagatedContext.ActivityContext) } : Array.Empty(); - var name = GetActivityName(routingKey, consumeOperationName); + var name = GetActivityName(consumeOperationName, routingKey); var activity = Source.StartActivity( name: name, kind: ActivityKind.Consumer, @@ -130,6 +134,7 @@ private static string GetActivityName(string? routingKey, string operationType) exchange, routingKey, consumeOperationName, + consumeOperationType, deliveryTag, bodyLength, messageId, @@ -148,6 +153,7 @@ private static void SetCommonTags( string? routingKey, int bodyLength, string operationName, + string operationType, string? hostName, int? port, EndPoint? remoteEndpoint) @@ -156,7 +162,8 @@ private static void SetCommonTags( activity .SetTag(MessagingAttributes.Keys.MessagingSystem, MessagingAttributes.Values.RabbitMq.MessagingSystemName) - .SetTag(MessagingAttributes.Keys.MessagingOperation, operationName) + .SetTag(MessagingAttributes.Keys.MessagingOperationName, operationName) + .SetTag(MessagingAttributes.Keys.MessagingOperationType, operationType) .SetTag(MessagingAttributes.Keys.DestinationName, exchange) .SetTag(MessagingAttributes.Keys.MessageBodySize, bodyLength); @@ -204,6 +211,7 @@ private static void SetConsumeTags( string? exchange, string? routingKey, string operationName, + string operationType, ulong deliveryTag, int bodyLength, string? basicPropertiesMessageId, @@ -212,7 +220,7 @@ private static void SetConsumeTags( int? port, EndPoint? remoteEndpoint) { - SetCommonTags(activity, exchange, routingKey, bodyLength, operationName, hostName, port, remoteEndpoint); + SetCommonTags(activity, exchange, routingKey, bodyLength, operationName, operationType, hostName, port, remoteEndpoint); if (!string.IsNullOrEmpty(basicPropertiesMessageId)) { activity.SetTag(MessagingAttributes.Keys.MessageId, basicPropertiesMessageId); From 239877d2a77521d54285fd5f4606e66ba74884f1 Mon Sep 17 00:00:00 2001 From: Yevhenii Solomchenko Date: Tue, 12 Nov 2024 15:02:31 +0100 Subject: [PATCH 2/3] update Changelog --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 26d0108bfa..aaa6770b39 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,6 +11,8 @@ This component adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.h ### Changed +- Update messaging attributes from [v1.23.0](https://github.com/open-telemetry/semantic-conventions/blob/v1.23.0/docs/messaging/messaging-spans.md) to [v1.28.0](https://github.com/open-telemetry/semantic-conventions/blob/v1.28.0/docs/messaging/messaging-spans.md) + #### Dependency updates ### Deprecated From 0fb4d99adf301a6488436c28eaf716f4d39ea93e Mon Sep 17 00:00:00 2001 From: Yevhenii Solomchenko Date: Tue, 12 Nov 2024 15:04:58 +0100 Subject: [PATCH 3/3] wp tests --- test/IntegrationTests/KafkaTests.cs | 32 +++++++++++++++----------- test/IntegrationTests/RabbitMqTests.cs | 23 ++++++++++-------- 2 files changed, 31 insertions(+), 24 deletions(-) diff --git a/test/IntegrationTests/KafkaTests.cs b/test/IntegrationTests/KafkaTests.cs index 897d53f240..9bff315787 100644 --- a/test/IntegrationTests/KafkaTests.cs +++ b/test/IntegrationTests/KafkaTests.cs @@ -11,15 +11,17 @@ namespace IntegrationTests; [Collection(KafkaCollection.Name)] public class KafkaTests : TestHelper { - private const string MessagingPublishOperationAttributeValue = "publish"; + private const string MessagingPublishOperationAttributeValue = "send"; private const string MessagingReceiveOperationAttributeValue = "receive"; + private const string MessagingPollOperationAttributeValue = "poll"; private const string MessagingSystemAttributeName = "messaging.system"; - private const string MessagingOperationAttributeName = "messaging.operation"; + private const string MessagingOperationNameAttributeName = "messaging.operation.name"; + private const string MessagingOperationTypeAttributeName = "messaging.operation.type"; private const string MessagingDestinationAttributeName = "messaging.destination.name"; private const string MessagingClientIdAttributeName = "messaging.client_id"; + private const string MessagingConsumerGroupNameAttributeName = "messaging.consumer.group.name"; private const string KafkaMessageSystemAttributeValue = "kafka"; - private const string KafkaConsumerGroupAttributeName = "messaging.kafka.consumer.group"; private const string KafkaMessageKeyAttributeName = "messaging.kafka.message.key"; private const string KafkaMessageKeyAttributeValue = "testkey"; private const string KafkaDestinationPartitionAttributeName = "messaging.kafka.destination.partition"; @@ -124,15 +126,15 @@ private static bool ValidateConsumeExceptionSpan(Span span, string topicName) private static bool ValidateConsumerSpan(Span span, string topicName, int messageOffset, string? expectedMessageKey = KafkaMessageKeyAttributeValue) { var kafkaMessageOffset = span.Attributes.SingleOrDefault(kv => kv.Key == KafkaMessageOffsetAttributeName)?.Value.IntValue; - var consumerGroupId = span.Attributes.Single(kv => kv.Key == KafkaConsumerGroupAttributeName).Value.StringValue; - return ValidateCommonAttributes(span.Attributes, topicName, KafkaConsumerClientIdAttributeValue, MessagingReceiveOperationAttributeValue, 0, expectedMessageKey) && + var consumerGroupId = span.Attributes.Single(kv => kv.Key == MessagingConsumerGroupNameAttributeName).Value.StringValue; + return ValidateCommonAttributes(span.Attributes, topicName, KafkaConsumerClientIdAttributeValue, MessagingReceiveOperationAttributeValue, MessagingPollOperationAttributeValue, 0, expectedMessageKey) && kafkaMessageOffset == messageOffset && consumerGroupId == GetConsumerGroupIdAttributeValue(topicName); } private static bool ValidateBasicProduceExceptionSpan(Span span, string topicName) { - return ValidateCommonAttributes(span.Attributes, topicName, KafkaProducerClientIdAttributeValue, MessagingPublishOperationAttributeValue, -1, KafkaMessageKeyAttributeValue) && + return ValidateCommonAttributes(span.Attributes, topicName, KafkaProducerClientIdAttributeValue, MessagingPublishOperationAttributeValue, MessagingPublishOperationAttributeValue, -1, KafkaMessageKeyAttributeValue) && span.Status.Code == Status.Types.StatusCode.Error; } @@ -154,38 +156,40 @@ private static bool ValidateProducerSpan(Span span, string topicName, int partit { var isTombstone = span.Attributes.Single(kv => kv.Key == KafkaMessageTombstoneAttributeName).Value.BoolValue; - return ValidateCommonAttributes(span.Attributes, topicName, KafkaProducerClientIdAttributeValue, MessagingPublishOperationAttributeValue, partition, KafkaMessageKeyAttributeValue) && + return ValidateCommonAttributes(span.Attributes, topicName, KafkaProducerClientIdAttributeValue, MessagingPublishOperationAttributeValue, MessagingPublishOperationAttributeValue, partition, KafkaMessageKeyAttributeValue) && isTombstone == tombstoneExpected && span.Status is null; } - private static bool ValidateCommonAttributes(IReadOnlyCollection attributes, string topicName, string clientId, string operationName, int partition, string? expectedMessageKey) + private static bool ValidateCommonAttributes(IReadOnlyCollection attributes, string topicName, string clientId, string operationName, string operationType, int partition, string? expectedMessageKey) { var messagingDestinationName = attributes.SingleOrDefault(kv => kv.Key == MessagingDestinationAttributeName)?.Value.StringValue; var kafkaMessageKey = attributes.SingleOrDefault(kv => kv.Key == KafkaMessageKeyAttributeName)?.Value.StringValue; var kafkaPartition = attributes.SingleOrDefault(kv => kv.Key == KafkaDestinationPartitionAttributeName)?.Value.IntValue; - return ValidateBasicSpanAttributes(attributes, clientId, operationName) && + return ValidateBasicSpanAttributes(attributes, clientId, operationName, operationType) && messagingDestinationName == topicName && kafkaMessageKey == expectedMessageKey && kafkaPartition == partition; } - private static bool ValidateBasicSpanAttributes(IReadOnlyCollection attributes, string clientId, string operationName) + private static bool ValidateBasicSpanAttributes(IReadOnlyCollection attributes, string clientId, string operationName, string operationType) { var messagingSystem = attributes.Single(kv => kv.Key == MessagingSystemAttributeName).Value.StringValue; - var messagingOperation = attributes.Single(kv => kv.Key == MessagingOperationAttributeName).Value.StringValue; + var messagingOperationName = attributes.Single(kv => kv.Key == MessagingOperationNameAttributeName).Value.StringValue; + var messagingOperationType = attributes.Single(kv => kv.Key == MessagingOperationTypeAttributeName).Value.StringValue; var messagingClientId = attributes.Single(kv => kv.Key == MessagingClientIdAttributeName).Value.StringValue; return messagingSystem == KafkaMessageSystemAttributeValue && - messagingOperation == operationName && + messagingOperationName == operationName && + messagingOperationType == operationType && messagingClientId == clientId; } private static bool ValidatePropagation(ICollection collectedSpans, string topicName) { - var expectedReceiveOperationName = $"{topicName} {MessagingReceiveOperationAttributeValue}"; - var expectedPublishOperationName = $"{topicName} {MessagingPublishOperationAttributeValue}"; + var expectedReceiveOperationName = $"{MessagingPollOperationAttributeValue} {topicName}"; + var expectedPublishOperationName = $"{MessagingPublishOperationAttributeValue} {topicName}"; var producerSpans = collectedSpans .Where(span => span.Span.Name == expectedPublishOperationName && diff --git a/test/IntegrationTests/RabbitMqTests.cs b/test/IntegrationTests/RabbitMqTests.cs index 3722ab5a15..9f272d712e 100644 --- a/test/IntegrationTests/RabbitMqTests.cs +++ b/test/IntegrationTests/RabbitMqTests.cs @@ -16,7 +16,8 @@ public class RabbitMqTests : TestHelper // Required messaging attributes set by the instrumentation private const string MessagingSystemAttributeName = "messaging.system"; - private const string MessagingOperationAttributeName = "messaging.operation"; + private const string MessagingOperationNameAttributeName = "messaging.operation.name"; + private const string MessagingOperationTypeAttributeName = "messaging.operation.type"; private const string MessagingDestinationAttributeName = "messaging.destination.name"; // Required RabbitMQ attributes set by the instrumentation @@ -58,9 +59,9 @@ public void SubmitsTraces(string packageVersion) collector.Expect("OpenTelemetry.AutoInstrumentation.RabbitMq", span => ValidateProducerSpan(span)); collector.Expect("OpenTelemetry.AutoInstrumentation.RabbitMq", span => ValidateProducerSpan(span)); collector.Expect("OpenTelemetry.AutoInstrumentation.RabbitMq", span => ValidateProducerSpan(span)); - collector.Expect("OpenTelemetry.AutoInstrumentation.RabbitMq", span => ValidateConsumerSpan(span, "receive")); - collector.Expect("OpenTelemetry.AutoInstrumentation.RabbitMq", span => ValidateConsumerSpan(span, "deliver")); - collector.Expect("OpenTelemetry.AutoInstrumentation.RabbitMq", span => ValidateConsumerSpan(span, "deliver")); + collector.Expect("OpenTelemetry.AutoInstrumentation.RabbitMq", span => ValidateConsumerSpan(span, "receive", "receive")); + collector.Expect("OpenTelemetry.AutoInstrumentation.RabbitMq", span => ValidateConsumerSpan(span, "process", "consume")); + collector.Expect("OpenTelemetry.AutoInstrumentation.RabbitMq", span => ValidateConsumerSpan(span, "process", "consume")); collector.ExpectCollected(collected => ValidatePropagation(collected)); @@ -91,34 +92,36 @@ bool VerifySingleMatchingConsumerSpan(MockSpansCollector.Collected producerSpan) } } - private static bool ValidateBasicSpanAttributes(IReadOnlyCollection attributes, string operationName) + private static bool ValidateBasicSpanAttributes(IReadOnlyCollection attributes, string operationName, string operationType) { var messagingSystem = attributes.Single(kv => kv.Key == MessagingSystemAttributeName).Value.StringValue; - var messagingOperation = attributes.Single(kv => kv.Key == MessagingOperationAttributeName).Value.StringValue; + var messagingOperationName = attributes.Single(kv => kv.Key == MessagingOperationNameAttributeName).Value.StringValue; + var messagingOperationType = attributes.Single(kv => kv.Key == MessagingOperationTypeAttributeName).Value.StringValue; var destinationName = attributes.Single(kv => kv.Key == MessagingDestinationAttributeName).Value.StringValue; var routingKey = attributes.Single(kv => kv.Key == RabbitMqRoutingKeyAttributeName).Value.StringValue; var bodySize = attributes.Single(kv => kv.Key == MessagingBodySizeAttributeName).Value.IntValue; return messagingSystem == "rabbitmq" && - messagingOperation == operationName && + messagingOperationName == operationName && + messagingOperationType == operationType && destinationName == "amq.default" && routingKey == "hello" && bodySize == 13; } - private bool ValidateConsumerSpan(Span span, string operationName) + private bool ValidateConsumerSpan(Span span, string operationName, string operationType) { var deliveryTag = span.Attributes.SingleOrDefault(kv => kv.Key == RabbitMqDeliveryTagAttributeName)?.Value.StringValue; return span.Kind == Span.Types.SpanKind.Consumer && span.Links.Count == 1 && - ValidateBasicSpanAttributes(span.Attributes, operationName) && + ValidateBasicSpanAttributes(span.Attributes, operationName, operationType) && (operationName != "receive" || ValidateNetworkAttributes(span.Attributes)) && !string.IsNullOrEmpty(deliveryTag); } private bool ValidateProducerSpan(Span span) { - return span.Kind == Span.Types.SpanKind.Producer && ValidateBasicSpanAttributes(span.Attributes, "publish") && ValidateNetworkAttributes(span.Attributes); + return span.Kind == Span.Types.SpanKind.Producer && ValidateBasicSpanAttributes(span.Attributes, "send", "send") && ValidateNetworkAttributes(span.Attributes); } private bool ValidateNetworkAttributes(IReadOnlyCollection spanAttributes)