You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

重构.NET Framework应用:如何为.NET Core日志框架新增日志级别?

Adding Custom Log Levels to Microsoft.Extensions.Logging for .NET Framework

Hey Julian, great question! I’ve dealt with this exact scenario when migrating legacy .NET Framework apps to use the modern Microsoft.Extensions.Logging stack, so let’s break down how to add your custom log levels without ditching the framework’s built-in functionality.

Step 1: Define Your Custom Log Level Enumeration

First, create an enumeration that includes the default .NET log levels plus your custom ones. This makes it easier to reference levels throughout your code instead of using magic numbers:

public enum CustomLogLevel
{
    // Match default Microsoft.Extensions.Logging.LogLevel values
    Trace = 0,
    Debug = 1,
    Information = 2,
    Warning = 3,
    Error = 4,
    Critical = 5,
    // Add your custom levels here
    Verbose = 6,
    Audit = 7
}

Step 2: Extend ILogger for Custom Level Methods

To make logging with your custom levels as intuitive as the default ones, add extension methods to ILogger:

public static class CustomLoggerExtensions
{
    // Basic logging methods
    public static void Verbose(this ILogger logger, string message, params object[] args)
    {
        logger.Log((LogLevel)(int)CustomLogLevel.Verbose, message, args);
    }

    public static void Audit(this ILogger logger, string message, params object[] args)
    {
        logger.Log((LogLevel)(int)CustomLogLevel.Audit, message, args);
    }

    // Overloads for logging exceptions
    public static void Verbose(this ILogger logger, Exception exception, string message, params object[] args)
    {
        logger.Log((LogLevel)(int)CustomLogLevel.Verbose, exception, message, args);
    }

    public static void Audit(this ILogger logger, Exception exception, string message, params object[] args)
    {
        logger.Log((LogLevel)(int)CustomLogLevel.Audit, exception, message, args);
    }
}

Now you can call logger.Verbose("Detailed trace message") just like you’d use logger.LogInformation(...).

Step 3: Handle Custom Levels in Log Formatting

Default log providers (like the Console provider) won’t recognize your custom level names out of the box. To display friendly names instead of numeric values, create a custom formatter:

public class CustomConsoleFormatter : ConsoleFormatter
{
    public CustomConsoleFormatter() : base("CustomFormatter") { }

    public override void Write<TState>(in LogEntry<TState> logEntry, IExternalScopeProvider scopeProvider, TextWriter textWriter)
    {
        // Map the numeric LogLevel to your custom enum name
        var levelName = ((CustomLogLevel)(int)logEntry.LogLevel).ToString();
        var timestamp = DateTimeOffset.Now.ToString("yyyy-MM-dd HH:mm:ss");

        // Build your log line (customize this to match your legacy format if needed)
        textWriter.WriteLine($"[{timestamp}] [{levelName}] {logEntry.Message}");

        // Include exception details if present
        if (logEntry.Exception != null)
        {
            textWriter.WriteLine(logEntry.Exception.ToString());
        }
    }
}

Then register this formatter when setting up your logging:

var serviceCollection = new ServiceCollection();
serviceCollection.AddLogging(builder =>
{
    builder.AddConsole(options =>
    {
        // Use your custom formatter
        options.FormatterName = "CustomFormatter";
    })
    .AddConsoleFormatter<CustomConsoleFormatter>();
});

Step 4: Configure Log Filtering for Custom Levels

When setting up log filters (either via code or config), you can reference your custom levels by their numeric value or map them in your config. For example, in appsettings.json:

{
  "Logging": {
    "LogLevel": {
      "Default": "Information",
      "YourAppNamespace": "6" // Allow Verbose level logs from your namespace
    },
    "Console": {
      "LogLevel": {
        "YourAppNamespace.Audit": "7" // Only show Audit logs from this sub-namespace
      }
    }
  }
}

If you prefer using names in config, you can add a custom configuration provider or map the names to numeric values in code during setup.

Step 5: Support Custom Levels in Your Custom Log Provider

Since you’re building a custom log provider for multi-target output, make sure it checks for your custom levels. For example, in your provider’s log processing logic:

public void Log<TState>(LogEntry<TState> logEntry)
{
    var customLevel = (CustomLogLevel)(int)logEntry.LogLevel;
    switch (customLevel)
    {
        case CustomLogLevel.Verbose:
            // Handle Verbose logs (e.g., write to a detailed trace file)
            break;
        case CustomLogLevel.Audit:
            // Handle Audit logs (e.g., write to a dedicated audit database)
            break;
        // Handle default levels
        default:
            // Process Trace/Debug/Info etc.
            break;
    }
}

Key Notes for .NET Framework

  • Make sure you’ve installed the necessary NuGet packages: Microsoft.Extensions.Logging, Microsoft.Extensions.Logging.Console, and Microsoft.Extensions.DependencyInjection (for dependency injection setup).
  • If your legacy app doesn’t use DI, you can still create a logger factory manually instead of using service collection.

This approach lets you leverage the full power of Microsoft.Extensions.Logging while preserving all the custom log levels from your original system. Test each level thoroughly to ensure logs are routed correctly to your multiple output targets!

内容的提问来源于stack exchange,提问作者Julian

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.15 04:18:24