Skip to content

Commit b6b354f

Browse files
committed
Add partial documentation; clarify test base logger
1 parent 69bbd05 commit b6b354f

File tree

2 files changed

+82
-34
lines changed

2 files changed

+82
-34
lines changed

google/api_core/client_logging.py

Lines changed: 53 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@
77
_LOGGING_INITIALIZED = False
88
_BASE_LOGGER_NAME = "google"
99

10+
# Fields to be included in the StructuredLogFormatter.
11+
#
1012
# TODO(https://github.com/googleapis/python-api-core/issues/761): Update this list to support additional logging fields.
1113
_recognized_logging_fields = [
1214
"httpRequest",
@@ -15,15 +17,36 @@
1517
] # Additional fields to be Logged.
1618

1719

18-
# TODO(https://github.com/googleapis/python-api-core/issues/763): Add documentation.
20+
# TODO(https://github.com/googleapis/python-api-core/issues/763): Expand documentation.
1921
def logger_configured(logger):
22+
"""Determines whether `logger` has non-default configuration
23+
24+
Args:
25+
logger: The logger to check.
26+
27+
Returns:
28+
bool: Whether the logger has any non-default configuration.
29+
"""
2030
return (
2131
logger.handlers != [] or logger.level != logging.NOTSET or not logger.propagate
2232
)
2333

2434

25-
# TODO(https://github.com/googleapis/python-api-core/issues/763): Add documentation.
35+
# TODO(https://github.com/googleapis/python-api-core/issues/763): Expand documentation.
2636
def initialize_logging():
37+
"""Initializes "google" loggers, partly based on the environment variable
38+
39+
Initializes the "google" logger and any loggers (at the "google"
40+
level or lower) specified by the environment variable
41+
GOOGLE_SDK_PYTHON_LOGGING_SCOPE, as long as none of these loggers
42+
were previously configured. If any such loggers (including the
43+
"google" logger) are initialized, they are set to NOT propagate
44+
log events up to their parent loggers.
45+
46+
This initialization is executed only once, and hence the
47+
environment variable is only processed the first time this
48+
function is called.
49+
"""
2750
global _LOGGING_INITIALIZED
2851
if _LOGGING_INITIALIZED:
2952
return
@@ -32,8 +55,18 @@ def initialize_logging():
3255
_LOGGING_INITIALIZED = True
3356

3457

35-
# TODO(https://github.com/googleapis/python-api-core/issues/763): Add documentation.
58+
# TODO(https://github.com/googleapis/python-api-core/issues/763): Expand documentation.
3659
def parse_logging_scopes(scopes: Optional[str] = None) -> List[str]:
60+
"""Returns a list of logger names.
61+
62+
Splits the single string of comma-separated logger names into a list of individual logger name strings.
63+
64+
Args:
65+
scopes: The name of a single logger. (In the future, this will be a comma-separated list of multiple loggers.)
66+
67+
Returns:
68+
A list of all the logger names in scopes.
69+
"""
3770
if not scopes:
3871
return []
3972
# TODO(https://github.com/googleapis/python-api-core/issues/759): check if the namespace is a valid namespace.
@@ -43,8 +76,9 @@ def parse_logging_scopes(scopes: Optional[str] = None) -> List[str]:
4376
return namespaces
4477

4578

46-
# TODO(https://github.com/googleapis/python-api-core/issues/763): Add documentation.
79+
# TODO(https://github.com/googleapis/python-api-core/issues/763): Expand documentation.
4780
def configure_defaults(logger):
81+
"""Configures `logger` to emit structured info to stdout."""
4882
if not logger_configured(logger):
4983
console_handler = logging.StreamHandler()
5084
logger.setLevel("DEBUG")
@@ -54,8 +88,22 @@ def configure_defaults(logger):
5488
logger.addHandler(console_handler)
5589

5690

57-
# TODO(https://github.com/googleapis/python-api-core/issues/763): Add documentation.
91+
# TODO(https://github.com/googleapis/python-api-core/issues/763): Expand documentation.
5892
def setup_logging(scopes=""):
93+
"""Sets up logging for the specified `scopes`.
94+
95+
If the loggers specified in `scopes` have not been previously
96+
configured, this will configure them to emit structured log
97+
entries to stdout, and to not propagate their log events to their
98+
parent loggers. Additionally, if the "google" logger (whether it
99+
was specified in `scopes` or not) was not previously configured,
100+
it will also configure it to not propagate log events to the root
101+
logger.
102+
103+
Args:
104+
scopes: The name of a single logger. (In the future, this will be a comma-separated list of multiple loggers.)
105+
106+
"""
59107

60108
# only returns valid logger scopes (namespaces)
61109
# this list has at most one element.

tests/unit/test_client_logging.py

Lines changed: 29 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -17,62 +17,62 @@ def reset_logger(scope):
1717

1818

1919
def test_setup_logging_w_no_scopes():
20-
with mock.patch("google.api_core.client_logging._BASE_LOGGER_NAME", "foo"):
20+
with mock.patch("google.api_core.client_logging._BASE_LOGGER_NAME", "foogle"):
2121
setup_logging()
22-
base_logger = logging.getLogger("foo")
22+
base_logger = logging.getLogger("foogle")
2323
assert base_logger.handlers == []
2424
assert not base_logger.propagate
2525
assert base_logger.level == logging.NOTSET
2626

27-
reset_logger("foo")
27+
reset_logger("foogle")
2828

2929

3030
def test_setup_logging_w_base_scope():
31-
with mock.patch("google.api_core.client_logging._BASE_LOGGER_NAME", "foo"):
32-
setup_logging("foo")
33-
base_logger = logging.getLogger("foo")
31+
with mock.patch("google.api_core.client_logging._BASE_LOGGER_NAME", "foogle"):
32+
setup_logging("foogle")
33+
base_logger = logging.getLogger("foogle")
3434
assert isinstance(base_logger.handlers[0], logging.StreamHandler)
3535
assert not base_logger.propagate
3636
assert base_logger.level == logging.DEBUG
3737

38-
reset_logger("foo")
38+
reset_logger("foogle")
3939

4040

4141
def test_setup_logging_w_configured_scope():
42-
with mock.patch("google.api_core.client_logging._BASE_LOGGER_NAME", "foo"):
43-
base_logger = logging.getLogger("foo")
42+
with mock.patch("google.api_core.client_logging._BASE_LOGGER_NAME", "foogle"):
43+
base_logger = logging.getLogger("foogle")
4444
base_logger.propagate = False
45-
setup_logging("foo")
45+
setup_logging("foogle")
4646
assert base_logger.handlers == []
4747
assert not base_logger.propagate
4848
assert base_logger.level == logging.NOTSET
4949

50-
reset_logger("foo")
50+
reset_logger("foogle")
5151

5252

5353
def test_setup_logging_w_module_scope():
54-
with mock.patch("google.api_core.client_logging._BASE_LOGGER_NAME", "foo"):
55-
setup_logging("foo.bar")
54+
with mock.patch("google.api_core.client_logging._BASE_LOGGER_NAME", "foogle"):
55+
setup_logging("foogle.bar")
5656

57-
base_logger = logging.getLogger("foo")
57+
base_logger = logging.getLogger("foogle")
5858
assert base_logger.handlers == []
5959
assert not base_logger.propagate
6060
assert base_logger.level == logging.NOTSET
6161

62-
module_logger = logging.getLogger("foo.bar")
62+
module_logger = logging.getLogger("foogle.bar")
6363
assert isinstance(module_logger.handlers[0], logging.StreamHandler)
6464
assert not module_logger.propagate
6565
assert module_logger.level == logging.DEBUG
6666

67-
reset_logger("foo")
68-
reset_logger("foo.bar")
67+
reset_logger("foogle")
68+
reset_logger("foogle.bar")
6969

7070

7171
def test_setup_logging_w_incorrect_scope():
72-
with mock.patch("google.api_core.client_logging._BASE_LOGGER_NAME", "foo"):
72+
with mock.patch("google.api_core.client_logging._BASE_LOGGER_NAME", "foogle"):
7373
setup_logging("abc")
7474

75-
base_logger = logging.getLogger("foo")
75+
base_logger = logging.getLogger("foogle")
7676
assert base_logger.handlers == []
7777
assert not base_logger.propagate
7878
assert base_logger.level == logging.NOTSET
@@ -83,22 +83,22 @@ def test_setup_logging_w_incorrect_scope():
8383
assert not logger.propagate
8484
assert logger.level == logging.DEBUG
8585

86-
reset_logger("foo")
86+
reset_logger("foogle")
8787
reset_logger("abc")
8888

8989

9090
def test_initialize_logging():
9191

92-
with mock.patch("os.getenv", return_value="foo.bar"):
93-
with mock.patch("google.api_core.client_logging._BASE_LOGGER_NAME", "foo"):
92+
with mock.patch("os.getenv", return_value="foogle.bar"):
93+
with mock.patch("google.api_core.client_logging._BASE_LOGGER_NAME", "foogle"):
9494
initialize_logging()
9595

96-
base_logger = logging.getLogger("foo")
96+
base_logger = logging.getLogger("foogle")
9797
assert base_logger.handlers == []
9898
assert not base_logger.propagate
9999
assert base_logger.level == logging.NOTSET
100100

101-
module_logger = logging.getLogger("foo.bar")
101+
module_logger = logging.getLogger("foogle.bar")
102102
assert isinstance(module_logger.handlers[0], logging.StreamHandler)
103103
assert not module_logger.propagate
104104
assert module_logger.level == logging.DEBUG
@@ -112,17 +112,17 @@ def test_initialize_logging():
112112
assert base_logger.propagate
113113
assert module_logger.propagate
114114

115-
reset_logger("foo")
116-
reset_logger("foo.bar")
115+
reset_logger("foogle")
116+
reset_logger("foogle.bar")
117117

118118

119119
def test_structured_log_formatter():
120120
# TODO(https://github.com/googleapis/python-api-core/issues/761): Test additional fields when implemented.
121121
record = logging.LogRecord(
122-
name="foo",
122+
name="Appelation",
123123
level=logging.DEBUG,
124124
msg="This is a test message.",
125-
pathname="foo/bar",
125+
pathname="some/path",
126126
lineno=25,
127127
args=None,
128128
exc_info=None,
@@ -134,7 +134,7 @@ def test_structured_log_formatter():
134134
formatted_msg = StructuredLogFormatter().format(record)
135135
parsed_msg = json.loads(formatted_msg)
136136

137-
assert parsed_msg["name"] == "foo"
137+
assert parsed_msg["name"] == "Appelation"
138138
assert parsed_msg["severity"] == "DEBUG"
139139
assert parsed_msg["message"] == "This is a test message."
140140
assert parsed_msg["rpcName"] == "bar"

0 commit comments

Comments
 (0)