From 3bac8e7bcdb784a82f7ecace717bf985fae9b4d3 Mon Sep 17 00:00:00 2001 From: Alex Valuyskiy Date: Mon, 15 Mar 2021 19:11:17 +0200 Subject: [PATCH] Updated MassTransit instrumentation to OpenTelemetry 1.0 (#85) * Updated MassTransit instrumentation * fixed unit tests * Assert only sampled traces * Update CODEOWNERS --- CODEOWNERS | 4 +- .../MassTransitDiagnosticListener.cs | 40 +++++++++----- .../MassTransitInstrumentationEventSource.cs | 52 +++++++++++++++++++ .../MassTransitSemanticConventions.cs | 25 +++++++++ .../Implementation/SemanticConventions.cs | 46 ---------------- .../MassTransitInstrumentation.cs | 21 +++----- ...Contrib.Instrumentation.MassTransit.csproj | 3 +- .../TracerProviderBuilderExtensions.cs | 11 +++- .../MassTransitInstrumentationTests.cs | 19 ++++--- ...b.Instrumentation.MassTransit.Tests.csproj | 1 + 10 files changed, 138 insertions(+), 84 deletions(-) create mode 100644 src/OpenTelemetry.Contrib.Instrumentation.MassTransit/Implementation/MassTransitInstrumentationEventSource.cs create mode 100644 src/OpenTelemetry.Contrib.Instrumentation.MassTransit/Implementation/MassTransitSemanticConventions.cs delete mode 100644 src/OpenTelemetry.Contrib.Instrumentation.MassTransit/Implementation/SemanticConventions.cs diff --git a/CODEOWNERS b/CODEOWNERS index af4120bfaa..f9c29251b1 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -8,12 +8,12 @@ src/OpenTelemetry.Contrib.Exporter.Stackdriver/ @ope src/OpenTelemetry.Contrib.Extensions.AWSXRay/ @open-telemetry/dotnet-contrib-approvers @srprash @lupengamzn src/OpenTelemetry.Contrib.Instrumentation.Elasticsearch/ @open-telemetry/dotnet-contrib-approvers src/OpenTelemetry.Contrib.Instrumentation.EntityFrameworkCore/ @open-telemetry/dotnet-contrib-approvers -src/OpenTelemetry.Contrib.Instrumentation.MassTransit/ @open-telemetry/dotnet-contrib-approvers +src/OpenTelemetry.Contrib.Instrumentation.MassTransit/ @open-telemetry/dotnet-contrib-approvers @alexvaluyskiy src/OpenTelemetry.Contrib.Instrumentation.GrpcCore/ @open-telemetry/dotnet-contrib-approvers @pcwiese test/OpenTelemetry.Contrib.Exporter.Stackdriver.Tests/ @open-telemetry/dotnet-contrib-approvers test/OpenTelemetry.Contrib.Extensions.AWSXRay.Tests/ @open-telemetry/dotnet-contrib-approvers @srprash @lupengamzn test/OpenTelemetry.Contrib.Instrumentation.Elasticsearch.Tests/ @open-telemetry/dotnet-contrib-approvers test/OpenTelemetry.Contrib.Instrumentation.EntityFrameworkCoreTests/ @open-telemetry/dotnet-contrib-approvers -test/OpenTelemetry.Contrib.Instrumentation.MassTransit.Tests/ @open-telemetry/dotnet-contrib-approvers +test/OpenTelemetry.Contrib.Instrumentation.MassTransit.Tests/ @open-telemetry/dotnet-contrib-approvers @alexvaluyskiy test/OpenTelemetry.Contrib.Instrumentation.GrpcCore.Tests/ @open-telemetry/dotnet-contrib-approvers @pcwiese diff --git a/src/OpenTelemetry.Contrib.Instrumentation.MassTransit/Implementation/MassTransitDiagnosticListener.cs b/src/OpenTelemetry.Contrib.Instrumentation.MassTransit/Implementation/MassTransitDiagnosticListener.cs index 75694dd141..3248e7a323 100644 --- a/src/OpenTelemetry.Contrib.Instrumentation.MassTransit/Implementation/MassTransitDiagnosticListener.cs +++ b/src/OpenTelemetry.Contrib.Instrumentation.MassTransit/Implementation/MassTransitDiagnosticListener.cs @@ -18,6 +18,7 @@ using System.Collections.Generic; using System.Diagnostics; using System.Linq; +using System.Reflection; using OpenTelemetry.Instrumentation; using OpenTelemetry.Trace; @@ -25,13 +26,16 @@ namespace OpenTelemetry.Contrib.Instrumentation.MassTransit.Implementation { internal class MassTransitDiagnosticListener : ListenerHandler { - private readonly ActivitySourceAdapter activitySource; + internal static readonly AssemblyName AssemblyName = typeof(MassTransitDiagnosticListener).Assembly.GetName(); + internal static readonly string ActivitySourceName = AssemblyName.Name; + internal static readonly Version Version = AssemblyName.Version; + internal static readonly ActivitySource ActivitySource = new ActivitySource(ActivitySourceName, Version.ToString()); + private readonly MassTransitInstrumentationOptions options; - public MassTransitDiagnosticListener(ActivitySourceAdapter activitySource, MassTransitInstrumentationOptions options) - : base("MassTransit") + public MassTransitDiagnosticListener(string name, MassTransitInstrumentationOptions options) + : base(name) { - this.activitySource = activitySource; this.options = options; } @@ -39,27 +43,37 @@ public override void OnStartActivity(Activity activity, object payload) { if (this.options.TracedOperations != null && !this.options.TracedOperations.Contains(activity.OperationName)) { + MassTransitInstrumentationEventSource.Log.RequestIsFilteredOut(activity.OperationName); + activity.IsAllDataRequested = false; return; } activity.DisplayName = this.GetDisplayName(activity); - this.activitySource.Start(activity, this.GetActivityKind(activity)); + ActivityInstrumentationHelper.SetActivitySourceProperty(activity, ActivitySource); + ActivityInstrumentationHelper.SetKindProperty(activity, this.GetActivityKind(activity)); } public override void OnStopActivity(Activity activity, object payload) { if (this.options.TracedOperations != null && !this.options.TracedOperations.Contains(activity.OperationName)) { + MassTransitInstrumentationEventSource.Log.RequestIsFilteredOut(activity.OperationName); + activity.IsAllDataRequested = false; return; } if (activity.IsAllDataRequested) { - this.TransformMassTransitTags(activity); + try + { + this.TransformMassTransitTags(activity); + } + catch (Exception ex) + { + MassTransitInstrumentationEventSource.Log.EnrichmentException(ex); + } } - - this.activitySource.Stop(activity); } private string GetDisplayName(Activity activity) @@ -94,8 +108,8 @@ private void TransformMassTransitTags(Activity activity) this.RenameTag(activity, TagName.MessageId, SemanticConventions.AttributeMessagingMessageId); this.RenameTag(activity, TagName.ConversationId, SemanticConventions.AttributeMessagingConversationId); - this.RenameTag(activity, TagName.InitiatorId, SemanticConventions.AttributeMessagingMassTransitInitiatorId); - this.RenameTag(activity, TagName.CorrelationId, SemanticConventions.AttributeMessagingMassTransitCorrelationId); + this.RenameTag(activity, TagName.InitiatorId, MassTransitSemanticConventions.AttributeMessagingMassTransitInitiatorId); + this.RenameTag(activity, TagName.CorrelationId, MassTransitSemanticConventions.AttributeMessagingMassTransitCorrelationId); activity.SetTag(TagName.SourceAddress, null); } @@ -105,8 +119,8 @@ private void TransformMassTransitTags(Activity activity) this.RenameTag(activity, TagName.MessageId, SemanticConventions.AttributeMessagingMessageId); this.RenameTag(activity, TagName.ConversationId, SemanticConventions.AttributeMessagingConversationId); - this.RenameTag(activity, TagName.InitiatorId, SemanticConventions.AttributeMessagingMassTransitInitiatorId); - this.RenameTag(activity, TagName.CorrelationId, SemanticConventions.AttributeMessagingMassTransitCorrelationId); + this.RenameTag(activity, TagName.InitiatorId, MassTransitSemanticConventions.AttributeMessagingMassTransitInitiatorId); + this.RenameTag(activity, TagName.CorrelationId, MassTransitSemanticConventions.AttributeMessagingMassTransitCorrelationId); activity.SetTag(TagName.MessageId, null); @@ -116,7 +130,7 @@ private void TransformMassTransitTags(Activity activity) } else if (activity.OperationName == OperationName.Consumer.Consume) { - this.RenameTag(activity, TagName.ConsumerType, SemanticConventions.AttributeMessagingMassTransitConsumerType); + this.RenameTag(activity, TagName.ConsumerType, MassTransitSemanticConventions.AttributeMessagingMassTransitConsumerType); } else if (activity.OperationName == OperationName.Consumer.Handle) { diff --git a/src/OpenTelemetry.Contrib.Instrumentation.MassTransit/Implementation/MassTransitInstrumentationEventSource.cs b/src/OpenTelemetry.Contrib.Instrumentation.MassTransit/Implementation/MassTransitInstrumentationEventSource.cs new file mode 100644 index 0000000000..ad3defb78e --- /dev/null +++ b/src/OpenTelemetry.Contrib.Instrumentation.MassTransit/Implementation/MassTransitInstrumentationEventSource.cs @@ -0,0 +1,52 @@ +// +// 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.Diagnostics.Tracing; +using OpenTelemetry.Internal; + +namespace OpenTelemetry.Contrib.Instrumentation.MassTransit.Implementation +{ + /// + /// EventSource events emitted from the project. + /// + [EventSource(Name = "OpenTelemetry-Instrumentation-MassTransit")] + internal class MassTransitInstrumentationEventSource : EventSource + { + public static MassTransitInstrumentationEventSource Log = new MassTransitInstrumentationEventSource(); + + [Event(1, Message = "Request is filtered out.", Level = EventLevel.Verbose)] + public void RequestIsFilteredOut(string eventName) + { + this.WriteEvent(1, eventName); + } + + [NonEvent] + public void EnrichmentException(Exception ex) + { + if (this.IsEnabled(EventLevel.Error, (EventKeywords)(-1))) + { + this.EnrichmentException(ex.ToInvariantString()); + } + } + + [Event(2, Message = "Enrich threw exception. Exception {0}.", Level = EventLevel.Error)] + public void EnrichmentException(string exception) + { + this.WriteEvent(2, exception); + } + } +} diff --git a/src/OpenTelemetry.Contrib.Instrumentation.MassTransit/Implementation/MassTransitSemanticConventions.cs b/src/OpenTelemetry.Contrib.Instrumentation.MassTransit/Implementation/MassTransitSemanticConventions.cs new file mode 100644 index 0000000000..61340afccd --- /dev/null +++ b/src/OpenTelemetry.Contrib.Instrumentation.MassTransit/Implementation/MassTransitSemanticConventions.cs @@ -0,0 +1,25 @@ +// +// 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. +// + +namespace OpenTelemetry.Contrib.Instrumentation.MassTransit.Implementation +{ + internal class MassTransitSemanticConventions + { + public const string AttributeMessagingMassTransitInitiatorId = "messaging.masstransit.initiator_id"; + public const string AttributeMessagingMassTransitCorrelationId = "messaging.masstransit.correlation_id"; + public const string AttributeMessagingMassTransitConsumerType = "messaging.masstransit.consumer_type"; + } +} diff --git a/src/OpenTelemetry.Contrib.Instrumentation.MassTransit/Implementation/SemanticConventions.cs b/src/OpenTelemetry.Contrib.Instrumentation.MassTransit/Implementation/SemanticConventions.cs deleted file mode 100644 index c7ada24748..0000000000 --- a/src/OpenTelemetry.Contrib.Instrumentation.MassTransit/Implementation/SemanticConventions.cs +++ /dev/null @@ -1,46 +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. -// - -namespace OpenTelemetry.Contrib.Instrumentation.MassTransit.Implementation -{ - internal class SemanticConventions - { - public const string AttributeNetTransport = "net.transport"; - public const string AttributeNetPeerIp = "net.peer.ip"; - public const string AttributeNetPeerPort = "net.peer.port"; - public const string AttributeNetPeerName = "net.peer.name"; - public const string AttributeNetHostIp = "net.host.ip"; - public const string AttributeNetHostPort = "net.host.port"; - public const string AttributeNetHostName = "net.host.name"; - - public const string AttributeMessagingSystem = "messaging.system"; - public const string AttributeMessagingDestination = "messaging.destination"; - public const string AttributeMessagingDestinationKind = "messaging.destination_kind"; - public const string AttributeMessagingTempDestination = "messaging.temp_destination"; - public const string AttributeMessagingProtocol = "messaging.protocol"; - public const string AttributeMessagingProtocolVersion = "messaging.protocol_version"; - public const string AttributeMessagingUrl = "messaging.url"; - public const string AttributeMessagingMessageId = "messaging.message_id"; - public const string AttributeMessagingConversationId = "messaging.conversation_id"; - public const string AttributeMessagingPayloadSize = "messaging.message_payload_size_bytes"; - public const string AttributeMessagingPayloadCompressedSize = "messaging.message_payload_compressed_size_bytes"; - public const string AttributeMessagingOperation = "messaging.operation"; - - public const string AttributeMessagingMassTransitInitiatorId = "messaging.masstransit.initiator_id"; - public const string AttributeMessagingMassTransitCorrelationId = "messaging.masstransit.correlation_id"; - public const string AttributeMessagingMassTransitConsumerType = "messaging.masstransit.consumer_type"; - } -} diff --git a/src/OpenTelemetry.Contrib.Instrumentation.MassTransit/MassTransitInstrumentation.cs b/src/OpenTelemetry.Contrib.Instrumentation.MassTransit/MassTransitInstrumentation.cs index 632746802f..342f34c8fb 100644 --- a/src/OpenTelemetry.Contrib.Instrumentation.MassTransit/MassTransitInstrumentation.cs +++ b/src/OpenTelemetry.Contrib.Instrumentation.MassTransit/MassTransitInstrumentation.cs @@ -17,32 +17,25 @@ using System; using OpenTelemetry.Contrib.Instrumentation.MassTransit.Implementation; using OpenTelemetry.Instrumentation; -using OpenTelemetry.Trace; namespace OpenTelemetry.Contrib.Instrumentation.MassTransit { internal class MassTransitInstrumentation : IDisposable { - private readonly DiagnosticSourceSubscriber diagnosticSourceSubscriber; + internal const string MassTransitDiagnosticListenerName = "MassTransit"; - /// - /// Initializes a new instance of the class. - /// - /// ActivitySource adapter instance. - public MassTransitInstrumentation(ActivitySourceAdapter activitySource) - : this(activitySource, new MassTransitInstrumentationOptions()) - { - } + private readonly DiagnosticSourceSubscriber diagnosticSourceSubscriber; /// /// Initializes a new instance of the class. /// - /// ActivitySource adapter instance. /// Instrumentation options. - public MassTransitInstrumentation(ActivitySourceAdapter activitySource, MassTransitInstrumentationOptions options) + public MassTransitInstrumentation(MassTransitInstrumentationOptions options) { - var diagnosticListener = new MassTransitDiagnosticListener(activitySource, options); - this.diagnosticSourceSubscriber = new DiagnosticSourceSubscriber(diagnosticListener, null); + this.diagnosticSourceSubscriber = new DiagnosticSourceSubscriber( + name => new MassTransitDiagnosticListener(name, options), + listener => listener.Name == MassTransitDiagnosticListenerName, + null); this.diagnosticSourceSubscriber.Subscribe(); } diff --git a/src/OpenTelemetry.Contrib.Instrumentation.MassTransit/OpenTelemetry.Contrib.Instrumentation.MassTransit.csproj b/src/OpenTelemetry.Contrib.Instrumentation.MassTransit/OpenTelemetry.Contrib.Instrumentation.MassTransit.csproj index b59281ebd7..78a5753e9b 100644 --- a/src/OpenTelemetry.Contrib.Instrumentation.MassTransit/OpenTelemetry.Contrib.Instrumentation.MassTransit.csproj +++ b/src/OpenTelemetry.Contrib.Instrumentation.MassTransit/OpenTelemetry.Contrib.Instrumentation.MassTransit.csproj @@ -4,8 +4,9 @@ OpenTelemetry instrumentation for MassTransit $(PackageTags);distributed-tracing;MassTransit Instrumentation.MassTransit- + true - + diff --git a/src/OpenTelemetry.Contrib.Instrumentation.MassTransit/TracerProviderBuilderExtensions.cs b/src/OpenTelemetry.Contrib.Instrumentation.MassTransit/TracerProviderBuilderExtensions.cs index d0cc19bfdf..34cae8a7a7 100644 --- a/src/OpenTelemetry.Contrib.Instrumentation.MassTransit/TracerProviderBuilderExtensions.cs +++ b/src/OpenTelemetry.Contrib.Instrumentation.MassTransit/TracerProviderBuilderExtensions.cs @@ -16,6 +16,7 @@ using System; using OpenTelemetry.Contrib.Instrumentation.MassTransit; +using OpenTelemetry.Contrib.Instrumentation.MassTransit.Implementation; namespace OpenTelemetry.Trace { @@ -42,7 +43,15 @@ public static TracerProviderBuilder AddMassTransitInstrumentation( var options = new MassTransitInstrumentationOptions(); configureMassTransitInstrumentationOptions?.Invoke(options); - return builder.AddInstrumentation(activitySource => new MassTransitInstrumentation(activitySource, options)); + builder.AddInstrumentation(() => new MassTransitInstrumentation(options)); + builder.AddSource(MassTransitDiagnosticListener.ActivitySourceName); + + builder.AddLegacySource(OperationName.Consumer.Consume); + builder.AddLegacySource(OperationName.Consumer.Handle); + builder.AddLegacySource(OperationName.Transport.Send); + builder.AddLegacySource(OperationName.Transport.Receive); + + return builder; } } } diff --git a/test/OpenTelemetry.Contrib.Instrumentation.MassTransit.Tests/MassTransitInstrumentationTests.cs b/test/OpenTelemetry.Contrib.Instrumentation.MassTransit.Tests/MassTransitInstrumentationTests.cs index d46342dd89..54f08102bd 100644 --- a/test/OpenTelemetry.Contrib.Instrumentation.MassTransit.Tests/MassTransitInstrumentationTests.cs +++ b/test/OpenTelemetry.Contrib.Instrumentation.MassTransit.Tests/MassTransitInstrumentationTests.cs @@ -171,7 +171,7 @@ public async Task ShouldMapMassTransitTagsForConsumeMessageToOpenTelemetrySpecif Assert.NotNull(expectedMessageContext); Assert.Equal("OpenTelemetry.Contrib.Instrumentation.MassTransit.Tests.TestConsumer process", actualActivity.DisplayName); Assert.Equal(ActivityKind.Internal, actualActivity.Kind); - Assert.Equal("OpenTelemetry.Contrib.Instrumentation.MassTransit.Tests.TestConsumer", actualActivity.GetTagValue(SemanticConventions.AttributeMessagingMassTransitConsumerType)?.ToString()); + Assert.Equal("OpenTelemetry.Contrib.Instrumentation.MassTransit.Tests.TestConsumer", actualActivity.GetTagValue(MassTransitSemanticConventions.AttributeMessagingMassTransitConsumerType)?.ToString()); Assert.Null(actualActivity.GetTagValue(TagName.SpanKind)); Assert.Null(actualActivity.GetTagValue(TagName.PeerService)); @@ -223,8 +223,12 @@ public async Task ShouldMapMassTransitTagsForHandleMessageToOpenTelemetrySpecifi } } - [Fact] - public async Task MassTransitInstrumentationTestOptions() + [Theory] + [InlineData(OperationName.Consumer.Consume)] + [InlineData(OperationName.Consumer.Handle)] + [InlineData(OperationName.Transport.Send)] + [InlineData(OperationName.Transport.Receive)] + public async Task MassTransitInstrumentationTestOptions(string operationName) { using Activity activity = new Activity("Parent"); activity.SetParentId( @@ -237,7 +241,7 @@ public async Task MassTransitInstrumentationTestOptions() using (Sdk.CreateTracerProviderBuilder() .AddProcessor(activityProcessor.Object) .AddMassTransitInstrumentation(o => - o.TracedOperations = new HashSet(new[] { OperationName.Consumer.Consume })) + o.TracedOperations = new HashSet(new[] { operationName })) .Build()) { var harness = new InMemoryTestHarness(); @@ -261,11 +265,11 @@ await harness.InputQueueSendEndpoint.Send(new } } - Assert.Equal(4, activityProcessor.Invocations.Count); + Assert.Equal(8, activityProcessor.Invocations.Count); - var consumes = this.GetActivitiesFromInvocationsByOperationName(activityProcessor.Invocations, OperationName.Consumer.Consume); + var consumes = this.GetActivitiesFromInvocationsByOperationName(activityProcessor.Invocations, operationName); - Assert.Equal(2, consumes.Count()); + Assert.Single(consumes); } private IEnumerable GetActivitiesFromInvocationsByOperationName(IEnumerable invocations, string operationName) @@ -275,6 +279,7 @@ private IEnumerable GetActivitiesFromInvocationsByOperationName(IEnume .Where(i => i.Arguments.OfType() .Any(a => a.OperationName == operationName)) + .Where(i => i.Method.Name == "OnEnd") .Select(i => i.Arguments.OfType().Single()); } } diff --git a/test/OpenTelemetry.Contrib.Instrumentation.MassTransit.Tests/OpenTelemetry.Contrib.Instrumentation.MassTransit.Tests.csproj b/test/OpenTelemetry.Contrib.Instrumentation.MassTransit.Tests/OpenTelemetry.Contrib.Instrumentation.MassTransit.Tests.csproj index 522d9d3a73..917ccb2489 100644 --- a/test/OpenTelemetry.Contrib.Instrumentation.MassTransit.Tests/OpenTelemetry.Contrib.Instrumentation.MassTransit.Tests.csproj +++ b/test/OpenTelemetry.Contrib.Instrumentation.MassTransit.Tests/OpenTelemetry.Contrib.Instrumentation.MassTransit.Tests.csproj @@ -4,6 +4,7 @@ Unit test project for OpenTelemetry MassTransit instrumentation netcoreapp2.1;netcoreapp3.1 $(TargetFrameworks);net461 + true