6

反復同期プロセスを行う複雑な分散サービスを開発しています。異なる情報システムのビジネス エンティティを 10 秒ごとに同期します。1 回の反復は、ビジネス オブジェクトの現在の状態 (顧客数、商品、特定の顧客と商品の詳細など) を取得するための一連のサード パーティ サービス呼び出しで構成され、ローカル DB にクエリを実行し、それらの違いを取得して平滑化し、これを同期します。違い。

繰り返しにはさまざまな種類があります。それらは高速 (一連のオブジェクトの変更のみ) であり、反復は低速 (データの完全なレビュー) です。高速は 10 秒ごと、低速は 1 日 1 回です。

では、NLog を使用してこのプロセスをどのようにログに記録できますか? データの保存に SQLite を使用しています。しかし、ログの DB 設計に行き詰まっています。

1. オブジェクトの現在の状態をサード パーティ サービスに要求する 2. ローカル データベースにオブジェクトの現在の状態を問い合わせる 3. 差分リストを取得する 4. 外部サービスを呼び出して不十分なデータをコミットする 5. 更新する不十分なデータのローカル データベース

TEXTしかし、ログに記録する情報は非常に多くの種類があるため、1 つのフィールドにまとめることはできません。

現時点では、ログにそのような構造を使用しています:

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);
        }
    }
}

ログレベルについては知っていますが、この詳細なログがすべて必要なので、情報としてログに記録します。これらの複雑で構造化されたログを記録する方法のチュートリアルが見つかりません。単純なダム ログ メッセージのみ。

4

1 に答える 1

1

典型的な「ログのこと」の「ログ」について話しているので、ワークフロー(エラー/パフォーマンス)を検査する必要がある場合に確認する必要があると思います。たとえば、「アカウンティング情報が必要であり、ログはドメイン データの一部であり、ワークフローに含まれています」などのログを意味するものではないと思います。

そして、あなたの投稿から得た情報から、ログのバックエンド ストレージ フォーマットについて心配しているので、後でログを処理して診断に使用できますか?


次に、ロギング コードをドメインの仕様に依存しないようにすることをお勧めします。

質問: 作成したログはどのように処理されますか? 構造化されたビューを提供するためにデータベースが必要なので、本当にどこからでもそれらにアクセスする必要がありますか? ログをどれだけ速くフィルタリングできるかは、何らかの関連がありますか? それとも、何か悪いことが起こったときに 2 週間おきに実行される 1 つの大きなログ アナライザー アプリケーションになってしまうのでしょうか?

私の意見では、ログ内のドメイン固有を避けたい最大の理由は、「問題が発生した場合にログが機能する必要がある」ことと、「問題が変更された後にログが機能する必要がある」ことです。

問題が発生した場合、ログは機能するはずです

ログ テーブルに「Request_response_pair」などのドメイン固有の値の列があり、ペアがない場合、ログ自体の書き込みに失敗する可能性があります (たとえば、インデックス フィールドの場合)。もちろん、DB 設計に null 以外の列や制限がないことを確認することはできますが、一歩下がって自問してください。ログは可能な限り信頼できるように機能するように設計されているため、どのような種類のテンプレートを使用しても、使用例が制限されたり、重要な情報をログに記録できなくなったりする可能性があります.

物事が変わった後、ログは機能するはずです

特に、バグの検出と修正、またはパフォーマンスの向上のためにログが必要な場合は、「変更前」のログと「変更後」のログを定期的に比較する必要があります。ドメイン データを変更したためにログ データベースの構造を変更する必要がある場合は、ログを比較する必要があるときに問題が発生します。

確かに、データ構造を変更した場合、おそらくログ アナライザーなどのツールを更新する必要がありますが、通常、ドメインの実際の構造に完全に依存しないロギング/分析コードの大部分があります。


多くのシステム (複雑なシステムを含む) は、「1 つの単純な文字列をログに記録するだけ」で済み、後でログをフィルター処理または処理する必要がある場合に、文字列を再び分解するツールを作成できます。

他のシステムは、単純な文字列のキーと値のペアでログを書き込みます。ログ関数自体はドメイン固有ではありませんが、文字列辞書を受け入れてそれを書き出すだけです (または、より簡単に、偶数のパラメーターを持つ必要がある params string[] で、2 つおきのパラメーターをキーとして使用します-そうでない場合)その命題に怯えている:-D)。

もちろん、ドメイン固有のデータ構造を認識し、文字列ディクショナリを構成して渡すベース ログ関数の上に、別のツール層を書き始めることになるでしょう。分解コードをあちこちにコピーしたくないのは確かです。ただし、何かをログに記録したいすべての場所で基本関数を使用できるようにします。一部の情報が欠落している「奇妙な」状況(例外ハンドラ)に実際に遭遇した場合、これは非常に役立ちます。

于 2013-06-07T10:59:16.487 に答える