🪵

Cloud Logging 構造化ログの特別な JSON フィールドまとめ

2023/10/23に公開

Google Cloud のログ管理サービスである Cloud Logging は JSON で出力されたログを構造化ログとして認識します。その際に特別な JSON フィールドを使うとログに特別な属性を与える事ができます。本記事ではそれらの特別な JSON フィールドを用途ごとにまとめて紹介します。

本記事の技術的な内容はほぼすべてこのドキュメント 1 ページに書いてありますが、「実際に UI でどう表示されるのか」と「その特別な JSON フィールドにどんな価値があるのか」はドキュメントにないので参考にしていただけると思います。

Cloud Logging へのログ書き込み

Cloud Logging へログを書き込むには大きく 2 つの方法があります。APILogEntry を直接書き込むか、それ以外かです。

API で直接書き込む方法の場合、メジャーな言語であれば各言語のライブラリを使うことで実現できます。それ以外の方法では標準出力やファイルなどに 1 行 1 ログエントリとしてログを出力することで Cloud Logging にログを書き込みます。例えば Cloud Run で標準出力に次のような 2 行の出力があった場合、2 つの LogEntry が Cloud Logging に書き込まれます。

$ python main.py
この行が 1 つ目の LogEntry になる
この行が 2 つ目の LogEntry になる

本記事では後者の中でも構造化ログと呼ばれるものを対象とします。構造化ログは次のように 1 行にひとつの JSON オブジェクトが出力されるログのことです。

$ python main.py
{"text":"この JSON オブジェクトが 1 つ目の LogEntry になる"}
{"text":"この JSON オブジェクトが 2 つ目の LogEntry になる"}

Cloud Logging の仕組み

特別な JSON フィールドを紹介する前に「ログに特別な属性を与える」とはどういうことなのかを説明します。

次のスクリーンショットは Cloud Logging のコンソール画面です。

Cloud Logging UI

右下に表示されている 1 行 1 行がひとつのログエントリであり、API で google.logging.v2.LogEntry として定義されています。Cloud Logging では JSON でログを書き込めば jsonPayload フィールドにその JSON オブジェクトが格納された LogEntry が作成されます。これを構造化ログを呼びますが、出力する JSON に「特別な JSON フィールド」をもたせることで JSON から LogEntry のフィールドを操作できます。

例えば次のような JSON を出力します (見やすくしていますが実際は 1 行です。以降も見やすさのため改行を入れている場合があります)。

{
  "message": "log message",
  "key1": "value1",
  "logging.googleapis.com/labels": {
    "label1": "label-value-1",
    "label2": "label-value-2"
  }
}

すると LogEntry は次のようになります。

{
  jsonPayload: {
    key1: "value1",
    message: "log message"
  },
  labels: {
    label1: "label-value-1",
    label2: "label-value-2"
  }
}

このように JSON にある特定のフィールド名で値を設定すると、LogEntry のフィールドを設定できるようになっています。これを上では「ログに特別な属性を与える」と表現しました。

必ずおさえておきたい特別な JSON フィールド

まずは Google Cloud 上でアプリケーションを開発する際に必ず理解して使いこなしておきたい特別な JSON フィールドを紹介します。

message

message JSON フィールドに文字列を設定するとコンソール上でその文字列が表示されます。

message フィールドがない場合は JSON がすべて表示されます (スクリーンショットの一番上です)。

{"text":"Hello, Cloud Logging!","key1":"value1","key2":"value2"}

message-before

message フィールドがある場合はその値が表示されます。

{"message":"Hello, Cloud Logging!","key1":"value1","key2":"value2"}

message-after

message フィールドに関しては少し特殊で、必ず LogEntry のフィールドにマッピングされるというわけではありません。jsonPayloadmessage しかない場合は jsonPayloadtextPayload に変換され、その結果コンソールでの表示も変化します。それ以外の場合は LogEntry に変化はありません。

severity

severity JSON フィールドに LogSeverity 型 (Enum) を表す文字列を設定すると LogEntry の重大度を設定できます。LogSeverity には次の 9 種類があります。

名前 数値 意味
DEFAULT 0 重大度が設定されていない
DEBUG 100 デバッグまたはトレース情報
INFO 200 進行中のステータスやパフォーマンスなど日常的な情報
NOTICE 300 スタートアップ、シャットダウン、設定変更など平常だが大きなイベント
WARNING 400 問題を起こす可能性がある警告イベント
ERROR 500 問題を起こす可能性が高いエラーイベント
CRITICAL 600 より深刻な問題や機能停止を起こすクリティカルイベント
ALERT 700 すぐに人間がアクションを取る必要がある
EMERGENCY 800 一つ以上のシステムが利用できない

severity フィールドがない場合は DEFAULT が設定されます。

{"message":"Hello, Cloud Logging!","key1":"value1","key2":"value2"}

severity-before

severity フィールドがある場合は対応した LogSeverity が設定されます。

{"message":"Hello, Cloud Logging!","severity":"ERROR","key1":"value1"}

severity-after

コンソールでは次のスクリーンショットのように LogSeverity によってアイコンが異なり視認しやすくなります。DEFAULT を除く LogSeverity が 8 種類あるのに対してアイコンは 5 種類しかないため、LogSeverity によっては同じアイコンが使用されます。

severity-icons

LogSeverity を設定しておくと Log fields ペインで LogSeverity によるフィルタリングができます。ワンクリックでエラーログのみを表示するといったことが可能です。

severity-log-fields

LogSeverity にはそれぞれ数値が設定されており大小で比較できます。次のようなクエリが可能です。

severity >= WARNING AND severity <= ALERT

severity-query

LogSeverity は 9 種類すべてを使う必要はなく、チームでどの LogSeverity をどのような基準で使うかを決めておくといいでしょう。アイコンで区別できる 5 種類を選択するぐらいがよさそうです。

time

time JSON フィールドに RFC3339 フォーマットの日付を設定すると LogEntry の timestamp を設定できます。

次の例は 30 分未来の time を設定したときの結果です。timestampreceiveTimestamp の 30 分未来に設定されています。receiveTimestamp は出力専用フィールドで Cloud Logging がログを受信したタイムスタンプです。

{
  "message": "Hello, Cloud Logging! with time",
  "severity": "INFO",
  "time": "2023-10-14T07:53:13.000000000Z",
  "key1": "value1"
}

time

同じく timestamp を設定するための特別な JSON フィールドとして timestamp フィールドや timestampSeconds / timestampNanos フィールドがありますが使い勝手が悪いため本記事では割愛します。

timestamp は自動で設定されるため必須のフィールドではありませんが、多くのログライブラリは時刻を出力できるので time JSON フィールドにあわせてフォーマットを設定しておくといいでしょう。

sourceLocation

logging.googleapis.com/sourceLocation JSON フィールドで LogEntry に関連するソースコードの位置情報を設定できます。位置情報は LogEntrySourceLocation 型で設定します。

{
  "message": "Hello, Cloud Logging! with sourceLocation",
  "severity": "INFO",
  "key1": "value1",
  "logging.googleapis.com/sourceLocation": {
    "file": "main.rb",
    "line": "85",
    "function": "in `some_func'"
  }
}

sourceLocation

sourceLocation を設定しておくことでそのログを出力したコードに素早くたどり着けるようになります。

trace、spanId、traceSampled

特別な JSON フィールドを使って LogEntry を Cloud Trace の Trace や Span と紐付けることができます。次の 3 つのフィールドがあります。

  • logging.googleapis.com/trace: "projects/{projectId}/traces/{traceId}" を設定することで Trace と紐付ける
  • logging.googleapis.com/spanId: "{spanId}" を設定することで Span と紐付ける
  • logging.googleapis.com/trace_sampled: boolean[1]
{
  "message": "Hello, Cloud Logging! with trace",
  "severity": "INFO",
  "key1": "value1",
  "logging.googleapis.com/trace": "projects/glass-archway-401508/traces/0b46338eb49895d2d02ab16ed740197c",
  "logging.googleapis.com/spanId": "04be1f2f17504cc4",
  "logging.googleapis.com/trace_sampled": true
}

trace-log

ログメッセージの先頭に表示されている Cloud Trace のアイコンをクリックすることで同じ Trace に紐づくログのみを表示したり、次のスクリーンショットのように Trace を表示できます。

trace-logging-to-trace

また、Cloud Trace からその Trace や Span に紐づくログを表示できます。

trace-trace-to-logging

従来は Request ID などを使ってひとつのリクエストに関するログの追跡をしていましたが、Google Cloud では多くのサービスが Cloud Trace と連携できるようになっているのでログに関しても Cloud Trace と紐づくようにこれらの特別な JSON フィールドを設定しておくといいでしょう。

stack_trace

stack_trace JSON フィールドにスタックトレースがあると Error Reporting にエラーとして報告されます。エラーとして報告するためには Severity が DEFAULT または ERROR 以上である必要があります[2]

{
  "message": "some error",
  "severity": "ERROR",
  "key1": "value1",
  "stack_trace": "some error\nmain.rb:117:in `some_error_func'\nmain.rb:122:in `block in <main>'\n/usr/local/bundle/gems/sinatra-3.1.0/lib/sinatra/base.rb:1763:in `call'\n/usr/local/bundle/gems/sinatra-3.1.0/lib/sinatra/base.rb:1763:in `block in compile!'\n/usr/local/bundle/gems/sinatra-3.1.0/lib/sinatra/base.rb:1066:in `block (3 levels) in route!'\n/usr/local/bundle/gems/sinatra-3.1.0/lib/sinatra/base.rb:1084:in `route_eval'\n/usr/local/bundle/gems/sinatra-3.1.0/lib/sinatra/base.rb:1066:in `block (2 levels) in route!'\n/usr/local/bundle/gems/sinatra-3.1.0/lib/sinatra/base.rb:1115:in `block in process_route'\n/usr/local/bundle/gems/sinatra-3.1.0/lib/sinatra/base.rb:1113:in `catch'\n/usr/local/bundle/gems/sinatra-3.1.0/lib/sinatra/base.rb:1113:in `process_route'\n/usr/local/bundle/gems/sinatra-3.1.0/lib/sinatra/base.rb:1064:in `block in route!'\n/usr/local/bundle/gems/sinatra-3.1.0/lib/sinatra/base.rb:1061:in `each'\n/usr/local/bundle/gems/sinatra-3.1.0/lib/sinatra/base.rb:1061:in `route!'\n/usr/local/bundle/gems/sinatra-3.1.0/lib/sinatra/base.rb:1185:in `block in dispatch!'\n/usr/local/bundle/gems/sinatra-3.1.0/lib/sinatra/base.rb:1156:in `catch'\n/usr/local/bundle/gems/sinatra-3.1.0/lib/sinatra/base.rb:1156:in `invoke'\n/usr/local/bundle/gems/sinatra-3.1.0/lib/sinatra/base.rb:1180:in `dispatch!'\n/usr/local/bundle/gems/sinatra-3.1.0/lib/sinatra/base.rb:996:in `block in call!'\n/usr/local/bundle/gems/sinatra-3.1.0/lib/sinatra/base.rb:1156:in `catch'\n/usr/local/bundle/gems/sinatra-3.1.0/lib/sinatra/base.rb:1156:in `invoke'\n/usr/local/bundle/gems/sinatra-3.1.0/lib/sinatra/base.rb:996:in `call!'\n/usr/local/bundle/gems/sinatra-3.1.0/lib/sinatra/base.rb:985:in `call'\n/usr/local/bundle/gems/rack-protection-3.1.0/lib/rack/protection/xss_header.rb:20:in `call'\n/usr/local/bundle/gems/rack-protection-3.1.0/lib/rack/protection/path_traversal.rb:18:in `call'\n/usr/local/bundle/gems/rack-protection-3.1.0/lib/rack/protection/json_csrf.rb:28:in `call'\n/usr/local/bundle/gems/rack-protection-3.1.0/lib/rack/protection/base.rb:53:in `call'\n/usr/local/bundle/gems/rack-protection-3.1.0/lib/rack/protection/base.rb:53:in `call'\n/usr/local/bundle/gems/rack-protection-3.1.0/lib/rack/protection/frame_options.rb:33:in `call'\n/usr/local/bundle/gems/rack-2.2.8/lib/rack/null_logger.rb:11:in `call'\n/usr/local/bundle/gems/rack-2.2.8/lib/rack/head.rb:12:in `call'\n/usr/local/bundle/gems/rack-2.2.8/lib/rack/method_override.rb:24:in `call'\n/usr/local/bundle/gems/sinatra-3.1.0/lib/sinatra/base.rb:219:in `call'\n/usr/local/bundle/gems/sinatra-3.1.0/lib/sinatra/base.rb:2074:in `call'\n/usr/local/bundle/gems/sinatra-3.1.0/lib/sinatra/base.rb:1633:in `block in call'\n/usr/local/bundle/gems/sinatra-3.1.0/lib/sinatra/base.rb:1849:in `synchronize'\n/usr/local/bundle/gems/sinatra-3.1.0/lib/sinatra/base.rb:1633:in `call'\n/usr/local/bundle/gems/rack-2.2.8/lib/rack/handler/webrick.rb:95:in `service'\n/usr/local/bundle/gems/webrick-1.8.1/lib/webrick/httpserver.rb:140:in `service'\n/usr/local/bundle/gems/webrick-1.8.1/lib/webrick/httpserver.rb:96:in `run'\n/usr/local/bundle/gems/webrick-1.8.1/lib/webrick/server.rb:310:in `block in start_thread'"
}

stack-trace-log

ログメッセージの先頭に Error Reporting のアイコンが表示され、クリックすると同じエラーグループのログを表示したり、次のスクリーンショットのような Error Reporting のコンソールにジャンプしたりできます。

stack-trace-error-reporting

上記 JSON の stack_trace フィールドの値を抜き出すとこうなっています。

some error
main.rb:117:in `some_error_func'
main.rb:122:in `block in <main>'
/usr/local/bundle/gems/sinatra-3.1.0/lib/sinatra/base.rb:1763:in `call'
/usr/local/bundle/gems/sinatra-3.1.0/lib/sinatra/base.rb:1763:in `block in compile!'
/usr/local/bundle/gems/sinatra-3.1.0/lib/sinatra/base.rb:1066:in `block (3 levels) in route!'
/usr/local/bundle/gems/sinatra-3.1.0/lib/sinatra/base.rb:1084:in `route_eval'
/usr/local/bundle/gems/sinatra-3.1.0/lib/sinatra/base.rb:1066:in `block (2 levels) in route!'
/usr/local/bundle/gems/sinatra-3.1.0/lib/sinatra/base.rb:1115:in `block in process_route'
/usr/local/bundle/gems/sinatra-3.1.0/lib/sinatra/base.rb:1113:in `catch'
/usr/local/bundle/gems/sinatra-3.1.0/lib/sinatra/base.rb:1113:in `process_route'
/usr/local/bundle/gems/sinatra-3.1.0/lib/sinatra/base.rb:1064:in `block in route!'
/usr/local/bundle/gems/sinatra-3.1.0/lib/sinatra/base.rb:1061:in `each'
/usr/local/bundle/gems/sinatra-3.1.0/lib/sinatra/base.rb:1061:in `route!'
/usr/local/bundle/gems/sinatra-3.1.0/lib/sinatra/base.rb:1185:in `block in dispatch!'
/usr/local/bundle/gems/sinatra-3.1.0/lib/sinatra/base.rb:1156:in `catch'
/usr/local/bundle/gems/sinatra-3.1.0/lib/sinatra/base.rb:1156:in `invoke'
/usr/local/bundle/gems/sinatra-3.1.0/lib/sinatra/base.rb:1180:in `dispatch!'
/usr/local/bundle/gems/sinatra-3.1.0/lib/sinatra/base.rb:996:in `block in call!'
/usr/local/bundle/gems/sinatra-3.1.0/lib/sinatra/base.rb:1156:in `catch'
/usr/local/bundle/gems/sinatra-3.1.0/lib/sinatra/base.rb:1156:in `invoke'
/usr/local/bundle/gems/sinatra-3.1.0/lib/sinatra/base.rb:996:in `call!'
/usr/local/bundle/gems/sinatra-3.1.0/lib/sinatra/base.rb:985:in `call'
/usr/local/bundle/gems/rack-protection-3.1.0/lib/rack/protection/xss_header.rb:20:in `call'
/usr/local/bundle/gems/rack-protection-3.1.0/lib/rack/protection/path_traversal.rb:18:in `call'
/usr/local/bundle/gems/rack-protection-3.1.0/lib/rack/protection/json_csrf.rb:28:in `call'
/usr/local/bundle/gems/rack-protection-3.1.0/lib/rack/protection/base.rb:53:in `call'
/usr/local/bundle/gems/rack-protection-3.1.0/lib/rack/protection/base.rb:53:in `call'
/usr/local/bundle/gems/rack-protection-3.1.0/lib/rack/protection/frame_options.rb:33:in `call'
/usr/local/bundle/gems/rack-2.2.8/lib/rack/null_logger.rb:11:in `call'
/usr/local/bundle/gems/rack-2.2.8/lib/rack/head.rb:12:in `call'
/usr/local/bundle/gems/rack-2.2.8/lib/rack/method_override.rb:24:in `call'
/usr/local/bundle/gems/sinatra-3.1.0/lib/sinatra/base.rb:219:in `call'
/usr/local/bundle/gems/sinatra-3.1.0/lib/sinatra/base.rb:2074:in `call'
/usr/local/bundle/gems/sinatra-3.1.0/lib/sinatra/base.rb:1633:in `block in call'
/usr/local/bundle/gems/sinatra-3.1.0/lib/sinatra/base.rb:1849:in `synchronize'
/usr/local/bundle/gems/sinatra-3.1.0/lib/sinatra/base.rb:1633:in `call'
/usr/local/bundle/gems/rack-2.2.8/lib/rack/handler/webrick.rb:95:in `service'
/usr/local/bundle/gems/webrick-1.8.1/lib/webrick/httpserver.rb:140:in `service'
/usr/local/bundle/gems/webrick-1.8.1/lib/webrick/httpserver.rb:96:in `run'
/usr/local/bundle/gems/webrick-1.8.1/lib/webrick/server.rb:310:in `block in start_thread'

これは Ruby のスタックトレースですが、Java、Python、JavaScript、Ruby、C#、PHP、Go に対応しています。各言語のフォーマットなどの詳細はドキュメントを参照してください。

stack_trace フィールドの 1 行目をエラーメッセージにしておくと Error Reporting がそれをエラーメッセージとして扱います。また、1 行目を error message (FOO) のようにしておくとカッコ内の文字が抽出されて FOO: error message のように表示されます。例えば "Runtime Error some error (#{severity})" と出力するようにしておくと次のように表示されます。

stack-trace-severity

stack_trace JSON フィールドは他のフィールドと異なり LogEntry を操作しません。かわりに Error Reporting の ReportedErrorEventレポートします。stack_trace フィールドの値は次のように ErrorEventmessage フィールドに格納されます。

{
  "errorEvents": [
    {
      "eventTime": "2023-10-21T03:36:56.426003Z",
      "serviceContext": {
        "service": "cloud-logging",
        "version": "cloud-logging-00021-4n9",
        "resourceType": "cloud_run_revision"
      },
      "message": "RuntimeError some error (ERROR)\nmain.rb:117:in `some_error_func'\nmain.rb:123:in `block in \u003cmain\u003e'\n/usr/local/bundle/gems/sinatra-3.1.0/lib/sinatra/base.rb:1763:in `call'\n/usr/local/bundle/gems/sinatra-3.1.0/lib/sinatra/base.rb:1763:in `block in compile!'\n/usr/local/bundle/gems/sinatra-3.1.0/lib/sinatra/base.rb:1066:in `block (3 levels) in route!'\n/usr/local/bundle/gems/sinatra-3.1.0/lib/sinatra/base.rb:1084:in `route_eval'\n/usr/local/bundle/gems/sinatra-3.1.0/lib/sinatra/base.rb:1066:in `block (2 levels) in route!'\n/usr/local/bundle/gems/sinatra-3.1.0/lib/sinatra/base.rb:1115:in `block in process_route'\n/usr/local/bundle/gems/sinatra-3.1.0/lib/sinatra/base.rb:1113:in `catch'\n/usr/local/bundle/gems/sinatra-3.1.0/lib/sinatra/base.rb:1113:in `process_route'\n/usr/local/bundle/gems/sinatra-3.1.0/lib/sinatra/base.rb:1064:in `block in route!'\n/usr/local/bundle/gems/sinatra-3.1.0/lib/sinatra/base.rb:1061:in `each'\n/usr/local/bundle/gems/sinatra-3.1.0/lib/sinatra/base.rb:1061:in `route!'\n/usr/local/bundle/gems/sinatra-3.1.0/lib/sinatra/base.rb:1185:in `block in dispatch!'\n/usr/local/bundle/gems/sinatra-3.1.0/lib/sinatra/base.rb:1156:in `catch'\n/usr/local/bundle/gems/sinatra-3.1.0/lib/sinatra/base.rb:1156:in `invoke'\n/usr/local/bundle/gems/sinatra-3.1.0/lib/sinatra/base.rb:1180:in `dispatch!'\n/usr/local/bundle/gems/sinatra-3.1.0/lib/sinatra/base.rb:996:in `block in call!'\n/usr/local/bundle/gems/sinatra-3.1.0/lib/sinatra/base.rb:1156:in `catch'\n/usr/local/bundle/gems/sinatra-3.1.0/lib/sinatra/base.rb:1156:in `invoke'\n/usr/local/bundle/gems/sinatra-3.1.0/lib/sinatra/base.rb:996:in `call!'\n/usr/local/bundle/gems/sinatra-3.1.0/lib/sinatra/base.rb:985:in `call'\n/usr/local/bundle/gems/rack-protection-3.1.0/lib/rack/protection/xss_header.rb:20:in `call'\n/usr/local/bundle/gems/rack-protection-3.1.0/lib/rack/protection/path_traversal.rb:18:in `call'\n/usr/local/bundle/gems/rack-protection-3.1.0/lib/rack/protection/json_csrf.rb:28:in `call'\n/usr/local/bundle/gems/rack-protection-3.1.0/lib/rack/protection/base.rb:53:in `call'\n/usr/local/bundle/gems/rack-protection-3.1.0/lib/rack/protection/base.rb:53:in `call'\n/usr/local/bundle/gems/rack-protection-3.1.0/lib/rack/protection/frame_options.rb:33:in `call'\n/usr/local/bundle/gems/rack-2.2.8/lib/rack/null_logger.rb:11:in `call'\n/usr/local/bundle/gems/rack-2.2.8/lib/rack/head.rb:12:in `call'\n/usr/local/bundle/gems/rack-2.2.8/lib/rack/method_override.rb:24:in `call'\n/usr/local/bundle/gems/sinatra-3.1.0/lib/sinatra/base.rb:219:in `call'\n/usr/local/bundle/gems/sinatra-3.1.0/lib/sinatra/base.rb:2074:in `call'\n/usr/local/bundle/gems/sinatra-3.1.0/lib/sinatra/base.rb:1633:in `block in call'\n/usr/local/bundle/gems/sinatra-3.1.0/lib/sinatra/base.rb:1849:in `synchronize'\n/usr/local/bundle/gems/sinatra-3.1.0/lib/sinatra/base.rb:1633:in `call'\n/usr/local/bundle/gems/rack-2.2.8/lib/rack/handler/webrick.rb:95:in `service'\n/usr/local/bundle/gems/webrick-1.8.1/lib/webrick/httpserver.rb:140:in `service'\n/usr/local/bundle/gems/webrick-1.8.1/lib/webrick/httpserver.rb:96:in `run'\n/usr/local/bundle/gems/webrick-1.8.1/lib/webrick/server.rb:310:in `block in start_thread'"
    }
  ],
  "timeRangeBegin": "2023-10-14T04:00:51Z"
}

この方法は stack_trace JSON フィールドだけでなく、exceptionmessage フィールドがスタックトレースを含む場合でも同様に動作します。他にも細かい使い方がありますが、詳細は次のドキュメントを参照してください。

ログでエラーをフォーマットする  |  Error Reporting  |  Google Cloud

便利に使える特別な JSON フィールド

必須ではないが便利に使える特別な JSON フィールドを紹介します。

labels

logging.googleapis.com/labels JSON フィールドに任意のキー・バリューマップを設定すると、それを LogEntry の labels に設定できます。キー・バリューはどちらも文字列です。

{
  "message": "Hello, Cloud Logging! with labels",
  "severity": "INFO",
  "key1": "value1",
  "logging.googleapis.com/labels": {
    "label1": "value1",
    "label2": "value2"
  }
}

labels-log

LogEntry の labels フィールドは Google Cloud のシステム側でも利用されるため、開発者が設定したものとシステムが設定したものが混在する形になります。

jsonPayload にも任意のキー・バリューは設定できますが、アプリケーションで共通のものやユーザー情報などを設定しておくとログをクエリするときなどに便利です。

httpRequest

httpRequest JSON フィールドを使うと LogEntry の httpRequest フィールドを設定できます。次のように HttpRequest 型の値を用います。

{
  "message": "Hello, Cloud Logging! with httpRequest",
  "severity": "INFO",
  "key1": "value1",
  "httpRequest": {
    "requestMethod": "GET",
    "requestUrl": "https://cloud-logging-vnt56eluaq-uc.a.run.app/http_request",
    "requestSize": "123",
    "status": 200,
    "responseSize": "456",
    "userAgent": "curl/7.81.0",
    "remoteIp": "169.254.1.1",
    "serverIp": "172.0.0.1",
    "latency": "3.5s",
    "cacheLookup": false,
    "cacheHit": false,
    "cacheValidatedWithOriginServer": false,
    "cacheFillBytes": "0",
    "protocol": "HTTP/1.1"
  }
}

http-request-log

httpRequest を設定するとスクリーンショットのように HTTP メソッドやステータスコード、ユーザーエージェントなどが視認しやすくなります。これらをクリックするとマッチするログだけをフィルタリング可能です。また、リクエスト URL がメッセージとして表示されます。

アプリケーションでアクセスログなど出力する場合に利用すると視認性やクエリ効率性の向上が期待できます。HttpRequest には不必要なフィールドも多いのでアプリケーションレイヤーのアクセスログとしては必要なフィールドのみを使うことになるでしょう。

出番があまりなさそうな特別な JSON フィールド

以降の特別な JSON フィールドはあまり使い所がなさそうなので詳細な説明は省略します。

insertId

logging.googleapis.com/insertId JSON フィールドを使うと LogEntry の insertId フィールドを設定できます。timestampinsertId どちらも同じ LogEntry が複数存在すると、それらは重複しているとみなされてクエリ結果でひとつになります。ただし、必ず重複排除されるわけではありません。

operation

logging.googleapis.com/operation JSON フィールドを使うと LogEntry の operation フィールドを設定できます。長時間実行されるようなオペレーションのログを表現するためのフィールドですが、Cloud Logging での特別扱いもなく、オペレーションのトラッキングにも Cloud Tracing のフィールドを使うのが良いでしょう。次のような LogEntryOperation 型の値を用います。

{
  "id": string,
  "producer": string,
  "first": boolean,
  "last": boolean
}

おわりに

本記事では Cloud Logging 構造化ログの特別な JSON フィールドとそのフィールドにどんな価値がありどのように表示されるのかを紹介しました。
他にもこういう使い方をすると便利ですよという使い方があればぜひ教えてください。

本記事の内容の一部は Encraft #7 AppDev with Google Cloud で発表しているので興味があればそちらも参照してください。

最後に、ナレッジワークではログや Observability にこだわりのあるソフトウェアエンジニアや SRE を絶賛募集しています。

https://kwork.studio/recruit-engineer

まずはお気軽にカジュアル面談も大歓迎です。

https://kitene.in/recruit-detail/1697865081929x220559030949249020

脚注
  1. Trace Context ↩︎

  2. ERROR 未満でもエラーを報告する方法はあります。必要な場合はドキュメントを参照してください。 ↩︎

GitHubで編集を提案

Discussion