nginxのメトリクス・ログ・トレースをDatadogでモニターする方法

クイズです。コンテナ環境で一番使われているテクノロジーは何でしょうか？　答えは。。

# 一番使われているコンテナはnginx
Datadog調べによると、Dockerのコンテナで一番よく使われているテクノロジーはnginxだそうです。

[8 Surprising facts about real Docker adoption](https://www.datadoghq.com/docker-adoption/)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/325973/05b13df6-3871-292e-f0fa-200cae836e59.png)
特にKubernetes環境では、全企業の内70%でnginxのイメージが使われているそうです。

[8 Facts about real-world container use](https://www.datadoghq.com/container-report-2019/)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/325973/3bb36734-51bd-b513-66b3-77cdbc30f9db.png)

世界のWebサーバーのシェアNo.1となったnginxですが、その高速さやシンプルさで人気があり、クラウド、オンプレ、サーバー、コンテナ問わず広く使われています。ですので、nginxの稼働状況をいろいろな観点で観測する機会は多いと思います。今日はDatadogでnginxを観測し尽くすことを目指してまとめていきます。

# メトリクス

まずはメトリクスから。メトリクスとは主に数値情報で、アクセス数やエラーの数など計測可能な数値情報を一定時間ごとに収集するものです。例えばアクセス数は、nginx.net.request_per_sというメトリクスに収められます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/325973/cd802229-585b-162f-f9e2-702118168b85.png)
これらの数値はnginxの[stub statusモジュール](http://nginx.org/en/docs/http/ngx_http_stub_status_module.html)から収集します。stub statusモジュールを適当なパスにマップすると以下のように現在の接続状況が取得できます。

```
$ curl localhost/nginx_status
Active connections: 1 
server accepts handled requests
 93370 93370 74159 
Reading: 0 Writing: 1 Waiting: 0
```

下から2行目の3つの数字は、受け付けたコネクション数(accepts)、処理したコネクション数(handled)、リクエスト数(requests)です。Datadogのエージェントは[nginxインテグレーション](https://docs.datadoghq.com/ja/integrations/nginx/)により、デフォルトで15秒に一度このURLにアクセスしてデータを取得して、Datadogに送り、上のようなグラフに視覚化します。

なお、有償版の[NGINX Plus](https://www.nginx.co.jp/)では、パフォーマンスデータがAPI経由で提供されているため、はるかに多彩なメトリクスが得られます。DatadogでもNGINX PlusのAPIに対応しており、フリー版nginxでは7つのメトリクスが得られるところ、NGINX Plusでは130以上のメトリクスが取得できます。

# ログ

次はログです。[nginxのログ形式](http://nginx.org/en/docs/http/ngx_http_log_module.html)は自由に設定できますが、多くの場合はドキュメントに書かれている`combined`を使われていることが多いのではないでしょうか。実はnginxはそれ以外にも処理時間を保持する変数`$request_time`を持っているので、Datadogではそれをログに含めることを推奨しています。具体的な設定としては[ドキュメント](https://docs.datadoghq.com/ja/integrations/nginx/?tab=host#%E3%83%AD%E3%82%B0%E3%81%AE%E5%8F%8E%E9%9B%86)にあるとおり、`$request_time`を下記の位置`$body_bytes_sent`の後に追加してください。

```
http {
    #推奨ログフォーマット
    log_format nginx '\$remote_addr - \$remote_user [\$time_local] '
                  '"\$request" \$status \$body_bytes_sent \$request_time '
                  '"\$http_referer" "\$http_user_agent"';

    access_log /var/log/nginx/access.log;
}
```

nginxのログはデフォルトではプレインテキスト形式なので、Datadog側では転送された後に構造化するためのルールが必要で、それもnginxインテグレーションに含まれています。このルールは上記のログ形式に対応しているので、`$request_time`を追加しても自動的に検知して構造化します。
下のスクリーンショットはログの一例で、上側のテキストログの赤枠に`$request_time`の値として`0.132`が入っていて、それが構造化処理後には`duration: 1320000`という値になっています。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/325973/71f7af2b-002f-27f8-fc0c-59361e1465d8.png)
この情報があるとパフォーマンスの統計が取れますし、遅いログだけ抜き出すことも簡単にできます。以下の例では10秒以上処理にかかっているログだけを抜き出します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/325973/7c118865-46e5-07f3-569e-b596ad7e38de.png)

あと、後述のトレースとログを関連づけるために、ログに`trace_id`を付加したい場面が出てくると思いますが、その場合も同様にnginx側の設定でカスタムログ形式を設定し、[OpenTracingの例](https://github.com/DataDog/dd-opentracing-cpp/blob/master/examples/nginx-tracing/nginx.conf)の`log_format`の部分を参考に、Trace IDをログに含めてください。この場合Datadog側では構造化処理のルールをカスタマイズする必要があります。

# トレース

nginxは元々は静的なコンテンツを提供するWebサーバーとして使われることが多かったかと思いますが、近年では動的なコンテンツを提供するサーバーの前段に配置して、リバースプロキシとして使用するケースが増えてきていると思います。アプリサーバーのリバースプロキシとして、また複数台のアプリサーバーへのロードバランサーとして広く活用されています。

APM(Application Performance Monitoring)では、アプリのトレースを生成して、リクエスト数、レイテンシー、エラーなどの情報を収集し、アプリのパフォーマンスや健全性を可視化します。またマイクロサービスなどの分散環境では、分散トレーシングとして、サービス間の呼び出し関係を含めて可視化できるため、サービス全体が遅くなっている時に、どの部分で遅くなっているのかが一目瞭然になります。

一般的に、APMではWebアプリケーションなどにトレースライブラリを組み込んで、トレースを収集しますが、実はnginxでもOpenTracingのモジュールを組み込むことで、分散トレーシングの一部として観測することができます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/325973/4d6ea4ca-e17d-63f5-7ca2-30b5a9074a1b.png)
スクリーンショット内の長方形の帯１つ１つがスパンと呼ばれるアプリの処理単位です。横軸が時間、縦軸が呼び出し関係です。上のスパンが親となり下のスパンを呼び出しています。ここで一番上のグリーンのスパン、つまりユーザーから見て一番手前に位置するサービスがnginxであることにお気づきかと思います。このようにnginxも分散トレーシングの一部として可視化できます。

この例では、nginxをリバースプロキシとして、その後ろにnode.jsのアプリ、さらにmysqlのデータベースが動いています。nginxにはopentracingを組み込んで、トレースを生成してDatadog Agentに送り、Datadogへ転送されています。

これらをまとめたサンプルを以下のレポジトリに置いています。docker環境があればdocker-composeで簡単にすぐ試せますので、設定や動きをぜひ見てみてください。

https://github.com/shigeya-dd/nginx-opentracing-datadog

ここで使っているOpenTracing関連の情報リンクです。

- Open tracing module
  - https://github.com/opentracing-contrib/nginx-opentracing
- Datadog Open tracing plug-in
  - https://github.com/DataDog/dd-opentracing-cpp 
  - https://github.com/DataDog/dd-opentracing-cpp/tree/master/examples/nginx-tracing 

また、ログの項の最後で説明したように`trace_id`をログに含めて出力してDatadogに送っていますので、APMとも関連づけられ、Logsタブで確認できます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/325973/f4300005-daa4-5bd8-ad59-204154281011.png)

以上nginxをDatadogで観測し尽くそうの巻でした。
Happy Datadogging!