Los registros y la supervisión trabajan en conjunto para ayudarte a comprender y optimizar rendimiento de la aplicación, así como para diagnosticar errores y problemas problemas. Debes activar los registros de resumen para todas las llamadas a la API y registros detallados de las llamadas fallidas a la API para que puedas proporcionar de llamadas cuando se necesita asistencia técnica.
Registro de la biblioteca cliente
Las bibliotecas cliente de la API de Google Ads incluyen registros integrados. Para plataformas específicas de registro, consulta la documentación de registro en tu biblioteca cliente es tu mejor opción.
Idioma | Guía |
---|---|
Java | Documentos de Logging para Java |
.NET | Documentos de Logging para .NET |
PHP | Documentos de Logging para PHP |
Python | Documentos de Logging para Python |
Rita | Documentos de Logging para Ruby |
Perl | Documentos de Logging para Perl |
Formato de registro
Las bibliotecas cliente de la API de Google Ads generan un registro detallado y un resumen log de cada llamada a la API. El registro detallado contiene todos los detalles de la llamada a la API, mientras que el registro de resumen contiene detalles mínimos de la llamada a la API. Se muestra un ejemplo de cada tipo de registro, con los registros truncados y con formato para facilitar la lectura.
Registro de resumen
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 detallado
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----------------
¿Qué sucede si no uso una biblioteca cliente?
Si no usas una biblioteca cliente, implementa tu propio registro para capturar
detalles de las llamadas a la API entrantes y salientes. Debes registrar al menos los
del encabezado de respuesta request-id
, que luego se puede compartir con el
equipos de asistencia técnica, según sea necesario.
Registro en la nube
Hay muchas herramientas que puedes usar para capturar registros y métricas de rendimiento tu aplicación. Por ejemplo, puedes usar Google Cloud Logging para registrar métricas de rendimiento a tu proyecto de Google Cloud. Esto hace que posible configurar paneles y alertas en Google Cloud Monitoring para usar las métricas registradas.
Cloud Logging ofrece bibliotecas cliente para todos los clientes compatibles de la API de Google Ads. lenguajes de biblioteca excepto para Perl, por lo que en la mayoría de los casos es posible realizar registros con Cloud Logging directamente desde la integración de tu biblioteca cliente. Para otros idiomas incluido Perl, Cloud Logging también ofrece una API de REST.
Existen varias opciones para acceder a Cloud Logging, o a otra herramienta, desde un biblioteca cliente de la API de Google Ads. Cada opción tiene sus propias compensaciones de tiempo la implementación, la complejidad y el rendimiento. Piensa detenidamente en estas ventajas y desventajas. antes de decidir qué solución implementar.
Opción 1: Escribe registros locales en la nube a partir de un proceso en segundo plano
Los registros de las bibliotecas cliente se pueden escribir en un archivo local en tu máquina modificando tu configuración de registro. Una vez que los registros se envían a un archivo local, puedes configurar un daemon para recopilar los registros y enviarlos a la nube.
Una limitación de este enfoque es que algunas métricas de rendimiento se capturan de forma predeterminada. Los registros de la biblioteca cliente incluyen detalles de la solicitud y los objetos de respuesta, por lo que las métricas de latencia no se incluirán, a menos que se realicen cambios adicionales para registrarlos también.
Opción 2: Ejecuta tu aplicación en Compute Engine y, luego, instala el Agente de operaciones
Si tu aplicación se ejecuta en Compute Engine, puedes enviar tu a Google Cloud Logging con la instalación del Agente de operaciones. Las operaciones El agente se puede configurar para que envíe los registros de tu aplicación a Cloud Logging, además de las métricas y los registros que se envían de forma predeterminada.
Si tu aplicación ya se está ejecutando en un entorno de Google Cloud o si consideras trasladar tu aplicación a Google Cloud, esta es una excelente opción para tener en cuenta.
Opción 3: Implementa el registro en el código de tu aplicación
El registro directamente desde el código de la aplicación se puede realizar de dos maneras:
Incorporar cálculos de métricas y instrucciones de registro en cada la ubicación correspondiente en tu código. Esta opción es más factible para las aplicaciones de código abierto, en las que el alcance y los costos de mantenimiento de dicho cambio mínimo.
Implementar una interfaz de registro Si se puede abstraer la lógica de la aplicación para que diferentes partes de la aplicación hereden contenido de la misma base de registro, la lógica de registro se puede implementar en esa clase base. Esta opción es generalmente prefiere en lugar de incorporar instrucciones de registro en todo el código de la aplicación, ya que es más fácil de mantener y escalar. Para grandes la capacidad de mantenimiento y la escalabilidad de esta solución son sean más relevantes.
Una limitación de este enfoque es que los registros completos de solicitudes y respuestas no disponible en el código de la aplicación. Los objetos de solicitud y respuesta completos se debe acceder a ellos desde los interceptores de gRPC; así es como la biblioteca cliente incorporada Logging obtiene los registros de solicitud y respuesta. En caso de que se produzca un error, las opciones información puede estar disponible en el objeto de excepción, pero hay menos detalles disponibles para respuestas exitosas en la lógica de la aplicación. Por ejemplo, en la mayoría de los casos, no se puede acceder al ID de una solicitud correcta desde el Objetos de respuesta de la API de Google Ads.
Opción 4: Implementa un interceptor de registro de gRPC personalizado
gRPC admite interceptores unarios y de transmisión que pueden acceder a la los objetos Request y Response a medida que pasan entre el cliente y el servidor. El Las bibliotecas cliente de la API de Google Ads usan interceptores de gRPC para ofrecer registros integrados y asistencia. De forma similar, puedes implementar un interceptor de gRPC personalizado para acceder al los objetos Request y Response, extraer información para el registro y la supervisión y escribe esos datos en la ubicación que quieras.
A diferencia de algunas de las otras soluciones que se presentaron aquí, la implementación de un gRPC personalizado un interceptor te da flexibilidad para capturar objetos Request y Response en en cada solicitud e implementar una lógica adicional para capturar los detalles de la solicitud. Por ejemplo, puedes calcular el tiempo transcurrido de una solicitud implementando lógica de sincronización de rendimiento dentro del mismo interceptor personalizado y, luego, registra de registro a Google Cloud Logging a fin de que esté disponible para la supervisión de latencia dentro de Google Cloud Monitoring.
Interceptor de Google Cloud Logging personalizado en Python
Para demostrar esta solución, escribimos un ejemplo de un modelo de registro un interceptor en Python. El interceptor personalizado se crea y pasa al cliente de servicio. Luego accede a los objetos Request y Response que pasan en cada llamada al método de servicio, procesa los datos de esos objetos y envía los datos a Google Cloud Logging.
Además de los datos que provienen de los objetos Request y Response, el ejemplo implementa alguna lógica adicional para capturar el tiempo transcurrido de la la solicitud y otros metadatos que serían útiles para fines de supervisión, por ejemplo, si la solicitud fue exitosa o no. Para obtener más información sobre cómo puede ser útil, tanto para la supervisión como para que combina Google Cloud Logging y Google Cloud Monitoring, consulta el curso Monitoring de la guía de YouTube.
# 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