Communication Tracing
Every IChannel raises PacketTraced when raw bytes are sent or received. The event does not parse protocols; it records actual TX/RX bytes for field diagnostics, communication windows, and fault snapshots.
Subscribe Directly
var meter = app.Channels.Get("meter");
meter.PacketTraced += (_, e) =>
{
var direction = e.Direction == ChannelTraceDirection.Sent ? "TX" : "RX";
Console.WriteLine($"{e.Timestamp:O} {meter.Name} {direction} {e.Hex}");
};
Hex is a continuous uppercase hex string. Format e.Data.Span yourself if you need spaces.
Keep the Last N Entries
var meter = app.Channels.Get("meter");
using var trace = new ChannelTraceBuffer(meter, capacity: 200);
await app.StartAsync();
await meter.WriteAsync(new byte[] { 0x01, 0x03, 0x00, 0x00 });
foreach (var entry in trace.Entries)
{
Console.WriteLine($"{entry.Timestamp:HH:mm:ss.fff} {entry.ChannelName} {entry.Direction} {entry.Hex}");
}
Entries returns a snapshot from oldest to newest. When capacity is full, the oldest entries are removed.
Write to ILogger
Host-level tracing uses AddCommunicationLogging. It attaches a logger to existing and later channels, and reattaches after hot reload rebuilds a channel with the same name. The default level is Debug; the EventId is ZeusLogEvents.PacketTrace.
await using var app = ZeusHost.Create(builder =>
{
builder.AddVirtualChannel("meter");
builder.AddCommunicationLogging();
});
To trace a single channel, or only while a diagnostic window is open, still use ChannelTraceLogger directly:
var meter = app.Channels.Get("meter");
var logger = app.Services.GetRequiredService<ILoggerFactory>().CreateLogger("comm.trace");
using var traceLog = new ChannelTraceLogger(meter, logger);
await app.StartAsync();
await meter.WriteAsync(new byte[] { 0x01, 0x03, 0x00, 0x00 });
The log template includes structured fields: Channel, Direction, ByteCount, and Hex. Dispose the handle to unsubscribe.
If you need files, databases, or packet-capture systems, subscribe to PacketTraced or configure an ILogger sink and choose the format, path, rotation, and retention in the application. Zeus no longer ships a file trace writer, so storage policy stays outside the framework.
Trace vs DataReceived
| API | Purpose |
|---|---|
DataReceived | Business or protocol code consumes received bytes |
PacketTraced | Diagnostic code records sent and received raw bytes |
ChannelTraceBuffer | Rolling in-memory trace |
ChannelTraceLogger | Structured ILogger trace |
AddCommunicationLogging | Attaches ChannelTraceLogger to every channel and follows hot reload |
PacketTraced and DataReceived may fire on IO threads. In WinForms, use control binding or BeginInvoke; in WPF, hand the data to a ViewModel and marshal through WpfUiDispatcher.