Webhook を実装する

このガイドでは、Webhook を実装するためのさまざまなサンプルと、Webhook のトラブルシューティングに関する推奨事項について説明します。

セッション パラメータを設定する

以下のサンプルは、セッション パラメータを設定する方法を示しています。

Go

Dialogflow への認証を行うには、アプリケーションのデフォルト認証情報を設定します。詳細については、ローカル開発環境の認証の設定をご覧ください。

Webhook クイックスタートをご覧ください。

Java

Dialogflow への認証を行うには、アプリケーションのデフォルト認証情報を設定します。詳細については、ローカル開発環境の認証の設定をご覧ください。


// TODO: Change class name to Example
// TODO: Uncomment the line below before running cloud function
// package com.example;

import com.google.cloud.functions.HttpFunction;
import com.google.cloud.functions.HttpRequest;
import com.google.cloud.functions.HttpResponse;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.JsonObject;
import java.io.BufferedWriter;

public class WebhookConfigureSessionParameters implements HttpFunction {
  @Override
  public void service(HttpRequest request, HttpResponse response) throws Exception {
    JsonObject orderParameter = new JsonObject();
    orderParameter.addProperty("order_number", "12345");

    JsonObject parameterObject = new JsonObject();
    parameterObject.add("parameters", orderParameter);

    // Creates webhook response object
    JsonObject webhookResponse = new JsonObject();
    webhookResponse.add("session_info", parameterObject);

    Gson gson = new GsonBuilder().setPrettyPrinting().create();
    String jsonResponseObject = gson.toJson(webhookResponse);

    /** { "session_info": { "parameters": { "order_number": "12345" } } } */
    BufferedWriter writer = response.getWriter();
    // Sends the webhookResponseObject
    writer.write(jsonResponseObject.toString());
  }
}

Node.js

Dialogflow への認証を行うには、アプリケーションのデフォルト認証情報を設定します。詳細については、ローカル開発環境の認証の設定をご覧ください。

const functions = require('@google-cloud/functions-framework');

functions.http('configureSessionParams', (request, response) => {
  // Session parameter configured by the webhook
  const orderNumber = 123;

  const jsonResponse = {
    sessionInfo: {
      parameters: {
        orderNumber: orderNumber,
      },
    },
  };

  response.send(jsonResponse);
});

Python

Dialogflow への認証を行うには、アプリケーションのデフォルト認証情報を設定します。詳細については、ローカル開発環境の認証の設定をご覧ください。

import functions_framework

# TODO (developer): change entry point to configure_session_params in Cloud Function


@functions_framework.http
def configure_session_params(request):
    """Webhook to validate or configure new session parameters."""

    order_number = 123

    json_response = {
        "sessionInfo": {
            "parameters": {
                "orderNumber": order_number,
            },
        },
    }

    return json_response

フルフィルメント レスポンスを返す

次のサンプルは、フルフィルメント レスポンスを返す方法を示しています。

Go

Dialogflow への認証を行うには、アプリケーションのデフォルト認証情報を設定します。詳細については、ローカル開発環境の認証の設定をご覧ください。

Webhook クイックスタートをご覧ください。

Java

Dialogflow への認証を行うには、アプリケーションのデフォルト認証情報を設定します。詳細については、ローカル開発環境の認証の設定をご覧ください。


// TODO: Change class name to Example
// TODO: add GSON dependency to Pom file
// (https://mvnrepository.com/artifact/com.google.code.gson/gson/2.8.5)
// TODO: Uncomment the line bellow before running cloud function
// package com.example;

import com.google.cloud.functions.HttpFunction;
import com.google.cloud.functions.HttpRequest;
import com.google.cloud.functions.HttpResponse;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.JsonObject;
import com.google.gson.JsonParser;
import java.io.BufferedWriter;

public class BasicWebhook implements HttpFunction {
  @Override
  public void service(HttpRequest request, HttpResponse response) throws Exception {
    Gson gson = new GsonBuilder().create();
    JsonObject parsedRequest = gson.fromJson(request.getReader(), JsonObject.class);

    // For more information on the structure of this object https://cloud.google.com/dialogflow/cx/docs/reference/rest/v3/Fulfillment
    String requestTag = parsedRequest.getAsJsonObject("fulfillmentInfo")
        .getAsJsonPrimitive("tag").toString();
    JsonObject responseObject = null;
    String defaultIntent = "\"Default Welcome Intent\"";
    String secondIntent = "\"get-agent-name\"";
    String responseText = "";

    // Compares the Intent Tag to provide the correct response 
    if (requestTag.equals(defaultIntent)) {
      responseText = "\"Hello from a Java GCF Webhook\"";
    } else if (requestTag.equals(secondIntent)) {
      responseText = "\"My name is Flowhook\"";
    } else {
      responseText = "\"Sorry I didn't get that\"";
    }

    // Constructing the response jsonObject 
    responseObject =
        JsonParser
            .parseString(
                "{ \"fulfillment_response\": { \"messages\": [ { \"text\": { \"text\": ["
                    + responseText
                    + "] } } ] } }")
            .getAsJsonObject();
    BufferedWriter writer = response.getWriter();

    //Sends the responseObject
    writer.write(responseObject.toString());
  }
}

Node.js

Dialogflow への認証を行うには、アプリケーションのデフォルト認証情報を設定します。詳細については、ローカル開発環境の認証の設定をご覧ください。

const functions = require('@google-cloud/functions-framework');

functions.http('handleWebhook', (request, response) => {
  const tag = request.body.fulfillmentInfo.tag;
  let text = '';

  if (tag === 'Default Welcome Intent') {
    text = 'Hello from a GCF Webhook';
  } else if (tag === 'get-name') {
    text = 'My name is Flowhook';
  } else {
    text = `There are no fulfillment responses defined for "${tag}"" tag`;
  }

  const jsonResponse = {
    fulfillment_response: {
      messages: [
        {
          text: {
            //fulfillment text response to be sent to the agent
            text: [text],
          },
        },
      ],
    },
  };

  response.send(jsonResponse);
});

Python

Dialogflow への認証を行うには、アプリケーションのデフォルト認証情報を設定します。詳細については、ローカル開発環境の認証の設定をご覧ください。

import functions_framework

# TODO(developer): change entry point to handle_webhook in cloud function


@functions_framework.http
def handle_webhook(request):
    req = request.get_json()

    tag = req["fulfillmentInfo"]["tag"]

    if tag == "Default Welcome Intent":
        text = "Hello from a GCF Webhook"
    elif tag == "get-name":
        text = "My name is Flowhook"
    else:
        text = f"There are no fulfillment responses defined for {tag} tag"

    # You can also use the google.cloud.dialogflowcx_v3.types.WebhookRequest protos instead of manually writing the json object
    # Please see https://googleapis.dev/python/dialogflow/latest/dialogflow_v2/types.html?highlight=webhookresponse#google.cloud.dialogflow_v2.types.WebhookResponse for an overview
    res = {"fulfillment_response": {"messages": [{"text": {"text": [text]}}]}}

    # Returns json
    return res

必要に応じてフォーム パラメータを設定する

次のサンプルは、パラメータに必須のフラグを付ける方法を示しています。

Java

Dialogflow への認証を行うには、アプリケーションのデフォルト認証情報を設定します。詳細については、ローカル開発環境の認証の設定をご覧ください。


// TODO: Change class name to Example
// TODO: Uncomment the line below before running cloud function
// package com.example;

import com.google.cloud.functions.HttpFunction;
import com.google.cloud.functions.HttpRequest;
import com.google.cloud.functions.HttpResponse;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.JsonArray;
import com.google.gson.JsonObject;
import java.io.BufferedWriter;

public class ConfigureWebhookToSetFormParametersAsOptionalOrRequired implements HttpFunction {
  @Override
  public void service(HttpRequest request, HttpResponse response) throws Exception {
    JsonObject parameterObject = new JsonObject();
    parameterObject.addProperty("display_name", "order_number");
    parameterObject.addProperty("required", "true");
    parameterObject.addProperty("state", "VALID");

    JsonArray parameterInfoList = new JsonArray();
    parameterInfoList.add(parameterObject);

    JsonObject parameterInfoObject = new JsonObject();
    parameterInfoObject.add("parameter_info", parameterInfoList);

    JsonObject formInfo = new JsonObject();
    formInfo.add("form_info", parameterInfoObject);

    // Constructs the webhook response object
    JsonObject webhookResponse = new JsonObject();
    webhookResponse.add("page_info", formInfo);

    Gson gson = new GsonBuilder().setPrettyPrinting().create();
    String jsonResponseObject = gson.toJson(webhookResponse);

    /* {
     *   "page_info": {
     *     "form_info": {
     *       "parameter_info": [
     *         {
     *           "display_name": "order_number",
     *           "required": "true",
     *           "state": "VALID"
     *         }
     *       ]
     *     }
     *   }
     * }
     */

    BufferedWriter writer = response.getWriter();

    // Sends the responseObject
    writer.write(jsonResponseObject.toString());
  }
}

Node.js

Dialogflow への認証を行うには、アプリケーションのデフォルト認証情報を設定します。詳細については、ローカル開発環境の認証の設定をご覧ください。

const functions = require('@google-cloud/functions-framework');

functions.http('configureOptionalFormParam', (request, response) => {
  // The value of the parameter that the webhook will set as optional or required.
  // Note that the webhook cannot add or remove any form parameter

  const jsonResponse = {
    pageInfo: {
      formInfo: {
        parameterInfo: [
          {
            displayName: 'order-number',
            // if required: false, the agent will not reprompt for this parameter, even if the state is 'INVALID'
            required: true,
            state: 'VALID',
          },
        ],
      },
    },
  };

  // Info about form parameter that is sent in the webhook response:
  console.log(
    'Parameter Info: \n',
    jsonResponse.pageInfo.formInfo.parameterInfo[0]
  );

  response.send(jsonResponse);
});

フォーム パラメータを検証する

次のサンプルは、フォーム パラメータを検証する方法を示しています。

Java

Dialogflow への認証を行うには、アプリケーションのデフォルト認証情報を設定します。詳細については、ローカル開発環境の認証の設定をご覧ください。


// TODO: Change class name to Example
// TODO: Uncomment the line below before running cloud function
// package com.example;

import com.google.cloud.functions.HttpFunction;
import com.google.cloud.functions.HttpRequest;
import com.google.cloud.functions.HttpResponse;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.JsonArray;
import com.google.gson.JsonObject;
import java.io.BufferedWriter;

public class WebhookValidateFormParameter implements HttpFunction {
  @Override
  public void service(HttpRequest request, HttpResponse response) throws Exception {
    JsonObject sessionInfo = new JsonObject();
    JsonObject sessionParameter = new JsonObject();

    sessionParameter.addProperty("order_number", "null");
    sessionInfo.add("parameters", sessionParameter);

    JsonObject parameterObject = new JsonObject();
    parameterObject.addProperty("display_name", "order_number");
    parameterObject.addProperty("required", "true");
    parameterObject.addProperty("state", "INVALID");
    parameterObject.addProperty("value", "123");

    JsonArray parameterInfoList = new JsonArray();
    parameterInfoList.add(parameterObject);

    JsonObject parameterInfoObject = new JsonObject();
    parameterInfoObject.add("parameter_info", parameterInfoList);

    JsonObject pageInfo = new JsonObject();
    pageInfo.add("form_info", parameterInfoObject);

    // Constructs the webhook response object
    JsonObject webhookResponse = new JsonObject();
    webhookResponse.add("page_info", pageInfo);
    webhookResponse.add("session_info", sessionInfo);

    Gson gson = new GsonBuilder().setPrettyPrinting().create();
    String jsonResponseObject = gson.toJson(webhookResponse);

    /**
     * { "page_info": { "form_info": { "parameter_info": [ { "display_name": "order_number",
     * "required": "true", "state": "INVALID", "value": "123" } ] } }, "session_info": {
     * "parameters": { "order_number": "null" } } }
     */
    BufferedWriter writer = response.getWriter();

    // Sends the responseObject
    writer.write(jsonResponseObject.toString());
  }
}

Node.js

Dialogflow への認証を行うには、アプリケーションのデフォルト認証情報を設定します。詳細については、ローカル開発環境の認証の設定をご覧ください。

const functions = require('@google-cloud/functions-framework');

functions.http('validateParameter', (request, response) => {
  // Webhook will validate or invalidate parameter based on logic configured by the user.
  // Access parameter values through the webhook request via `request.body.pageInfo.formInfo.parameterInfo[]`
  const jsonResponse = {
    page_info: {
      form_info: {
        parameter_info: [
          {
            displayName: 'orderNumber',
            required: true,
            state: 'INVALID',
            value: 123,
          },
        ],
      },
    },
    sessionInfo: {
      parameters: {
        // Set session parameter to null if the form parameter is 'INVALID' and your agent needs to reprompt the user
        orderNumber: null,
      },
    },
  };

  response.send(jsonResponse);
});

Python

Dialogflow への認証を行うには、アプリケーションのデフォルト認証情報を設定します。詳細については、ローカル開発環境の認証の設定をご覧ください。

import functions_framework


@functions_framework.http
def validate_parameter(request):
    """Webhook will validate or invalidate parameter based on logic configured by the user."""
    return {
        "page_info": {
            "form_info": {
                "parameter_info": [
                    {
                        "displayName": "orderNumber",
                        "required": True,
                        "state": "INVALID",
                        "value": 123,
                    },
                ],
            },
        },
        "sessionInfo": {
            "parameters": {
                # Set session parameter to None if the form parameter is 'INVALID' and your agent needs to reprompt the user
                "orderNumber": None,
            },
        },
    }

ログセッション ID

次のサンプルは、Webhook リクエストの session ID をログに記録する方法を示しています。

Python

Dialogflow への認証を行うには、アプリケーションのデフォルト認証情報を設定します。詳細については、ローカル開発環境の認証の設定をご覧ください。


import re

import functions_framework


@functions_framework.http
def log_session_id_for_troubleshooting(request):
    """Webhook will log session id corresponding to request."""

    req = request.get_json()
    # You can read more about SessionInfo at https://cloud.google.com/dialogflow/cx/docs/reference/rest/v3/SessionInfo
    # Use a regex pattern to get the session ID
    session_id_regex = r".+\/sessions\/(.+)"
    session = req["sessionInfo"]["session"]
    regex_match = re.search(session_id_regex, session)
    session_id = regex_match.group(1)

    # Instead of printing, use the logging tools available to you
    print(f"Debug Node: session ID = {session_id}")

    # Return a generic response
    res = {
        "fulfillment_response": {
            "messages": [{"text": {"text": [f"Request Session ID: {session_id}"]}}]
        }
    }

    # Returns json
    return res

トラブルシューティング

Webhook 呼び出しのライフサイクル

Webhook 呼び出しは常に会話エージェント(Dialogflow CX)によって開始され、HTTPS 経由でウェブサーバーに送信されます。汎用ウェブサービス Webhook 呼び出しは、Google に属するインターネット IP アドレスから発信され、公共のインターネットで利用可能なウェブサーバー(Webhook サーバー)に到達できます。一方、Service Directory Webhook は常に内部の Google Cloud アドレスから開始され、Google Cloud 内のプライベート ネットワーク内の Webhook サーバーにのみ到達できます。

Webhook のデバッグに役立つログ

通常、Webhook の問題をデバッグするには、Cloud Logging Dialogflow ログと Webhook サーバーログを収集する必要があります。Webhook サーバーが Cloud Run functions を使用して実装されている場合、そのログは Cloud Logging にあります。それ以外の場合は、通常、ログは Webhook サーバーが実行されている場所に存在します。

標準の Webhook ログには、UUID を含む detectIntentResponseId フィールドが含まれています。これは、Webhook サーバーで特定の呼び出しをトレースする場合に役立ちます。このログは、Cloud Logging が有効になっている場合、Dialogflow Cloud Logging ログにあります。

Webhook に関する一般的な問題

Webhook 呼び出しの Dialogflow ログに表示されるエラーの例を次に示します。

Webhook サーバー ホスト名の解決エラー

Dialogflow が汎用 Webhook のホスト名をルックアップしましたが、そのホスト名が DNS に存在しません。ホスト名がパブリック DNS に登録されていることを確認します。ホスト名が新しい場合、レコードが伝播されるまでに時間がかかることがあります。Cloud Logging メッセージ: State: URL_ERROR, Reason: ERROR_DNS

Webhook サーバーがクライアントサイド エラーを返す

ERROR_DNS を除き、このステータスは Webhook サーバーからの 4xx レスポンスを示します。未承認のステータス(401 - ERROR_AUTHENTICATION)の場合や、Webhook サーバーで URL が見つからなかった場合(404 - ERROR_NOT_FOUND)です。Cloud Logging メッセージ: State: URL_ERROR

Webhook サーバーがレスポンスを返す前に Dialogflow エージェントがタイムアウトする

ウェブサーバーが完了する前に、Dialogflow が Webhook タイムアウトの上限に達しました。考えられる 2 つの方法は、Webhook サーバー処理時間を短縮するか、Dialogflow が Webhook を待機する時間を長くするかです。処理時間を短縮すると通常は最適な結果が得られます。ただし、多くの場合、簡単ではありません。Webhook にはタイムアウトの上限があり、この設定を増やすと、エンド コール元またはユーザーがエージェントからの回答を受け取るまでにさらに長く待機する必要があることを考慮してください。Cloud Logging メッセージ: State: URL_TIMEOUT, Reason: TIMEOUT_WEB

Webhook サーバーがレスポンスを返す前に gRPC がタイムアウトする

Webhook 呼び出しが完了する前に、Dialogflow API 呼び出しで gRPC によって設定された時間制限に達しました。この上限は通常、統合レベルで設定され、Dialogflow パラメータや Webhook タイムアウトの上限とは関係ありません。gRPC の期限の詳細については、https://grpc.io/docs/guides/deadlines/ をご覧ください。Cloud Logging メッセージ: State: URL_REJECTED, Reason: REJECTED_DEADLINE_EXCEEDED

Dialogflow が webhook サーバーに接続できなかった

ネットワーク エラーが原因で webhook サーバーに到達できなかったか、接続が確立され、webhook サーバーがリクエストの処理中に問題があることを示す HTTP ステータス 5xx を返しました。Dialogflow がネットワーキング レベルで webhook サーバー アドレスに到達できることを確認します。リクエストが Webhook サーバーログに表示されている場合は、呼び出しが 5xx エラーを返した理由を特定します。Cloud Logging メッセージ: State: URL_UNREACHABLE

Webhook 呼び出しのトレース

標準の Webhook 呼び出しは、セッション ID、detectIntentResponse ID、Cloud Run functions の Trace ID、呼び出しのタイムスタンプを使用して、Dialogflow と Webhook サーバーの間で関連付けることができます。柔軟な Webhook トレースを行うには、呼び出しのタイムスタンプと、設計時に Webhook 定義で指定されたセッション パラメータ値を使用します。標準 Webhook リクエストとフレキシブル Webhook リクエストの詳細については、Webhook をご覧ください。

セッション ID は WebhookRequestsessionInfo.session フィールドに表示されます。このセッション ID は会話ごとに一意にする必要があります。このセッション ID を使用するとリクエストのエージェント ログと Webhook ログを比較する際に役立ちます。上記のログセッション ID セクションでは、Webhook からセッション ID をログに記録する方法を示しています。

また、Webhook をホストしている場合は、Cloud Run 関数または、同様の Google Cloud サーバーレス オプションを使用している場合は、ログエントリから trace フィールドをログフィルタとして使用します。関数を 1 回実行すると、同じトレース値を持つ複数のログエントリが生成されます。

次の例では、セッション ID とトレース値の両方を使用して、特定の Dialogflow エージェントのエラーログを、対応する Cloud Run functions Webhook ログエントリに関連付けます。この例では、Cloud Logging を有効にしたエージェントに対して Cloud Logging フィルタを使用します。

1. 特定のエージェントのエラーログに対して Dialogflow ログをフィルタする

次の Cloud Logging フィルタを使用して、特定のエージェントのエラーログに対して Dialogflow ログをフィルタします。

labels.location_id="global"
labels.agent_id="AGENT_ID"
severity=ERROR

Webhook ログのエラーエントリは次のようになります。

{
  "insertId": "-j4gkkre31e2o",
  "jsonPayload": {
    "code": 14,
    "message": "Error calling webhook 'https://us-central1-PROJECT_ID.cloudfunctions.net/function-webhook': State: URL_UNREACHABLE, Reason: UNREACHABLE_5xx, HTTP status code: 500"
  },
  "labels": {
    "agent_id": "e9e01392-1351-42dc-9b15-b583fb2d2881",
    "environment_id": "",
    "location_id": "global",
    "session_id": "07c899-a86-78b-a77-569625b37"
  },
  "logName": "projects/PROJECT_ID/logs/dialogflow-runtime.googleapis.com%2Frequests",
  "receiveTimestamp": "2024-10-28T21:49:04.288439054Z",
  "resource": {
    "labels": {
      "project_id": "PROJECT_ID"
    },
    "type": "global",
  },
  "severity": "ERROR",
  "timestamp": "2024-10-28T21:49:04.132548Z"
}

セッション ID を含む labels.session_id フィールドをメモします。セッション ID は次のステップで使用します。

2. Cloud Run functions のログをセッション ID でフィルタする

次の Cloud Logging フィルタを使用して、セッション ID で Cloud Run 関数のログをフィルタリングします。

resource.type = "cloud_run_revision"
resource.labels.service_name = "CLOUD_RUN_FUNCTION_NAME"
resource.labels.location = "CLOUD_RUN_FUNCTION_REGION"
textPayload="Debug Node: session ID = SESSION_ID"

結果のログは、指定されたセッション中に作成された Webhook ログに対応します。次に例を示します。

{
  "insertId": "671c42940007ebebdbb1d56e",
  "labels": {
    "execution_id": "pgy8jvvblovs",
    "goog-managed-by": "cloudfunctions",
    "instance_id": "004940b3b8e3d975a4b11a4ed7d1ded4ce3ed37467ffc5e2a8f13a1908db928f8200b01cc554a5eda66ffc9d23d76dd75cec1619a07cb5751fa2e8a93bc6cfc3df86dfa0650a"
  },
  "logName": "projects/PROJECT_ID/logs/run.googleapis.com%2Fstdout",
  "receiveTimestamp": "2024-10-26T01:15:00.523313187Z",
  "resource": {
    "labels": {
      "configuration_name": "function-webhook",
      "location": "us-central1",
      "project_id": "PROJECT_ID",
      "revision_name": "function-webhook-00001-jiv",
      "service_name": "function-webhook",
    },
    "type": "cloud_run_revision"
  },
  "spanId": "6938366936362981595",
  "trace": "d1b54fbc8945dd59bdcaed37d7d5e185",
  "textPayload": "Debug Node: session ID = 07c899-a86-78b-a77-569625b37",
  "timestamp": "2024-10-26T01:15:00.519147Z"
}

trace フィールドをメモします。これは次のステップで使用します。

3. Cloud Functions のログを特定のトレースでフィルタする

次の Cloud Logging フィルタを使用して、特定のトレースのために Cloud Functions 関数のログをフィルタします。

resource.type = "cloud_run_revision"
resource.labels.service_name = "CLOUD_RUN_FUNCTION_NAME"
resource.labels.location = "CLOUD_RUN_FUNCTION_REGION"
trace="projects/PROJECT_ID/traces/TRACE_ID"

ここで、TRACE_ID はトレースの最後のセグメントです。たとえば、projects/PROJECT_ID/traces/e41eefc1fac48665b442bfa400cc2f5eTRACE_IDe41eefc1fac48665b442bfa400cc2f5e です。

結果は、ステップ 1 のセッション ID とステップ 2 のトレースに関連付けられた Webhook リクエストの実行中に生成された Webhook サーバーログです。ログは次のようになります。

{
  "insertId": "671c42940008465e29f5faf0",
  "httpRequest": {
    "requestMethod": "POST",
    "requestUrl": "https://us-central1-TEST_PROJECT.cloudfunctions.net/function-webhook",
    "requestSize": "2410",
    "status": 200,
    "responseSize": "263",
    "userAgent": "Google-Dialogflow",
    "remoteIp": "8.34.210.1",
    "serverIp": "216.239.36.1",
    "latency": "0.166482342s",
    "protocol": "HTTP/1.1"
  },
  "resource": {
    "type": "cloud_run_revision",
    "labels": {
      "project_id": "PROJECT_ID",
      "service_name": "function-webhook",
      "location": "us-central1",
      "revision_name": "function-webhook-00001-jiv",
      "configuration_name": "function-webhook"
    }
  },
  "timestamp": "2024-10-26T01:15:00.352197Z",
  "severity": "INFO",
  "labels": {
    "instanceId": "004940b3b813af8a656c92aac1bd07ffad5165f1353e1e346b6161c14bcde225f68f4a88ceedc08aa9020f387b1b59471f73de45f2882a710ced37dea921f05ad962347690be",
    "goog-managed-by": "cloudfunctions"
  },
  "logName": "projects/test-project-12837/logs/run.googleapis.com%2Frequests",
  "trace": "projects/test-project-12837/traces/d1b54fbc8945dd59bdcaed37d7d5e185",
  "receiveTimestamp": "2024-10-26T01:15:00.548931586Z",
  "spanId": "604a07f7b33b18db",
  "traceSampled": true
}