-
Notifications
You must be signed in to change notification settings - Fork 1
Internal Flow Tracking
Internal Flow Tracking adds interactive internal flow visualisation to your sequence diagrams. When enabled, clicking an arrow in a PlantUML sequence diagram opens a popup showing the internal class/method activity that occurred inside the SUT between that HTTP boundary and the next — captured via OpenTelemetry spans.
This lets you see not just what your API called, but what happened inside the API while processing each request and response.
-
OpenTelemetry spans are captured during test execution using the
TestTrackingDiagrams.Extensions.OpenTelemetrypackage. A custom exporter stores allActivityspans in memory. -
HTTP boundaries are timestamped —
TestTrackingMessageHandlerandMessageTrackerrecordActivity.Current?.TraceId,Activity.Current?.SpanId, andDateTimeOffset.UtcNowon every request and response log entry. -
Segments are built at report generation time.
InternalFlowSegmentBuildercorrelates the captured OTel spans with the HTTP boundary timestamps, grouping spans into segments — one segment per arrow in the sequence diagram. Each segment contains the spans that started between two consecutive HTTP boundaries. -
Clickable links are injected into the PlantUML sequence diagram arrows using PlantUML's
[[link]]syntax. Each arrow becomes a clickable hyperlink with an#iflow-{id}anchor. -
A popup script intercepts clicks on these SVG links. When you click an arrow, it looks up the segment data from
window.__iflowSegmentsand displays the internal flow as either a PlantUML activity diagram (rendered in-browser) or an HTML call tree.
Note: Internal Flow Tracking requires
DiagramFormat = DiagramFormat.PlantUml. It is not supported with Mermaid output.
- Install the OpenTelemetry extension package:
dotnet add package TestTrackingDiagrams.Extensions.OpenTelemetry- Configure OpenTelemetry in your test setup to capture spans from your SUT's activity sources:
builder.ConfigureTestServices(services =>
{
services.AddOpenTelemetry()
.WithTracing(tracing => tracing
.AddSource("MyApi.Services") // Your SUT's ActivitySource names
.AddSource("Microsoft.AspNetCore") // ASP.NET Core auto-instrumentation
.AddSource("System.Net.Http") // HttpClient auto-instrumentation
.AddTestTrackingExporter()); // Captures spans for diagram popups
});See Integration OpenTelemetry Extension for full setup details.
Set InternalFlowTracking = true on your ReportConfigurationOptions:
new ReportConfigurationOptions
{
InternalFlowTracking = true,
// ... other options
}When InternalFlowTracking is enabled, the following are automatically forced:
-
InlineSvgRendering = true— SVG diagrams are embedded inline in the HTML (required for clickable arrows) -
PlantUmlImageFormat = PlantUmlImageFormat.Svg— when usingPlantUmlRendering.ServerorPlantUmlRendering.Local(required for SVG-based interaction)
Note:
PlantUmlRendering.BrowserJsalready renders inline SVG, so no override is needed for that mode.
The popup content can be rendered in two styles, controlled by InternalFlowDiagramStyle:
Renders a PlantUML activity diagram with swimlanes grouped by ActivitySource name. Each span appears as an action in its source's swimlane, with duration shown in milliseconds. The activity diagram is rendered client-side using the PlantUML TeaVM JS engine.
InternalFlowDiagramStyle = InternalFlowDiagramStyle.ActivityDiagramRenders an HTML nested list showing the span parent-child hierarchy as a call tree. Each node shows the source name, span display name, and duration. This is lightweight and doesn't require the PlantUML JS engine.
InternalFlowDiagramStyle = InternalFlowDiagramStyle.CallTreeReserved for future use.
Control which spans are included using InternalFlowSpanGranularity:
| Value | Behaviour | Best for |
|---|---|---|
AutoInstrumentation (default) |
Only includes spans from well-known auto-instrumentation sources (ASP.NET Core, HttpClient, EF Core, Redis, Cosmos, etc.) | Most projects — shows framework-level flow without noise |
Manual |
Only includes spans from sources listed in InternalFlowActivitySources
|
When you want to show only your own custom activity sources |
Full |
Includes all captured spans regardless of source | Debugging or when you need complete visibility |
The AutoInstrumentation filter recognises these ActivitySource names:
Microsoft.AspNetCoreSystem.Net.HttpMicrosoft.EntityFrameworkCoreNpgsqlStackExchange.RedisAzure.CosmosAzure.StorageMicrosoft.Azure.CosmosOpenTelemetry.Instrumentation.HttpOpenTelemetry.Instrumentation.AspNetCoreOpenTelemetry.Instrumentation.SqlClientOpenTelemetry.Instrumentation.EntityFrameworkCore
To show only specific activity sources, use Manual granularity with InternalFlowActivitySources:
new ReportConfigurationOptions
{
InternalFlowTracking = true,
InternalFlowSpanGranularity = InternalFlowSpanGranularity.Manual,
InternalFlowActivitySources = ["MyApi.Services", "MyApi.Repositories"]
}| Property | Type | Default | Description |
|---|---|---|---|
InternalFlowTracking |
bool |
false |
Master switch. When true, enables internal flow popups on PlantUML sequence diagram arrows. Forces InlineSvgRendering = true and PlantUmlImageFormat.Svg for Server/Local. |
InternalFlowDisplay |
InternalFlowDisplay |
Popup |
How the internal flow content is shown. Popup shows it in a modal overlay. Inline embeds it directly below the diagram. |
InternalFlowTrigger |
InternalFlowTrigger |
Click |
User interaction that opens the popup. Click requires clicking the arrow. Hover shows on mouse hover. |
InternalFlowDiagramStyle |
InternalFlowDiagramStyle |
ActivityDiagram |
Visual style for the internal flow content. ActivityDiagram renders a PlantUML activity diagram with swimlanes. CallTree renders an HTML nested list. |
InternalFlowSpanGranularity |
InternalFlowSpanGranularity |
AutoInstrumentation |
Controls which spans are included. AutoInstrumentation filters to well-known sources. Manual uses InternalFlowActivitySources. Full includes everything. |
InternalFlowActivitySources |
string[]? |
null |
Activity source names to include when InternalFlowSpanGranularity is Manual. Ignored for other granularity settings. |
InternalFlowNoDataBehavior |
InternalFlowNoDataBehavior |
ShowMessage |
What happens when an arrow has no captured spans. ShowMessage shows "No internal activity captured". HideLink removes the clickable link. VisualDistinction visually marks the arrow differently. |
InternalFlowShowFlameChart |
bool |
false |
When true, adds a flame chart visualisation alongside the main content. |
InternalFlowFlameChartPosition |
InternalFlowFlameChartPosition |
BehindWithToggle |
Where the flame chart appears. Underneath places it below the main content. BehindWithToggle shows a toggle button to switch between the main view and the flame chart. |
InternalFlowContentStrategy |
InternalFlowContentStrategy |
Embedded |
How segment data is stored. Embedded includes all data inline in the HTML. SeparateFragments writes each segment to a separate file in InternalFlowFragmentsFolderName. |
InternalFlowFragmentsFolderName |
string |
"spans" |
Folder name for separate fragment files when InternalFlowContentStrategy is SeparateFragments. Relative to the reports folder. |
InternalFlowPopupCustomStyleSheet |
string? |
null |
Custom CSS injected into the popup. When set, allows overriding or extending the default popup styles. |
When the OpenTelemetry extension is not installed, or spans are not captured for a particular segment, the InternalFlowNoDataBehavior setting controls how empty segments are handled:
| Value | Effect |
|---|---|
ShowMessage (default) |
The arrow is still clickable but the popup shows "No internal activity captured for this segment." |
HideLink |
The arrow is not clickable — no [[link]] is injected for segments without span data. |
VisualDistinction |
The arrow is clickable but visually styled differently (e.g. dashed or lighter colour) to indicate no data is available. |
By default, all segment data is embedded inline in the HTML report as a <script> block containing window.__iflowSegments. For large test suites with many spans, this can increase file size significantly.
Use InternalFlowContentStrategy.SeparateFragments to write each segment's data to a separate file:
new ReportConfigurationOptions
{
InternalFlowTracking = true,
InternalFlowContentStrategy = InternalFlowContentStrategy.SeparateFragments,
InternalFlowFragmentsFolderName = "spans" // default
}This produces files like Reports/spans/iflow-{guid}.html that are loaded on demand when the user clicks an arrow.
// In your test setup (e.g. WebApplicationFactory ConfigureTestServices)
builder.ConfigureTestServices(services =>
{
services.AddOpenTelemetry()
.WithTracing(tracing => tracing
.AddSource("MyApi.Services")
.AddSource("Microsoft.AspNetCore")
.AddSource("System.Net.Http")
.AddSource("Microsoft.EntityFrameworkCore")
.AddTestTrackingExporter());
});
// In your report generation
var options = new ReportConfigurationOptions
{
InternalFlowTracking = true,
InternalFlowDiagramStyle = InternalFlowDiagramStyle.ActivityDiagram,
InternalFlowSpanGranularity = InternalFlowSpanGranularity.AutoInstrumentation,
InternalFlowNoDataBehavior = InternalFlowNoDataBehavior.ShowMessage,
PlantUmlRendering = PlantUmlRendering.BrowserJs // Recommended for internal flow
};When you open the HTML report and click a sequence diagram arrow, a popup will show the internal flow activity that occurred inside your SUT during that segment of the request processing.
Test Execution Report Generation
┌──────────────────────────┐ ┌──────────────────────────────┐
│ OTel TracerProvider │ │ InternalFlowSpanCollector │
│ └─ AddTestTrackingExporter()──┐ │ └─ Loads spans via │
│ │ │ reflection from │
│ Activity spans │ │ TestTrackingSpanStore │
│ └─ Captured to ▼ │ │
│ TestTrackingSpanStore ◄──┘ │ InternalFlowSegmentBuilder │
│ │ └─ Correlates spans with │
│ TestTrackingMessageHandler ──────────────► │ HTTP boundary timestamps │
│ └─ Timestamps + TraceId │ │
│ on RequestResponseLog │ InternalFlowRenderer │
│ │ └─ ActivityDiagram or │
│ │ CallTree output │
│ │ │
│ │ InternalFlowHtmlGenerator │
│ │ └─ window.__iflowSegments │
│ │ JSON data block │
│ │ │
│ │ DiagramContextMenu │
│ │ └─ Popup JS/CSS for │
│ │ interactive arrows │
└──────────────────────────┘ └──────────────────────────────┘
-
PlantUML only — Internal Flow Tracking requires
DiagramFormat.PlantUml. Mermaid does not support clickable links with the same mechanism. -
Inline SVG required — The feature relies on injecting
[[link]]anchors into PlantUML arrows and intercepting them in the rendered SVG. This requires inline SVG rendering (automatically enabled). -
OpenTelemetry package optional — The core library uses reflection to load spans from
TestTrackingSpanStore. If theTestTrackingDiagrams.Extensions.OpenTelemetrypackage is not installed, internal flow arrows will show "No internal activity captured" (or behave according toInternalFlowNoDataBehavior). - Span correlation by timestamp — Spans are correlated with HTTP boundaries using timestamps, not parent-child span relationships. This means spans are grouped into the segment whose HTTP boundary immediately precedes them.
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