Skip to content

Commit f889439

Browse files
committed
Configure logger
Why these changes are being introduced: As a library that is installed and imported, it is important that logging is setup in a way that aligns with the calling application. How this addresses that need: * Function configure_logger returns a logger instance that is configured properly and uses an optional env var TDA_LOG_LEVEL to set the level for only this logger. Side effects of this change: * None Relevant ticket(s): * https://mitlibraries.atlassian.net/browse/TIMX-415
1 parent d5f3549 commit f889439

5 files changed

Lines changed: 75 additions & 0 deletions

File tree

README.md

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,15 @@ timdex_dataset_api = {git = "https://github.com/MITLibraries/timdex-dataset-api.
2626
... other dependencies...
2727
```
2828

29+
## Environment Variables
30+
31+
### Required
32+
33+
### Optional
34+
```shell
35+
TDA_LOG_LEVEL=# log level for timdex-dataset-api, accepts [DEBUG, INFO, WARNING, ERROR], default INFO
36+
```
37+
2938
## Usage
3039

3140
_TODO..._

pyproject.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,7 @@ ignore = [
9494
"S320",
9595
"S321",
9696
"S608",
97+
"TRY003"
9798
]
9899

99100
fixable = ["E", "F", "I", "Q"]

tests/conftest.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
import pytest
2+
3+
4+
@pytest.fixture(autouse=True)
5+
def _test_env(monkeypatch):
6+
monkeypatch.setenv("TDA_LOG_LEVEL", "INFO")

tests/test_config.py

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
from timdex_dataset_api.config import configure_logger
2+
3+
4+
def test_configure_logger_default_info_level(monkeypatch, caplog):
5+
caplog.set_level("DEBUG")
6+
logger = configure_logger(__name__)
7+
8+
info_msg = "hello INFO world"
9+
logger.info(info_msg)
10+
assert info_msg in caplog.text
11+
12+
debug_msg = "hello DEBUG world"
13+
logger.debug(debug_msg)
14+
assert debug_msg not in caplog.text # NOT captured
15+
16+
17+
def test_configure_logger_env_var_sets_debug_level(monkeypatch, caplog):
18+
caplog.set_level("DEBUG")
19+
monkeypatch.setenv("TDA_LOG_LEVEL", "DEBUG")
20+
logger = configure_logger(__name__)
21+
22+
info_msg = "hello INFO world"
23+
logger.info(info_msg)
24+
assert info_msg in caplog.text
25+
26+
debug_msg = "hello DEBUG world"
27+
logger.debug(debug_msg)
28+
assert debug_msg in caplog.text # IS captured

timdex_dataset_api/config.py

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
import logging
2+
import os
3+
4+
5+
def configure_logger(name: str) -> logging.Logger:
6+
"""Prepares and returns a logger instance for a given module name.
7+
8+
This approach is suitable for an installed and imported library such as this, where
9+
any calling application logging levels and handlers should be utilized.
10+
11+
Args:
12+
name (str): The name of the logger, typically __name__ is passed by caller
13+
"""
14+
logger = logging.getLogger(name)
15+
logger.addHandler(logging.NullHandler())
16+
17+
log_level = os.getenv("TDA_LOG_LEVEL", "INFO").strip().upper()
18+
if log_level not in ["DEBUG", "INFO", "WARNING", "ERROR", "CRITICAL"]:
19+
raise ValueError(f"Invalid log level: '{log_level}'")
20+
21+
handler = logging.StreamHandler()
22+
handler.setFormatter(
23+
logging.Formatter(
24+
"%(asctime)s %(levelname)s %(name)s.%(funcName)s() "
25+
"line %(lineno)d: %(message)s"
26+
)
27+
)
28+
logger.addHandler(handler)
29+
logger.setLevel(getattr(logging, log_level))
30+
31+
return logger

0 commit comments

Comments
 (0)