WPF中如何统一控制日志

在 WPF 应用程序中统一控制日志是一个常见需求,特别是在需要监控应用状态、调试问题或记录用户操作时。以下是实现统一日志控制的几种方法:

  • 使用第三方日志库(推荐)
    推荐库
  • NLog:功能强大,支持多种目标(文件、数据库、控制台等)和配置方式。
  • Serilog:结构化日志记录,与ASP.NET Core 集成良好。
  • log4net:经典日志库,配置灵活。

示例:使用 NLog

  • 安装包:
Install-Package NLog
Install-Package NLog.Config
  • 配置 NLog(NLog.config):
<?xml version="1.0" encoding="utf-8" ?>
<nlog xmlns="http://www.nlog-project.org/schemas/NLog.xsd"
      xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
  <targets>
    <target name="logfile" xsi:type="File" fileName="log.txt" />
    <target name="logconsole" xsi:type="Console" />
  </targets>
  <rules>
    <logger name="*" minlevel="Debug" writeTo="logfile,logconsole" />
  </rules>
</nlog>
  • 在 App.xaml.cs 中初始化:
public partial class App : Application
{
    private static readonly NLog.Logger Logger = NLog.LogManager.GetCurrentClassLogger();
    
    protected override void OnStartup(StartupEventArgs e)
    {
        try
        {
            // 应用程序启动逻辑
            Logger.Info("Application started");
            base.OnStartup(e);
        }
        catch (Exception ex)
        {
            Logger.Fatal(ex, "Application startup failed");
            throw;
        }
    }
    
    protected override void OnExit(ExitEventArgs e)
    {
        Logger.Info("Application exited");
        NLog.LogManager.Shutdown(); // 确保日志完全写入
        base.OnExit(e);
    }
}
  • 在 ViewModel 或 Service 中使用:
public class MainViewModel
{
    private readonly NLog.Logger _logger = NLog.LogManager.GetCurrentClassLogger();
    
    public void SaveData()
    {
        try
        {
            _logger.Debug("Saving data...");
            // 业务逻辑
            _logger.Info("Data saved successfully");
        }
        catch (Exception ex)
        {
            _logger.Error(ex, "Failed to save data");
        }
    }
}
  1. 自定义日志服务(轻量级方案)
    如果你不想引入第三方库,可以创建一个简单的单例日志服务:
public class LoggerService
{
    private static readonly Lazy<LoggerService> _instance = 
        new Lazy<LoggerService>(() => new LoggerService());
    
    public static LoggerService Instance => _instance.Value;
    
    private readonly string _logFilePath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "app.log");
    private readonly object _lockObject = new object();
    
    private LoggerService() { }
    
    public void Log(string message, LogLevel level = LogLevel.Info)
    {
        var logEntry = $"[{DateTime.Now:yyyy-MM-dd HH:mm:ss}] [{level}] {message}";
        
        // 写入文件
        lock (_lockObject)
        {
            try
            {
                File.AppendAllLines(_logFilePath, new[] { logEntry });
            }
            catch (Exception ex)
            {
                // 日志写入失败的处理
                Console.WriteLine($"Failed to write log: {ex.Message}");
            }
        }
        
        // 也可以同时输出到控制台
        Console.WriteLine(logEntry);
    }
    
    public void Debug(string message) => Log(message, LogLevel.Debug);
    public void Info(string message) => Log(message, LogLevel.Info);
    public void Warning(string message) => Log(message, LogLevel.Warning);
    public void Error(string message, Exception ex = null)
    {
        var errorMessage = ex != null ? $"{message} - {ex}" : message;
        Log(errorMessage, LogLevel.Error);
    }
}

public enum LogLevel
{
    Debug,
    Info,
    Warning,
    Error,
    Fatal
}

使用方式:

// 在App.xaml.cs中初始化
public partial class App : Application
{
    protected override void OnStartup(StartupEventArgs e)
    {
        LoggerService.Instance.Info("Application started");
        base.OnStartup(e);
    }
}

// 在其他地方使用
public class MainViewModel
{
    public void DoSomething()
    {
        LoggerService.Instance.Info("Doing something...");
        try
        {
            // 业务逻辑
        }
        catch (Exception ex)
        {
            LoggerService.Instance.Error("Operation failed", ex);
        }
    }
}
  1. 在 UI 中显示实时日志(可选)
    如果你需要在 WPF 界面中实时显示日志,可以创建一个日志视图:
<!-- MainWindow.xaml -->
<Window x:Class="WpfApp1.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        Title="MainWindow" Height="450" Width="800">
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="*"/>
            <RowDefinition Height="200"/>
        </Grid.RowDefinitions>
        
        <!-- 主内容区域 -->
        <Button Content="Do Something" Command="{Binding DoSomethingCommand}" 
                HorizontalAlignment="Center" VerticalAlignment="Center"/>
        
        <!-- 日志显示区域 -->
        <TextBox Grid.Row="1" Text="{Binding LogText, UpdateSourceTrigger=PropertyChanged}" 
                 IsReadOnly="True" AcceptsReturn="True" VerticalScrollBarVisibility="Auto"/>
    </Grid>
</Window>
// MainViewModel.cs
public class MainViewModel : INotifyPropertyChanged
{
    private readonly StringBuilder _logBuilder = new StringBuilder();
    private string _logText;
    
    public string LogText
    {
        get => _logText;
        set
        {
            _logText = value;
            OnPropertyChanged(nameof(LogText));
        }
    }
    
    public ICommand DoSomethingCommand { get; }
    
    public MainViewModel()
    {
        DoSomethingCommand = new RelayCommand(DoSomething);
        
        // 注册日志事件(使用NLog或自定义服务)
        LoggerService.Instance.Logged += OnLogged;
    }
    
    private void OnLogged(string message)
    {
        // 在UI线程更新日志
        Application.Current.Dispatcher.Invoke(() =>
        {
            _logBuilder.AppendLine(message);
            LogText = _logBuilder.ToString();
        });
    }
    
    private void DoSomething()
    {
        LoggerService.Instance.Info("Button clicked");
        // 业务逻辑
    }
    
    public event PropertyChangedEventHandler PropertyChanged;
    protected virtual void OnPropertyChanged(string propertyName)
    {
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
    }
}
  • 配置日志级别和目标
    无论是使用第三方库还是自定义服务,都建议支持动态配置:
  • 日志级别:控制记录哪些级别的日志(Debug、Info、Warning 等)。
  • 日志目标:决定日志输出到文件、数据库、控制台还是 UI 界面。
    例如,在 NLog 中可以通过修改配置文件动态调整日志行为,无需重新编译代码。

总结
推荐使用第三方日志库(如 NLog),因为它们提供了更完善的功能和更好的性能。对于简单应用,自定义日志服务也是一个不错的选择。实时日志显示可以帮助调试和监控应用状态,但要注意性能问题(特别是频繁写入时)。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值