Skip to content

v6.3.0

Choose a tag to compare

@github-actions github-actions released this 23 Jul 09:17
· 15 commits to master since this release

v6.3.0 — first-class logging and metrics

This release makes the engine observable through the tools you already use. Point Serilog (or
NLog, or the console) at it and every executed query shows up in your logs — the same way EF Core
does it, with no logger-specific packages to install.

Logging — Microsoft.Extensions.Logging, EF-style

Log.Logger = new LoggerConfiguration()
    .MinimumLevel.Override("eQuantic.Core.Data", LogEventLevel.Information)
    .WriteTo.Console()
    .CreateLogger();

Add the assembly's category to your configuration and executed queries log with placeholders,
elapsed time and row counts. Categories are stable (eQuantic.Core.Data.{provider}.Command,
and eQuantic.Core.Data.cosmosdb.Request) with stable event ids, so any
Microsoft.Extensions.Logging sink — Serilog, NLog, the ASP.NET console — plugs in through the
providers it already ships. No eQuantic.Core.Data.Serilog package needed: the mechanism serves
every logger on day one.

Event Id Level Carries
CommandExecuted 10001 Information statement (placeholders), elapsed, rows; Cosmos adds status + RU charge
CommandFailed 10002 Error statement + exception
CommitExecuted 10101 Information staged writes flushed, elapsed
ClientEvaluation 10201 Warning a residual that ran client-side (behind its opt-in)
AllowFiltering 10202 Warning a Cassandra query running as a declared scan
QuerySplit 10203 Warning an OR filter fanned out into parallel native queries
ConcurrencyConflict 10301 Warning expected vs affected on a lost race

Beyond what EF logs

The pushdown gates log at Warning — an opt-in that quietly became a hot path's habit surfaces
in production logs, not in an incident review. And Cosmos DB logs the request charge (RU) per
operation, the number Cosmos operators actually chase.

Values are opt-in, always

Parameter values never log by default — statements carry placeholders, the same policy the traces
follow. Turn them on the way you turn EF's on, deliberately, per environment:

services.AddSingleton(new DataConventions { EnableSensitiveDataLogging = true });

Metrics — one Meter for the dashboards

services.AddOpenTelemetry().WithMetrics(m => m.AddMeter("eQuantic.Core.Data").AddOtlpExporter());

Command counters and a duration histogram, commit/write counters, and — the differentiator — the
gate counters (equantic.client_evaluations, equantic.allow_filtering,
equantic.query_splits, equantic.concurrency_conflicts) that make the engine's honesty
graphable: a rising client-evaluation line is an alert, not an archaeology project.

How it's wired

One seam per provider, each the store's natural one — a delegating DbCommand on the relational
engine (catches reads, aggregates, set-based writes and includes in one place), the
prepared-statement executor on Cassandra, the driver's own command events on MongoDB, a
RequestHandler in the pipeline on Cosmos DB. An ILoggerFactory from DI is optional; without one
the engine logs to a null logger and costs nothing.

Verification

Suites green on real stores: PostgreSQL 55 (the logging contract itself pinned — stable category,
placeholder default, sensitive opt-in, commit event), Cassandra 94, MongoDB 131, Cosmos DB 41,
core 62.

Compatibility: no breaking changes; adds a floored Microsoft.Extensions.Logging.Abstractions
dependency (8.0.0 on net8, 10.0.0 on net10 — your own generation, never forced upward). Requires
eQuantic.Core.DataModel 4.0.0 / eQuantic.Core.Domain 4.0.0 (as since v6.0.0). Full guide:
Operations → Observability.