1# -*- coding: utf-8 -*-
2# Copyright 2025 Google LLC
3#
4# Licensed under the Apache License, Version 2.0 (the "License");
5# you may not use this file except in compliance with the License.
6# You may obtain a copy of the License at
7#
8# http://www.apache.org/licenses/LICENSE-2.0
9#
10# Unless required by applicable law or agreed to in writing, software
11# distributed under the License is distributed on an "AS IS" BASIS,
12# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13# See the License for the specific language governing permissions and
14# limitations under the License.
15#
16from collections import OrderedDict
17from http import HTTPStatus
18import json
19import logging as std_logging
20import os
21import re
22from typing import (
23 Dict,
24 Callable,
25 Mapping,
26 MutableMapping,
27 MutableSequence,
28 Optional,
29 Sequence,
30 Tuple,
31 Type,
32 Union,
33 cast,
34)
35import warnings
36
37from google.cloud.errorreporting_v1beta1 import gapic_version as package_version
38
39from google.api_core import client_options as client_options_lib
40from google.api_core import exceptions as core_exceptions
41from google.api_core import gapic_v1
42from google.api_core import retry as retries
43from google.auth import credentials as ga_credentials # type: ignore
44from google.auth.transport import mtls # type: ignore
45from google.auth.transport.grpc import SslCredentials # type: ignore
46from google.auth.exceptions import MutualTLSChannelError # type: ignore
47from google.oauth2 import service_account # type: ignore
48import google.protobuf
49
50try:
51 OptionalRetry = Union[retries.Retry, gapic_v1.method._MethodDefault, None]
52except AttributeError: # pragma: NO COVER
53 OptionalRetry = Union[retries.Retry, object, None] # type: ignore
54
55try:
56 from google.api_core import client_logging # type: ignore
57
58 CLIENT_LOGGING_SUPPORTED = True # pragma: NO COVER
59except ImportError: # pragma: NO COVER
60 CLIENT_LOGGING_SUPPORTED = False
61
62_LOGGER = std_logging.getLogger(__name__)
63
64from google.cloud.errorreporting_v1beta1.types import report_errors_service
65from .transports.base import ReportErrorsServiceTransport, DEFAULT_CLIENT_INFO
66from .transports.grpc import ReportErrorsServiceGrpcTransport
67from .transports.grpc_asyncio import ReportErrorsServiceGrpcAsyncIOTransport
68from .transports.rest import ReportErrorsServiceRestTransport
69
70
71class ReportErrorsServiceClientMeta(type):
72 """Metaclass for the ReportErrorsService client.
73
74 This provides class-level methods for building and retrieving
75 support objects (e.g. transport) without polluting the client instance
76 objects.
77 """
78
79 _transport_registry = (
80 OrderedDict()
81 ) # type: Dict[str, Type[ReportErrorsServiceTransport]]
82 _transport_registry["grpc"] = ReportErrorsServiceGrpcTransport
83 _transport_registry["grpc_asyncio"] = ReportErrorsServiceGrpcAsyncIOTransport
84 _transport_registry["rest"] = ReportErrorsServiceRestTransport
85
86 def get_transport_class(
87 cls,
88 label: Optional[str] = None,
89 ) -> Type[ReportErrorsServiceTransport]:
90 """Returns an appropriate transport class.
91
92 Args:
93 label: The name of the desired transport. If none is
94 provided, then the first transport in the registry is used.
95
96 Returns:
97 The transport class to use.
98 """
99 # If a specific transport is requested, return that one.
100 if label:
101 return cls._transport_registry[label]
102
103 # No transport is requested; return the default (that is, the first one
104 # in the dictionary).
105 return next(iter(cls._transport_registry.values()))
106
107
108class ReportErrorsServiceClient(metaclass=ReportErrorsServiceClientMeta):
109 """An API for reporting error events."""
110
111 @staticmethod
112 def _get_default_mtls_endpoint(api_endpoint):
113 """Converts api endpoint to mTLS endpoint.
114
115 Convert "*.sandbox.googleapis.com" and "*.googleapis.com" to
116 "*.mtls.sandbox.googleapis.com" and "*.mtls.googleapis.com" respectively.
117 Args:
118 api_endpoint (Optional[str]): the api endpoint to convert.
119 Returns:
120 str: converted mTLS api endpoint.
121 """
122 if not api_endpoint:
123 return api_endpoint
124
125 mtls_endpoint_re = re.compile(
126 r"(?P<name>[^.]+)(?P<mtls>\.mtls)?(?P<sandbox>\.sandbox)?(?P<googledomain>\.googleapis\.com)?"
127 )
128
129 m = mtls_endpoint_re.match(api_endpoint)
130 name, mtls, sandbox, googledomain = m.groups()
131 if mtls or not googledomain:
132 return api_endpoint
133
134 if sandbox:
135 return api_endpoint.replace(
136 "sandbox.googleapis.com", "mtls.sandbox.googleapis.com"
137 )
138
139 return api_endpoint.replace(".googleapis.com", ".mtls.googleapis.com")
140
141 # Note: DEFAULT_ENDPOINT is deprecated. Use _DEFAULT_ENDPOINT_TEMPLATE instead.
142 DEFAULT_ENDPOINT = "clouderrorreporting.googleapis.com"
143 DEFAULT_MTLS_ENDPOINT = _get_default_mtls_endpoint.__func__( # type: ignore
144 DEFAULT_ENDPOINT
145 )
146
147 _DEFAULT_ENDPOINT_TEMPLATE = "clouderrorreporting.{UNIVERSE_DOMAIN}"
148 _DEFAULT_UNIVERSE = "googleapis.com"
149
150 @staticmethod
151 def _use_client_cert_effective():
152 """Returns whether client certificate should be used for mTLS if the
153 google-auth version supports should_use_client_cert automatic mTLS enablement.
154
155 Alternatively, read from the GOOGLE_API_USE_CLIENT_CERTIFICATE env var.
156
157 Returns:
158 bool: whether client certificate should be used for mTLS
159 Raises:
160 ValueError: (If using a version of google-auth without should_use_client_cert and
161 GOOGLE_API_USE_CLIENT_CERTIFICATE is set to an unexpected value.)
162 """
163 # check if google-auth version supports should_use_client_cert for automatic mTLS enablement
164 if hasattr(mtls, "should_use_client_cert"): # pragma: NO COVER
165 return mtls.should_use_client_cert()
166 else: # pragma: NO COVER
167 # if unsupported, fallback to reading from env var
168 use_client_cert_str = os.getenv(
169 "GOOGLE_API_USE_CLIENT_CERTIFICATE", "false"
170 ).lower()
171 if use_client_cert_str not in ("true", "false"):
172 raise ValueError(
173 "Environment variable `GOOGLE_API_USE_CLIENT_CERTIFICATE` must be"
174 " either `true` or `false`"
175 )
176 return use_client_cert_str == "true"
177
178 @classmethod
179 def from_service_account_info(cls, info: dict, *args, **kwargs):
180 """Creates an instance of this client using the provided credentials
181 info.
182
183 Args:
184 info (dict): The service account private key info.
185 args: Additional arguments to pass to the constructor.
186 kwargs: Additional arguments to pass to the constructor.
187
188 Returns:
189 ReportErrorsServiceClient: The constructed client.
190 """
191 credentials = service_account.Credentials.from_service_account_info(info)
192 kwargs["credentials"] = credentials
193 return cls(*args, **kwargs)
194
195 @classmethod
196 def from_service_account_file(cls, filename: str, *args, **kwargs):
197 """Creates an instance of this client using the provided credentials
198 file.
199
200 Args:
201 filename (str): The path to the service account private key json
202 file.
203 args: Additional arguments to pass to the constructor.
204 kwargs: Additional arguments to pass to the constructor.
205
206 Returns:
207 ReportErrorsServiceClient: The constructed client.
208 """
209 credentials = service_account.Credentials.from_service_account_file(filename)
210 kwargs["credentials"] = credentials
211 return cls(*args, **kwargs)
212
213 from_service_account_json = from_service_account_file
214
215 @property
216 def transport(self) -> ReportErrorsServiceTransport:
217 """Returns the transport used by the client instance.
218
219 Returns:
220 ReportErrorsServiceTransport: The transport used by the client
221 instance.
222 """
223 return self._transport
224
225 @staticmethod
226 def common_billing_account_path(
227 billing_account: str,
228 ) -> str:
229 """Returns a fully-qualified billing_account string."""
230 return "billingAccounts/{billing_account}".format(
231 billing_account=billing_account,
232 )
233
234 @staticmethod
235 def parse_common_billing_account_path(path: str) -> Dict[str, str]:
236 """Parse a billing_account path into its component segments."""
237 m = re.match(r"^billingAccounts/(?P<billing_account>.+?)$", path)
238 return m.groupdict() if m else {}
239
240 @staticmethod
241 def common_folder_path(
242 folder: str,
243 ) -> str:
244 """Returns a fully-qualified folder string."""
245 return "folders/{folder}".format(
246 folder=folder,
247 )
248
249 @staticmethod
250 def parse_common_folder_path(path: str) -> Dict[str, str]:
251 """Parse a folder path into its component segments."""
252 m = re.match(r"^folders/(?P<folder>.+?)$", path)
253 return m.groupdict() if m else {}
254
255 @staticmethod
256 def common_organization_path(
257 organization: str,
258 ) -> str:
259 """Returns a fully-qualified organization string."""
260 return "organizations/{organization}".format(
261 organization=organization,
262 )
263
264 @staticmethod
265 def parse_common_organization_path(path: str) -> Dict[str, str]:
266 """Parse a organization path into its component segments."""
267 m = re.match(r"^organizations/(?P<organization>.+?)$", path)
268 return m.groupdict() if m else {}
269
270 @staticmethod
271 def common_project_path(
272 project: str,
273 ) -> str:
274 """Returns a fully-qualified project string."""
275 return "projects/{project}".format(
276 project=project,
277 )
278
279 @staticmethod
280 def parse_common_project_path(path: str) -> Dict[str, str]:
281 """Parse a project path into its component segments."""
282 m = re.match(r"^projects/(?P<project>.+?)$", path)
283 return m.groupdict() if m else {}
284
285 @staticmethod
286 def common_location_path(
287 project: str,
288 location: str,
289 ) -> str:
290 """Returns a fully-qualified location string."""
291 return "projects/{project}/locations/{location}".format(
292 project=project,
293 location=location,
294 )
295
296 @staticmethod
297 def parse_common_location_path(path: str) -> Dict[str, str]:
298 """Parse a location path into its component segments."""
299 m = re.match(r"^projects/(?P<project>.+?)/locations/(?P<location>.+?)$", path)
300 return m.groupdict() if m else {}
301
302 @classmethod
303 def get_mtls_endpoint_and_cert_source(
304 cls, client_options: Optional[client_options_lib.ClientOptions] = None
305 ):
306 """Deprecated. Return the API endpoint and client cert source for mutual TLS.
307
308 The client cert source is determined in the following order:
309 (1) if `GOOGLE_API_USE_CLIENT_CERTIFICATE` environment variable is not "true", the
310 client cert source is None.
311 (2) if `client_options.client_cert_source` is provided, use the provided one; if the
312 default client cert source exists, use the default one; otherwise the client cert
313 source is None.
314
315 The API endpoint is determined in the following order:
316 (1) if `client_options.api_endpoint` if provided, use the provided one.
317 (2) if `GOOGLE_API_USE_CLIENT_CERTIFICATE` environment variable is "always", use the
318 default mTLS endpoint; if the environment variable is "never", use the default API
319 endpoint; otherwise if client cert source exists, use the default mTLS endpoint, otherwise
320 use the default API endpoint.
321
322 More details can be found at https://google.aip.dev/auth/4114.
323
324 Args:
325 client_options (google.api_core.client_options.ClientOptions): Custom options for the
326 client. Only the `api_endpoint` and `client_cert_source` properties may be used
327 in this method.
328
329 Returns:
330 Tuple[str, Callable[[], Tuple[bytes, bytes]]]: returns the API endpoint and the
331 client cert source to use.
332
333 Raises:
334 google.auth.exceptions.MutualTLSChannelError: If any errors happen.
335 """
336
337 warnings.warn(
338 "get_mtls_endpoint_and_cert_source is deprecated. Use the api_endpoint property instead.",
339 DeprecationWarning,
340 )
341 if client_options is None:
342 client_options = client_options_lib.ClientOptions()
343 use_client_cert = ReportErrorsServiceClient._use_client_cert_effective()
344 use_mtls_endpoint = os.getenv("GOOGLE_API_USE_MTLS_ENDPOINT", "auto")
345 if use_mtls_endpoint not in ("auto", "never", "always"):
346 raise MutualTLSChannelError(
347 "Environment variable `GOOGLE_API_USE_MTLS_ENDPOINT` must be `never`, `auto` or `always`"
348 )
349
350 # Figure out the client cert source to use.
351 client_cert_source = None
352 if use_client_cert:
353 if client_options.client_cert_source:
354 client_cert_source = client_options.client_cert_source
355 elif mtls.has_default_client_cert_source():
356 client_cert_source = mtls.default_client_cert_source()
357
358 # Figure out which api endpoint to use.
359 if client_options.api_endpoint is not None:
360 api_endpoint = client_options.api_endpoint
361 elif use_mtls_endpoint == "always" or (
362 use_mtls_endpoint == "auto" and client_cert_source
363 ):
364 api_endpoint = cls.DEFAULT_MTLS_ENDPOINT
365 else:
366 api_endpoint = cls.DEFAULT_ENDPOINT
367
368 return api_endpoint, client_cert_source
369
370 @staticmethod
371 def _read_environment_variables():
372 """Returns the environment variables used by the client.
373
374 Returns:
375 Tuple[bool, str, str]: returns the GOOGLE_API_USE_CLIENT_CERTIFICATE,
376 GOOGLE_API_USE_MTLS_ENDPOINT, and GOOGLE_CLOUD_UNIVERSE_DOMAIN environment variables.
377
378 Raises:
379 ValueError: If GOOGLE_API_USE_CLIENT_CERTIFICATE is not
380 any of ["true", "false"].
381 google.auth.exceptions.MutualTLSChannelError: If GOOGLE_API_USE_MTLS_ENDPOINT
382 is not any of ["auto", "never", "always"].
383 """
384 use_client_cert = ReportErrorsServiceClient._use_client_cert_effective()
385 use_mtls_endpoint = os.getenv("GOOGLE_API_USE_MTLS_ENDPOINT", "auto").lower()
386 universe_domain_env = os.getenv("GOOGLE_CLOUD_UNIVERSE_DOMAIN")
387 if use_mtls_endpoint not in ("auto", "never", "always"):
388 raise MutualTLSChannelError(
389 "Environment variable `GOOGLE_API_USE_MTLS_ENDPOINT` must be `never`, `auto` or `always`"
390 )
391 return use_client_cert, use_mtls_endpoint, universe_domain_env
392
393 @staticmethod
394 def _get_client_cert_source(provided_cert_source, use_cert_flag):
395 """Return the client cert source to be used by the client.
396
397 Args:
398 provided_cert_source (bytes): The client certificate source provided.
399 use_cert_flag (bool): A flag indicating whether to use the client certificate.
400
401 Returns:
402 bytes or None: The client cert source to be used by the client.
403 """
404 client_cert_source = None
405 if use_cert_flag:
406 if provided_cert_source:
407 client_cert_source = provided_cert_source
408 elif mtls.has_default_client_cert_source():
409 client_cert_source = mtls.default_client_cert_source()
410 return client_cert_source
411
412 @staticmethod
413 def _get_api_endpoint(
414 api_override, client_cert_source, universe_domain, use_mtls_endpoint
415 ):
416 """Return the API endpoint used by the client.
417
418 Args:
419 api_override (str): The API endpoint override. If specified, this is always
420 the return value of this function and the other arguments are not used.
421 client_cert_source (bytes): The client certificate source used by the client.
422 universe_domain (str): The universe domain used by the client.
423 use_mtls_endpoint (str): How to use the mTLS endpoint, which depends also on the other parameters.
424 Possible values are "always", "auto", or "never".
425
426 Returns:
427 str: The API endpoint to be used by the client.
428 """
429 if api_override is not None:
430 api_endpoint = api_override
431 elif use_mtls_endpoint == "always" or (
432 use_mtls_endpoint == "auto" and client_cert_source
433 ):
434 _default_universe = ReportErrorsServiceClient._DEFAULT_UNIVERSE
435 if universe_domain != _default_universe:
436 raise MutualTLSChannelError(
437 f"mTLS is not supported in any universe other than {_default_universe}."
438 )
439 api_endpoint = ReportErrorsServiceClient.DEFAULT_MTLS_ENDPOINT
440 else:
441 api_endpoint = ReportErrorsServiceClient._DEFAULT_ENDPOINT_TEMPLATE.format(
442 UNIVERSE_DOMAIN=universe_domain
443 )
444 return api_endpoint
445
446 @staticmethod
447 def _get_universe_domain(
448 client_universe_domain: Optional[str], universe_domain_env: Optional[str]
449 ) -> str:
450 """Return the universe domain used by the client.
451
452 Args:
453 client_universe_domain (Optional[str]): The universe domain configured via the client options.
454 universe_domain_env (Optional[str]): The universe domain configured via the "GOOGLE_CLOUD_UNIVERSE_DOMAIN" environment variable.
455
456 Returns:
457 str: The universe domain to be used by the client.
458
459 Raises:
460 ValueError: If the universe domain is an empty string.
461 """
462 universe_domain = ReportErrorsServiceClient._DEFAULT_UNIVERSE
463 if client_universe_domain is not None:
464 universe_domain = client_universe_domain
465 elif universe_domain_env is not None:
466 universe_domain = universe_domain_env
467 if len(universe_domain.strip()) == 0:
468 raise ValueError("Universe Domain cannot be an empty string.")
469 return universe_domain
470
471 def _validate_universe_domain(self):
472 """Validates client's and credentials' universe domains are consistent.
473
474 Returns:
475 bool: True iff the configured universe domain is valid.
476
477 Raises:
478 ValueError: If the configured universe domain is not valid.
479 """
480
481 # NOTE (b/349488459): universe validation is disabled until further notice.
482 return True
483
484 def _add_cred_info_for_auth_errors(
485 self, error: core_exceptions.GoogleAPICallError
486 ) -> None:
487 """Adds credential info string to error details for 401/403/404 errors.
488
489 Args:
490 error (google.api_core.exceptions.GoogleAPICallError): The error to add the cred info.
491 """
492 if error.code not in [
493 HTTPStatus.UNAUTHORIZED,
494 HTTPStatus.FORBIDDEN,
495 HTTPStatus.NOT_FOUND,
496 ]:
497 return
498
499 cred = self._transport._credentials
500
501 # get_cred_info is only available in google-auth>=2.35.0
502 if not hasattr(cred, "get_cred_info"):
503 return
504
505 # ignore the type check since pypy test fails when get_cred_info
506 # is not available
507 cred_info = cred.get_cred_info() # type: ignore
508 if cred_info and hasattr(error._details, "append"):
509 error._details.append(json.dumps(cred_info))
510
511 @property
512 def api_endpoint(self):
513 """Return the API endpoint used by the client instance.
514
515 Returns:
516 str: The API endpoint used by the client instance.
517 """
518 return self._api_endpoint
519
520 @property
521 def universe_domain(self) -> str:
522 """Return the universe domain used by the client instance.
523
524 Returns:
525 str: The universe domain used by the client instance.
526 """
527 return self._universe_domain
528
529 def __init__(
530 self,
531 *,
532 credentials: Optional[ga_credentials.Credentials] = None,
533 transport: Optional[
534 Union[
535 str,
536 ReportErrorsServiceTransport,
537 Callable[..., ReportErrorsServiceTransport],
538 ]
539 ] = None,
540 client_options: Optional[Union[client_options_lib.ClientOptions, dict]] = None,
541 client_info: gapic_v1.client_info.ClientInfo = DEFAULT_CLIENT_INFO,
542 ) -> None:
543 """Instantiates the report errors service client.
544
545 Args:
546 credentials (Optional[google.auth.credentials.Credentials]): The
547 authorization credentials to attach to requests. These
548 credentials identify the application to the service; if none
549 are specified, the client will attempt to ascertain the
550 credentials from the environment.
551 transport (Optional[Union[str,ReportErrorsServiceTransport,Callable[..., ReportErrorsServiceTransport]]]):
552 The transport to use, or a Callable that constructs and returns a new transport.
553 If a Callable is given, it will be called with the same set of initialization
554 arguments as used in the ReportErrorsServiceTransport constructor.
555 If set to None, a transport is chosen automatically.
556 client_options (Optional[Union[google.api_core.client_options.ClientOptions, dict]]):
557 Custom options for the client.
558
559 1. The ``api_endpoint`` property can be used to override the
560 default endpoint provided by the client when ``transport`` is
561 not explicitly provided. Only if this property is not set and
562 ``transport`` was not explicitly provided, the endpoint is
563 determined by the GOOGLE_API_USE_MTLS_ENDPOINT environment
564 variable, which have one of the following values:
565 "always" (always use the default mTLS endpoint), "never" (always
566 use the default regular endpoint) and "auto" (auto-switch to the
567 default mTLS endpoint if client certificate is present; this is
568 the default value).
569
570 2. If the GOOGLE_API_USE_CLIENT_CERTIFICATE environment variable
571 is "true", then the ``client_cert_source`` property can be used
572 to provide a client certificate for mTLS transport. If
573 not provided, the default SSL client certificate will be used if
574 present. If GOOGLE_API_USE_CLIENT_CERTIFICATE is "false" or not
575 set, no client certificate will be used.
576
577 3. The ``universe_domain`` property can be used to override the
578 default "googleapis.com" universe. Note that the ``api_endpoint``
579 property still takes precedence; and ``universe_domain`` is
580 currently not supported for mTLS.
581
582 client_info (google.api_core.gapic_v1.client_info.ClientInfo):
583 The client info used to send a user-agent string along with
584 API requests. If ``None``, then default info will be used.
585 Generally, you only need to set this if you're developing
586 your own client library.
587
588 Raises:
589 google.auth.exceptions.MutualTLSChannelError: If mutual TLS transport
590 creation failed for any reason.
591 """
592 self._client_options = client_options
593 if isinstance(self._client_options, dict):
594 self._client_options = client_options_lib.from_dict(self._client_options)
595 if self._client_options is None:
596 self._client_options = client_options_lib.ClientOptions()
597 self._client_options = cast(
598 client_options_lib.ClientOptions, self._client_options
599 )
600
601 universe_domain_opt = getattr(self._client_options, "universe_domain", None)
602
603 (
604 self._use_client_cert,
605 self._use_mtls_endpoint,
606 self._universe_domain_env,
607 ) = ReportErrorsServiceClient._read_environment_variables()
608 self._client_cert_source = ReportErrorsServiceClient._get_client_cert_source(
609 self._client_options.client_cert_source, self._use_client_cert
610 )
611 self._universe_domain = ReportErrorsServiceClient._get_universe_domain(
612 universe_domain_opt, self._universe_domain_env
613 )
614 self._api_endpoint = None # updated below, depending on `transport`
615
616 # Initialize the universe domain validation.
617 self._is_universe_domain_valid = False
618
619 if CLIENT_LOGGING_SUPPORTED: # pragma: NO COVER
620 # Setup logging.
621 client_logging.initialize_logging()
622
623 api_key_value = getattr(self._client_options, "api_key", None)
624 if api_key_value and credentials:
625 raise ValueError(
626 "client_options.api_key and credentials are mutually exclusive"
627 )
628
629 # Save or instantiate the transport.
630 # Ordinarily, we provide the transport, but allowing a custom transport
631 # instance provides an extensibility point for unusual situations.
632 transport_provided = isinstance(transport, ReportErrorsServiceTransport)
633 if transport_provided:
634 # transport is a ReportErrorsServiceTransport instance.
635 if credentials or self._client_options.credentials_file or api_key_value:
636 raise ValueError(
637 "When providing a transport instance, "
638 "provide its credentials directly."
639 )
640 if self._client_options.scopes:
641 raise ValueError(
642 "When providing a transport instance, provide its scopes "
643 "directly."
644 )
645 self._transport = cast(ReportErrorsServiceTransport, transport)
646 self._api_endpoint = self._transport.host
647
648 self._api_endpoint = (
649 self._api_endpoint
650 or ReportErrorsServiceClient._get_api_endpoint(
651 self._client_options.api_endpoint,
652 self._client_cert_source,
653 self._universe_domain,
654 self._use_mtls_endpoint,
655 )
656 )
657
658 if not transport_provided:
659 import google.auth._default # type: ignore
660
661 if api_key_value and hasattr(
662 google.auth._default, "get_api_key_credentials"
663 ):
664 credentials = google.auth._default.get_api_key_credentials(
665 api_key_value
666 )
667
668 transport_init: Union[
669 Type[ReportErrorsServiceTransport],
670 Callable[..., ReportErrorsServiceTransport],
671 ] = (
672 ReportErrorsServiceClient.get_transport_class(transport)
673 if isinstance(transport, str) or transport is None
674 else cast(Callable[..., ReportErrorsServiceTransport], transport)
675 )
676 # initialize with the provided callable or the passed in class
677 self._transport = transport_init(
678 credentials=credentials,
679 credentials_file=self._client_options.credentials_file,
680 host=self._api_endpoint,
681 scopes=self._client_options.scopes,
682 client_cert_source_for_mtls=self._client_cert_source,
683 quota_project_id=self._client_options.quota_project_id,
684 client_info=client_info,
685 always_use_jwt_access=True,
686 api_audience=self._client_options.api_audience,
687 )
688
689 if "async" not in str(self._transport):
690 if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor(
691 std_logging.DEBUG
692 ): # pragma: NO COVER
693 _LOGGER.debug(
694 "Created client `google.devtools.clouderrorreporting_v1beta1.ReportErrorsServiceClient`.",
695 extra={
696 "serviceName": "google.devtools.clouderrorreporting.v1beta1.ReportErrorsService",
697 "universeDomain": getattr(
698 self._transport._credentials, "universe_domain", ""
699 ),
700 "credentialsType": f"{type(self._transport._credentials).__module__}.{type(self._transport._credentials).__qualname__}",
701 "credentialsInfo": getattr(
702 self.transport._credentials, "get_cred_info", lambda: None
703 )(),
704 }
705 if hasattr(self._transport, "_credentials")
706 else {
707 "serviceName": "google.devtools.clouderrorreporting.v1beta1.ReportErrorsService",
708 "credentialsType": None,
709 },
710 )
711
712 def report_error_event(
713 self,
714 request: Optional[
715 Union[report_errors_service.ReportErrorEventRequest, dict]
716 ] = None,
717 *,
718 project_name: Optional[str] = None,
719 event: Optional[report_errors_service.ReportedErrorEvent] = None,
720 retry: OptionalRetry = gapic_v1.method.DEFAULT,
721 timeout: Union[float, object] = gapic_v1.method.DEFAULT,
722 metadata: Sequence[Tuple[str, Union[str, bytes]]] = (),
723 ) -> report_errors_service.ReportErrorEventResponse:
724 r"""Report an individual error event and record the event to a log.
725
726 This endpoint accepts **either** an OAuth token, **or** an `API
727 key <https://support.google.com/cloud/answer/6158862>`__ for
728 authentication. To use an API key, append it to the URL as the
729 value of a ``key`` parameter. For example:
730
731 ``POST https://clouderrorreporting.googleapis.com/v1beta1/{projectName}/events:report?key=123ABC456``
732
733 **Note:** [Error Reporting]
734 (https://cloud.google.com/error-reporting) is a service built on
735 Cloud Logging and can analyze log entries when all of the
736 following are true:
737
738 - Customer-managed encryption keys (CMEK) are disabled on the
739 log bucket.
740 - The log bucket satisfies one of the following:
741
742 - The log bucket is stored in the same project where the logs
743 originated.
744 - The logs were routed to a project, and then that project
745 stored those logs in a log bucket that it owns.
746
747 .. code-block:: python
748
749 # This snippet has been automatically generated and should be regarded as a
750 # code template only.
751 # It will require modifications to work:
752 # - It may require correct/in-range values for request initialization.
753 # - It may require specifying regional endpoints when creating the service
754 # client as shown in:
755 # https://googleapis.dev/python/google-api-core/latest/client_options.html
756 from google.cloud import errorreporting_v1beta1
757
758 def sample_report_error_event():
759 # Create a client
760 client = errorreporting_v1beta1.ReportErrorsServiceClient()
761
762 # Initialize request argument(s)
763 event = errorreporting_v1beta1.ReportedErrorEvent()
764 event.message = "message_value"
765
766 request = errorreporting_v1beta1.ReportErrorEventRequest(
767 project_name="project_name_value",
768 event=event,
769 )
770
771 # Make the request
772 response = client.report_error_event(request=request)
773
774 # Handle the response
775 print(response)
776
777 Args:
778 request (Union[google.cloud.errorreporting_v1beta1.types.ReportErrorEventRequest, dict]):
779 The request object. A request for reporting an individual
780 error event.
781 project_name (str):
782 Required. The resource name of the Google Cloud Platform
783 project. Written as ``projects/{projectId}``, where
784 ``{projectId}`` is the `Google Cloud Platform project
785 ID <https://support.google.com/cloud/answer/6158840>`__.
786
787 Example: // ``projects/my-project-123``.
788
789 This corresponds to the ``project_name`` field
790 on the ``request`` instance; if ``request`` is provided, this
791 should not be set.
792 event (google.cloud.errorreporting_v1beta1.types.ReportedErrorEvent):
793 Required. The error event to be
794 reported.
795
796 This corresponds to the ``event`` field
797 on the ``request`` instance; if ``request`` is provided, this
798 should not be set.
799 retry (google.api_core.retry.Retry): Designation of what errors, if any,
800 should be retried.
801 timeout (float): The timeout for this request.
802 metadata (Sequence[Tuple[str, Union[str, bytes]]]): Key/value pairs which should be
803 sent along with the request as metadata. Normally, each value must be of type `str`,
804 but for metadata keys ending with the suffix `-bin`, the corresponding values must
805 be of type `bytes`.
806
807 Returns:
808 google.cloud.errorreporting_v1beta1.types.ReportErrorEventResponse:
809 Response for reporting an individual
810 error event. Data may be added to this
811 message in the future.
812
813 """
814 # Create or coerce a protobuf request object.
815 # - Quick check: If we got a request object, we should *not* have
816 # gotten any keyword arguments that map to the request.
817 flattened_params = [project_name, event]
818 has_flattened_params = (
819 len([param for param in flattened_params if param is not None]) > 0
820 )
821 if request is not None and has_flattened_params:
822 raise ValueError(
823 "If the `request` argument is set, then none of "
824 "the individual field arguments should be set."
825 )
826
827 # - Use the request object if provided (there's no risk of modifying the input as
828 # there are no flattened fields), or create one.
829 if not isinstance(request, report_errors_service.ReportErrorEventRequest):
830 request = report_errors_service.ReportErrorEventRequest(request)
831 # If we have keyword arguments corresponding to fields on the
832 # request, apply these.
833 if project_name is not None:
834 request.project_name = project_name
835 if event is not None:
836 request.event = event
837
838 # Wrap the RPC method; this adds retry and timeout information,
839 # and friendly error handling.
840 rpc = self._transport._wrapped_methods[self._transport.report_error_event]
841
842 # Certain fields should be provided within the metadata header;
843 # add these here.
844 metadata = tuple(metadata) + (
845 gapic_v1.routing_header.to_grpc_metadata(
846 (("project_name", request.project_name),)
847 ),
848 )
849
850 # Validate the universe domain.
851 self._validate_universe_domain()
852
853 # Send the request.
854 response = rpc(
855 request,
856 retry=retry,
857 timeout=timeout,
858 metadata=metadata,
859 )
860
861 # Done; return the response.
862 return response
863
864 def __enter__(self) -> "ReportErrorsServiceClient":
865 return self
866
867 def __exit__(self, type, value, traceback):
868 """Releases underlying transport's resources.
869
870 .. warning::
871 ONLY use as a context manager if the transport is NOT shared
872 with other clients! Exiting the with block will CLOSE the transport
873 and may cause errors in other clients!
874 """
875 self.transport.close()
876
877
878DEFAULT_CLIENT_INFO = gapic_v1.client_info.ClientInfo(
879 gapic_version=package_version.__version__
880)
881
882if hasattr(DEFAULT_CLIENT_INFO, "protobuf_runtime_version"): # pragma: NO COVER
883 DEFAULT_CLIENT_INFO.protobuf_runtime_version = google.protobuf.__version__
884
885__all__ = ("ReportErrorsServiceClient",)