C#中的灵活日志界面设计

我想编写自己的Logging类(在C#中),它实现了一个标准接口,我可以从代码的任何部分调用它。

我的想法是让多个Log类实现Logger接口,每个接口都针对其特定的日志目的地,例如,FileLogger将实现日志记录到文件,TextBox记录器将实现登录到Form中的多行TextBox,DBLogger将实现日志记录到数据库表等

此外,每个记录器类可以具有嵌套的记录器或链式记录器类,因此从应用程序代码单次调用Log()方法可以在多个目的地中记录消息; 示例在单个调用中记录到Form上的文件和文本框。

我面临的困难是:

通常我会记录一个正在运行的日志文件(其中包含调试所需的所有日志消息),一个审阅日志文件(其中只包含要由用户审阅的日志消息,或需要用户操作的日志消息),多行文本框屏幕(将复制所有日志消息以向用户提供进度指示),以及另一个多行文本框(将仅记录用户要查看的消息)。

当我调用logger.Log(消息)时,某些消息可能不适用于特定的日志目标。 例如,某些消息可能仅记录在正在运行的日志文件或进度文本框中,但不会记录在用户评论文本框中,反之亦然。

由于记录器将被链接以便单个函数调用可以登录到所有必需的目标,因此特定记录器如何识别日志消息不适用于它并因此忽略日志消息?

我的示例日志界面是:

public interface Logger { public void Log(string msg); public void Log(string msgType, string msg); public void InitLogSession(); public void EndLogSession(); public void AddLogger(Logger chainedLogger); public void RemoveLogger(Logger chainedLogger); } public class FileLogger : Logger { //implement methods } public class TextBoxLogger : Logger { //implement methods } public class DBLogger : Logger { //implement methods } 

编辑1:

更准确地说,可能有4个记录器:2个文件记录器和2个文本框记录器。 假设一个特定的消息用于1个文本框记录器和1个文件记录器; 我的设计应如何处理?

编辑2:请不要建议现有的日志框架。 我只是想自己写吧!

编辑3:好的。 我有一个设计。 请提供您的反馈,并填补空白。

修改后的界面:

 public interface Logger { public void Log(string msg); public void Log(string msgType, string msg); public void Log(int loggerIds, string msg); public void Log(int loggerIds, string msgType, string msg); public void InitLogSession(); public void EndLogSession(); public int getLoggerId(); } public enum LoggerType { File, TextBox }; public class LoggerFactory { public Logger getLogger(LoggerType loggerType) { } } 

LoggerFactory类将是实例化记录器的唯一方法。 该类将为记录器的每个实例分配唯一的id。 这个唯一的ID将是2的幂。例如,第一个记录器将获得id 1,第二个将获得id 2,第三个将获得4,第四个将获得8,依此类推。

返回的logger对象可以是特定类的类型转换,调用者可以设置其他值,如filePath,textbox等,否则我可以在LoggerFactory中有多个方法:每种类型的logger一个,它将接受特定的参数。

所以,假设我们有4个带有ID 1,2,4,8的记录器。 必须使用以下函数记录必须由第1和第3记录器(即记录器ID 1和4)处理的特定消息:

  public void Log(int loggerIds, string msg); 

传递给loggerIds的值应为“0101”。 每个记录器将检查其记录器ID位是否为ON。 如果是,则只有它才会记录该消息。

现在在函数签名中,我提到了int类型,但是哪个是用于执行位操作和比较的特定优化类型?

在这种方法中,最大值可能有限制。 记录器,但对我来说没问题。 请提供反馈。

注意:目前我仍然使用.NET 2.0。 如果可能的话,在.NET 2.0中建议解决方案,否则很好,我可以转向更高版本。

这种设计的缺点:每个需要记录的类,需要知道应用程序实例化的所有可用记录器,并相应地设置位模式。 任何想法如何设计松散耦合?

为什么不查看(或确实使用)现有的日志框架,如log4net或NLog 。

它们具有日志级别的概念(例如跟踪,信息,错误等),并且能够按日志名称(通常是调用日志记录调用的完全限定类型名称)进行过滤。 然后,您可以将这些映射到一个或多个“目标”。

正如devdigital所写,这些框架通常通过提供Logging的指定方法来实现这一点:Warn(“…”),Fail(“…”)……

您还可以查找castle项目的日志记录工具的ILogger接口。 (也许尝试谷歌ILogger.cs源代码)

如果您仍然坚持使用具有通用接口的链式记录器(为此您还必须实现链接机制),则必须为Log()方法提供一种日志记录级别。 这可能只是整数或枚举。

像这样:

  public interface Logger { public void Log(LogLevel level, string msg); public void Log(LogLevel level, string msgType, string msg); public void InitLogSession(); public void EndLogSession(); public void AddLogger(Logger chainedLogger); public void RemoveLogger(Logger chainedLogger); } 

使用这样的日志级别枚举:

 public enum LogLevel { Info, Warn, Debug, Error, Fail } 

然后在责任链中选择要使用的记录器。

我不久前写了自己的记录器。 说实话,它不如免费提供的那么好,我意识到我正试图重新发明一个已经圆的轮子!

我看到你想编写自己的代码但是查看开源解决方案可能仍然是一个想法,也许可以使用它们或根据自己的特定需求修改它们

我现在使用TracerX: http : //www.codeproject.com/Articles/23424/TracerX-Logger-and-Viewer-for-NET这是一个开源项目,因此很容易修改你需要的源代码。 提到的其他伐木工人当然也很好。

编辑

这是基于我在这里接受的问题答案: 如何在松散耦合的应用程序中将状态信息传递给GUI所以我声称没有原创性。 我想,你的日志信息很简单

我建议的答案是你使用的消息类型可以根据运行时传递给它的一些逻辑或者根据运行时条件使用工厂创建不同的消息类型来处理(例如)将自身发送到不同的记录器。

所以

  1. 创建一个具有流程方法的抽象消息类或接口。
  2. 创建从抽象类或接口inheritance的许多消息类型,这些消息类型表示要执行的不同类型的日志记录。 处理方法可以确定将它们发送到何处。
  3. 考虑使用工厂在运行时创建所需的消息类型,这样您就无需事先确定需要的类型
  4. 生成日志消息时,请使用进程消息将消息路由到您希望它转到的记录器

这似乎是使用扩展方法的好地方。

创建基类 ,然后为其创建扩展方法

 BaseLogger(LogMessage).toTextBoxLog().toFileLog().toDatabaseLog(). 

这样,您总是调用BaseLogger ,然后只调用扩展方法

“请不要建议现有的日志记录框架。我只想自己编写它!”

接受的答案:不要重新发明轮子! 使用此现有的日志框架!

捂脸

最好的答案,就是我的回答,就是这样的。 如果需要即插即用function,请使用接口。 您可以轻松配置它。 这是高水平的下降。

  1. 使用配置文件指示实现日志记录界面所需的记录器类型

  2. 使用reflection来实例化您从配置文件AT RUNTIME中提取的类型。

  3. 通过类中的构造函数注入传入刚刚创建的logger接口。

你不是通过界面设计重新发明轮子。 如果你使你的界面足够通用,那么它是非特定的实现(理想情况下)。 这意味着如果log4net变为废话,或者不再受支持,则不必RIP OUT和修改所有调用代码 。 这就像将灯直接连接到您家中以将其打开一样。 为了上帝的爱,请不要这样做。 接口定义组件交互的合同,而不是实现。

我唯一能想到的是,查看现有的日志框架,找到共同的元素,并将您的界面编写为常见function的交集。 显然,你会错过任何function。 这取决于你想要多少灵活性。 您可以使用Log4net或Microsoft Event Viewer记录器,或两者兼而有之! 没有重新实施实施细节。 与代码中的所有内容绑定到一个技术/框架相比,它是一个耦合较少的系统。