Skip to content

Integration MongoDB Extension

aryehcitron@gmail.com edited this page May 24, 2026 · 15 revisions

The Kronikol.Extensions.MongoDB package adds MongoDB operation tracking to your test diagrams using the driver's built-in command monitoring events. Instead of opaque internal database calls, your sequence diagrams show classified operations like Find → users with a clean mongodb:///mydb/users URI.

Using a shared library or abstraction layer? If your code doesn't use the MongoDB driver directly — e.g. it goes through a shared repository library, wrapper, or custom abstraction — this extension won't be able to hook into the driver's command monitoring. See Tracking Custom Dependencies for alternative approaches including RequestResponseLogger.LogPair(), TrackingProxy<T>, and MessageTracker.


How It Works

The MongoDB .NET driver provides a first-class event subscription API via MongoClientSettings.ClusterConfigurator. MongoDbTrackingSubscriber subscribes to three events:

  • CommandStartedEvent — captures the command name, BsonDocument, and database namespace
  • CommandSucceededEvent — captures the reply and duration
  • CommandFailedEvent — captures the exception

The subscriber correlates start→success/failure pairs using RequestId via a ConcurrentDictionary, then logs both a request and response entry to RequestResponseLogger. Because it logs to the same logger as the standard TestTrackingMessageHandler, MongoDB operations appear alongside your HTTP API calls in the same sequence diagram.


Install

dotnet add package Kronikol.Extensions.MongoDB

Verbosity Levels

Level Label shown URI shown Request content Response content
Raw Find mydb.users filter={...} mongodb:///mydb/users Full BSON command Full BSON reply
Detailed Find → users mongodb:///mydb/users Filter text only Metadata + document preview
Summarised Find mongodb:///mydb None Metadata + document preview

The default is Detailed.


Classified Operations

Category Operations
CRUD Find, Insert, Update, Delete
Aggregation Aggregate, Count, Distinct
Atomic FindAndModify
Batch BulkWrite
DDL CreateIndex, DropIndex, CreateCollection, DropCollection, RenameCollection
Metadata ListCollections, ListDatabases, ListIndexes
Change Streams Watch (detected via $changeStream in aggregate pipeline)
Transactions CommitTransaction, AbortTransaction
Admin DropDatabase, ServerStatus, DbStats, CollStats
Legacy MapReduce
Cursor GetMore (disabled by default)
Fallback Other (unrecognised commands)

Directional Arrows

In Detailed verbosity, labels include directional arrows indicating the data flow:

Direction Arrow Examples
Read Find ← users, Aggregate ← orders, Count ← items, Distinct ← items, Watch ← orders, GetMore ← users, ListIndexes ← users
Write Insert (×5) → users, Update → orders, Delete → orders, BulkWrite → users, DropCollection → temp
Read-modify-write FindAndModify ↔ users
Schema / Admin (none) CreateIndex, ServerStatus, CommitTransaction

Pipeline Stage Annotations

For Aggregate and Watch operations, the label includes the pipeline stage names when available. For example:

  • Aggregate ($match, $group, $sort) ← orders
  • Watch ($changeStream) ← orders

GridFS Detection

Collections ending in .files or .chunks are automatically annotated with (GridFS):

  • Find (GridFS) ← uploads.files

Document Count Annotation

Insert operations with multiple documents include a count:

  • Insert (×5) → users

Collection Name Extraction

The collection name is extracted from the first element of the BsonDocument command. For example:

  • { "find": "users", "filter": {...} } → collection = users
  • { "insert": "orders", "documents": [...] } → collection = orders
  • { "aggregate": 1, "pipeline": [...] } → database-level aggregate, collection = null

Setup

Option A: With MongoClientSettings Extension (Recommended)

var trackingOptions = new MongoDbTrackingOptions
{
    ServiceName = "MongoDB",
    CallerName = "My API",
    Verbosity = MongoDbTrackingVerbosity.Detailed,
    CurrentTestInfoFetcher = CurrentTestInfo.Fetcher
};

var settings = MongoClientSettings.FromConnectionString("mongodb://localhost:27017");
settings.WithTestTracking(trackingOptions);

var client = new MongoClient(settings);

WithTestTracking chains a tracking subscriber into ClusterConfigurator without replacing any existing configurator. This requires no production code changes.

Option B: Manual Subscriber Setup

If you need more control:

var trackingOptions = new MongoDbTrackingOptions
{
    ServiceName = "MongoDB",
    CallerName = "My API",
    Verbosity = MongoDbTrackingVerbosity.Detailed,
    CurrentTestInfoFetcher = CurrentTestInfo.Fetcher
};

var subscriber = new MongoDbTrackingSubscriber(trackingOptions);

var settings = MongoClientSettings.FromConnectionString("mongodb://localhost:27017");
settings.ClusterConfigurator = builder => subscriber.Subscribe(builder);

var client = new MongoClient(settings);

Option C: In DI-based Tests (WebApplicationFactory)

builder.ConfigureTestServices(services =>
{
    services.AddSingleton<IMongoClient>(sp =>
    {
        var trackingOptions = new MongoDbTrackingOptions
        {
            ServiceName = "MongoDB",
            CallerName = "My API",
            Verbosity = MongoDbTrackingVerbosity.Detailed,
            CurrentTestInfoFetcher = CurrentTestInfo.Fetcher
        };

        var settings = MongoClientSettings.FromConnectionString("mongodb://localhost:27017");
        settings.WithTestTracking(trackingOptions);

        return new MongoClient(settings);
    });
});

Option D: DI Extension Method (v2.26.0+)

The simplest approach — registers a MongoDbTrackingSubscriber singleton with IHttpContextAccessor auto-resolved from DI:

builder.ConfigureTestServices(services =>
{
    services.AddMongoDbTestTracking(options =>
    {
        options.ServiceName = "MongoDB";
        options.Verbosity = MongoDbTrackingVerbosity.Detailed;
    });
});

Configuration Reference

MongoDbTrackingOptions

Property Type Default Description
ServiceName string "MongoDB" The participant name shown in the diagram for the MongoDB service
CallerName string "Caller" The participant name shown for the service making MongoDB calls
Verbosity MongoDbTrackingVerbosity Detailed Controls how much detail appears in the diagram (Raw, Detailed, Summarised)
CurrentTestInfoFetcher Func<(string Name, string Id)>? null Returns the current test's name and ID. Required — if null, commands are monitored but not logged
CurrentStepTypeFetcher Func<string?>? null Optional — returns the current BDD step type (Given/When/Then)
ExcludedOperations HashSet<MongoDbOperation> [] Operations to suppress from tracking entirely (e.g. suppress ListDatabases or ServerStatus noise)
LogFilterText bool true When true, includes the filter document text in Detailed mode request content
AutoCorrelateWrites bool true When true, tracked write operations (Insert, Update, FindAndModify) auto-populate TestCorrelationStore for parallel-safe background thread correlation (e.g. Change Stream attribution). See Change Stream Correlation
LogResponseContent bool true Include response content (documents from cursor.firstBatch) in diagram response arrows at all verbosity levels (v2.37.3+). At Raw, the full reply is always shown regardless. Set to false to restore previous empty-arrow behaviour
MaxResponseDocuments int 10 Maximum number of documents to include from cursor.firstBatch in response content (v2.37.0+)

v2.23.0+ Dual-Resolution: MongoDbTrackingSubscriber accepts an optional IHttpContextAccessor? httpContextAccessor constructor parameter for resolving test identity from HTTP request headers when running inside the SUT's request pipeline. See HTTP Tracking Setup#Dual-Resolution Test Identity (v2.23.0+) for details.

| IgnoredCommands | HashSet<string> | See below | Commands to ignore entirely (not logged even when test info is available) | | TrackGetMore | bool | false | Whether to track getMore cursor continuation commands | | SetupVerbosity | MongoDbTrackingVerbosity? | null | Verbosity override for the Setup phase. See Phase-Aware Tracking | | ActionVerbosity | MongoDbTrackingVerbosity? | null | Verbosity override for the Action phase. See Phase-Aware Tracking | | TrackDuringSetup | bool | true | When false, tracking is suppressed during Setup. See Phase-Aware Tracking | | TrackDuringAction | bool | true | When false, tracking is suppressed during Action. See Phase-Aware Tracking |

Default Ignored Commands

These MongoDB internal/handshake commands are ignored by default:

  • isMaster, hello — server handshake
  • saslStart, saslContinue — authentication
  • ping — health check
  • buildInfo — server metadata
  • getLastError — legacy error check
  • killCursors — cursor cleanup
  • endSessions — session cleanup

Override IgnoredCommands to customise:

new MongoDbTrackingOptions
{
    IgnoredCommands = ["isMaster", "hello"] // Only ignore these two
}

ITrackingComponent

MongoDbTrackingSubscriber implements ITrackingComponent and auto-registers with TrackingComponentRegistry. The invocation count increments for every command (including ignored ones), so you can verify MongoDB was actually contacted:

var subscriber = new MongoDbTrackingSubscriber(options);

// ... run test ...

Assert.True(subscriber.WasInvoked);
Assert.Equal(3, subscriber.InvocationCount);

Or use TrackingComponentRegistry.GetUnusedComponents() to find services that were wired up but never called.


Response Payload Capture (v2.37.0+)

Response arrows in diagrams show document data from cursor.firstBatch instead of being empty. At Detailed and Summarised verbosity, response content includes metadata and document previews. At Raw, the full BSON reply is always shown.

Response content is shown at all verbosity levels when LogResponseContent = true (the default). Set LogResponseContent = false to restore previous empty-arrow behaviour.

Tuning Response Output

new MongoDbTrackingOptions
{
    Verbosity = MongoDbTrackingVerbosity.Summarised,
    LogResponseContent = true,          // default — show response data
    MaxResponseDocuments = 10           // capture up to 10 documents (default: 10)
}

Note: MongoDB uses MaxResponseDocuments instead of MaxResponseRows since responses contain BSON documents rather than tabular rows.


Change Stream Correlation

If your application uses MongoDB Change Streams, background processing generates tracking entries on threads where test context is unavailable. ChangeStreamCorrelation attributes change items back to the originating test using TestCorrelationStore.

When AutoCorrelateWrites is true (the default), every tracked write (Insert, Update, FindAndModify) populates TestCorrelationStore with the document ID. When the Change Stream processes that document, ChangeStreamCorrelation looks up the test identity from the store.

ChangeStreamCorrelation.Wrap<T>()

Wraps a single-item Change Stream handler:

ChangeStreamCorrelation.Wrap<MyDocument>(
    async item =>
    {
        await ProcessChange(item);
    },
    serviceName: "MongoDB",
    idSelector: doc => doc.Id)  // optional — defaults to "id"/"Id" property

ChangeStreamCorrelation.WrapBatch<T>()

Wraps a batch handler:

ChangeStreamCorrelation.WrapBatch<MyDocument>(
    async items =>
    {
        foreach (var item in items)
            await ProcessChange(item);
    },
    serviceName: "MongoDB",
    idSelector: doc => doc.Id)

See Background Thread Correlation and Parallel-Safe Background Correlation for more details on the correlation system.


Event Correlation

The subscriber uses ConcurrentDictionary<int, PendingOperation> keyed by RequestId to correlate CommandStartedEventCommandSucceededEvent/CommandFailedEvent. This handles concurrent operations correctly — multiple in-flight commands on different connections don't interfere with each other.

If a CommandSucceededEvent or CommandFailedEvent arrives without a matching CommandStartedEvent (e.g., due to race conditions or late subscription), it is silently ignored.

Home


Demo


Getting Started

Common Tasks

Integration Guides

Extensions

Configuration

Features

Reference

Clone this wiki locally