// Copyright © WireMock.Net // OpenTelemetry Tracing Demo for WireMock.Net // This demo uses the Console Exporter to visualize traces in the terminal. using OpenTelemetry; using OpenTelemetry.Trace; using WireMock.OpenTelemetry; using WireMock.Server; using WireMock.Settings; using WireMock.RequestBuilders; using WireMock.ResponseBuilders; Console.WriteLine("=== WireMock.Net OpenTelemetry Tracing Demo ===\n"); // WireMock.Net creates Activity objects using System.Diagnostics.Activity (built into .NET). // These activities are automatically created when ActivityTracingEnabled is set to true. // // To export these traces, you have two options: // // Option 1: Configure your own TracerProvider (shown below) // - Full control over exporters (Console, OTLP, Jaeger, etc.) // - Add additional instrumentation (HttpClient, database, etc.) // - Recommended for most applications // // Option 2: Use WireMock.Net.OpenTelemetry package // - Reference the WireMock.Net.OpenTelemetry NuGet package // - Use services.AddWireMockOpenTelemetry(openTelemetryOptions) // - Adds WireMock + ASP.NET Core instrumentation and OTLP exporter // - Good for quick setup with all-in-one configuration // Option 1: Custom TracerProvider with Console exporter for this demo using var tracerProvider = Sdk.CreateTracerProviderBuilder() .AddWireMockInstrumentation(new OpenTelemetryOptions() { ExcludeAdminRequests = true }) .AddHttpClientInstrumentation() // HTTP client traces (for our test requests) .AddConsoleExporter() // Export traces to console for demo purposes .AddOtlpExporter() // Export to real OTLP collector (e.g. Jaeger, Tempo, etc.) .Build(); Console.WriteLine("Console Exporter configured to visualize:"); Console.WriteLine(" - WireMock.Net traces (wiremock.* tags)"); Console.WriteLine(" - ASP.NET Core server traces"); Console.WriteLine(" - HTTP client traces\n"); // Start WireMock server with OpenTelemetry enabled (ActivityTracingOptions != null enables tracing) var server = WireMockServer.Start(new WireMockServerSettings { StartAdminInterface = true, ActivityTracingOptions = new ActivityTracingOptions { ExcludeAdminRequests = true } }); Console.WriteLine($"WireMock server started at: {string.Join(", ", server.Urls)}\n"); // Configure some mock mappings server .Given(Request.Create() .WithPath("/api/hello") .UsingGet()) .RespondWith(Response.Create() .WithStatusCode(200) .WithBody("Hello from WireMock!")); server .Given(Request.Create() .WithPath("/api/user/*") .UsingGet()) .RespondWith(Response.Create() .WithStatusCode(200) .WithHeader("Content-Type", "application/json") .WithBody(@"{""name"": ""John Doe"", ""email"": ""john@example.com""}")); server .Given(Request.Create() .WithPath("/api/error") .UsingGet()) .RespondWith(Response.Create() .WithStatusCode(500) .WithBody("Internal Server Error")); Console.WriteLine("Mock mappings configured:"); Console.WriteLine(" GET /api/hello -> 200 OK"); Console.WriteLine(" GET /api/user/* -> 200 OK (JSON)"); Console.WriteLine(" GET /api/error -> 500 Error"); Console.WriteLine(); // Make some test requests to generate traces using var httpClient = server.CreateClient(); Console.WriteLine("Making test requests to generate traces...\n"); Console.WriteLine("─────────────────────────────────────────────────────────────────"); // Request 1: Successful request Console.WriteLine("\n>>> Request 1: GET /api/hello"); var response1 = await httpClient.GetAsync("/api/hello"); Console.WriteLine($"<<< Response: {(int)response1.StatusCode} {response1.StatusCode}"); Console.WriteLine($" Body: {await response1.Content.ReadAsStringAsync()}"); await Task.Delay(500); // Small delay to let trace export complete // Request 2: Another successful request with path parameter Console.WriteLine("\n>>> Request 2: GET /api/user/123"); var response2 = await httpClient.GetAsync("/api/user/123"); Console.WriteLine($"<<< Response: {(int)response2.StatusCode} {response2.StatusCode}"); Console.WriteLine($" Body: {await response2.Content.ReadAsStringAsync()}"); await Task.Delay(500); // Request 3: Error response Console.WriteLine("\n>>> Request 3: GET /api/error"); var response3 = await httpClient.GetAsync("/api/error"); Console.WriteLine($"<<< Response: {(int)response3.StatusCode} {response3.StatusCode}"); Console.WriteLine($" Body: {await response3.Content.ReadAsStringAsync()}"); await Task.Delay(500); // Request 4: No matching mapping (404) Console.WriteLine("\n>>> Request 4: GET /api/notfound"); var response4 = await httpClient.GetAsync("/api/notfound"); Console.WriteLine($"<<< Response: {(int)response4.StatusCode} {response4.StatusCode}"); await Task.Delay(500); // Request 5: Admin API request (should be excluded from tracing) Console.WriteLine("\n>>> Request 5: GET /__admin/health"); var response5 = await httpClient.GetAsync("/__admin/health"); Console.WriteLine($"<<< Admin Health Status: {response5.StatusCode}"); Console.WriteLine("\n─────────────────────────────────────────────────────────────────"); Console.WriteLine("\nTraces above show OpenTelemetry activities from WireMock.Net!"); Console.WriteLine("Look for 'Activity.TraceId', 'Activity.SpanId', and custom tags like:"); Console.WriteLine(" - http.request.method"); Console.WriteLine(" - url.path"); Console.WriteLine(" - http.response.status_code"); Console.WriteLine(" - wiremock.mapping.matched"); Console.WriteLine(" - wiremock.mapping.guid"); Console.WriteLine(); // Cleanup server.Stop(); Console.WriteLine("WireMock server stopped. Demo complete!");