PrimusSaaS.Logging
1.2.3
See the version list below for details.
dotnet add package PrimusSaaS.Logging --version 1.2.3
NuGet\Install-Package PrimusSaaS.Logging -Version 1.2.3
<PackageReference Include="PrimusSaaS.Logging" Version="1.2.3" />
<PackageVersion Include="PrimusSaaS.Logging" Version="1.2.3" />
<PackageReference Include="PrimusSaaS.Logging" />
paket add PrimusSaaS.Logging --version 1.2.3
#r "nuget: PrimusSaaS.Logging, 1.2.3"
#:package PrimusSaaS.Logging@1.2.3
#addin nuget:?package=PrimusSaaS.Logging&version=1.2.3
#tool nuget:?package=PrimusSaaS.Logging&version=1.2.3
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.
v1.2.3:
- DOCS: Comprehensive documentation update with accurate implementation examples and best practices.
- Improved developer experience with clear migration guides and copy-paste ready samples.
v1.2.2: Resolved duplicate UsePrimusLogging extension ambiguity; safe serialization; scopes + correlation IDs; async buffering with metrics.