Skip to content

Commit a659861

Browse files
committed
Central logging.
1 parent d59e68e commit a659861

File tree

3 files changed

+139
-13
lines changed

3 files changed

+139
-13
lines changed

pymodbus/__init__.py

Lines changed: 4 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -3,29 +3,20 @@
33
Released under the the BSD license
44
"""
55

6-
import logging as __logging
7-
from logging import NullHandler as __null
6+
from logging import WARNING
87

98
import pymodbus.version as __version
9+
from pymodbus.logging import Log
1010

1111

1212
__version__ = __version.version.short()
1313
__author__ = "Galen Collins"
1414
__maintainer__ = "dhoomakethu, janiversen"
1515

16-
# ---------------------------------------------------------------------------#
17-
# Block unhandled logging
18-
# ---------------------------------------------------------------------------#
19-
__logging.getLogger(__name__).addHandler(__null())
2016

21-
22-
def pymodbus_apply_logging_config(level=__logging.WARNING):
17+
def pymodbus_apply_logging_config(level=WARNING):
2318
"""Apply basic logging configuration used by default by Pymodbus maintainers.
2419
2520
Please call this function to format logging appropriately when opening issues.
2621
"""
27-
__logging.basicConfig(
28-
format="%(asctime)s %(levelname)-5s %(module)s:%(lineno)s %(message)s",
29-
datefmt="%H:%M:%S",
30-
level=level,
31-
)
22+
Log.apply_logging_config(level)

pymodbus/logging.py

Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
"""Pymodbus: Modbus Protocol Implementation.
2+
3+
Released under the the BSD license
4+
"""
5+
6+
import logging
7+
from logging import NullHandler as __null
8+
9+
from pymodbus.utilities import hexlify_packets
10+
11+
12+
# ---------------------------------------------------------------------------#
13+
# Block unhandled logging
14+
# ---------------------------------------------------------------------------#
15+
logging.getLogger(__name__).addHandler(__null())
16+
17+
18+
class Log:
19+
"""Class to hide logging complexity.
20+
21+
:meta private:
22+
"""
23+
24+
CRITICAL = logging.CRITICAL
25+
ERROR = logging.ERROR
26+
WARNING = logging.WARNING
27+
DEBUG = logging.DEBUG
28+
INFO = logging.INFO
29+
30+
LOG_LEVEL = logging.WARNING
31+
_logger = logging.getLogger(__name__)
32+
33+
@classmethod
34+
def apply_logging_config(cls, level=logging.WARNING):
35+
"""Apply basic logging configuration"""
36+
logging.basicConfig(
37+
format="%(asctime)s %(levelname)-5s %(module)s:%(lineno)s %(message)s",
38+
datefmt="%H:%M:%S",
39+
)
40+
cls._logger.setLevel(level)
41+
cls.LOG_LEVEL = level
42+
43+
@classmethod
44+
def build_msg(cls, txt, *args):
45+
"""Build message."""
46+
string_args = []
47+
count_args = len(args) - 1
48+
skip = False
49+
for i in range(count_args + 1):
50+
if skip:
51+
skip = False
52+
continue
53+
if (
54+
i < count_args
55+
and isinstance(args[i + 1], str)
56+
and args[i + 1][0] == ":"
57+
):
58+
if args[i + 1] == ":hex":
59+
string_args.append(hexlify_packets(args[i]))
60+
elif args[i + 1] == ":str":
61+
string_args.append(str(args[i]))
62+
skip = True
63+
else:
64+
string_args.append(args[i])
65+
return txt.format(*string_args)
66+
67+
@classmethod
68+
def info(cls, txt, *args):
69+
"""Log info messagees."""
70+
if logging.INFO >= cls.LOG_LEVEL:
71+
cls._logger.info(cls.build_msg(txt, *args))
72+
73+
@classmethod
74+
def debug(cls, txt, **args):
75+
"""Log debug messagees."""
76+
if logging.DEBUG >= cls.LOG_LEVEL:
77+
cls._logger.debug(cls.build_msg(txt, *args))
78+
79+
@classmethod
80+
def warning(cls, txt, **args):
81+
"""Log warning messagees."""
82+
if logging.WARNING >= cls.LOG_LEVEL:
83+
cls._logger.warning(cls.build_msg(txt, *args))
84+
85+
@classmethod
86+
def error(cls, txt, **args):
87+
"""Log error messagees."""
88+
if logging.ERROR >= cls.LOG_LEVEL:
89+
cls._logger.error(cls.build_msg(txt, *args))
90+
91+
@classmethod
92+
def critical(cls, txt, **args):
93+
"""Log critical messagees."""
94+
if logging.CRITICAL >= cls.LOG_LEVEL:
95+
cls._logger.critical(cls.build_msg(txt, *args))

test/test_logging.py

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
"""Test datastore."""
2+
import pytest
3+
4+
from pymodbus import pymodbus_apply_logging_config
5+
from pymodbus.logging import Log
6+
7+
8+
class TestLogging:
9+
"""Tests of pymodbus logging."""
10+
11+
def test_log_our_default(self):
12+
"""Test default logging"""
13+
pymodbus_apply_logging_config()
14+
assert Log.LOG_LEVEL == Log.WARNING
15+
16+
def test_log_set_level(self):
17+
"""Test default logging"""
18+
pymodbus_apply_logging_config(Log.DEBUG)
19+
assert Log.LOG_LEVEL == Log.DEBUG
20+
pymodbus_apply_logging_config(Log.INFO)
21+
assert Log.LOG_LEVEL == Log.INFO
22+
23+
def test_log_simple(self):
24+
"""Test simple string"""
25+
txt = "simple string"
26+
log_txt = Log.build_msg(txt)
27+
assert log_txt == txt
28+
29+
@pytest.mark.parametrize(
30+
"txt, result, params",
31+
[
32+
("string {} {} {}", "string 101 102 103", (101, 102, 103)),
33+
("string {}", "string 0x41 0x42 0x43 0x44", (b"ABCD", ":hex")),
34+
("string {}", "string 125", (125, ":str")),
35+
],
36+
)
37+
def test_log_parms(self, txt, result, params):
38+
"""Test string with parameters (old f-string)"""
39+
log_txt = Log.build_msg(txt, *params)
40+
assert log_txt == result

0 commit comments

Comments
 (0)