Implementare gli webhook

Questa guida fornisce vari esempi per l'implementazione dei webhooks, nonché consigli per la risoluzione dei problemi relativi ai webhook.

Impostare un parametro di sessione

Gli esempi riportati di seguito mostrano come impostare un parametro di sessione.

Go

Per autenticarti a Dialogflow, configura le Credenziali predefinite dell'applicazione. Per maggiori informazioni, consulta Configurare l'autenticazione per un ambiente di sviluppo locale.

Consulta la guida rapida agli webhook.

Java

Per autenticarti a Dialogflow, configura le Credenziali predefinite dell'applicazione. Per maggiori informazioni, consulta Configurare l'autenticazione per un ambiente di sviluppo locale.


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

Per autenticarti a Dialogflow, configura le Credenziali predefinite dell'applicazione. Per maggiori informazioni, consulta Configurare l'autenticazione per un ambiente di sviluppo locale.

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

Per autenticarti a Dialogflow, configura le Credenziali predefinite dell'applicazione. Per maggiori informazioni, consulta Configurare l'autenticazione per un ambiente di sviluppo locale.

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

Restituire una risposta di evasione

Gli esempi riportati di seguito mostrano come restituire una risposta di adempimento.

Go

Per autenticarti a Dialogflow, configura le Credenziali predefinite dell'applicazione. Per maggiori informazioni, consulta Configurare l'autenticazione per un ambiente di sviluppo locale.

Consulta la guida rapida agli webhook.

Java

Per autenticarti a Dialogflow, configura le Credenziali predefinite dell'applicazione. Per maggiori informazioni, consulta Configurare l'autenticazione per un ambiente di sviluppo locale.


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

Per autenticarti a Dialogflow, configura le Credenziali predefinite dell'applicazione. Per maggiori informazioni, consulta Configurare l'autenticazione per un ambiente di sviluppo locale.

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

Per autenticarti a Dialogflow, configura le Credenziali predefinite dell'applicazione. Per maggiori informazioni, consulta Configurare l'autenticazione per un ambiente di sviluppo locale.

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

Imposta i parametri del modulo come richiesto

Gli esempi riportati di seguito mostrano come contrassegnare un parametro come obbligatorio.

Java

Per autenticarti a Dialogflow, configura le Credenziali predefinite dell'applicazione. Per maggiori informazioni, consulta Configurare l'autenticazione per un ambiente di sviluppo locale.


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

Per autenticarti a Dialogflow, configura le Credenziali predefinite dell'applicazione. Per maggiori informazioni, consulta Configurare l'autenticazione per un ambiente di sviluppo locale.

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

Convalidare un parametro del modulo

Gli esempi riportati di seguito mostrano come convalidare un parametro del modulo.

Java

Per autenticarti a Dialogflow, configura le Credenziali predefinite dell'applicazione. Per maggiori informazioni, consulta Configurare l'autenticazione per un ambiente di sviluppo locale.


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

Per autenticarti a Dialogflow, configura le Credenziali predefinite dell'applicazione. Per maggiori informazioni, consulta Configurare l'autenticazione per un ambiente di sviluppo locale.

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

Per autenticarti a Dialogflow, configura le Credenziali predefinite dell'applicazione. Per maggiori informazioni, consulta Configurare l'autenticazione per un ambiente di sviluppo locale.

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 sessione log

L'esempio seguente mostra come registrare il session ID da una richiesta webhook.

Python

Per autenticarti a Dialogflow, configura le Credenziali predefinite dell'applicazione. Per maggiori informazioni, consulta Configurare l'autenticazione per un ambiente di sviluppo locale.


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

Risoluzione dei problemi

Ciclo di vita di una chiamata webhook

Le chiamate webhook vengono sempre avviate da Conversational Agents (Dialogflow CX) e inviate a un server web tramite HTTPS. Le chiamate ai webhook di servizi web generici hanno origine da un indirizzo IP internet appartenente a Google e possono raggiungere i server web (server webhook) disponibili sulla rete internet pubblica. D'altra parte, gli webhook di Service Directory partono sempre da un indirizzo interno di Google Cloud e possono raggiungere solo i server webhook in reti private all'interno di Google Cloud.

Log utili per il debug degli webhook

Il debug dei problemi relativi ai webhook in genere prevede la raccolta dei log di Dialogflow di Cloud Logging e dei log del server webhook. Se il server webhook è implementato utilizzando le funzioni Cloud Run, i relativi log si trovano in Cloud Logging. In caso contrario, i log in genere si trovano dove viene eseguito il server webhook.

I log webhook standard contengono un campo detectIntentResponseId con un UUID che può essere utile per tracciare una determinata chiamata nei server webhook. Questo log è presente nei log di Cloud Logging di Dialogflow quando Cloud Logging è abilitato.

Problemi comuni relativi ai webhook

Ecco alcuni errori che possono essere trovati nei log di Dialogflow per le chiamate ai webhook:

Errore di risoluzione del nome host del server webhook

Dialogflow ha cercato il nome host di un webhook generico e il nome host non esiste nel DNS. Assicurati che il nome host sia registrato nel DNS pubblico. Se il nome host è nuovo, la propagazione del record potrebbe richiedere del tempo. Messaggio di Cloud Logging: State: URL_ERROR, Reason: ERROR_DNS.

Il server webhook restituisce un errore lato client

A parte ERROR_DNS, questo stato indica una risposta 4xx del server webhook. Può trattarsi di uno stato di mancata autorizzazione (401 - ERROR_AUTHENTICATION) o di un URL non trovato nel server webhook (404 - ERROR_NOT_FOUND). Messaggio di Cloud Logging: State: URL_ERROR.

L'agente Dialogflow scade prima che il server webhook restituisca una risposta

Dialogflow ha raggiunto il limite di tempo del webhook prima del termine del servizio web. I due possibili approcci sono ridurre il tempo di elaborazione del server webhook o aumentare il tempo di attesa di Dialogflow per il webhook. Di solito, ridurre il tempo di elaborazione porta a risultati migliori, anche se in molti casi non è banale. Tieni presente che esiste un limite di tempo massimo per i webhook e che gli utenti o i chiamanti finali dovranno attendere più a lungo per ricevere una risposta dall'agente prima di aumentare questa impostazione. messaggio Cloud Logging: State: URL_TIMEOUT, Reason: TIMEOUT_WEB.

gRPC ha un timeout prima che il server webhook restituisca una risposta

Il limite di tempo impostato da gRPC nella chiamata all'API Dialogflow è stato raggiunto prima del termine della chiamata all'webhook. Questo limite viene impostato in genere a livello di integrazione ed è indipendente dai parametri di Dialogflow e dai limiti di timeout dei webhook. Per ulteriori informazioni sulle scadenze gRPC, consulta https://grpc.io/docs/guides/deadlines/. messaggio Cloud Logging: State: URL_REJECTED, Reason: REJECTED_DEADLINE_EXCEEDED.

Dialogflow non è riuscito a contattare il server webhook

Il server webhook non è stato raggiunto a causa di un errore di rete o la connessione è stata stabilita e il server webhook ha restituito lo stato HTTP 5xx che indica un problema durante l'elaborazione della richiesta. Assicurati che Dialogflow possa raggiungere l'indirizzo del server webhook a livello di rete. Se la richiesta viene visualizzata nei log del server webhook, scopri perché la chiamata ha restituito un errore 5xx. Messaggio di Cloud Logging: State: URL_UNREACHABLE.

Monitoraggio delle chiamate webhook

Una chiamata webhook standard può essere correlata tra Dialogflow e un server webhook utilizzando l'ID sessione, l'ID detectIntentResponse, l'ID traccia per le funzioni Cloud Run e un timestamp della chiamata. Il monitoraggio degli webhook flessibili può essere eseguito utilizzando il timestamp della chiamata e i valori del parametro della sessione specificati nella definizione dell'webhook in fase di progettazione. Per ulteriori informazioni sulle richieste di webhook standard e flessibili, consulta Webhook.

L'ID sessione viene visualizzato nel campo sessionInfo.session di WebhookRequest. Questo ID sessione deve essere univoco per ogni conversazione e può aiutarti a confrontare i log degli agenti con i log webhook per le richieste che utilizzano lo stesso ID sessione. La sezione precedente Registrare l'ID sessione illustra come registrare l'ID sessione da un webhook.

Inoltre, se ospiti il tuo webhook su funzioni Cloud Run o un'opzione serverless di Google Cloud simile, puoi utilizzare il campo trace delle voci di log come filtro di log. Una singola esecuzione di una funzione genera più voci di log con lo stesso valore di traccia.

L'esempio seguente utilizza sia l'ID sessione sia il valore traccia per associare un determinato log degli errori dell'agente Dialogflow alle voci di log degli webhook delle funzioni Cloud Run corrispondenti. L'esempio utilizza Filtri di Cloud Logging per un agente che ha attivato Cloud Logging.

1. Filtrare i log di Dialogflow per i log degli errori di un determinato agente

Utilizza il seguente filtro Cloud Logging per filtrare i log di Dialogflow in base ai log di errore di un determinato agente:

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

Una voce di errore del log webhook è simile alla seguente:

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

Prendi nota del campo labels.session_id che contiene l'ID sessione. Utilizzerai l'ID sessione nel passaggio successivo.

2. Filtrare i log delle funzioni Cloud Run per ID sessione

Utilizza il seguente filtro Cloud Logging per filtrare i log delle funzioni Cloud Run in base all'ID sessione:

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"

I log risultanti corrispondono ai log webhook generati durante la sessione indicata. Ad esempio:

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

Prendi nota del campo trace che viene utilizzato nel passaggio successivo.

3. Filtrare i log di Cloud Functions per una determinata traccia

Utilizza il seguente filtro Cloud Logging per filtrare i log di Cloud Function per una determinata traccia:

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"

dove TRACE_ID è l'ultimo tratto della traccia. Ad esempio, il TRACE_ID per projects/PROJECT_ID/traces/e41eefc1fac48665b442bfa400cc2f5e è e41eefc1fac48665b442bfa400cc2f5e.

Il risultato è il log del server webhook generato durante l'esecuzione della richiesta webhook associata all'ID sessione del passaggio 1 e alla traccia del passaggio 2. Il log sarà simile al seguente.

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