6

我正在开发一个复杂的分布式服务,它可以进行迭代同步过程。它每 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);

因此,每一个服务请求和响应都是把descriptionrequest_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);
        }
    }
}

我知道日志记录级别,但我需要所有这些详细日志,所以我将其记录为信息。我找不到任何教程如何记录这些复杂的结构化日志。只有普通的愚蠢日志消息。

4

1 回答 1

1

我假设,您正在谈论典型的“日志内容”的“日志”,因此如果我们需要检查我们的工作流程(错误/性能),我们可以查看一些内容。我假设您不是指日志,例如“我们需要会计信息,并且日志是我们域数据的一部分并包含在工作流程中”。

根据我从您的帖子中得到的信息,您担心日志上的后端存储格式,以便您以后可以处理它们并用于所述诊断?


然后我建议您使日志记录代码独立于域细节。

问题:您创建的日志将如何处理?你真的需要到处访问它们,所以你需要数据库来为你提供结构化的视图吗?过滤日志的速度是否与任何相关?或者它们最终会出现在一个大型日志分析器应用程序中,该应用程序仅在第二周发生不好的事情时运行?

在我看来,您希望避免在日志中出现任何域细节的最大原因是“如果出现问题,日志应该可以工作”和“在事情发生变化后日志应该可以工作”。

如果出现问题,日志应该可以工作

如果您的日志表中有“Request_response_pair”等域特定值的列,并且没有对,那么写入日志本身可能会失败(例如,如果它是索引字段)。当然,您可以确保在您的 DB 设计中没有非空列和没有限制,但退后一步问:您为什么要在日志数据库中使用这种结构?日志旨在尽可能可靠地工作,因此您按下它们的任何类型的模板都可能限制用例或可能使您无法记录关键信息。

事情发生变化后,日志应该可以工作

特别是如果您需要日志来检测和修复错误或提高性能,这意味着您将定期比较“更改前”的日志和“更改后”的日志。如果您需要更改日志数据库的结构,因为您更改了域数据,那么当您需要比较日志时,这会伤害您。

诚然,如果您进行数据结构更改,您可能仍需要更新一些工具,如日志分析器等,但通常有很大一部分日志/分析代码与域的实际结构完全无关。


许多系统(包括复杂系统)可以使用“只记录一个简单的字符串”,然后在需要过滤或处理日志时编写工具再次将字符串分开。

其他系统以简单的字符串键/值对写入日志。log 函数本身不是特定于域的,只是接受一个字符串字典并将其写下来(或者更简单,一个 params string[] 应该有偶数个参数,并且你使用每个第二个参数作为键 - 如果你不是被那个提议吓到了:-D)。

当然,您可能会开始在基本日志函数之上编写另一个工具层,该工具层了解特定于域的数据结构,然后组成字符串字典并将其传递。您当然不想到处复制分解代码。但是在您可能想要记录某些内容的所有地方都可以使用基本功能。如果您确实遇到缺少某些信息的“奇怪”情况(异常处理程序),它真的很有帮助。

于 2013-06-07T10:59:16.487 回答