Skip to content

Commit

Permalink
address PR feedback
Browse files Browse the repository at this point in the history
  • Loading branch information
ohmayr committed Nov 25, 2024
1 parent 48b9ed9 commit ef66ac5
Show file tree
Hide file tree
Showing 2 changed files with 66 additions and 21 deletions.
29 changes: 16 additions & 13 deletions google/api_core/client_logging.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,16 +4,16 @@
import os

_LOGGING_INITIALIZED = False

# TODO(<add-link>): Update Request / Response messages.
_BASE_LOGGER_NAME = "google"
# TODO(https://github.com/googleapis/python-api-core/issues/760): Update Request / Response messages.
REQUEST_MESSAGE = "Sending request ..."
RESPONSE_MESSAGE = "Receiving response ..."

# TODO(<add-link>): Update this list to support additional logging fields
# TODO(https://github.com/googleapis/python-api-core/issues/761): Update this list to support additional logging fields
_recognized_logging_fields = ["httpRequest", "rpcName", "serviceName"] # Additional fields to be Logged.

def logger_configured(logger):
return logger.hasHandlers() or logger.level != logging.NOTSET or logger.propagate == False
return logger.handlers != [] or logger.level != logging.NOTSET or logger.propagate == False

def initialize_logging():
global _LOGGING_INITIALIZED
Expand All @@ -26,8 +26,9 @@ def initialize_logging():
def parse_logging_scopes(scopes):
if not scopes:
return []
# TODO(<add-link>): check if the namespace is a valid namespace.
# TODO(<add-link>): parse a list of namespaces. Current flow expects a single string for now.
# TODO(https://github.com/googleapis/python-api-core/issues/759): check if the namespace is a valid namespace.
# TODO(b/380481951): Support logging multiple scopes.
# TODO(b/380483756): Raise or log a warning for an invalid scope.
namespaces = [scopes]
return namespaces

Expand All @@ -40,23 +41,25 @@ def configure_defaults(logger):
console_handler.setFormatter(formatter)
logger.addHandler(console_handler)

def setup_logging(scopes):
# disable log propagation at base logger level to the root logger only if a base logger is not already configured via code changes.
base_logger = logging.getLogger("google")
if not logger_configured(base_logger):
base_logger.propagate = False
def setup_logging(scopes=[]):

# only returns valid logger scopes (namespaces)
# this list has at most one element.
loggers = parse_logging_scopes(scopes)
logger_names = parse_logging_scopes(scopes)

for namespace in loggers:
for namespace in logger_names:
# This will either create a module level logger or get the reference of the base logger instantiated above.
logger = logging.getLogger(namespace)

# Configure default settings.
configure_defaults(logger)

# disable log propagation at base logger level to the root logger only if a base logger is not already configured via code changes.
# Maybe we do this at the end?
base_logger = logging.getLogger(_BASE_LOGGER_NAME)
if not logger_configured(base_logger):
base_logger.propagate = False

class StructuredLogFormatter(logging.Formatter):
def format(self, record):
log_obj = {
Expand Down
58 changes: 50 additions & 8 deletions tests/unit/test_client_logging.py
Original file line number Diff line number Diff line change
@@ -1,20 +1,62 @@
import logging
import pytest

from google.api_core.client_logging import setup_logging
# Test expected behaviour for warnings, propagation, handler + formatter.

def reset_logger(scope):
logger = logging.getLogger(scope)
logger.handlers = []
logger.setLevel(logging.NOTSET)
logger.propagate = True

def test_setup_logging_w_no_scopes():
# TODO(in-progress):
pass
setup_logging()
base_logger = logging.getLogger("google")
assert base_logger.handlers == []
assert base_logger.propagate == False
assert base_logger.level == logging.NOTSET

reset_logger("google")


def test_setup_logging_w_base_scope():
# TODO(in-progress):
pass
setup_logging("google")
base_logger = logging.getLogger("google")
assert isinstance(base_logger.handlers[0], logging.StreamHandler)
assert base_logger.propagate == False
assert base_logger.level == logging.DEBUG

reset_logger("google")

def test_setup_logging_w_module_scope():
# TODO(in-progress):
pass
setup_logging("google.foo")

base_logger = logging.getLogger("google")
assert base_logger.handlers == []
assert base_logger.propagate == False
assert base_logger.level == logging.NOTSET

module_logger = logging.getLogger("google.foo")
assert isinstance(module_logger.handlers[0], logging.StreamHandler)
assert module_logger.propagate == False
assert module_logger.level == logging.DEBUG


reset_logger("google")

def test_setup_logging_w_incorrect_scope():
# TODO(in-progress):
pass
setup_logging("foo")

base_logger = logging.getLogger("google")
assert base_logger.handlers == []
assert base_logger.propagate == False
assert base_logger.level == logging.NOTSET

# TODO: update test once we add logic to ignore an incorrect scope.
logger = logging.getLogger("foo")
assert isinstance(logger.handlers[0], logging.StreamHandler)
assert logger.propagate == False
assert logger.level == logging.DEBUG

reset_logger("google")

0 comments on commit ef66ac5

Please sign in to comment.