-
Notifications
You must be signed in to change notification settings - Fork 1
Diagnostics and Debugging
TestTrackingDiagrams includes several diagnostic tools to help you understand what's being tracked, identify configuration issues, and debug missing or unexpected diagram content.
Enable DiagnosticMode on ReportConfigurationOptions to generate a comprehensive DiagnosticReport.html alongside your normal reports:
var options = new ReportConfigurationOptions
{
DiagnosticMode = true // generates DiagnosticReport.html
};The diagnostic report includes:
| Section | Contents |
|---|---|
| Configuration Dump | All ReportConfigurationOptions values, including InternalFlow settings |
| Log Counts by Service | Number of request/response logs per ServiceName
|
| Log Counts by Test | Number of logs per test, sorted descending — highlights tests with zero logs |
| Unpaired Requests | Request logs without matching responses (same TraceId + RequestResponseId) |
| Orphaned Test IDs | Test IDs in logs that don't match any Feature/Scenario
|
| Scenarios with No Logs | Scenarios that ran but produced zero logged interactions |
| Activity Source Discovery | All detected ActivitySource names from captured OTel spans, with span counts and tracked/well-known status |
Tip: Enable
DiagnosticModetemporarily during development to identify why diagrams are missing content — unpaired logs, orphaned IDs, or missing activity sources are the most common root causes.
ReportDiagnostics.Analyse() runs automatically at report generation time and produces warning strings that appear in the report footer. Common warnings include:
-
"No request/response logs recorded" — No interactions were tracked. Check that
TestTrackingMessageHandleris wired up. - "N test(s) have no request/response logs" — Some scenarios didn't produce any HTTP interactions.
- "InternalFlowSpanStore contains 0 spans" — No OTel spans were captured. Check that the activity listener is running.
When ActivitySourceDiscovery is enabled on ReportConfigurationOptions, the diagnostics additionally list all discovered activity sources with their span counts:
var options = new ReportConfigurationOptions
{
ActivitySourceDiscovery = true // includes source discovery in diagnostics
};ActivitySourceDiscovery.GetDiscoveredSources() returns a dictionary of all ActivitySource names that produced spans during the test run, with their span counts:
var sources = ActivitySourceDiscovery.GetDiscoveredSources();
// e.g. { "Microsoft.AspNetCore": 42, "System.Net.Http": 38, "MyApi.Services": 15 }This is useful for:
-
Identifying which sources are producing spans — Helps you decide which to include/exclude via
InternalFlowSpanGranularityandInternalFlowActivitySources. -
Verifying custom sources are being captured — If your custom
ActivitySourcedoesn't appear, check thatInternalFlowActivitySourcesincludes its name. - Understanding span volume — High span counts from a single source may indicate noisy instrumentation that could be filtered.
When creating manual spans (e.g. inside a TrackingProxy or custom tracking code), use InternalFlowSpanStore.Complete(activity) as a one-liner to stop and store the span:
var activity = new ActivitySource("MySource").StartActivity("MyOperation");
try
{
// ... do work ...
}
finally
{
InternalFlowSpanStore.Complete(activity);
}Complete() is null-safe — it does nothing if the activity is null. If the activity hasn't been stopped, it calls Stop() before adding it to the store.
When InternalFlowNoDataBehavior is set to ShowMessage (the default), segments with no captured spans show an enriched diagnostic message instead of a generic "No data" notice. The message includes:
- The current
InternalFlowSpanGranularitysetting - The configured
InternalFlowActivitySources(ifManualgranularity) - A count of total spans in the
InternalFlowSpanStore - Actionable suggestions (e.g. "Try switching to
Fullgranularity", "Check that your activity sources are listed")
This makes it much easier to diagnose why a particular popup has no internal flow content.
LogPair() is a convenience method that logs a matched request/response pair in a single call, automatically generating TraceId and RequestResponseId values:
RequestResponseLogger.LogPair(
testName: "My test",
testId: "test-123",
method: "Cache Get", // OneOf<HttpMethod, string>
uri: new Uri("redis://cache/my-key"),
serviceName: "Redis Cache",
callerName: "My Service",
requestContent: "GET my-key",
responseContent: "{\"value\": 42}",
statusCode: HttpStatusCode.OK
);This is equivalent to calling RequestResponseLogger.Log() twice (once for Request, once for Response) with matching identifiers and timestamps. It's the recommended approach for custom dependency tracking when you already have both the request and response data available.
See Tracking Custom Dependencies for the full manual approach when you need more control (e.g. different timestamps for request vs response, custom headers, or TrackingIgnore support).
Flame charts in internal flow popups and whole-test flow sections now support interactive zoom:
| Action | Effect |
|---|---|
| Click a bar | Zooms into that span's time range (with 5% padding) |
| Double-click anywhere | Resets to the full view |
When zoomed, a hint banner appears: "🔍 Zoomed — double-click to reset"
Tooltips on each bar now include:
- Activity source name (e.g.
[Microsoft.AspNetCore]) - Span display name
- Duration in milliseconds
- Percentage of total duration
All tracking components (TestTrackingMessageHandler, SqlTrackingInterceptor, CosmosTrackingMessageHandler, BlobTrackingMessageHandler, BigQueryTrackingMessageHandler, RedisTracker) auto-register with TrackingComponentRegistry when constructed. This enables automated detection of misconfigured components that were wired up but never processed any traffic.
Call ValidateAllComponentsWereInvoked() in your test teardown to catch misconfiguration early:
// In test base class Dispose, AssemblyCleanup, or [AfterAll]:
TrackingComponentRegistry.ValidateAllComponentsWereInvoked();If any registered component was never invoked, you'll get a detailed InvalidOperationException:
The following tracking components were registered but never invoked:
• SqlTrackingInterceptor (Identity Database)
This usually means the component was added to the wrong pipeline, options, or service.
Common causes:
- EF Core: The interceptor was added to DbContextOptions<TDerived> but the
DbContext constructor accepts DbContextOptions<TBase> (e.g. Duende IdentityServer's
ConfigurationDbContext). Fix: add the interceptor to the base class's options.
- HTTP: The handler was added to an HttpClient that isn't being used by the target service.
- Redis: An untracked IDatabase instance is being used instead of the tracked one.
// All registered components
var all = TrackingComponentRegistry.GetRegisteredComponents();
// Only unused components
var unused = TrackingComponentRegistry.GetUnusedComponents();
// Individual component properties (via ITrackingComponent interface)
foreach (var c in all)
{
Console.WriteLine($"{c.ComponentName}: invoked={c.WasInvoked}, count={c.InvocationCount}");
}Call Clear() alongside RequestResponseLogger.Clear():
RequestResponseLogger.Clear();
TrackingComponentRegistry.Clear();All tracking components implement this interface:
public interface ITrackingComponent
{
string ComponentName { get; } // e.g. "SqlTrackingInterceptor (Identity Database)"
bool WasInvoked { get; } // true after first request/command
int InvocationCount { get; } // total requests/commands processed
}Getting Started
Common Tasks
Integration Guides
- Integration xUnit3
- Integration xUnit2
- Integration NUnit
- Integration MSTest
- Integration TUnit
- Integration BDDfy xUnit3
- Integration LightBDD xUnit2
- Integration LightBDD xUnit3
- Integration LightBDD TUnit
- Integration ReqNRoll xUnit2
- Integration ReqNRoll xUnit3
- Integration ReqNRoll TUnit
Extensions
- Integration AtlasDataApi Extension
- Integration BigQuery Extension
- Integration Bigtable Extension
- Integration BlobStorage Extension
- Integration ClickHouse Extension
- Integration CloudStorage Extension
- Integration CosmosDB Extension
- Integration Dapper Extension
- Integration DynamoDB Extension
- Integration EF Core Relational Extension
- Integration Elasticsearch Extension
- Integration EventBridge Extension
- Integration EventHubs Extension
- Integration Grpc Extension
- Integration Kafka Extension
- Integration MassTransit Extension
- Integration MongoDB Extension
- Integration MySqlConnector Extension
- Integration Npgsql Extension
- Integration Oracle Extension
- Integration PubSub Extension
- Integration Redis Extension
- Integration S3 Extension
- Integration ServiceBus Extension
- Integration SNS Extension
- Integration Spanner Extension
- Integration SqlClient Extension
- Integration Sqlite Extension
- Integration SQS Extension
- Integration StorageQueues Extension
- Integration OpenTelemetry Extension
- Integration DispatchProxy Extension
- Integration MediatR Extension
- Integration PlantUML IKVM
Configuration
- Tracking Dependencies
- Tracking Custom Dependencies
- HTTP Tracking Setup
- Report Configuration
- Diagram Customisation
- Phase-Aware Tracking
- Content Formatting
- PlantUML Server Configuration
Features
- Generated Reports
- Search Syntax
- Component Diagrams
- PlantUML Browser Rendering
- Inline SVG Rendering
- Internal Flow Tracking
- Tags and Attributes
- Excluding Requests
- Excluded Headers
- Multi-Host Test Architectures
- Event-Driven Architecture Testing
- Service Bus Tracking Patterns
- Background Thread Correlation
- Parallel-Safe Background Correlation
- Event & Message Tracking
- Assertion Tracking
- Step Tracking
- Tabular Attributes
- Large Response and Diagram Handling
- Diagnostics and Debugging
- CI Summary Integration
- CI Artifact Upload
- Merging Parallel Reports
Reference