log4net:如何自定义要存储的数据

时间:2010-11-29 21:57:22

标签: logging log4net

我的网站提供的网络服务很少。这是我想达到的目标:

  1. 将所有数据存储在一个表中的数据库中;
  2. 每条记录都应包含带有“服务/组件”名称的文本字段;
  3. 在调用任何方法时,必须存储所有收入参数;
  4. 如果发生任何异常,则必须存储所有结果参数和错误消息。
  5. 我的初衷是使用log4net。但是从这些演练(http://sadi02.wordpress.com/2008/09/15/how-to-store-log-in-database-using-log4net/, http://logging.apache.org/log4net/release/config-examples.html)我不知道查看将自定义数据添加到日志表中的简单方法。

    将log4net用于此类目的是否可行?如何更改日志表架构以存储自定义数据?我应该修改log4net库的源代码吗?编写自定义功能来存储这类数据可能会更好吗?

    感谢。

3 个答案:

答案 0 :(得分:14)

根据这个discussion,这个过程非常简单。

第一步是将appender声明中的命令文本更新到配置文件中:

<commandText value="INSERT INTO Log4Net ([Date],[Thread],[Level],[Logger],[Message],[Exception],[MyColumn]) VALUES (@log_date, @thread, @log_level, @logger, @message, @exception,@MyColumn)"/>        

下一步是为自定义列添加新的参数定义:

<parameter>
   <parameterName value="@MyColumn "/>
   <dbType value="String" />
   <size value="255" />
   <layout type="log4net.Layout.PatternLayout">
      <conversionPattern value="%property{MyColumn}" />
   </layout>
</parameter>

最后,您可以通过log4net的GlobalContext属性访问该值:

log4net.GlobalContext.Properties["MyColumn"] = "MyValue";
log.Debug("My message");

您可以根据需要为多个字段执行此操作。

答案 1 :(得分:2)

建议的答案都不适合我。问题是我需要有几个自定义字段。对我来说,创建不同的记录器实例或每次通过'属性'设置列值似乎太复杂了。

我将(实际上已经实现)将数据放入数据库的自定义记录器。

答案 2 :(得分:1)

查看log4net文档,您能想出如何将自定义数据记录到文件中吗?如果是这样,您还应该能够将相同的数据记录到数据库中。只需在表格中添加更多列,在AdoNetAppender的<command text>节点中添加更多列,以及更多<parameter>个节点。

我认为您需要做一些工作来记录传入和传出的参数。你需要他们登录在单独的列中(可能不容易干净)?如果它们与消息一起记录是否可以?

例如,如果您要将以下方法放入登录:

public void DoSomething(int x, int y)
{
  log.Info("Inside DoSomething");
}

您希望输出看起来像什么?您是否希望“标准”log4net信息显示在单独的列中(时间戳,记录器名称,级别,消息)?参数怎么样? x和y应该出现在不同的列中(除非每个方法都有相同数量的参数,否则可能不是很容易)或者如果参数记录如下就可以了:

public void DoSomething(int x, int y)
{
  ILog log = LogManager.GetLogger("abc");
  log.InfoFormat("Parameters: x = {0}, y = {1}", x, y);
  log.Info("Inside DoSomething");
}

日志语句将生成如下所示的消息:

11/29/2010 16:36:00 | abc | INFO | Parameters: x = 10, y = 20
11/29/2010 16:36:00 | abc | INFO | Inside DoSomething

我用过|字符,用于显示带有时间戳,loggername,日志级别和消息的模式布局的字段。

查看像PostSharp这样的AOP解决方案可能对您有所帮助,因为您可以相对轻松地添加进入/退出日志记录,而无需使用日志记录语句“污染”您的应用程序源代码。在日志“方面”内部,您可以访问该方法的参数。

我可能会遗漏一些东西,但我怀疑如果你想将你的方法参数作为数据库中的单个列维护,那么你会发现很难做到。如果您对将每个方法的所有参数(手动)组合为单个列(本质上是格式化的字符串)感到满意,那么这将更容易。您必须支付的一个价格是您必须明确记录所有参数(除非您使用AOP路线)。

如果您正在考虑使用log4net,您还应该考虑使用NLog。它不一定会帮助你解决我上面描述的问题,但我认为它是log4net的一个有价值的竞争对手。

[编辑]

要获取log4net记录的“组件名称”,您应该为组件命名记录器。当您调用LogManager.GetLogger(名称)时,您可以传递任何名称(或类型)。一个常见的模式是在每个类中都有这样的代码:

public class MyClass
{
  private static readonly ILog logger = LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);

  public void DoSomething(int x)
  {
    logger.InfoFormat("Inside DoSomething.  x = {0}", x);
  }
}

这将获得一个以完全限定的类名(命名空间+类名)命名的记录器。如果你在每个类中都这样做,那么你可以控制每个类的日志记录(级别,它进入哪个appender等)。因此,您可以轻松地将Class1的日志记录转换为Info并记录Class2 Off等。这使您可以最大程度地控制日志记录。

现在,在您的配置文件中,您没有义务明确列出每个记录器(即每个完全限定的类名)。您可以只配置根记录器,然后这些设置将应用于每个记录器。您可以通过命名空间控制日志记录。例如,如果您使用CompanyX并且您具有明确的命名空间规则,则您的命名空间可能如下所示:

CompanyX
CompanyX.DataAccess
CompanyX.DataAccess.Read
CompanyX.DataAccess.Write
CompanyX.GUI
CompanyX.Forms
CompanyX.Controls

在每个命名空间中,您可能有各种类(如几个不同的数据读取器,辅助类,数据编写器等)。对于像这样组织的类,并且您的类如上所述获取记录器,您可以轻松地为CompanyX中的所有类或CompanyX.DataAccess或CompanyX.DataAccess.Read等中的所有记录器配置日志记录。您甚至可以关闭所有日志记录,但是为那个给你带来麻烦的麻烦课程打开它。

您还可以通过任意名称获取记录器(例如,如果您不想使用,则不必使用类名)。您可以在应用程序中定义功能区域,并根据以下内容获取记录器:

ILog logger = LogManager.GetLogger("DataAccess");
ILog logger = LogManager.GetLogger("Performance");
ILog logger = LogManager.GetLogger("UI");

等等。我没有看到这比使用完全限定的类名有很多好处。如果您的命名空间组织良好,那么您配置日志记录的能力将具有最大的灵活性,而您只需付出最小的努力。

NLog上的另一个词...... NLog与log4net非常相似。它确实具有能够自动返回当前类的记录器的有用功能:

Logger logger = NLog.LogManager.GetCurrentClassLogger();

这至少可以节省一些打字。 NLog刚刚发布了一个新版本(目前处于测试阶段)。

不知道是否有任何帮助,但我希望它能做到!

祝你好运!