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

WPF(Prism8)中如何用Serilog实现运行时动态子日志配置?

用Serilog在WPF Prism 8中实现动态多项目日志记录

核心思路

完全可以通过Serilog的子日志(Logger.ForContext)结合动态Sink管理实现需求:

  • 根日志负责记录全局应用信息(异常、关键操作)到固定的应用日志文件
  • 为每个项目创建独立的子日志实例,绑定对应的项目日志文件,通过上下文标记区分项目,实现同时写入根日志和激活的项目日志

具体实现步骤

1. 初始化根日志(应用全局日志)

在Prism的App.xaml.cs中初始化根日志,负责记录所有应用级信息:

public partial class App : PrismApplication
{
    protected override void OnStartup(StartupEventArgs e)
    {
        // 初始化根日志
        Log.Logger = new LoggerConfiguration()
            .MinimumLevel.Information()
            .WriteTo.File(
                path: @"C:\Logs\AppLog-.txt",
                rollingInterval: RollingInterval.Day,
                retainedFileCountLimit: 30,
                outputTemplate: "{Timestamp:yyyy-MM-dd HH:mm:ss.fff zzz} [{Level:u3}] {Message:lj}{NewLine}{Exception}"
            )
            .CreateLogger();

        base.OnStartup(e);
    }

    protected override void OnExit(ExitEventArgs e)
    {
        Log.CloseAndFlush();
        base.OnExit(e);
    }
}

2. 封装项目日志管理类

创建单例的ProjectLogManager,管理所有项目的子日志实例并跟踪当前激活项目:

public class ProjectLogManager
{
    private readonly Dictionary<string, ILogger> _projectLoggers = new();
    private string _activeProjectId;

    // 获取当前激活的项目日志(若存在)
    public ILogger ActiveProjectLogger => _activeProjectId != null && _projectLoggers.TryGetValue(_activeProjectId, out var logger) 
        ? logger 
        : null;

    // 创建或获取项目日志实例
    public ILogger GetOrCreateProjectLogger(string projectId, string projectLogFilePath)
    {
        if (_projectLoggers.TryGetValue(projectId, out var existingLogger))
            return existingLogger;

        // 创建绑定项目文件的子日志,继承根日志配置
        var projectLogger = Log.Logger.ForContext("ProjectId", projectId)
            .WriteTo.File(
                path: projectLogFilePath,
                rollingInterval: RollingInterval.Day,
                retainedFileCountLimit: 10,
                outputTemplate: "{Timestamp:yyyy-MM-dd HH:mm:ss.fff zzz} [{Level:u3}] {Message:lj}{NewLine}{Exception}"
            )
            .CreateLogger();

        _projectLoggers.Add(projectId, projectLogger);
        return projectLogger;
    }

    // 设置当前激活项目
    public void SetActiveProject(string projectId)
    {
        _activeProjectId = projectId;
    }

    // 移除项目日志(项目关闭时清理)
    public void RemoveProjectLogger(string projectId)
    {
        if (_projectLoggers.TryGetValue(projectId, out var logger))
        {
            logger.Dispose();
            _projectLoggers.Remove(projectId);
            if (_activeProjectId == projectId)
                _activeProjectId = null;
        }
    }
}

3. 在Prism中注入日志管理器

在Prism的容器注册中,将ProjectLogManager注册为单例:

protected override void RegisterTypes(IContainerRegistry containerRegistry)
{
    containerRegistry.RegisterSingleton<ProjectLogManager>();
    // 其他服务注册...
}

4. 业务代码中使用日志

在ViewModel或服务中注入ProjectLogManager,同时记录到根日志和激活项目日志:

public class ProjectViewModel : BindableBase
{
    private readonly ILogger _rootLogger;
    private readonly ProjectLogManager _logManager;

    public ProjectViewModel(ILogger rootLogger, ProjectLogManager logManager)
    {
        _rootLogger = rootLogger;
        _logManager = logManager;
    }

    // 打开项目时创建并激活日志
    public void OpenProject(string projectId, string projectFolder)
    {
        var logFilePath = Path.Combine(projectFolder, $"ProjectLog-.txt");
        _logManager.GetOrCreateProjectLogger(projectId, logFilePath);
        _logManager.SetActiveProject(projectId);

        var message = $"项目 {projectId} 已激活";
        _rootLogger.Information(message);
        _logManager.ActiveProjectLogger?.Information(message);
    }

    // 处理项目文件时记录日志
    public void ProcessProjectFile(string fileName)
    {
        try
        {
            // 业务操作逻辑...
            var message = $"成功处理文件: {fileName}";
            _rootLogger.Information(message);
            _logManager.ActiveProjectLogger?.Information(message);
        }
        catch (Exception ex)
        {
            var errorMsg = $"处理文件 {fileName} 失败";
            _rootLogger.Error(ex, errorMsg);
            _logManager.ActiveProjectLogger?.Error(ex, errorMsg);
        }
    }

    // 关闭项目时清理日志
    public void CloseProject(string projectId)
    {
        _logManager.RemoveProjectLogger(projectId);
        _rootLogger.Information($"项目 {projectId} 已关闭");
    }
}

5. 可选:添加项目日志过滤器

如果需要确保项目日志只记录对应项目的内容,可在创建子日志时添加过滤器:

var projectLogger = Log.Logger.ForContext("ProjectId", projectId)
    .Filter.ByIncludingOnly(evt => evt.Properties.ContainsKey("ProjectId") && 
                                  evt.Properties["ProjectId"].ToString() == $"\"{projectId}\"")
    .WriteTo.File(...)
    .CreateLogger();

关键说明

  • 子日志Logger.ForContext会继承根日志的所有配置,同时可添加独立的Sink和过滤器
  • 项目关闭时务必调用RemoveProjectLogger清理资源,避免内存泄漏
  • 切换激活项目只需调用SetActiveProject,后续日志会自动写入新的项目文件

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.29 22:50:13