Skip to content

The search box knows all the secrets -- try it!

Polecat is part of the Critter Stack ecosystem.

JasperFx Logo JasperFx provides formal support for Polecat and other Critter Stack libraries. Please check our Support Plans for more details.

Diagnostics and Instrumentation ​

Polecat provides several tools for monitoring, debugging, and understanding what's happening in your application.

Session Logging ​

IPolecatLogger ​

Implement IPolecatLogger at the store level to create per-session loggers:

cs
public class ConsolePolecatLogger : IPolecatLogger
{
    public IPolecatSessionLogger StartSession(IQuerySession session)
    {
        return new ConsoleSessionLogger();
    }
}

public class ConsoleSessionLogger : IPolecatSessionLogger
{
    public void OnBeforeExecute(string sql)
    {
        Console.WriteLine($"Executing: {sql}");
    }

    public void LogSuccess(string sql)
    {
        Console.WriteLine($"Success: {sql}");
    }

    public void LogFailure(string sql, Exception ex)
    {
        Console.WriteLine($"Failed: {sql} - {ex.Message}");
    }

    public void RecordSavedChanges(IDocumentSession session)
    {
        Console.WriteLine($"Saved changes ({session.RequestCount} requests)");
    }
}

Register the logger:

cs
opts.Logger(new ConsolePolecatLogger());

Request Counting ​

Track database requests per session:

cs
await using var session = store.LightweightSession();
await session.LoadAsync<User>(id);
Console.WriteLine(session.RequestCount); // 1

SQL Preview ​

ToSql ​

Preview the SQL generated by a LINQ query:

cs
var sql = session.Query<User>()
    .Where(x => x.LastName == "Smith")
    .ToSql();

Console.WriteLine(sql);
// SELECT data FROM pc_doc_user WHERE JSON_VALUE(data, '$.lastName') = @p0

Schema Diagnostics ​

ToDatabaseScript ​

Generate the complete DDL script for all Polecat tables:

cs
var script = await store.Advanced.ToDatabaseScript();
Console.WriteLine(script);

WriteCreationScriptToFileAsync ​

Save the schema script to a file:

cs
await store.Advanced.WriteCreationScriptToFileAsync("/path/to/schema.sql");

Reads against a schema that is not there ​

Every diagnostic read of the event-store tables — projection progression, dead-letter counts and rows, the highest event sequence, the event-store floor at a timestamp, and Advanced.FetchEventStoreStatistics() — answers "no results" rather than throwing when the storage it reads does not exist. Empty, null or 0, depending on the read.

Two situations reach it, and both are ordinary:

  • AutoCreate.None against a database where the schema was never applied. Being in the migration set does not help if nothing ever applies it.
  • Column drift. A pc_event_progression created before Events.EnableExtendedProgressionTracking was turned on has none of the heartbeat / agent_status / pause_reason columns the progression reads select.

This matters most for a monitoring tool polling a fleet: one store in the fan-out throwing would otherwise abort the whole poll, and the operator gets an empty page for the shards that do have data. The decision is made from the database's own error rather than from configuration, because drift is invisible to configuration — a store can declare extended tracking, have every table in its migration set, and still be pointed at a schema where neither is true.

WARNING

This applies to diagnostic reads only. Writes still throw: silently dropping a progression or telemetry write is a worse failure than a read returning nothing. The single exception is DeleteProjectionProgressByShardNameAsync, whose contract already promises a clean no-op for a row that is not there.

Data Cleanup ​

CleanAllDocumentsAsync ​

Delete all data from all document tables:

cs
await store.Advanced.CleanAllDocumentsAsync();

CleanAsync ​

Delete all data from a specific document table:

cs
await store.Advanced.CleanAsync<User>();

CleanAllEventDataAsync ​

Delete all event data (events, streams, progressions):

cs
await store.Advanced.CleanAllEventDataAsync();

WARNING

These cleanup methods permanently delete data. They are intended for testing and development, not production use.

Projection Daemon Monitoring ​

Extended Progression Tracking ​

Polecat can extend its event-progression table (pc_event_progression) with additional columns that the asynchronous projection daemon uses to report per-shard health — the same surface monitoring tools such as CritterWatch read to show heartbeat liveness, agent status, pause reasons, and per-shard alert thresholds.

Opt in via the event store options:

cs
var store = DocumentStore.For(opts =>
{
    opts.Connection("...");
    opts.Events.EnableExtendedProgressionTracking = true;
});

When enabled, the next schema apply adds six nullable columns to pc_event_progression (heartbeat, agent_status, pause_reason, running_on_node, warning_behind_threshold, critical_behind_threshold); the daemon writes its runtime agent state to them, and they are read back into JasperFx.Events.Projections.ShardState. The default is false, in which case no extra columns are created.

StoreOptions.Events also implements the storage-agnostic JasperFx.Events.IEventStoreInstrumentation interface, whose ExtendedProgressionEnabled property is an alias for EnableExtendedProgressionTracking. This lets store-agnostic tooling toggle the same monitoring fidelity across Marten and Polecat without referencing store-specific types:

cs
IEventStoreInstrumentation instrumentation = store.Options.Events;
instrumentation.ExtendedProgressionEnabled = true;

Released under the MIT License.