Skip to main content
Version: Current

Advanced Features

Enhance your logging with PII masking, correlation IDs, enrichers, and sampling.


PII Masking

Automatically mask sensitive data in your logs:

{
"PrimusLogging": {
"ApplicationId": "MyService",
"Targets": [
{ "Type": "console", "Pretty": true }
],
"Pii": {
"MaskEmails": true,
"MaskCreditCards": true,
"MaskSSN": true,
"MaskPasswords": true,
"MaskTokens": true,
"MaskSecrets": true
}
}
}

Result:

OriginalMasked
user@example.comu***@***.com
4111111111111111************1111
123-45-6789***-**-****

Custom PII Patterns

Mask custom sensitive data:

{
"Pii": {
"MaskEmails": true,
"CustomSensitiveKeys": ["apiKey", "secret"],
"CustomRegexPatterns": ["ORD-\\d{8}"]
}
}

Correlation IDs

The UsePrimusLogging() middleware automatically:

  • Generates a unique X-Correlation-ID for each request
  • Adds the correlation ID to all log entries
  • Returns the header in responses for tracing
var app = builder.Build();
app.UsePrimusLogging(); // Enables correlation IDs

Custom Enrichers

Add context to every log entry. Built-in enrichers: PropertyEnricher, MachineNameEnricher, ThreadIdEnricher.

// At the top of Program.cs — you need BOTH usings
using PrimusSaaS.Logging.Core; // for enricher classes
using PrimusSaaS.Logging.Extensions; // for AddPrimus()

builder.Logging.AddPrimus(opts =>
{
builder.Configuration.GetSection("PrimusLogging").Bind(opts);

// Static properties
opts.Enrichers.Add(new PropertyEnricher("Application", "OrderService"));
opts.Enrichers.Add(new PropertyEnricher("Environment", builder.Environment.EnvironmentName));

// Machine/thread info
opts.Enrichers.Add(new MachineNameEnricher());
opts.Enrichers.Add(new ThreadIdEnricher());
});

All three enricher classes live in the PrimusSaaS.Logging.Core namespace. Without this using, the compiler will not find them.


Sampling

Reduce log volume in high-traffic scenarios.

Option A — via appsettings.json (recommended):

{
"PrimusLogging": {
"Sampling": {
"Enabled": true,
"SampleRate": 0.10,
"AlwaysLogOnError": true
}
}
}

Option B — via code:

builder.Logging.AddPrimus(opts =>
{
builder.Configuration.GetSection("PrimusLogging").Bind(opts);
opts.SamplingRate = 0.10; // Keep 10% of low-importance logs
opts.AlwaysLogOnError = true; // Never sample out errors
});

is a convenience shortcut — setting it to automatically enables sampling with a 10% rate. ensures errors are never dropped.


Multiple Targets

Send logs to multiple destinations:

{
"PrimusLogging": {
"ApplicationId": "MyService",
"Environment": "Production",
"MinLevel": 1,
"Targets": [
{ "Type": "console", "Pretty": true },
{ "Type": "file", "Path": "logs/app.log" },
{ "Type": "applicationInsights", "ConnectionString": "..." }
],
"Pii": {
"MaskEmails": true,
"MaskCreditCards": true
}
}
}

Category Truncation

Shorten long category names:

builder.Logging.AddPrimus(opts =>
{
builder.Configuration.GetSection("PrimusLogging").Bind(opts);
opts.TruncateCategoryNames = true;
opts.MaxCategoryLength = 40; // Default: 120
});

Structured Logging Tips

  1. Use message templates with named properties:

    _logger.LogInformation("Order {OrderId} placed by {UserId}", orderId, userId);
  2. Use scopes for request-specific context:

    using (_logger.BeginScope(new Dictionary<string, object> { { "OrderId", order.Id } }))
    {
    _logger.LogInformation("Processing order");
    }
  3. Pass exceptions as the first parameter:

    _logger.LogError(ex, "Payment failed for {OrderId}", order.Id);

Environment-Aware Defaults

Pass IHostEnvironment to automatically apply environment-specific configuration:

using PrimusSaaS.Logging.Extensions;

builder.Services.AddPrimusLogging(builder.Environment);
SettingDevelopmentStagingProduction
MinLevelDebugInfoWarning
Console Prettytrueunchangedfalse (JSON)
PII MaskingOpt-inStrict (all on)Strict + MaskIPs
SamplingDisabledEnabledEnabled

Explicit values you set are never overwritten by defaults.


Log Level Hot-Reload

Change MinLevel at runtime without restarting:

{
"PrimusLogging": {
"MinLevel": 0
}
}

When using configuration binding (AddPrimus(builder.Configuration.GetSection(...))), changes to appsettings.json take effect immediately via IOptionsMonitor<LoggerOptions>.


Audit Logging

Typed, tamper-evident audit entries with schema versioning:

using PrimusSaaS.Logging.Audit;

auditLogger.Log(AuditEntries.DataAccess("user-1", "Read", "Orders:123", durationMs: 45.2));
auditLogger.Log(AuditEntries.Security("user-1", "Login", AuditOutcome.Failure, reason: "Bad password"));
auditLogger.Log(AuditEntries.Governance("system", "PolicyCheck", "GDPR", confidenceScore: 0.95));
auditLogger.Log(AuditEntries.ConfigurationChange("admin", "MaxRetries", oldValue: "3", newValue: "5"));
auditLogger.Log(AuditEntries.Lifecycle("user-1", "Deleted", "Order", "ORD-123"));

See also: Audit Logging | CloudWatch Audit Routing


Routing Telemetry

Typed models for orchestrator routing and dispatch decisions:

using PrimusSaaS.Logging.Telemetry;

var record = new RoutingTelemetryRecord("trace-123", "tenant-42", "evt-001", "Routed")
{
Reason = "Matched claims domain",
CompletedAt = DateTime.UtcNow
};
auditLogger.LogRoutingTelemetry(record);