Skip to content

Commit 37e6c8e

Browse files
fix: no duplicate logs on GCF or GAE (#209)
1 parent 1d8bb42 commit 37e6c8e

File tree

5 files changed

+59
-2
lines changed

5 files changed

+59
-2
lines changed

google/cloud/logging_v2/client.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@
5252

5353
_GAE_RESOURCE_TYPE = "gae_app"
5454
_GKE_RESOURCE_TYPE = "k8s_container"
55+
_GCF_RESOURCE_TYPE = "cloud_function"
5556

5657

5758
class Client(ClientWithProject):

google/cloud/logging_v2/handlers/_monitored_resources.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -163,7 +163,7 @@ def _create_global_resource(project):
163163
return Resource(type="global", labels={"project_id": project})
164164

165165

166-
def detect_resource(project):
166+
def detect_resource(project=""):
167167
"""Return the default monitored resource based on the local environment.
168168
Args:
169169
project (str): The project ID to pass on to the resource

google/cloud/logging_v2/handlers/handlers.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,8 @@
2323

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

26+
_CLEAR_HANDLER_RESOURCE_TYPES = ("gae_app", "cloud_function")
27+
2628

2729
class CloudLoggingHandler(logging.StreamHandler):
2830
"""Handler that directly makes Cloud Logging API calls.
@@ -160,6 +162,11 @@ def setup_logging(
160162
"""
161163
all_excluded_loggers = set(excluded_loggers + EXCLUDED_LOGGER_DEFAULTS)
162164
logger = logging.getLogger()
165+
166+
# remove built-in handlers on App Engine or Cloud Functions environments
167+
if detect_resource().type in _CLEAR_HANDLER_RESOURCE_TYPES:
168+
logger.handlers.clear()
169+
163170
logger.setLevel(log_level)
164171
logger.addHandler(handler)
165172
for logger_name in all_excluded_loggers:

tests/unit/handlers/test_handlers.py

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,14 @@
1414

1515
import logging
1616
import unittest
17+
from unittest.mock import patch
1718
import mock
1819

20+
from google.cloud.logging_v2.handlers._monitored_resources import (
21+
_FUNCTION_ENV_VARS,
22+
_GAE_ENV_VARS,
23+
)
24+
1925

2026
class TestCloudLoggingHandler(unittest.TestCase):
2127

@@ -165,6 +171,49 @@ def test_setup_logging_excludes(self):
165171
self.assertNotIn(handler, excluded_logger.handlers)
166172
self.assertFalse(excluded_logger.propagate)
167173

174+
@patch.dict("os.environ", {envar: "1" for envar in _FUNCTION_ENV_VARS})
175+
def test_remove_handlers_gcf(self):
176+
logger = logging.getLogger()
177+
# add fake handler
178+
added_handler = logging.StreamHandler()
179+
logger.addHandler(added_handler)
180+
181+
handler = _Handler(logging.INFO)
182+
self._call_fut(handler)
183+
self.assertNotIn(added_handler, logger.handlers)
184+
# handler should be removed from logger
185+
self.assertEqual(len(logger.handlers), 1)
186+
187+
@patch.dict("os.environ", {envar: "1" for envar in _GAE_ENV_VARS})
188+
def test_remove_handlers_gae(self):
189+
logger = logging.getLogger()
190+
# add fake handler
191+
added_handler = logging.StreamHandler()
192+
logger.addHandler(added_handler)
193+
194+
handler = _Handler(logging.INFO)
195+
self._call_fut(handler)
196+
self.assertNotIn(added_handler, logger.handlers)
197+
# handler should be removed from logger
198+
self.assertEqual(len(logger.handlers), 1)
199+
200+
def test_keep_handlers_others(self):
201+
# mock non-cloud environment
202+
patch = mock.patch(
203+
"google.cloud.logging_v2.handlers._monitored_resources.retrieve_metadata_server",
204+
return_value=None,
205+
)
206+
with patch:
207+
# add fake handler
208+
added_handler = logging.StreamHandler()
209+
logger = logging.getLogger()
210+
logger.addHandler(added_handler)
211+
212+
handler = _Handler(logging.INFO)
213+
self._call_fut(handler)
214+
# added handler should remain in logger
215+
self.assertIn(added_handler, logger.handlers)
216+
168217
def setUp(self):
169218
self._handlers_cache = logging.getLogger().handlers[:]
170219

0 commit comments

Comments
 (0)