Skip to content

Commit 2fb85f8

Browse files
authored
Central logging. (#1324)
1 parent d59e68e commit 2fb85f8

32 files changed

+405
-535
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/client/base.py

Lines changed: 8 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@
22
from __future__ import annotations
33

44
import asyncio
5-
import logging
65
import socket
76
from dataclasses import dataclass
87

@@ -11,12 +10,10 @@
1110
from pymodbus.exceptions import ConnectionException, NotImplementedException
1211
from pymodbus.factory import ClientDecoder
1312
from pymodbus.framer import ModbusFramer
13+
from pymodbus.logging import Log
1414
from pymodbus.pdu import ModbusRequest, ModbusResponse
1515
from pymodbus.transaction import DictTransactionManager
16-
from pymodbus.utilities import ModbusTransactionState, hexlify_packets
17-
18-
19-
_logger = logging.getLogger(__name__)
16+
from pymodbus.utilities import ModbusTransactionState
2017

2118

2219
class ModbusBaseClient(ModbusClientMixin):
@@ -207,7 +204,7 @@ def send(self, request):
207204
:meta private:
208205
"""
209206
if self.state != ModbusTransactionState.RETRYING:
210-
_logger.debug('New Transaction state "SENDING"')
207+
Log.debug('New Transaction state "SENDING"')
211208
self.state = ModbusTransactionState.SENDING
212209
return request
213210

@@ -360,13 +357,12 @@ def raise_future(self, my_future, exc):
360357

361358
def _connection_made(self):
362359
"""Call upon a successful client connection."""
363-
_logger.debug("Client connected to modbus server")
360+
Log.debug("Client connected to modbus server")
364361
self._connected = True
365362

366363
def _connection_lost(self, reason):
367364
"""Call upon a client disconnect."""
368-
txt = f"Client disconnected from modbus server: {reason}"
369-
_logger.debug(txt)
365+
Log.debug("Client disconnected from modbus server: {}", reason)
370366
self._connected = False
371367
for tid in list(self.transaction):
372368
self.raise_future(
@@ -389,17 +385,13 @@ def _execute(self, request, **kwargs): # pylint: disable=unused-argument
389385
"""Start the producer to send the next request to consumer.write(Frame(request))."""
390386
request.transaction_id = self.transaction.getNextTID()
391387
packet = self.framer.buildPacket(request)
392-
if _logger.isEnabledFor(logging.DEBUG):
393-
txt = f"send: {hexlify_packets(packet)}"
394-
_logger.debug(txt)
388+
Log.debug("send: {}", packet, ":hex")
395389
self.write_transport(packet)
396390
return self._build_response(request.transaction_id)
397391

398392
def _data_received(self, data):
399393
"""Get response, check for valid message, decode result."""
400-
if _logger.isEnabledFor(logging.DEBUG):
401-
txt = f"recv: {hexlify_packets(data)}"
402-
_logger.debug(txt)
394+
Log.debug("recv: {}", data, ":hex")
403395
self.framer.processIncomingPacket(data, self._handle_response, unit=0)
404396

405397
def _handle_response(self, reply, **kwargs): # pylint: disable=unused-argument
@@ -409,8 +401,7 @@ def _handle_response(self, reply, **kwargs): # pylint: disable=unused-argument
409401
if handler := self.transaction.getTransaction(tid):
410402
self.resolve_future(handler, reply)
411403
else:
412-
txt = f"Unrequested message: {str(reply)}"
413-
_logger.debug(txt)
404+
Log.debug("Unrequested message: {}", reply, ":str")
414405

415406
def _build_response(self, tid):
416407
"""Return a deferred response for the current request."""

pymodbus/client/mixin.py

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
"""Modbus Client Common."""
2-
import logging
32
from typing import List, Tuple, Union
43

54
import pymodbus.bit_read_message as pdu_bit_read
@@ -13,9 +12,6 @@
1312
from pymodbus.pdu import ModbusRequest, ModbusResponse
1413

1514

16-
_logger = logging.getLogger(__name__)
17-
18-
1915
class ModbusClientMixin: # pylint: disable=too-many-public-methods
2016
"""**ModbusClientMixin**.
2117

pymodbus/client/serial.py

Lines changed: 16 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
"""Modbus client async serial communication."""
22
import asyncio
3-
import logging
43
import time
54
from functools import partial
65

@@ -10,7 +9,8 @@
109
from pymodbus.exceptions import ConnectionException
1110
from pymodbus.framer import ModbusFramer
1211
from pymodbus.framer.rtu_framer import ModbusRtuFramer
13-
from pymodbus.utilities import ModbusTransactionState, hexlify_packets
12+
from pymodbus.logging import Log
13+
from pymodbus.utilities import ModbusTransactionState
1414

1515

1616
try:
@@ -19,9 +19,6 @@
1919
pass
2020

2121

22-
_logger = logging.getLogger(__name__)
23-
24-
2522
class AsyncModbusSerialClient(ModbusBaseClient):
2623
"""**AsyncModbusSerialClient**.
2724
@@ -104,7 +101,7 @@ async def connect(self): # pylint: disable=invalid-overridden-method
104101
# get current loop, if there are no loop a RuntimeError will be raised
105102
self.loop = asyncio.get_running_loop()
106103

107-
_logger.debug("Starting serial connection")
104+
Log.debug("Starting serial connection")
108105
try:
109106
await create_serial_connection(
110107
self.loop,
@@ -118,28 +115,26 @@ async def connect(self): # pylint: disable=invalid-overridden-method
118115
**self.params.kwargs,
119116
)
120117
await self._connected_event.wait()
121-
txt = f"Connected to {self.params.port}"
122-
_logger.info(txt)
118+
Log.info("Connected to {}", self.params.port)
123119
except Exception as exc: # pylint: disable=broad-except
124-
txt = f"Failed to connect: {exc}"
125-
_logger.warning(txt)
120+
Log.warning("Failed to connect: {}", exc)
126121
return self.connected
127122

128123
def protocol_made_connection(self, protocol):
129124
"""Notify successful connection."""
130-
_logger.info("Serial connected.")
125+
Log.info("Serial connected.")
131126
if not self.connected:
132127
self._connected_event.set()
133128
self.protocol = protocol
134129
else:
135-
_logger.error("Factory protocol connect callback called while connected.")
130+
Log.error("Factory protocol connect callback called while connected.")
136131

137132
def protocol_lost_connection(self, protocol):
138133
"""Notify lost connection."""
139134
if self.connected:
140-
_logger.info("Serial lost connection.")
135+
Log.info("Serial lost connection.")
141136
if protocol is not self.protocol:
142-
_logger.error("Serial: protocol is not self.protocol.")
137+
Log.error("Serial: protocol is not self.protocol.")
143138

144139
self._connected_event.clear()
145140
if self.protocol is not None:
@@ -148,7 +143,7 @@ def protocol_lost_connection(self, protocol):
148143
# if self.host:
149144
# asyncio.asynchronous(self._reconnect())
150145
else:
151-
_logger.error("Serial, lost_connection but not connected.")
146+
Log.error("Serial, lost_connection but not connected.")
152147

153148

154149
class ModbusSerialClient(ModbusBaseClient):
@@ -235,7 +230,7 @@ def connect(self):
235230
self.socket.interCharTimeout = self.inter_char_timeout
236231
self.last_frame_end = None
237232
except serial.SerialException as msg:
238-
_logger.error(msg)
233+
Log.error("{}", msg)
239234
self.close()
240235
return self.socket is not None
241236

@@ -270,16 +265,15 @@ def send(self, request):
270265
if waitingbytes := self._in_waiting():
271266
result = self.socket.read(waitingbytes)
272267
if self.state == ModbusTransactionState.RETRYING:
273-
txt = f"Sending available data in recv buffer {hexlify_packets(result)}"
274-
_logger.debug(txt)
268+
Log.debug(
269+
"Sending available data in recv buffer {}", result, ":hex"
270+
)
275271
return result
276-
if _logger.isEnabledFor(logging.WARNING):
277-
txt = f"Cleanup recv buffer before send: {hexlify_packets(result)}"
278-
_logger.warning(txt)
272+
Log.warning("Cleanup recv buffer before send: {}", result, ":hex")
279273
except NotImplementedError:
280274
pass
281275
if self.state != ModbusTransactionState.SENDING:
282-
_logger.debug('New Transaction state "SENDING"')
276+
Log.debug('New Transaction state "SENDING"')
283277
self.state = ModbusTransactionState.SENDING
284278
size = self.socket.write(request)
285279
return size

pymodbus/client/sync_diag.py

Lines changed: 11 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,14 @@
11
"""Sync diag."""
2-
import logging
32
import socket
43
import time
54

65
from pymodbus.client.tcp import ModbusTcpClient
76
from pymodbus.constants import Defaults
87
from pymodbus.exceptions import ConnectionException
98
from pymodbus.framer.socket_framer import ModbusSocketFramer
9+
from pymodbus.logging import Log
1010

1111

12-
_logger = logging.getLogger(__name__)
13-
1412
LOG_MSGS = {
1513
"conn_msg": "Connecting to modbus device %s",
1614
"connfail_msg": "Connection to (%s, %s) failed: %s",
@@ -91,23 +89,21 @@ def connect(self):
9189
if self.socket:
9290
return True
9391
try:
94-
_logger.info(LOG_MSGS["conn_msg"], self)
92+
Log.info(LOG_MSGS["conn_msg"], self)
9593
self.socket = socket.create_connection(
9694
(self.params.host, self.params.port),
9795
timeout=self.params.timeout,
9896
source_address=self.params.source_address,
9997
)
10098
except socket.error as msg:
101-
_logger.error(
102-
LOG_MSGS["connfail_msg"], self.params.host, self.params.port, msg
103-
)
99+
Log.error(LOG_MSGS["connfail_msg"], self.params.host, self.params.port, msg)
104100
self.close()
105101
return self.socket is not None
106102

107103
def close(self):
108104
"""Close the underlying socket connection."""
109105
if self.socket:
110-
_logger.info(LOG_MSGS["discon_msg"], self)
106+
Log.info(LOG_MSGS["discon_msg"], self)
111107
self.socket.close()
112108
self.socket = None
113109

@@ -122,29 +118,29 @@ def recv(self, size):
122118
if self.warn_delay_limit is not None and delay >= self.warn_delay_limit:
123119
self._log_delayed_response(len(result), size, delay)
124120
elif not size:
125-
_logger.debug(LOG_MSGS["timelimit_read_msg"], delay, len(result))
121+
Log.debug(LOG_MSGS["timelimit_read_msg"], delay, len(result))
126122
else:
127-
_logger.debug(LOG_MSGS["read_msg"], delay, len(result), size)
123+
Log.debug(LOG_MSGS["read_msg"], delay, len(result), size)
128124

129125
return result
130126
except ConnectionException as exc:
131127
# Only log actual network errors, "if not self.socket" then it's a internal code issue
132128
if "Connection unexpectedly closed" in exc.string:
133-
_logger.error(LOG_MSGS["unexpected_dc_msg"], self, exc)
129+
Log.error(LOG_MSGS["unexpected_dc_msg"], self, exc)
134130
raise ConnectionException from exc
135131

136132
def _log_delayed_response(self, result_len, size, delay):
137133
"""Log delayed response."""
138134
if not size and result_len > 0:
139-
_logger.info(LOG_MSGS["timelimit_read_msg"], delay, result_len)
135+
Log.info(LOG_MSGS["timelimit_read_msg"], delay, result_len)
140136
elif (
141137
(not result_len) or (size and result_len < size)
142138
) and delay >= self.params.timeout:
143139
size_txt = size if size else "in timelimit read"
144140
read_type = f"of {size_txt} expected"
145-
_logger.warning(LOG_MSGS["timeout_msg"], delay, result_len, read_type)
141+
Log.warning(LOG_MSGS["timeout_msg"], delay, result_len, read_type)
146142
else:
147-
_logger.warning(LOG_MSGS["delay_msg"], delay, result_len, size)
143+
Log.warning(LOG_MSGS["delay_msg"], delay, result_len, size)
148144

149145
def __str__(self):
150146
"""Build a string representation of the connection.
@@ -163,9 +159,7 @@ def get_client():
163159
164160
:returns: ModbusTcpClient or a child class thereof
165161
"""
166-
return (
167-
ModbusTcpDiagClient if _logger.isEnabledFor(logging.ERROR) else ModbusTcpClient
168-
)
162+
return ModbusTcpDiagClient
169163

170164

171165
# --------------------------------------------------------------------------- #

0 commit comments

Comments
 (0)