Skip to content

Commit 16d2bde

Browse files
committed
Prevent function crash when setting unknown log level.
1 parent b9f8c0f commit 16d2bde

File tree

3 files changed

+72
-4
lines changed

3 files changed

+72
-4
lines changed

datadog_lambda/__init__.py

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
1-
import os
2-
import logging
31
from datadog_lambda.cold_start import initialize_cold_start_tracing
2+
from datadog_lambda.logger import initialize_logging
43

54
initialize_cold_start_tracing()
65

@@ -13,5 +12,4 @@
1312

1413
__version__ = importlib_metadata.version(__name__)
1514

16-
logger = logging.getLogger(__name__)
17-
logger.setLevel(logging.getLevelName(os.environ.get("DD_LOG_LEVEL", "INFO").upper()))
15+
initialize_logging(__name__)

datadog_lambda/logger.py

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
import logging
2+
import os
3+
4+
try:
5+
_level_mappping = logging.getLevelNamesMapping()
6+
except AttributeError:
7+
# python 3.8
8+
_level_mappping = {name: num for num, name in logging._levelToName.items()}
9+
# https://docs.datadoghq.com/agent/troubleshooting/debug_mode/?tab=agentv6v7#agent-log-level
10+
_level_mappping.update(
11+
{
12+
"TRACE": 5,
13+
"WARN": logging.WARNING,
14+
"OFF": 100,
15+
}
16+
)
17+
18+
19+
def initialize_logging(name):
20+
logger = logging.getLogger(name)
21+
str_level = (os.environ.get("DD_LOG_LEVEL") or "INFO").upper()
22+
level = _level_mappping.get(str_level)
23+
if level is None:
24+
logger.setLevel(logging.INFO)
25+
logger.warning("Invalid log level: %s Defaulting to INFO", str_level)
26+
else:
27+
logger.setLevel(level)

tests/test_logger.py

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
import io
2+
import logging
3+
import pytest
4+
5+
from datadog_lambda.logger import initialize_logging
6+
7+
_test_initialize_logging = (
8+
("TRACE", (10, 20, 30, 40, 50)),
9+
("DEBUG", (10, 20, 30, 40, 50)),
10+
("debug", (10, 20, 30, 40, 50)),
11+
("INFO", (20, 30, 40, 50)),
12+
("WARNING", (30, 40, 50)),
13+
("WARN", (30, 40, 50)),
14+
("ERROR", (40, 50)),
15+
("CRITICAL", (50,)),
16+
("OFF", ()),
17+
("", (20, 30, 40, 50)),
18+
(None, (20, 30, 40, 50)),
19+
("PURPLE", (30, 20, 30, 40, 50)), # log warning then default to INFO
20+
)
21+
22+
23+
@pytest.mark.parametrize("level,logged_levels", _test_initialize_logging)
24+
def test_initialize_logging(level, logged_levels, monkeypatch):
25+
if level is not None:
26+
monkeypatch.setenv("DD_LOG_LEVEL", level)
27+
28+
stream = io.StringIO()
29+
handler = logging.StreamHandler(stream)
30+
handler.setFormatter(logging.Formatter("%(levelno)s"))
31+
logger = logging.getLogger(__name__)
32+
logger.addHandler(handler)
33+
34+
initialize_logging(__name__)
35+
36+
logger.debug("debug")
37+
logger.info("info")
38+
logger.warning("warning")
39+
logger.error("error")
40+
logger.critical("critical")
41+
42+
logged = tuple(map(int, stream.getvalue().strip().split()))
43+
assert logged == logged_levels

0 commit comments

Comments
 (0)