diff --git a/packages/google-shopping-css/google/shopping/css/gapic_version.py b/packages/google-shopping-css/google/shopping/css/gapic_version.py index 9413c3341313..558c8aab67c5 100644 --- a/packages/google-shopping-css/google/shopping/css/gapic_version.py +++ b/packages/google-shopping-css/google/shopping/css/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "0.1.10" # {x-release-please-version} +__version__ = "0.0.0" # {x-release-please-version} diff --git a/packages/google-shopping-css/google/shopping/css_v1/gapic_version.py b/packages/google-shopping-css/google/shopping/css_v1/gapic_version.py index 9413c3341313..558c8aab67c5 100644 --- a/packages/google-shopping-css/google/shopping/css_v1/gapic_version.py +++ b/packages/google-shopping-css/google/shopping/css_v1/gapic_version.py @@ -13,4 +13,4 @@ # See the License for the specific language governing permissions and # limitations under the License. # -__version__ = "0.1.10" # {x-release-please-version} +__version__ = "0.0.0" # {x-release-please-version} diff --git a/packages/google-shopping-css/google/shopping/css_v1/services/account_labels_service/async_client.py b/packages/google-shopping-css/google/shopping/css_v1/services/account_labels_service/async_client.py index 66e098bc2490..af95ad18a80f 100644 --- a/packages/google-shopping-css/google/shopping/css_v1/services/account_labels_service/async_client.py +++ b/packages/google-shopping-css/google/shopping/css_v1/services/account_labels_service/async_client.py @@ -14,6 +14,7 @@ # limitations under the License. # from collections import OrderedDict +import logging as std_logging import re from typing import ( Callable, @@ -49,6 +50,15 @@ from .transports.base import DEFAULT_CLIENT_INFO, AccountLabelsServiceTransport from .transports.grpc_asyncio import AccountLabelsServiceGrpcAsyncIOTransport +try: + from google.api_core import client_logging # type: ignore + + CLIENT_LOGGING_SUPPORTED = True # pragma: NO COVER +except ImportError: # pragma: NO COVER + CLIENT_LOGGING_SUPPORTED = False + +_LOGGER = std_logging.getLogger(__name__) + class AccountLabelsServiceAsyncClient: """Manages Merchant Center and CSS accounts labels.""" @@ -260,6 +270,28 @@ def __init__( client_info=client_info, ) + if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( + std_logging.DEBUG + ): # pragma: NO COVER + _LOGGER.debug( + "Created client `google.shopping.css_v1.AccountLabelsServiceAsyncClient`.", + extra={ + "serviceName": "google.shopping.css.v1.AccountLabelsService", + "universeDomain": getattr( + self._client._transport._credentials, "universe_domain", "" + ), + "credentialsType": f"{type(self._client._transport._credentials).__module__}.{type(self._client._transport._credentials).__qualname__}", + "credentialsInfo": getattr( + self.transport._credentials, "get_cred_info", lambda: None + )(), + } + if hasattr(self._client._transport, "_credentials") + else { + "serviceName": "google.shopping.css.v1.AccountLabelsService", + "credentialsType": None, + }, + ) + async def list_account_labels( self, request: Optional[Union[accounts_labels.ListAccountLabelsRequest, dict]] = None, @@ -267,9 +299,9 @@ async def list_account_labels( parent: Optional[str] = None, retry: OptionalRetry = gapic_v1.method.DEFAULT, timeout: Union[float, object] = gapic_v1.method.DEFAULT, - metadata: Sequence[Tuple[str, str]] = (), + metadata: Sequence[Tuple[str, Union[str, bytes]]] = (), ) -> pagers.ListAccountLabelsAsyncPager: - r"""Lists the labels assigned to an account. + r"""Lists the labels owned by an account. .. code-block:: python @@ -311,8 +343,10 @@ async def sample_list_account_labels(): retry (google.api_core.retry_async.AsyncRetry): Designation of what errors, if any, should be retried. timeout (float): The timeout for this request. - metadata (Sequence[Tuple[str, str]]): Strings which should be - sent along with the request as metadata. + metadata (Sequence[Tuple[str, Union[str, bytes]]]): Key/value pairs which should be + sent along with the request as metadata. Normally, each value must be of type `str`, + but for metadata keys ending with the suffix `-bin`, the corresponding values must + be of type `bytes`. Returns: google.shopping.css_v1.services.account_labels_service.pagers.ListAccountLabelsAsyncPager: @@ -389,7 +423,7 @@ async def create_account_label( account_label: Optional[accounts_labels.AccountLabel] = None, retry: OptionalRetry = gapic_v1.method.DEFAULT, timeout: Union[float, object] = gapic_v1.method.DEFAULT, - metadata: Sequence[Tuple[str, str]] = (), + metadata: Sequence[Tuple[str, Union[str, bytes]]] = (), ) -> accounts_labels.AccountLabel: r"""Creates a new label, not assigned to any account. @@ -438,8 +472,10 @@ async def sample_create_account_label(): retry (google.api_core.retry_async.AsyncRetry): Designation of what errors, if any, should be retried. timeout (float): The timeout for this request. - metadata (Sequence[Tuple[str, str]]): Strings which should be - sent along with the request as metadata. + metadata (Sequence[Tuple[str, Union[str, bytes]]]): Key/value pairs which should be + sent along with the request as metadata. Normally, each value must be of type `str`, + but for metadata keys ending with the suffix `-bin`, the corresponding values must + be of type `bytes`. Returns: google.shopping.css_v1.types.AccountLabel: @@ -504,7 +540,7 @@ async def update_account_label( account_label: Optional[accounts_labels.AccountLabel] = None, retry: OptionalRetry = gapic_v1.method.DEFAULT, timeout: Union[float, object] = gapic_v1.method.DEFAULT, - metadata: Sequence[Tuple[str, str]] = (), + metadata: Sequence[Tuple[str, Union[str, bytes]]] = (), ) -> accounts_labels.AccountLabel: r"""Updates a label. @@ -546,8 +582,10 @@ async def sample_update_account_label(): retry (google.api_core.retry_async.AsyncRetry): Designation of what errors, if any, should be retried. timeout (float): The timeout for this request. - metadata (Sequence[Tuple[str, str]]): Strings which should be - sent along with the request as metadata. + metadata (Sequence[Tuple[str, Union[str, bytes]]]): Key/value pairs which should be + sent along with the request as metadata. Normally, each value must be of type `str`, + but for metadata keys ending with the suffix `-bin`, the corresponding values must + be of type `bytes`. Returns: google.shopping.css_v1.types.AccountLabel: @@ -612,7 +650,7 @@ async def delete_account_label( name: Optional[str] = None, retry: OptionalRetry = gapic_v1.method.DEFAULT, timeout: Union[float, object] = gapic_v1.method.DEFAULT, - metadata: Sequence[Tuple[str, str]] = (), + metadata: Sequence[Tuple[str, Union[str, bytes]]] = (), ) -> None: r"""Deletes a label and removes it from all accounts to which it was assigned. @@ -655,8 +693,10 @@ async def sample_delete_account_label(): retry (google.api_core.retry_async.AsyncRetry): Designation of what errors, if any, should be retried. timeout (float): The timeout for this request. - metadata (Sequence[Tuple[str, str]]): Strings which should be - sent along with the request as metadata. + metadata (Sequence[Tuple[str, Union[str, bytes]]]): Key/value pairs which should be + sent along with the request as metadata. Normally, each value must be of type `str`, + but for metadata keys ending with the suffix `-bin`, the corresponding values must + be of type `bytes`. """ # Create or coerce a protobuf request object. # - Quick check: If we got a request object, we should *not* have diff --git a/packages/google-shopping-css/google/shopping/css_v1/services/account_labels_service/client.py b/packages/google-shopping-css/google/shopping/css_v1/services/account_labels_service/client.py index 4b29559d6563..92ce045e0ae2 100644 --- a/packages/google-shopping-css/google/shopping/css_v1/services/account_labels_service/client.py +++ b/packages/google-shopping-css/google/shopping/css_v1/services/account_labels_service/client.py @@ -14,6 +14,7 @@ # limitations under the License. # from collections import OrderedDict +import logging as std_logging import os import re from typing import ( @@ -48,6 +49,15 @@ except AttributeError: # pragma: NO COVER OptionalRetry = Union[retries.Retry, object, None] # type: ignore +try: + from google.api_core import client_logging # type: ignore + + CLIENT_LOGGING_SUPPORTED = True # pragma: NO COVER +except ImportError: # pragma: NO COVER + CLIENT_LOGGING_SUPPORTED = False + +_LOGGER = std_logging.getLogger(__name__) + from google.shopping.css_v1.services.account_labels_service import pagers from google.shopping.css_v1.types import accounts_labels @@ -577,6 +587,10 @@ def __init__( # Initialize the universe domain validation. self._is_universe_domain_valid = False + if CLIENT_LOGGING_SUPPORTED: # pragma: NO COVER + # Setup logging. + client_logging.initialize_logging() + api_key_value = getattr(self._client_options, "api_key", None) if api_key_value and credentials: raise ValueError( @@ -643,6 +657,29 @@ def __init__( api_audience=self._client_options.api_audience, ) + if "async" not in str(self._transport): + if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( + std_logging.DEBUG + ): # pragma: NO COVER + _LOGGER.debug( + "Created client `google.shopping.css_v1.AccountLabelsServiceClient`.", + extra={ + "serviceName": "google.shopping.css.v1.AccountLabelsService", + "universeDomain": getattr( + self._transport._credentials, "universe_domain", "" + ), + "credentialsType": f"{type(self._transport._credentials).__module__}.{type(self._transport._credentials).__qualname__}", + "credentialsInfo": getattr( + self.transport._credentials, "get_cred_info", lambda: None + )(), + } + if hasattr(self._transport, "_credentials") + else { + "serviceName": "google.shopping.css.v1.AccountLabelsService", + "credentialsType": None, + }, + ) + def list_account_labels( self, request: Optional[Union[accounts_labels.ListAccountLabelsRequest, dict]] = None, @@ -650,9 +687,9 @@ def list_account_labels( parent: Optional[str] = None, retry: OptionalRetry = gapic_v1.method.DEFAULT, timeout: Union[float, object] = gapic_v1.method.DEFAULT, - metadata: Sequence[Tuple[str, str]] = (), + metadata: Sequence[Tuple[str, Union[str, bytes]]] = (), ) -> pagers.ListAccountLabelsPager: - r"""Lists the labels assigned to an account. + r"""Lists the labels owned by an account. .. code-block:: python @@ -694,8 +731,10 @@ def sample_list_account_labels(): retry (google.api_core.retry.Retry): Designation of what errors, if any, should be retried. timeout (float): The timeout for this request. - metadata (Sequence[Tuple[str, str]]): Strings which should be - sent along with the request as metadata. + metadata (Sequence[Tuple[str, Union[str, bytes]]]): Key/value pairs which should be + sent along with the request as metadata. Normally, each value must be of type `str`, + but for metadata keys ending with the suffix `-bin`, the corresponding values must + be of type `bytes`. Returns: google.shopping.css_v1.services.account_labels_service.pagers.ListAccountLabelsPager: @@ -769,7 +808,7 @@ def create_account_label( account_label: Optional[accounts_labels.AccountLabel] = None, retry: OptionalRetry = gapic_v1.method.DEFAULT, timeout: Union[float, object] = gapic_v1.method.DEFAULT, - metadata: Sequence[Tuple[str, str]] = (), + metadata: Sequence[Tuple[str, Union[str, bytes]]] = (), ) -> accounts_labels.AccountLabel: r"""Creates a new label, not assigned to any account. @@ -818,8 +857,10 @@ def sample_create_account_label(): retry (google.api_core.retry.Retry): Designation of what errors, if any, should be retried. timeout (float): The timeout for this request. - metadata (Sequence[Tuple[str, str]]): Strings which should be - sent along with the request as metadata. + metadata (Sequence[Tuple[str, Union[str, bytes]]]): Key/value pairs which should be + sent along with the request as metadata. Normally, each value must be of type `str`, + but for metadata keys ending with the suffix `-bin`, the corresponding values must + be of type `bytes`. Returns: google.shopping.css_v1.types.AccountLabel: @@ -881,7 +922,7 @@ def update_account_label( account_label: Optional[accounts_labels.AccountLabel] = None, retry: OptionalRetry = gapic_v1.method.DEFAULT, timeout: Union[float, object] = gapic_v1.method.DEFAULT, - metadata: Sequence[Tuple[str, str]] = (), + metadata: Sequence[Tuple[str, Union[str, bytes]]] = (), ) -> accounts_labels.AccountLabel: r"""Updates a label. @@ -923,8 +964,10 @@ def sample_update_account_label(): retry (google.api_core.retry.Retry): Designation of what errors, if any, should be retried. timeout (float): The timeout for this request. - metadata (Sequence[Tuple[str, str]]): Strings which should be - sent along with the request as metadata. + metadata (Sequence[Tuple[str, Union[str, bytes]]]): Key/value pairs which should be + sent along with the request as metadata. Normally, each value must be of type `str`, + but for metadata keys ending with the suffix `-bin`, the corresponding values must + be of type `bytes`. Returns: google.shopping.css_v1.types.AccountLabel: @@ -986,7 +1029,7 @@ def delete_account_label( name: Optional[str] = None, retry: OptionalRetry = gapic_v1.method.DEFAULT, timeout: Union[float, object] = gapic_v1.method.DEFAULT, - metadata: Sequence[Tuple[str, str]] = (), + metadata: Sequence[Tuple[str, Union[str, bytes]]] = (), ) -> None: r"""Deletes a label and removes it from all accounts to which it was assigned. @@ -1029,8 +1072,10 @@ def sample_delete_account_label(): retry (google.api_core.retry.Retry): Designation of what errors, if any, should be retried. timeout (float): The timeout for this request. - metadata (Sequence[Tuple[str, str]]): Strings which should be - sent along with the request as metadata. + metadata (Sequence[Tuple[str, Union[str, bytes]]]): Key/value pairs which should be + sent along with the request as metadata. Normally, each value must be of type `str`, + but for metadata keys ending with the suffix `-bin`, the corresponding values must + be of type `bytes`. """ # Create or coerce a protobuf request object. # - Quick check: If we got a request object, we should *not* have diff --git a/packages/google-shopping-css/google/shopping/css_v1/services/account_labels_service/pagers.py b/packages/google-shopping-css/google/shopping/css_v1/services/account_labels_service/pagers.py index 2c4fcdcd2201..f1c3a5224d72 100644 --- a/packages/google-shopping-css/google/shopping/css_v1/services/account_labels_service/pagers.py +++ b/packages/google-shopping-css/google/shopping/css_v1/services/account_labels_service/pagers.py @@ -67,7 +67,7 @@ def __init__( *, retry: OptionalRetry = gapic_v1.method.DEFAULT, timeout: Union[float, object] = gapic_v1.method.DEFAULT, - metadata: Sequence[Tuple[str, str]] = () + metadata: Sequence[Tuple[str, Union[str, bytes]]] = () ): """Instantiate the pager. @@ -81,8 +81,10 @@ def __init__( retry (google.api_core.retry.Retry): Designation of what errors, if any, should be retried. timeout (float): The timeout for this request. - metadata (Sequence[Tuple[str, str]]): Strings which should be - sent along with the request as metadata. + metadata (Sequence[Tuple[str, Union[str, bytes]]]): Key/value pairs which should be + sent along with the request as metadata. Normally, each value must be of type `str`, + but for metadata keys ending with the suffix `-bin`, the corresponding values must + be of type `bytes`. """ self._method = method self._request = accounts_labels.ListAccountLabelsRequest(request) @@ -141,7 +143,7 @@ def __init__( *, retry: OptionalAsyncRetry = gapic_v1.method.DEFAULT, timeout: Union[float, object] = gapic_v1.method.DEFAULT, - metadata: Sequence[Tuple[str, str]] = () + metadata: Sequence[Tuple[str, Union[str, bytes]]] = () ): """Instantiates the pager. @@ -155,8 +157,10 @@ def __init__( retry (google.api_core.retry.AsyncRetry): Designation of what errors, if any, should be retried. timeout (float): The timeout for this request. - metadata (Sequence[Tuple[str, str]]): Strings which should be - sent along with the request as metadata. + metadata (Sequence[Tuple[str, Union[str, bytes]]]): Key/value pairs which should be + sent along with the request as metadata. Normally, each value must be of type `str`, + but for metadata keys ending with the suffix `-bin`, the corresponding values must + be of type `bytes`. """ self._method = method self._request = accounts_labels.ListAccountLabelsRequest(request) diff --git a/packages/google-shopping-css/google/shopping/css_v1/services/account_labels_service/transports/grpc.py b/packages/google-shopping-css/google/shopping/css_v1/services/account_labels_service/transports/grpc.py index f66a6122f35f..3d9467a9b2fe 100644 --- a/packages/google-shopping-css/google/shopping/css_v1/services/account_labels_service/transports/grpc.py +++ b/packages/google-shopping-css/google/shopping/css_v1/services/account_labels_service/transports/grpc.py @@ -13,6 +13,9 @@ # See the License for the specific language governing permissions and # limitations under the License. # +import json +import logging as std_logging +import pickle from typing import Callable, Dict, Optional, Sequence, Tuple, Union import warnings @@ -21,12 +24,90 @@ from google.auth import credentials as ga_credentials # type: ignore from google.auth.transport.grpc import SslCredentials # type: ignore from google.protobuf import empty_pb2 # type: ignore +from google.protobuf.json_format import MessageToJson +import google.protobuf.message import grpc # type: ignore +import proto # type: ignore from google.shopping.css_v1.types import accounts_labels from .base import DEFAULT_CLIENT_INFO, AccountLabelsServiceTransport +try: + from google.api_core import client_logging # type: ignore + + CLIENT_LOGGING_SUPPORTED = True # pragma: NO COVER +except ImportError: # pragma: NO COVER + CLIENT_LOGGING_SUPPORTED = False + +_LOGGER = std_logging.getLogger(__name__) + + +class _LoggingClientInterceptor(grpc.UnaryUnaryClientInterceptor): # pragma: NO COVER + def intercept_unary_unary(self, continuation, client_call_details, request): + logging_enabled = CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( + std_logging.DEBUG + ) + if logging_enabled: # pragma: NO COVER + request_metadata = client_call_details.metadata + if isinstance(request, proto.Message): + request_payload = type(request).to_json(request) + elif isinstance(request, google.protobuf.message.Message): + request_payload = MessageToJson(request) + else: + request_payload = f"{type(request).__name__}: {pickle.dumps(request)}" + + request_metadata = { + key: value.decode("utf-8") if isinstance(value, bytes) else value + for key, value in request_metadata + } + grpc_request = { + "payload": request_payload, + "requestMethod": "grpc", + "metadata": dict(request_metadata), + } + _LOGGER.debug( + f"Sending request for {client_call_details.method}", + extra={ + "serviceName": "google.shopping.css.v1.AccountLabelsService", + "rpcName": client_call_details.method, + "request": grpc_request, + "metadata": grpc_request["metadata"], + }, + ) + + response = continuation(client_call_details, request) + if logging_enabled: # pragma: NO COVER + response_metadata = response.trailing_metadata() + # Convert gRPC metadata `` to list of tuples + metadata = ( + dict([(k, str(v)) for k, v in response_metadata]) + if response_metadata + else None + ) + result = response.result() + if isinstance(result, proto.Message): + response_payload = type(result).to_json(result) + elif isinstance(result, google.protobuf.message.Message): + response_payload = MessageToJson(result) + else: + response_payload = f"{type(result).__name__}: {pickle.dumps(result)}" + grpc_response = { + "payload": response_payload, + "metadata": metadata, + "status": "OK", + } + _LOGGER.debug( + f"Received response for {client_call_details.method}.", + extra={ + "serviceName": "google.shopping.css.v1.AccountLabelsService", + "rpcName": client_call_details.method, + "response": grpc_response, + "metadata": grpc_response["metadata"], + }, + ) + return response + class AccountLabelsServiceGrpcTransport(AccountLabelsServiceTransport): """gRPC backend transport for AccountLabelsService. @@ -180,7 +261,12 @@ def __init__( ], ) - # Wrap messages. This must be done after self._grpc_channel exists + self._interceptor = _LoggingClientInterceptor() + self._logged_channel = grpc.intercept_channel( + self._grpc_channel, self._interceptor + ) + + # Wrap messages. This must be done after self._logged_channel exists self._prep_wrapped_messages(client_info) @classmethod @@ -244,7 +330,7 @@ def list_account_labels( ]: r"""Return a callable for the list account labels method over gRPC. - Lists the labels assigned to an account. + Lists the labels owned by an account. Returns: Callable[[~.ListAccountLabelsRequest], @@ -257,7 +343,7 @@ def list_account_labels( # gRPC handles serialization and deserialization, so we just need # to pass in the functions for each. if "list_account_labels" not in self._stubs: - self._stubs["list_account_labels"] = self.grpc_channel.unary_unary( + self._stubs["list_account_labels"] = self._logged_channel.unary_unary( "/google.shopping.css.v1.AccountLabelsService/ListAccountLabels", request_serializer=accounts_labels.ListAccountLabelsRequest.serialize, response_deserializer=accounts_labels.ListAccountLabelsResponse.deserialize, @@ -285,7 +371,7 @@ def create_account_label( # gRPC handles serialization and deserialization, so we just need # to pass in the functions for each. if "create_account_label" not in self._stubs: - self._stubs["create_account_label"] = self.grpc_channel.unary_unary( + self._stubs["create_account_label"] = self._logged_channel.unary_unary( "/google.shopping.css.v1.AccountLabelsService/CreateAccountLabel", request_serializer=accounts_labels.CreateAccountLabelRequest.serialize, response_deserializer=accounts_labels.AccountLabel.deserialize, @@ -313,7 +399,7 @@ def update_account_label( # gRPC handles serialization and deserialization, so we just need # to pass in the functions for each. if "update_account_label" not in self._stubs: - self._stubs["update_account_label"] = self.grpc_channel.unary_unary( + self._stubs["update_account_label"] = self._logged_channel.unary_unary( "/google.shopping.css.v1.AccountLabelsService/UpdateAccountLabel", request_serializer=accounts_labels.UpdateAccountLabelRequest.serialize, response_deserializer=accounts_labels.AccountLabel.deserialize, @@ -340,7 +426,7 @@ def delete_account_label( # gRPC handles serialization and deserialization, so we just need # to pass in the functions for each. if "delete_account_label" not in self._stubs: - self._stubs["delete_account_label"] = self.grpc_channel.unary_unary( + self._stubs["delete_account_label"] = self._logged_channel.unary_unary( "/google.shopping.css.v1.AccountLabelsService/DeleteAccountLabel", request_serializer=accounts_labels.DeleteAccountLabelRequest.serialize, response_deserializer=empty_pb2.Empty.FromString, @@ -348,7 +434,7 @@ def delete_account_label( return self._stubs["delete_account_label"] def close(self): - self.grpc_channel.close() + self._logged_channel.close() @property def kind(self) -> str: diff --git a/packages/google-shopping-css/google/shopping/css_v1/services/account_labels_service/transports/grpc_asyncio.py b/packages/google-shopping-css/google/shopping/css_v1/services/account_labels_service/transports/grpc_asyncio.py index cf2c05d3337b..678c64874a47 100644 --- a/packages/google-shopping-css/google/shopping/css_v1/services/account_labels_service/transports/grpc_asyncio.py +++ b/packages/google-shopping-css/google/shopping/css_v1/services/account_labels_service/transports/grpc_asyncio.py @@ -14,6 +14,9 @@ # limitations under the License. # import inspect +import json +import logging as std_logging +import pickle from typing import Awaitable, Callable, Dict, Optional, Sequence, Tuple, Union import warnings @@ -23,14 +26,93 @@ from google.auth import credentials as ga_credentials # type: ignore from google.auth.transport.grpc import SslCredentials # type: ignore from google.protobuf import empty_pb2 # type: ignore +from google.protobuf.json_format import MessageToJson +import google.protobuf.message import grpc # type: ignore from grpc.experimental import aio # type: ignore +import proto # type: ignore from google.shopping.css_v1.types import accounts_labels from .base import DEFAULT_CLIENT_INFO, AccountLabelsServiceTransport from .grpc import AccountLabelsServiceGrpcTransport +try: + from google.api_core import client_logging # type: ignore + + CLIENT_LOGGING_SUPPORTED = True # pragma: NO COVER +except ImportError: # pragma: NO COVER + CLIENT_LOGGING_SUPPORTED = False + +_LOGGER = std_logging.getLogger(__name__) + + +class _LoggingClientAIOInterceptor( + grpc.aio.UnaryUnaryClientInterceptor +): # pragma: NO COVER + async def intercept_unary_unary(self, continuation, client_call_details, request): + logging_enabled = CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( + std_logging.DEBUG + ) + if logging_enabled: # pragma: NO COVER + request_metadata = client_call_details.metadata + if isinstance(request, proto.Message): + request_payload = type(request).to_json(request) + elif isinstance(request, google.protobuf.message.Message): + request_payload = MessageToJson(request) + else: + request_payload = f"{type(request).__name__}: {pickle.dumps(request)}" + + request_metadata = { + key: value.decode("utf-8") if isinstance(value, bytes) else value + for key, value in request_metadata + } + grpc_request = { + "payload": request_payload, + "requestMethod": "grpc", + "metadata": dict(request_metadata), + } + _LOGGER.debug( + f"Sending request for {client_call_details.method}", + extra={ + "serviceName": "google.shopping.css.v1.AccountLabelsService", + "rpcName": str(client_call_details.method), + "request": grpc_request, + "metadata": grpc_request["metadata"], + }, + ) + response = await continuation(client_call_details, request) + if logging_enabled: # pragma: NO COVER + response_metadata = await response.trailing_metadata() + # Convert gRPC metadata `` to list of tuples + metadata = ( + dict([(k, str(v)) for k, v in response_metadata]) + if response_metadata + else None + ) + result = await response + if isinstance(result, proto.Message): + response_payload = type(result).to_json(result) + elif isinstance(result, google.protobuf.message.Message): + response_payload = MessageToJson(result) + else: + response_payload = f"{type(result).__name__}: {pickle.dumps(result)}" + grpc_response = { + "payload": response_payload, + "metadata": metadata, + "status": "OK", + } + _LOGGER.debug( + f"Received response to rpc {client_call_details.method}.", + extra={ + "serviceName": "google.shopping.css.v1.AccountLabelsService", + "rpcName": str(client_call_details.method), + "response": grpc_response, + "metadata": grpc_response["metadata"], + }, + ) + return response + class AccountLabelsServiceGrpcAsyncIOTransport(AccountLabelsServiceTransport): """gRPC AsyncIO backend transport for AccountLabelsService. @@ -227,10 +309,13 @@ def __init__( ], ) - # Wrap messages. This must be done after self._grpc_channel exists + self._interceptor = _LoggingClientAIOInterceptor() + self._grpc_channel._unary_unary_interceptors.append(self._interceptor) + self._logged_channel = self._grpc_channel self._wrap_with_kind = ( "kind" in inspect.signature(gapic_v1.method_async.wrap_method).parameters ) + # Wrap messages. This must be done after self._logged_channel exists self._prep_wrapped_messages(client_info) @property @@ -252,7 +337,7 @@ def list_account_labels( ]: r"""Return a callable for the list account labels method over gRPC. - Lists the labels assigned to an account. + Lists the labels owned by an account. Returns: Callable[[~.ListAccountLabelsRequest], @@ -265,7 +350,7 @@ def list_account_labels( # gRPC handles serialization and deserialization, so we just need # to pass in the functions for each. if "list_account_labels" not in self._stubs: - self._stubs["list_account_labels"] = self.grpc_channel.unary_unary( + self._stubs["list_account_labels"] = self._logged_channel.unary_unary( "/google.shopping.css.v1.AccountLabelsService/ListAccountLabels", request_serializer=accounts_labels.ListAccountLabelsRequest.serialize, response_deserializer=accounts_labels.ListAccountLabelsResponse.deserialize, @@ -294,7 +379,7 @@ def create_account_label( # gRPC handles serialization and deserialization, so we just need # to pass in the functions for each. if "create_account_label" not in self._stubs: - self._stubs["create_account_label"] = self.grpc_channel.unary_unary( + self._stubs["create_account_label"] = self._logged_channel.unary_unary( "/google.shopping.css.v1.AccountLabelsService/CreateAccountLabel", request_serializer=accounts_labels.CreateAccountLabelRequest.serialize, response_deserializer=accounts_labels.AccountLabel.deserialize, @@ -323,7 +408,7 @@ def update_account_label( # gRPC handles serialization and deserialization, so we just need # to pass in the functions for each. if "update_account_label" not in self._stubs: - self._stubs["update_account_label"] = self.grpc_channel.unary_unary( + self._stubs["update_account_label"] = self._logged_channel.unary_unary( "/google.shopping.css.v1.AccountLabelsService/UpdateAccountLabel", request_serializer=accounts_labels.UpdateAccountLabelRequest.serialize, response_deserializer=accounts_labels.AccountLabel.deserialize, @@ -352,7 +437,7 @@ def delete_account_label( # gRPC handles serialization and deserialization, so we just need # to pass in the functions for each. if "delete_account_label" not in self._stubs: - self._stubs["delete_account_label"] = self.grpc_channel.unary_unary( + self._stubs["delete_account_label"] = self._logged_channel.unary_unary( "/google.shopping.css.v1.AccountLabelsService/DeleteAccountLabel", request_serializer=accounts_labels.DeleteAccountLabelRequest.serialize, response_deserializer=empty_pb2.Empty.FromString, @@ -399,7 +484,7 @@ def _wrap_method(self, func, *args, **kwargs): return gapic_v1.method_async.wrap_method(func, *args, **kwargs) def close(self): - return self.grpc_channel.close() + return self._logged_channel.close() @property def kind(self) -> str: diff --git a/packages/google-shopping-css/google/shopping/css_v1/services/account_labels_service/transports/rest.py b/packages/google-shopping-css/google/shopping/css_v1/services/account_labels_service/transports/rest.py index 5d8eb88e7636..40e81c19ee91 100644 --- a/packages/google-shopping-css/google/shopping/css_v1/services/account_labels_service/transports/rest.py +++ b/packages/google-shopping-css/google/shopping/css_v1/services/account_labels_service/transports/rest.py @@ -13,9 +13,9 @@ # See the License for the specific language governing permissions and # limitations under the License. # - import dataclasses import json # type: ignore +import logging from typing import Any, Callable, Dict, List, Optional, Sequence, Tuple, Union import warnings @@ -38,6 +38,14 @@ except AttributeError: # pragma: NO COVER OptionalRetry = Union[retries.Retry, object, None] # type: ignore +try: + from google.api_core import client_logging # type: ignore + + CLIENT_LOGGING_SUPPORTED = True # pragma: NO COVER +except ImportError: # pragma: NO COVER + CLIENT_LOGGING_SUPPORTED = False + +_LOGGER = logging.getLogger(__name__) DEFAULT_CLIENT_INFO = gapic_v1.client_info.ClientInfo( gapic_version=BASE_DEFAULT_CLIENT_INFO.gapic_version, @@ -98,8 +106,11 @@ def post_update_account_label(self, response): def pre_create_account_label( self, request: accounts_labels.CreateAccountLabelRequest, - metadata: Sequence[Tuple[str, str]], - ) -> Tuple[accounts_labels.CreateAccountLabelRequest, Sequence[Tuple[str, str]]]: + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[ + accounts_labels.CreateAccountLabelRequest, + Sequence[Tuple[str, Union[str, bytes]]], + ]: """Pre-rpc interceptor for create_account_label Override in a subclass to manipulate the request or metadata @@ -121,8 +132,11 @@ def post_create_account_label( def pre_delete_account_label( self, request: accounts_labels.DeleteAccountLabelRequest, - metadata: Sequence[Tuple[str, str]], - ) -> Tuple[accounts_labels.DeleteAccountLabelRequest, Sequence[Tuple[str, str]]]: + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[ + accounts_labels.DeleteAccountLabelRequest, + Sequence[Tuple[str, Union[str, bytes]]], + ]: """Pre-rpc interceptor for delete_account_label Override in a subclass to manipulate the request or metadata @@ -133,8 +147,11 @@ def pre_delete_account_label( def pre_list_account_labels( self, request: accounts_labels.ListAccountLabelsRequest, - metadata: Sequence[Tuple[str, str]], - ) -> Tuple[accounts_labels.ListAccountLabelsRequest, Sequence[Tuple[str, str]]]: + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[ + accounts_labels.ListAccountLabelsRequest, + Sequence[Tuple[str, Union[str, bytes]]], + ]: """Pre-rpc interceptor for list_account_labels Override in a subclass to manipulate the request or metadata @@ -156,8 +173,11 @@ def post_list_account_labels( def pre_update_account_label( self, request: accounts_labels.UpdateAccountLabelRequest, - metadata: Sequence[Tuple[str, str]], - ) -> Tuple[accounts_labels.UpdateAccountLabelRequest, Sequence[Tuple[str, str]]]: + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[ + accounts_labels.UpdateAccountLabelRequest, + Sequence[Tuple[str, Union[str, bytes]]], + ]: """Pre-rpc interceptor for update_account_label Override in a subclass to manipulate the request or metadata @@ -299,7 +319,7 @@ def __call__( *, retry: OptionalRetry = gapic_v1.method.DEFAULT, timeout: Optional[float] = None, - metadata: Sequence[Tuple[str, str]] = (), + metadata: Sequence[Tuple[str, Union[str, bytes]]] = (), ) -> accounts_labels.AccountLabel: r"""Call the create account label method over HTTP. @@ -310,8 +330,10 @@ def __call__( retry (google.api_core.retry.Retry): Designation of what errors, if any, should be retried. timeout (float): The timeout for this request. - metadata (Sequence[Tuple[str, str]]): Strings which should be - sent along with the request as metadata. + metadata (Sequence[Tuple[str, Union[str, bytes]]]): Key/value pairs which should be + sent along with the request as metadata. Normally, each value must be of type `str`, + but for metadata keys ending with the suffix `-bin`, the corresponding values must + be of type `bytes`. Returns: ~.accounts_labels.AccountLabel: @@ -323,6 +345,7 @@ def __call__( http_options = ( _BaseAccountLabelsServiceRestTransport._BaseCreateAccountLabel._get_http_options() ) + request, metadata = self._interceptor.pre_create_account_label( request, metadata ) @@ -339,6 +362,33 @@ def __call__( transcoded_request ) + if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( + logging.DEBUG + ): # pragma: NO COVER + request_url = "{host}{uri}".format( + host=self._host, uri=transcoded_request["uri"] + ) + method = transcoded_request["method"] + try: + request_payload = type(request).to_json(request) + except: + request_payload = None + http_request = { + "payload": request_payload, + "requestMethod": method, + "requestUrl": request_url, + "headers": dict(metadata), + } + _LOGGER.debug( + f"Sending request for google.shopping.css_v1.AccountLabelsServiceClient.CreateAccountLabel", + extra={ + "serviceName": "google.shopping.css.v1.AccountLabelsService", + "rpcName": "CreateAccountLabel", + "httpRequest": http_request, + "metadata": http_request["headers"], + }, + ) + # Send the request response = ( AccountLabelsServiceRestTransport._CreateAccountLabel._get_response( @@ -362,7 +412,29 @@ def __call__( pb_resp = accounts_labels.AccountLabel.pb(resp) json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) + resp = self._interceptor.post_create_account_label(resp) + if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( + logging.DEBUG + ): # pragma: NO COVER + try: + response_payload = accounts_labels.AccountLabel.to_json(response) + except: + response_payload = None + http_response = { + "payload": response_payload, + "headers": dict(response.headers), + "status": response.status_code, + } + _LOGGER.debug( + "Received response for google.shopping.css_v1.AccountLabelsServiceClient.create_account_label", + extra={ + "serviceName": "google.shopping.css.v1.AccountLabelsService", + "rpcName": "CreateAccountLabel", + "metadata": http_response["headers"], + "httpResponse": http_response, + }, + ) return resp class _DeleteAccountLabel( @@ -400,7 +472,7 @@ def __call__( *, retry: OptionalRetry = gapic_v1.method.DEFAULT, timeout: Optional[float] = None, - metadata: Sequence[Tuple[str, str]] = (), + metadata: Sequence[Tuple[str, Union[str, bytes]]] = (), ): r"""Call the delete account label method over HTTP. @@ -411,13 +483,16 @@ def __call__( retry (google.api_core.retry.Retry): Designation of what errors, if any, should be retried. timeout (float): The timeout for this request. - metadata (Sequence[Tuple[str, str]]): Strings which should be - sent along with the request as metadata. + metadata (Sequence[Tuple[str, Union[str, bytes]]]): Key/value pairs which should be + sent along with the request as metadata. Normally, each value must be of type `str`, + but for metadata keys ending with the suffix `-bin`, the corresponding values must + be of type `bytes`. """ http_options = ( _BaseAccountLabelsServiceRestTransport._BaseDeleteAccountLabel._get_http_options() ) + request, metadata = self._interceptor.pre_delete_account_label( request, metadata ) @@ -430,6 +505,33 @@ def __call__( transcoded_request ) + if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( + logging.DEBUG + ): # pragma: NO COVER + request_url = "{host}{uri}".format( + host=self._host, uri=transcoded_request["uri"] + ) + method = transcoded_request["method"] + try: + request_payload = json_format.MessageToJson(request) + except: + request_payload = None + http_request = { + "payload": request_payload, + "requestMethod": method, + "requestUrl": request_url, + "headers": dict(metadata), + } + _LOGGER.debug( + f"Sending request for google.shopping.css_v1.AccountLabelsServiceClient.DeleteAccountLabel", + extra={ + "serviceName": "google.shopping.css.v1.AccountLabelsService", + "rpcName": "DeleteAccountLabel", + "httpRequest": http_request, + "metadata": http_request["headers"], + }, + ) + # Send the request response = ( AccountLabelsServiceRestTransport._DeleteAccountLabel._get_response( @@ -482,7 +584,7 @@ def __call__( *, retry: OptionalRetry = gapic_v1.method.DEFAULT, timeout: Optional[float] = None, - metadata: Sequence[Tuple[str, str]] = (), + metadata: Sequence[Tuple[str, Union[str, bytes]]] = (), ) -> accounts_labels.ListAccountLabelsResponse: r"""Call the list account labels method over HTTP. @@ -492,8 +594,10 @@ def __call__( retry (google.api_core.retry.Retry): Designation of what errors, if any, should be retried. timeout (float): The timeout for this request. - metadata (Sequence[Tuple[str, str]]): Strings which should be - sent along with the request as metadata. + metadata (Sequence[Tuple[str, Union[str, bytes]]]): Key/value pairs which should be + sent along with the request as metadata. Normally, each value must be of type `str`, + but for metadata keys ending with the suffix `-bin`, the corresponding values must + be of type `bytes`. Returns: ~.accounts_labels.ListAccountLabelsResponse: @@ -503,6 +607,7 @@ def __call__( http_options = ( _BaseAccountLabelsServiceRestTransport._BaseListAccountLabels._get_http_options() ) + request, metadata = self._interceptor.pre_list_account_labels( request, metadata ) @@ -515,6 +620,33 @@ def __call__( transcoded_request ) + if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( + logging.DEBUG + ): # pragma: NO COVER + request_url = "{host}{uri}".format( + host=self._host, uri=transcoded_request["uri"] + ) + method = transcoded_request["method"] + try: + request_payload = type(request).to_json(request) + except: + request_payload = None + http_request = { + "payload": request_payload, + "requestMethod": method, + "requestUrl": request_url, + "headers": dict(metadata), + } + _LOGGER.debug( + f"Sending request for google.shopping.css_v1.AccountLabelsServiceClient.ListAccountLabels", + extra={ + "serviceName": "google.shopping.css.v1.AccountLabelsService", + "rpcName": "ListAccountLabels", + "httpRequest": http_request, + "metadata": http_request["headers"], + }, + ) + # Send the request response = ( AccountLabelsServiceRestTransport._ListAccountLabels._get_response( @@ -537,7 +669,31 @@ def __call__( pb_resp = accounts_labels.ListAccountLabelsResponse.pb(resp) json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) + resp = self._interceptor.post_list_account_labels(resp) + if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( + logging.DEBUG + ): # pragma: NO COVER + try: + response_payload = ( + accounts_labels.ListAccountLabelsResponse.to_json(response) + ) + except: + response_payload = None + http_response = { + "payload": response_payload, + "headers": dict(response.headers), + "status": response.status_code, + } + _LOGGER.debug( + "Received response for google.shopping.css_v1.AccountLabelsServiceClient.list_account_labels", + extra={ + "serviceName": "google.shopping.css.v1.AccountLabelsService", + "rpcName": "ListAccountLabels", + "metadata": http_response["headers"], + "httpResponse": http_response, + }, + ) return resp class _UpdateAccountLabel( @@ -576,7 +732,7 @@ def __call__( *, retry: OptionalRetry = gapic_v1.method.DEFAULT, timeout: Optional[float] = None, - metadata: Sequence[Tuple[str, str]] = (), + metadata: Sequence[Tuple[str, Union[str, bytes]]] = (), ) -> accounts_labels.AccountLabel: r"""Call the update account label method over HTTP. @@ -586,8 +742,10 @@ def __call__( retry (google.api_core.retry.Retry): Designation of what errors, if any, should be retried. timeout (float): The timeout for this request. - metadata (Sequence[Tuple[str, str]]): Strings which should be - sent along with the request as metadata. + metadata (Sequence[Tuple[str, Union[str, bytes]]]): Key/value pairs which should be + sent along with the request as metadata. Normally, each value must be of type `str`, + but for metadata keys ending with the suffix `-bin`, the corresponding values must + be of type `bytes`. Returns: ~.accounts_labels.AccountLabel: @@ -599,6 +757,7 @@ def __call__( http_options = ( _BaseAccountLabelsServiceRestTransport._BaseUpdateAccountLabel._get_http_options() ) + request, metadata = self._interceptor.pre_update_account_label( request, metadata ) @@ -615,6 +774,33 @@ def __call__( transcoded_request ) + if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( + logging.DEBUG + ): # pragma: NO COVER + request_url = "{host}{uri}".format( + host=self._host, uri=transcoded_request["uri"] + ) + method = transcoded_request["method"] + try: + request_payload = type(request).to_json(request) + except: + request_payload = None + http_request = { + "payload": request_payload, + "requestMethod": method, + "requestUrl": request_url, + "headers": dict(metadata), + } + _LOGGER.debug( + f"Sending request for google.shopping.css_v1.AccountLabelsServiceClient.UpdateAccountLabel", + extra={ + "serviceName": "google.shopping.css.v1.AccountLabelsService", + "rpcName": "UpdateAccountLabel", + "httpRequest": http_request, + "metadata": http_request["headers"], + }, + ) + # Send the request response = ( AccountLabelsServiceRestTransport._UpdateAccountLabel._get_response( @@ -638,7 +824,29 @@ def __call__( pb_resp = accounts_labels.AccountLabel.pb(resp) json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) + resp = self._interceptor.post_update_account_label(resp) + if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( + logging.DEBUG + ): # pragma: NO COVER + try: + response_payload = accounts_labels.AccountLabel.to_json(response) + except: + response_payload = None + http_response = { + "payload": response_payload, + "headers": dict(response.headers), + "status": response.status_code, + } + _LOGGER.debug( + "Received response for google.shopping.css_v1.AccountLabelsServiceClient.update_account_label", + extra={ + "serviceName": "google.shopping.css.v1.AccountLabelsService", + "rpcName": "UpdateAccountLabel", + "metadata": http_response["headers"], + "httpResponse": http_response, + }, + ) return resp @property diff --git a/packages/google-shopping-css/google/shopping/css_v1/services/accounts_service/async_client.py b/packages/google-shopping-css/google/shopping/css_v1/services/accounts_service/async_client.py index 0cb6cae3efce..ffe3a66e987c 100644 --- a/packages/google-shopping-css/google/shopping/css_v1/services/accounts_service/async_client.py +++ b/packages/google-shopping-css/google/shopping/css_v1/services/accounts_service/async_client.py @@ -14,6 +14,7 @@ # limitations under the License. # from collections import OrderedDict +import logging as std_logging import re from typing import ( Callable, @@ -49,6 +50,15 @@ from .transports.base import DEFAULT_CLIENT_INFO, AccountsServiceTransport from .transports.grpc_asyncio import AccountsServiceGrpcAsyncIOTransport +try: + from google.api_core import client_logging # type: ignore + + CLIENT_LOGGING_SUPPORTED = True # pragma: NO COVER +except ImportError: # pragma: NO COVER + CLIENT_LOGGING_SUPPORTED = False + +_LOGGER = std_logging.getLogger(__name__) + class AccountsServiceAsyncClient: """Service for managing CSS/MC account information.""" @@ -256,6 +266,28 @@ def __init__( client_info=client_info, ) + if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( + std_logging.DEBUG + ): # pragma: NO COVER + _LOGGER.debug( + "Created client `google.shopping.css_v1.AccountsServiceAsyncClient`.", + extra={ + "serviceName": "google.shopping.css.v1.AccountsService", + "universeDomain": getattr( + self._client._transport._credentials, "universe_domain", "" + ), + "credentialsType": f"{type(self._client._transport._credentials).__module__}.{type(self._client._transport._credentials).__qualname__}", + "credentialsInfo": getattr( + self.transport._credentials, "get_cred_info", lambda: None + )(), + } + if hasattr(self._client._transport, "_credentials") + else { + "serviceName": "google.shopping.css.v1.AccountsService", + "credentialsType": None, + }, + ) + async def list_child_accounts( self, request: Optional[Union[accounts.ListChildAccountsRequest, dict]] = None, @@ -263,7 +295,7 @@ async def list_child_accounts( parent: Optional[str] = None, retry: OptionalRetry = gapic_v1.method.DEFAULT, timeout: Union[float, object] = gapic_v1.method.DEFAULT, - metadata: Sequence[Tuple[str, str]] = (), + metadata: Sequence[Tuple[str, Union[str, bytes]]] = (), ) -> pagers.ListChildAccountsAsyncPager: r"""Lists all the accounts under the specified CSS account ID, and optionally filters by label ID and @@ -311,8 +343,10 @@ async def sample_list_child_accounts(): retry (google.api_core.retry_async.AsyncRetry): Designation of what errors, if any, should be retried. timeout (float): The timeout for this request. - metadata (Sequence[Tuple[str, str]]): Strings which should be - sent along with the request as metadata. + metadata (Sequence[Tuple[str, Union[str, bytes]]]): Key/value pairs which should be + sent along with the request as metadata. Normally, each value must be of type `str`, + but for metadata keys ending with the suffix `-bin`, the corresponding values must + be of type `bytes`. Returns: google.shopping.css_v1.services.accounts_service.pagers.ListChildAccountsAsyncPager: @@ -386,7 +420,7 @@ async def get_account( name: Optional[str] = None, retry: OptionalRetry = gapic_v1.method.DEFAULT, timeout: Union[float, object] = gapic_v1.method.DEFAULT, - metadata: Sequence[Tuple[str, str]] = (), + metadata: Sequence[Tuple[str, Union[str, bytes]]] = (), ) -> accounts.Account: r"""Retrieves a single CSS/MC account by ID. @@ -430,8 +464,10 @@ async def sample_get_account(): retry (google.api_core.retry_async.AsyncRetry): Designation of what errors, if any, should be retried. timeout (float): The timeout for this request. - metadata (Sequence[Tuple[str, str]]): Strings which should be - sent along with the request as metadata. + metadata (Sequence[Tuple[str, Union[str, bytes]]]): Key/value pairs which should be + sent along with the request as metadata. Normally, each value must be of type `str`, + but for metadata keys ending with the suffix `-bin`, the corresponding values must + be of type `bytes`. Returns: google.shopping.css_v1.types.Account: @@ -490,7 +526,7 @@ async def update_labels( name: Optional[str] = None, retry: OptionalRetry = gapic_v1.method.DEFAULT, timeout: Union[float, object] = gapic_v1.method.DEFAULT, - metadata: Sequence[Tuple[str, str]] = (), + metadata: Sequence[Tuple[str, Union[str, bytes]]] = (), ) -> accounts.Account: r"""Updates labels assigned to CSS/MC accounts by a CSS domain. @@ -534,8 +570,10 @@ async def sample_update_labels(): retry (google.api_core.retry_async.AsyncRetry): Designation of what errors, if any, should be retried. timeout (float): The timeout for this request. - metadata (Sequence[Tuple[str, str]]): Strings which should be - sent along with the request as metadata. + metadata (Sequence[Tuple[str, Union[str, bytes]]]): Key/value pairs which should be + sent along with the request as metadata. Normally, each value must be of type `str`, + but for metadata keys ending with the suffix `-bin`, the corresponding values must + be of type `bytes`. Returns: google.shopping.css_v1.types.Account: diff --git a/packages/google-shopping-css/google/shopping/css_v1/services/accounts_service/client.py b/packages/google-shopping-css/google/shopping/css_v1/services/accounts_service/client.py index 6b1360339591..607097515615 100644 --- a/packages/google-shopping-css/google/shopping/css_v1/services/accounts_service/client.py +++ b/packages/google-shopping-css/google/shopping/css_v1/services/accounts_service/client.py @@ -14,6 +14,7 @@ # limitations under the License. # from collections import OrderedDict +import logging as std_logging import os import re from typing import ( @@ -48,6 +49,15 @@ except AttributeError: # pragma: NO COVER OptionalRetry = Union[retries.Retry, object, None] # type: ignore +try: + from google.api_core import client_logging # type: ignore + + CLIENT_LOGGING_SUPPORTED = True # pragma: NO COVER +except ImportError: # pragma: NO COVER + CLIENT_LOGGING_SUPPORTED = False + +_LOGGER = std_logging.getLogger(__name__) + from google.shopping.css_v1.services.accounts_service import pagers from google.shopping.css_v1.types import accounts @@ -573,6 +583,10 @@ def __init__( # Initialize the universe domain validation. self._is_universe_domain_valid = False + if CLIENT_LOGGING_SUPPORTED: # pragma: NO COVER + # Setup logging. + client_logging.initialize_logging() + api_key_value = getattr(self._client_options, "api_key", None) if api_key_value and credentials: raise ValueError( @@ -638,6 +652,29 @@ def __init__( api_audience=self._client_options.api_audience, ) + if "async" not in str(self._transport): + if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( + std_logging.DEBUG + ): # pragma: NO COVER + _LOGGER.debug( + "Created client `google.shopping.css_v1.AccountsServiceClient`.", + extra={ + "serviceName": "google.shopping.css.v1.AccountsService", + "universeDomain": getattr( + self._transport._credentials, "universe_domain", "" + ), + "credentialsType": f"{type(self._transport._credentials).__module__}.{type(self._transport._credentials).__qualname__}", + "credentialsInfo": getattr( + self.transport._credentials, "get_cred_info", lambda: None + )(), + } + if hasattr(self._transport, "_credentials") + else { + "serviceName": "google.shopping.css.v1.AccountsService", + "credentialsType": None, + }, + ) + def list_child_accounts( self, request: Optional[Union[accounts.ListChildAccountsRequest, dict]] = None, @@ -645,7 +682,7 @@ def list_child_accounts( parent: Optional[str] = None, retry: OptionalRetry = gapic_v1.method.DEFAULT, timeout: Union[float, object] = gapic_v1.method.DEFAULT, - metadata: Sequence[Tuple[str, str]] = (), + metadata: Sequence[Tuple[str, Union[str, bytes]]] = (), ) -> pagers.ListChildAccountsPager: r"""Lists all the accounts under the specified CSS account ID, and optionally filters by label ID and @@ -693,8 +730,10 @@ def sample_list_child_accounts(): retry (google.api_core.retry.Retry): Designation of what errors, if any, should be retried. timeout (float): The timeout for this request. - metadata (Sequence[Tuple[str, str]]): Strings which should be - sent along with the request as metadata. + metadata (Sequence[Tuple[str, Union[str, bytes]]]): Key/value pairs which should be + sent along with the request as metadata. Normally, each value must be of type `str`, + but for metadata keys ending with the suffix `-bin`, the corresponding values must + be of type `bytes`. Returns: google.shopping.css_v1.services.accounts_service.pagers.ListChildAccountsPager: @@ -765,7 +804,7 @@ def get_account( name: Optional[str] = None, retry: OptionalRetry = gapic_v1.method.DEFAULT, timeout: Union[float, object] = gapic_v1.method.DEFAULT, - metadata: Sequence[Tuple[str, str]] = (), + metadata: Sequence[Tuple[str, Union[str, bytes]]] = (), ) -> accounts.Account: r"""Retrieves a single CSS/MC account by ID. @@ -809,8 +848,10 @@ def sample_get_account(): retry (google.api_core.retry.Retry): Designation of what errors, if any, should be retried. timeout (float): The timeout for this request. - metadata (Sequence[Tuple[str, str]]): Strings which should be - sent along with the request as metadata. + metadata (Sequence[Tuple[str, Union[str, bytes]]]): Key/value pairs which should be + sent along with the request as metadata. Normally, each value must be of type `str`, + but for metadata keys ending with the suffix `-bin`, the corresponding values must + be of type `bytes`. Returns: google.shopping.css_v1.types.Account: @@ -866,7 +907,7 @@ def update_labels( name: Optional[str] = None, retry: OptionalRetry = gapic_v1.method.DEFAULT, timeout: Union[float, object] = gapic_v1.method.DEFAULT, - metadata: Sequence[Tuple[str, str]] = (), + metadata: Sequence[Tuple[str, Union[str, bytes]]] = (), ) -> accounts.Account: r"""Updates labels assigned to CSS/MC accounts by a CSS domain. @@ -910,8 +951,10 @@ def sample_update_labels(): retry (google.api_core.retry.Retry): Designation of what errors, if any, should be retried. timeout (float): The timeout for this request. - metadata (Sequence[Tuple[str, str]]): Strings which should be - sent along with the request as metadata. + metadata (Sequence[Tuple[str, Union[str, bytes]]]): Key/value pairs which should be + sent along with the request as metadata. Normally, each value must be of type `str`, + but for metadata keys ending with the suffix `-bin`, the corresponding values must + be of type `bytes`. Returns: google.shopping.css_v1.types.Account: diff --git a/packages/google-shopping-css/google/shopping/css_v1/services/accounts_service/pagers.py b/packages/google-shopping-css/google/shopping/css_v1/services/accounts_service/pagers.py index 957a41cb4042..5b56fdd4c2ee 100644 --- a/packages/google-shopping-css/google/shopping/css_v1/services/accounts_service/pagers.py +++ b/packages/google-shopping-css/google/shopping/css_v1/services/accounts_service/pagers.py @@ -67,7 +67,7 @@ def __init__( *, retry: OptionalRetry = gapic_v1.method.DEFAULT, timeout: Union[float, object] = gapic_v1.method.DEFAULT, - metadata: Sequence[Tuple[str, str]] = () + metadata: Sequence[Tuple[str, Union[str, bytes]]] = () ): """Instantiate the pager. @@ -81,8 +81,10 @@ def __init__( retry (google.api_core.retry.Retry): Designation of what errors, if any, should be retried. timeout (float): The timeout for this request. - metadata (Sequence[Tuple[str, str]]): Strings which should be - sent along with the request as metadata. + metadata (Sequence[Tuple[str, Union[str, bytes]]]): Key/value pairs which should be + sent along with the request as metadata. Normally, each value must be of type `str`, + but for metadata keys ending with the suffix `-bin`, the corresponding values must + be of type `bytes`. """ self._method = method self._request = accounts.ListChildAccountsRequest(request) @@ -141,7 +143,7 @@ def __init__( *, retry: OptionalAsyncRetry = gapic_v1.method.DEFAULT, timeout: Union[float, object] = gapic_v1.method.DEFAULT, - metadata: Sequence[Tuple[str, str]] = () + metadata: Sequence[Tuple[str, Union[str, bytes]]] = () ): """Instantiates the pager. @@ -155,8 +157,10 @@ def __init__( retry (google.api_core.retry.AsyncRetry): Designation of what errors, if any, should be retried. timeout (float): The timeout for this request. - metadata (Sequence[Tuple[str, str]]): Strings which should be - sent along with the request as metadata. + metadata (Sequence[Tuple[str, Union[str, bytes]]]): Key/value pairs which should be + sent along with the request as metadata. Normally, each value must be of type `str`, + but for metadata keys ending with the suffix `-bin`, the corresponding values must + be of type `bytes`. """ self._method = method self._request = accounts.ListChildAccountsRequest(request) diff --git a/packages/google-shopping-css/google/shopping/css_v1/services/accounts_service/transports/grpc.py b/packages/google-shopping-css/google/shopping/css_v1/services/accounts_service/transports/grpc.py index 88b7554c79fb..615955891e29 100644 --- a/packages/google-shopping-css/google/shopping/css_v1/services/accounts_service/transports/grpc.py +++ b/packages/google-shopping-css/google/shopping/css_v1/services/accounts_service/transports/grpc.py @@ -13,6 +13,9 @@ # See the License for the specific language governing permissions and # limitations under the License. # +import json +import logging as std_logging +import pickle from typing import Callable, Dict, Optional, Sequence, Tuple, Union import warnings @@ -20,12 +23,90 @@ import google.auth # type: ignore from google.auth import credentials as ga_credentials # type: ignore from google.auth.transport.grpc import SslCredentials # type: ignore +from google.protobuf.json_format import MessageToJson +import google.protobuf.message import grpc # type: ignore +import proto # type: ignore from google.shopping.css_v1.types import accounts from .base import DEFAULT_CLIENT_INFO, AccountsServiceTransport +try: + from google.api_core import client_logging # type: ignore + + CLIENT_LOGGING_SUPPORTED = True # pragma: NO COVER +except ImportError: # pragma: NO COVER + CLIENT_LOGGING_SUPPORTED = False + +_LOGGER = std_logging.getLogger(__name__) + + +class _LoggingClientInterceptor(grpc.UnaryUnaryClientInterceptor): # pragma: NO COVER + def intercept_unary_unary(self, continuation, client_call_details, request): + logging_enabled = CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( + std_logging.DEBUG + ) + if logging_enabled: # pragma: NO COVER + request_metadata = client_call_details.metadata + if isinstance(request, proto.Message): + request_payload = type(request).to_json(request) + elif isinstance(request, google.protobuf.message.Message): + request_payload = MessageToJson(request) + else: + request_payload = f"{type(request).__name__}: {pickle.dumps(request)}" + + request_metadata = { + key: value.decode("utf-8") if isinstance(value, bytes) else value + for key, value in request_metadata + } + grpc_request = { + "payload": request_payload, + "requestMethod": "grpc", + "metadata": dict(request_metadata), + } + _LOGGER.debug( + f"Sending request for {client_call_details.method}", + extra={ + "serviceName": "google.shopping.css.v1.AccountsService", + "rpcName": client_call_details.method, + "request": grpc_request, + "metadata": grpc_request["metadata"], + }, + ) + + response = continuation(client_call_details, request) + if logging_enabled: # pragma: NO COVER + response_metadata = response.trailing_metadata() + # Convert gRPC metadata `` to list of tuples + metadata = ( + dict([(k, str(v)) for k, v in response_metadata]) + if response_metadata + else None + ) + result = response.result() + if isinstance(result, proto.Message): + response_payload = type(result).to_json(result) + elif isinstance(result, google.protobuf.message.Message): + response_payload = MessageToJson(result) + else: + response_payload = f"{type(result).__name__}: {pickle.dumps(result)}" + grpc_response = { + "payload": response_payload, + "metadata": metadata, + "status": "OK", + } + _LOGGER.debug( + f"Received response for {client_call_details.method}.", + extra={ + "serviceName": "google.shopping.css.v1.AccountsService", + "rpcName": client_call_details.method, + "response": grpc_response, + "metadata": grpc_response["metadata"], + }, + ) + return response + class AccountsServiceGrpcTransport(AccountsServiceTransport): """gRPC backend transport for AccountsService. @@ -179,7 +260,12 @@ def __init__( ], ) - # Wrap messages. This must be done after self._grpc_channel exists + self._interceptor = _LoggingClientInterceptor() + self._logged_channel = grpc.intercept_channel( + self._grpc_channel, self._interceptor + ) + + # Wrap messages. This must be done after self._logged_channel exists self._prep_wrapped_messages(client_info) @classmethod @@ -257,7 +343,7 @@ def list_child_accounts( # gRPC handles serialization and deserialization, so we just need # to pass in the functions for each. if "list_child_accounts" not in self._stubs: - self._stubs["list_child_accounts"] = self.grpc_channel.unary_unary( + self._stubs["list_child_accounts"] = self._logged_channel.unary_unary( "/google.shopping.css.v1.AccountsService/ListChildAccounts", request_serializer=accounts.ListChildAccountsRequest.serialize, response_deserializer=accounts.ListChildAccountsResponse.deserialize, @@ -281,7 +367,7 @@ def get_account(self) -> Callable[[accounts.GetAccountRequest], accounts.Account # gRPC handles serialization and deserialization, so we just need # to pass in the functions for each. if "get_account" not in self._stubs: - self._stubs["get_account"] = self.grpc_channel.unary_unary( + self._stubs["get_account"] = self._logged_channel.unary_unary( "/google.shopping.css.v1.AccountsService/GetAccount", request_serializer=accounts.GetAccountRequest.serialize, response_deserializer=accounts.Account.deserialize, @@ -308,7 +394,7 @@ def update_labels( # gRPC handles serialization and deserialization, so we just need # to pass in the functions for each. if "update_labels" not in self._stubs: - self._stubs["update_labels"] = self.grpc_channel.unary_unary( + self._stubs["update_labels"] = self._logged_channel.unary_unary( "/google.shopping.css.v1.AccountsService/UpdateLabels", request_serializer=accounts.UpdateAccountLabelsRequest.serialize, response_deserializer=accounts.Account.deserialize, @@ -316,7 +402,7 @@ def update_labels( return self._stubs["update_labels"] def close(self): - self.grpc_channel.close() + self._logged_channel.close() @property def kind(self) -> str: diff --git a/packages/google-shopping-css/google/shopping/css_v1/services/accounts_service/transports/grpc_asyncio.py b/packages/google-shopping-css/google/shopping/css_v1/services/accounts_service/transports/grpc_asyncio.py index 6fd4ab3905f0..be073e49eda9 100644 --- a/packages/google-shopping-css/google/shopping/css_v1/services/accounts_service/transports/grpc_asyncio.py +++ b/packages/google-shopping-css/google/shopping/css_v1/services/accounts_service/transports/grpc_asyncio.py @@ -14,6 +14,9 @@ # limitations under the License. # import inspect +import json +import logging as std_logging +import pickle from typing import Awaitable, Callable, Dict, Optional, Sequence, Tuple, Union import warnings @@ -22,14 +25,93 @@ from google.api_core import retry_async as retries from google.auth import credentials as ga_credentials # type: ignore from google.auth.transport.grpc import SslCredentials # type: ignore +from google.protobuf.json_format import MessageToJson +import google.protobuf.message import grpc # type: ignore from grpc.experimental import aio # type: ignore +import proto # type: ignore from google.shopping.css_v1.types import accounts from .base import DEFAULT_CLIENT_INFO, AccountsServiceTransport from .grpc import AccountsServiceGrpcTransport +try: + from google.api_core import client_logging # type: ignore + + CLIENT_LOGGING_SUPPORTED = True # pragma: NO COVER +except ImportError: # pragma: NO COVER + CLIENT_LOGGING_SUPPORTED = False + +_LOGGER = std_logging.getLogger(__name__) + + +class _LoggingClientAIOInterceptor( + grpc.aio.UnaryUnaryClientInterceptor +): # pragma: NO COVER + async def intercept_unary_unary(self, continuation, client_call_details, request): + logging_enabled = CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( + std_logging.DEBUG + ) + if logging_enabled: # pragma: NO COVER + request_metadata = client_call_details.metadata + if isinstance(request, proto.Message): + request_payload = type(request).to_json(request) + elif isinstance(request, google.protobuf.message.Message): + request_payload = MessageToJson(request) + else: + request_payload = f"{type(request).__name__}: {pickle.dumps(request)}" + + request_metadata = { + key: value.decode("utf-8") if isinstance(value, bytes) else value + for key, value in request_metadata + } + grpc_request = { + "payload": request_payload, + "requestMethod": "grpc", + "metadata": dict(request_metadata), + } + _LOGGER.debug( + f"Sending request for {client_call_details.method}", + extra={ + "serviceName": "google.shopping.css.v1.AccountsService", + "rpcName": str(client_call_details.method), + "request": grpc_request, + "metadata": grpc_request["metadata"], + }, + ) + response = await continuation(client_call_details, request) + if logging_enabled: # pragma: NO COVER + response_metadata = await response.trailing_metadata() + # Convert gRPC metadata `` to list of tuples + metadata = ( + dict([(k, str(v)) for k, v in response_metadata]) + if response_metadata + else None + ) + result = await response + if isinstance(result, proto.Message): + response_payload = type(result).to_json(result) + elif isinstance(result, google.protobuf.message.Message): + response_payload = MessageToJson(result) + else: + response_payload = f"{type(result).__name__}: {pickle.dumps(result)}" + grpc_response = { + "payload": response_payload, + "metadata": metadata, + "status": "OK", + } + _LOGGER.debug( + f"Received response to rpc {client_call_details.method}.", + extra={ + "serviceName": "google.shopping.css.v1.AccountsService", + "rpcName": str(client_call_details.method), + "response": grpc_response, + "metadata": grpc_response["metadata"], + }, + ) + return response + class AccountsServiceGrpcAsyncIOTransport(AccountsServiceTransport): """gRPC AsyncIO backend transport for AccountsService. @@ -226,10 +308,13 @@ def __init__( ], ) - # Wrap messages. This must be done after self._grpc_channel exists + self._interceptor = _LoggingClientAIOInterceptor() + self._grpc_channel._unary_unary_interceptors.append(self._interceptor) + self._logged_channel = self._grpc_channel self._wrap_with_kind = ( "kind" in inspect.signature(gapic_v1.method_async.wrap_method).parameters ) + # Wrap messages. This must be done after self._logged_channel exists self._prep_wrapped_messages(client_info) @property @@ -266,7 +351,7 @@ def list_child_accounts( # gRPC handles serialization and deserialization, so we just need # to pass in the functions for each. if "list_child_accounts" not in self._stubs: - self._stubs["list_child_accounts"] = self.grpc_channel.unary_unary( + self._stubs["list_child_accounts"] = self._logged_channel.unary_unary( "/google.shopping.css.v1.AccountsService/ListChildAccounts", request_serializer=accounts.ListChildAccountsRequest.serialize, response_deserializer=accounts.ListChildAccountsResponse.deserialize, @@ -292,7 +377,7 @@ def get_account( # gRPC handles serialization and deserialization, so we just need # to pass in the functions for each. if "get_account" not in self._stubs: - self._stubs["get_account"] = self.grpc_channel.unary_unary( + self._stubs["get_account"] = self._logged_channel.unary_unary( "/google.shopping.css.v1.AccountsService/GetAccount", request_serializer=accounts.GetAccountRequest.serialize, response_deserializer=accounts.Account.deserialize, @@ -319,7 +404,7 @@ def update_labels( # gRPC handles serialization and deserialization, so we just need # to pass in the functions for each. if "update_labels" not in self._stubs: - self._stubs["update_labels"] = self.grpc_channel.unary_unary( + self._stubs["update_labels"] = self._logged_channel.unary_unary( "/google.shopping.css.v1.AccountsService/UpdateLabels", request_serializer=accounts.UpdateAccountLabelsRequest.serialize, response_deserializer=accounts.Account.deserialize, @@ -370,7 +455,7 @@ def _wrap_method(self, func, *args, **kwargs): return gapic_v1.method_async.wrap_method(func, *args, **kwargs) def close(self): - return self.grpc_channel.close() + return self._logged_channel.close() @property def kind(self) -> str: diff --git a/packages/google-shopping-css/google/shopping/css_v1/services/accounts_service/transports/rest.py b/packages/google-shopping-css/google/shopping/css_v1/services/accounts_service/transports/rest.py index de86742084d7..9a085333d5f3 100644 --- a/packages/google-shopping-css/google/shopping/css_v1/services/accounts_service/transports/rest.py +++ b/packages/google-shopping-css/google/shopping/css_v1/services/accounts_service/transports/rest.py @@ -13,9 +13,9 @@ # See the License for the specific language governing permissions and # limitations under the License. # - import dataclasses import json # type: ignore +import logging from typing import Any, Callable, Dict, List, Optional, Sequence, Tuple, Union import warnings @@ -37,6 +37,14 @@ except AttributeError: # pragma: NO COVER OptionalRetry = Union[retries.Retry, object, None] # type: ignore +try: + from google.api_core import client_logging # type: ignore + + CLIENT_LOGGING_SUPPORTED = True # pragma: NO COVER +except ImportError: # pragma: NO COVER + CLIENT_LOGGING_SUPPORTED = False + +_LOGGER = logging.getLogger(__name__) DEFAULT_CLIENT_INFO = gapic_v1.client_info.ClientInfo( gapic_version=BASE_DEFAULT_CLIENT_INFO.gapic_version, @@ -91,8 +99,10 @@ def post_update_labels(self, response): """ def pre_get_account( - self, request: accounts.GetAccountRequest, metadata: Sequence[Tuple[str, str]] - ) -> Tuple[accounts.GetAccountRequest, Sequence[Tuple[str, str]]]: + self, + request: accounts.GetAccountRequest, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[accounts.GetAccountRequest, Sequence[Tuple[str, Union[str, bytes]]]]: """Pre-rpc interceptor for get_account Override in a subclass to manipulate the request or metadata @@ -112,8 +122,10 @@ def post_get_account(self, response: accounts.Account) -> accounts.Account: def pre_list_child_accounts( self, request: accounts.ListChildAccountsRequest, - metadata: Sequence[Tuple[str, str]], - ) -> Tuple[accounts.ListChildAccountsRequest, Sequence[Tuple[str, str]]]: + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[ + accounts.ListChildAccountsRequest, Sequence[Tuple[str, Union[str, bytes]]] + ]: """Pre-rpc interceptor for list_child_accounts Override in a subclass to manipulate the request or metadata @@ -135,8 +147,10 @@ def post_list_child_accounts( def pre_update_labels( self, request: accounts.UpdateAccountLabelsRequest, - metadata: Sequence[Tuple[str, str]], - ) -> Tuple[accounts.UpdateAccountLabelsRequest, Sequence[Tuple[str, str]]]: + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[ + accounts.UpdateAccountLabelsRequest, Sequence[Tuple[str, Union[str, bytes]]] + ]: """Pre-rpc interceptor for update_labels Override in a subclass to manipulate the request or metadata @@ -274,7 +288,7 @@ def __call__( *, retry: OptionalRetry = gapic_v1.method.DEFAULT, timeout: Optional[float] = None, - metadata: Sequence[Tuple[str, str]] = (), + metadata: Sequence[Tuple[str, Union[str, bytes]]] = (), ) -> accounts.Account: r"""Call the get account method over HTTP. @@ -284,8 +298,10 @@ def __call__( retry (google.api_core.retry.Retry): Designation of what errors, if any, should be retried. timeout (float): The timeout for this request. - metadata (Sequence[Tuple[str, str]]): Strings which should be - sent along with the request as metadata. + metadata (Sequence[Tuple[str, Union[str, bytes]]]): Key/value pairs which should be + sent along with the request as metadata. Normally, each value must be of type `str`, + but for metadata keys ending with the suffix `-bin`, the corresponding values must + be of type `bytes`. Returns: ~.accounts.Account: @@ -295,6 +311,7 @@ def __call__( http_options = ( _BaseAccountsServiceRestTransport._BaseGetAccount._get_http_options() ) + request, metadata = self._interceptor.pre_get_account(request, metadata) transcoded_request = _BaseAccountsServiceRestTransport._BaseGetAccount._get_transcoded_request( http_options, request @@ -305,6 +322,33 @@ def __call__( transcoded_request ) + if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( + logging.DEBUG + ): # pragma: NO COVER + request_url = "{host}{uri}".format( + host=self._host, uri=transcoded_request["uri"] + ) + method = transcoded_request["method"] + try: + request_payload = type(request).to_json(request) + except: + request_payload = None + http_request = { + "payload": request_payload, + "requestMethod": method, + "requestUrl": request_url, + "headers": dict(metadata), + } + _LOGGER.debug( + f"Sending request for google.shopping.css_v1.AccountsServiceClient.GetAccount", + extra={ + "serviceName": "google.shopping.css.v1.AccountsService", + "rpcName": "GetAccount", + "httpRequest": http_request, + "metadata": http_request["headers"], + }, + ) + # Send the request response = AccountsServiceRestTransport._GetAccount._get_response( self._host, @@ -325,7 +369,29 @@ def __call__( pb_resp = accounts.Account.pb(resp) json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) + resp = self._interceptor.post_get_account(resp) + if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( + logging.DEBUG + ): # pragma: NO COVER + try: + response_payload = accounts.Account.to_json(response) + except: + response_payload = None + http_response = { + "payload": response_payload, + "headers": dict(response.headers), + "status": response.status_code, + } + _LOGGER.debug( + "Received response for google.shopping.css_v1.AccountsServiceClient.get_account", + extra={ + "serviceName": "google.shopping.css.v1.AccountsService", + "rpcName": "GetAccount", + "metadata": http_response["headers"], + "httpResponse": http_response, + }, + ) return resp class _ListChildAccounts( @@ -363,7 +429,7 @@ def __call__( *, retry: OptionalRetry = gapic_v1.method.DEFAULT, timeout: Optional[float] = None, - metadata: Sequence[Tuple[str, str]] = (), + metadata: Sequence[Tuple[str, Union[str, bytes]]] = (), ) -> accounts.ListChildAccountsResponse: r"""Call the list child accounts method over HTTP. @@ -374,8 +440,10 @@ def __call__( retry (google.api_core.retry.Retry): Designation of what errors, if any, should be retried. timeout (float): The timeout for this request. - metadata (Sequence[Tuple[str, str]]): Strings which should be - sent along with the request as metadata. + metadata (Sequence[Tuple[str, Union[str, bytes]]]): Key/value pairs which should be + sent along with the request as metadata. Normally, each value must be of type `str`, + but for metadata keys ending with the suffix `-bin`, the corresponding values must + be of type `bytes`. Returns: ~.accounts.ListChildAccountsResponse: @@ -385,6 +453,7 @@ def __call__( http_options = ( _BaseAccountsServiceRestTransport._BaseListChildAccounts._get_http_options() ) + request, metadata = self._interceptor.pre_list_child_accounts( request, metadata ) @@ -397,6 +466,33 @@ def __call__( transcoded_request ) + if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( + logging.DEBUG + ): # pragma: NO COVER + request_url = "{host}{uri}".format( + host=self._host, uri=transcoded_request["uri"] + ) + method = transcoded_request["method"] + try: + request_payload = type(request).to_json(request) + except: + request_payload = None + http_request = { + "payload": request_payload, + "requestMethod": method, + "requestUrl": request_url, + "headers": dict(metadata), + } + _LOGGER.debug( + f"Sending request for google.shopping.css_v1.AccountsServiceClient.ListChildAccounts", + extra={ + "serviceName": "google.shopping.css.v1.AccountsService", + "rpcName": "ListChildAccounts", + "httpRequest": http_request, + "metadata": http_request["headers"], + }, + ) + # Send the request response = AccountsServiceRestTransport._ListChildAccounts._get_response( self._host, @@ -417,7 +513,31 @@ def __call__( pb_resp = accounts.ListChildAccountsResponse.pb(resp) json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) + resp = self._interceptor.post_list_child_accounts(resp) + if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( + logging.DEBUG + ): # pragma: NO COVER + try: + response_payload = accounts.ListChildAccountsResponse.to_json( + response + ) + except: + response_payload = None + http_response = { + "payload": response_payload, + "headers": dict(response.headers), + "status": response.status_code, + } + _LOGGER.debug( + "Received response for google.shopping.css_v1.AccountsServiceClient.list_child_accounts", + extra={ + "serviceName": "google.shopping.css.v1.AccountsService", + "rpcName": "ListChildAccounts", + "metadata": http_response["headers"], + "httpResponse": http_response, + }, + ) return resp class _UpdateLabels( @@ -455,7 +575,7 @@ def __call__( *, retry: OptionalRetry = gapic_v1.method.DEFAULT, timeout: Optional[float] = None, - metadata: Sequence[Tuple[str, str]] = (), + metadata: Sequence[Tuple[str, Union[str, bytes]]] = (), ) -> accounts.Account: r"""Call the update labels method over HTTP. @@ -465,8 +585,10 @@ def __call__( retry (google.api_core.retry.Retry): Designation of what errors, if any, should be retried. timeout (float): The timeout for this request. - metadata (Sequence[Tuple[str, str]]): Strings which should be - sent along with the request as metadata. + metadata (Sequence[Tuple[str, Union[str, bytes]]]): Key/value pairs which should be + sent along with the request as metadata. Normally, each value must be of type `str`, + but for metadata keys ending with the suffix `-bin`, the corresponding values must + be of type `bytes`. Returns: ~.accounts.Account: @@ -476,6 +598,7 @@ def __call__( http_options = ( _BaseAccountsServiceRestTransport._BaseUpdateLabels._get_http_options() ) + request, metadata = self._interceptor.pre_update_labels(request, metadata) transcoded_request = _BaseAccountsServiceRestTransport._BaseUpdateLabels._get_transcoded_request( http_options, request @@ -490,6 +613,33 @@ def __call__( transcoded_request ) + if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( + logging.DEBUG + ): # pragma: NO COVER + request_url = "{host}{uri}".format( + host=self._host, uri=transcoded_request["uri"] + ) + method = transcoded_request["method"] + try: + request_payload = type(request).to_json(request) + except: + request_payload = None + http_request = { + "payload": request_payload, + "requestMethod": method, + "requestUrl": request_url, + "headers": dict(metadata), + } + _LOGGER.debug( + f"Sending request for google.shopping.css_v1.AccountsServiceClient.UpdateLabels", + extra={ + "serviceName": "google.shopping.css.v1.AccountsService", + "rpcName": "UpdateLabels", + "httpRequest": http_request, + "metadata": http_request["headers"], + }, + ) + # Send the request response = AccountsServiceRestTransport._UpdateLabels._get_response( self._host, @@ -511,7 +661,29 @@ def __call__( pb_resp = accounts.Account.pb(resp) json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) + resp = self._interceptor.post_update_labels(resp) + if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( + logging.DEBUG + ): # pragma: NO COVER + try: + response_payload = accounts.Account.to_json(response) + except: + response_payload = None + http_response = { + "payload": response_payload, + "headers": dict(response.headers), + "status": response.status_code, + } + _LOGGER.debug( + "Received response for google.shopping.css_v1.AccountsServiceClient.update_labels", + extra={ + "serviceName": "google.shopping.css.v1.AccountsService", + "rpcName": "UpdateLabels", + "metadata": http_response["headers"], + "httpResponse": http_response, + }, + ) return resp @property diff --git a/packages/google-shopping-css/google/shopping/css_v1/services/css_product_inputs_service/async_client.py b/packages/google-shopping-css/google/shopping/css_v1/services/css_product_inputs_service/async_client.py index 8c7085c07388..3f7255ea1ec4 100644 --- a/packages/google-shopping-css/google/shopping/css_v1/services/css_product_inputs_service/async_client.py +++ b/packages/google-shopping-css/google/shopping/css_v1/services/css_product_inputs_service/async_client.py @@ -14,6 +14,7 @@ # limitations under the License. # from collections import OrderedDict +import logging as std_logging import re from typing import ( Callable, @@ -51,6 +52,15 @@ from .transports.base import DEFAULT_CLIENT_INFO, CssProductInputsServiceTransport from .transports.grpc_asyncio import CssProductInputsServiceGrpcAsyncIOTransport +try: + from google.api_core import client_logging # type: ignore + + CLIENT_LOGGING_SUPPORTED = True # pragma: NO COVER +except ImportError: # pragma: NO COVER + CLIENT_LOGGING_SUPPORTED = False + +_LOGGER = std_logging.getLogger(__name__) + class CssProductInputsServiceAsyncClient: """Service to use CssProductInput resource. @@ -272,6 +282,28 @@ def __init__( client_info=client_info, ) + if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( + std_logging.DEBUG + ): # pragma: NO COVER + _LOGGER.debug( + "Created client `google.shopping.css_v1.CssProductInputsServiceAsyncClient`.", + extra={ + "serviceName": "google.shopping.css.v1.CssProductInputsService", + "universeDomain": getattr( + self._client._transport._credentials, "universe_domain", "" + ), + "credentialsType": f"{type(self._client._transport._credentials).__module__}.{type(self._client._transport._credentials).__qualname__}", + "credentialsInfo": getattr( + self.transport._credentials, "get_cred_info", lambda: None + )(), + } + if hasattr(self._client._transport, "_credentials") + else { + "serviceName": "google.shopping.css.v1.CssProductInputsService", + "credentialsType": None, + }, + ) + async def insert_css_product_input( self, request: Optional[ @@ -280,7 +312,7 @@ async def insert_css_product_input( *, retry: OptionalRetry = gapic_v1.method.DEFAULT, timeout: Union[float, object] = gapic_v1.method.DEFAULT, - metadata: Sequence[Tuple[str, str]] = (), + metadata: Sequence[Tuple[str, Union[str, bytes]]] = (), ) -> css_product_inputs.CssProductInput: r"""Uploads a CssProductInput to your CSS Center account. If an input with the same contentLanguage, identity, @@ -331,8 +363,10 @@ async def sample_insert_css_product_input(): retry (google.api_core.retry_async.AsyncRetry): Designation of what errors, if any, should be retried. timeout (float): The timeout for this request. - metadata (Sequence[Tuple[str, str]]): Strings which should be - sent along with the request as metadata. + metadata (Sequence[Tuple[str, Union[str, bytes]]]): Key/value pairs which should be + sent along with the request as metadata. Normally, each value must be of type `str`, + but for metadata keys ending with the suffix `-bin`, the corresponding values must + be of type `bytes`. Returns: google.shopping.css_v1.types.CssProductInput: @@ -384,7 +418,7 @@ async def delete_css_product_input( name: Optional[str] = None, retry: OptionalRetry = gapic_v1.method.DEFAULT, timeout: Union[float, object] = gapic_v1.method.DEFAULT, - metadata: Sequence[Tuple[str, str]] = (), + metadata: Sequence[Tuple[str, Union[str, bytes]]] = (), ) -> None: r"""Deletes a CSS Product input from your CSS Center account. @@ -429,8 +463,10 @@ async def sample_delete_css_product_input(): retry (google.api_core.retry_async.AsyncRetry): Designation of what errors, if any, should be retried. timeout (float): The timeout for this request. - metadata (Sequence[Tuple[str, str]]): Strings which should be - sent along with the request as metadata. + metadata (Sequence[Tuple[str, Union[str, bytes]]]): Key/value pairs which should be + sent along with the request as metadata. Normally, each value must be of type `str`, + but for metadata keys ending with the suffix `-bin`, the corresponding values must + be of type `bytes`. """ # Create or coerce a protobuf request object. # - Quick check: If we got a request object, we should *not* have diff --git a/packages/google-shopping-css/google/shopping/css_v1/services/css_product_inputs_service/client.py b/packages/google-shopping-css/google/shopping/css_v1/services/css_product_inputs_service/client.py index 2a003b922e3c..970c28576f03 100644 --- a/packages/google-shopping-css/google/shopping/css_v1/services/css_product_inputs_service/client.py +++ b/packages/google-shopping-css/google/shopping/css_v1/services/css_product_inputs_service/client.py @@ -14,6 +14,7 @@ # limitations under the License. # from collections import OrderedDict +import logging as std_logging import os import re from typing import ( @@ -48,6 +49,15 @@ except AttributeError: # pragma: NO COVER OptionalRetry = Union[retries.Retry, object, None] # type: ignore +try: + from google.api_core import client_logging # type: ignore + + CLIENT_LOGGING_SUPPORTED = True # pragma: NO COVER +except ImportError: # pragma: NO COVER + CLIENT_LOGGING_SUPPORTED = False + +_LOGGER = std_logging.getLogger(__name__) + from google.protobuf import timestamp_pb2 # type: ignore from google.shopping.type.types import types @@ -588,6 +598,10 @@ def __init__( # Initialize the universe domain validation. self._is_universe_domain_valid = False + if CLIENT_LOGGING_SUPPORTED: # pragma: NO COVER + # Setup logging. + client_logging.initialize_logging() + api_key_value = getattr(self._client_options, "api_key", None) if api_key_value and credentials: raise ValueError( @@ -654,6 +668,29 @@ def __init__( api_audience=self._client_options.api_audience, ) + if "async" not in str(self._transport): + if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( + std_logging.DEBUG + ): # pragma: NO COVER + _LOGGER.debug( + "Created client `google.shopping.css_v1.CssProductInputsServiceClient`.", + extra={ + "serviceName": "google.shopping.css.v1.CssProductInputsService", + "universeDomain": getattr( + self._transport._credentials, "universe_domain", "" + ), + "credentialsType": f"{type(self._transport._credentials).__module__}.{type(self._transport._credentials).__qualname__}", + "credentialsInfo": getattr( + self.transport._credentials, "get_cred_info", lambda: None + )(), + } + if hasattr(self._transport, "_credentials") + else { + "serviceName": "google.shopping.css.v1.CssProductInputsService", + "credentialsType": None, + }, + ) + def insert_css_product_input( self, request: Optional[ @@ -662,7 +699,7 @@ def insert_css_product_input( *, retry: OptionalRetry = gapic_v1.method.DEFAULT, timeout: Union[float, object] = gapic_v1.method.DEFAULT, - metadata: Sequence[Tuple[str, str]] = (), + metadata: Sequence[Tuple[str, Union[str, bytes]]] = (), ) -> css_product_inputs.CssProductInput: r"""Uploads a CssProductInput to your CSS Center account. If an input with the same contentLanguage, identity, @@ -713,8 +750,10 @@ def sample_insert_css_product_input(): retry (google.api_core.retry.Retry): Designation of what errors, if any, should be retried. timeout (float): The timeout for this request. - metadata (Sequence[Tuple[str, str]]): Strings which should be - sent along with the request as metadata. + metadata (Sequence[Tuple[str, Union[str, bytes]]]): Key/value pairs which should be + sent along with the request as metadata. Normally, each value must be of type `str`, + but for metadata keys ending with the suffix `-bin`, the corresponding values must + be of type `bytes`. Returns: google.shopping.css_v1.types.CssProductInput: @@ -764,7 +803,7 @@ def delete_css_product_input( name: Optional[str] = None, retry: OptionalRetry = gapic_v1.method.DEFAULT, timeout: Union[float, object] = gapic_v1.method.DEFAULT, - metadata: Sequence[Tuple[str, str]] = (), + metadata: Sequence[Tuple[str, Union[str, bytes]]] = (), ) -> None: r"""Deletes a CSS Product input from your CSS Center account. @@ -809,8 +848,10 @@ def sample_delete_css_product_input(): retry (google.api_core.retry.Retry): Designation of what errors, if any, should be retried. timeout (float): The timeout for this request. - metadata (Sequence[Tuple[str, str]]): Strings which should be - sent along with the request as metadata. + metadata (Sequence[Tuple[str, Union[str, bytes]]]): Key/value pairs which should be + sent along with the request as metadata. Normally, each value must be of type `str`, + but for metadata keys ending with the suffix `-bin`, the corresponding values must + be of type `bytes`. """ # Create or coerce a protobuf request object. # - Quick check: If we got a request object, we should *not* have diff --git a/packages/google-shopping-css/google/shopping/css_v1/services/css_product_inputs_service/transports/grpc.py b/packages/google-shopping-css/google/shopping/css_v1/services/css_product_inputs_service/transports/grpc.py index 94f333d4b6b2..c868e4321233 100644 --- a/packages/google-shopping-css/google/shopping/css_v1/services/css_product_inputs_service/transports/grpc.py +++ b/packages/google-shopping-css/google/shopping/css_v1/services/css_product_inputs_service/transports/grpc.py @@ -13,6 +13,9 @@ # See the License for the specific language governing permissions and # limitations under the License. # +import json +import logging as std_logging +import pickle from typing import Callable, Dict, Optional, Sequence, Tuple, Union import warnings @@ -21,12 +24,90 @@ from google.auth import credentials as ga_credentials # type: ignore from google.auth.transport.grpc import SslCredentials # type: ignore from google.protobuf import empty_pb2 # type: ignore +from google.protobuf.json_format import MessageToJson +import google.protobuf.message import grpc # type: ignore +import proto # type: ignore from google.shopping.css_v1.types import css_product_inputs from .base import DEFAULT_CLIENT_INFO, CssProductInputsServiceTransport +try: + from google.api_core import client_logging # type: ignore + + CLIENT_LOGGING_SUPPORTED = True # pragma: NO COVER +except ImportError: # pragma: NO COVER + CLIENT_LOGGING_SUPPORTED = False + +_LOGGER = std_logging.getLogger(__name__) + + +class _LoggingClientInterceptor(grpc.UnaryUnaryClientInterceptor): # pragma: NO COVER + def intercept_unary_unary(self, continuation, client_call_details, request): + logging_enabled = CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( + std_logging.DEBUG + ) + if logging_enabled: # pragma: NO COVER + request_metadata = client_call_details.metadata + if isinstance(request, proto.Message): + request_payload = type(request).to_json(request) + elif isinstance(request, google.protobuf.message.Message): + request_payload = MessageToJson(request) + else: + request_payload = f"{type(request).__name__}: {pickle.dumps(request)}" + + request_metadata = { + key: value.decode("utf-8") if isinstance(value, bytes) else value + for key, value in request_metadata + } + grpc_request = { + "payload": request_payload, + "requestMethod": "grpc", + "metadata": dict(request_metadata), + } + _LOGGER.debug( + f"Sending request for {client_call_details.method}", + extra={ + "serviceName": "google.shopping.css.v1.CssProductInputsService", + "rpcName": client_call_details.method, + "request": grpc_request, + "metadata": grpc_request["metadata"], + }, + ) + + response = continuation(client_call_details, request) + if logging_enabled: # pragma: NO COVER + response_metadata = response.trailing_metadata() + # Convert gRPC metadata `` to list of tuples + metadata = ( + dict([(k, str(v)) for k, v in response_metadata]) + if response_metadata + else None + ) + result = response.result() + if isinstance(result, proto.Message): + response_payload = type(result).to_json(result) + elif isinstance(result, google.protobuf.message.Message): + response_payload = MessageToJson(result) + else: + response_payload = f"{type(result).__name__}: {pickle.dumps(result)}" + grpc_response = { + "payload": response_payload, + "metadata": metadata, + "status": "OK", + } + _LOGGER.debug( + f"Received response for {client_call_details.method}.", + extra={ + "serviceName": "google.shopping.css.v1.CssProductInputsService", + "rpcName": client_call_details.method, + "response": grpc_response, + "metadata": grpc_response["metadata"], + }, + ) + return response + class CssProductInputsServiceGrpcTransport(CssProductInputsServiceTransport): """gRPC backend transport for CssProductInputsService. @@ -181,7 +262,12 @@ def __init__( ], ) - # Wrap messages. This must be done after self._grpc_channel exists + self._interceptor = _LoggingClientInterceptor() + self._logged_channel = grpc.intercept_channel( + self._grpc_channel, self._interceptor + ) + + # Wrap messages. This must be done after self._logged_channel exists self._prep_wrapped_messages(client_info) @classmethod @@ -265,7 +351,7 @@ def insert_css_product_input( # gRPC handles serialization and deserialization, so we just need # to pass in the functions for each. if "insert_css_product_input" not in self._stubs: - self._stubs["insert_css_product_input"] = self.grpc_channel.unary_unary( + self._stubs["insert_css_product_input"] = self._logged_channel.unary_unary( "/google.shopping.css.v1.CssProductInputsService/InsertCssProductInput", request_serializer=css_product_inputs.InsertCssProductInputRequest.serialize, response_deserializer=css_product_inputs.CssProductInput.deserialize, @@ -294,7 +380,7 @@ def delete_css_product_input( # gRPC handles serialization and deserialization, so we just need # to pass in the functions for each. if "delete_css_product_input" not in self._stubs: - self._stubs["delete_css_product_input"] = self.grpc_channel.unary_unary( + self._stubs["delete_css_product_input"] = self._logged_channel.unary_unary( "/google.shopping.css.v1.CssProductInputsService/DeleteCssProductInput", request_serializer=css_product_inputs.DeleteCssProductInputRequest.serialize, response_deserializer=empty_pb2.Empty.FromString, @@ -302,7 +388,7 @@ def delete_css_product_input( return self._stubs["delete_css_product_input"] def close(self): - self.grpc_channel.close() + self._logged_channel.close() @property def kind(self) -> str: diff --git a/packages/google-shopping-css/google/shopping/css_v1/services/css_product_inputs_service/transports/grpc_asyncio.py b/packages/google-shopping-css/google/shopping/css_v1/services/css_product_inputs_service/transports/grpc_asyncio.py index bc09141cc86e..517bc45020da 100644 --- a/packages/google-shopping-css/google/shopping/css_v1/services/css_product_inputs_service/transports/grpc_asyncio.py +++ b/packages/google-shopping-css/google/shopping/css_v1/services/css_product_inputs_service/transports/grpc_asyncio.py @@ -14,6 +14,9 @@ # limitations under the License. # import inspect +import json +import logging as std_logging +import pickle from typing import Awaitable, Callable, Dict, Optional, Sequence, Tuple, Union import warnings @@ -23,14 +26,93 @@ from google.auth import credentials as ga_credentials # type: ignore from google.auth.transport.grpc import SslCredentials # type: ignore from google.protobuf import empty_pb2 # type: ignore +from google.protobuf.json_format import MessageToJson +import google.protobuf.message import grpc # type: ignore from grpc.experimental import aio # type: ignore +import proto # type: ignore from google.shopping.css_v1.types import css_product_inputs from .base import DEFAULT_CLIENT_INFO, CssProductInputsServiceTransport from .grpc import CssProductInputsServiceGrpcTransport +try: + from google.api_core import client_logging # type: ignore + + CLIENT_LOGGING_SUPPORTED = True # pragma: NO COVER +except ImportError: # pragma: NO COVER + CLIENT_LOGGING_SUPPORTED = False + +_LOGGER = std_logging.getLogger(__name__) + + +class _LoggingClientAIOInterceptor( + grpc.aio.UnaryUnaryClientInterceptor +): # pragma: NO COVER + async def intercept_unary_unary(self, continuation, client_call_details, request): + logging_enabled = CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( + std_logging.DEBUG + ) + if logging_enabled: # pragma: NO COVER + request_metadata = client_call_details.metadata + if isinstance(request, proto.Message): + request_payload = type(request).to_json(request) + elif isinstance(request, google.protobuf.message.Message): + request_payload = MessageToJson(request) + else: + request_payload = f"{type(request).__name__}: {pickle.dumps(request)}" + + request_metadata = { + key: value.decode("utf-8") if isinstance(value, bytes) else value + for key, value in request_metadata + } + grpc_request = { + "payload": request_payload, + "requestMethod": "grpc", + "metadata": dict(request_metadata), + } + _LOGGER.debug( + f"Sending request for {client_call_details.method}", + extra={ + "serviceName": "google.shopping.css.v1.CssProductInputsService", + "rpcName": str(client_call_details.method), + "request": grpc_request, + "metadata": grpc_request["metadata"], + }, + ) + response = await continuation(client_call_details, request) + if logging_enabled: # pragma: NO COVER + response_metadata = await response.trailing_metadata() + # Convert gRPC metadata `` to list of tuples + metadata = ( + dict([(k, str(v)) for k, v in response_metadata]) + if response_metadata + else None + ) + result = await response + if isinstance(result, proto.Message): + response_payload = type(result).to_json(result) + elif isinstance(result, google.protobuf.message.Message): + response_payload = MessageToJson(result) + else: + response_payload = f"{type(result).__name__}: {pickle.dumps(result)}" + grpc_response = { + "payload": response_payload, + "metadata": metadata, + "status": "OK", + } + _LOGGER.debug( + f"Received response to rpc {client_call_details.method}.", + extra={ + "serviceName": "google.shopping.css.v1.CssProductInputsService", + "rpcName": str(client_call_details.method), + "response": grpc_response, + "metadata": grpc_response["metadata"], + }, + ) + return response + class CssProductInputsServiceGrpcAsyncIOTransport(CssProductInputsServiceTransport): """gRPC AsyncIO backend transport for CssProductInputsService. @@ -228,10 +310,13 @@ def __init__( ], ) - # Wrap messages. This must be done after self._grpc_channel exists + self._interceptor = _LoggingClientAIOInterceptor() + self._grpc_channel._unary_unary_interceptors.append(self._interceptor) + self._logged_channel = self._grpc_channel self._wrap_with_kind = ( "kind" in inspect.signature(gapic_v1.method_async.wrap_method).parameters ) + # Wrap messages. This must be done after self._logged_channel exists self._prep_wrapped_messages(client_info) @property @@ -273,7 +358,7 @@ def insert_css_product_input( # gRPC handles serialization and deserialization, so we just need # to pass in the functions for each. if "insert_css_product_input" not in self._stubs: - self._stubs["insert_css_product_input"] = self.grpc_channel.unary_unary( + self._stubs["insert_css_product_input"] = self._logged_channel.unary_unary( "/google.shopping.css.v1.CssProductInputsService/InsertCssProductInput", request_serializer=css_product_inputs.InsertCssProductInputRequest.serialize, response_deserializer=css_product_inputs.CssProductInput.deserialize, @@ -304,7 +389,7 @@ def delete_css_product_input( # gRPC handles serialization and deserialization, so we just need # to pass in the functions for each. if "delete_css_product_input" not in self._stubs: - self._stubs["delete_css_product_input"] = self.grpc_channel.unary_unary( + self._stubs["delete_css_product_input"] = self._logged_channel.unary_unary( "/google.shopping.css.v1.CssProductInputsService/DeleteCssProductInput", request_serializer=css_product_inputs.DeleteCssProductInputRequest.serialize, response_deserializer=empty_pb2.Empty.FromString, @@ -332,7 +417,7 @@ def _wrap_method(self, func, *args, **kwargs): return gapic_v1.method_async.wrap_method(func, *args, **kwargs) def close(self): - return self.grpc_channel.close() + return self._logged_channel.close() @property def kind(self) -> str: diff --git a/packages/google-shopping-css/google/shopping/css_v1/services/css_product_inputs_service/transports/rest.py b/packages/google-shopping-css/google/shopping/css_v1/services/css_product_inputs_service/transports/rest.py index 4c153a42493b..bd27ed1300a7 100644 --- a/packages/google-shopping-css/google/shopping/css_v1/services/css_product_inputs_service/transports/rest.py +++ b/packages/google-shopping-css/google/shopping/css_v1/services/css_product_inputs_service/transports/rest.py @@ -13,9 +13,9 @@ # See the License for the specific language governing permissions and # limitations under the License. # - import dataclasses import json # type: ignore +import logging from typing import Any, Callable, Dict, List, Optional, Sequence, Tuple, Union import warnings @@ -38,6 +38,14 @@ except AttributeError: # pragma: NO COVER OptionalRetry = Union[retries.Retry, object, None] # type: ignore +try: + from google.api_core import client_logging # type: ignore + + CLIENT_LOGGING_SUPPORTED = True # pragma: NO COVER +except ImportError: # pragma: NO COVER + CLIENT_LOGGING_SUPPORTED = False + +_LOGGER = logging.getLogger(__name__) DEFAULT_CLIENT_INFO = gapic_v1.client_info.ClientInfo( gapic_version=BASE_DEFAULT_CLIENT_INFO.gapic_version, @@ -82,9 +90,10 @@ def post_insert_css_product_input(self, response): def pre_delete_css_product_input( self, request: css_product_inputs.DeleteCssProductInputRequest, - metadata: Sequence[Tuple[str, str]], + metadata: Sequence[Tuple[str, Union[str, bytes]]], ) -> Tuple[ - css_product_inputs.DeleteCssProductInputRequest, Sequence[Tuple[str, str]] + css_product_inputs.DeleteCssProductInputRequest, + Sequence[Tuple[str, Union[str, bytes]]], ]: """Pre-rpc interceptor for delete_css_product_input @@ -96,9 +105,10 @@ def pre_delete_css_product_input( def pre_insert_css_product_input( self, request: css_product_inputs.InsertCssProductInputRequest, - metadata: Sequence[Tuple[str, str]], + metadata: Sequence[Tuple[str, Union[str, bytes]]], ) -> Tuple[ - css_product_inputs.InsertCssProductInputRequest, Sequence[Tuple[str, str]] + css_product_inputs.InsertCssProductInputRequest, + Sequence[Tuple[str, Union[str, bytes]]], ]: """Pre-rpc interceptor for insert_css_product_input @@ -241,7 +251,7 @@ def __call__( *, retry: OptionalRetry = gapic_v1.method.DEFAULT, timeout: Optional[float] = None, - metadata: Sequence[Tuple[str, str]] = (), + metadata: Sequence[Tuple[str, Union[str, bytes]]] = (), ): r"""Call the delete css product input method over HTTP. @@ -252,13 +262,16 @@ def __call__( retry (google.api_core.retry.Retry): Designation of what errors, if any, should be retried. timeout (float): The timeout for this request. - metadata (Sequence[Tuple[str, str]]): Strings which should be - sent along with the request as metadata. + metadata (Sequence[Tuple[str, Union[str, bytes]]]): Key/value pairs which should be + sent along with the request as metadata. Normally, each value must be of type `str`, + but for metadata keys ending with the suffix `-bin`, the corresponding values must + be of type `bytes`. """ http_options = ( _BaseCssProductInputsServiceRestTransport._BaseDeleteCssProductInput._get_http_options() ) + request, metadata = self._interceptor.pre_delete_css_product_input( request, metadata ) @@ -271,6 +284,33 @@ def __call__( transcoded_request ) + if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( + logging.DEBUG + ): # pragma: NO COVER + request_url = "{host}{uri}".format( + host=self._host, uri=transcoded_request["uri"] + ) + method = transcoded_request["method"] + try: + request_payload = json_format.MessageToJson(request) + except: + request_payload = None + http_request = { + "payload": request_payload, + "requestMethod": method, + "requestUrl": request_url, + "headers": dict(metadata), + } + _LOGGER.debug( + f"Sending request for google.shopping.css_v1.CssProductInputsServiceClient.DeleteCssProductInput", + extra={ + "serviceName": "google.shopping.css.v1.CssProductInputsService", + "rpcName": "DeleteCssProductInput", + "httpRequest": http_request, + "metadata": http_request["headers"], + }, + ) + # Send the request response = CssProductInputsServiceRestTransport._DeleteCssProductInput._get_response( self._host, @@ -322,7 +362,7 @@ def __call__( *, retry: OptionalRetry = gapic_v1.method.DEFAULT, timeout: Optional[float] = None, - metadata: Sequence[Tuple[str, str]] = (), + metadata: Sequence[Tuple[str, Union[str, bytes]]] = (), ) -> css_product_inputs.CssProductInput: r"""Call the insert css product input method over HTTP. @@ -333,8 +373,10 @@ def __call__( retry (google.api_core.retry.Retry): Designation of what errors, if any, should be retried. timeout (float): The timeout for this request. - metadata (Sequence[Tuple[str, str]]): Strings which should be - sent along with the request as metadata. + metadata (Sequence[Tuple[str, Union[str, bytes]]]): Key/value pairs which should be + sent along with the request as metadata. Normally, each value must be of type `str`, + but for metadata keys ending with the suffix `-bin`, the corresponding values must + be of type `bytes`. Returns: ~.css_product_inputs.CssProductInput: @@ -349,6 +391,7 @@ def __call__( http_options = ( _BaseCssProductInputsServiceRestTransport._BaseInsertCssProductInput._get_http_options() ) + request, metadata = self._interceptor.pre_insert_css_product_input( request, metadata ) @@ -365,6 +408,33 @@ def __call__( transcoded_request ) + if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( + logging.DEBUG + ): # pragma: NO COVER + request_url = "{host}{uri}".format( + host=self._host, uri=transcoded_request["uri"] + ) + method = transcoded_request["method"] + try: + request_payload = type(request).to_json(request) + except: + request_payload = None + http_request = { + "payload": request_payload, + "requestMethod": method, + "requestUrl": request_url, + "headers": dict(metadata), + } + _LOGGER.debug( + f"Sending request for google.shopping.css_v1.CssProductInputsServiceClient.InsertCssProductInput", + extra={ + "serviceName": "google.shopping.css.v1.CssProductInputsService", + "rpcName": "InsertCssProductInput", + "httpRequest": http_request, + "metadata": http_request["headers"], + }, + ) + # Send the request response = CssProductInputsServiceRestTransport._InsertCssProductInput._get_response( self._host, @@ -386,7 +456,31 @@ def __call__( pb_resp = css_product_inputs.CssProductInput.pb(resp) json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) + resp = self._interceptor.post_insert_css_product_input(resp) + if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( + logging.DEBUG + ): # pragma: NO COVER + try: + response_payload = css_product_inputs.CssProductInput.to_json( + response + ) + except: + response_payload = None + http_response = { + "payload": response_payload, + "headers": dict(response.headers), + "status": response.status_code, + } + _LOGGER.debug( + "Received response for google.shopping.css_v1.CssProductInputsServiceClient.insert_css_product_input", + extra={ + "serviceName": "google.shopping.css.v1.CssProductInputsService", + "rpcName": "InsertCssProductInput", + "metadata": http_response["headers"], + "httpResponse": http_response, + }, + ) return resp @property diff --git a/packages/google-shopping-css/google/shopping/css_v1/services/css_products_service/async_client.py b/packages/google-shopping-css/google/shopping/css_v1/services/css_products_service/async_client.py index 59fa5016dcc9..1bd43a0ba0bf 100644 --- a/packages/google-shopping-css/google/shopping/css_v1/services/css_products_service/async_client.py +++ b/packages/google-shopping-css/google/shopping/css_v1/services/css_products_service/async_client.py @@ -14,6 +14,7 @@ # limitations under the License. # from collections import OrderedDict +import logging as std_logging import re from typing import ( Callable, @@ -51,6 +52,15 @@ from .transports.base import DEFAULT_CLIENT_INFO, CssProductsServiceTransport from .transports.grpc_asyncio import CssProductsServiceGrpcAsyncIOTransport +try: + from google.api_core import client_logging # type: ignore + + CLIENT_LOGGING_SUPPORTED = True # pragma: NO COVER +except ImportError: # pragma: NO COVER + CLIENT_LOGGING_SUPPORTED = False + +_LOGGER = std_logging.getLogger(__name__) + class CssProductsServiceAsyncClient: """Service for doing get and list on Css Products(a.k.a @@ -264,6 +274,28 @@ def __init__( client_info=client_info, ) + if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( + std_logging.DEBUG + ): # pragma: NO COVER + _LOGGER.debug( + "Created client `google.shopping.css_v1.CssProductsServiceAsyncClient`.", + extra={ + "serviceName": "google.shopping.css.v1.CssProductsService", + "universeDomain": getattr( + self._client._transport._credentials, "universe_domain", "" + ), + "credentialsType": f"{type(self._client._transport._credentials).__module__}.{type(self._client._transport._credentials).__qualname__}", + "credentialsInfo": getattr( + self.transport._credentials, "get_cred_info", lambda: None + )(), + } + if hasattr(self._client._transport, "_credentials") + else { + "serviceName": "google.shopping.css.v1.CssProductsService", + "credentialsType": None, + }, + ) + async def get_css_product( self, request: Optional[Union[css_products.GetCssProductRequest, dict]] = None, @@ -271,7 +303,7 @@ async def get_css_product( name: Optional[str] = None, retry: OptionalRetry = gapic_v1.method.DEFAULT, timeout: Union[float, object] = gapic_v1.method.DEFAULT, - metadata: Sequence[Tuple[str, str]] = (), + metadata: Sequence[Tuple[str, Union[str, bytes]]] = (), ) -> css_products.CssProduct: r"""Retrieves the processed CSS Product from your CSS Center account. After inserting, updating, or deleting a @@ -317,8 +349,10 @@ async def sample_get_css_product(): retry (google.api_core.retry_async.AsyncRetry): Designation of what errors, if any, should be retried. timeout (float): The timeout for this request. - metadata (Sequence[Tuple[str, str]]): Strings which should be - sent along with the request as metadata. + metadata (Sequence[Tuple[str, Union[str, bytes]]]): Key/value pairs which should be + sent along with the request as metadata. Normally, each value must be of type `str`, + but for metadata keys ending with the suffix `-bin`, the corresponding values must + be of type `bytes`. Returns: google.shopping.css_v1.types.CssProduct: @@ -379,7 +413,7 @@ async def list_css_products( parent: Optional[str] = None, retry: OptionalRetry = gapic_v1.method.DEFAULT, timeout: Union[float, object] = gapic_v1.method.DEFAULT, - metadata: Sequence[Tuple[str, str]] = (), + metadata: Sequence[Tuple[str, Union[str, bytes]]] = (), ) -> pagers.ListCssProductsAsyncPager: r"""Lists the processed CSS Products in your CSS Center account. The response might contain fewer items than @@ -432,8 +466,10 @@ async def sample_list_css_products(): retry (google.api_core.retry_async.AsyncRetry): Designation of what errors, if any, should be retried. timeout (float): The timeout for this request. - metadata (Sequence[Tuple[str, str]]): Strings which should be - sent along with the request as metadata. + metadata (Sequence[Tuple[str, Union[str, bytes]]]): Key/value pairs which should be + sent along with the request as metadata. Normally, each value must be of type `str`, + but for metadata keys ending with the suffix `-bin`, the corresponding values must + be of type `bytes`. Returns: google.shopping.css_v1.services.css_products_service.pagers.ListCssProductsAsyncPager: diff --git a/packages/google-shopping-css/google/shopping/css_v1/services/css_products_service/client.py b/packages/google-shopping-css/google/shopping/css_v1/services/css_products_service/client.py index 906fdac7d928..730ef9df1d9b 100644 --- a/packages/google-shopping-css/google/shopping/css_v1/services/css_products_service/client.py +++ b/packages/google-shopping-css/google/shopping/css_v1/services/css_products_service/client.py @@ -14,6 +14,7 @@ # limitations under the License. # from collections import OrderedDict +import logging as std_logging import os import re from typing import ( @@ -48,6 +49,15 @@ except AttributeError: # pragma: NO COVER OptionalRetry = Union[retries.Retry, object, None] # type: ignore +try: + from google.api_core import client_logging # type: ignore + + CLIENT_LOGGING_SUPPORTED = True # pragma: NO COVER +except ImportError: # pragma: NO COVER + CLIENT_LOGGING_SUPPORTED = False + +_LOGGER = std_logging.getLogger(__name__) + from google.shopping.type.types import types from google.shopping.css_v1.services.css_products_service import pagers @@ -583,6 +593,10 @@ def __init__( # Initialize the universe domain validation. self._is_universe_domain_valid = False + if CLIENT_LOGGING_SUPPORTED: # pragma: NO COVER + # Setup logging. + client_logging.initialize_logging() + api_key_value = getattr(self._client_options, "api_key", None) if api_key_value and credentials: raise ValueError( @@ -649,6 +663,29 @@ def __init__( api_audience=self._client_options.api_audience, ) + if "async" not in str(self._transport): + if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( + std_logging.DEBUG + ): # pragma: NO COVER + _LOGGER.debug( + "Created client `google.shopping.css_v1.CssProductsServiceClient`.", + extra={ + "serviceName": "google.shopping.css.v1.CssProductsService", + "universeDomain": getattr( + self._transport._credentials, "universe_domain", "" + ), + "credentialsType": f"{type(self._transport._credentials).__module__}.{type(self._transport._credentials).__qualname__}", + "credentialsInfo": getattr( + self.transport._credentials, "get_cred_info", lambda: None + )(), + } + if hasattr(self._transport, "_credentials") + else { + "serviceName": "google.shopping.css.v1.CssProductsService", + "credentialsType": None, + }, + ) + def get_css_product( self, request: Optional[Union[css_products.GetCssProductRequest, dict]] = None, @@ -656,7 +693,7 @@ def get_css_product( name: Optional[str] = None, retry: OptionalRetry = gapic_v1.method.DEFAULT, timeout: Union[float, object] = gapic_v1.method.DEFAULT, - metadata: Sequence[Tuple[str, str]] = (), + metadata: Sequence[Tuple[str, Union[str, bytes]]] = (), ) -> css_products.CssProduct: r"""Retrieves the processed CSS Product from your CSS Center account. After inserting, updating, or deleting a @@ -702,8 +739,10 @@ def sample_get_css_product(): retry (google.api_core.retry.Retry): Designation of what errors, if any, should be retried. timeout (float): The timeout for this request. - metadata (Sequence[Tuple[str, str]]): Strings which should be - sent along with the request as metadata. + metadata (Sequence[Tuple[str, Union[str, bytes]]]): Key/value pairs which should be + sent along with the request as metadata. Normally, each value must be of type `str`, + but for metadata keys ending with the suffix `-bin`, the corresponding values must + be of type `bytes`. Returns: google.shopping.css_v1.types.CssProduct: @@ -761,7 +800,7 @@ def list_css_products( parent: Optional[str] = None, retry: OptionalRetry = gapic_v1.method.DEFAULT, timeout: Union[float, object] = gapic_v1.method.DEFAULT, - metadata: Sequence[Tuple[str, str]] = (), + metadata: Sequence[Tuple[str, Union[str, bytes]]] = (), ) -> pagers.ListCssProductsPager: r"""Lists the processed CSS Products in your CSS Center account. The response might contain fewer items than @@ -814,8 +853,10 @@ def sample_list_css_products(): retry (google.api_core.retry.Retry): Designation of what errors, if any, should be retried. timeout (float): The timeout for this request. - metadata (Sequence[Tuple[str, str]]): Strings which should be - sent along with the request as metadata. + metadata (Sequence[Tuple[str, Union[str, bytes]]]): Key/value pairs which should be + sent along with the request as metadata. Normally, each value must be of type `str`, + but for metadata keys ending with the suffix `-bin`, the corresponding values must + be of type `bytes`. Returns: google.shopping.css_v1.services.css_products_service.pagers.ListCssProductsPager: diff --git a/packages/google-shopping-css/google/shopping/css_v1/services/css_products_service/pagers.py b/packages/google-shopping-css/google/shopping/css_v1/services/css_products_service/pagers.py index 7a800cac351f..927c1af68e7b 100644 --- a/packages/google-shopping-css/google/shopping/css_v1/services/css_products_service/pagers.py +++ b/packages/google-shopping-css/google/shopping/css_v1/services/css_products_service/pagers.py @@ -67,7 +67,7 @@ def __init__( *, retry: OptionalRetry = gapic_v1.method.DEFAULT, timeout: Union[float, object] = gapic_v1.method.DEFAULT, - metadata: Sequence[Tuple[str, str]] = () + metadata: Sequence[Tuple[str, Union[str, bytes]]] = () ): """Instantiate the pager. @@ -81,8 +81,10 @@ def __init__( retry (google.api_core.retry.Retry): Designation of what errors, if any, should be retried. timeout (float): The timeout for this request. - metadata (Sequence[Tuple[str, str]]): Strings which should be - sent along with the request as metadata. + metadata (Sequence[Tuple[str, Union[str, bytes]]]): Key/value pairs which should be + sent along with the request as metadata. Normally, each value must be of type `str`, + but for metadata keys ending with the suffix `-bin`, the corresponding values must + be of type `bytes`. """ self._method = method self._request = css_products.ListCssProductsRequest(request) @@ -141,7 +143,7 @@ def __init__( *, retry: OptionalAsyncRetry = gapic_v1.method.DEFAULT, timeout: Union[float, object] = gapic_v1.method.DEFAULT, - metadata: Sequence[Tuple[str, str]] = () + metadata: Sequence[Tuple[str, Union[str, bytes]]] = () ): """Instantiates the pager. @@ -155,8 +157,10 @@ def __init__( retry (google.api_core.retry.AsyncRetry): Designation of what errors, if any, should be retried. timeout (float): The timeout for this request. - metadata (Sequence[Tuple[str, str]]): Strings which should be - sent along with the request as metadata. + metadata (Sequence[Tuple[str, Union[str, bytes]]]): Key/value pairs which should be + sent along with the request as metadata. Normally, each value must be of type `str`, + but for metadata keys ending with the suffix `-bin`, the corresponding values must + be of type `bytes`. """ self._method = method self._request = css_products.ListCssProductsRequest(request) diff --git a/packages/google-shopping-css/google/shopping/css_v1/services/css_products_service/transports/grpc.py b/packages/google-shopping-css/google/shopping/css_v1/services/css_products_service/transports/grpc.py index ba4c8eb1c92c..113d84f9da25 100644 --- a/packages/google-shopping-css/google/shopping/css_v1/services/css_products_service/transports/grpc.py +++ b/packages/google-shopping-css/google/shopping/css_v1/services/css_products_service/transports/grpc.py @@ -13,6 +13,9 @@ # See the License for the specific language governing permissions and # limitations under the License. # +import json +import logging as std_logging +import pickle from typing import Callable, Dict, Optional, Sequence, Tuple, Union import warnings @@ -20,12 +23,90 @@ import google.auth # type: ignore from google.auth import credentials as ga_credentials # type: ignore from google.auth.transport.grpc import SslCredentials # type: ignore +from google.protobuf.json_format import MessageToJson +import google.protobuf.message import grpc # type: ignore +import proto # type: ignore from google.shopping.css_v1.types import css_products from .base import DEFAULT_CLIENT_INFO, CssProductsServiceTransport +try: + from google.api_core import client_logging # type: ignore + + CLIENT_LOGGING_SUPPORTED = True # pragma: NO COVER +except ImportError: # pragma: NO COVER + CLIENT_LOGGING_SUPPORTED = False + +_LOGGER = std_logging.getLogger(__name__) + + +class _LoggingClientInterceptor(grpc.UnaryUnaryClientInterceptor): # pragma: NO COVER + def intercept_unary_unary(self, continuation, client_call_details, request): + logging_enabled = CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( + std_logging.DEBUG + ) + if logging_enabled: # pragma: NO COVER + request_metadata = client_call_details.metadata + if isinstance(request, proto.Message): + request_payload = type(request).to_json(request) + elif isinstance(request, google.protobuf.message.Message): + request_payload = MessageToJson(request) + else: + request_payload = f"{type(request).__name__}: {pickle.dumps(request)}" + + request_metadata = { + key: value.decode("utf-8") if isinstance(value, bytes) else value + for key, value in request_metadata + } + grpc_request = { + "payload": request_payload, + "requestMethod": "grpc", + "metadata": dict(request_metadata), + } + _LOGGER.debug( + f"Sending request for {client_call_details.method}", + extra={ + "serviceName": "google.shopping.css.v1.CssProductsService", + "rpcName": client_call_details.method, + "request": grpc_request, + "metadata": grpc_request["metadata"], + }, + ) + + response = continuation(client_call_details, request) + if logging_enabled: # pragma: NO COVER + response_metadata = response.trailing_metadata() + # Convert gRPC metadata `` to list of tuples + metadata = ( + dict([(k, str(v)) for k, v in response_metadata]) + if response_metadata + else None + ) + result = response.result() + if isinstance(result, proto.Message): + response_payload = type(result).to_json(result) + elif isinstance(result, google.protobuf.message.Message): + response_payload = MessageToJson(result) + else: + response_payload = f"{type(result).__name__}: {pickle.dumps(result)}" + grpc_response = { + "payload": response_payload, + "metadata": metadata, + "status": "OK", + } + _LOGGER.debug( + f"Received response for {client_call_details.method}.", + extra={ + "serviceName": "google.shopping.css.v1.CssProductsService", + "rpcName": client_call_details.method, + "response": grpc_response, + "metadata": grpc_response["metadata"], + }, + ) + return response + class CssProductsServiceGrpcTransport(CssProductsServiceTransport): """gRPC backend transport for CssProductsService. @@ -180,7 +261,12 @@ def __init__( ], ) - # Wrap messages. This must be done after self._grpc_channel exists + self._interceptor = _LoggingClientInterceptor() + self._logged_channel = grpc.intercept_channel( + self._grpc_channel, self._interceptor + ) + + # Wrap messages. This must be done after self._logged_channel exists self._prep_wrapped_messages(client_info) @classmethod @@ -257,7 +343,7 @@ def get_css_product( # gRPC handles serialization and deserialization, so we just need # to pass in the functions for each. if "get_css_product" not in self._stubs: - self._stubs["get_css_product"] = self.grpc_channel.unary_unary( + self._stubs["get_css_product"] = self._logged_channel.unary_unary( "/google.shopping.css.v1.CssProductsService/GetCssProduct", request_serializer=css_products.GetCssProductRequest.serialize, response_deserializer=css_products.CssProduct.deserialize, @@ -292,7 +378,7 @@ def list_css_products( # gRPC handles serialization and deserialization, so we just need # to pass in the functions for each. if "list_css_products" not in self._stubs: - self._stubs["list_css_products"] = self.grpc_channel.unary_unary( + self._stubs["list_css_products"] = self._logged_channel.unary_unary( "/google.shopping.css.v1.CssProductsService/ListCssProducts", request_serializer=css_products.ListCssProductsRequest.serialize, response_deserializer=css_products.ListCssProductsResponse.deserialize, @@ -300,7 +386,7 @@ def list_css_products( return self._stubs["list_css_products"] def close(self): - self.grpc_channel.close() + self._logged_channel.close() @property def kind(self) -> str: diff --git a/packages/google-shopping-css/google/shopping/css_v1/services/css_products_service/transports/grpc_asyncio.py b/packages/google-shopping-css/google/shopping/css_v1/services/css_products_service/transports/grpc_asyncio.py index 5ae2aefa9b75..a7c76405e13e 100644 --- a/packages/google-shopping-css/google/shopping/css_v1/services/css_products_service/transports/grpc_asyncio.py +++ b/packages/google-shopping-css/google/shopping/css_v1/services/css_products_service/transports/grpc_asyncio.py @@ -14,6 +14,9 @@ # limitations under the License. # import inspect +import json +import logging as std_logging +import pickle from typing import Awaitable, Callable, Dict, Optional, Sequence, Tuple, Union import warnings @@ -22,14 +25,93 @@ from google.api_core import retry_async as retries from google.auth import credentials as ga_credentials # type: ignore from google.auth.transport.grpc import SslCredentials # type: ignore +from google.protobuf.json_format import MessageToJson +import google.protobuf.message import grpc # type: ignore from grpc.experimental import aio # type: ignore +import proto # type: ignore from google.shopping.css_v1.types import css_products from .base import DEFAULT_CLIENT_INFO, CssProductsServiceTransport from .grpc import CssProductsServiceGrpcTransport +try: + from google.api_core import client_logging # type: ignore + + CLIENT_LOGGING_SUPPORTED = True # pragma: NO COVER +except ImportError: # pragma: NO COVER + CLIENT_LOGGING_SUPPORTED = False + +_LOGGER = std_logging.getLogger(__name__) + + +class _LoggingClientAIOInterceptor( + grpc.aio.UnaryUnaryClientInterceptor +): # pragma: NO COVER + async def intercept_unary_unary(self, continuation, client_call_details, request): + logging_enabled = CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( + std_logging.DEBUG + ) + if logging_enabled: # pragma: NO COVER + request_metadata = client_call_details.metadata + if isinstance(request, proto.Message): + request_payload = type(request).to_json(request) + elif isinstance(request, google.protobuf.message.Message): + request_payload = MessageToJson(request) + else: + request_payload = f"{type(request).__name__}: {pickle.dumps(request)}" + + request_metadata = { + key: value.decode("utf-8") if isinstance(value, bytes) else value + for key, value in request_metadata + } + grpc_request = { + "payload": request_payload, + "requestMethod": "grpc", + "metadata": dict(request_metadata), + } + _LOGGER.debug( + f"Sending request for {client_call_details.method}", + extra={ + "serviceName": "google.shopping.css.v1.CssProductsService", + "rpcName": str(client_call_details.method), + "request": grpc_request, + "metadata": grpc_request["metadata"], + }, + ) + response = await continuation(client_call_details, request) + if logging_enabled: # pragma: NO COVER + response_metadata = await response.trailing_metadata() + # Convert gRPC metadata `` to list of tuples + metadata = ( + dict([(k, str(v)) for k, v in response_metadata]) + if response_metadata + else None + ) + result = await response + if isinstance(result, proto.Message): + response_payload = type(result).to_json(result) + elif isinstance(result, google.protobuf.message.Message): + response_payload = MessageToJson(result) + else: + response_payload = f"{type(result).__name__}: {pickle.dumps(result)}" + grpc_response = { + "payload": response_payload, + "metadata": metadata, + "status": "OK", + } + _LOGGER.debug( + f"Received response to rpc {client_call_details.method}.", + extra={ + "serviceName": "google.shopping.css.v1.CssProductsService", + "rpcName": str(client_call_details.method), + "response": grpc_response, + "metadata": grpc_response["metadata"], + }, + ) + return response + class CssProductsServiceGrpcAsyncIOTransport(CssProductsServiceTransport): """gRPC AsyncIO backend transport for CssProductsService. @@ -227,10 +309,13 @@ def __init__( ], ) - # Wrap messages. This must be done after self._grpc_channel exists + self._interceptor = _LoggingClientAIOInterceptor() + self._grpc_channel._unary_unary_interceptors.append(self._interceptor) + self._logged_channel = self._grpc_channel self._wrap_with_kind = ( "kind" in inspect.signature(gapic_v1.method_async.wrap_method).parameters ) + # Wrap messages. This must be done after self._logged_channel exists self._prep_wrapped_messages(client_info) @property @@ -267,7 +352,7 @@ def get_css_product( # gRPC handles serialization and deserialization, so we just need # to pass in the functions for each. if "get_css_product" not in self._stubs: - self._stubs["get_css_product"] = self.grpc_channel.unary_unary( + self._stubs["get_css_product"] = self._logged_channel.unary_unary( "/google.shopping.css.v1.CssProductsService/GetCssProduct", request_serializer=css_products.GetCssProductRequest.serialize, response_deserializer=css_products.CssProduct.deserialize, @@ -303,7 +388,7 @@ def list_css_products( # gRPC handles serialization and deserialization, so we just need # to pass in the functions for each. if "list_css_products" not in self._stubs: - self._stubs["list_css_products"] = self.grpc_channel.unary_unary( + self._stubs["list_css_products"] = self._logged_channel.unary_unary( "/google.shopping.css.v1.CssProductsService/ListCssProducts", request_serializer=css_products.ListCssProductsRequest.serialize, response_deserializer=css_products.ListCssProductsResponse.deserialize, @@ -349,7 +434,7 @@ def _wrap_method(self, func, *args, **kwargs): return gapic_v1.method_async.wrap_method(func, *args, **kwargs) def close(self): - return self.grpc_channel.close() + return self._logged_channel.close() @property def kind(self) -> str: diff --git a/packages/google-shopping-css/google/shopping/css_v1/services/css_products_service/transports/rest.py b/packages/google-shopping-css/google/shopping/css_v1/services/css_products_service/transports/rest.py index 02319ec999ae..85e10300ba56 100644 --- a/packages/google-shopping-css/google/shopping/css_v1/services/css_products_service/transports/rest.py +++ b/packages/google-shopping-css/google/shopping/css_v1/services/css_products_service/transports/rest.py @@ -13,9 +13,9 @@ # See the License for the specific language governing permissions and # limitations under the License. # - import dataclasses import json # type: ignore +import logging from typing import Any, Callable, Dict, List, Optional, Sequence, Tuple, Union import warnings @@ -37,6 +37,14 @@ except AttributeError: # pragma: NO COVER OptionalRetry = Union[retries.Retry, object, None] # type: ignore +try: + from google.api_core import client_logging # type: ignore + + CLIENT_LOGGING_SUPPORTED = True # pragma: NO COVER +except ImportError: # pragma: NO COVER + CLIENT_LOGGING_SUPPORTED = False + +_LOGGER = logging.getLogger(__name__) DEFAULT_CLIENT_INFO = gapic_v1.client_info.ClientInfo( gapic_version=BASE_DEFAULT_CLIENT_INFO.gapic_version, @@ -85,8 +93,10 @@ def post_list_css_products(self, response): def pre_get_css_product( self, request: css_products.GetCssProductRequest, - metadata: Sequence[Tuple[str, str]], - ) -> Tuple[css_products.GetCssProductRequest, Sequence[Tuple[str, str]]]: + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[ + css_products.GetCssProductRequest, Sequence[Tuple[str, Union[str, bytes]]] + ]: """Pre-rpc interceptor for get_css_product Override in a subclass to manipulate the request or metadata @@ -108,8 +118,10 @@ def post_get_css_product( def pre_list_css_products( self, request: css_products.ListCssProductsRequest, - metadata: Sequence[Tuple[str, str]], - ) -> Tuple[css_products.ListCssProductsRequest, Sequence[Tuple[str, str]]]: + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[ + css_products.ListCssProductsRequest, Sequence[Tuple[str, Union[str, bytes]]] + ]: """Pre-rpc interceptor for list_css_products Override in a subclass to manipulate the request or metadata @@ -251,7 +263,7 @@ def __call__( *, retry: OptionalRetry = gapic_v1.method.DEFAULT, timeout: Optional[float] = None, - metadata: Sequence[Tuple[str, str]] = (), + metadata: Sequence[Tuple[str, Union[str, bytes]]] = (), ) -> css_products.CssProduct: r"""Call the get css product method over HTTP. @@ -261,8 +273,10 @@ def __call__( retry (google.api_core.retry.Retry): Designation of what errors, if any, should be retried. timeout (float): The timeout for this request. - metadata (Sequence[Tuple[str, str]]): Strings which should be - sent along with the request as metadata. + metadata (Sequence[Tuple[str, Union[str, bytes]]]): Key/value pairs which should be + sent along with the request as metadata. Normally, each value must be of type `str`, + but for metadata keys ending with the suffix `-bin`, the corresponding values must + be of type `bytes`. Returns: ~.css_products.CssProduct: @@ -274,6 +288,7 @@ def __call__( http_options = ( _BaseCssProductsServiceRestTransport._BaseGetCssProduct._get_http_options() ) + request, metadata = self._interceptor.pre_get_css_product(request, metadata) transcoded_request = _BaseCssProductsServiceRestTransport._BaseGetCssProduct._get_transcoded_request( http_options, request @@ -284,6 +299,33 @@ def __call__( transcoded_request ) + if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( + logging.DEBUG + ): # pragma: NO COVER + request_url = "{host}{uri}".format( + host=self._host, uri=transcoded_request["uri"] + ) + method = transcoded_request["method"] + try: + request_payload = type(request).to_json(request) + except: + request_payload = None + http_request = { + "payload": request_payload, + "requestMethod": method, + "requestUrl": request_url, + "headers": dict(metadata), + } + _LOGGER.debug( + f"Sending request for google.shopping.css_v1.CssProductsServiceClient.GetCssProduct", + extra={ + "serviceName": "google.shopping.css.v1.CssProductsService", + "rpcName": "GetCssProduct", + "httpRequest": http_request, + "metadata": http_request["headers"], + }, + ) + # Send the request response = CssProductsServiceRestTransport._GetCssProduct._get_response( self._host, @@ -304,7 +346,29 @@ def __call__( pb_resp = css_products.CssProduct.pb(resp) json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) + resp = self._interceptor.post_get_css_product(resp) + if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( + logging.DEBUG + ): # pragma: NO COVER + try: + response_payload = css_products.CssProduct.to_json(response) + except: + response_payload = None + http_response = { + "payload": response_payload, + "headers": dict(response.headers), + "status": response.status_code, + } + _LOGGER.debug( + "Received response for google.shopping.css_v1.CssProductsServiceClient.get_css_product", + extra={ + "serviceName": "google.shopping.css.v1.CssProductsService", + "rpcName": "GetCssProduct", + "metadata": http_response["headers"], + "httpResponse": http_response, + }, + ) return resp class _ListCssProducts( @@ -342,7 +406,7 @@ def __call__( *, retry: OptionalRetry = gapic_v1.method.DEFAULT, timeout: Optional[float] = None, - metadata: Sequence[Tuple[str, str]] = (), + metadata: Sequence[Tuple[str, Union[str, bytes]]] = (), ) -> css_products.ListCssProductsResponse: r"""Call the list css products method over HTTP. @@ -353,8 +417,10 @@ def __call__( retry (google.api_core.retry.Retry): Designation of what errors, if any, should be retried. timeout (float): The timeout for this request. - metadata (Sequence[Tuple[str, str]]): Strings which should be - sent along with the request as metadata. + metadata (Sequence[Tuple[str, Union[str, bytes]]]): Key/value pairs which should be + sent along with the request as metadata. Normally, each value must be of type `str`, + but for metadata keys ending with the suffix `-bin`, the corresponding values must + be of type `bytes`. Returns: ~.css_products.ListCssProductsResponse: @@ -366,6 +432,7 @@ def __call__( http_options = ( _BaseCssProductsServiceRestTransport._BaseListCssProducts._get_http_options() ) + request, metadata = self._interceptor.pre_list_css_products( request, metadata ) @@ -378,6 +445,33 @@ def __call__( transcoded_request ) + if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( + logging.DEBUG + ): # pragma: NO COVER + request_url = "{host}{uri}".format( + host=self._host, uri=transcoded_request["uri"] + ) + method = transcoded_request["method"] + try: + request_payload = type(request).to_json(request) + except: + request_payload = None + http_request = { + "payload": request_payload, + "requestMethod": method, + "requestUrl": request_url, + "headers": dict(metadata), + } + _LOGGER.debug( + f"Sending request for google.shopping.css_v1.CssProductsServiceClient.ListCssProducts", + extra={ + "serviceName": "google.shopping.css.v1.CssProductsService", + "rpcName": "ListCssProducts", + "httpRequest": http_request, + "metadata": http_request["headers"], + }, + ) + # Send the request response = CssProductsServiceRestTransport._ListCssProducts._get_response( self._host, @@ -398,7 +492,31 @@ def __call__( pb_resp = css_products.ListCssProductsResponse.pb(resp) json_format.Parse(response.content, pb_resp, ignore_unknown_fields=True) + resp = self._interceptor.post_list_css_products(resp) + if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( + logging.DEBUG + ): # pragma: NO COVER + try: + response_payload = css_products.ListCssProductsResponse.to_json( + response + ) + except: + response_payload = None + http_response = { + "payload": response_payload, + "headers": dict(response.headers), + "status": response.status_code, + } + _LOGGER.debug( + "Received response for google.shopping.css_v1.CssProductsServiceClient.list_css_products", + extra={ + "serviceName": "google.shopping.css.v1.CssProductsService", + "rpcName": "ListCssProducts", + "metadata": http_response["headers"], + "httpResponse": http_response, + }, + ) return resp @property diff --git a/packages/google-shopping-css/samples/generated_samples/snippet_metadata_google.shopping.css.v1.json b/packages/google-shopping-css/samples/generated_samples/snippet_metadata_google.shopping.css.v1.json index bffe33091b83..bb49e4f2bf14 100644 --- a/packages/google-shopping-css/samples/generated_samples/snippet_metadata_google.shopping.css.v1.json +++ b/packages/google-shopping-css/samples/generated_samples/snippet_metadata_google.shopping.css.v1.json @@ -8,7 +8,7 @@ ], "language": "PYTHON", "name": "google-shopping-css", - "version": "0.1.10" + "version": "0.1.0" }, "snippets": [ { @@ -51,7 +51,7 @@ }, { "name": "metadata", - "type": "Sequence[Tuple[str, str]" + "type": "Sequence[Tuple[str, Union[str, bytes]]]" } ], "resultType": "google.shopping.css_v1.types.AccountLabel", @@ -135,7 +135,7 @@ }, { "name": "metadata", - "type": "Sequence[Tuple[str, str]" + "type": "Sequence[Tuple[str, Union[str, bytes]]]" } ], "resultType": "google.shopping.css_v1.types.AccountLabel", @@ -216,7 +216,7 @@ }, { "name": "metadata", - "type": "Sequence[Tuple[str, str]" + "type": "Sequence[Tuple[str, Union[str, bytes]]]" } ], "shortName": "delete_account_label" @@ -293,7 +293,7 @@ }, { "name": "metadata", - "type": "Sequence[Tuple[str, str]" + "type": "Sequence[Tuple[str, Union[str, bytes]]]" } ], "shortName": "delete_account_label" @@ -371,7 +371,7 @@ }, { "name": "metadata", - "type": "Sequence[Tuple[str, str]" + "type": "Sequence[Tuple[str, Union[str, bytes]]]" } ], "resultType": "google.shopping.css_v1.services.account_labels_service.pagers.ListAccountLabelsAsyncPager", @@ -451,7 +451,7 @@ }, { "name": "metadata", - "type": "Sequence[Tuple[str, str]" + "type": "Sequence[Tuple[str, Union[str, bytes]]]" } ], "resultType": "google.shopping.css_v1.services.account_labels_service.pagers.ListAccountLabelsPager", @@ -532,7 +532,7 @@ }, { "name": "metadata", - "type": "Sequence[Tuple[str, str]" + "type": "Sequence[Tuple[str, Union[str, bytes]]]" } ], "resultType": "google.shopping.css_v1.types.AccountLabel", @@ -612,7 +612,7 @@ }, { "name": "metadata", - "type": "Sequence[Tuple[str, str]" + "type": "Sequence[Tuple[str, Union[str, bytes]]]" } ], "resultType": "google.shopping.css_v1.types.AccountLabel", @@ -693,7 +693,7 @@ }, { "name": "metadata", - "type": "Sequence[Tuple[str, str]" + "type": "Sequence[Tuple[str, Union[str, bytes]]]" } ], "resultType": "google.shopping.css_v1.types.Account", @@ -773,7 +773,7 @@ }, { "name": "metadata", - "type": "Sequence[Tuple[str, str]" + "type": "Sequence[Tuple[str, Union[str, bytes]]]" } ], "resultType": "google.shopping.css_v1.types.Account", @@ -854,7 +854,7 @@ }, { "name": "metadata", - "type": "Sequence[Tuple[str, str]" + "type": "Sequence[Tuple[str, Union[str, bytes]]]" } ], "resultType": "google.shopping.css_v1.services.accounts_service.pagers.ListChildAccountsAsyncPager", @@ -934,7 +934,7 @@ }, { "name": "metadata", - "type": "Sequence[Tuple[str, str]" + "type": "Sequence[Tuple[str, Union[str, bytes]]]" } ], "resultType": "google.shopping.css_v1.services.accounts_service.pagers.ListChildAccountsPager", @@ -1015,7 +1015,7 @@ }, { "name": "metadata", - "type": "Sequence[Tuple[str, str]" + "type": "Sequence[Tuple[str, Union[str, bytes]]]" } ], "resultType": "google.shopping.css_v1.types.Account", @@ -1095,7 +1095,7 @@ }, { "name": "metadata", - "type": "Sequence[Tuple[str, str]" + "type": "Sequence[Tuple[str, Union[str, bytes]]]" } ], "resultType": "google.shopping.css_v1.types.Account", @@ -1176,7 +1176,7 @@ }, { "name": "metadata", - "type": "Sequence[Tuple[str, str]" + "type": "Sequence[Tuple[str, Union[str, bytes]]]" } ], "shortName": "delete_css_product_input" @@ -1253,7 +1253,7 @@ }, { "name": "metadata", - "type": "Sequence[Tuple[str, str]" + "type": "Sequence[Tuple[str, Union[str, bytes]]]" } ], "shortName": "delete_css_product_input" @@ -1327,7 +1327,7 @@ }, { "name": "metadata", - "type": "Sequence[Tuple[str, str]" + "type": "Sequence[Tuple[str, Union[str, bytes]]]" } ], "resultType": "google.shopping.css_v1.types.CssProductInput", @@ -1403,7 +1403,7 @@ }, { "name": "metadata", - "type": "Sequence[Tuple[str, str]" + "type": "Sequence[Tuple[str, Union[str, bytes]]]" } ], "resultType": "google.shopping.css_v1.types.CssProductInput", @@ -1484,7 +1484,7 @@ }, { "name": "metadata", - "type": "Sequence[Tuple[str, str]" + "type": "Sequence[Tuple[str, Union[str, bytes]]]" } ], "resultType": "google.shopping.css_v1.types.CssProduct", @@ -1564,7 +1564,7 @@ }, { "name": "metadata", - "type": "Sequence[Tuple[str, str]" + "type": "Sequence[Tuple[str, Union[str, bytes]]]" } ], "resultType": "google.shopping.css_v1.types.CssProduct", @@ -1645,7 +1645,7 @@ }, { "name": "metadata", - "type": "Sequence[Tuple[str, str]" + "type": "Sequence[Tuple[str, Union[str, bytes]]]" } ], "resultType": "google.shopping.css_v1.services.css_products_service.pagers.ListCssProductsAsyncPager", @@ -1725,7 +1725,7 @@ }, { "name": "metadata", - "type": "Sequence[Tuple[str, str]" + "type": "Sequence[Tuple[str, Union[str, bytes]]]" } ], "resultType": "google.shopping.css_v1.services.css_products_service.pagers.ListCssProductsPager", diff --git a/packages/google-shopping-css/tests/unit/gapic/css_v1/test_account_labels_service.py b/packages/google-shopping-css/tests/unit/gapic/css_v1/test_account_labels_service.py index 5e8e99fb20be..bdbd908f0492 100644 --- a/packages/google-shopping-css/tests/unit/gapic/css_v1/test_account_labels_service.py +++ b/packages/google-shopping-css/tests/unit/gapic/css_v1/test_account_labels_service.py @@ -2839,6 +2839,7 @@ def test_list_account_labels_rest_required_fields( response_value._content = json_return_value.encode("UTF-8") req.return_value = response_value + req.return_value.headers = {"header-1": "value-1", "header-2": "value-2"} response = client.list_account_labels(request) @@ -2892,6 +2893,7 @@ def test_list_account_labels_rest_flattened(): json_return_value = json_format.MessageToJson(return_value) response_value._content = json_return_value.encode("UTF-8") req.return_value = response_value + req.return_value.headers = {"header-1": "value-1", "header-2": "value-2"} client.list_account_labels(**mock_args) @@ -3089,6 +3091,7 @@ def test_create_account_label_rest_required_fields( response_value._content = json_return_value.encode("UTF-8") req.return_value = response_value + req.return_value.headers = {"header-1": "value-1", "header-2": "value-2"} response = client.create_account_label(request) @@ -3143,6 +3146,7 @@ def test_create_account_label_rest_flattened(): json_return_value = json_format.MessageToJson(return_value) response_value._content = json_return_value.encode("UTF-8") req.return_value = response_value + req.return_value.headers = {"header-1": "value-1", "header-2": "value-2"} client.create_account_label(**mock_args) @@ -3273,6 +3277,7 @@ def test_update_account_label_rest_required_fields( response_value._content = json_return_value.encode("UTF-8") req.return_value = response_value + req.return_value.headers = {"header-1": "value-1", "header-2": "value-2"} response = client.update_account_label(request) @@ -3318,6 +3323,7 @@ def test_update_account_label_rest_flattened(): json_return_value = json_format.MessageToJson(return_value) response_value._content = json_return_value.encode("UTF-8") req.return_value = response_value + req.return_value.headers = {"header-1": "value-1", "header-2": "value-2"} client.update_account_label(**mock_args) @@ -3449,6 +3455,7 @@ def test_delete_account_label_rest_required_fields( response_value._content = json_return_value.encode("UTF-8") req.return_value = response_value + req.return_value.headers = {"header-1": "value-1", "header-2": "value-2"} response = client.delete_account_label(request) @@ -3492,6 +3499,7 @@ def test_delete_account_label_rest_flattened(): json_return_value = "" response_value._content = json_return_value.encode("UTF-8") req.return_value = response_value + req.return_value.headers = {"header-1": "value-1", "header-2": "value-2"} client.delete_account_label(**mock_args) @@ -3881,6 +3889,7 @@ def test_list_account_labels_rest_bad_request( response_value.status_code = 400 response_value.request = mock.Mock() req.return_value = response_value + req.return_value.headers = {"header-1": "value-1", "header-2": "value-2"} client.list_account_labels(request) @@ -3916,6 +3925,7 @@ def test_list_account_labels_rest_call_success(request_type): json_return_value = json_format.MessageToJson(return_value) response_value.content = json_return_value.encode("UTF-8") req.return_value = response_value + req.return_value.headers = {"header-1": "value-1", "header-2": "value-2"} response = client.list_account_labels(request) # Establish that the response is the type that we expect. @@ -3956,6 +3966,7 @@ def test_list_account_labels_rest_interceptors(null_interceptor): req.return_value = mock.Mock() req.return_value.status_code = 200 + req.return_value.headers = {"header-1": "value-1", "header-2": "value-2"} return_value = accounts_labels.ListAccountLabelsResponse.to_json( accounts_labels.ListAccountLabelsResponse() ) @@ -4002,6 +4013,7 @@ def test_create_account_label_rest_bad_request( response_value.status_code = 400 response_value.request = mock.Mock() req.return_value = response_value + req.return_value.headers = {"header-1": "value-1", "header-2": "value-2"} client.create_account_label(request) @@ -4117,6 +4129,7 @@ def get_message_fields(field): json_return_value = json_format.MessageToJson(return_value) response_value.content = json_return_value.encode("UTF-8") req.return_value = response_value + req.return_value.headers = {"header-1": "value-1", "header-2": "value-2"} response = client.create_account_label(request) # Establish that the response is the type that we expect. @@ -4162,6 +4175,7 @@ def test_create_account_label_rest_interceptors(null_interceptor): req.return_value = mock.Mock() req.return_value.status_code = 200 + req.return_value.headers = {"header-1": "value-1", "header-2": "value-2"} return_value = accounts_labels.AccountLabel.to_json( accounts_labels.AccountLabel() ) @@ -4208,6 +4222,7 @@ def test_update_account_label_rest_bad_request( response_value.status_code = 400 response_value.request = mock.Mock() req.return_value = response_value + req.return_value.headers = {"header-1": "value-1", "header-2": "value-2"} client.update_account_label(request) @@ -4323,6 +4338,7 @@ def get_message_fields(field): json_return_value = json_format.MessageToJson(return_value) response_value.content = json_return_value.encode("UTF-8") req.return_value = response_value + req.return_value.headers = {"header-1": "value-1", "header-2": "value-2"} response = client.update_account_label(request) # Establish that the response is the type that we expect. @@ -4368,6 +4384,7 @@ def test_update_account_label_rest_interceptors(null_interceptor): req.return_value = mock.Mock() req.return_value.status_code = 200 + req.return_value.headers = {"header-1": "value-1", "header-2": "value-2"} return_value = accounts_labels.AccountLabel.to_json( accounts_labels.AccountLabel() ) @@ -4414,6 +4431,7 @@ def test_delete_account_label_rest_bad_request( response_value.status_code = 400 response_value.request = mock.Mock() req.return_value = response_value + req.return_value.headers = {"header-1": "value-1", "header-2": "value-2"} client.delete_account_label(request) @@ -4444,6 +4462,7 @@ def test_delete_account_label_rest_call_success(request_type): json_return_value = "" response_value.content = json_return_value.encode("UTF-8") req.return_value = response_value + req.return_value.headers = {"header-1": "value-1", "header-2": "value-2"} response = client.delete_account_label(request) # Establish that the response is the type that we expect. @@ -4480,6 +4499,7 @@ def test_delete_account_label_rest_interceptors(null_interceptor): req.return_value = mock.Mock() req.return_value.status_code = 200 + req.return_value.headers = {"header-1": "value-1", "header-2": "value-2"} request = accounts_labels.DeleteAccountLabelRequest() metadata = [ diff --git a/packages/google-shopping-css/tests/unit/gapic/css_v1/test_accounts_service.py b/packages/google-shopping-css/tests/unit/gapic/css_v1/test_accounts_service.py index 8d5039fa2ca3..bb6835d5bc1c 100644 --- a/packages/google-shopping-css/tests/unit/gapic/css_v1/test_accounts_service.py +++ b/packages/google-shopping-css/tests/unit/gapic/css_v1/test_accounts_service.py @@ -2444,6 +2444,7 @@ def test_list_child_accounts_rest_required_fields( response_value._content = json_return_value.encode("UTF-8") req.return_value = response_value + req.return_value.headers = {"header-1": "value-1", "header-2": "value-2"} response = client.list_child_accounts(request) @@ -2499,6 +2500,7 @@ def test_list_child_accounts_rest_flattened(): json_return_value = json_format.MessageToJson(return_value) response_value._content = json_return_value.encode("UTF-8") req.return_value = response_value + req.return_value.headers = {"header-1": "value-1", "header-2": "value-2"} client.list_child_accounts(**mock_args) @@ -2692,6 +2694,7 @@ def test_get_account_rest_required_fields(request_type=accounts.GetAccountReques response_value._content = json_return_value.encode("UTF-8") req.return_value = response_value + req.return_value.headers = {"header-1": "value-1", "header-2": "value-2"} response = client.get_account(request) @@ -2737,6 +2740,7 @@ def test_get_account_rest_flattened(): json_return_value = json_format.MessageToJson(return_value) response_value._content = json_return_value.encode("UTF-8") req.return_value = response_value + req.return_value.headers = {"header-1": "value-1", "header-2": "value-2"} client.get_account(**mock_args) @@ -2867,6 +2871,7 @@ def test_update_labels_rest_required_fields( response_value._content = json_return_value.encode("UTF-8") req.return_value = response_value + req.return_value.headers = {"header-1": "value-1", "header-2": "value-2"} response = client.update_labels(request) @@ -2912,6 +2917,7 @@ def test_update_labels_rest_flattened(): json_return_value = json_format.MessageToJson(return_value) response_value._content = json_return_value.encode("UTF-8") req.return_value = response_value + req.return_value.headers = {"header-1": "value-1", "header-2": "value-2"} client.update_labels(**mock_args) @@ -3249,6 +3255,7 @@ def test_list_child_accounts_rest_bad_request( response_value.status_code = 400 response_value.request = mock.Mock() req.return_value = response_value + req.return_value.headers = {"header-1": "value-1", "header-2": "value-2"} client.list_child_accounts(request) @@ -3284,6 +3291,7 @@ def test_list_child_accounts_rest_call_success(request_type): json_return_value = json_format.MessageToJson(return_value) response_value.content = json_return_value.encode("UTF-8") req.return_value = response_value + req.return_value.headers = {"header-1": "value-1", "header-2": "value-2"} response = client.list_child_accounts(request) # Establish that the response is the type that we expect. @@ -3324,6 +3332,7 @@ def test_list_child_accounts_rest_interceptors(null_interceptor): req.return_value = mock.Mock() req.return_value.status_code = 200 + req.return_value.headers = {"header-1": "value-1", "header-2": "value-2"} return_value = accounts.ListChildAccountsResponse.to_json( accounts.ListChildAccountsResponse() ) @@ -3368,6 +3377,7 @@ def test_get_account_rest_bad_request(request_type=accounts.GetAccountRequest): response_value.status_code = 400 response_value.request = mock.Mock() req.return_value = response_value + req.return_value.headers = {"header-1": "value-1", "header-2": "value-2"} client.get_account(request) @@ -3410,6 +3420,7 @@ def test_get_account_rest_call_success(request_type): json_return_value = json_format.MessageToJson(return_value) response_value.content = json_return_value.encode("UTF-8") req.return_value = response_value + req.return_value.headers = {"header-1": "value-1", "header-2": "value-2"} response = client.get_account(request) # Establish that the response is the type that we expect. @@ -3455,6 +3466,7 @@ def test_get_account_rest_interceptors(null_interceptor): req.return_value = mock.Mock() req.return_value.status_code = 200 + req.return_value.headers = {"header-1": "value-1", "header-2": "value-2"} return_value = accounts.Account.to_json(accounts.Account()) req.return_value.content = return_value @@ -3499,6 +3511,7 @@ def test_update_labels_rest_bad_request( response_value.status_code = 400 response_value.request = mock.Mock() req.return_value = response_value + req.return_value.headers = {"header-1": "value-1", "header-2": "value-2"} client.update_labels(request) @@ -3541,6 +3554,7 @@ def test_update_labels_rest_call_success(request_type): json_return_value = json_format.MessageToJson(return_value) response_value.content = json_return_value.encode("UTF-8") req.return_value = response_value + req.return_value.headers = {"header-1": "value-1", "header-2": "value-2"} response = client.update_labels(request) # Establish that the response is the type that we expect. @@ -3588,6 +3602,7 @@ def test_update_labels_rest_interceptors(null_interceptor): req.return_value = mock.Mock() req.return_value.status_code = 200 + req.return_value.headers = {"header-1": "value-1", "header-2": "value-2"} return_value = accounts.Account.to_json(accounts.Account()) req.return_value.content = return_value diff --git a/packages/google-shopping-css/tests/unit/gapic/css_v1/test_css_product_inputs_service.py b/packages/google-shopping-css/tests/unit/gapic/css_v1/test_css_product_inputs_service.py index 3b658de6b349..698cbedd8d35 100644 --- a/packages/google-shopping-css/tests/unit/gapic/css_v1/test_css_product_inputs_service.py +++ b/packages/google-shopping-css/tests/unit/gapic/css_v1/test_css_product_inputs_service.py @@ -1846,6 +1846,7 @@ def test_insert_css_product_input_rest_required_fields( response_value._content = json_return_value.encode("UTF-8") req.return_value = response_value + req.return_value.headers = {"header-1": "value-1", "header-2": "value-2"} response = client.insert_css_product_input(request) @@ -1984,6 +1985,7 @@ def test_delete_css_product_input_rest_required_fields( response_value._content = json_return_value.encode("UTF-8") req.return_value = response_value + req.return_value.headers = {"header-1": "value-1", "header-2": "value-2"} response = client.delete_css_product_input(request) @@ -2027,6 +2029,7 @@ def test_delete_css_product_input_rest_flattened(): json_return_value = "" response_value._content = json_return_value.encode("UTF-8") req.return_value = response_value + req.return_value.headers = {"header-1": "value-1", "header-2": "value-2"} client.delete_css_product_input(**mock_args) @@ -2307,6 +2310,7 @@ def test_insert_css_product_input_rest_bad_request( response_value.status_code = 400 response_value.request = mock.Mock() req.return_value = response_value + req.return_value.headers = {"header-1": "value-1", "header-2": "value-2"} client.insert_css_product_input(request) @@ -2513,6 +2517,7 @@ def get_message_fields(field): json_return_value = json_format.MessageToJson(return_value) response_value.content = json_return_value.encode("UTF-8") req.return_value = response_value + req.return_value.headers = {"header-1": "value-1", "header-2": "value-2"} response = client.insert_css_product_input(request) # Establish that the response is the type that we expect. @@ -2559,6 +2564,7 @@ def test_insert_css_product_input_rest_interceptors(null_interceptor): req.return_value = mock.Mock() req.return_value.status_code = 200 + req.return_value.headers = {"header-1": "value-1", "header-2": "value-2"} return_value = css_product_inputs.CssProductInput.to_json( css_product_inputs.CssProductInput() ) @@ -2605,6 +2611,7 @@ def test_delete_css_product_input_rest_bad_request( response_value.status_code = 400 response_value.request = mock.Mock() req.return_value = response_value + req.return_value.headers = {"header-1": "value-1", "header-2": "value-2"} client.delete_css_product_input(request) @@ -2635,6 +2642,7 @@ def test_delete_css_product_input_rest_call_success(request_type): json_return_value = "" response_value.content = json_return_value.encode("UTF-8") req.return_value = response_value + req.return_value.headers = {"header-1": "value-1", "header-2": "value-2"} response = client.delete_css_product_input(request) # Establish that the response is the type that we expect. @@ -2672,6 +2680,7 @@ def test_delete_css_product_input_rest_interceptors(null_interceptor): req.return_value = mock.Mock() req.return_value.status_code = 200 + req.return_value.headers = {"header-1": "value-1", "header-2": "value-2"} request = css_product_inputs.DeleteCssProductInputRequest() metadata = [ diff --git a/packages/google-shopping-css/tests/unit/gapic/css_v1/test_css_products_service.py b/packages/google-shopping-css/tests/unit/gapic/css_v1/test_css_products_service.py index c863dd8a1008..bbde0a0dd355 100644 --- a/packages/google-shopping-css/tests/unit/gapic/css_v1/test_css_products_service.py +++ b/packages/google-shopping-css/tests/unit/gapic/css_v1/test_css_products_service.py @@ -2083,6 +2083,7 @@ def test_get_css_product_rest_required_fields( response_value._content = json_return_value.encode("UTF-8") req.return_value = response_value + req.return_value.headers = {"header-1": "value-1", "header-2": "value-2"} response = client.get_css_product(request) @@ -2128,6 +2129,7 @@ def test_get_css_product_rest_flattened(): json_return_value = json_format.MessageToJson(return_value) response_value._content = json_return_value.encode("UTF-8") req.return_value = response_value + req.return_value.headers = {"header-1": "value-1", "header-2": "value-2"} client.get_css_product(**mock_args) @@ -2266,6 +2268,7 @@ def test_list_css_products_rest_required_fields( response_value._content = json_return_value.encode("UTF-8") req.return_value = response_value + req.return_value.headers = {"header-1": "value-1", "header-2": "value-2"} response = client.list_css_products(request) @@ -2319,6 +2322,7 @@ def test_list_css_products_rest_flattened(): json_return_value = json_format.MessageToJson(return_value) response_value._content = json_return_value.encode("UTF-8") req.return_value = response_value + req.return_value.headers = {"header-1": "value-1", "header-2": "value-2"} client.list_css_products(**mock_args) @@ -2660,6 +2664,7 @@ def test_get_css_product_rest_bad_request( response_value.status_code = 400 response_value.request = mock.Mock() req.return_value = response_value + req.return_value.headers = {"header-1": "value-1", "header-2": "value-2"} client.get_css_product(request) @@ -2698,6 +2703,7 @@ def test_get_css_product_rest_call_success(request_type): json_return_value = json_format.MessageToJson(return_value) response_value.content = json_return_value.encode("UTF-8") req.return_value = response_value + req.return_value.headers = {"header-1": "value-1", "header-2": "value-2"} response = client.get_css_product(request) # Establish that the response is the type that we expect. @@ -2741,6 +2747,7 @@ def test_get_css_product_rest_interceptors(null_interceptor): req.return_value = mock.Mock() req.return_value.status_code = 200 + req.return_value.headers = {"header-1": "value-1", "header-2": "value-2"} return_value = css_products.CssProduct.to_json(css_products.CssProduct()) req.return_value.content = return_value @@ -2785,6 +2792,7 @@ def test_list_css_products_rest_bad_request( response_value.status_code = 400 response_value.request = mock.Mock() req.return_value = response_value + req.return_value.headers = {"header-1": "value-1", "header-2": "value-2"} client.list_css_products(request) @@ -2820,6 +2828,7 @@ def test_list_css_products_rest_call_success(request_type): json_return_value = json_format.MessageToJson(return_value) response_value.content = json_return_value.encode("UTF-8") req.return_value = response_value + req.return_value.headers = {"header-1": "value-1", "header-2": "value-2"} response = client.list_css_products(request) # Establish that the response is the type that we expect. @@ -2860,6 +2869,7 @@ def test_list_css_products_rest_interceptors(null_interceptor): req.return_value = mock.Mock() req.return_value.status_code = 200 + req.return_value.headers = {"header-1": "value-1", "header-2": "value-2"} return_value = css_products.ListCssProductsResponse.to_json( css_products.ListCssProductsResponse() )