Logging

Structured logging with PLC connection context for multi-PLC environments.

The PLCLoggerAdapter automatically injects PLC host, rack, and slot into every log message:

import logging
logging.basicConfig(level=logging.DEBUG)

from s7 import Client
client = Client()
client.connect("192.168.1.10", 0, 1)
# Logs: [192.168.1.10 R0/S1] Connected to 192.168.1.10:102 ...

For JSON output (ELK, Datadog, Loki):

from snap7.log import JSONFormatter

handler = logging.StreamHandler()
handler.setFormatter(JSONFormatter())
logging.getLogger("snap7").addHandler(handler)

API reference

Structured logging for S7 communication.

Provides a PLCLoggerAdapter that automatically injects PLC connection context (host, rack, slot, protocol) into log messages. This makes it easy to filter and correlate log messages in multi-PLC environments.

Usage:

import logging
from snap7.log import PLCLoggerAdapter

base_logger = logging.getLogger("snap7.client")
logger = PLCLoggerAdapter(base_logger, plc_host="192.168.1.10", rack=0, slot=1)

logger.info("Connected")
# Output: [192.168.1.10 R0/S1] Connected

The adapter is used automatically by snap7.client.Client when a connection is established. No configuration is needed for basic use — just configure the snap7 logger as usual:

logging.basicConfig(level=logging.INFO)

For JSON-structured output compatible with tools like ELK or Datadog, use the JSONFormatter:

handler = logging.StreamHandler()
handler.setFormatter(JSONFormatter())
logging.getLogger("snap7").addHandler(handler)
class snap7.log.JSONFormatter(fmt=None, datefmt=None, style='%', validate=True, *, defaults=None)[source]

Format log records as single-line JSON objects.

Includes PLC context fields (plc_host, plc_rack, plc_slot, plc_protocol) when present in the record’s extra dict.

Output example:

{"ts":"2024-01-15T10:30:00","level":"INFO","logger":"snap7.client",
 "msg":"Connected","plc_host":"192.168.1.10","plc_rack":0,"plc_slot":1}
format(record: LogRecord) str[source]

Format the specified record as text.

The record’s attribute dictionary is used as the operand to a string formatting operation which yields the returned string. Before formatting the dictionary, a couple of preparatory steps are carried out. The message attribute of the record is computed using LogRecord.getMessage(). If the formatting string uses the time (as determined by a call to usesTime(), formatTime() is called to format the event time. If there is exception information, it is formatted using formatException() and appended to the message.

class snap7.log.OperationLogger(logger: Logger | PLCLoggerAdapter, operation: str, **context: Any)[source]

Context manager that logs operation timing at DEBUG level.

Usage:

with OperationLogger(logger, "db_read", db=1, start=0, size=4):
    data = connection.send_receive(request)
class snap7.log.PLCLoggerAdapter(logger: Logger, plc_host: str = '', rack: int = 0, slot: int = 0, protocol: str = '')[source]

Logger adapter that prepends PLC connection context to messages.

Adds plc_host, plc_rack, plc_slot, and plc_protocol to the extra dict of every log record, and prefixes messages with [host R{rack}/S{slot}].

process(msg: str, kwargs: MutableMapping[str, Any]) tuple[str, MutableMapping[str, Any]][source]

Prepend PLC context prefix to the message.

update_context(plc_host: str | None = None, rack: int | None = None, slot: int | None = None, protocol: str | None = None) None[source]

Update the PLC context after connecting.