PrimusSaaS.Logging
1.2.2
See the version list below for details.
dotnet add package PrimusSaaS.Logging --version 1.2.2
NuGet\Install-Package PrimusSaaS.Logging -Version 1.2.2
<PackageReference Include="PrimusSaaS.Logging" Version="1.2.2" />
<PackageVersion Include="PrimusSaaS.Logging" Version="1.2.2" />
<PackageReference Include="PrimusSaaS.Logging" />
paket add PrimusSaaS.Logging --version 1.2.2
#r "nuget: PrimusSaaS.Logging, 1.2.2"
#:package PrimusSaaS.Logging@1.2.2
#addin nuget:?package=PrimusSaaS.Logging&version=1.2.2
#tool nuget:?package=PrimusSaaS.Logging&version=1.2.2
PrimusSaaS.Logging - Enterprise Logging for .NET
Enterprise-grade structured logging library for .NET applications with automatic context enrichment, PII masking, and multiple output targets.
Full client integration guide (Node + .NET + Identity + Logging): see
docs-site/docs/modules/client-integration-guide.md.
Features
- ✅ Structured Logging - JSON-formatted logs with rich context
- ✅ Log Levels - DEBUG, INFO, WARNING, ERROR, CRITICAL
- ✅ Multiple Targets - Console, File, Azure Application Insights
- ✅ PII Masking - Automatic redaction of sensitive data
- ✅ File Rotation - Size-based rotation with gzip compression
- ✅ Async Buffering - High-performance non-blocking logging
- ✅ Custom Enrichers - Add dynamic context to every log
- ✅ Standard ILogger - Full compatibility with Microsoft.Extensions.Logging
- ✅ Serilog/NLog Bridge - Forward enriched logs into existing sink ecosystems
- ✅ ASP.NET Core Integration - Middleware for automatic HTTP context enrichment
- ✅ Thread-Safe - Safe for concurrent use
Installation
dotnet add package PrimusSaaS.Logging
Quick Start
Option 1: Standard ILogger (Recommended)
Use the familiar ILogger<T> interface:
using Microsoft.Extensions.Logging;
using PrimusSaaS.Logging.Extensions;
// Alias to avoid conflict with Microsoft.Extensions.Logging.LogLevel
using PrimusLogLevel = PrimusSaaS.Logging.Core.LogLevel;
var builder = WebApplication.CreateBuilder(args);
// Replace default logging with PrimusSaaS.Logging
// Both AddPrimus() and AddPrimusLogging() work (aliases)
builder.Logging.ClearProviders();
builder.Logging.AddPrimus(builder.Configuration.GetSection("PrimusLogging"));
// or configure in code:
// builder.Logging.AddPrimus(options =>
// {
// options.ApplicationId = "MY-APP";
// options.Environment = "production";
// options.MinLevel = PrimusLogLevel.Info;
// options.Targets = new List<PrimusSaaS.Logging.Core.TargetConfig>
// {
// new() { Type = "console", Pretty = true },
// new() { Type = "file", Path = "logs/app.log", Async = true }
// };
// });
var app = builder.Build();
// Optional: Add middleware for automatic HTTP context enrichment
// Requires: using PrimusSaaS.Logging.Extensions;
app.UsePrimusLogging();
app.Run();
// Use in controllers
[ApiController]
public class MyController : ControllerBase
{
private readonly ILogger<MyController> _logger;
public MyController(ILogger<MyController> logger)
{
_logger = logger;
}
[HttpGet]
public IActionResult Get()
{
_logger.LogInformation("Request received");
_logger.LogInformation("User {UserId} from {IP}", "user-123", "192.168.1.1");
return Ok();
}
}
Option 2: Direct Logger
Use the PrimusSaaS Logger class directly:
using PrimusSaaS.Logging.Core;
// If Microsoft.Extensions.Logging is NOT used in this file, LogLevel is unambiguous
// Otherwise use PrimusSaaS.Logging.Core.LogLevel
var logger = new Logger(new LoggerOptions
{
ApplicationId = "MY-APP",
Environment = "production",
MinLevel = LogLevel.Info
});
logger.Info("Application started");
logger.Error("Something went wrong", new Dictionary<string, object>
{
["errorCode"] = "ERR_001",
["userId"] = "12345"
});
Migrate from Microsoft.Extensions.Logging with No Call-Site Changes
If your controllers/services already use ILogger<T>, keep them as-is:
- Add configuration (appsettings.json):
{
"PrimusLogging": {
"ApplicationId": "MY-APP",
"Environment": "production",
"MinLevel": 1,
"Targets": [
{ "Type": "console", "Pretty": true },
{ "Type": "file", "Path": "logs/app.log", "Async": true }
]
}
}
- Wire up the compatibility shim in Program.cs:
builder.Logging.ClearProviders();
builder.Logging.AddPrimus(builder.Configuration.GetSection("PrimusLogging"));
// existing ILogger<T> injections continue to work
- (Optional) Add
app.UsePrimusLogging()for automatic HTTP context enrichment.
## Configuration
### Logger Options
```csharp
var options = new LoggerOptions
{
// Application identifier
ApplicationId = "MY-APP",
// Environment (development, testing, production)
Environment = "production",
// Minimum log level (use fully qualified name if needed)
MinLevel = PrimusSaaS.Logging.Core.LogLevel.Info,
// Output targets
Targets = new List<TargetConfig>
{
new() { Type = "console", Pretty = true },
new() { Type = "file", Path = "logs/app.log" }
}
};
Output Targets
Console Target
new TargetConfig
{
Type = "console",
Pretty = true // Colored output for development
}
File Target
new TargetConfig
{
Type = "file",
Path = "logs/app.log",
Async = true, // Non-blocking writes
MaxFileSize = 10 * 1024 * 1024, // 10MB
MaxRetainedFiles = 5, // Keep 5 old files
CompressRotatedFiles = true // Gzip old files
}
Azure Application Insights
new TargetConfig
{
Type = "applicationInsights",
ConnectionString = "InstrumentationKey=..."
}
Bridge to Serilog or NLog
- Reuse an existing Serilog pipeline (and its sinks like Elasticsearch/Seq/Splunk/App Insights):
options.Targets = new List<TargetConfig>
{
new() { Type = "serilog" }
};
- Reuse an existing NLog configuration (targets/layouts from NLog.config or code):
options.Targets = new List<TargetConfig>
{
new() { Type = "nlog" }
};
Enterprise Features
PII Masking
Automatically redact sensitive information:
builder.Logging.AddPrimus(options =>
{
options.Pii.MaskEmails = true;
options.Pii.MaskCreditCards = true;
options.Pii.MaskSSN = true;
options.Pii.CustomSensitiveKeys.Add("password");
options.Pii.CustomSensitiveKeys.Add("apiKey");
});
Custom Enrichers
Add dynamic context to every log:
public class MachineNameEnricher : IEnricher
{
public void Enrich(Dictionary<string, object> context)
{
context["machineName"] = Environment.MachineName;
}
}
options.Enrichers.Add(new MachineNameEnricher());
options.Enrichers.Add(new ThreadIdEnricher());
Performance Tracking
var timer = logger.StartTimer();
// Your operation
await ProcessData();
timer.Done("Data processed", new Dictionary<string, object>
{
["recordCount"] = 1000
});
// Logs: "Data processed" with duration in milliseconds
Correlation IDs
var correlationId = logger.GenerateCorrelationId();
logger.Info("Step 1", new Dictionary<string, object>
{
["correlationId"] = correlationId
});
logger.Info("Step 2", new Dictionary<string, object>
{
["correlationId"] = correlationId
});
ASP.NET Core Integration
Middleware
The middleware automatically enriches logs with HTTP context:
using Microsoft.Extensions.Logging;
using PrimusSaaS.Logging.Extensions;
var builder = WebApplication.CreateBuilder(args);
// Add Primus Logging to the logging pipeline
builder.Logging.ClearProviders();
builder.Logging.AddPrimus(options =>
{
options.ApplicationId = "MY-WEBAPI";
options.Environment = "production";
});
var app = builder.Build();
// Add middleware for automatic HTTP context enrichment
app.UsePrimusLogging();
app.Run();
Logs will automatically include:
- Request ID - From
X-Request-IDheader or auto-generated - HTTP Method & Path
- Status Code
- User Context - If set in
HttpContext.Items["PrimusUser"] - Tenant Context - If set in
HttpContext.Items["PrimusTenantContext"]
Manual Context Enrichment
// In your authentication middleware
HttpContext.Items["PrimusUser"] = new Dictionary<string, object>
{
["userId"] = "user-12345",
["email"] = "john@example.com"
};
HttpContext.Items["PrimusTenantContext"] = new Dictionary<string, object>
{
["tenantId"] = "tenant-acme",
["tenantName"] = "Acme Corporation"
};
// All subsequent logs will include this context
Log Levels
| Level | Value | Description |
|---|---|---|
| Debug | 0 | Detailed diagnostic information |
| Info | 1 | Informational messages |
| Warning | 2 | Warning messages |
| Error | 3 | Error messages |
| Critical | 4 | Critical failures |
Log Level Filtering
var logger = new Logger(new LoggerOptions
{
MinLevel = LogLevel.Warning // Only WARNING, ERROR, CRITICAL
});
logger.Debug("Not logged");
logger.Info("Not logged");
logger.Warn("Logged!");
logger.Error("Logged!");
Best Practices
- Use Standard ILogger - For ecosystem compatibility
- Set Appropriate Log Levels - DEBUG for development, INFO+ for production
- Include Context - Always add relevant context data
- Use Correlation IDs - For tracking requests across services
- Enable PII Masking - Protect sensitive data in production
- Use Async Targets - For high-throughput applications
- Configure File Rotation - Prevent disk space exhaustion
Examples
See the Examples/ directory:
BasicUsage/- Console applicationWebApiExample/- ASP.NET Core Web APIStandardLoggerExample/- Using ILogger interface
Performance
- Async Buffering: Non-blocking writes with configurable buffer size
- Thread-Safe: Lock-free reads, minimal contention
- File Rotation: Automatic cleanup prevents disk exhaustion
- Compression: Gzip reduces storage by ~70%
Documentation
- CONFIGURATION_GUIDE.md - Detailed configuration options
- CUSTOM_ENRICHERS_GUIDE.md - Guide to creating custom enrichers
- TROUBLESHOOTING.md - Common issues and solutions
- VERIFICATION_GUIDE.md - Verification steps
- MIGRATION_GUIDE.md - Moving from Microsoft.Extensions.Logging to Primus
- ROLLOUT_RUNBOOK.md - Canary/dual/cutover steps + monitoring
- Call-site converter (dry-run by default):
dotnet run --project ./PrimusSaaS.Logging.CallsiteConverter/PrimusSaaS.Logging.CallsiteConverter.csproj -- --path <root> [--write]
License
MIT License - See LICENSE file for details
Support
For issues and questions:
- GitHub Issues: https://github.com/primus-saas/logging
- Documentation: https://docs.primus-saas.com/logging
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net6.0 is compatible. net6.0-android was computed. net6.0-ios was computed. net6.0-maccatalyst was computed. net6.0-macos was computed. net6.0-tvos was computed. net6.0-windows was computed. net7.0 is compatible. net7.0-android was computed. net7.0-ios was computed. net7.0-maccatalyst was computed. net7.0-macos was computed. net7.0-tvos was computed. net7.0-windows was computed. net8.0 was computed. net8.0-android was computed. net8.0-browser was computed. net8.0-ios was computed. net8.0-maccatalyst was computed. net8.0-macos was computed. net8.0-tvos was computed. net8.0-windows was computed. net9.0 was computed. net9.0-android was computed. net9.0-browser was computed. net9.0-ios was computed. net9.0-maccatalyst was computed. net9.0-macos was computed. net9.0-tvos was computed. net9.0-windows was computed. net10.0 was computed. net10.0-android was computed. net10.0-browser was computed. net10.0-ios was computed. net10.0-maccatalyst was computed. net10.0-macos was computed. net10.0-tvos was computed. net10.0-windows was computed. |
-
net6.0
- Microsoft.ApplicationInsights.AspNetCore (>= 2.21.0)
- Microsoft.AspNetCore.Http.Abstractions (>= 2.2.0)
- Microsoft.AspNetCore.Routing (>= 2.2.0)
- Microsoft.Extensions.DependencyInjection (>= 6.0.0)
- Microsoft.Extensions.Logging (>= 6.0.0)
- Microsoft.Extensions.Logging.Abstractions (>= 6.0.0)
- Microsoft.Extensions.Options (>= 6.0.0)
- Microsoft.Extensions.Primitives (>= 6.0.0)
- NLog (>= 5.2.8)
- Serilog (>= 2.12.0)
- System.Diagnostics.DiagnosticSource (>= 6.0.0)
-
net7.0
- Microsoft.ApplicationInsights.AspNetCore (>= 2.21.0)
- Microsoft.AspNetCore.Http.Abstractions (>= 2.2.0)
- Microsoft.AspNetCore.Routing (>= 2.2.0)
- Microsoft.Extensions.DependencyInjection (>= 7.0.0)
- Microsoft.Extensions.Logging (>= 7.0.0)
- Microsoft.Extensions.Logging.Abstractions (>= 7.0.0)
- Microsoft.Extensions.Options (>= 7.0.0)
- Microsoft.Extensions.Primitives (>= 7.0.0)
- NLog (>= 5.2.8)
- Serilog (>= 2.12.0)
- System.Diagnostics.DiagnosticSource (>= 7.0.0)
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.
Resolved duplicate UsePrimusLogging extension ambiguity when used alongside other Primus packages; safe serialization; scopes + correlation IDs; async buffering with metrics; logging metrics endpoint helper; file rotation and AI target support; health/metrics guidance updated.