Skip to content

Commit

Permalink
Issue #125:Adding enricher for Wcf instrumentation
Browse files Browse the repository at this point in the history
  • Loading branch information
epaulsen committed Jun 3, 2021
1 parent 0e3cc6d commit bf03535
Show file tree
Hide file tree
Showing 7 changed files with 133 additions and 3 deletions.
18 changes: 18 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,24 @@ 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;
options.Enrich = (activity,eventName,message) => // -> Enable enriching an activity after it is created.
{
if(eventName == "AfterReceiveRequest") // For event names, please refer to string contstants in WcfEventNames class.
{
activity.AddTag("companyname.customtag", Guid.NewGuid());
}
}
})
.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,8 @@ public object BeforeSendRequest(ref Message request, IClientChannel channel)
{
activity.SetTag(WcfInstrumentationConstants.SoapViaTag, request.Properties.Via.ToString());
}

WcfInstrumentationActivitySource.Options.Enrich?.Invoke(activity, WcfEventNames.BeforeSendRequest, request);
}
}

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

activity.SetTag(WcfInstrumentationConstants.SoapReplyActionTag, reply.Headers.Action);
WcfInstrumentationActivitySource.Options.Enrich?.Invoke(activity, WcfEventNames.AfterReceiveReply, reply);
}

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

WcfInstrumentationActivitySource.Options.Enrich?.Invoke(activity, WcfEventNames.AfterReceiveRequest, request);
}
}

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

activity.SetTag(WcfInstrumentationConstants.SoapReplyActionTag, reply.Headers.Action);
WcfInstrumentationActivitySource.Options.Enrich?.Invoke(activity, WcfEventNames.BeforeSendReply, reply);
}

activity.Stop();
Expand Down
46 changes: 46 additions & 0 deletions src/OpenTelemetry.Contrib.Instrumentation.Wcf/WcfEventNames.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
// <copyright file="WcfEventNames.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 WcfEventNames
{
#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="WcfEventNames"/>.
/// </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,13 @@ public void Dispose()
[InlineData(true, false, false)]
[InlineData(false)]
[InlineData(true, false, true, true)]
[InlineData(true, false, true, true, true)]
public async Task OutgoingRequestInstrumentationTest(
bool instrument,
bool filter = false,
bool suppressDownstreamInstrumentation = true,
bool includeVersion = false)
bool includeVersion = false,
bool enrich = false)
{
#if NETFRAMEWORK
const string OutgoingHttpOperationName = "OpenTelemetry.HttpWebRequest.HttpRequestOut";
Expand All @@ -147,6 +149,22 @@ public async Task OutgoingRequestInstrumentationTest(
builder
.AddWcfInstrumentation(options =>
{
if (enrich)
{
options.Enrich = (activity, eventName, message) =>
{
switch (eventName)
{
case WcfEventNames.BeforeSendRequest:
activity.AddTag("client.beforesendrequest", WcfEventNames.BeforeSendRequest);
break;
case WcfEventNames.AfterReceiveReply:
activity.AddTag("client.afterreceivereply", WcfEventNames.AfterReceiveReply);
break;
}
};
}

options.OutgoingRequestFilter = (Message m) =>
{
return !filter;
Expand Down Expand Up @@ -226,6 +244,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)
{
Assert.Equal(WcfEventNames.BeforeSendRequest, activity.TagObjects.Single(t => t.Key == "client.beforesendrequest").Value);
Assert.Equal(WcfEventNames.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,12 @@ public void Dispose()
[InlineData(true, true)]
[InlineData(false)]
[InlineData(true, false, true)]
[InlineData(true, false, true, true)]
public async Task IncomingRequestInstrumentationTest(
bool instrument,
bool filter = false,
bool includeVersion = false)
bool includeVersion = false,
bool enrich = false)
{
List<Activity> stoppedActivities = new List<Activity>();

Expand All @@ -108,6 +110,22 @@ public async Task IncomingRequestInstrumentationTest(
tracerProvider = Sdk.CreateTracerProviderBuilder()
.AddWcfInstrumentation(options =>
{
if (enrich)
{
options.Enrich = (activity, eventName, message) =>
{
switch (eventName)
{
case WcfEventNames.AfterReceiveRequest:
activity.AddTag("server.afterreceiverequest", WcfEventNames.AfterReceiveRequest);
break;
case WcfEventNames.BeforeSendReply:
activity.AddTag("server.beforesendreply", WcfEventNames.BeforeSendReply);
break;
}
};
}

options.IncomingRequestFilter = (Message m) =>
{
return !filter;
Expand Down Expand Up @@ -164,6 +182,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)
{
Assert.Equal(WcfEventNames.AfterReceiveRequest, activity.TagObjects.Single(t => t.Key == "server.afterreceiverequest").Value);
Assert.Equal(WcfEventNames.BeforeSendReply, activity.TagObjects.Single(t => t.Key == "server.beforesendreply").Value);
}
}
else
{
Expand Down

0 comments on commit bf03535

Please sign in to comment.