https://d226lax1qjow5r.cloudfront.net/blog/blogposts/minimizing-production-headaches-with-log-tracing/screen-shot-2021-03-23-at-13.16.56.png

ログトレースによる生産上の頭痛の種の最小化

最終更新日 March 22, 2021

所要時間:1 分

シーンを設定しよう:

プロダクションでクリティカル・インシデントが発生しました。それは あなたである。あなたは100の異なるサービスのログを調査し、完全に迷子になった。どのアクションがどの反応を引き起こしたのか?エラーはこのAPIコールに関係しているのか、それとも別のAPIコールに関係しているのか?私たちは皆、そのような経験をしたことがある。そして私たちは皆、それが楽しいものではないことに同意するだろう。

しかし がある。解決策がある。プロダクションの問題をすべて解決するわけではないが、非常に役立つソリューションだ。そして朗報は、それがあなたのサービスに簡単に統合できるということだ。

ログのトレース。

簡単そうに聞こえるだろう?しかし実際には、それはほとんどあらゆる種類の調査のための強力なツールになり得る。というのも、今日のモダンなアーキテクチャでは、ユーザーがサイトのボタンを1つ押すと、APIゲートウェイ、ビジネスサービス、データベース、別のサービス、集中型メッセージバス、別のサービスなどにAPIリクエストが発行されるからだ。

何十万人ものユーザーによって1秒間に何百回も起こるあらゆるフローによって生成される何百ものログが氾濫する圧倒的な旅なのだ。 ふぅー。

ログトレースとはどういう意味ですか?

これらのコンセプトの実装に入る前に、ログをトレースするという意味を理解しよう。トレースとは通常、データを集計するために使用できる識別子を追加することを意味する。それぞれのIDの意味は、好みの問題である。一つのリクエストの全てのデータに追加される一つのトレースIDを持つこともできます。あるいは、1つのサービスのコンテキストで使用される一連のスパンIDを持つこともできます。基本的な考え方は以下の通りです:

diagram-1basic log tracing flow

理解すべき重要な概念が2つある:

  1. トレースによって各リクエストの全サービスのログを集約する

  2. ビジネス・ロジックの邪魔にならないよう、トレースはインフラに任せる。

では、どうやってそれを実行するのか?

各リクエストのログを集計

このコンセプトはとても簡単だ。非常にシンプルな2つのルールに従う必要がある:

  • リクエストに対して書くログにトレース ID を追加し、IO 操作をするたびにトレース ID を渡す。

  • つのサービスがメッセージバスを介して同じリクエストで通信する場合、バスに追加されたメッセージにトレースIDを追加します。二つのサービスが http リクエストで通信する場合、リクエストのヘッダーにトレース ID を追加します。こうすることで、並行して発生する他のリクエストやログのノイズなしに、 一つのリクエストのフロー全体を追うことができます。

ビジネスロジックとインフラの分離

送受信されたデータをすべて追跡できるようにするには、かなりの量のコーディングが必要になります。このようなインフラストラクチャーのコンセプトは、できる限りビジネス・ロジックから切り離したいものです。幸運なことに、私たちのケースでは、トレース管理をほぼ完全に分割することは簡単です。

我々のコードでは、様々なイベントやエラーに対してログを書き、そのログにデータを追加している。トレースをすべてのログに並行して追加しながら、これらのフローを変更しないようにしたい。今日我々が使っているツールのほとんどは、受け取ったリクエストにインターセプターを追加することができる。IOツールとロギングツールにインターセプターを追加するようにすれば、既存のコードに触れることなく、すべてのログを確実にトレースできるようになります。

最も簡単に説明する方法は、私たちのサービスでの実例を示すことだ。

このコードは、httpリクエストを受信し、いくつかのログを書き、次のサービスにhttpリクエストを行うnodejsサービスのものである。これはインターセプターを配置した3つの場所のうちの1つである:インバウンドリクエスト、ロギング、アウトバウンドリクエスト。

function tracingMiddleware(req,res,next) {
    ns.run(() => {
        let traceId = req.headers['x-b3-traceid'];
        let spanId = req.headers['x-b3-spanid'];
        if (!traceId || !spanId) {
            traceId = uuid().replace(/-/g, '');
            spanId = uuid().replace(/-/g, '').substring(16);
        }
        ns.set('traceId', traceId);
        ns.set('spanId', spanId);
        next();
    });
}

私たちはExpressをAPIインフラとして使用し、expressを実装しています。 ミドルウェアを実装している。リクエストからトレースIDを抽出するか、あるいはチェーン内の最初のサービスであれば新しいトレースIDを作成する。そして、セッション・ストレージ・ツールにトレースIDをセットし、すべてのステップでトレースIDを取得できるようにする。

に注目してほしい。 ns.set.これは cls-hookedこれはノードの非同期フックをラップする継続ローカルストレージパッケージである。これによって、各セッションのトレースIDをローカルに保存することができます。しかし、もしあなたが Node 14 を使っているなら、この機能はすでに 非同期ローカルストレージ.しかし、この方法がクールなのは、どの言語でも実装できることです。

次に、セッションストレージからトレースIDを取得し、すべてのログ行に追加するインターセプターをロギングツールに追加する:

function createBunyanStreamMiddleware(streams) {
    return {
        type: 'raw',
        level: process.env.LOG_LEVEL,
        stream: {
            write: (entry) => {
                if(ns && ns.active) {
                    entry['traceId'] = ns.get('traceId');
                    entry['spanId'] = ns.get('spanId');
                }
                streams.forEach((stream) => {
                        stream.stream.write(entry)
                });
            }
        }
    }
}

最後に、httpツールにインターセプターを追加し、リクエストが発射される前に、リクエストヘッダーにトレースIDを追加する:

function insertTracingHeaders(config = {}){
    if(ns && ns.active) {
        const traceId = ns.get('traceId');
        const spanId = ns.get('spanId');
        if (!config.headers) {
            config.headers = {};
        }
        if (traceId && spanId) {
            config.headers['x-b3-parentspanid'] = spanId;
            config.headers['x-b3-traceid'] = traceId;
        }
    }
    return config;
}

全体の流れは次のようになる:

diagram-2tracing flow with interceptors

結論として

ログトレースはいろいろな場面で使われますが、この特別な使い方をすることで、 エラーを調査するときの頭痛の種をかなり防ぐことができます。各フローのリクエストログに簡単にアクセスできるので、 何千もの無関係なログを調べる必要がなくなります。

私たちは個人的に、これらのコンセプトを適用したサービスにおいて、ログ調査の効率と価値が急上昇したと断言できます。それ以来、他の方法でログをふるいにかけても、しっくりこないのです。

次回、本番で重大なインシデントが発生し、それを解決するのはあなた次第だが、少なくとも今回はログがあなたの味方になってくれるだろう。

シェア:

https://a.storyblok.com/f/270183/400x558/679b85cd1e/tech-lead.png
Ori Shofman Shimoniテック・リード

オリはVonage Israelの技術リード。ソフトウェア、音楽、サッカー、チェス、動物をこよなく愛する。