C# 如何记录复杂的同步过程?

C# 如何记录复杂的同步过程?,c#,.net,database,logging,nlog,C#,.net,Database,Logging,Nlog,我正在开发一个复杂的分布式服务,使迭代同步过程。它每10秒同步一次不同信息系统中的业务实体。一个迭代是由一堆3d party service调用组成,以检索业务对象的当前状态(客户、商品、特定客户和商品的详细信息等),查询本地数据库,然后获取它们之间的差异,并平滑、同步这些差异 有不同类型的迭代。它们是快速的(仅在一组对象中进行更改)和缓慢的迭代(对数据进行全面审查)。快是每10秒一次,慢是每天一次 那么,如何使用NLog记录这些过程?我使用SQLite来存储数据。但是我被困在日志的DB设计中

我正在开发一个复杂的分布式服务,使迭代同步过程。它每10秒同步一次不同信息系统中的业务实体。一个迭代是由一堆3d party service调用组成,以检索业务对象的当前状态(客户、商品、特定客户和商品的详细信息等),查询本地数据库,然后获取它们之间的差异,并平滑、同步这些差异

有不同类型的迭代。它们是快速的(仅在一组对象中进行更改)和缓慢的迭代(对数据进行全面审查)。快是每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);
因此,每个服务请求和响应都放在
描述
中,而
请求与响应对
是链接每个响应与每个请求的关键

这是我的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);
        }
    }
}
名称空间NLog
{
公共静态类LoggerExtensions
{
publicstaticvoidinfoex(此记录器为l、字符串消息、字典上下文参数)
{
LogEventInfo eventInfo=新的LogEventInfo(LogLevel.Info,”,消息);
foreach(contextParams中的KeyValuePair kvp)
{
添加(kvp.Key、kvp.Value);
}
l、 日志(事件信息);
}
public static void InfoEx(此记录器l、字符串消息、字符串服务器id、字符串服务器别名、字典contextParams=null)
{
字典p=新字典();
p、 添加(“服务器id”,服务器id);
p、 添加(“服务器别名”,服务器别名);
if(contextParams!=null)
{
foreach(contextParams中的KeyValuePair kvp)
{
p、 添加(kvp.Key,kvp.Value);
}
}
l、 InfoEx(message,p);
}
}
}

我知道日志记录级别,但我需要所有这些详细的日志,所以我将其记录为info。我找不到任何关于如何记录这些复杂的结构化日志的教程。只有简单的哑日志消息。

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

从我从你的帖子中得到的信息来看,你担心日志的后端存储格式,以便以后处理日志并用于上述诊断


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

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

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

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

如果您的日志表中有特定于域的列,如“Request\u response\u pair”,但没有对,则写入日志本身可能会失败(例如,如果它是索引字段)。当然,您可以确保在DB设计中没有非空列和限制,但退一步问问:为什么您要在日志数据库中使用该结构?日志意味着尽可能可靠地工作,因此任何类型的模板都可能会限制用例或使您无法记录关键信息

日志应在事情发生变化后生效

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

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


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

其他系统以简单的字符串键/值对写入日志。log函数本身不是特定于域的,只是接受一个字符串字典并将其注销(或者更简单的是,一个params string[],它应该有偶数个参数,并且您使用每一秒的参数作为键-如果您不害怕这个命题:-D)

当然,您可能会开始在基本日志函数的基础上编写另一个工具层,该工具层了解特定于域的数据结构,然后编写字符串字典并将其传递下去。您当然不想复制分解代码al