我正在开发一个复杂的分布式服务,它可以实现迭代同步过程。它在不同的信息系统中每10秒同步一次业务实体。一次迭代由一堆3d派对服务调用组成,用于检索业务对象的当前状态(客户数量,商品数量,某些客户和商品详细信息等),查询本地数据库然后获取它们之间的差异并平滑,同步差异。
有不同类型的迭代。它们很快(只有对象集的变化)和缓慢的迭代(完整的数据审查)。快速是每10秒,慢是每天一次。
那么,如何使用NLog记录此进程?我正在使用SQLite来存储数据。但是我坚持使用日志数据库设计。
所以我想记录每次迭代的流程: 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);
因此,每个服务请求和响应都会发送到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>
以下是我记录的方式:
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);
}
}
}
我知道记录级别,但我需要所有这些详细日志,因此我将其记录为信息。我找不到任何教程如何记录这些复杂的结构化日志。只有简单的愚蠢日志信息。
答案 0 :(得分:1)
我假设,你在谈论&#34; Logs&#34;对于典型的日志事物,如果我们需要检查我们的工作流程(错误/性能),我们需要注意一些事项。我假设你不是指日志,例如in&#34;我们需要会计信息,日志是我们的域数据的一部分,并包含在工作流程中。&#34;
根据我发布的内容,你担心日志中的后端存储格式,以便以后处理它们并用于所述诊断?
然后,我建议您将日志记录代码作为域特定的独立内容。
问题:您创建的日志将如何处理?您是否真的需要在整个地方访问它们,因此您需要数据库为您提供结构化视图?是否与您过滤日志的速度有何关联?或者他们最终会在一个大的日志分析器应用程序中结束,只有在第二周发生了一些不好的事情时才会运行?
在我看来,您希望避免日志中任何域细节的最大原因是,如果出现问题,日志应该可以正常工作&#34; &#34; 日志应该在事情发生变化后起作用&#34;。
如果出现问题,日志应该有效
如果您的日志表中有特定于域的列,例如&#34; Request_response_pair&#34;,并且没有对,则写入日志本身可能会失败(例如,如果它是索引字段)。当然,您可以确保在数据库设计中没有非空列且没有限制,但退后一步并问:为什么您还想要日志数据库中的结构?日志应尽可能可靠地工作,因此您按下它们的任何类型的模板都可能限制用例,或者可能使您无法记录关键信息。
日志应在更改后生效
特别是如果您需要用于检测和修复错误或提高性能的日志,这意味着您将在更改之前定期比较&#34;中的日志。来自&#34;更改后的日志&#34;。如果您需要更改日志数据库的结构,因为您更改了域数据,当您需要比较日志时,这会对您造成伤害。
是的,如果你改变数据结构,你可能仍然需要更新一些工具,比如日志分析器等,但是通常有很大一部分日志/分析代码与域的实际结构完全无关。
许多系统(包括复杂系统)都可以使用&#34;只记录一个简单的字符串&#34;如果他们需要过滤或处理日志,则稍后再编写工具以将字符串分开。
其他系统将日志写入简单的字符串键/值对。日志函数本身不是特定于域的,但只是接受一个字符串字典并将其写下来(甚至更容易,一个params字符串[],它应该有一个偶数个参数,你使用每一个参数作为键 - 如果你不是&#39被这个命题吓到了:-D)。
当然,您可能会开始在知道域特定数据结构的基本日志函数之上编写另一个工具层,然后编写字符串字典并将其传递。你当然不想复制所有地方的分解代码。但是,在您可能想要记录某些内容的所有位置都可以使用基本功能。如果你确实遇到了“奇怪的”#34;它真的很有帮助。缺少某些信息的情况(异常处理程序)。