Geração de registros

A geração de registros e o monitoramento funcionam em conjunto para ajudar você a entender e otimizar o desempenho do aplicativo, bem como para diagnosticar erros e problemas. Você deve ativar os registros de resumo para todas as chamadas de API e registros detalhados de chamadas de API com falha para que você possa fornecer a API. registros de chamadas quando precisar de suporte técnico.

Geração de registros da biblioteca de cliente

As bibliotecas de cliente da API Google Ads vêm com registros integrados. Para plataformas detalhes de registro, consulte a documentação de registro em sua biblioteca de cliente do uma melhor opção.

Idioma Guia
Java Documentação do Logging para Java
.NET Documentos do Logging para .NET
PHP Documentos do Logging para PHP
Python Documentação do Logging para Python
Ruby Documentação do Logging para Ruby
Perl Documentos do Logging para Perl (em inglês)

Formato do registro

As bibliotecas clientes da API Google Ads geram um registro detalhado e um resumo log para cada chamada de API. O registro detalhado contém todos os detalhes a chamada de API, enquanto o registro de resumo contém detalhes mínimos da chamada de API. Um exemplo de cada tipo de registro é mostrado, com os registros truncados e formatados para facilitar a leitura.

Registro de resumo

GoogleAds.SummaryRequestLogs Warning: 1 : [2023-09-15 19:58:39Z] -
Request made: Host: , Method: /google.ads.googleads.v14.services.GoogleAdsService/SearchStream,
ClientCustomerID: 5951878031, RequestID: hELhBPNlEDd8mWYcZu7b8g,
IsFault: True, FaultMessage: Status(StatusCode="InvalidArgument",
Detail="Request contains an invalid argument.")

Registro detalhado

GoogleAds.DetailedRequestLogs Verbose: 1 : [2023-11-02 21:09:36Z] -
---------------BEGIN API CALL---------------

Request
-------

Method Name: /google.ads.googleads.v14.services.GoogleAdsService/SearchStream
Host:
Headers: {
  "x-goog-api-client": "gl-dotnet/5.0.0 gapic/17.0.1 gax/4.2.0 grpc/2.46.3 gccl/3.0.1 pb/3.21.5",
  "developer-token": "REDACTED",
  "login-customer-id": "1234567890",
  "x-goog-request-params": "customer_id=4567890123"
}

{ "customerId": "4567890123", "query": "SELECT ad_group_criterion.type FROM
  ad_group_criterion WHERE ad_group.status IN(ENABLED, PAUSED) AND
  campaign.status IN(ENABLED, PAUSED) ", "summaryRowSetting": "NO_SUMMARY_ROW" }

Response
--------
Headers: {
  "date": "Thu, 02 Nov 2023 21:09:35 GMT",
  "alt-svc": "h3-29=\":443\"; ma=2592000"
}

{
  "results": [ {
    "adGroupCriterion": {
      "resourceName": "customers/4567890123/adGroupCriteria/456789456789~123456123467",
      "type": "KEYWORD"
    } }, {
    "adGroupCriterion": {
      "resourceName": "customers/4567890123/adGroupCriteria/456789456789~56789056788",
      "type": "KEYWORD"
    } } ],
    "fieldMask": "adGroupCriterion.type", "requestId": "VsJ4F00ew6s9heHvAJ-abw"
}
----------------END API CALL----------------

E se eu não usar uma biblioteca de cliente?

Se você não usa uma biblioteca de cliente, implemente seu próprio registro para capturar os das chamadas de API feitas e recebidas. Você deve registrar pelo menos o do cabeçalho de resposta request-id, que pode ser compartilhado com os equipes de suporte técnico conforme necessário.

Geração de registros na nuvem

Há muitas ferramentas que podem ser usadas para capturar registros e métricas de desempenho seu aplicativo. Por exemplo, é possível usar o Google Cloud Logging para registrar métricas de desempenho ao seu projeto do Google Cloud. Assim, configurar painéis e alertas no Google Cloud Monitoring para usar as métricas registradas.

O Cloud Logging oferece bibliotecas de cliente para todos os clientes compatíveis com a API Google Ads linguagens da biblioteca, exceto Perl, portanto, na maioria dos casos, é possível fazer o registro com Cloud Logging diretamente da integração da biblioteca de cliente. Para outros idiomas incluindo Perl, o Cloud Logging também oferece uma API REST.

Há algumas opções para gerar registros no Cloud Logging ou em outra ferramenta biblioteca de cliente da API Google Ads. Cada opção tem vantagens e desvantagens implementação, complexidade e desempenho. Pense bem sobre essas vantagens e desvantagens antes de decidir qual solução implementar.

Opção 1: gravar registros locais na nuvem usando um processo em segundo plano

Os registros da biblioteca de cliente podem ser gravados em um arquivo local na sua máquina modificando-se a configuração da geração de registros. Depois que os registros forem enviados a um arquivo local, será possível configurar um daemon para coletar os registros e enviá-los para a nuvem.

Uma limitação dessa abordagem é que algumas métricas de desempenho não serão são capturados por padrão. Os registros da biblioteca de cliente incluem detalhes da solicitação e objetos de resposta. Portanto, as métricas de latência não serão incluídas, a menos que sejam alteradas também são feitas para registrá-las.

Opção 2: executar o aplicativo no Compute Engine e instalar o Agente de operações

Se o aplicativo estiver em execução no Compute Engine, envie sua registros no Google Cloud Logging instalando o Agente de operações. O Agente de O agente pode ser configurado para enviar os registros do seu aplicativo para o Cloud Logging, além das métricas e registros enviados por padrão.

Se o aplicativo já estiver em execução em um ambiente do Google Cloud ou se você está pensando em migrar seu aplicativo para o Google Cloud, essa é uma ótima opção a serem considerados.

Opção 3: implementar a geração de registros no código do aplicativo

A geração de registros diretamente no código do aplicativo pode ser feita de duas maneiras:

  1. Incorporação de cálculos de métricas e log statements em cada local aplicável em seu código. Essa opção é mais viável para aplicativos bases de código, em que o escopo e os custos de manutenção de tal mudança seriam mínimas.

  2. Implementar uma interface de geração de registros. Se a lógica do aplicativo puder ser abstraída de modo que partes diferentes do aplicativo sejam herdadas da mesma base a lógica de registro pode ser implementada nessa classe de base. Essa opção é geralmente preferíveis a incorporar log statements em todo o código do aplicativo, já que é mais fácil de manter e escalonar. Para dispositivos maiores bases de código, a capacidade de manutenção e a escalonabilidade dessa solução são fatores mais relevantes.

Uma limitação dessa abordagem é que os registros completos de solicitação e resposta são não disponíveis no código do aplicativo. Objetos de solicitação e resposta completos podem ser acessados de interceptadores gRPC, é assim que a biblioteca de cliente integrada a geração de registros recebe registros de solicitação e resposta. Em caso de erro, outras pode estar disponível no objeto de exceção, mas menos detalhes disponíveis para respostas bem-sucedidas dentro da lógica do aplicativo. Por exemplo, em na maioria dos casos, o ID de solicitação para uma solicitação bem-sucedida não é acessível no Objetos de resposta da API Google Ads.

Opção 4: implementar um interceptador de geração de registros gRPC personalizado

O gRPC oferece suporte a interceptores unários e de streaming, que podem acessar o objetos de solicitação e resposta à medida que passam entre o cliente e o servidor. A As bibliotecas de cliente da API Google Ads usam interceptadores gRPC para oferecer geração de registros integrada. suporte. Da mesma forma, é possível implementar um interceptador gRPC personalizado para acessar o objetos de solicitação e resposta, extrair informações para geração de registros e monitoramento e gravar os dados no local de sua escolha.

Ao contrário de algumas das outras soluções apresentadas aqui, implementar um gRPC personalizado interceptor oferece flexibilidade para capturar objetos de solicitação e resposta em cada solicitação e implemente lógica adicional para capturar detalhes da solicitação. Por exemplo, é possível calcular o tempo decorrido de uma solicitação implementando lógica de tempo de desempenho dentro do próprio interceptador personalizado e, em seguida, registre a métrica ao Google Cloud Logging a fim de disponibilizá-la para monitoramento de latência no Google Cloud Monitoring.

Interceptador personalizado do Google Cloud Logging em Python

Para demonstrar essa solução, escrevemos um exemplo de um pipeline personalizado interceptador em Python. O interceptador personalizado é criado e transmitido para a cliente de serviço. Em seguida, ele acessa os objetos de solicitação e resposta que passam em cada chamada de método do serviço, processa dados desses objetos e e envia os dados para o Google Cloud Logging.

Além dos dados que vêm dos objetos de solicitação e resposta, os implementa uma lógica adicional para capturar o tempo decorrido do solicitação e alguns outros metadados que podem ser úteis para fins de monitoramento, por exemplo, se a solicitação foi bem-sucedida ou não. Para mais informações sobre como fazer isso em geral podem ser úteis, tanto para monitoramento quanto para combinando o Google Cloud Logging e o Google Cloud Monitoring, consulte a seção Monitoramento guia.

# Copyright 2022 Google LLC
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     https://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
"""A custom gRPC Interceptor that logs requests and responses to Cloud Logging.

The custom interceptor object is passed into the get_service method of the
GoogleAdsClient. It intercepts requests and responses, parses them into a
human readable structure and logs them using the logging service instantiated
within the class (in this case, a Cloud Logging client).
"""

import logging
import time

from google.cloud import logging
from grpc import UnaryUnaryClientInterceptor, UnaryStreamClientInterceptor

from google.ads.googleads.interceptors import LoggingInterceptor, mask_message


class CloudLoggingInterceptor(LoggingInterceptor):
    """An interceptor that logs rpc request and response details to Google Cloud Logging.

    This class inherits logic from the LoggingInterceptor, which simplifies the
    implementation here. Some logic is required here in order to make the
    underlying logic work -- comments make note of this where applicable.
    NOTE: Inheriting from the LoggingInterceptor class could yield unexpected side
    effects. For example, if the LoggingInterceptor class is updated, this class would
    inherit the updated logic, which could affect its functionality. One option to avoid
    this is to inherit from the Interceptor class instead, and selectively copy whatever
    logic is needed from the LoggingInterceptor class."""

    def __init__(self, api_version):
        """Initializer for the CloudLoggingInterceptor.

        Args:
            api_version: a str of the API version of the request.
        """
        super().__init__(logger=None, api_version=api_version)
        # Instantiate the Cloud Logging client.
        logging_client = logging.Client()
        self.logger = logging_client.logger("cloud_logging")

    def log_successful_request(
        self,
        method,
        customer_id,
        metadata_json,
        request_id,
        request,
        trailing_metadata_json,
        response,
    ):
        """Handles logging of a successful request.

        Args:
            method: The method of the request.
            customer_id: The customer ID associated with the request.
            metadata_json: A JSON str of initial_metadata.
            request_id: A unique ID for the request provided in the response.
            request: An instance of a request proto message.
            trailing_metadata_json: A JSON str of trailing_metadata.
            response: A grpc.Call/grpc.Future instance.
        """
        # Retrieve and mask the RPC result from the response future.
        # This method is available from the LoggingInterceptor class.
        # Ensure self._cache is set in order for this to work.
        # The response result could contain up to 10,000 rows of data,
        # so consider truncating this value before logging it, to save
        # on data storage costs and maintain readability.
        result = self.retrieve_and_mask_result(response)

        # elapsed_ms is the approximate elapsed time of the RPC, in milliseconds.
        # There are different ways to define and measure elapsed time, so use
        # whatever approach makes sense for your monitoring purposes.
        # rpc_start and rpc_end are set in the intercept_unary_* methods below.
        elapsed_ms = (self.rpc_end - self.rpc_start) * 1000

        debug_log = {
            "method": method,
            "host": metadata_json,
            "request_id": request_id,
            "request": str(request),
            "headers": trailing_metadata_json,
            "response": str(result),
            "is_fault": False,
            "elapsed_ms": elapsed_ms,
        }
        self.logger.log_struct(debug_log, severity="DEBUG")

        info_log = {
            "customer_id": customer_id,
            "method": method,
            "request_id": request_id,
            "is_fault": False,
            # Available from the Interceptor class.
            "api_version": self._api_version,
        }
        self.logger.log_struct(info_log, severity="INFO")

    def log_failed_request(
        self,
        method,
        customer_id,
        metadata_json,
        request_id,
        request,
        trailing_metadata_json,
        response,
    ):
        """Handles logging of a failed request.

        Args:
            method: The method of the request.
            customer_id: The customer ID associated with the request.
            metadata_json: A JSON str of initial_metadata.
            request_id: A unique ID for the request provided in the response.
            request: An instance of a request proto message.
            trailing_metadata_json: A JSON str of trailing_metadata.
            response: A JSON str of the response message.
        """
        exception = self._get_error_from_response(response)
        exception_str = self._parse_exception_to_str(exception)
        fault_message = self._get_fault_message(exception)

        info_log = {
            "method": method,
            "endpoint": self.endpoint,
            "host": metadata_json,
            "request_id": request_id,
            "request": str(request),
            "headers": trailing_metadata_json,
            "exception": exception_str,
            "is_fault": True,
        }
        self.logger.log_struct(info_log, severity="INFO")

        error_log = {
            "method": method,
            "endpoint": self.endpoint,
            "request_id": request_id,
            "customer_id": customer_id,
            "is_fault": True,
            "fault_message": fault_message,
        }
        self.logger.log_struct(error_log, severity="ERROR")

    def intercept_unary_unary(self, continuation, client_call_details, request):
        """Intercepts and logs API interactions.

        Overrides abstract method defined in grpc.UnaryUnaryClientInterceptor.

        Args:
            continuation: a function to continue the request process.
            client_call_details: a grpc._interceptor._ClientCallDetails
                instance containing request metadata.
            request: a SearchGoogleAdsRequest or SearchGoogleAdsStreamRequest
                message class instance.

        Returns:
            A grpc.Call/grpc.Future instance representing a service response.
        """
        # Set the rpc_end value to current time when RPC completes.
        def update_rpc_end(response_future):
            self.rpc_end = time.perf_counter()

        # Capture precise clock time to later calculate approximate elapsed
        # time of the RPC.
        self.rpc_start = time.perf_counter()

        # The below call is REQUIRED.
        response = continuation(client_call_details, request)

        response.add_done_callback(update_rpc_end)

        self.log_request(client_call_details, request, response)

        # The below return is REQUIRED.
        return response

    def intercept_unary_stream(
        self, continuation, client_call_details, request
    ):
        """Intercepts and logs API interactions for Unary-Stream requests.

        Overrides abstract method defined in grpc.UnaryStreamClientInterceptor.

        Args:
            continuation: a function to continue the request process.
            client_call_details: a grpc._interceptor._ClientCallDetails
                instance containing request metadata.
            request: a SearchGoogleAdsRequest or SearchGoogleAdsStreamRequest
                message class instance.

        Returns:
            A grpc.Call/grpc.Future instance representing a service response.
        """

        def on_rpc_complete(response_future):
            self.rpc_end = time.perf_counter()
            self.log_request(client_call_details, request, response_future)

        # Capture precise clock time to later calculate approximate elapsed
        # time of the RPC.
        self.rpc_start = time.perf_counter()

        # The below call is REQUIRED.
        response = continuation(client_call_details, request)

        # Set self._cache to the cache on the response wrapper in order to
        # access the streaming logs. This is REQUIRED in order to log streaming
        # requests.
        self._cache = response.get_cache()

        response.add_done_callback(on_rpc_complete)

        # The below return is REQUIRED.
        return response