Task 2-1: Hex Packet Logging cho Binary Protocol Debug
Phase: 2 Priority: Medium Module:
ConnectedClient,TranslateMsgToWWJDepends on: Không có Reference: docs/BountyHunter-ControlServer/details/feature-iot-bridge/SPEC.md
Background
Binary protocol giữa ControlServer và claw machines sử dụng raw hex bytes. Khi có bug (packet sai format, checksum lỗi, length mismatch), developer hiện tại không có cách nào xem raw bytes — chỉ thấy exception stacktrace hoặc silent discard. PLAN.md Phase 1 đề cập hex packet logging nhưng chưa implement. Thiếu visibility này làm debug production incident rất khó: developer phải attach debugger hoặc thêm log tạm thời mỗi lần có sự cố.
Tasks
Note: SLF4J
log.debug()chỉ evaluate arguments nếu DEBUG level enabled. Tuy nhiên,Arrays.toString(byte[])tạo intermediate String ngay cả khi level không match. Dùnglog.isDebugEnabled()guard hoặc implementLogUtil.toHexString()như một lazySupplier<String>để tránh overhead khi không cần log. Trong production (INFO level), không có hex string nào được tạo ra.
- [ ] Tạo static utility method
LogUtil.toHexString(byte[] data)trong package util:
public class LogUtil {
/**
* Converts byte array to uppercase hex string with spaces.
* Example: {0xFE, 0x01, 0x00} → "FE 01 00"
*/
public static String toHexString(byte[] data) {
if (data == null || data.length == 0) return "(empty)";
StringBuilder sb = new StringBuilder(data.length * 3);
for (int i = 0; i < data.length; i++) {
if (i > 0) sb.append(' ');
sb.append(String.format("%02X", data[i] & 0xFF));
}
return sb.toString();
}
}
- [ ] Log outbound packets trong
sendDataToMachine()(trước khiout.write(data)):
if (log.isDebugEnabled()) {
log.debug("[TX→{}] {} bytes: {}", macIp, data.length, LogUtil.toHexString(data));
}
out.write(data);
out.flush();
- [ ] Log inbound packets sau khi parse type trong
ClientMessageHandler(hoặcreadMessages()loop):
if (log.isDebugEnabled()) {
log.debug("[RX←{}] type={} {} bytes: {}", macIp, resultType, rawBytes.length, LogUtil.toHexString(rawBytes));
}
- [ ] Log WARN khi checksum mismatch (thay vì silent discard):
log.warn("[RX←{}] Checksum MISMATCH — expected=0x{} actual=0x{} raw: {}",
macIp,
String.format("%02X", expectedChecksum),
String.format("%02X", actualChecksum),
LogUtil.toHexString(rawBytes));
- [ ] Log handshake magic bytes
"aa"khi initial connection:
log.debug("[→{}] Sending handshake: {}", remoteAddr, LogUtil.toHexString(HANDSHAKE_BYTES));
- [ ] Verify không có hex log ở INFO level bằng cách kiểm tra tất cả call sites chỉ dùng
log.debug()hoặclog.isDebugEnabled()guard
Verification / Acceptance Criteria
- [ ] Với
logging.level.bap.partner=DEBUG(hoặc package tương đương): hex bytes xuất hiện trong logs cho mọi inbound và outbound packet - [ ] Format nhất quán:
[TX→<macIp>]cho outbound,[RX←<macIp>]cho inbound - [ ] Với INFO level (production default): không có hex string nào trong logs, zero performance overhead từ
LogUtil.toHexString() - [ ] Checksum mismatch → WARN log với raw bytes, không chỉ là silent exception
- [ ] Unit test
LogUtil.toHexString():{0xFE, 0x01, 0x00}→"FE 01 00", empty array →"(empty)", null →"(empty)"
Files to Modify
src/main/java/.../ConnectedClient.javasrc/main/java/.../TranslateMsgToWWJ.java(hoặcClientMessageHandler.java)src/main/java/.../util/LogUtil.java← file mới tạo