Repository navigation
Integration Npgsql Extension
The Kronikol.Extensions.Npgsql package adds PostgreSQL operation tracking to your test diagrams via Npgsql's built-in DiagnosticSource instrumentation. No code changes required in production — just install and configure in your test project.
Zero production changes. Npgsql emits diagnostic events automatically. This extension subscribes to them globally, so every
NpgsqlConnectionin the process is tracked without any wrapping or decoration.
Npgsql publishes DiagnosticSource events under the listener name "Npgsql". The NpgsqlDiagnosticTracker subscribes to these events and correlates BeforeExecuteCommand / AfterExecuteCommand pairs using ExecutionId (a GUID extracted via reflection). Each pair is classified by UnifiedSqlClassifier and logged to RequestResponseLogger.
Because it logs to the same RequestResponseLogger as the standard TestTrackingMessageHandler, SQL operations appear alongside your HTTP API calls in the same sequence diagram.
dotnet add package Kronikol.Extensions.NpgsqlThe package asks for Npgsql 10.0.0 or later, so a suite can pin whichever 10.x from 10.0.0 its application ships with.
The package's own suite runs on the newest 10.x, and in CI on 10.0.0 as well. A project that takes the client only
through this package resolves 10.0.0; reference the client yourself for a newer one. The floor is 10.0.0, the first of
the major, where the suite passes. Before 5.27.12 the package asked for 10.0.2.
// In your test WebApplicationFactory ConfigureTestServices:
services.AddPostgreSqlTestTracking(options =>
{
options.Verbosity = SqlTrackingVerbosityLevel.Detailed;
// options.LogSqlText = true;
// options.LogParameters = true;
});// In your test setup (e.g. constructor or OneTimeSetUp):
NpgsqlTestTracking.EnsureTracking(new NpgsqlTrackingOptions
{
Verbosity = SqlTrackingVerbosityLevel.Detailed
});
// In teardown:
NpgsqlTestTracking.Reset();| Property | Default | Description |
|---|---|---|
ServiceName |
"PostgreSQL" |
The participant name shown in diagrams |
CallerName |
"Caller" |
The caller participant name |
Verbosity |
Detailed |
Raw, Detailed, or Summarised
|
LogSqlText |
true |
Include full SQL text in Detailed mode |
LogParameters |
false |
Include parameter values |
DependencyCategory |
"PostgreSQL" |
Controls participant shape/colour |
UriScheme |
"postgresql" |
URI scheme in diagram URIs |
CurrentTestInfoFetcher |
null |
Returns the current test's name and ID. Required for wrapping approach |
HttpContextAccessor |
null |
Optional — enables dual-resolution of test identity from HTTP headers |
ExcludedOperations |
[] |
Operations to exclude from tracking |
SetupVerbosity |
null |
Verbosity override for the Setup phase. See Phase-Aware Tracking |
ActionVerbosity |
null |
Verbosity override for the Action phase. See Phase-Aware Tracking |
TrackDuringSetup |
true |
Track during test setup phase |
TrackDuringAction |
true |
Track during test action phase |
LogResponseContent |
true |
Include response data in diagram arrows at all verbosity levels (v2.37.0+) |
MaxResponseRows |
10 |
Maximum rows to capture in response content |
MaxValueDisplayLength |
500 |
Truncate individual cell values beyond this length |
ResponseDetail |
(follows verbosity) |
RowCountOnly, RowCountAndColumns, or FullRows; unset = FullRows at Raw/Detailed, RowCountAndColumns at Summarised |
All options inherit from SqlTrackingOptionsBase in the core package.
| Level | Arrow label | URI |
|---|---|---|
| Raw | Full SQL text | postgresql://host/database |
| Detailed | SELECT FROM Users |
postgresql://host/database/Users |
| Summarised | SELECT |
postgresql:///database/Users |
Comments and string literals are ignored when picking the table (3.0.83+). The table name is extracted by regular expression, and the
FROM/INTOextractors match anywhere in the statement, so a comment or a literal that mentions those words used to win: a query carrying-- rolled up from the weekly aggregatewas reported as reading a table calledthe. A statement that opened with a comment was worse: it classified asOtherwith no table at all, and at Summarised verbosity such a call was dropped from the report.--comments,/* */comments and'…'literals are now removed before classification. Quoted identifiers (double-quoted, bracketed and backticked) are left alone, and the SQL the report displays is unchanged — this affects classification only.
Uses UnifiedSqlClassifier — supports SELECT, INSERT, UPDATE, DELETE, MERGE, UPSERT (ON CONFLICT DO UPDATE), stored procedures (EXEC/CALL), DDL (CREATE/ALTER/DROP TABLE), TRUNCATE, and transactions. Multi-dialect: handles PostgreSQL double-quotes, brackets, backticks, CTEs, SET prefix stripping, and Spanner hints.
Response arrows in diagrams now show actual data instead of being empty. The ResponseDetail option controls the level of detail:
ResponseDetail |
Example output |
|---|---|
RowCountOnly |
3 rows |
RowCountAndColumns (default at Summarised verbosity)
|
3 rows [Name, Preference, CreatedAt] |
FullRows (default at Raw/Detailed verbosity)
|
JSON row preview (up to MaxResponseRows) |
With LogResponseContent = false a query's or a scalar's response arrow has no note, and a command that changed rows still says how many, except at Summarised verbosity.
A statement that fails is drawn with its error (since 4.4.1): a response arrow with status Error, with the exception's message as its note, and the exception reaches your code unchanged. A COMMIT or ROLLBACK that fails is drawn the same way. Before 4.4.1 a failed statement left a request with no response, and a failed commit or rollback drew nothing.
The reader your code gets behaves as the provider's own (since 5.11.1): every member goes to the provider's reader, so GetFieldValue<T> returns the provider's conversion (a DateTimeOffset or a List<int> on Npgsql, a DateOnly on SQL Server), and a reader opened with CommandBehavior.SequentialAccess, as Dapper opens every query, is recorded as your code reads it, never ahead of it. Before 5.11.1 every Dapper query failed on SqlClient and Npgsql for that reason. A command with several result sets has one note per set, each on its own line, and a cell holding a provider's own type (a geography, a range) shows its text. Nothing the wrapper does while it records a command can fail the command: a failure is caught, and the run's diagnostics name the command it could not record. A data source that is not a host ((localdb)\MSSQLLocalDB, host,1433, a named instance, a pipe) is drawn against a host made from it (localdb-mssqllocaldb, host:1433), where before it failed every command with a UriFormatException.
In addition to the zero-change DiagnosticSource approach above, the Npgsql extension also provides a connection-wrapping approach. This is useful when DiagnosticSource instrumentation is unavailable, disabled, or when you need response payload capture from ExecuteReader/ExecuteScalar.
| Class | Wraps | Purpose |
|---|---|---|
TrackingNpgsqlConnection |
NpgsqlConnection |
Intercepts command creation and transaction begin |
TrackingNpgsqlCommand |
NpgsqlCommand |
Intercepts ExecuteReader, ExecuteNonQuery, ExecuteScalar (sync + async) |
TrackingNpgsqlTransaction |
NpgsqlTransaction |
Logs BEGIN, COMMIT, ROLLBACK
|
using Npgsql;
using Kronikol.Extensions.Npgsql;
var connection = new NpgsqlConnection(connectionString)
.WithTestTracking(new NpgsqlTrackingOptions
{
ServiceName = "PostgreSQL",
Verbosity = SqlTrackingVerbosityLevel.Detailed,
CurrentTestInfoFetcher = CurrentTestInfo.Fetcher
});NpgsqlConnection.WithTestTracking() returns a TrackingNpgsqlConnection (which extends DbConnection), so it works transparently with any code that accepts DbConnection — including Dapper, raw ADO.NET, and DI registrations.
builder.ConfigureTestServices(services =>
{
services.AddScoped<DbConnection>(sp =>
{
var inner = new NpgsqlConnection(connectionString);
return inner.WithTestTracking(new NpgsqlTrackingOptions
{
ServiceName = "PostgreSQL",
Verbosity = SqlTrackingVerbosityLevel.Detailed,
CurrentTestInfoFetcher = CurrentTestInfo.Fetcher
});
});
});DiagnosticSource vs Wrapping: The DiagnosticSource approach (Option A/B above) requires zero production code changes but cannot capture response payloads. The wrapping approach captures response data from
ExecuteReaderandExecuteScalar, but requires the connection to be wrapped. Choose based on your needs — you can use both in the same project for different connections.
A statement, a commit or a rollback that fails is answered Error, with the outer message as its note and, from 5.34.3, the message chain in error (#232). A reader that fails partway is answered Error with the reason, where it was answered OK at Close with the rows read so far. Every answer is filed under the test and phase its call started in, where the answer read them again when it came. History's older rules still read the call as the release before recorded it, so a suite that upgrades reads no change there (Cross-Run History).
Home · 🔍 Search this wiki Full-text search across every page. The “Pages” list above matches page and heading names, not page content.
Getting Started
- Quick Start (xUnit)
- Project Templates
- AI Integration Prompt
- Framework Integration Guides
- Migrating to v5
- Migrating to v4
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
- Integration Playwright
Uninstrumentable / polyglot backends
- Integration ProxyTap Extension
- Integration TcpTap Extension
- Integration Otlp Extension
- Exporting to OpenTelemetry
- Ingesting External Captures
- Ingesting from Jest
- Integration Cucumber Messages
- Capture-Time Redaction
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
- Report Themes
- Search and Filter 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
- Querying Reports
- Service Card
- Cross-Run History
- Diagnostics and Debugging
- CI Summary Integration
- CI Artifact Upload
- Merging Parallel Reports
Reference