Logging Advanced Features
Keep the advanced options aligned with the shipped SDK: correlation middleware, PII masking, enrichers, and sampling.
Baseline wiring
using PrimusSaaS.Logging.Extensions;
var builder = WebApplication.CreateBuilder(args);
builder.Logging.AddPrimus(opts =>
builder.Configuration.GetSection("PrimusLogging").Bind(opts));
var app = builder.Build();
// Request logging + correlation IDs (adds X-Correlation-ID header)
app.UsePrimusLogging();
app.MapControllers();
app.Run();
ApplicationId in PrimusLogging tags every log with the service name.
PII masking
Control masking via config and optional custom patterns/keys.
{
"PrimusLogging": {
"Pii": {
"MaskEmails": true,
"MaskCreditCards": true,
"MaskSSN": true,
"MaskPasswords": true,
"MaskTokens": true,
"MaskSecrets": true,
"CustomSensitiveKeys": ["apiKey", "secret"],
"CustomRegexPatterns": ["ORD-\\d{8}"]
}
}
}
Correlation IDs
app.UsePrimusLogging() issues/propagates X-Correlation-ID and adds it to logs. Downstream services can read the header and forward it on outgoing requests if needed.
Enrichers (add context)
Use built-in enrichers to append context to every log entry.
using PrimusSaaS.Logging.Core;
using PrimusSaaS.Logging.Extensions;
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());
});
For per-request context, use ILogger.BeginScope in your code to push properties for that request.
Sampling and category length
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
opts.TruncateCategoryNames = true;
opts.MaxCategoryLength = 120; // default
});
Multiple targets (example)
{
"PrimusLogging": {
"ApplicationId": "MyService",
"Environment": "Production",
"MinLevel": 1,
"Targets": [
{ "Type": "console", "Pretty": true },
{
"Type": "file",
"Path": "logs/app-.log",
"Async": true,
"MaxFileSize": 10485760,
"MaxRetainedFiles": 5,
"CompressRotatedFiles": true
},
{
"Type": "applicationInsights",
"ConnectionString": "your-connection-string"
}
],
"Pii": {
"MaskEmails": true,
"MaskCreditCards": true,
"MaskSSN": true
}
}
}
Structured logging tips
- Use message templates with named properties (
_logger.LogInformation("Order {OrderId}", orderId)). - Use scopes (
using _logger.BeginScope(new Dictionary<string,object>{{"OrderId", order.Id}}))) to add request-specific context. - Pass exceptions as the first parameter (
_logger.LogError(ex, "Payment failed for {OrderId}", order.Id)).
Environment-Aware Defaults
Automatically apply environment-specific configuration:
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 the defaults.
Log Level Hot-Reload
Change MinLevel at runtime without restarting. When using configuration binding, changes to appsettings.json take effect immediately via IOptionsMonitor<LoggerOptions>.
CloudWatch & X-Ray Integration
Send logs and metrics to AWS CloudWatch with optional X-Ray trace correlation:
builder.Services.AddPrimusLogging(opts => opts
.AddCloudWatchTarget(cw =>
{
cw.LogGroupName = "/app/my-service";
cw.Region = "us-east-1";
cw.EmitMetrics = true;
}));
See CloudWatch destination guide for IAM permissions, EMF metrics, and X-Ray setup.
Routing Telemetry
Typed models for orchestrator routing and dispatch decisions:
var record = new RoutingTelemetryRecord("trace-123", "tenant-42", "evt-001", "Routed");
auditLogger.LogRoutingTelemetry(record);