Implementa webhooks

En esta guía, se proporcionan varias muestras para implementar webhooks así como recomendaciones para solucionar problemas relacionados con ellos.

Establece un parámetro de sesión

En los siguientes ejemplos, se muestra cómo establecer un parámetro de sesión.

Go

Para autenticarte en Dialogflow CX, configura las credenciales predeterminadas de la aplicación. Para obtener más información, consulta Configura la autenticación para un entorno de desarrollo local.

Consulta el inicio rápido de Webhooks.

Java

Para autenticarte en Dialogflow CX, configura las credenciales predeterminadas de la aplicación. Para obtener más información, consulta Configura la autenticación para un entorno de desarrollo local.


// 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

Para autenticarte en Dialogflow CX, configura las credenciales predeterminadas de la aplicación. Para obtener más información, consulta Configura la autenticación para un entorno de desarrollo local.

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

Para autenticarte en Dialogflow CX, configura las credenciales predeterminadas de la aplicación. Para obtener más información, consulta Configura la autenticación para un entorno de desarrollo local.

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

Muestra una respuesta de entrega

En los siguientes ejemplos, se muestra cómo mostrar una respuesta de entrega.

Go

Para autenticarte en Dialogflow CX, configura las credenciales predeterminadas de la aplicación. Para obtener más información, consulta Configura la autenticación para un entorno de desarrollo local.

Consulta el inicio rápido de Webhooks.

Java

Para autenticarte en Dialogflow CX, configura las credenciales predeterminadas de la aplicación. Para obtener más información, consulta Configura la autenticación para un entorno de desarrollo local.


// 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

Para autenticarte en Dialogflow CX, configura las credenciales predeterminadas de la aplicación. Para obtener más información, consulta Configura la autenticación para un entorno de desarrollo local.

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

Para autenticarte en Dialogflow CX, configura las credenciales predeterminadas de la aplicación. Para obtener más información, consulta Configura la autenticación para un entorno de desarrollo local.

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

Establece los parámetros del formulario según sea necesario

En los siguientes ejemplos, se muestra cómo marcar un parámetro como obligatorio.

Java

Para autenticarte en Dialogflow CX, configura las credenciales predeterminadas de la aplicación. Para obtener más información, consulta Configura la autenticación para un entorno de desarrollo local.


// 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

Para autenticarte en Dialogflow CX, configura las credenciales predeterminadas de la aplicación. Para obtener más información, consulta Configura la autenticación para un entorno de desarrollo local.

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);
});

Valida un parámetro de formulario

En los siguientes ejemplos, se muestra cómo validar un parámetro de formulario.

Java

Para autenticarte en Dialogflow CX, configura las credenciales predeterminadas de la aplicación. Para obtener más información, consulta Configura la autenticación para un entorno de desarrollo local.


// 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

Para autenticarte en Dialogflow CX, configura las credenciales predeterminadas de la aplicación. Para obtener más información, consulta Configura la autenticación para un entorno de desarrollo local.

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

Para autenticarte en Dialogflow CX, configura las credenciales predeterminadas de la aplicación. Para obtener más información, consulta Configura la autenticación para un entorno de desarrollo local.

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,
            },
        },
    }

Registra el ID de sesión

En el siguiente ejemplo, se muestra cómo registrar el session ID de una solicitud de webhook.

Python

Para autenticarte en Dialogflow CX, configura las credenciales predeterminadas de la aplicación. Para obtener más información, consulta Configura la autenticación para un entorno de desarrollo local.


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

Soluciona problemas

Ciclo de vida de una llamada de webhook

Dialogflow CX siempre inicia las llamadas de webhook y se dirigen a un servidor web a través de HTTPS. Las llamadas de webhook de servicio web genérico se originan en una dirección IP de Internet que pertenece a Google y pueden llegar a servidores web (servidores de webhook) que están disponibles en Internet pública. Por otro lado, los webhooks del Directorio de servicios siempre comienzan desde una dirección interna Google Cloud y solo pueden llegar a servidores de webhook en redes privadas dentro de ella Google Cloud.

Registros útiles para depurar webhooks

Por lo general, la depuración de problemas de webhook implica recopilar los registros de Cloud Logging Dialogflow CX y los registros del servidor de webhook. Si el servidor de webhook se implementa con funciones de Cloud Run, sus registros estarán en Cloud Logging. De lo contrario, los registros suelen residir donde se ejecuta el servidor de webhook.

Los registros de webhook estándar contienen un campo detectIntentResponseId con un UUID que puede ser útil para rastrear una llamada en particular en servidores de webhook. Este registro existe en los registros de Cloud Logging de Dialogflow CX cuando Cloud Logging está habilitado.

Problemas comunes con webhook

Algunos errores que se pueden encontrar en los registros de Dialogflow CX para llamadas de webhook son los siguientes:

Error de resolución del nombre de host del servidor de webhook

Dialogflow CX buscó el nombre de host de un webhook genérico y el nombre de host no existe en el DNS. Asegúrate de que el nombre de host esté registrado en el DNS público. Si el nombre de host es nuevo, es posible que el registro tarde un tiempo en propagarse. Mensaje de Cloud Logging: State: URL_ERROR, Reason: ERROR_DNS.

El servidor de webhook muestra un error del cliente

Además de ERROR_DNS, este estado indica una respuesta 4xx del servidor de webhook. Puede ser un estado no autorizado (401 - ERROR_AUTHENTICATION) o que no se encontró la URL en el servidor de webhook (404 - ERROR_NOT_FOUND). Mensaje de Cloud Logging: State: URL_ERROR.

El agente de Dialogflow agota el tiempo de espera antes de que el servidor de webhook muestre una respuesta

Dialogflow CX alcanzó el límite de tiempo de espera del webhook antes de que finalizara el servidor web. Los dos enfoques posibles aquí son reducir el tiempo de procesamiento del servidor de webhook o aumentar el tiempo que Dialogflow CX espera el webhook. Por lo general, reducir el tiempo de procesamiento produce mejores resultados, aunque no es trivial en muchos casos. Ten en cuenta que hay un límite máximo de tiempo de espera para los webhooks y que los usuarios o quienes llaman finales deberán esperar más tiempo para obtener una respuesta del agente antes de aumentar esta configuración. Mensaje de Cloud Logging: State: URL_TIMEOUT, Reason: TIMEOUT_WEB.

gRPC agota el tiempo de espera antes de que el servidor de webhook muestre una respuesta

Se alcanzó el límite de tiempo establecido por gRPC en la llamada a la API de Dialogflow CX antes de que finalizara la llamada de webhook. Por lo general, este límite se establece en el nivel de integración y es independiente de los parámetros de Dialogflow CX y los límites de tiempo de espera del webhook. Para obtener más información sobre los plazos de gRPC, consulta https://grpc.io/docs/guides/deadlines/. Mensaje de Cloud Logging: State: URL_REJECTED, Reason: REJECTED_DEADLINE_EXCEEDED.

Dialogflow no pudo comunicarse con el servidor de webhook

No se pudo acceder al servidor de webhook debido a un error de red, o bien se estableció la conexión y el servidor de webhook mostró el estado HTTP 5xx, lo que indica un problema mientras procesaba la solicitud. Asegúrate de que Dialogflow CX pueda llegar a la dirección del servidor de webhook en el nivel de red. Si la solicitud aparece en los registros del servidor de webhook, averigua por qué la llamada mostró un error 5xx. Mensaje de Cloud Logging: State: URL_UNREACHABLE.

Cómo rastrear llamadas de webhook

Se puede correlacionar una llamada de webhook estándar entre Dialogflow CX y un servidor de webhook con el ID de sesión, el ID de detectIntentResponse, el ID de seguimiento de las funciones de Cloud Run y una marca de tiempo de la llamada. El seguimiento flexible de webhook se puede realizar con la marca de tiempo de la llamada y los valores de los parámetros de sesión especificados en la definición de webhook en el momento del diseño. Para obtener más información sobre las solicitudes de webhook estándar y flexibles, consulta Webhooks.

El ID de sesión aparece en el campo sessionInfo.session de WebhookRequest. Este ID de sesión debe ser único para cada conversación y puede ayudarte a comparar los registros del agente con los registros de webhook para las solicitudes que usan el mismo ID de sesión. En la sección anterior, Registra el ID de sesión, se muestra cómo registrar el ID de sesión de un webhook.

Además, si alojas tu webhook en funciones de Cloud Run o en una opción similar Google Cloud sin servidores, puedes usar el campo trace de las entradas de registro como filtro de registro. Una sola ejecución de una función genera varias entradas de registro con el mismo valor de seguimiento.

En el siguiente ejemplo, se usan el ID de sesión y el valor de seguimiento para asociar un registro de errores de agente de Dialogflow CX en particular con las entradas de registro de webhook de funciones de Cloud Run correspondientes. En el ejemplo, se usan filtros de Cloud Logging para un agente que habilitó Cloud Logging.

1. Filtra los registros de Dialogflow CX para los registros de errores de un agente en particular

Usa el siguiente filtro de Cloud Logging para filtrar los registros de Dialogflow CX para los registros de errores de un agente en particular:

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

Una entrada de error de registro de webhook se ve de la siguiente manera:

{
  "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"
}

Observa el campo labels.session_id, que contiene el ID de sesión. Usarás el ID de sesión en el siguiente paso.

2. Filtra los registros de funciones de Cloud Run por ID de sesión

Usa el siguiente filtro de Cloud Logging para filtrar los registros de funciones de Cloud Run por ID de sesión:

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"

Los registros resultantes corresponden a los registros de webhook realizados durante la sesión proporcionada. Por ejemplo:

{
  "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"
}

Observa el campo trace, que se usa en el siguiente paso.

3. Filtra los registros de Cloud Functions para un seguimiento en particular

Usa el siguiente filtro de Cloud Logging para filtrar los registros de Cloud Function para un seguimiento en particular:

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"

donde TRACE_ID es el último segmento del seguimiento. Por ejemplo, el TRACE_ID para projects/PROJECT_ID/traces/e41eefc1fac48665b442bfa400cc2f5e es e41eefc1fac48665b442bfa400cc2f5e.

El resultado es el registro del servidor de webhook generado durante la ejecución de la solicitud de webhook asociada con el ID de sesión del paso 1 y con el seguimiento del paso 2. El registro se vería de la siguiente manera.

{
  "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
}