在工作中,有个WPF项目已经完成且已交付使用,但是在二开时新增一个需求:在把日志输出到日志文件功能不变的情况下,再把Error、Warn、Info级别的日志输出到日志查看界面。
在接到这个需求时,一开始我想的是自己封装一个日志工具,再修改需要记录日志的代码。但后来想到这是一个中大型的项目,每个日志记录的地方都要修改。工作量太大且会有很多遗漏的地方。所以在博客园等网站上寻求帮助,但是没找到符合的解决方法。后来在翻看Nlog的日志调用相关代码时发现可以自定义一个TargetWithLayout,实现自己业务需求。
记录一下实现的过程
一、先创建一个CallbackTarget类,继承于NLog的TargetWithLayout,里面增加一个LogCallback的委托,用于处理记录日志后的相关功能。具体代码如下
[Target("CallbackTarget")]
public class CallbackTarget : TargetWithLayout
{
public static Action<LogEventInfo> LogCallback { get; set; }
public static View.LogInfo FrmLogInfo { get; set; }
protected override void Write(LogEventInfo logEvent)
{
// 记录日志
base.Write(logEvent);
// 执行某个方法
LogCallback?.Invoke(logEvent);
}
}
二、在项目启动类APP中添加处理CallbackTarget自定义的规则
/// <summary>
/// App.xaml 的交互逻辑
/// </summary>
public partial class App : Application
{
public App()
{
// 加载注册NLog
AddNLogRules();
}
/// <summary>
/// 添加日志规则
/// </summary>
private void AddNLogRules()
{
LogManager.LoadConfiguration("NLog.config");
// 这里可以添加自定义规则
var config = LogManager.Configuration;
// 创建自定义目标
var customTarget = new CallbackTarget
{
Layout = "${longdate} ${level} ${message}"
};
config.AddRule(LogLevel.Info, LogLevel.Error, customTarget);
// 应用新的配置
LogManager.ReconfigExistingLoggers();
}
}
三,在日志显示界面使用
public class LogInfoViewModel
{
public View.LogInfo frmLogInfo;
public LogInfoViewModel()
{
CallbackTarget.LogCallback = (logEvent) =>
{
if (string.IsNullOrWhiteSpace(logEvent?.Level?.Name))
{
OrtherLog(logEvent.Message);
return;
}
switch (logEvent.Level.Name)
{
case "Info":
{
var msg = $"{logEvent.TimeStamp:yyyy-MM-dd HH:mm:ss.fff} - 信息:{logEvent.Message}";
InfoLog(msg);
}
break;
case "Warn":
{
var msg = $"{logEvent.TimeStamp:yyyy-MM-dd HH:mm:ss.fff} - 警告:{logEvent.Message}";
WarnLog(msg);
}
break;
case "Error":
{
var msg = $"{logEvent.TimeStamp:yyyy-MM-dd HH:mm:ss.fff} - 错误:{logEvent.Message}";
ErrorLog(msg);
}
break;
default:
{
var msg = $"{logEvent.TimeStamp:yyyy-MM-dd HH:mm:ss.fff} - 信息:{logEvent.Message}";
OrtherLog(msg);
}
break;
}
};
}
public void Log(string message, Color color)
{
Application.Current?.Dispatcher?.Invoke(() =>
{
Paragraph paragraph = new Paragraph()
{
LineHeight = 12
};
Run run = new Run(message);
run.Foreground = new SolidColorBrush(color);
paragraph.Inlines.Add(run);
frmLogInfo.rtbLog.Document.Blocks.Add(paragraph);
});
}
public void OrtherLog(string message)
{
Log(message, Colors.White);
}
public void ErrorLog(string message)
{
Log(message, Colors.Red);
}
public void WarnLog(string message)
{
Log(message, Colors.Orange);
}
public void InfoLog(string message)
{
Log(message, Colors.Green);
}
}
四、把项目运行起来就能实现对应的效果

五、结束语:
本篇文章记录的是符合当前项目的需求,只是提供一个思路。CallbackTarget类或者后面的LogCallback委托可以根据自己的需求自定义实现



评论一下吧
取消回复 评论守则