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

自定义ILogger Provider读取appSettings.json配置失败问题咨询

自定义ILoggerProvider配置失效问题排查与修复

问题1:appSettings.json配置无法传入Provider构造函数

原因分析

你的FileLoggerProvider第二个构造函数中硬编码覆盖了配置值,导致配置文件的设置被强行替换:

public FileLoggerProvider(FileLoggerOptions options)
{
    options.Path = "C:/temp/log-{yyyy-MM-dd}.txt"; // 此行直接覆盖配置文件的Path值
    _options = options;
}

当通过IOptionsMonitor<FileLoggerOptions>注入时,会调用该构造函数,配置文件中Logging:File:Path的设置完全失效。

修复方案

删除硬编码覆盖的代码,保留构造函数对传入选项的赋值:

public FileLoggerProvider(FileLoggerOptions options)
{
    _options = options;
}

问题2:专属LogLevel设置被忽略

原因分析

日志系统的Provider专属LogLevel生效需要两个前提:

  1. 配置节点名称与Provider标识匹配(你的File节点与FileLoggerProvider自动生成的标识一致,这部分没问题);
  2. 自定义ILogger必须正确读取日志系统的过滤规则,在IsEnabled方法中判断是否输出日志。

你当前的代码仅处理了Provider的配置注入,但未让自定义Logger集成日志系统的LogLevel过滤逻辑,导致Logging:File:LogLevel的设置被忽略。

修复方案

步骤1:修改FileLoggerProvider,注入ILoggerFactory获取过滤规则

在Provider中注入ILoggerFactory,复用系统内置的过滤逻辑:

public class FileLoggerProvider : ILoggerProvider
{
    private readonly FileLoggerOptions _options;
    private readonly ILoggerFactory _loggerFactory;
    private IDisposable? _settingsChangeToken;

    public FileLoggerProvider(IOptionsMonitor<FileLoggerOptions> options, ILoggerFactory loggerFactory)
        : this(options.CurrentValue, loggerFactory)
    {
        _settingsChangeToken = options.OnChange(opt => { _options = opt; });
    }

    public FileLoggerProvider(FileLoggerOptions options, ILoggerFactory loggerFactory)
    {
        _options = options;
        _loggerFactory = loggerFactory;
    }

    public ILogger CreateLogger(string categoryName)
    {
        return new FileLogger(categoryName, _options, _loggerFactory);
    }

    public void Dispose()
    {
        _settingsChangeToken?.Dispose();
    }
}

步骤2:实现FileLogger的IsEnabled方法,应用过滤规则

public class FileLogger : ILogger
{
    private readonly string _categoryName;
    private readonly FileLoggerOptions _options;
    private readonly ILoggerFactory _loggerFactory;

    public FileLogger(string categoryName, FileLoggerOptions options, ILoggerFactory loggerFactory)
    {
        _categoryName = categoryName;
        _options = options;
        _loggerFactory = loggerFactory;
    }

    public bool IsEnabled(LogLevel logLevel)
    {
        // 复用系统过滤逻辑,判断当前日志级别是否符合配置
        return _loggerFactory.CreateLogger(_categoryName).IsEnabled(logLevel);
    }

    public void Log<TState>(LogLevel logLevel, EventId eventId, TState state, Exception? exception, Func<TState, Exception?, string> formatter)
    {
        if (!IsEnabled(logLevel)) return;

        // 实现你的文件写入逻辑
        var logMessage = formatter(state, exception);
        File.AppendAllText(_options.Path ?? string.Empty, $"{DateTime.Now:yyyy-MM-dd HH:mm:ss} [{logLevel}] {_categoryName}: {logMessage}{Environment.NewLine}");
    }

    public IDisposable? BeginScope<TState>(TState state) where TState : notnull
    {
        return null;
    }
}

步骤3:修正注册代码,确保依赖注入完整

调整AddFileLogger扩展方法,保证ILoggerFactory能被正确注入:

public static ILoggingBuilder AddFileLogger(this ILoggingBuilder builder)
{
    builder.AddConfiguration();

    builder.Services.TryAddEnumerable(ServiceDescriptor.Singleton<ILoggerProvider, FileLoggerProvider>(sp =>
    {
        var optionsMonitor = sp.GetRequiredService<IOptionsMonitor<FileLoggerOptions>>();
        var loggerFactory = sp.GetRequiredService<ILoggerFactory>();
        return new FileLoggerProvider(optionsMonitor, loggerFactory);
    }));

    builder.Services.TryAddEnumerable(ServiceDescriptor.Singleton<IConfigureOptions<FileLoggerOptions>, FileLoggerOptionsSetup>());
    builder.Services.TryAddEnumerable(ServiceDescriptor.Singleton<IOptionsChangeTokenSource<FileLoggerOptions>, LoggerProviderOptionsChangeTokenSource<FileLoggerOptions, FileLoggerProvider>>());
    
    return builder;
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.08 19:55:02