Fastly のログの収集
このページでは、Fastly アプリケーションのログ収集をセットアップする手順を説明します。
ステップ 1: Collector および Source の設定
このステップでは、Fastly ログを受信するために Collector および Source を設定します。
- Sumo Logic の Hosted Collector を Sumo Logic 組織に追加します。
- Fastly リクエスト ログ用に HTTP Source を設定します。HTTP Source を設定するときに、必ず Source Category を設定してください。例:
fastly
。Source に割り当てる Source Category を書き留めます。この Source Category 値は、Fastly アプリケーションをインストールするときに指定します。
ステップ 2.CDN ログ用の Fastly でのエンドポイントの設定
このステップでは、Fastly サービス用のログ エンドポイントとして Sumo Logic を追加し、CDN ログを受信するように設定します。このプロセスについては、Fastly ヘルプの「Adding Sumo Logic as a logging endpoint (ログ エンドポイントとしての Sumo Logic の追加)」で説明しています。
CDN および Request WAF ログを収集する場合は、下記の「WAF リクエスト ログの収集」を参照してください。
Fastly で Sumo Logic エンドポイントを設定するとき:
- Name (名前): 接続の名前を入力します。たとえば、“Prod Fastly” です。
- Log format (ログ形式)。次の形式文字列を使用します。これによって、必要な JSON 出力が生成されます。
{ "service_id":"%{req.service_id}V", "service_version":"%{fastly_info.version}V", "time_start":"%{begin:%Y-%m-%dT%H:%M:%S%Z}t", "time_end":"%{end:%Y-%m-%dT%H:%M:%S%Z}t", "time_elapsed":%{time.elapsed.usec}V, "client_ip":"%{req.http.Fastly-Client-IP}V", "request":"%{req.request}V", "protocol":"%{req.proto}V", "host":"%{req.http.Fastly-Orig-Host}V", "origin_host":"%{req.http.Host}V", "url":"%{cstr_escape(req.url)}V", "is_ipv6":%{if(req.is_ipv6, "true", "false")}V, "is_tls":%{if(req.is_ssl, "true", "false")}V, "tls_client_protocol":"%{cstr_escape(tls.client.protocol)}V", "tls_client_servername":"%{cstr_escape(tls.client.servername)}V", "tls_client_cipher":"%{cstr_escape(tls.client.cipher)}V", "tls_client_cipher_sha":"%{cstr_escape(tls.client.ciphers_sha )}V", "tls_client_tlsexts_sha":"%{cstr_escape(tls.client.tlsexts_sha)}V", "is_h2":%{if(fastly_info.is_h2, "true", "false")}V, "is_h2_push":%{if(fastly_info.h2.is_push, "true", "false")}V, "h2_stream_id":"%{fastly_info.h2.stream_id}V", "request_referer":"%{cstr_escape(req.http.Referer)}V", "request_user_agent":"%{cstr_escape(req.http.User-Agent)}V", "request_accept_content":"%{cstr_escape(req.http.Accept)}V", "request_accept_language":"%{cstr_escape(req.http.Accept-Language)}V", "request_accept_encoding":"%{cstr_escape(req.http.Accept-Encoding)}V", "request_accept_charset":"%{cstr_escape(req.http.Accept-Charset)}V", "request_connection":"%{cstr_escape(req.http.Connection)}V", "request_dnt":"%{cstr_escape(req.http.DNT)}V", "request_forwarded":"%{cstr_escape(req.http.Forwarded)}V", "request_via":"%{cstr_escape(req.http.Via)}V", "request_cache_control":"%{cstr_escape(req.http.Cache-Control)}V", "request_x_requested_with":"%{cstr_escape(req.http.X-Requested-With)}V", "request_x_forwarded_for":"%{cstr_escape(req.http.X-Forwarded-For)}V", "status":"%{resp.status}V", "content_type":"%{cstr_escape(resp.http.Content-Type)}V", "cache_status":"%{regsub(fastly_info.state, "^(HIT-(SYNTH)|(HITPASS|HIT|MISS|PASS|ERROR|PIPE)).*", "\\2\\3")}V", "is_cacheable":%{if(fastly_info.state ~"^(HIT|MISS)$", "true", "false")}V, "response_age":"%{cstr_escape(resp.http.Age)}V", "response_cache_control":"%{cstr_escape(resp.http.Cache-Control)}V", "response_expires":"%{cstr_escape(resp.http.Expires)}V", "response_last_modified":"%{cstr_escape(resp.http.Last-Modified)}V", "response_tsv":"%{cstr_escape(resp.http.TSV)}V", "geo_datacenter":"%{server.datacenter}V", "geo_city":"%{geoip.city}V", "geo_country_code":"%{geoip.country_code}V", "geo_continent_code":"%{geoip.continent_code}V", "geo_region":"%{geoip.region}V", "req_header_size":%{req.header_bytes_read}V, "req_body_size":%{req.body_bytes_read}V, "resp_header_size":%{resp.header_bytes_written}V, "resp_body_size":%{resp.body_bytes_written}V, "socket_cwnd":%{client.socket.cwnd}V, "socket_nexthop":"%{client.socket.nexthop}V", "socket_tcpi_rcv_mss":%{client.socket.tcpi_rcv_mss}V, "socket_tcpi_snd_mss":%{client.socket.tcpi_snd_mss}V, "socket_tcpi_rtt":%{client.socket.tcpi_rtt}V, "socket_tcpi_rttvar":%{client.socket.tcpi_rttvar}V, "socket_tcpi_rcv_rtt":%{client.socket.tcpi_rcv_rtt}V, "socket_tcpi_rcv_space":%{client.socket.tcpi_rcv_space}V, "socket_tcpi_last_data_sent":%{client.socket.tcpi_last_data_sent}V, "socket_tcpi_total_retrans":%{client.socket.tcpi_total_retrans}V, "socket_tcpi_delta_retrans":%{client.socket.tcpi_delta_retrans}V, "socket_ploss":%{client.socket.ploss}V }
- Collector URL (Collector URL)。上記のステップ 1 で作成した HTTP Source の URL を入力します。
- [Advanced options (詳細オプション)] をクリックします。
- デフォルトでは、ログ行の形式は [Classic (クラシック)] に設定されます。[Blank (空白)] に変更します。
- [Create (作成)] ボタンをクリックして、新しいログ エンドポイントを作成します。
- [Activate (アクティブ化)] ボタンをクリックして、設定をデプロイします。
ステップ 3: WAF リクエスト ログの収集
Fastly の Web アプリケーション ファイアウォール (WAF) がある場合は、以下のステップを実行して、上記のステップ 2 で作成したエンドポイントの設定を更新します。WAF リクエスト ログおよび CDN ログを受信するようにエンドポイントを更新します。
- 「CDN ログ用の Fastly でのエンドポイントの設定」で指定したオブジェクトではなく、下記の JSON オブジェクトを [Log format (ログ形式)] フィールドに使用します。
{"service_id":"%{req.service_id}V","service_version":"%{fastly_info.version}V","time_start":"%{begin:%Y-%m-%dT%H:%M:%S%Z}t","time_end":"%{end:%Y-%m-%dT%H:%M:%S%Z}t","time_elapsed":%{time.elapsed.usec}V,"client_ip":"%{req.http.Fastly-Client-IP}V","request":"%{req.request}V","protocol":"%{req.proto}V","host":"%{req.http.Fastly-Orig-Host}V","origin_host":"%{req.http.Host}V","url":"%{cstr_escape(req.url)}V","is_ipv6":%{if(req.is_ipv6,"true","false")}V,"is_tls":%{if(req.is_ssl,"true","false")}V,"tls_client_protocol":"%{cstr_escape(tls.client.protocol)}V","tls_client_servername":"%{cstr_escape(tls.client.servername)}V","tls_client_cipher":"%{cstr_escape(tls.client.cipher)}V","tls_client_cipher_sha":"%{cstr_escape(tls.client.ciphers_sha)}V","tls_client_tlsexts_sha":"%{cstr_escape(tls.client.tlsexts_sha)}V","is_h2":%{if(fastly_info.is_h2,"true","false")}V,"is_h2_push":%{if(fastly_info.h2.is_push,"true","false")}V,"h2_stream_id":"%{fastly_info.h2.stream_id}V","request_referer":"%{cstr_escape(req.http.Referer)}V","request_user_agent":"%{cstr_escape(req.http.User-Agent)}V","request_accept_content":"%{cstr_escape(req.http.Accept)}V","request_accept_language":"%{cstr_escape(req.http.Accept-Language)}V","request_accept_encoding":"%{cstr_escape(req.http.Accept-Encoding)}V","request_accept_charset":"%{cstr_escape(req.http.Accept-Charset)}V","request_connection":"%{cstr_escape(req.http.Connection)}V","request_dnt":"%{cstr_escape(req.http.DNT)}V","request_forwarded":"%{cstr_escape(req.http.Forwarded)}V","request_via":"%{cstr_escape(req.http.Via)}V","request_cache_control":"%{cstr_escape(req.http.Cache-Control)}V","request_x_requested_with":"%{cstr_escape(req.http.X-Requested-With)}V","request_x_forwarded_for":"%{cstr_escape(req.http.X-Forwarded-For)}V","status":"%{resp.status}V","content_type":"%{cstr_escape(resp.http.Content-Type)}V","cache_status":"%{regsub(fastly_info.state,"^(HIT-(SYNTH)|(HITPASS|HIT|MISS|PASS|ERROR|PIPE)).*","\\2\\3")}V","is_cacheable":%{if(fastly_info.state~"^(HIT|MISS)$","true","false")}V,"response_age":"%{cstr_escape(resp.http.Age)}V","response_cache_control":"%{cstr_escape(resp.http.Cache-Control)}V","response_expires":"%{cstr_escape(resp.http.Expires)}V","response_last_modified":"%{cstr_escape(resp.http.Last-Modified)}V","response_tsv":"%{cstr_escape(resp.http.TSV)}V","geo_datacenter":"%{server.datacenter}V","geo_city":"%{geoip.city}V","geo_country_code":"%{geoip.country_code}V","geo_continent_code":"%{geoip.continent_code}V","geo_region":"%{geoip.region}V","req_header_size":%{req.header_bytes_read}V,"req_body_size":%{req.body_bytes_read}V,"resp_header_size":%{resp.header_bytes_written}V,"resp_body_size":%{resp.body_bytes_written}V,"socket_cwnd":%{client.socket.cwnd}V,"socket_nexthop":"%{client.socket.nexthop}V","socket_tcpi_rcv_mss":%{client.socket.tcpi_rcv_mss}V,"socket_tcpi_snd_mss":%{client.socket.tcpi_snd_mss}V,"socket_tcpi_rtt":%{client.socket.tcpi_rtt}V,"socket_tcpi_rttvar":%{client.socket.tcpi_rttvar}V,"socket_tcpi_rcv_rtt":%{client.socket.tcpi_rcv_rtt}V,"socket_tcpi_rcv_space":%{client.socket.tcpi_rcv_space}V,"socket_tcpi_last_data_sent":%{client.socket.tcpi_last_data_sent}V,"socket_tcpi_total_retrans":%{client.socket.tcpi_total_retrans}V,"socket_tcpi_delta_retrans":%{client.socket.tcpi_delta_retrans}V,"socket_ploss":%{client.socket.ploss}V,"type":"request_logs","request_id":"%{req.http.x-request-id}V","waf_logged":"%{waf.logged}V","waf_block":"%{waf.blocked}V","waf_failures":"%{waf.failures}V","waf_rule_id":"%{waf.rule_id}V","waf_severity":"%{waf.severity}V","waf_passed":"%{waf.passed}V","waf_logdata":"%{cstr_escape(waf.logdata)}V","waf_executed":"%{waf.executed}V","waf_anomaly_score":"%{waf.anomaly_score}V","waf_sql_score":"%{waf.sql_injection_score}V","waf_rfi_score":"%{waf.rfi_score}V","waf_lfi_score":"%{waf.lfi_score}V","waf_xss_score":"%{waf.xss_score}V","waf_http_score":"%{waf.http_violation_score}V","waf_php_score":"%{waf.php_injection_score}V","waf_rce_score":"%{waf.rce_score}V","waf_session_fixation_score":"%{waf.session_fixation_score}V","waf_message":"%{cstr_escape(waf.message)}V"}
- Fastly ヘルプの「waf_debug_log」で説明しているように、curl を使用してログ エンドポイントで
waf_debug_log
サブルーティンを参照します。 - 1 つのリクエストをトラッキングするために request_id ヘッダを作成します。
ステップ 4: WAF デバッグ ログの収集
Fastly の Web アプリケーション ファイアウォール (WAF) がある場合は、Fastly で次のステップを実行してもう 1 つのログ エンドポイントを追加し、WAF リクエストを Sumo Logic に送信するように設定します。
- デバッグ ログ用にもう 1 つの HTTP Source を設定し、その Source Category を設定します。たとえば、fastly/debug です。Source に割り当てる Source Category を書き留めます。この Source Category 値は、Fastly アプリケーションをインストールするときに指定します。
- ステップ 2 の手順に従って Fastly でもう 1 つログ エンドポイントを作成しますが、下記の JSON を [Log format (ログ形式)] フィールドに入力します。
{"type":"debug_logs", "service_id":"%{req.service_id}V", "client_ip":"%{req.http.Fastly-Client-IP}V", "request":"%{req.request}V", "protocol":"%{req.proto}V", "origin_host":"%{req.http.Host}V", "url":"%{cstr_escape(req.url)}V", "request_referer":"%{cstr_escape(req.http.Referer)}V", "request_user_agent":"%{cstr_escape(req.http.User-Agent)}V", "request_accept_content":"%{cstr_escape(req.http.Accept)}V", "cache_status": "%{regsub(fastly_info.state, \"^(HIT-(SYNTH)|(HITPASS|HIT|MISS|PASS|ERROR|PIPE|NONE)).*\", \"\\2\\3\")}V", "geo_datacenter":"%{server.datacenter}V", "geo_city":"%{geoip.city}V", "geo_country_code":"%{geoip.country_code}V", "geo_continent_code": "%{geoip.continent_code}V", "geo_region":"%{geoip.region}V", "request_id":"%{req.http.x-request-id}V", "waf_logged":"%{waf.logged}V", "waf_block":"%{waf.blocked}V", "waf_failures":"%{waf.failures}V", "waf_rule_id":"%{waf.rule_id}V", "waf_severity":"%{waf.severity}V", "waf_passed":"%{waf.passed}V", "waf_logdata":"%{cstr_escape(waf.logdata)}V", "waf_executed":"%{waf.executed}V", "waf_anomaly_score":"%{waf.anomaly_score}V", "waf_sql_score":"%{waf.sql_injection_score}V", "waf_rfi_score":"%{waf.rfi_score}V", "waf_lfi_score":"%{waf.lfi_score}V", "waf_xss_score":"%{waf.xss_score}V", "waf_http_score":"%{waf.http_violation_score}V", "waf_php_score":"%{waf.php_injection_score}V", "waf_rce_score":"%{waf.rce_score}V", "waf_session_fixation_score":"%{waf.session_fixation_score}V", "waf_message":"%{cstr_escape(waf.message)}V" }
FER (Field Extraction Rules)
この FER (Field Extraction Rules) は、全体の parse 時間を削減するための例として提供されています。すべての parse オペレーションが FER でサポートされているわけではありません。詳細については、「FER (Field Extraction Rules) の作成」を参照してください。
parse "\"reqMethod\":\"*\"" as method, "\"status\":\"*\"" as status, "\"fwdHost\":\"*\"" as origin| parse "\"bytes\":\"*\"" as bytes, "\"edgeIP\":\"*\"" as edgeip, "\"country\":\"*\"" as country, "\"cookie\":\"*\"" as cookie
クエリのサンプル
エラーを起こしている上位の URL
_sourceCategory=fastly 50? | parse "\"reqPath\":\"*\"" as path, "\"status\":\"*\"" as status | urldecode(path) as path | where status > 499 | where status < 600 | count as errors by path | sort by errors
キャッシュのパフォーマンス
_sourceCategory=fastly cacheStatus | parse "\"cacheStatus\":\"*\"" as status | where !(status="") | if(status="0", "0 - Non cacheable", if(status="1" OR status="2", "1/2 - Cache Hit", if(status="3", "3 - Cache Miss", ""))) as cachestatus | count by cachestatus
ホスト別の上位の拒否
_sourceCategory=fastly waf denyRules reqHost | parse "\"denyRules\":\"*\"" as deny, "\"reqHost\":\"*\"" as host | where deny != "" | timeslice 1m | count by host, _timeslice | transpose row _timeslice column host