使用しているプラットフォームにかかわらず、ロギングは、ビッグデータ処理、統計、監査、クライアント向けレポート、トランザクションに加え、クライアントとサーバー間の通信や潜在的な問題のデバッグにおいても、多くの場合、不可欠な要件です。
このブログでは、デバッグにおけるロギングの役割を取り上げます。ロギングは、インターネット通信で頻繁に発生するさまざまな問題の特定に極めて有効なツールです。

クライアントとWebサーバー間の通信をログに記録すると、ブラウザのバージョン、クライアントのネットワーク、アクセス対象のファイルに関連して発生する可能性のある問題のデバッグに大いに役立ちます。ただし、ログの用途はそれだけではありません。何を記録するかは、使用するプラットフォームと要件に応じて多岐にわたります。
NGINXのログアーキテクチャ
リバースプロキシ、ロードバランサー、コンテンツ配信ネットワーク(CDN)を運用すると、クライアントとサーバー間の通信フローに別のノードが加わります。リバースプロキシのようにデータを処理する中間サーバーは、予期しない問題を引き起こすことが少なくありません。
NGINXはリバースプロキシとして、クライアントからの接続を終端し、サーバーへの新しい接続を確立することで、クライアントとWebサーバー(またはその他のアプリケーションサーバー)間の接続を2つの独立した接続に変換します。このように接続を2つに「分割」すると、ログ記録のコンテキストも2つに分かれ、NGINXではそれぞれのログ記録をやや異なる方法でサポートします。
- クライアントとリバースプロキシ間のトラフィックについて、NGINXは、エラーログと、エラー以外の処理イベントやアクションを記録するアクセスログの両方を提供します。エラーログは
error_logディレクティブで有効にし、記録するエラーの重大度レベルを設定できます。アクセスログはaccess_logディレクティブで有効にします。関連するlog_formatディレクティブを使用すると、ログに含める情報の種類とログエントリの形式をカスタマイズできます。ログはファイル、syslog、またはその両方に書き込めます。 - リバースプロキシとWebサーバーまたはアプリケーションサーバー(NGINXでは「アップストリームサーバー」と呼びます)の間のトラフィックについては、NGINXはエラーログをサポートしています。ただし、このトラフィックのアクセスログはサポートしていません。プロキシサーバーとアップストリームサーバーの間で発生するエラー以外のイベントを確認する唯一の方法は、エラーログの重大度レベルを
debugに設定することです。この設定には、膨大な量のデータがログに記録されるという欠点があります。その結果、リクエスト処理が遅くなるだけでなく、非常に大きなファイルが作成され、ストレージ容量をすぐに使い切る可能性があります。(デバッグのサポートはデフォルトでは有効になっていないため、--with-debug引数をconfigureコマンドに指定してNGINXを再コンパイルする必要もあります。)
F5のアップストリームログソリューション
CDNプロバイダーとして、リバースプロキシサーバーやクライアントと適切に通信できないアップストリームサーバーに遭遇することがよくあります。エラーログのdebugレベルのメッセージだけでは、アップストリームサーバーの問題を解決するために必要な情報を得られない場合があります。
解決策はすぐに明らかになりました。リバースプロキシサーバーとアップストリームサーバー間の通信から必要不可欠な情報だけを収集する機能を追加し、アップストリームアクセスログを生成することです。

基本的な考え方は、アップストリームサーバーへのリクエストが行われるたびに、NGINXから関数を呼び出すことです。これにより、アップストリームのロギングに関するすべてのロジックを関数自体に実装できます。
標準の「ngx_http_upstream_module」はアップストリームへのリクエストを処理しますが、このモジュールから関数を呼び出す必要があります。現在、このモジュールはそのような機能をサポートしていないため、必要に応じてコールバックを有効にできるようパッチを適用しました。
ログ記録自体は、独自に作成した別のモジュールで処理します。このモジュールは、パッチを適用したアップストリームモジュールに追加したログコールバック機能を使用します。新しいモジュールでは、ログ機能を設定するための新しい「upstream_log」ディレクティブを定義しています。このディレクティブは「access_log」ディレクティブと同じパーサーを使用するため、データをファイルに書き込むことも、ソケットを使用してsyslogサーバーに送信することもできます。
起動時にNGINXがupstream_logディレクティブをnginx.confから読み込むと、2つの関数が呼び出されます。
ngx_http_upstream_log_set_log。この関数はディレクティブを解析し、内部でngx_log_tを使用してログ構造体(ngx_log_set_log)自体を準備しますngx_http_upstream_log_init(構成後の処理で)、メインのロギング関数をupstreamモジュールに登録します
これにより、リクエストをアップストリームにプロキシする必要が生じた時点で、すべての準備が整っています。アップストリームモジュールがアップストリームサーバーへの接続を開始すると、このパッチによってロギング関数が呼び出され、リクエストの詳細がログに記録されます。
ログ形式はアップストリームモジュールに直接組み込まれています。必要であれば、log_formatディレクティブを使用した設定のサポートを追加できますが、今回のユースケースでは必要ありません。
アップストリームから記録される値
アップストリームサーバーへの接続が閉じられた直後に、ロギング関数が呼び出されます。この関数の引数は、現在処理中のリクエスト(ngx_http_ request_t構造体)へのポインターです。これにより、関数は構造体内のすべてのデータにアクセスし、ログに記録できます。特に注目すべきなのは、アップストリームリクエストに関するデータを格納するupstreamフィールド(ngx_http_upstream_tへのポインター)です。特に重要なのは、次の項目です。
- オリジンサーバーからのレスポンスのステータスコード
- リクエストの所要時間
- レスポンスのHTTPヘッダーまたはHostヘッダーの値
リクエスト構造全体にアクセスできるため、さまざまな情報をログに記録でき、モジュールを柔軟に使用できます。
直面した課題
当初、この機能は「ngx_http_core_module」に実装しました。プロトタイプとしては十分でしたが、将来の更新や変更が複雑になる可能性があり、あまり洗練されたソリューションではありませんでした。最終的に、「アップストリームログに関するF5のソリューション」で説明しているとおり、アップストリームロギング機能を独立したモジュールとして分離しました。
もちろん、実装上の問題もいくつかありました。特に、一部でngx_str_t文字列を誤って処理していました。たとえば、Cライブラリ関数のsprintfをngx_snprintfの代わりに使用していました。その結果、未定義のデータがアップストリームログに書き込まれたり、ワーカースレッドでセグメンテーションフォールトが発生したりする可能性があります。こうした問題は、ValgrindやAddressSanitizerなどのツールを使用して徹底的にデバッグとテストを行うことで解決しました。
CDN77で使用されているNGINXの機能
CDN77がNGINXを使用する主な理由は、そのキャッシュ機能にあります。CDNサーバーは、クライアントとWebサーバー(アップストリームサーバー)の間に配置されるノードで、クライアントからのリクエストを中継し、アップストリームサーバーに適切なファイルを要求します。ファイルがキャッシュされると、同じ場所から同じファイルを要求する他のユーザーにも配信されます。
「ローカルで提供されるファイル」は、リクエストを受信した際にNGINXがサーバーのディスクからファイルを提供するために使用している機能の1つです。
セキュアなキャッシュには、追加の機能と設定が必要です。コンテンツを適切に保護するため、SSL(0‑RTT対応のTLS 1.3)または特定のIPアドレス向けに生成できるセキュアトークンを使用します。
このほか、クライアント向けのカスタムエラーページ、NGINXのデフォルトのOCSPステープリング実装、必要なPHPプロセス数を削減するためのPHP用FastCGIなどの機能も使用しています。
まとめ
アップストリームロギングは、これまでさまざまな問題のデバッグに役立ち、現在も引き続き有用であるだけでなく、NGINXのコア機能をより深く掘り下げる絶好の機会となり、私たちが取り組んできた他の多くのプロジェクトも簡素化しました。
CDN77について
CDN77は、世界中でコンテンツ配信の品質と利便性を向上させます。30か所を超えるデータセンターを活用し、世界各地でコンテンツを効率的にキャッシュして配信できます。対象には、Webサイトの静的コンテンツ、ソフトウェア配信、ビデオオンデマンド(VoD)のほか、専用ストリーミングエンジンを使用したHLSやMPEG‑DASHなど、各種プロトコルによるライブストリーミングが含まれます。
CDN77は、簡単かつ迅速に利用を開始できます。まず、無料トライアルに登録してCDNリソースを作成し、生成されたCDN URLまたはカスタマイズしたCNAMEレコードを使用して、Webサイトやストリーミングソリューションと統合します。豊富な機能や設定、カスタムソリューションにより、CDN77はお客さまの要件に対応します。
著者について
関連するブログ記事
チュートリアル:NGINXを使用してアプリケーション向けにOpenTelemetryを構成する
OpenTelemetryを使用してNGINXサーバーの状態と健全性をより明確に把握することで、問題のトラブルシューティングを行い、Webアプリケーションのパフォーマンスを向上できます。
AkitaのNGINX Plus認定モジュールでAPIエンドポイントの問題を特定・修正
Akita SoftwareのAPIオブザーバビリティ向け新しいNGINX Plus Certified Moduleを活用して、APIエンドポイントの問題をより迅速に特定し、修正できます。
JavaプロジェクトをスキャフォールディングしてKubernetesネイティブアプリを構築する方法
Red HatのシニアプリンシパルデベロッパーアドボケイトであるDaniel Oh氏が、Javaプロジェクトをゼロから構築するためのひな形を作成し、Kubernetesネイティブアプリケーションとしてビルドする方法を解説します。
F5 NGINXaaS for Azureのご紹介:Microsoft Azureでネイティブに利用できるSaaS型ロードバランシング
NGINXaaS for Azureは、NGINX PlusをAzureネイティブのSaaSとして利用できるサービスです。NGINXの設定を容易にリフト&シフトできるため、クラウド導入とモダンアプリの展開を加速できます。

SELinuxでNGINXおよびNGINX Plusを使用する
Red Hat Enterprise Linux(RHEL)および関連ディストリビューションでSecurity-Enhanced Linux(SELinux)を有効にすると、デフォルト設定によりNGINXとNGINX Plusの一部の操作が制限されます。この記事では、すべての機能を利用できるようにSELinuxの設定を変更する方法について説明します。
NGINX PlusによるAWS Auto Scalingグループの負荷分散
新しいnginx-asg-sync統合ソフトウェアにより、NGINX PlusはAWS Auto Scalingグループの負荷を直接分散できるため、クラウドでの負荷分散がさらに柔軟になります