packet-trace 加 log:[u8]: LowerHex is not satisfied(上游 bug)
主线位置:网络驱动收发帧的那一层,
Runner把驱动的RxToken/TxToken包成 smoltcp 的令牌。DriverAdapter和令牌适配器见驱动接口。
flowchart TB
f["packet-trace"] --> t["trace 打印 buf"]
t --> which{"日志后端"}
which -->|defmt| ok1["02x 支持切片"]
which -->|log| err["core fmt 不支持"]
which -->|都没有| ok2["不展开"]
err --> e["E0277 LowerHex"]
实验 crate exp-embassy/pitb-ptrace,bin p27_trace(platform-std,release):两个 embassy-net 栈用进程内的假驱动接起来,A 给 B 发一个 UDP 包。M2 Max、macOS 27、rustc 1.99.0。
现象
想看网卡收发的每一帧,在 std 上调试,日志走 log + env_logger:
embassy-net = { version = "=0.9.1", features = ["std", "log", "packet-trace", "udp", "medium-ethernet", "proto-ipv4"] }
error[E0277]: the trait bound `[u8]: LowerHex` is not satisfied
--> ~/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/embassy-net-0.9.1/src/driver_util.rs:92:49
|
92 | trace!("embassy device rx: {:02x}", buf);
| ------ ^^^ the trait `LowerHex` is not implemented for `[u8]`
| |
| required by this formatting parameter
|
= help: the following other types implement trait `LowerHex`:
...
= note: required for `&mut [u8]` to implement `LowerHex`
= note: this error originates in the macro `$crate::__private_api::format_args` which comes from the expansion of the macro `trace` (in Nightly builds, run with -Z macro-backtrace for more info)
error[E0277]: the trait bound `[u8]: LowerHex` is not satisfied
--> ~/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/embassy-net-0.9.1/src/driver_util.rs:113:49
...
error: could not compile `embassy-net` (lib) due to 2 previous errors
报错在依赖的源码里,自己的代码一行没动。
出处
driver_util.rs 的接收令牌适配器(consume)和发送令牌适配器(consume)各有一行:
#[cfg(feature = "packet-trace")]
trace!("embassy device rx: {:02x}", buf);
trace! 是 embassy-net 自己的 fmt.rs 里的宏:开了 log 就展开成 ::log::trace!,开了 defmt 就展开成 ::defmt::trace!,两者都没开就只是 let _ = (&buf);。{:02x} 对字节切片只在 defmt 里成立(defmt 的格式化把它当成「每个元素按十六进制」),core::fmt 的 LowerHex 没有为 [u8] 实现。所以:
| 日志后端 | packet-trace |
|---|---|
defmt | 编译,按十六进制打印 |
log | E0277 |
| 都不开 | 编译,什么也不打印 |
embassy-net 0.9.1 自己的 CI 配置(Cargo.toml 的 [package.metadata] 构建矩阵)里,带 packet-trace 的两行都配的是 defmt,所以没有发现。
packet-trace 是提交 01b0af5a8「net: add packet-trace feature.」(2024-01,首个包含它的 tag 是 embassy-net-v0.4.0)加的,当时那两行是 trace!("rx: {:?}", buf) 和 trace!("tx: {:?}", buf):{:?} 对 log 和 defmt 都成立。PR #3488 里的提交 af694d233「chore: improve some log msgs」(2024-11,首个包含它的 tag 是 embassy-net-v0.5.0)把它们改成了现在的 "embassy device rx: {:02x}",十六进制在 defmt 下更好读,log 这条路从此编不过。之后的 0.6 到 0.9.1 都没有改。main 上 embassy-net 换到 xarxa 之后(daac2c6ab「net: port to new xarxa」,未发版)packet-trace 这个 feature 已经不存在了。
修法
本地补丁:把 embassy-net 0.9.1 复制到项目里,两行的 {:02x} 改成 {:02x?}(Debug 加十六进制,对切片成立),用 [patch.crates-io] 指过去:
92c92
< trace!("embassy device rx: {:02x}", buf);
---
> trace!("embassy device rx: {:02x?}", buf); // pitb: {:02x} -> {:02x?}
113c113
< trace!("embassy device tx: {:02x}", buf);
---
> trace!("embassy device tx: {:02x?}", buf); // pitb: {:02x} -> {:02x?}
[patch.crates-io]
embassy-net = { path = "embassy-net-patched" }
RUST_LOG=embassy_net=trace 运行:
[INFO embassy_net] link_up = true
[TRACE embassy_net::driver_util] embassy device tx: [ff, ff, ff, ff, ff, ff, 02, 00, 00, 00, 00, 0a, 08, 06, 00, 01, 08, 00, 06, 04, 00, 01, 02, 00, 00, 00, 00, 0a, 0a, 00, 00, 01, ff, ff, ff, ff, ff, ff, 0a, 00, 00, 02]
...
[TRACE embassy_net::driver_util] embassy device rx: [02, 00, 00, 00, 00, 0b, 02, 00, 00, 00, 00, 0a, 08, 00, 45, 00, 00, 1e, 00, 00, 40, 00, 40, 11, 26, cd, 0a, 00, 00, 01, 0a, 00, 00, 02, 00, 09, 00, 09, 00, 0a, 83, 5c, 68, 69]
B got [104, 105] from 10.0.0.1:9
第一帧是 A 的 ARP 请求(目的 MAC 全 ff,类型 08 06),最后一帧是那个 UDP 包,末尾的 68 69 就是 "hi"。
不打补丁的两个办法:
- 去掉 embassy-net 的
logfeature(保留packet-trace)能编过,但trace!什么也不展开,实测 0 行帧日志;只适合「先让它编过」。注意log也可能被别的依赖经 feature 合并打开。 - 不用
packet-trace,在自己的驱动里打印:RxToken::consume/TxToken::consume拿得到同一块buf,在那里log::trace!("{:02x?}", buf)(驱动接口里手写驱动的那一节就是这两个方法)。
怎么确认没中招
- 报错位置在
embassy-net-0.9.1/src/driver_util.rs:92和:113,trait 是LowerHex:就是这个。 cargo tree -e features -i embassy-net --offline看log和packet-trace是否同时打开,以及是谁打开的。- 嵌入式目标上用 defmt 时这个组合是好的,不用改。
小结
- embassy-net 0.9.1 的
packet-trace用{:02x}打印&[u8],只有 defmt 支持;和log一起开就是 E0277(上游 bug,自 0.5.0 起,main 上这个 feature 已随 xarxa 移植去掉,未发版)。 - 修法:本地补丁改成
{:02x?};或去掉log(但什么也不打印);或在自己的驱动令牌里打印帧。