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:
| Original | Masked |
|---|---|
user@example.com | u***@***.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-IDfor 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.Corenamespace. Without thisusing, 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
-
Use message templates with named properties:
_logger.LogInformation("Order {OrderId} placed by {UserId}", orderId, userId); -
Use scopes for request-specific context:
using (_logger.BeginScope(new Dictionary<string, object> { { "OrderId", order.Id } }))
{
_logger.LogInformation("Processing order");
} -
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);
| Setting | Development | Staging | Production |
|---|---|---|---|
| MinLevel | Debug | Info | Warning |
| Console Pretty | true | unchanged | false (JSON) |
| PII Masking | Opt-in | Strict (all on) | Strict + MaskIPs |
| Sampling | Disabled | Enabled | Enabled |
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);