C# 将日志记录作为我的域模型的一部分
我正在编写一个应用程序,其中日志记录是我实际域模型的一部分。它是一个自动化和批处理工具,最终用户将能够查看实际应用程序中批处理作业的日志,而不仅仅是文本日志文件 因此,我的域模型包括一个C# 将日志记录作为我的域模型的一部分,c#,logging,nlog,error-logging,C#,Logging,Nlog,Error Logging,我正在编写一个应用程序,其中日志记录是我实际域模型的一部分。它是一个自动化和批处理工具,最终用户将能够查看实际应用程序中批处理作业的日志,而不仅仅是文本日志文件 因此,我的域模型包括一个LogMessage类: public sealed class LogMessage { public string Message { get; } public DateTime TimestampUtc { get; } public LogLevel Level { get; }
LogMessage
类:
public sealed class LogMessage
{
public string Message { get; }
public DateTime TimestampUtc { get; }
public LogLevel Level { get; }
}
public enum LogLevel
{
Fatal = 5,
Error = 4,
Warn = 3,
Info = 2,
Debug = 1,
Trace = 0
}
我还有一个Result
类,它的集合属性为LogMessages
。最终用户可以使用“我的应用程序”将结果保存到文件并从中打开
public class Result
{
public bool Succeeded {get; set;}
public string StatusMessage {get; set;}
public IList<LogMessage> LogMessages {get; set;}
}
我向写入Result.LogMessages
的插件提供了ILogger
的实例
public interface IPlugIn
{
Output DoSomeThing(Input in, ILogger logger);
}
显然,我也希望能够从自己的内部代码登录,并最终希望Result.LogMessages
包含我的内部日志消息和来自插件的日志消息。因此,有问题的最终用户可以向我发送一个结果文件,其中包含来自我的内部代码和使用的任何插件的调试日志
目前,我有一个使用自定义NLog目标的解决方案
public class LogResultTarget : NLog.Targets.Target
{
public static Result CurrentTargetResult { get; set; }
protected override void Write(NLog.LogEventInfo logEvent)
{
if (CurrentTargetResult != null)
{
//Convert NLog logEvent to LogMessage
LogLevel level = (LogLevel)Enum.Parse(typeof(LogLevel), logEvent.Level.Name);
LogMessage lm = new LogMessage(logEvent.TimeStamp.ToUniversalTime(), level, logEvent.Message);
CurrentTargetResult.LogMessages.Add(lm);
}
}
protected override void Write(NLog.Common.AsyncLogEventInfo logEvent)
{
Write(logEvent.LogEvent);
}
}
此类将消息转发到分配给静态LogResultTarget.CurrentTargetResult
属性的结果。我的内部代码记录到NLog记录器,我有一个ILogger
的实现,它也记录到一个NLog.Logger
这是工作,但感觉真的很脆弱。如果CurrentTargetResult
未正确设置或未设置回null,则最终会将日志消息存储到它们不适用的结果中。另外,因为只有一个静态的CurrentTargetResult
,所以我无法支持同时处理多个结果
我有没有其他/更好的方法来解决这个问题?或者我试图做的根本错误吗?我认为你的方法是正确的,但是你可以通过使用一个已经为你做了这个抽象的库来节省精力。图书馆就是你要找的
您的域代码将仅依赖于公共日志中的ILogger
接口。只有当您的域被运行时(例如Web API)使用时,您才能配置要使用的日志记录提供程序
有许多预构建的提供程序作为单独的nuget软件包提供:
Common.Logging提供的适配器支持.NET中以下所有流行的日志目标/框架:
- Log4Net(v1.2.9-v1.2.15)
- NLog(v1.0-v4.4.1)
- SeriLog(v1.5.14)
- Microsoft企业库日志记录应用程序块(v3.1-v6.0)
- Microsoft AppInsights(2.4.0)
- Microsoft Windows事件跟踪(ETW)
- 登录到标准输出
- 登录以进行调试
我已经使用它很多年了,能够在另一个上下文中重用域/库代码非常好,但不必对日志框架有固定的依赖性(我已经从企业库转移到log4net,最后是NLog…这是一件轻而易举的事).在我看来,静态
CurrentTargetResult确实有点脆弱,但总体方法还不错
我建议作出以下修改:
取消对CurrentTargetResult的静态设置,并始终将其初始化
大概是这样的:
公共类LogResultTarget:NLog.Targets.Target
{
公共结果CurrentTargetResult{get;}=新结果();
受保护的重写无效写入(NLog.LogEventInfo logEvent)
{
//将NLog logEvent转换为LogMessage
LogLevel=(LogLevel)Enum.Parse(typeof(LogLevel),logEvent.level.Name);
LogMessage lm=新的LogMessage(logEvent.TimeStamp.ToUniversalTime(),级别,logEvent.Message);
CurrentTargetResult.LogMessages.Add(lm);
}
受保护的重写无效写入(NLog.Common.AsyncLogEventInfo logEvent)
{
写入(logEvent.logEvent);
}
}
始终初始化日志消息:
公共类结果
{
公共布尔成功{get;set;}
公共字符串状态消息{get;set;}
公共IList日志消息{get;set;}=new List();
}
在需要时通过以下调用检索消息:
//按名称查找目标
var logresultarget1=LogManager.Configuration.FindTargetByName(“target1”);
var结果=logResultTarget1.CurrentTargetResult;
//或多个目标
var logresultargets=LogManager.Configuration.AllTargets.OfType();
var allResults=logresultargets.Select(t=>t.CurrentTargetResult);
PS:您也可以在LogResultTarget
中覆盖InitializeTarget
以初始化目标我不完全理解CurrentTargetResult
属性,它没有在您当前的目标中使用?(只有空检查?)结果的确切外观是什么样的?Result
类型的外观是什么样的?啊,看起来我的示例代码中有一个输入错误,我用了“Target”而不是“CurrentTargetResult”。我还添加了一个“Result”类的示例。这有帮助吗?是的,添加了一个答案:)
public class LogResultTarget : NLog.Targets.Target
{
public static Result CurrentTargetResult { get; set; }
protected override void Write(NLog.LogEventInfo logEvent)
{
if (CurrentTargetResult != null)
{
//Convert NLog logEvent to LogMessage
LogLevel level = (LogLevel)Enum.Parse(typeof(LogLevel), logEvent.Level.Name);
LogMessage lm = new LogMessage(logEvent.TimeStamp.ToUniversalTime(), level, logEvent.Message);
CurrentTargetResult.LogMessages.Add(lm);
}
}
protected override void Write(NLog.Common.AsyncLogEventInfo logEvent)
{
Write(logEvent.LogEvent);
}
}