This commit is contained in:
Stef Heyenrath
2026-01-18 18:43:18 +01:00
44 changed files with 1990 additions and 88 deletions

View File

@@ -0,0 +1,35 @@
// Copyright © WireMock.Net
using JetBrains.Annotations;
namespace WireMock.OpenTelemetry;
/// <summary>
/// OpenTelemetry exporter configuration options for WireMock.Net.
/// These options control the export of traces to an OTLP endpoint.
/// For controlling what data is recorded in traces, configure ActivityTracingOptions in WireMockServerSettings.
/// </summary>
public class OpenTelemetryOptions
{
/// <summary>
/// Gets or sets a value indicating whether to exclude admin interface requests from ASP.NET Core instrumentation.
/// Default is <c>true</c>.
/// </summary>
/// <remarks>
/// This controls the ASP.NET Core HTTP server instrumentation filter.
/// To also exclude admin requests from WireMock's own activity tracing,
/// set <c>ActivityTracingOptions.ExcludeAdminRequests</c> in WireMockServerSettings.
/// </remarks>
[PublicAPI]
public bool ExcludeAdminRequests { get; set; } = true;
/// <summary>
/// Gets or sets the OTLP exporter endpoint URL.
/// When set, traces will be exported to this endpoint using the OTLP protocol.
/// Example: "http://localhost:4317" for gRPC or "http://localhost:4318" for HTTP.
/// If not set, the OTLP exporter will use the <c>OTEL_EXPORTER_OTLP_ENDPOINT</c> environment variable,
/// or fall back to the default endpoint (<c>http://localhost:4317</c> for gRPC).
/// </summary>
[PublicAPI]
public string? OtlpExporterEndpoint { get; set; }
}

View File

@@ -0,0 +1,44 @@
// Copyright © WireMock.Net
using System.Collections;
using Stef.Validation;
using WireMock.Settings;
namespace WireMock.OpenTelemetry;
/// <summary>
/// A static helper class to parse commandline arguments into OpenTelemetryOptions.
/// </summary>
public static class OpenTelemetryOptionsParser
{
private const string Prefix = "OpenTelemetry";
/// <summary>
/// Parse commandline arguments into OpenTelemetryOptions.
/// </summary>
/// <param name="args">The commandline arguments</param>
/// <param name="environment">The environment settings (optional)</param>
/// <param name="options">The parsed options, or null if OpenTelemetry is not enabled</param>
/// <returns>Always returns true.</returns>
public static bool TryParseArguments(string[] args, IDictionary? environment, out OpenTelemetryOptions? options)
{
Guard.HasNoNulls(args);
var parser = new SimpleSettingsParser();
parser.Parse(args, environment);
if (!parser.GetBoolValue($"{Prefix}Enabled"))
{
options = null;
return true;
}
options = new OpenTelemetryOptions
{
ExcludeAdminRequests = parser.GetBoolValue($"{Prefix}ExcludeAdminRequests", defaultValue: true),
OtlpExporterEndpoint = parser.GetStringValue($"{Prefix}OtlpExporterEndpoint")
};
return true;
}
}

View File

@@ -0,0 +1,160 @@
# WireMock.Net.OpenTelemetry
OpenTelemetry tracing support for WireMock.Net. This package provides instrumentation and OTLP (OpenTelemetry Protocol) exporting capabilities.
## Overview
WireMock.Net automatically creates `System.Diagnostics.Activity` objects for request tracing when `ActivityTracingOptions` is configured (not null). These activities use the built-in .NET distributed tracing infrastructure and are available without any additional dependencies.
This package provides:
- **WireMock.Net instrumentation** - Adds the WireMock.Net ActivitySource to the tracing pipeline
- **ASP.NET Core instrumentation** - Standard HTTP server tracing with request filtering
- **OTLP exporter** - Sends traces to an OpenTelemetry collector
## Installation
```bash
dotnet add package WireMock.Net.OpenTelemetry
```
## Usage
### Option 1: Using AdditionalServiceRegistration (Recommended)
```csharp
using WireMock.OpenTelemetry;
using WireMock.Server;
using WireMock.Settings;
var openTelemetryOptions = new OpenTelemetryOptions
{
ExcludeAdminRequests = true,
OtlpExporterEndpoint = "http://localhost:4317" // Your OTEL collector
};
var settings = new WireMockServerSettings
{
// Setting ActivityTracingOptions (not null) enables activity creation in middleware
ActivityTracingOptions = new ActivityTracingOptions
{
ExcludeAdminRequests = true,
RecordRequestBody = false, // PII concern
RecordResponseBody = false, // PII concern
RecordMatchDetails = true
},
AdditionalServiceRegistration = services =>
{
services.AddWireMockOpenTelemetry(openTelemetryOptions);
}
};
var server = WireMockServer.Start(settings);
```
### Option 2: Custom TracerProvider Configuration
For more control over the tracing configuration:
```csharp
using OpenTelemetry;
using OpenTelemetry.Trace;
using WireMock.OpenTelemetry;
var openTelemetryOptions = new OpenTelemetryOptions();
// Configure your own TracerProvider
using var tracerProvider = Sdk.CreateTracerProviderBuilder()
.AddWireMockInstrumentation(openTelemetryOptions) // Adds WireMock.Net source
.AddOtlpExporter(options =>
{
options.Endpoint = new Uri("http://localhost:4317");
})
.Build();
```
## Extension Methods
### `AddWireMockOpenTelemetry`
Adds full OpenTelemetry tracing to the service collection with instrumentation and OTLP exporter:
```csharp
services.AddWireMockOpenTelemetry(openTelemetryOptions);
```
This configures:
- The WireMock.Net ActivitySource
- ASP.NET Core instrumentation
- OTLP exporter (using the endpoint from `OpenTelemetryOptions.OtlpExporterEndpoint` or the `OTEL_EXPORTER_OTLP_ENDPOINT` environment variable)
### `AddWireMockInstrumentation`
Adds WireMock instrumentation to an existing TracerProviderBuilder:
```csharp
tracerProvider.AddWireMockInstrumentation(openTelemetryOptions);
```
## Configuration
### OpenTelemetryOptions (Exporter configuration)
| Property | Description | Default |
|----------|-------------|---------|
| `ExcludeAdminRequests` | Exclude `/__admin/*` from ASP.NET Core instrumentation | `true` |
| `OtlpExporterEndpoint` | OTLP collector endpoint URL | Uses `OTEL_EXPORTER_OTLP_ENDPOINT` env var |
### ActivityTracingOptions (Trace content configuration)
Configured in `WireMockServerSettings.ActivityTracingOptions`:
| Property | Description | Default |
|----------|-------------|---------|
| `ExcludeAdminRequests` | Exclude `/__admin/*` from WireMock activity creation | `true` |
| `RecordRequestBody` | Include request body in trace attributes | `false` |
| `RecordResponseBody` | Include response body in trace attributes | `false` |
| `RecordMatchDetails` | Include mapping match details in trace attributes | `true` |
## Trace Attributes
WireMock.Net traces include these semantic conventions:
**Standard HTTP attributes:**
- `http.request.method`
- `url.full`
- `url.path`
- `server.address`
- `http.response.status_code`
- `client.address`
**WireMock-specific attributes:**
- `wiremock.mapping.matched` - Whether a mapping was found
- `wiremock.mapping.guid` - GUID of the matched mapping
- `wiremock.mapping.title` - Title of the matched mapping
- `wiremock.match.score` - Match score
- `wiremock.request.guid` - GUID of the request
## CLI Arguments
When using WireMock.Net.StandAlone or Docker images, activity tracing and OpenTelemetry can be configured via command-line arguments:
**Activity Tracing (what gets recorded):**
```bash
--ActivityTracingEnabled true
--ActivityTracingExcludeAdminRequests true
--ActivityTracingRecordRequestBody false
--ActivityTracingRecordResponseBody false
--ActivityTracingRecordMatchDetails true
```
**OpenTelemetry Export (where traces are sent):**
```bash
--OpenTelemetryEnabled true
--OpenTelemetryOtlpExporterEndpoint http://localhost:4317
--OpenTelemetryExcludeAdminRequests true
```
## Requirements
- .NET 6.0 or later
- WireMock.Net 1.6.0 or later

View File

@@ -0,0 +1,38 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<!--<Version>0.0.1-preview-01</Version>-->
<Description>OpenTelemetry exporter support for WireMock.Net</Description>
<AssemblyTitle>WireMock.Net.OpenTelemetry</AssemblyTitle>
<Authors>Petr Houška</Authors>
<TargetFrameworks>net4.8;net8.0</TargetFrameworks>
<GenerateDocumentationFile>true</GenerateDocumentationFile>
<RootNamespace>WireMock.OpenTelemetry</RootNamespace>
<PackageTags>wiremock;opentelemetry;otel;tracing;telemetry</PackageTags>
<ProjectGuid>{C8F4E6D2-9A3B-4F1C-8D5E-7A2B3C4D5E6F}</ProjectGuid>
<PublishRepositoryUrl>true</PublishRepositoryUrl>
<EmbedUntrackedSources>true</EmbedUntrackedSources>
<AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>
<GenerateBindingRedirectsOutputType>true</GenerateBindingRedirectsOutputType>
<CodeAnalysisRuleSet>../WireMock.Net/WireMock.Net.ruleset</CodeAnalysisRuleSet>
<SignAssembly>true</SignAssembly>
<AssemblyOriginatorKeyFile>../WireMock.Net/WireMock.Net.snk</AssemblyOriginatorKeyFile>
<PublicSign Condition=" '$(OS)' != 'Windows_NT' ">true</PublicSign>
<PackageLicenseExpression>MIT</PackageLicenseExpression>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)' == 'Release' ">
<GeneratePackageOnBuild>true</GeneratePackageOnBuild>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="OpenTelemetry.Extensions.Hosting" Version="1.14.0" />
<PackageReference Include="OpenTelemetry.Instrumentation.AspNetCore" Version="1.14.0" />
<PackageReference Include="OpenTelemetry.Exporter.OpenTelemetryProtocol" Version="1.14.0" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\WireMock.Net.Shared\WireMock.Net.Shared.csproj" />
</ItemGroup>
</Project>

View File

@@ -0,0 +1,114 @@
// Copyright © WireMock.Net
using System;
using Microsoft.Extensions.DependencyInjection;
using OpenTelemetry.Resources;
using OpenTelemetry.Trace;
namespace WireMock.OpenTelemetry;
/// <summary>
/// Extension methods for configuring OpenTelemetry tracing for WireMock.Net.
/// </summary>
public static class WireMockOpenTelemetryExtensions
{
private const string ServiceName = "WireMock.Net";
private const string WireMockActivitySourceName = "WireMock.Net";
/// <summary>
/// Adds OpenTelemetry tracing to the WireMock server with instrumentation and OTLP exporter.
/// This configures:
/// - WireMock.Net ActivitySource instrumentation (custom WireMock traces with mapping details)
/// - ASP.NET Core instrumentation (standard HTTP server traces)
/// - OTLP exporter to send traces to a collector
/// </summary>
/// <param name="services">The service collection.</param>
/// <param name="options">The OpenTelemetry options containing exporter configuration.</param>
/// <returns>The service collection for chaining.</returns>
public static IServiceCollection AddWireMockOpenTelemetry(
this IServiceCollection services,
OpenTelemetryOptions? options)
{
if (options is null)
{
return services;
}
services.AddOpenTelemetry()
.ConfigureResource(resource =>
{
resource.AddService(
serviceName: ServiceName,
serviceVersion: typeof(WireMockOpenTelemetryExtensions).Assembly.GetName().Version?.ToString() ?? "unknown"
);
})
.WithTracing(tracing =>
{
// Add WireMock-specific traces
tracing.AddSource(WireMockActivitySourceName);
// Add ASP.NET Core instrumentation for standard HTTP server traces
tracing.AddAspNetCoreInstrumentation(aspNetOptions =>
{
// Filter out admin requests if configured
if (options.ExcludeAdminRequests)
{
aspNetOptions.Filter = context =>
{
var path = context.Request.Path.Value ?? string.Empty;
return !path.StartsWith("/__admin", StringComparison.OrdinalIgnoreCase);
};
}
});
// Add OTLP exporter - automatically reads OTEL_EXPORTER_OTLP_ENDPOINT from environment
// If explicit endpoint is specified in options, use that instead
var otlpEndpoint = options.OtlpExporterEndpoint;
if (!string.IsNullOrEmpty(otlpEndpoint))
{
tracing.AddOtlpExporter(exporterOptions =>
{
exporterOptions.Endpoint = new Uri(otlpEndpoint);
});
}
else
{
// Use default - reads from OTEL_EXPORTER_OTLP_ENDPOINT env var
tracing.AddOtlpExporter();
}
});
return services;
}
/// <summary>
/// Configures OpenTelemetry tracing builder with WireMock.Net ActivitySource and ASP.NET Core instrumentation.
/// Use this method when you want more control over the TracerProvider configuration.
/// </summary>
/// <param name="tracing">The TracerProviderBuilder to configure.</param>
/// <param name="options">The OpenTelemetry options (optional).</param>
/// <returns>The TracerProviderBuilder for chaining.</returns>
public static TracerProviderBuilder AddWireMockInstrumentation(
this TracerProviderBuilder tracing,
OpenTelemetryOptions? options = null)
{
// Add WireMock-specific traces
tracing.AddSource(WireMockActivitySourceName);
// Add ASP.NET Core instrumentation for standard HTTP server traces
tracing.AddAspNetCoreInstrumentation(aspNetOptions =>
{
// Filter out admin requests if configured
if (options?.ExcludeAdminRequests == true)
{
aspNetOptions.Filter = context =>
{
var path = context.Request.Path.Value ?? string.Empty;
return !path.StartsWith("/__admin", StringComparison.OrdinalIgnoreCase);
};
}
});
return tracing;
}
}