-
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.
Setup order: This page covers the report configuration for Internal Flow Tracking. For the OpenTelemetry exporter setup that captures the spans, see Integration OpenTelemetry Extension first. Complete that setup, then return here to configure how internal flow data is displayed in your reports.
-
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
});
⚠️ If your project already has OpenTelemetry configured (e.g. via a shared telemetry library), register this as a separateAddOpenTelemetry().WithTracing(...)call rather than adding to the existing builder. See Integration OpenTelemetry Extension#Projects with Existing OpenTelemetry Configuration for details.
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)
// If you already have OTel configured, register this as a SEPARATE AddOpenTelemetry() call.
// See "Projects with Existing OpenTelemetry Configuration" in the OpenTelemetry Extension page.
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