kse*_*een 6 .net c# database logging nlog
我正在开发一个复杂的分布式服务,它可以实现迭代同步过程.它在不同的信息系统中每10秒同步一次业务实体.一次迭代由一堆3d派对服务调用组成,用于检索业务对象的当前状态(客户数量,商品数量,某些客户和商品详细信息等),查询本地数据库然后获取它们之间的差异并平滑,同步差异.
有不同类型的迭代.它们很快(只有对象集的变化)和缓慢的迭代(完整的数据审查).快速是每10秒,慢速是每天一次.
那么,如何使用NLog记录此进程?我正在使用SQLite来存储数据.但是我坚持使用DB设计日志.
所以我想记录每次迭代的流程:1.请求当前状态的对象到3d派对服务2.查询本地数据库以获取对象的当前状态3.获取差异列表4.调用外部服务以提交不足的数据5.更新本地数据库,数据不足
但是有很多种信息需要记录,所以我不能把它放在一个TEXT字段中.
目前我正在使用这种结构的日志:
CREATE TABLE [Log] (
[id] INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
[ts] TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
[iteration_id] varchar,
[request_response_pair] varchar,
[type] VARCHAR NOT NULL,
[level] TEXT NOT NULL,
[server_id] VARCHAR,
[server_alias] VARCHAR,
[description] TEXT,
[error] Text);
Run Code Online (Sandbox Code Playgroud)
因此,每个服务请求和响应都会将每个响应链接到每个请求,description并且request_response_pair是关键.
这是我的NLog配置:
<?xml version="1.0" encoding="utf-8" ?>
<nlog xmlns="http://www.nlog-project.org/schemas/NLog.xsd"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" internalLogFile="D:\nlog.txt" internalLogLevel="Trace">
<targets>
<target name="Database" xsi:type="Database" keepConnection="false"
useTransactions="false"
dbProvider="System.Data.SQLite.SQLiteConnection, System.Data.SQLite, Version=1.0.82.0, Culture=neutral, PublicKeyToken=db937bc2d44ff139"
connectionString="Data Source=${basedir}\SyncLog.db;Version=3;"
commandText="INSERT into Log(iteration_id, request_response_pair, type, level, server_id, server_alias, description, error) values(@Iteration_id, @Request_response_pair, @Type, @Loglevel, @server_id, @server_alias, @Description, @Error)">
<parameter name="@Type" layout="${message}"/>
<parameter name="@Loglevel" layout="${level:uppercase=true}"/>
<parameter name="@Request_response_pair" layout="${event-context:item=request_response_pair}"/>
<parameter name="@Iteration_id" layout="${event-context:item=iteration_id}"/>
<parameter name="@server_id" layout="${event-context:item=server_id}"/>
<parameter name="@server_alias" layout="${event-context:item=server_alias}"/>
<parameter name="@Description" layout="${event-context:item=description}"/>
<parameter name="@Error" layout="${event-context:item=error}"/>
</target>
</targets>
<rules>
<logger name="*" minlevel="Trace" writeTo="Database" />
</rules>
</nlog>
Run Code Online (Sandbox Code Playgroud)
这是我记录的方式:
namespace NLog
{
public static class LoggerExtensions
{
public static void InfoEx(this Logger l, string message, Dictionary<string, object> contextParams)
{
LogEventInfo eventInfo = new LogEventInfo(LogLevel.Info, "", message);
foreach (KeyValuePair<string, object> kvp in contextParams)
{
eventInfo.Properties.Add(kvp.Key, kvp.Value);
}
l.Log(eventInfo);
}
public static void InfoEx(this Logger l, string message, string server_id, string server_alias, Dictionary<string, object> contextParams = null)
{
Dictionary<string, object> p = new Dictionary<string, object>();
p.Add("server_id", server_id);
p.Add("server_alias", server_alias);
if (contextParams != null)
{
foreach (KeyValuePair<string, object> kvp in contextParams)
{
p.Add(kvp.Key, kvp.Value);
}
}
l.InfoEx(message, p);
}
}
}
Run Code Online (Sandbox Code Playgroud)
我知道日志记录级别,但我需要所有这些详细日志,所以我将其记录为信息.我找不到任何教程如何记录这些复杂的结构化日志.只有简单的愚蠢日志消息.
我假设,您正在谈论典型的“日志内容”的“日志”,因此如果我们需要检查我们的工作流程(错误/性能),我们需要查看一些内容。我假设您指的不是“我们需要会计信息,日志是我们域数据的一部分并且包含在工作流程中”中的日志。
从我从您的帖子中得到的信息来看,您担心日志上的后端存储格式,以便您稍后可以处理它们并用于所述诊断?
然后我建议您使日志记录代码独立于域细节。
问题:您创建的日志将如何处理?您是否真的需要到处访问它们,因此需要数据库为您提供结构化视图?与过滤日志的速度有什么关系吗?或者它们最终会出现在一个大型日志分析器应用程序中,该应用程序仅在发生不良情况时第二周运行一次?
在我看来,您想要避免日志中任何特定领域的最大原因是“如果出现问题,日志应该起作用”和“日志应该在事情发生变化后起作用”。
如果出现问题,日志应该可以工作
如果日志表中有域特定值(例如“Request_response_pair”)的列,并且没有对,则写入日志本身可能会失败(例如,如果它是索引字段)。当然,您可以确保数据库设计中没有非空列并且没有任何限制,但退一步问:为什么您仍然需要日志数据库中的结构?日志的目的是尽可能可靠地工作,因此您按下日志的任何类型的模板都可能会限制用例或可能使您无法记录关键信息。
日志应该在事情发生变化后起作用
特别是如果您需要日志来检测和修复错误或提高性能,这意味着您将定期比较“更改之前”的日志与“更改后”的日志。如果您需要更改日志数据库的结构,因为您更改了域数据,那么当您需要比较日志时,这会对您造成伤害。
确实,如果您更改数据结构,您可能仍然需要更新一些工具,例如日志分析器等,但通常有很大一部分日志记录/分析代码与域的实际结构完全无关。
许多系统(包括复杂的系统)都可以接受“仅记录一个简单的字符串”,然后如果需要过滤或处理日志,则编写工具来再次拆分该字符串。
其他系统以简单的字符串键/值对形式写入日志。日志函数本身不是特定于域的,而是只接受一个字符串字典并将其注销(或者更简单,一个 params string[] 应该有偶数个参数,并且您使用每个第二个参数作为键 - 如果您不是被这个提议吓到了:-D)。
当然,您可能会开始在基本日志函数之上编写另一个工具层,该工具层了解特定于域的数据结构,然后组成字符串字典并将其传递。您当然不想将分解代码复制到各处。但要在您可能想要记录某些内容的所有地方提供基本功能。如果您确实遇到缺少某些信息的“奇怪”情况(异常处理程序),它确实很有帮助。