Skip to content

Commit

Permalink
Wcf instrumentation + example apps (#38)
Browse files Browse the repository at this point in the history
* WCF instrumentation + example apps.

* Added an event source to log errors in Wcf instrumentation.

* Added content to the WCF instrumentation's README.

* Added support for the .NET Core version of WCF clients.

* Code review feedback.

* Updated code for 1.0 and changes done in main.

* Lint errors.

* Server tests and cleanup.

* Added client tests.

* Fixed some weirdness with SuppressDownstreamInstrumentation.

* Bug fixes.

* Attempting to fix lint errors.

* Code review and clean up.

* Added "wcf-" MinVerTagPrefix in csproj.

* Fun with copy-paste.

* Removed OpenTelemetry.Instrumentation.Http from wcf client examples.

* Updated link paths.

* Code review.

* Added wcf examples readme.

* Code review.

* Typo.

* Markdown lint.

* Code review.

* Code review.

* Code review.

* Code review.

* Add support for To & Via properties.

* Code review.

* Code review.

* Example readme update.

* Mirror fix from PR open-telemetry#73.

* Nits.

* Hashtable for cache.

* Code review.
  • Loading branch information
CodeBlanch authored Mar 5, 2021
1 parent 9c11735 commit fd31e5b
Show file tree
Hide file tree
Showing 43 changed files with 2,241 additions and 2 deletions.
50 changes: 50 additions & 0 deletions .github/workflows/package-Instrumentation.Wcf.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
name: Pack OpenTelemetry.Contrib.Instrumentation.Wcf

on:
workflow_dispatch:
inputs:
logLevel:
description: 'Log level'
required: true
default: 'warning'
push:
tags:
- 'Instrumentation.Wcf-*'

jobs:
build-test-pack:
runs-on: ${{ matrix.os }}
env:
PROJECT: OpenTelemetry.Contrib.Instrumentation.Wcf

strategy:
matrix:
os: [windows-latest]

steps:
- uses: actions/checkout@v2
with:
fetch-depth: 0 # fetching all

- name: Install dependencies
run: dotnet restore

- name: dotnet build ${{env.PROJECT}}
run: dotnet build src/${{env.PROJECT}} --configuration Release --no-restore -p:Deterministic=true

- name: dotnet test ${{env.PROJECT}}
run: dotnet test test/${{env.PROJECT}}.Tests

- name: dotnet pack ${{env.PROJECT}}
run: dotnet pack src/${{env.PROJECT}} --configuration Release --no-build

- name: Publish Artifacts
uses: actions/upload-artifact@v2
with:
name: ${{env.PROJECT}}-packages
path: '**/${{env.PROJECT}}/bin/**/*.*nupkg'

- name: Publish MyGet
run: |
nuget setApiKey ${{ secrets.MYGET_TOKEN }} -Source https://www.myget.org/F/opentelemetry-contrib/api/v2/package
nuget push **/${{env.PROJECT}}/bin/**/*.nupkg -Source https://www.myget.org/F/opentelemetry-contrib/api/v2/package
3 changes: 3 additions & 0 deletions examples/Directory.Build.props
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
<Project>
<Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildProjectDirectory), 'opentelemetry-dotnet-contrib.sln'))\build\Common.nonprod.props" />
</Project>
28 changes: 28 additions & 0 deletions examples/wcf/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
# WCF Instrumentation for OpenTelemetry .NET - Examples

Project structure:

* Examples.Wcf.Client.Core

An example of how to call a WCF service with OpenTelemetry instrumentation on
.NET Core.

* Examples.Wcf.Client.NetFramework

An example of how to call a WCF service with OpenTelemetry instrumentation on
.NET Framework.

* Examples.Wcf.Server.NetFramework

An example of how to implement a WCF service with OpenTelemetry
instrumentation on .NET Framework. The service will listen on http which
requires special permission on Windows. The easiest thing to do is run VS with
admin privileges. For details see: [Configuring HTTP and
HTTPS](https://docs.microsoft.com/en-us/dotnet/framework/wcf/feature-details/configuring-http-and-https).

Note: There is no .NET Core server example because only the client libraries
for WCF are available on .NET Core / .NET 5.

* Examples.Wcf.Shared

Contains the shared contract and request & response objects.
31 changes: 31 additions & 0 deletions examples/wcf/client-core/Examples.Wcf.Client.Core.csproj
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>netcoreapp3.1</TargetFramework>
<IsPackable>false</IsPackable>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="System.ServiceModel.Http" Version="4.7.0" />
<PackageReference Include="System.ServiceModel.NetTcp" Version="4.7.0" />
<PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="3.1.9" />
<PackageReference Include="Microsoft.Extensions.Configuration.Binder" Version="3.1.9" />
<PackageReference Include="OpenTelemetry.Exporter.Zipkin" Version="1.0.1" />
</ItemGroup>

<ItemGroup>
<ProjectReference Include="..\..\..\src\OpenTelemetry.Contrib.Instrumentation.Wcf\OpenTelemetry.Contrib.Instrumentation.Wcf.csproj" />
</ItemGroup>

<ItemGroup>
<ProjectReference Include="..\shared\Examples.Wcf.Shared.csproj" />
</ItemGroup>

<ItemGroup>
<None Update="appsettings.json">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
</ItemGroup>

</Project>
94 changes: 94 additions & 0 deletions examples/wcf/client-core/Program.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
// <copyright file="Program.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>

using System;
using System.IO;
using System.ServiceModel;
using System.ServiceModel.Channels;
using System.Threading.Tasks;
using Microsoft.Extensions.Configuration;
using OpenTelemetry;
using OpenTelemetry.Contrib.Instrumentation.Wcf;
using OpenTelemetry.Resources;
using OpenTelemetry.Trace;

namespace Examples.Wcf.Client
{
internal static class Program
{
public static async Task Main()
{
IConfigurationRoot config = new ConfigurationBuilder()
.SetBasePath(Directory.GetCurrentDirectory())
.AddJsonFile("appsettings.json")
.Build();

using var openTelemetry = Sdk.CreateTracerProviderBuilder()
.SetResourceBuilder(ResourceBuilder.CreateDefault().AddService("Wcf-Client-Core"))
.AddWcfInstrumentation()
.AddZipkinExporter()
.Build();

await CallService(
new BasicHttpBinding(BasicHttpSecurityMode.None),
new EndpointAddress(config.GetSection("Service").GetValue<string>("HttpAddress"))).ConfigureAwait(false);
await CallService(
new NetTcpBinding(SecurityMode.None),
new EndpointAddress(config.GetSection("Service").GetValue<string>("TcpAddress"))).ConfigureAwait(false);

Console.WriteLine("Press enter to exit.");
Console.ReadLine();
}

private static async Task CallService(Binding binding, EndpointAddress remoteAddress)
{
// Note: Best practice is to re-use your client/channel instances.
// This code is not meant to illustrate best practices, only the
// instrumentation.
StatusServiceClient client = new StatusServiceClient(binding, remoteAddress);
client.Endpoint.EndpointBehaviors.Add(new TelemetryEndpointBehavior());
try
{
await client.OpenAsync().ConfigureAwait(false);

var response = await client.PingAsync(
new StatusRequest
{
Status = Guid.NewGuid().ToString("N"),
}).ConfigureAwait(false);

Console.WriteLine($"Server returned: {response?.ServerTime}");
}
finally
{
try
{
if (client.State == CommunicationState.Faulted)
{
client.Abort();
}
else
{
await client.CloseAsync().ConfigureAwait(false);
}
}
catch
{
}
}
}
}
}
50 changes: 50 additions & 0 deletions examples/wcf/client-core/StatusServiceClient.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
// <copyright file="StatusServiceClient.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>

using System.ServiceModel;
using System.ServiceModel.Channels;
using System.Threading.Tasks;

namespace Examples.Wcf.Client
{
public class StatusServiceClient : ClientBase<IStatusServiceContract>, IStatusServiceContract
{
public StatusServiceClient(string name)
: base(name)
{
}

public StatusServiceClient(Binding binding, EndpointAddress remoteAddress)
: base(binding, remoteAddress)
{
}

public Task<StatusResponse> PingAsync(StatusRequest request)
=> this.Channel.PingAsync(request);

public Task OpenAsync()
{
ICommunicationObject communicationObject = this;
return Task.Factory.FromAsync(communicationObject.BeginOpen, communicationObject.EndOpen, null);
}

public Task CloseAsync()
{
ICommunicationObject communicationObject = this;
return Task.Factory.FromAsync(communicationObject.BeginClose, communicationObject.EndClose, null);
}
}
}
6 changes: 6 additions & 0 deletions examples/wcf/client-core/appsettings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
"Service": {
"HttpAddress": "http://localhost:9009/Telemetry",
"TcpAddress": "net.tcp://localhost:9090/Telemetry"
}
}
33 changes: 33 additions & 0 deletions examples/wcf/client-netframework/App.config
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<system.serviceModel>
<extensions>
<behaviorExtensions>
<add name="telemetryExtension" type="OpenTelemetry.Contrib.Instrumentation.Wcf.TelemetryBehaviourExtensionElement, OpenTelemetry.Contrib.Instrumentation.Wcf" />
</behaviorExtensions>
</extensions>
<behaviors>
<endpointBehaviors>
<behavior name="telemetry">
<telemetryExtension />
</behavior>
</endpointBehaviors>
</behaviors>
<bindings>
<basicHttpBinding>
<binding name="basicHttpConfig">
<security mode="None" />
</binding>
</basicHttpBinding>
<netTcpBinding>
<binding name="netTCPConfig">
<security mode="None" />
</binding>
</netTcpBinding>
</bindings>
<client>
<endpoint address="http://localhost:9009/Telemetry" binding="basicHttpBinding" bindingConfiguration="basicHttpConfig" behaviorConfiguration="telemetry" contract="Examples.Wcf.IStatusServiceContract" name="StatusService_Http" />
<endpoint address="net.tcp://localhost:9090/Telemetry" binding="netTcpBinding" bindingConfiguration="netTCPConfig" behaviorConfiguration="telemetry" contract="Examples.Wcf.IStatusServiceContract" name="StatusService_Tcp" />
</client>
</system.serviceModel>
</configuration>
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net46</TargetFramework>
<IsPackable>false</IsPackable>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="OpenTelemetry.Exporter.Zipkin" Version="1.0.1" />
</ItemGroup>

<ItemGroup>
<ProjectReference Include="..\..\..\src\OpenTelemetry.Contrib.Instrumentation.Wcf\OpenTelemetry.Contrib.Instrumentation.Wcf.csproj" />
</ItemGroup>

<ItemGroup>
<ProjectReference Include="..\shared\Examples.Wcf.Shared.csproj" />
</ItemGroup>

<ItemGroup>
<Reference Include="System.ServiceModel" />
</ItemGroup>

</Project>
Loading

0 comments on commit fd31e5b

Please sign in to comment.