Skip to content

Commit 1bc87fd

Browse files
committed
Central logging.
1 parent d59e68e commit 1bc87fd

File tree

3 files changed

+129
-13
lines changed

3 files changed

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

test/test_logging.py

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
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+
txt = "simple string"
25+
log_txt = Log.build_msg(txt)
26+
assert log_txt == txt
27+
28+
@pytest.mark.parametrize("txt, result, parms", [
29+
("string {} {} {}", "string 101 102 103", (101, 102, 103)),
30+
("string {}", "string 0x41 0x42 0x43 0x44", (b'ABCD', ":hex")),
31+
("string {}", "string 125", (125, ":str")),
32+
])
33+
def test_log_parms(self, txt, result, parms):
34+
log_txt = Log.build_msg(txt, *parms)
35+
assert log_txt == result

0 commit comments

Comments
 (0)