Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
fix: no duplicate logs on GCF or GAE (#209)
  • Loading branch information
daniel-sanche committed Mar 15, 2021
1 parent 1d8bb42 commit 37e6c8e
Show file tree
Hide file tree
Showing 5 changed files with 59 additions and 2 deletions.
1 change: 1 addition & 0 deletions google/cloud/logging_v2/client.py
Expand Up @@ -52,6 +52,7 @@

_GAE_RESOURCE_TYPE = "gae_app"
_GKE_RESOURCE_TYPE = "k8s_container"
_GCF_RESOURCE_TYPE = "cloud_function"


class Client(ClientWithProject):
Expand Down
2 changes: 1 addition & 1 deletion google/cloud/logging_v2/handlers/_monitored_resources.py
Expand Up @@ -163,7 +163,7 @@ def _create_global_resource(project):
return Resource(type="global", labels={"project_id": project})


def detect_resource(project):
def detect_resource(project=""):
"""Return the default monitored resource based on the local environment.
Args:
project (str): The project ID to pass on to the resource
Expand Down
7 changes: 7 additions & 0 deletions google/cloud/logging_v2/handlers/handlers.py
Expand Up @@ -23,6 +23,8 @@

EXCLUDED_LOGGER_DEFAULTS = ("google.cloud", "google.auth", "google_auth_httplib2")

_CLEAR_HANDLER_RESOURCE_TYPES = ("gae_app", "cloud_function")


class CloudLoggingHandler(logging.StreamHandler):
"""Handler that directly makes Cloud Logging API calls.
Expand Down Expand Up @@ -160,6 +162,11 @@ def setup_logging(
"""
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:
Expand Down
49 changes: 49 additions & 0 deletions tests/unit/handlers/test_handlers.py
Expand Up @@ -14,8 +14,14 @@

import logging
import unittest
from unittest.mock import patch
import mock

from google.cloud.logging_v2.handlers._monitored_resources import (
_FUNCTION_ENV_VARS,
_GAE_ENV_VARS,
)


class TestCloudLoggingHandler(unittest.TestCase):

Expand Down Expand Up @@ -165,6 +171,49 @@ def test_setup_logging_excludes(self):
self.assertNotIn(handler, excluded_logger.handlers)
self.assertFalse(excluded_logger.propagate)

@patch.dict("os.environ", {envar: "1" for envar in _FUNCTION_ENV_VARS})
def test_remove_handlers_gcf(self):
logger = logging.getLogger()
# add fake handler
added_handler = logging.StreamHandler()
logger.addHandler(added_handler)

handler = _Handler(logging.INFO)
self._call_fut(handler)
self.assertNotIn(added_handler, logger.handlers)
# handler should be removed from logger
self.assertEqual(len(logger.handlers), 1)

@patch.dict("os.environ", {envar: "1" for envar in _GAE_ENV_VARS})
def test_remove_handlers_gae(self):
logger = logging.getLogger()
# add fake handler
added_handler = logging.StreamHandler()
logger.addHandler(added_handler)

handler = _Handler(logging.INFO)
self._call_fut(handler)
self.assertNotIn(added_handler, logger.handlers)
# handler should be removed from logger
self.assertEqual(len(logger.handlers), 1)

def test_keep_handlers_others(self):
# mock non-cloud environment
patch = mock.patch(
"google.cloud.logging_v2.handlers._monitored_resources.retrieve_metadata_server",
return_value=None,
)
with patch:
# add fake handler
added_handler = logging.StreamHandler()
logger = logging.getLogger()
logger.addHandler(added_handler)

handler = _Handler(logging.INFO)
self._call_fut(handler)
# added handler should remain in logger
self.assertIn(added_handler, logger.handlers)

def setUp(self):
self._handlers_cache = logging.getLogger().handlers[:]

Expand Down

0 comments on commit 37e6c8e

Please sign in to comment.