Week 06 · lesson
Exit Codes and Logs Are Part of the Interface
A script that prints “done” is not necessarily done.
Operational tools need a way to communicate outcome to both humans and other programs.
Two common mechanisms are exit status and structured logs.
Exit status communicates success or failure
On many operating systems, a process exits with a numeric status.
By convention:
0 → success
non-zero → some form of failure
The exact non-zero values depend on the program.
This means another process can make a decision without scraping a sentence from the screen.
Example shell pattern in an isolated lab:
python3 archive_logs.py
status=$?
echo "exit_status=$status"
If you do not have a shell, use the supplied traces in this lesson instead.
“Partial success” needs a policy
Suppose a script processes ten files:
8 moved
1 skipped because it was not a .log file
1 failed because destination already existed
Should the exit code be success?
There is no universal answer. The task contract should decide.
Possible policy:
- unexpected file type is a normal skip;
- destination conflict is an error;
- any error produces non-zero exit status.
The important thing is consistency between documented semantics and observed outcome.
Structured logs reduce ambiguity
Compare:
Something went wrong
with:
level=error event=destination-conflict file=alpha.log action=not-moved
The second message lets you ask specific questions.
But do not log everything merely because you can.
Avoid recording:
- passwords;
- API tokens;
- private student records;
- full secret-bearing configuration;
- unrelated file contents; or
- unnecessary personal identifiers.
A log is itself a data system.
Supplied execution trace
Review this fictional run:
10:02:11 level=info event=start candidates=3
10:02:11 level=info event=moved file=a.log
10:02:11 level=error event=destination-conflict file=b.log
10:02:11 level=info event=skip file=notes.txt reason=extension
10:02:11 level=info event=finish moved=1 skipped=1 errors=1
exit_status=0
The logging says an error occurred, but the exit status says success.
That is an interface inconsistency.
Do not claim data loss occurred; the trace does not show that.
A defensible claim is:
The supplied run reported one destination conflict while returning success status, so an automated caller that relies only on exit status could misclassify this run as successful.
That is precise.
Activity: define outcome semantics
Create an outcome table for your Week 6 task.
| Condition | Log level/event | Exit outcome | Continue? |
|---|---|---|---|
| all expected changes succeed | info/complete | success | n/a |
| allowed non-target file | info/skip | success | yes |
| destination conflict | error/conflict | failure | policy |
| source root missing | error/precondition | failure | stop |
| unexpected root/path | error/scope | failure | stop |
Your exact table may differ. Defend it from the task contract.
Retries need limits
A retry can recover from a transient failure.
An unbounded retry can create a new failure.
Model:
attempt
↓
success? ─ yes → finish
│
no
↓
retryable? ─ no → stop + report
│
yes
↓
attempts remaining? ─ no → stop + report
│
yes
↓
wait → retry
A good retry policy defines:
- which failures are retryable;
- maximum attempts;
- delay/backoff;
- stop condition; and
- evidence recorded for each attempt.
“Retry until it works” is not a policy.
Monitoring scripts need truthful status
Imagine a monitoring job reports healthy because the process itself ran successfully, even though the check discovered the service was unhealthy.
That confuses script health with system health.
Names and outcomes should distinguish them.
For example:
check_execution=success
service_state=unhealthy
Now two different claims remain separate.
Extend your Automation Safety Record
Add:
- outcome table;
- success exit rule;
- failure exit rule;
- bounded log fields;
- prohibited log data;
- retry policy if relevant;
- one supplied or local execution trace; and
- one inconsistency you would detect.
Lesson 3 will test repeatability and recovery.