diff --git a/google/cloud/logging_v2/client.py b/google/cloud/logging_v2/client.py index 94c1e6ca7..9a4e52023 100644 --- a/google/cloud/logging_v2/client.py +++ b/google/cloud/logging_v2/client.py @@ -32,8 +32,14 @@ from google.cloud.logging_v2.handlers import setup_logging from google.cloud.logging_v2.handlers.handlers import EXCLUDED_LOGGER_DEFAULTS from google.cloud.logging_v2.resource import Resource -from google.cloud.logging_v2.handlers._monitored_resources import detect_resource - +from google.cloud.logging_v2.handlers._monitored_resources import ( + detect_resource, + _GAE_RESOURCE_TYPE, + _GKE_RESOURCE_TYPE, + _GCF_RESOURCE_TYPE, + _RUN_RESOURCE_TYPE, + _CLOUD_RUN_JOB_RESOURCE_TYPE, +) from google.cloud.logging_v2.logger import Logger from google.cloud.logging_v2.metric import Metric @@ -56,11 +62,6 @@ _USE_GRPC = _HAVE_GRPC and not _DISABLE_GRPC -_GAE_RESOURCE_TYPE = "gae_app" -_GKE_RESOURCE_TYPE = "k8s_container" -_GCF_RESOURCE_TYPE = "cloud_function" -_RUN_RESOURCE_TYPE = "cloud_run_revision" - class Client(ClientWithProject): """Client to bundle configuration needed for API requests.""" @@ -376,18 +377,27 @@ def get_default_handler(self, **kw): """ monitored_resource = kw.pop("resource", detect_resource(self.project)) - if isinstance(monitored_resource, Resource): - if monitored_resource.type == _GAE_RESOURCE_TYPE: - return CloudLoggingHandler(self, resource=monitored_resource, **kw) - elif monitored_resource.type == _GKE_RESOURCE_TYPE: - return StructuredLogHandler(**kw, project_id=self.project) - elif monitored_resource.type == _GCF_RESOURCE_TYPE: + _structured_log_types = [ + _GAE_RESOURCE_TYPE, + _GKE_RESOURCE_TYPE, + _GCF_RESOURCE_TYPE, + _RUN_RESOURCE_TYPE, + _CLOUD_RUN_JOB_RESOURCE_TYPE, + ] + + if ( + isinstance(monitored_resource, Resource) + and monitored_resource.type in _structured_log_types + ): + if monitored_resource.type == _GCF_RESOURCE_TYPE: # __stdout__ stream required to support structured logging on Python 3.7 kw["stream"] = kw.get("stream", sys.__stdout__) - return StructuredLogHandler(**kw, project_id=self.project) - elif monitored_resource.type == _RUN_RESOURCE_TYPE: - return StructuredLogHandler(**kw, project_id=self.project) - return CloudLoggingHandler(self, resource=monitored_resource, **kw) + + handler = StructuredLogHandler(**kw, project_id=self.project) + else: + handler = CloudLoggingHandler(self, resource=monitored_resource, **kw) + + return handler def setup_logging( self, *, log_level=logging.INFO, excluded_loggers=EXCLUDED_LOGGER_DEFAULTS, **kw diff --git a/google/cloud/logging_v2/handlers/_monitored_resources.py b/google/cloud/logging_v2/handlers/_monitored_resources.py index 5240fe746..c15c42d7b 100644 --- a/google/cloud/logging_v2/handlers/_monitored_resources.py +++ b/google/cloud/logging_v2/handlers/_monitored_resources.py @@ -60,6 +60,9 @@ _GCE_INSTANCE_ID = "instance/id" """Attribute in metadata server for compute region and instance.""" +_GKE_RESOURCE_TYPE = "k8s_container" +"""Resource type for the GKE environment.""" + _GKE_CLUSTER_NAME = "instance/attributes/cluster-name" """Attribute in metadata server when in GKE environment.""" @@ -72,6 +75,12 @@ _GAE_RESOURCE_TYPE = "gae_app" """Resource type for App Engine environment.""" +_GCF_RESOURCE_TYPE = "cloud_function" +"""Resource type for Cloud Functions environment.""" + +_RUN_RESOURCE_TYPE = "cloud_run_revision" +"""Resource type for Cloud Run environment.""" + _CLOUD_RUN_JOB_RESOURCE_TYPE = "cloud_run_job" """Resource type for Cloud Run Jobs.""" diff --git a/google/cloud/logging_v2/handlers/handlers.py b/google/cloud/logging_v2/handlers/handlers.py index 06e131442..5b11bfe30 100644 --- a/google/cloud/logging_v2/handlers/handlers.py +++ b/google/cloud/logging_v2/handlers/handlers.py @@ -18,12 +18,19 @@ import json import logging -from google.cloud.logging_v2.handlers.transports import BackgroundThreadTransport +from typing import Optional, IO + +from google.cloud.logging_v2.handlers.transports import ( + BackgroundThreadTransport, + Transport, +) from google.cloud.logging_v2.handlers._monitored_resources import ( detect_resource, add_resource_labels, ) from google.cloud.logging_v2.handlers._helpers import get_request_data +from google.cloud.logging_v2.resource import Resource + DEFAULT_LOGGER_NAME = "python" @@ -149,11 +156,11 @@ def __init__( self, client, *, - name=DEFAULT_LOGGER_NAME, - transport=BackgroundThreadTransport, - resource=None, - labels=None, - stream=None, + name: str = DEFAULT_LOGGER_NAME, + transport: Transport = BackgroundThreadTransport, + resource: Resource = None, + labels: Optional[dict] = None, + stream: Optional[IO] = None, **kwargs, ): """ diff --git a/google/cloud/logging_v2/logger.py b/google/cloud/logging_v2/logger.py index 64130f02f..27553994b 100644 --- a/google/cloud/logging_v2/logger.py +++ b/google/cloud/logging_v2/logger.py @@ -29,6 +29,7 @@ from google.api_core.exceptions import InvalidArgument from google.rpc.error_details_pb2 import DebugInfo +import google.cloud.logging_v2 import google.protobuf.message _GLOBAL_RESOURCE = Resource(type="global", labels={}) diff --git a/tests/system/test_system.py b/tests/system/test_system.py index 801cab341..d4ec4da36 100644 --- a/tests/system/test_system.py +++ b/tests/system/test_system.py @@ -622,7 +622,7 @@ def test_handlers_w_extras(self): "trace_sampled": True, "http_request": expected_request, "source_location": expected_source, - "resource": Resource(type="cloudiot_device", labels={}), + "resource": Resource(type="global", labels={}), "labels": {"test-label": "manual"}, } cloud_logger.warning(LOG_MESSAGE, extra=extra) diff --git a/tests/unit/test_client.py b/tests/unit/test_client.py index 2d12a283e..4bfd984ff 100644 --- a/tests/unit/test_client.py +++ b/tests/unit/test_client.py @@ -766,7 +766,7 @@ def test_get_default_handler_app_engine(self): import os from google.cloud._testing import _Monkey from google.cloud.logging_v2.handlers._monitored_resources import _GAE_ENV_VARS - from google.cloud.logging.handlers import CloudLoggingHandler + from google.cloud.logging.handlers import StructuredLogHandler credentials = _make_credentials() client = self._make_one( @@ -778,9 +778,7 @@ def test_get_default_handler_app_engine(self): with _Monkey(os, environ=gae_env_vars): handler = client.get_default_handler() - handler.transport.worker.stop() - - self.assertIsInstance(handler, CloudLoggingHandler) + self.assertIsInstance(handler, StructuredLogHandler) def test_get_default_handler_container_engine(self): from google.cloud.logging.handlers import StructuredLogHandler @@ -800,6 +798,26 @@ def test_get_default_handler_container_engine(self): self.assertIsInstance(handler, StructuredLogHandler) + def test_get_default_handler_cloud_run_jobs(self): + import os + from google.cloud._testing import _Monkey + from google.cloud.logging_v2.handlers._monitored_resources import ( + _CLOUD_RUN_JOB_ENV_VARS, + ) + from google.cloud.logging.handlers import StructuredLogHandler + + credentials = _make_credentials() + client = self._make_one( + project=self.PROJECT, credentials=credentials, _use_grpc=False + ) + + cloud_run_job_env_vars = {var: "TRUE" for var in _CLOUD_RUN_JOB_ENV_VARS} + + with _Monkey(os, environ=cloud_run_job_env_vars): + handler = client.get_default_handler() + + self.assertIsInstance(handler, StructuredLogHandler) + def test_get_default_handler_general(self): import io from google.cloud.logging.handlers import CloudLoggingHandler