Skip to main content

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);