NLog 日志和审计高级目标
一种使用 NLog 审计您的业务对象的方法。
这是对该 API 的一次彻底重构。自上一篇文章以来,发生了很多变化,我将额外努力解释此工具的主要目标。演示项目也得到了极大改进。只需在 NLog.config 文件中配置连接字符串,指向有效的 SQL Server 数据库,即可开始使用。
引言
这是 NLog 的一个自定义目标,允许您跟踪对象上所做的更改。使用此 API,您将能够回答以下问题:
- 谁更改了此对象?
- 何时更改了此对象?
- 它是什么被更改的?(历史列表或特定更改。)
- 我的对象在某个时间点是什么样的?
用法非常简单,只需将对象传递给 NLog,它就会存储自上次以来对其所做的任何更改。
强烈建议您在开始使用此自定义目标之前,仅使用 NLog 进行一次小型测试。
此代码在 NLog 版本 1.0 Refresh 下进行了测试。所有操作都在 VS2010 中完成,但我没有使用任何 .net 4.0 的新功能,因此您可以在 2.0 中顺利编译它。请从以下网址下载 NLog:http://nlog-project.org/download.html。
背景
在开发我的核心模块以作为我所有应用程序的基础起点时,我认为有一个方法可以记录这些应用程序中的某些操作会是个好主意。此外,我还想知道谁在何时更改了一个对象,以及实际更改了什么。为此,我们通常会开发一个历史表,它只不过是原始表的副本,每次对原始表进行更改时,我们将同一行插入历史表中。这样,我们就能够了解一个对象的变化历史……太棒了!:) 但是……实际更改的是什么?如果只更改了一个列还是全部更改了,我们并不立即知道。另一个问题是大小……如果我只更改了一个字段,为什么要复制所有列?另外,如果我给对象添加一个属性,我需要费心更新原始表和历史表之间的复制代码。
它是如何做到的?
使用反射,我可以枚举对象属性并与数据库中已存储的内容进行匹配。
我可能不想自定义对象的每个属性。我能自定义记录什么吗?
当然!这是一个主要要求。您可以通过两种方式做到这一点:
- 将属性应用于对象类和属性。
- 在目标配置中添加要记录的预期类型及其属性。
它将更改保存在哪里?
此版本仅支持 SQL Server,尽管它采用了工厂模式进行开发,允许开发其他数据库提供程序。
查询数据
如果无法获取日志历史记录,所有这些都毫无用处。
所以现在,您可以:
- 获取修改列表
- 获取对象的最新版本
- 获取给定日期的对象版本
使用代码
要记录一个 Customer
类,您只需这样做:
// here 'customer' is the business object I want to log.
NLog.Logger logger = LogManager.GetCurrentClassLogger();
logger.Trace(customer);
如果您想添加**谁**进行了更改,您还需要传递一个 OHAuditInfo
对象来携带额外信息。
// here 'customer' is the business object I want to log.
NLog.Logger logger = LogManager.GetCurrentClassLogger();
logger.Info(string.Empty, customer, new OHAuditInfo() { UserName = "Admin" });
我将向此 OHAuditInfo
对象添加更多字段。
目前,我打算添加:
ActionType
:您可以在其中指定更改的类型(插入、更新、删除等)。ExtraInfo
:自由文本字段,您可以在其中添加任何您想要的内容(文本、XML 等)。
基本上,上面展示的是一个带有某些虚拟数据被记录的 Customer
类的实例。正如您所见,您只需将客户传递给 NLog 即可。
配置
NLog 和此自定义目标对您的类一无所知,因此我们必须指示它们在收到要记录的 Customer
类类型时该怎么做。
此配置可以通过直接在对象代码中或在目标 XML 配置中完成。如果一个对象同时定义了这两种配置,则 XML 配置将优先。
代码属性配置
在代码中,您需要告诉 NLog 该类是要被记录的,以及哪些属性是要被记录的。为此,您可以使用以下属性:
- [Log]
- 将此属性应用于您想要记录的类。
- [LogKey]
- 每个“可记录”对象都需要有一个唯一标识它的属性。
- 此属性指定该属性。
- [LogProperty]
- 应用于属性,表示该属性将在日志记录过程中被考虑。
- 只有具有此属性的属性才会被保存到日志数据库。
- 可以随时根据需要添加或删除属性。
XML 配置
- ConnectionString(必需)
- 指定要使用的连接字符串。
- DbProviderInvariantName(必需)
- 这是此目标标识要使用哪个 DbClient 的方式。
- 使用方式与 ADO.NET Factory 中的方式相同。
- DBTablesPrefix
- 如果您想为表名添加前缀,请使用此项。
- 这有助于避免与数据库中现有表发生命名冲突,并将所有日志表集中在一起。
- 默认情况下,没有分配任何前缀。
- AutoCreateDatabase
- 如果您不想关心数据库是否已包含必需的表,请使用此选项。
- 将此选项设置为 true 将使目标验证数据库架构并在必要时更新它。
- 我建议将此选项设置为 off。仅在首次运行时或执行版本更新时启用它。
- 默认情况下,此选项为 true。
- LogTypes
- 这是我们告诉 NLog 目标它应该期望哪些类型的地方。
- 在此处配置的类型将覆盖使用
[LogKey]
和[LogProperty]
属性直接在类代码中进行的任何配置。 - 在此处配置的预期类型必须遵循以下规则:
- 每个类型配置由 | 分隔。
- 每个配置参数由 ; 分隔。
- 参数定义为:Name:Value
- Properties 参数指定要考虑的类型的属性;每个属性名称必须用 , 分隔。
- 配置参数:
- name:类型的完全限定名,例如:App.Logger.WebTests.BusinessObjects.Supplier
- key:表示对象唯一标识符的属性名称
- properties:要记录的属性
这是演示中使用的 NLog.config 示例。
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<nlog xmlns="http://www.nlog-project.org/schemas/NLog.xsd"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<extensions>
<add assembly="App.Logger"/>
</extensions>
<targets>
<target name="OHTarget" type="OHTarget"
connectionString="Server=.;Database=MyDatabase;UID=sa;PWD=MyP@ssw0rd;"
DBTablesPrefix=""
DbProviderInvariantName="System.Data.SqlClient"
AutoCreateDatabase="True"
LogTypes="name:App.Logger.WebTests.BusinessObjects.
Supplier;key:SupplierID;properties:CompanyName,InvoicingAddress,Balance;"
/>
</targets>
<rules>
<logger name="*" minlevel="Trace" writeTo="OHTarget" />
</rules>
</nlog>
</configuration>
关注点
最初这是一个用于深入研究 NLog 的测试项目。之后,我做了一些您可能会感兴趣的附带开发:
- NLog 自定义目标创建。
- 在 NLog.Config 文件中进行自定义目标配置。
- 轻松地在应用程序中实现审计!
- 使用反射获取可记录的属性及其值。
- 数据库自动更新和脚本版本控制,这样您就不必担心存储架构的创建或更新。
历史
- [2010-05-26] - 深度重构
- 改进了工厂模式以支持多种数据库引擎。
- 不再需要接收
OHInfo
对象。 - 现在我们可以直接将对象传递给 NLog 进行记录。
- 添加了可选参数
OHAuditInfo
以添加审计信息。 - 添加了对 XML 配置的支持。
- 现在可以在目标配置 XML 中配置可记录的属性。
- 次要 bug 修复。
- [2010-05-11] - 初始版本