Step 5 does not change behavior. It changes whether humans can understand that behavior.
Part A – English Version
Why Step 5 Exists
Up to Step 4, our firmware:
- has explicit control flow
- integrates real hardware
- talks to the network
- survives failure structurally
But there is still a critical gap:
If this device fails in the field, can we explain what happened?
If the answer is “we can attach a debugger” or “we can reproduce it locally”, the firmware is not production-ready.
Production firmware must explain itself after the fact.
Logging Is Not Debugging
Many junior engineers treat logging as:
printfspam- something enabled only during bring-up
- a substitute for a debugger
That mindset leads to:
- noisy logs
- missing critical information
- performance problems
- unreadable output
In production firmware:
Logging is a communication channel to future humans.
The Core Rule of Step 5
Logs must describe system behavior, not implementation details.
Bad logs:
read sensor
sending http
sending http
error
error
Good logs:
State: IDLE -> SAMPLE
State: SAMPLE -> SEND
Error -110, retry 2, recover to NET_INIT
One tells a story. The other does not.
Log State Transitions, Not Actions
The most important thing to log is state transitions.
Why?
- states represent intent
- transitions represent decisions
- everything else is noise
We add a helper:
static const char *state_str(enum app_state s)
{
switch (s) {
case APP_STATE_BOOT: return "BOOT";
case APP_STATE_SENSOR_INIT: return "SENSOR_INIT";
case APP_STATE_NET_INIT: return "NET_INIT";
case APP_STATE_IDLE: return "IDLE";
case APP_STATE_SAMPLE: return "SAMPLE";
case APP_STATE_SEND: return "SEND";
case APP_STATE_WAIT: return "WAIT";
case APP_STATE_ERROR: return "ERROR";
default: return "UNKNOWN";
}
}
And log only on change:
if (prev_state != ctx->state) {
LOG_INF("State: %s -> %s",
state_str(prev_state),
state_str(ctx->state));
}
This alone makes the system readable.
Centralized Error Logging
Another critical rule:
An error should be logged exactly once.
If errors are logged:
- in drivers
- in callbacks
- in SEND
- in WAIT
You lose signal in noise.
We log errors only when entering ERROR:
case APP_STATE_ERROR:
LOG_ERR("Error %d, retry %u, recover to %s",
ctx->last_error,
ctx->retry_count,
state_str(ctx->recovery_state));
ctx->retry_count++;
ctx->state = APP_STATE_WAIT;
break;
Everything important is in one line.
Why ERROR Is the Perfect Logging Point
At ERROR:
- the failure has already happened
- the system is about to decide policy
- the context is complete
Logging earlier:
- lacks context
- leads to duplication
Logging later:
- loses cause
ERROR is the sweet spot.
Logging Success (Sparingly)
Success logs matter — but only when they confirm progress.
Example:
LOG_INF("Temperature %d mdeg sent successfully", ctx->last_temp_mdeg);
This tells us:
- the device is alive
- the data path works
Do not log every success.
Log Levels Discipline
A simple policy works well:
LOG_ERR– state-changing failuresLOG_INF– state transitions, milestonesLOG_DBG– bring-up only
Production systems should run mostly at INF + ERR.
What Step 5 Deliberately Avoids
Step 5 does not introduce:
- metrics
- persistent logs
- tracing buffers
- cloud logging
Those are product decisions later.
Here we focus on clarity, not analytics.
A Reviewer’s Perspective
A reviewer reading your logs should be able to:
- reconstruct execution flow
- identify failure causes
- understand recovery behavior
Without reading the code.
That is the bar.
Final Thought (English)
If your logs cannot explain your firmware, your firmware is not finished.
Step 5 makes behavior observable.
Part B – Phiên bản tiếng Việt
Vì sao cần Step 5
Sau Step 4, firmware đã:
- có kiến trúc rõ ràng
- xử lý lỗi
- giao tiếp network
Nhưng câu hỏi quan trọng vẫn là:
Khi thiết bị lỗi ngoài thực tế, ta có giải thích được không?
Nếu cần debugger hoặc phải đoán, firmware chưa sẵn sàng cho production.
Logging không phải debug
Logging không phải là printf cho vui.
Nó là:
Kênh giao tiếp với con người trong tương lai.
Quy tắc cốt lõi
Log hành vi hệ thống, không log chi tiết triển khai.
Log tốt kể câu chuyện.
Log state transition
State nói lên ý định.
Transition nói lên quyết định.
Đó là thứ cần log.
Log lỗi tập trung
Lỗi chỉ nên log một lần.
Tại state ERROR.
Vì sao ERROR là nơi log lý tưởng
Ở ERROR:
- biết lỗi gì
- biết retry bao nhiêu
- biết sẽ phục hồi ra sao
Context đầy đủ.
Log thành công có chọn lọc
Chỉ log khi:
- xác nhận hệ thống đang tiến triển
Không spam.
Kỷ luật log level
- ERR: lỗi thay đổi state
- INF: transition, mốc quan trọng
- DBG: bring-up
Step 5 KHÔNG làm gì
- không metrics
- không cloud log
- không tracing
Chỉ tập trung vào dễ hiểu.
Góc nhìn reviewer
Reviewer chỉ cần log là hiểu được:
- hệ thống chạy thế nào
- lỗi gì xảy ra
- phục hồi ra sao
Lời kết (Tiếng Việt)
Nếu log không giải thích được firmware, firmware chưa hoàn thành.
Step 5 làm hệ thống trở nên quan sát được.