Implemente webhooks

Este guia fornece vários exemplos para implementar webhooks , bem como recomendações de resolução de problemas de webhooks.

Defina um parâmetro de sessão

Os exemplos seguintes mostram como definir um parâmetro de sessão.

Go

Para se autenticar no Dialogflow, configure as Credenciais padrão da aplicação. Para mais informações, consulte o artigo Configure a autenticação para um ambiente de desenvolvimento local.

Consulte o início rápido dos webhooks.

Java

Para se autenticar no Dialogflow, configure as Credenciais padrão da aplicação. Para mais informações, consulte o artigo Configure a autenticação para um ambiente de desenvolvimento 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 se autenticar no Dialogflow, configure as Credenciais padrão da aplicação. Para mais informações, consulte o artigo Configure a autenticação para um ambiente de desenvolvimento 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 se autenticar no Dialogflow, configure as Credenciais padrão da aplicação. Para mais informações, consulte o artigo Configure a autenticação para um ambiente de desenvolvimento 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

Devolva uma resposta de processamento

Os exemplos seguintes mostram como devolver uma resposta de processamento.

Go

Para se autenticar no Dialogflow, configure as Credenciais padrão da aplicação. Para mais informações, consulte o artigo Configure a autenticação para um ambiente de desenvolvimento local.

Consulte o início rápido dos webhooks.

Java

Para se autenticar no Dialogflow, configure as Credenciais padrão da aplicação. Para mais informações, consulte o artigo Configure a autenticação para um ambiente de desenvolvimento 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 se autenticar no Dialogflow, configure as Credenciais padrão da aplicação. Para mais informações, consulte o artigo Configure a autenticação para um ambiente de desenvolvimento 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 se autenticar no Dialogflow, configure as Credenciais padrão da aplicação. Para mais informações, consulte o artigo Configure a autenticação para um ambiente de desenvolvimento 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

Defina os parâmetros do formulário conforme necessário

Os exemplos seguintes mostram como sinalizar um parâmetro como obrigatório.

Java

Para se autenticar no Dialogflow, configure as Credenciais padrão da aplicação. Para mais informações, consulte o artigo Configure a autenticação para um ambiente de desenvolvimento 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 se autenticar no Dialogflow, configure as Credenciais padrão da aplicação. Para mais informações, consulte o artigo Configure a autenticação para um ambiente de desenvolvimento 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);
});

Valide um parâmetro de formulário

Os exemplos seguintes mostram como validar um parâmetro de formulário.

Java

Para se autenticar no Dialogflow, configure as Credenciais padrão da aplicação. Para mais informações, consulte o artigo Configure a autenticação para um ambiente de desenvolvimento 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 se autenticar no Dialogflow, configure as Credenciais padrão da aplicação. Para mais informações, consulte o artigo Configure a autenticação para um ambiente de desenvolvimento 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 se autenticar no Dialogflow, configure as Credenciais padrão da aplicação. Para mais informações, consulte o artigo Configure a autenticação para um ambiente de desenvolvimento 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,
            },
        },
    }

ID da sessão de registo

O exemplo seguinte mostra como registar o session ID a partir de um pedido de webhook.

Python

Para se autenticar no Dialogflow, configure as Credenciais padrão da aplicação. Para mais informações, consulte o artigo Configure a autenticação para um ambiente de desenvolvimento 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

Resolução de problemas

Ciclo de vida de uma chamada webhook

As chamadas de webhook são sempre iniciadas por agentes conversacionais (Dialogflow CX) e direcionadas para um servidor Web através de HTTPS. As chamadas de webhooks de serviços Web genéricos têm origem num endereço IP da Internet que pertence à Google e podem alcançar servidores Web (servidores de webhook) que estão disponíveis na Internet pública. Por outro lado, os webhooks do Service Directory começam sempre a partir de um endereçoGoogle Cloud interno e só podem alcançar servidores de webhook em redes privadas dentro Google Cloud.

Registos úteis para depurar webhooks

A depuração de problemas de webhook envolve normalmente a recolha dos registos do Cloud Logging do Dialogflow e dos registos do servidor webhook. Se o servidor de webhook estiver implementado através de funções do Cloud Run, os respetivos registos encontram-se no Cloud Logging. Caso contrário, os registos residem normalmente no local onde o servidor do webhook é executado.

Os registos de webhook padrão contêm um campo detectIntentResponseId com um UUID que pode ser útil para rastrear uma chamada específica nos servidores de webhook. Este registo existe nos registos do Cloud Logging do Dialogflow quando o Cloud Logging está ativado.

Problemas comuns com webhooks

Seguem-se alguns erros que podem ser encontrados nos registos do Dialogflow para chamadas de webhooks:

Erro de resolução do nome de anfitrião do servidor de webhook

O Dialogflow procurou o nome do anfitrião de um webhook genérico e o nome do anfitrião não existe no DNS. Certifique-se de que o nome do anfitrião está registado no DNS público. Se o nome do anfitrião for novo, a propagação do registo CNAME pode demorar algum tempo. Mensagem do Cloud Logging: State: URL_ERROR, Reason: ERROR_DNS.

O servidor do webhook devolve um erro do lado do cliente

Além disso, ERROR_DNSeste estado indica uma resposta 4xx do servidor do webhook. Este pode ser um estado não autorizado (401) ou o URL não foi encontrado no servidor de webhook (404). Mensagem do Cloud Logging: State: URL_ERROR.ERROR_AUTHENTICATIONERROR_NOT_FOUND

O agente do Dialogflow excede o tempo limite antes de o servidor do webhook devolver uma resposta

O Dialogflow atingiu o limite de tempo limite do webhook antes de o servidor Web terminar. As duas abordagens possíveis aqui são reduzir o tempo de processamento do servidor de webhook ou aumentar o tempo que o Dialogflow aguarda pelo webhook. A redução do tempo de processamento costuma gerar os melhores resultados, embora, em muitos casos, não seja trivial. Tenha em atenção que existe um limite de tempo máximo para os webhooks e que os autores de chamadas ou os utilizadores finais têm de esperar mais tempo para receber uma resposta do agente antes de aumentar esta definição. Mensagem do Cloud Logging: State: URL_TIMEOUT, Reason: TIMEOUT_WEB.

O gRPC excede o limite de tempo antes de o servidor do webhook devolver uma resposta

O limite de tempo definido pelo gRPC na chamada da API Dialogflow foi atingido antes de a chamada do webhook terminar. Normalmente, este limite é definido ao nível da integração e é independente dos parâmetros do Dialogflow e dos limites de tempo limite do webhook. Para mais informações sobre os prazos do gRPC, consulte https://grpc.io/docs/guides/deadlines/. Mensagem do Cloud Logging: State: URL_REJECTED, Reason: REJECTED_DEADLINE_EXCEEDED.

O Dialogflow não conseguiu contactar o servidor de webhook

Não foi possível aceder ao servidor do webhook devido a um erro de rede ou a ligação foi estabelecida e o servidor do webhook devolveu o estado HTTP 5xx, o que indica um problema durante o processamento do pedido. Certifique-se de que o Dialogflow consegue alcançar o endereço do servidor de webhook ao nível da rede. Se o pedido aparecer nos registos do servidor do webhook, descubra por que motivo a chamada devolveu um erro 5xx. Mensagem do Cloud Logging: State: URL_UNREACHABLE.

Rastreio de chamadas de webhook

Uma chamada de webhook padrão pode ser correlacionada entre o Dialogflow e um servidor de webhook através do ID da sessão, do detectIntentResponse ID, do ID de rastreio para funções do Cloud Run e de uma data/hora da chamada. A monitorização flexível de webhooks pode ser feita através da data/hora da chamada e dos valores dos parâmetros da sessão especificados na definição do webhook no momento da conceção. Para mais informações sobre pedidos de webhooks padrão e flexíveis, consulte Webhooks.

O ID da sessão é apresentado no campo sessionInfo.session do WebhookRequest. Este ID da sessão deve ser exclusivo para cada conversa e pode ajudar a comparar os registos dos agentes com os registos dos webhooks para pedidos que usam o mesmo ID da sessão. A secção anterior ID da sessão de registo mostra como registar o ID da sessão a partir de um webhook.

Além disso, se estiver a alojar o webhook em funções do Cloud Run ou numa opção Google Cloud sem servidor semelhante, pode usar o campo trace das entradas do registo como um filtro de registo. Uma única execução de uma função resulta em várias entradas de registo com o mesmo valor de rastreio.

O exemplo seguinte usa o ID da sessão e o valor de rastreio para associar um registo de erros do agente do Dialogflow específico às entradas de registo do webhook das funções do Cloud Run correspondentes. O exemplo usa filtros do Cloud Logging para um agente que ativou o Cloud Logging.

1. Filtre os registos do Dialogflow para os registos de erros de um agente específico

Use o seguinte filtro do Cloud Logging para filtrar os registos do Dialogflow relativos aos registos de erros de um agente específico:

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

Uma entrada de erro do registo de webhooks tem o seguinte aspeto:

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

Tenha em atenção o campo labels.session_id, que contém o ID da sessão. Vai usar o ID da sessão no passo seguinte.

2. Filtre os registos de funções do Cloud Run por ID da sessão

Use o seguinte filtro do Cloud Logging para filtrar os registos das funções do Cloud Run por ID da sessão:

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"

Os registos resultantes correspondem aos registos de webhook feitos durante a sessão fornecida. Por exemplo:

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

Tenha em atenção o campo trace, que é usado no passo seguinte.

3. Filtre os registos do Cloud Functions para um rastreio específico

Use o seguinte filtro do Cloud Logging para filtrar os registos do Cloud Functions para um rastreio específico:

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"

onde TRACE_ID é o último segmento do trajeto. Por exemplo, o TRACE_ID para projects/PROJECT_ID/traces/e41eefc1fac48665b442bfa400cc2f5e é e41eefc1fac48665b442bfa400cc2f5e.

O resultado é o registo do servidor do webhook gerado durante a execução do pedido de webhook associado ao ID da sessão do passo 1 e ao rastreio do passo 2. O registo teria o seguinte aspeto.

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