Skip to main content

Logging

The library uses the tracing crate for contextual logging. Rust users should refer to the tracing documentation for details.

The bindings provide a single callback method for logging messages. Configurable options include:

  • LogLevel that controls which messages are generated
  • How and if to print the time as part of the message
  • Line or JSON based output
note

The LogLevel defaults to Info, recording Info, Warn, and Error messages. Use Debug and Trace levels only when debugging runtime issues.

Protocol decoding is always logged at the Info level and is configured separately for each client channel and server.

Configuration​

tracing_subscriber::fmt()
.with_max_level(tracing::Level::INFO)
.with_target(false)
.init();
note

The bindings use the tracing_subscriber crate internally. If you use Rust, you can pick which tracing backend to use.

Example output​

Logs include contextual metadata so you can:

  • Determine which communication session produced the message
  • Understand what state the software was in when the event occurred

Here is the example server, with data values, MBAP headers and physical-layer lengths decoded, answering one read from a client that then disconnects:

2026-10-23T23:03:53.225466Z  INFO Modbus-Server-TCP{listen=127.0.0.1:502}: accepted connection from: 127.0.0.1:34736 - assigned session id: 0
2026-10-23T23:03:54.222005Z INFO Modbus-Server-TCP{listen=127.0.0.1:502}:Session{id=0 remote=127.0.0.1:34736}: PHYS RX - 12 bytes
2026-10-23T23:03:54.222256Z INFO Modbus-Server-TCP{listen=127.0.0.1:502}:Session{id=0 remote=127.0.0.1:34736}: MBAP RX - tx_id: 0x00 unit: 0x01 len: 6
2026-10-23T23:03:54.222336Z INFO Modbus-Server-TCP{listen=127.0.0.1:502}:Session{id=0 remote=127.0.0.1:34736}: PDU RX - READ DISCRETE INPUTS (0x02) start: 0x0000 qty: 5
2026-10-23T23:03:54.222379Z INFO Modbus-Server-TCP{listen=127.0.0.1:502}:Session{id=0 remote=127.0.0.1:34736}: PDU TX - READ DISCRETE INPUTS (0x02) start: 0x0000 qty: 5
idx: 0x0000 value: 0
idx: 0x0001 value: 0
idx: 0x0002 value: 0
idx: 0x0003 value: 0
idx: 0x0004 value: 0
2026-10-23T23:03:54.222406Z INFO Modbus-Server-TCP{listen=127.0.0.1:502}:Session{id=0 remote=127.0.0.1:34736}: MBAP TX - tx_id: 0x00 unit: 0x01 len: 4
2026-10-23T23:03:54.222425Z INFO Modbus-Server-TCP{listen=127.0.0.1:502}:Session{id=0 remote=127.0.0.1:34736}: PHYS TX - 10 bytes
2026-10-23T23:03:55.224061Z INFO Modbus-Server-TCP{listen=127.0.0.1:502}:Session{id=0 remote=127.0.0.1:34736}: PHYS RX - 0 bytes
2026-10-23T23:03:55.224151Z WARN Modbus-Server-TCP{listen=127.0.0.1:502}:Session{id=0 remote=127.0.0.1:34736}: session error: unexpected end of file
2026-10-23T23:03:55.224340Z INFO Modbus-Server-TCP{listen=127.0.0.1:502}:Session{id=0 remote=127.0.0.1:34736}: session shutdown

Protocol decoding​

Set the DecodeLevel when you create a client channel or a server, and change it at runtime with set_decode_level. It controls decoding for each layer of the protocol stack:

  • Application layer (PDU): the function code, the request or response header, and the data values
  • Frame (ADU): the MBAP header on TCP and TLS, or the serial frame on RTU
  • Physical layer: the length and bytes of data sent and received

See the language-specific API documentation for the meaning of each enumeration value.

Protocol decoding is always output at the Info log level and can be too verbose for a production system. When you're debugging a communication issue, try application-layer decoding first.