def get_default_handler(self, **kw): """Return the default logging handler based on the local environment. Args: kw (dict): keyword args passed to handler constructor Returns: logging.Handler: The default log handler based on the environment """ 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: # __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)
def test_detect_compute_engine(self): patch = mock.patch( "google.cloud.logging_v2.handlers._monitored_resources.retrieve_metadata_server", wraps=self._mock_gce_metadata, ) with patch: resource = detect_resource(self.PROJECT) self.assertIsInstance(resource, Resource) self.assertEqual(resource.type, "gce_instance")
def test_detection_unknown(self): patch = mock.patch( "google.cloud.logging_v2.handlers._monitored_resources.retrieve_metadata_server", return_value=None, ) with patch: resource = detect_resource(self.PROJECT) self.assertIsInstance(resource, Resource) self.assertEqual(resource.type, "global")
def test_detect_kubernetes(self): patch = mock.patch( "google.cloud.logging_v2.handlers._monitored_resources.retrieve_metadata_server", wraps=self._mock_k8s_metadata, ) with patch: resource = detect_resource(self.PROJECT) self.assertIsInstance(resource, Resource) self.assertEqual(resource.type, "k8s_container")
def setup_logging(handler, *, excluded_loggers=EXCLUDED_LOGGER_DEFAULTS, log_level=logging.INFO): """Attach a logging handler to the Python root logger Excludes loggers that this library itself uses to avoid infinite recursion. Example: .. code-block:: python import logging import google.cloud.logging from google.cloud.logging_v2.handlers import CloudLoggingHandler client = google.cloud.logging.Client() handler = CloudLoggingHandler(client) google.cloud.logging.handlers.setup_logging(handler) logging.getLogger().setLevel(logging.DEBUG) logging.error('bad news') # API call Args: handler (logging.handler): the handler to attach to the global handler excluded_loggers (Optional[Tuple[str]]): The loggers to not attach the handler to. This will always include the loggers in the path of the logging client itself. log_level (Optional[int]): Python logging log level. Defaults to :const:`logging.INFO`. """ all_excluded_loggers = set(excluded_loggers + EXCLUDED_LOGGER_DEFAULTS) logger = logging.getLogger() # remove built-in handlers on App Engine or Cloud Functions environments if detect_resource().type in _CLEAR_HANDLER_RESOURCE_TYPES: logger.handlers.clear() logger.setLevel(log_level) logger.addHandler(handler) for logger_name in all_excluded_loggers: # prevent excluded loggers from propagating logs to handler logger = logging.getLogger(logger_name) logger.propagate = False
def __init__( self, client, *, name=DEFAULT_LOGGER_NAME, transport=BackgroundThreadTransport, resource=None, labels=None, stream=None, ): """ Args: client (~logging_v2.client.Client): The authenticated Google Cloud Logging client for this handler to use. name (str): the name of the custom log in Cloud Logging. Defaults to 'python'. The name of the Python logger will be represented in the ``python_logger`` field. transport (~logging_v2.transports.Transport): Class for creating new transport objects. It should extend from the base :class:`.Transport` type and implement :meth`.Transport.send`. Defaults to :class:`.BackgroundThreadTransport`. The other option is :class:`.SyncTransport`. resource (~logging_v2.resource.Resource): Resource for this Handler. If not given, will be inferred from the environment. labels (Optional[dict]): Additional labels to attach to logs. stream (Optional[IO]): Stream to be used by the handler. """ super(CloudLoggingHandler, self).__init__(stream) if not resource: # infer the correct monitored resource from the local environment resource = detect_resource(client.project) self.name = name self.client = client self.transport = transport(client, name, resource=resource) self.project_id = client.project self.resource = resource self.labels = labels # add extra keys to log record log_filter = CloudLoggingFilter(project=self.project_id, default_labels=labels) self.addFilter(log_filter)
def get_default_handler(self, **kw): """Return the default logging handler based on the local environment. Args: kw (dict): keyword args passed to handler constructor Returns: logging.Handler: The default log handler based on the environment """ monitored_resource = kw.pop("resource", detect_resource(self.project)) if (isinstance(monitored_resource, Resource) and monitored_resource.type == _GAE_RESOURCE_TYPE): return AppEngineHandler(self, **kw) elif (isinstance(monitored_resource, Resource) and monitored_resource.type == _GKE_RESOURCE_TYPE): return ContainerEngineHandler(**kw) else: return CloudLoggingHandler(self, resource=monitored_resource, **kw)
def __init__(self, name, client, *, labels=None, resource=None): """ Args: name (str): The name of the logger. client (~logging_v2.client.Client): A client which holds credentials and project configuration for the logger (which requires a project). resource (Optional[~logging_v2.Resource]): a monitored resource object representing the resource the code was run on. If not given, will be inferred from the environment. labels (Optional[dict]): Mapping of default labels for entries written via this logger. """ if not resource: # infer the correct monitored resource from the local environment resource = detect_resource(client.project) self.name = name self._client = client self.labels = labels self.default_resource = resource
def get_default_handler(self, **kw): """Return the default logging handler based on the local environment. Args: kw (dict): keyword args passed to handler constructor Returns: logging.Handler: The default log handler based on the environment """ monitored_resource = kw.pop("resource", detect_resource(self.project)) if isinstance(monitored_resource, Resource): if monitored_resource.type == _GAE_RESOURCE_TYPE: return AppEngineHandler(self, **kw) elif monitored_resource.type == _GKE_RESOURCE_TYPE: return ContainerEngineHandler(**kw) elif (monitored_resource.type == _GCF_RESOURCE_TYPE and sys.version_info[0] == 3 and sys.version_info[1] >= 8): # Cloud Functions with runtimes > 3.8 supports structured logs on standard out # 3.7 should use the standard CloudLoggingHandler, which sends logs over the network. 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)
def test_detect_cloud_run(self): for env in _monitored_resources._CLOUD_RUN_ENV_VARS: os.environ[env] = "TRUE" resource = detect_resource(self.PROJECT) self.assertIsInstance(resource, Resource) self.assertEqual(resource.type, "cloud_run_revision")
def test_detect_legacy_functions(self): for env in _monitored_resources._LEGACY_FUNCTION_ENV_VARS: os.environ[env] = "TRUE" resource = detect_resource(self.PROJECT) self.assertIsInstance(resource, Resource) self.assertEqual(resource.type, "cloud_function")
def test_detect_appengine(self): for env in _monitored_resources._GAE_ENV_VARS: os.environ[env] = "TRUE" resource = detect_resource(self.PROJECT) self.assertIsInstance(resource, Resource) self.assertEqual(resource.type, "gae_app")