Skip to content

Commit

Permalink
Issue #125:Adding enricher for Wcf instrumentation (#126)
Browse files Browse the repository at this point in the history
  • Loading branch information
epaulsen authored Jun 15, 2021
1 parent e6b225e commit df49552
Show file tree
Hide file tree
Showing 9 changed files with 214 additions and 6 deletions.
3 changes: 3 additions & 0 deletions src/OpenTelemetry.Contrib.Instrumentation.Wcf/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,8 @@

## Unreleased

* Added enricher for WCF activity
([#126])(<https://github.com/open-telemetry/opentelemetry-dotnet-contrib/pull/126>)

* Updated OTel SDK package version to 1.1.0-beta1
([#100](https://github.com/open-telemetry/opentelemetry-dotnet-contrib/pull/100))
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,21 @@ public void RequestFilterException(string exception)
this.WriteEvent(EventIds.RequestFilterException, exception);
}

[NonEvent]
public void EnrichmentException(Exception exception)
{
if (this.IsEnabled(EventLevel.Error, (EventKeywords)(-1)))
{
this.EnrichmentException(ToInvariantString(exception));
}
}

[Event(EventIds.EnrichmentException, Message = "Enrichment threw exception. Exception {0}.", Level = EventLevel.Error)]
public void EnrichmentException(string exception)
{
this.WriteEvent(EventIds.EnrichmentException, exception);
}

/// <summary>
/// Returns a culture-independent string representation of the given <paramref name="exception"/> object,
/// appropriate for diagnostics tracing.
Expand All @@ -70,6 +85,7 @@ private class EventIds
{
public const int RequestIsFilteredOut = 1;
public const int RequestFilterException = 2;
public const int EnrichmentException = 3;
}
}
}
27 changes: 27 additions & 0 deletions src/OpenTelemetry.Contrib.Instrumentation.Wcf/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,33 @@ using var openTelemetry = Sdk.CreateTracerProviderBuilder()
.Build();
```

Instrumentation can be configured via options overload for
`AddWcfInstrumentation` method:

```csharp
using var openTelemetry = Sdk.CreateTracerProviderBuilder()
.AddWcfInstrumentation(options =>
{
options.SuppressDownstreamInstrumentation = false;

// Enable enriching an activity after it is created.
options.Enrich = (activity, eventName, message) =>
{
var wcfMessage = message as Message;

// For event names, please refer to string constants in
// WcfEnrichEventNames class.
if (eventName == WcfEnrichEventNames.AfterReceiveReply)
{
activity.SetTag(
"companyname.messagetag",
wcfMessage.Properties["CustomProperty"]);
}
};
})
.Build();
```

## WCF Client Configuration (.NET Framework)

Add the `IClientMessageInspector` instrumentation via a behavior extension on
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,6 @@ public object BeforeSendRequest(ref Message request, IClientChannel channel)
Activity activity = WcfInstrumentationActivitySource.ActivitySource.StartActivity(
WcfInstrumentationActivitySource.OutgoingRequestActivityName,
ActivityKind.Client);

IDisposable suppressionScope = this.SuppressDownstreamInstrumentation();

if (activity != null)
Expand Down Expand Up @@ -111,6 +110,15 @@ public object BeforeSendRequest(ref Message request, IClientChannel channel)
{
activity.SetTag(WcfInstrumentationConstants.SoapViaTag, request.Properties.Via.ToString());
}

try
{
WcfInstrumentationActivitySource.Options.Enrich?.Invoke(activity, WcfEnrichEventNames.BeforeSendRequest, request);
}
catch (Exception ex)
{
WcfInstrumentationEventSource.Log.EnrichmentException(ex);
}
}
}

Expand Down Expand Up @@ -139,6 +147,14 @@ public void AfterReceiveReply(ref Message reply, object correlationState)
}

activity.SetTag(WcfInstrumentationConstants.SoapReplyActionTag, reply.Headers.Action);
try
{
WcfInstrumentationActivitySource.Options.Enrich?.Invoke(activity, WcfEnrichEventNames.AfterReceiveReply, reply);
}
catch (Exception ex)
{
WcfInstrumentationEventSource.Log.EnrichmentException(ex);
}
}

activity.Stop();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,15 @@ public object AfterReceiveRequest(ref Message request, IClientChannel channel, I
activity.SetTag(WcfInstrumentationConstants.WcfChannelSchemeTag, localAddressUri.Scheme);
activity.SetTag(WcfInstrumentationConstants.WcfChannelPathTag, localAddressUri.LocalPath);
}

try
{
WcfInstrumentationActivitySource.Options.Enrich?.Invoke(activity, WcfEnrichEventNames.AfterReceiveRequest, request);
}
catch (Exception ex)
{
WcfInstrumentationEventSource.Log.EnrichmentException(ex);
}
}
}

Expand All @@ -121,6 +130,14 @@ public void BeforeSendReply(ref Message reply, object correlationState)
}

activity.SetTag(WcfInstrumentationConstants.SoapReplyActionTag, reply.Headers.Action);
try
{
WcfInstrumentationActivitySource.Options.Enrich?.Invoke(activity, WcfEnrichEventNames.BeforeSendReply, reply);
}
catch (Exception ex)
{
WcfInstrumentationEventSource.Log.EnrichmentException(ex);
}
}

activity.Stop();
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
// <copyright file="WcfEnrichEventNames.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>

namespace OpenTelemetry.Contrib.Instrumentation.Wcf
{
/// <summary>
/// Constants used for event names when enriching an activity.
/// </summary>
public class WcfEnrichEventNames
{
#if NETFRAMEWORK
/// <summary>
/// WCF service activity, event happens before WCF service method is invoked.
/// </summary>
public const string AfterReceiveRequest = "AfterReceiveRequest";

/// <summary>
/// WCF service activity, event happens after the WCF service method is invoked but before the reply is sent back to the client.
/// </summary>
public const string BeforeSendReply = "BeforeSendReply";
#endif

/// <summary>
/// WCF client activity, event happens before the request is sent across the wire.
/// </summary>
public const string BeforeSendRequest = "BeforeSendRequest";

/// <summary>
/// WCF client activity, event happens after a reply from the WCF service is received.
/// </summary>
public const string AfterReceiveReply = "AfterReceiveReply";
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
// </copyright>

using System;
using System.Diagnostics;
using System.ServiceModel.Channels;
using OpenTelemetry.Context.Propagation;

Expand All @@ -34,6 +35,18 @@ public class WcfInstrumentationOptions
new BaggagePropagator(),
});

/// <summary>
/// Gets or sets an action to enrich an Activity.
/// </summary>
/// <remarks>
/// <para><see cref="Activity"/>: the activity being enriched.</para>
/// <para>string: the name of the event. Will be one of the constants in <see cref="WcfEnrichEventNames"/>.
/// </para>
/// <para>object: the raw <see cref="Message"/> from which additional information can be extracted to enrich the activity.
/// </para>
/// </remarks>
public Action<Activity, string, object> Enrich { get; set; }

/// <summary>
/// Gets or sets a Filter function to filter instrumentation for requests on a per request basis.
/// The Filter gets the Message, and should return a boolean.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -126,11 +126,15 @@ public void Dispose()
[InlineData(true, false, false)]
[InlineData(false)]
[InlineData(true, false, true, true)]
[InlineData(true, false, true, true, true)]
[InlineData(true, false, true, true, true, true)]
public async Task OutgoingRequestInstrumentationTest(
bool instrument,
bool filter = false,
bool suppressDownstreamInstrumentation = true,
bool includeVersion = false)
bool includeVersion = false,
bool enrich = false,
bool enrichmentException = false)
{
#if NETFRAMEWORK
const string OutgoingHttpOperationName = "OpenTelemetry.HttpWebRequest.HttpRequestOut";
Expand All @@ -147,10 +151,30 @@ public async Task OutgoingRequestInstrumentationTest(
builder
.AddWcfInstrumentation(options =>
{
options.OutgoingRequestFilter = (Message m) =>
if (enrich)
{
return !filter;
};
if (!enrichmentException)
{
options.Enrich = (activity, eventName, message) =>
{
switch (eventName)
{
case WcfEnrichEventNames.BeforeSendRequest:
activity.SetTag("client.beforesendrequest", WcfEnrichEventNames.BeforeSendRequest);
break;
case WcfEnrichEventNames.AfterReceiveReply:
activity.SetTag("client.afterreceivereply", WcfEnrichEventNames.AfterReceiveReply);
break;
}
};
}
else
{
options.Enrich = (activity, eventName, message) => throw new Exception("Error while enriching activity");
}
}

options.OutgoingRequestFilter = (Message m) => !filter;
options.SuppressDownstreamInstrumentation = suppressDownstreamInstrumentation;
options.SetSoapMessageVersion = includeVersion;
})
Expand Down Expand Up @@ -226,6 +250,12 @@ public async Task OutgoingRequestInstrumentationTest(
{
Assert.Equal("Soap11 (http://schemas.xmlsoap.org/soap/envelope/) AddressingNone (http://schemas.microsoft.com/ws/2005/05/addressing/none)", activity.TagObjects.FirstOrDefault(t => t.Key == WcfInstrumentationConstants.SoapMessageVersionTag).Value);
}

if (enrich && !enrichmentException)
{
Assert.Equal(WcfEnrichEventNames.BeforeSendRequest, activity.TagObjects.Single(t => t.Key == "client.beforesendrequest").Value);
Assert.Equal(WcfEnrichEventNames.AfterReceiveReply, activity.TagObjects.Single(t => t.Key == "client.afterreceivereply").Value);
}
}
else
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -87,10 +87,14 @@ public void Dispose()
[InlineData(true, true)]
[InlineData(false)]
[InlineData(true, false, true)]
[InlineData(true, false, true, true)]
[InlineData(true, false, true, true, true)]
public async Task IncomingRequestInstrumentationTest(
bool instrument,
bool filter = false,
bool includeVersion = false)
bool includeVersion = false,
bool enrich = false,
bool enrichmentExcecption = false)
{
List<Activity> stoppedActivities = new List<Activity>();

Expand All @@ -108,6 +112,36 @@ public async Task IncomingRequestInstrumentationTest(
tracerProvider = Sdk.CreateTracerProviderBuilder()
.AddWcfInstrumentation(options =>
{
if (enrich)
{
if (!enrichmentExcecption)
{
options.Enrich = (activity, eventName, message) =>
{
switch (eventName)
{
case WcfEnrichEventNames.AfterReceiveRequest:
activity.SetTag(
"server.afterreceiverequest",
WcfEnrichEventNames.AfterReceiveRequest);
break;
case WcfEnrichEventNames.BeforeSendReply:
activity.SetTag(
"server.beforesendreply",
WcfEnrichEventNames.BeforeSendReply);
break;
}
};
}
else
{
options.Enrich = (activity, eventName, message) =>
{
throw new Exception("Failure whilst enriching activity");
};
}
}

options.IncomingRequestFilter = (Message m) =>
{
return !filter;
Expand Down Expand Up @@ -164,6 +198,12 @@ public async Task IncomingRequestInstrumentationTest(
{
Assert.Equal("Soap12 (http://www.w3.org/2003/05/soap-envelope) Addressing10 (http://www.w3.org/2005/08/addressing)", activity.TagObjects.FirstOrDefault(t => t.Key == WcfInstrumentationConstants.SoapMessageVersionTag).Value);
}

if (enrich && !enrichmentExcecption)
{
Assert.Equal(WcfEnrichEventNames.AfterReceiveRequest, activity.TagObjects.Single(t => t.Key == "server.afterreceiverequest").Value);
Assert.Equal(WcfEnrichEventNames.BeforeSendReply, activity.TagObjects.Single(t => t.Key == "server.beforesendreply").Value);
}
}
else
{
Expand Down

0 comments on commit df49552

Please sign in to comment.