Skip to content

Logging & Observability

CaeriusNet uses [LoggerMessage] source-generated logging for zero-allocation structured log output. Every database operation emits timing, procedure name, and result metadata — enabling diagnostics, performance monitoring, and alerting without custom instrumentation.

Overview

FeatureImplementation
Zero-allocation[LoggerMessage] source generators — no string interpolation at runtime
Structured parametersNamed placeholders ({ProcedureName}, {Duration}, {RowCount})
Execution timingStopwatch.GetElapsedTime for high-resolution elapsed measurement
Event ID conventionCategorized by subsystem (see table below)
Provider-agnosticWorks with any ILogger implementation

Configuration

Setting the logger

CaeriusNet uses a static LoggerProvider to obtain the logger instance. Configure it during application startup:

csharp
using CaeriusNet.Logging;

var builder = WebApplication.CreateBuilder(args);

// After building the service provider, set the logger
var app = builder.Build();
LoggerProvider.SetLogger(app.Services.GetRequiredService<ILoggerFactory>());

Integration with dependency injection

When using CaeriusNetBuilder, the logger is configured automatically if ILoggerFactory is registered in the DI container:

csharp
var builder = WebApplication.CreateBuilder(args);

builder.Services.AddLogging(logging =>
{
    logging.AddConsole();
    logging.SetMinimumLevel(LogLevel.Information);
});

CaeriusNetBuilder
    .Create(builder.Services)
    .WithSqlServer(connectionString)
    .Build();

Filtering by event ID range

Use ILoggerFactory configuration to filter CaeriusNet logs by event ID ranges:

csharp
builder.Services.AddLogging(logging =>
{
    logging.AddFilter("CaeriusNet", LogLevel.Information);

    // Show only command execution events (5xxx)
    logging.AddFilter("CaeriusNet.Commands", LogLevel.Debug);

    // Suppress cache hit/miss noise in production
    logging.AddFilter("CaeriusNet.Cache", LogLevel.Warning);
});

Event ID categories

CaeriusNet organizes event IDs by subsystem. Use these ranges to filter, route, or alert on specific categories:

RangeCategoryDescription
1000–1999In-Memory CacheCache hit, miss, set, eviction
2000–2999Frozen CacheCache hit, miss, freeze operations
3000–3999Redis CacheRedis get, set, connection events
4000–4999Database / ConnectionConnection open, close, pool events
5000–5999Command ExecutionStart, complete, duration, row count

Detailed event reference

Event IDLevelMessage template
1001DebugIn-memory cache hit for key '{CacheKey}'
1002DebugIn-memory cache miss for key '{CacheKey}'
1003InformationIn-memory cache set for key '{CacheKey}' with expiration {Expiration}
2001DebugFrozen cache hit for key '{CacheKey}'
2002DebugFrozen cache miss for key '{CacheKey}'
2003InformationFrozen cache set for key '{CacheKey}'
3001DebugRedis cache hit for key '{CacheKey}'
3002DebugRedis cache miss for key '{CacheKey}'
3003InformationRedis cache set for key '{CacheKey}' with expiration {Expiration}
3004WarningRedis connection failed: {ErrorMessage}
4001DebugOpening SQL connection
4002DebugSQL connection opened in {Duration}
4003DebugSQL connection closed
5001DebugExecuting stored procedure '{ProcedureName}'
5002InformationStored procedure '{ProcedureName}' completed in {Duration} ({RowCount} rows)
5003WarningStored procedure '{ProcedureName}' exceeded threshold: {Duration}
5004ErrorStored procedure '{ProcedureName}' failed: {ErrorMessage}

Structured parameters

CaeriusNet logs use semantic (structured) parameters. These are preserved as key-value pairs by structured logging sinks:

ParameterTypeDescription
{ProcedureName}stringFully qualified stored procedure name
{Duration}TimeSpanElapsed execution time
{RowCount}intNumber of rows returned or affected
{CacheKey}stringCache key used for lookup/store
{Expiration}TimeSpanCache entry TTL
{ErrorMessage}stringException message on failure
{IsolationLevel}stringTransaction isolation level

Structured logging benefits

Structured parameters enable powerful queries: "Show all executions of sp_GetUsers that took longer than 500ms" or "Count cache misses per key in the last hour."

Integration examples

Serilog

csharp
using Serilog;

var builder = WebApplication.CreateBuilder(args);

builder.Host.UseSerilog((context, config) =>
{
    config
        .ReadFrom.Configuration(context.Configuration)
        .WriteTo.Console(outputTemplate:
            "[{Timestamp:HH:mm:ss} {Level:u3}] [{EventId}] {Message:lj}{NewLine}{Exception}")
        .WriteTo.Seq("http://localhost:5341");
});

CaeriusNetBuilder
    .Create(builder.Services)
    .WithSqlServer(connectionString)
    .Build();

Filter CaeriusNet events in appsettings.json:

json
{
  "Serilog": {
    "MinimumLevel": {
      "Default": "Information",
      "Override": {
        "CaeriusNet.Cache": "Warning",
        "CaeriusNet.Commands": "Debug"
      }
    }
  }
}

OpenTelemetry

Export CaeriusNet logs to an OTLP-compatible backend:

csharp
builder.Services.AddOpenTelemetry()
    .WithLogging(logging =>
    {
        logging.AddOtlpExporter();
    });

builder.Services.AddLogging(logging =>
{
    logging.AddOpenTelemetry(options =>
    {
        options.IncludeFormattedMessage = true;
        options.IncludeScopes = true;
    });
});

Application Insights

csharp
builder.Services.AddApplicationInsightsTelemetry();
builder.Services.AddLogging(logging =>
{
    logging.AddApplicationInsights();
    logging.AddFilter<ApplicationInsightsLoggerProvider>(
        "CaeriusNet", LogLevel.Information);
});
Custom telemetry from CaeriusNet events

Use ILogger event subscriptions or middleware to convert CaeriusNet log events into custom Application Insights metrics:

csharp
// Example: track execution duration as a custom metric
services.AddSingleton<ILoggerProvider, CustomMetricsLoggerProvider>();

Performance considerations

AspectGuidance
Log level filteringSet CaeriusNet.Cache to Warning in production to suppress per-request cache hit/miss noise
High-throughput pathsDebug level events are compiled out when the level is not enabled (source-generator check)
Structured sinksPrefer Seq, Elasticsearch, or OTLP over flat-file for queryability
SamplingFor very high RPS, configure sampling in your telemetry pipeline

Avoid excessive logging in hot paths

Debug-level cache events fire on every database call. In production, ensure your minimum level is Information or higher for CaeriusNet categories to avoid log volume overwhelming sinks.

Troubleshooting

SymptomCauseFix
No CaeriusNet logs appearLogger not configuredCall LoggerProvider.SetLogger(...) at startup
Missing structured parametersUsing flat-text sinkSwitch to a structured sink (Seq, OTLP, JSON console)
High log volumeDebug level in productionRaise minimum level to Information
Missing timing dataLogs filtered too aggressivelyEnsure event ID 5002 (command complete) is not filtered

Next: Best Practices — recommendations for production-ready CaeriusNet usage.

Released under the MIT License.