Tokuro.OpenTelemetry.Instrumentation.MongoDB
0.1.0
dotnet add package Tokuro.OpenTelemetry.Instrumentation.MongoDB --version 0.1.0
NuGet\Install-Package Tokuro.OpenTelemetry.Instrumentation.MongoDB -Version 0.1.0
<PackageReference Include="Tokuro.OpenTelemetry.Instrumentation.MongoDB" Version="0.1.0" />
<PackageVersion Include="Tokuro.OpenTelemetry.Instrumentation.MongoDB" Version="0.1.0" />
<PackageReference Include="Tokuro.OpenTelemetry.Instrumentation.MongoDB" />
paket add Tokuro.OpenTelemetry.Instrumentation.MongoDB --version 0.1.0
#r "nuget: Tokuro.OpenTelemetry.Instrumentation.MongoDB, 0.1.0"
#:package Tokuro.OpenTelemetry.Instrumentation.MongoDB@0.1.0
#addin nuget:?package=Tokuro.OpenTelemetry.Instrumentation.MongoDB&version=0.1.0
#tool nuget:?package=Tokuro.OpenTelemetry.Instrumentation.MongoDB&version=0.1.0
Tokuro.OpenTelemetry.Instrumentation.MongoDB
OpenTelemetry instrumentation for the official MongoDB.Driver (3.x). PII-safe by default, dual-writes legacy and stable OTel DB semantic conventions, and bounds its in-flight activity map so a leaky cursor cannot exhaust process memory.
Quick example
Two calls are required: one on the OpenTelemetry tracer provider, one on the MongoClientSettings that backs each MongoClient. The first tells OpenTelemetry to listen; the second tells MongoDB to emit. Both are required — registering only the tracer side produces zero spans.
1. Register the ActivitySource on your tracer provider so the OpenTelemetry SDK listens for the instrumentation's spans:
using OpenTelemetry.Trace;
builder.Services.AddOpenTelemetry()
.WithTracing(t => t
.AddMongoDBInstrumentation()
.AddOtlpExporter());
2. Wire the subscriber on each MongoClientSettings so the MongoDB driver actually publishes command events. This is where all instrumentation configuration lives:
var settings = MongoClientSettings.FromConnectionString(connectionString);
settings.AddOpenTelemetryInstrumentation(options =>
{
options.CaptureCommandText = true;
options.SuppressExceptionMessage = true;
options.MaxCommandTextLength = 4_000;
options.MaxInFlightCommands = 10_000;
options.EmitLegacyAttributes = true;
options.EmitStableAttributes = true;
options.FilterCommand = e => e.CommandName != "ping";
});
var client = new MongoClient(settings);
Every command issued by that MongoClient now emits a span with redacted BSON, db.system.name = "mongodb", db.namespace, server.address, and server.port. No connection strings, no document payloads, no exception bodies.
Heads-up. If your service constructs
MongoClientfrom DI, you need to plumb the instrumentedMongoClientSettingsthrough your DI registration. See the sample atsamples/Sample.AspNetCore/Program.cs.
Why this library
Production-tested gap-fill over MongoDB.Driver.Core.Extensions.DiagnosticSources v3.0.0:
- PII-safe redaction by default. The BSON tree is walked; every scalar becomes
"?". Collection names, operators, and structure are preserved. Raw capture is opt-in, not opt-out. exception.messagesuppressed on failed commands. MongoDB driver exceptions echo BSON fragments (E11000 duplicate-key errors carry the conflicting document, schema validation surfaces the rejected payload, bulk-write rejects include rows). Off by default.- Dual-write OTel DB semantic conventions. Emits both legacy (
db.system,db.statement,db.name) and stable (db.system.name,db.query.text,db.namespace) attributes during the OTel sem-conv migration window. - Bounded in-flight Activity map. Struct dictionary key, configurable cap with drop-new overflow. Upstream uses an unbounded
ConcurrentDictionary<int, Activity>— a leaky long-running cursor or a flood of unmatchedgetMores grows the heap forever.
Installation
dotnet add package Tokuro.OpenTelemetry.Instrumentation.MongoDB
Usage
Configuration via object initializer
If you prefer not to use the configure callback, the same options surface accepts an instance:
var settings = MongoClientSettings.FromConnectionString(connectionString);
settings.AddOpenTelemetryInstrumentation(new MongoDBInstrumentationOptions
{
SuppressExceptionMessage = true,
MaxCommandTextLength = 2_000,
FilterCommand = e => e.CommandName != "ping",
});
Backend interop
Spans are vendor-neutral OTel. Shipping to Datadog via the DD Agent or DDOT, the agent's DB service-splitting automatically surfaces these spans under service:<svc>-mongodb thanks to the db.system.name attribute. Tempo, Honeycomb, Jaeger, New Relic, and Grafana Cloud OTLP all consume the same payload without backend-specific configuration.
Configuration
All options live on MongoDBInstrumentationOptions, passed to MongoClientSettings.AddOpenTelemetryInstrumentation.
| Option | Default | Meaning |
|---|---|---|
CaptureCommandText |
true |
Emit db.statement / db.query.text with the redacted BSON. Values are always redacted regardless; this flag only controls whether the attribute is attached at all. |
MaxCommandTextLength |
4000 |
Truncate redacted command text beyond this many chars; suffix ...[truncated]. |
SuppressExceptionMessage |
true |
Omit the exception span event (which would carry exception.type + exception.message) on failed commands; the error.type span attribute is always kept. |
MaxInFlightCommands |
10000 |
Defensive upper bound on the in-flight Activity map; on overflow the new command's activity is dropped (stopped, not tracked) while existing in-flight entries are preserved. Each drop emits an EventSource counter. |
EmitLegacyAttributes |
true |
Emit pre-stable attrs (db.system, db.statement, db.name). |
EmitStableAttributes |
true |
Emit stable attrs (db.system.name, db.query.text, db.namespace, db.operation.name). |
FilterCommand |
null |
Optional predicate over CommandStartedEvent. Return false to suppress the span entirely. When null, only the built-in handshake/heartbeat list is filtered. |
Features comparison
| Capability | This library | jbogard/MongoDB.Driver.Core.Extensions.DiagnosticSources v3.0.0 |
|---|---|---|
| BSON redaction default | On (scalars → "?") |
Off — raw command captured |
| Opt-in raw capture | Yes (CaptureCommandText + explicit unredacted toggle) |
Always-on raw capture when enabled |
exception.message handling |
Suppressed by default | Recorded raw (leaks BSON fragments) |
| OTel legacy attributes | Yes | Yes |
OTel stable attributes (db.system.name …) |
Yes | No |
server.address / server.port |
Yes, low-64-bit-safe IP handling | Partial |
| Bounded in-flight map | Yes (MaxInFlightCommands) |
No — unbounded ConcurrentDictionary<int, Activity> |
| Struct dictionary key | Yes (no boxing) | No |
| TFMs | net8.0;net9.0;net10.0 |
net6.0;net8.0 |
How it works
The instrumentation subscribes to the MongoDB driver's command-monitoring events via a ClusterConfigurator. On CommandStartedEvent, an Activity is started (cheap when no listener is registered) and stashed in a bounded map keyed by request id. On CommandSucceededEvent / CommandFailedEvent, the activity is retrieved, tagged, and stopped.
flowchart LR
A[CommandStartedEvent] --> B[ActivitySource.StartActivity]
B --> C{IsAllDataRequested?}
C -- no --> D[Stash in bounded map]
C -- yes --> E[Walk BSON tree, scalars to '?']
E --> F[SetTag db.namespace, server.address, ...]
F --> D
D --> G{Succeeded or Failed?}
G -- Succeeded --> H[SetStatus Ok, Stop]
G -- Failed --> I[SetStatus Error, error.type, optional exception event, Stop]
The hot path is gated on Activity.IsAllDataRequested. Sampled-out commands incur only a dictionary insert + remove and one Activity allocation that the runtime can elide under tiered JIT.
Caveats & known limitations
- Aggregation pipelines are redacted structurally only. Stage operators (
$match,$group, …) are kept; user-supplied values are not. The shape of a pipeline is sometimes itself sensitive — review before enablingCaptureCommandTextin shared-tenancy databases. getMorecursor continuation is not correlated to the originatingfind. The driver does not surface a parent request id. EachgetMoreis its own root span by design; correlate via cursor id if needed.- Bounded map overflow is a signal. When the in-flight map reaches
MaxInFlightCommands, the instrumentation drops the new command's activity (stops it without tracking) and preserves the existing in-flight entries, emitting anEventSourcecounter on each drop. A non-zero overflow count means either a misbehaving consumer (unmatched request ids) or a real leak.
Performance
The hot path is gated on Activity.IsAllDataRequested. BenchmarkDotNet results live in bench/. The contract is: no allocation regression on the steady-state sampled-out path versus a no-op subscriber, measured on net8.0 and net10.0 with the tiered server GC.
Compatibility
MongoDB.Driver>= 3.0.0, < 4.0.0- .NET 8, .NET 9, .NET 10
- OpenTelemetry SDK 1.9+
Contributing
See CONTRIBUTING.md.
Security
See SECURITY.md. Do not file security issues publicly.
License
Apache-2.0. See LICENSE.
Acknowledgements
Prior art: Jimmy Bogard's MongoDB.Driver.Core.Extensions.DiagnosticSources. This library exists to cover gaps that surfaced during a production audit of that package — chiefly PII redaction defaults, exception-message suppression, dual sem-conv emission, and a bounded in-flight map. The shape of the public API is intentionally close to make migration mechanical; see docs/migration-from-jbogard.md.
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net8.0 is compatible. net8.0-android was computed. net8.0-browser was computed. net8.0-ios was computed. net8.0-maccatalyst was computed. net8.0-macos was computed. net8.0-tvos was computed. net8.0-windows was computed. net9.0 is compatible. net9.0-android was computed. net9.0-browser was computed. net9.0-ios was computed. net9.0-maccatalyst was computed. net9.0-macos was computed. net9.0-tvos was computed. net9.0-windows was computed. net10.0 is compatible. net10.0-android was computed. net10.0-browser was computed. net10.0-ios was computed. net10.0-maccatalyst was computed. net10.0-macos was computed. net10.0-tvos was computed. net10.0-windows was computed. |
-
net10.0
- MongoDB.Driver (>= 3.5.2)
- OpenTelemetry.Api (>= 1.15.3)
- SharpCompress (>= 0.49.0)
- Snappier (>= 1.3.1)
-
net8.0
- MongoDB.Driver (>= 3.5.2)
- OpenTelemetry.Api (>= 1.15.3)
- SharpCompress (>= 0.49.0)
- Snappier (>= 1.3.1)
- System.Diagnostics.DiagnosticSource (>= 10.0.0)
-
net9.0
- MongoDB.Driver (>= 3.5.2)
- OpenTelemetry.Api (>= 1.15.3)
- SharpCompress (>= 0.49.0)
- Snappier (>= 1.3.1)
- System.Diagnostics.DiagnosticSource (>= 10.0.0)
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.
| Version | Downloads | Last Updated |
|---|---|---|
| 0.1.0 | 53 | 5/29/2026 |