通信报文追踪
每个 IChannel 都会在收发原始字节时触发 PacketTraced。它不解析协议,只记录通道实际提交的 TX 字节和底层收到的 RX 字节,适合现场调试、通信窗口和故障快照。
直接订阅事件
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 是连续大写十六进制字符串。如果需要带空格的显示,可以自己格式化 e.Data.Span。
保留最近 N 条
如果只想保留最近一段通信记录,使用 ChannelTraceBuffer:
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 返回的是快照,顺序从旧到新。容量满后会自动丢弃最旧记录。
写入 ILogger
宿主级写法是 AddCommunicationLogging:给已有和后续新增的通道自动挂报文日志,热重载重建同名通道时会退订旧实例再挂到新实例。默认级别是 Debug,事件编号是 ZeusLogEvents.PacketTrace。
await using var app = ZeusHost.Create(builder =>
{
builder.AddVirtualChannel("meter");
builder.AddCommunicationLogging();
});
如果只想追踪某一条通道,或只在排障窗口打开时记录,仍可手写 ChannelTraceLogger:
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 });
日志模板包含结构化字段:Channel、Direction、ByteCount、Hex。关闭窗口时释放句柄即可退订。
需要写入文件、数据库或抓包系统时,订阅 PacketTraced 或接入 ILogger sink 自己决定格式、路径、轮转和留存策略。Zeus 不再内置文件追踪器,避免框架替应用承担存储职责。
和 DataReceived 的区别
| API | 用途 |
|---|---|
DataReceived | 业务或协议层消费收到的数据 |
PacketTraced | 诊断层记录发送和接收的原始字节 |
ChannelTraceBuffer | 在内存中滚动保留最近 N 条追踪记录 |
ChannelTraceLogger | 把后续追踪记录写入 ILogger 结构化日志 |
AddCommunicationLogging | 给全部通道自动挂 ChannelTraceLogger,热重载后跟着迁 |
这些能力可以同时使用。PacketTraced 和 DataReceived 可能在 IO 线程触发;WinForms 更新控件时用控件绑定或 BeginInvoke,WPF 则把数据交给 ViewModel 并通过 WpfUiDispatcher 封送。