MongoDB Statements in C# loggen
Welche Statements schickt der MongoDB Driver for C# eigentlich an die Datenbank? Ist das genauso effizient wie das, was wir in MongoDB Compass vorbereitet haben? Folgende Methoden bringen Licht ins Dunkel:
Pipelines im Debugger betrachten
Insbesondere bei Aggregation Pipelines, die ja eher für die komplexeren Abfragen verwendet werden, ist es glücklicherweise relativ einfach, eine Pipeline während des Debuggens zu betrachten. Nehmen wir beispielsweise folgende Aggregation:
var aggregate = movies.Aggregate()
.Match(x => x.Year >= 1980 && x.Year < 1990)
.SortByDescending(x => x.Awards.Wins)
.Limit(30);
var results = await aggregate.ToListAsync();
Wenn man aggregate
im Debugger betrachtet, wird die Pipeline schon einmal deutlich dargestellt:
{aggregate([{ "$match" : { "year" : { "$gte" : 1980, "$lt" : 1990 } } },
{ "$sort" : { "awards.wins" : -1 } },
{ "$limit" : 30 }])}
Das hilft zur Entwurfszeit schon einmal enorm, aber was ist, wenn wir Verhalten auf einem Testsystem nachvollziehen wollen? Hier hilft das Loggen der Statements.
Alle MongoDB Statements loggen
Um alle Statements zu loggen, die der Driver an die Datenbank schickt, ist der ClusterConfigurator
ein geeigneter Ansatzpunkt. Zu beachten ist jedoch, dass das Loggen der Statements einen beträchtlichen Performance Hit mit sich bringen kann, so dass man selbst auf der Entwicklungsumgebung dies nur optional zuschaltbar machen sollte - dies gilt natürlich verstärkt auf anderen Umgebungen, um die Arbeit derjenigen, die die Anwendung verwenden, nicht zu beeinträchtigen.
var settings = MongoClientSettings.FromConnectionString("...");
settings.ClusterConfigurator = cb =>
{
cb.Subscribe<CommandStartedEvent>(ev => logger.LogDebug("{event}/{request}: {name}, {command}",
nameof(CommandStartedEvent),
ev.RequestId,
ev.CommandName,
ev.Command.ToJson()));
cb.Subscribe<CommandSucceededEvent>(ev => logger.LogDebug("{event}/{request}: took {duration}.",
nameof(CommandSucceededEvent),
ev.RequestId,
ev.Duration));
cb.Subscribe<CommandFailedEvent>(ev => logger.LogDebug("{event}/{request}: took {duration}, but failed: {failure}",
nameof(CommandFailedEvent),
ev.RequestId,
ev.Duration,
ev.Failure));
};
var client = new MongoClient(settings);
In obigem Beispiel werden Handler für die drei verfügbaren Events im ClusterBuilder
konfiguriert. Das CommandStartedEvent
wird zu Beginn jedes Commands ausgelöst und liefert Informationen zum Statement, bevor dieses abgeschickt wird. Die beiden weiteren Events (CommandSucceededEvent
und CommandFailedEvent
) informieren über Erfolg bzw. Fehlschlag. Enthalten sind beispielsweise auch Informationen zur Laufzeit und gegebenenfalls die Fehlermeldung. In obigem Beispiel für das Aggregate führt dies zu folgender Ausgabe:
CommandStartedEvent/4: isMaster, { "isMaster" : 1, "helloOk" : true, "client" : { "driver" : { "name" : "mongo-csharp-driver", "version" : "2.17.1.0" }, "os" : { "type" : "Windows", "name" : "Microsoft Windows 10.0.22621", "architecture" : "x86_64", "version" : "10.0.22621" }, "platform" : ".NET 6.0.9" }, "compression" : [] }
CommandSucceededEvent/4: took 00:00:00.0553008.
CommandStartedEvent/5: aggregate, { "aggregate" : "movies", "pipeline" : [{ "$match" : { "year" : { "$gte" : 1980, "$lt" : 1990 } } }, { "$sort" : { "awards.wins" : -1 } }, { "$limit" : 30 }], "cursor" : { }, "$db" : "sample_mflix", "lsid" : { "id" : UUID("a97ff971-8188-4a5d-8307-09dc926a4124") } }
CommandSucceededEvent/5: took 00:00:00.1056318.
Wie zu sehen ist, werden auch die ersten Statements beim Verbindungsaufbau mit geloggt. Klar zu erkennen ist auch das Aggrgate. Über die Request-Id kann eine Verbindung zwischen dem CommandStartedEvent
und dem nachfolgenden Event hergestellt werden.
Fazit
Das Beispiel zeigt, dass einfacher Code ausreicht, um Statements, die der MongoDB Driver for C# absetzt, zu loggen und analysieren zu können. Wir hoffen, dass Ihnen dieses Beispiel ebenso wie uns hilft, um im Detail zu sehen, ob die Statements den Erwartungen entsprechen.