Introduction
FRAME Studio now needs a short record of a work session, not a disappearing terminal display. The resource sampler is already complete in this independent instance. Your job is to turn observations into explicit warnings and append them without losing the operator's earlier record.
You will implement three short functions: classify one reading, record one complete row, and repeat the prepared sampling action. Basic Bash variables, functions, conditions and loops are prerequisites; the first Guided Lab explains the measurement meanings. No files from that lab are needed. Limits are local training policy, not universal production recommendations. The duration is an author estimate.
Give Every Reading an Explicit State
In this step, you will turn one percentage and its limit into a reusable warning decision.
Start in Terminal. This independent instance already contains working metrics.sh, so no earlier files are needed. Enter the workspace:
cd /home/labex/project/resource-watch
See a current observation:
bash snapshot.sh
The four tab-separated fields are UTC timestamp, CPU non-idle, memory pressure and target-filesystem usage. They describe this instance, not a production fleet. A resource warning does not establish that the photo export has failed.
cat displays the policy without changing it:
cat policy.sh
Read the three limits and the complete target/log paths. For this unit the CPU and memory limits are 80 and the disk limit is 50. These are training choices. The explicit rule is WARN when a reading is greater than or equal to its own limit; otherwise OK. Equality matters. Preserve the supplied policy and sampler.
Open the incomplete functions with nano:
This lab starts again with a prepared, working metrics file. Edit the monitoring-functions file named in the next command, rather than copying your earlier metrics file into this instance. In the policy output, the three LIMIT values are integer percentages; TARGET is the observed directory and LOG is the saved-history path. Reading the policy does not change it.
nano monitor-functions.sh
Replace only classify with:
classify() {
if (( $1 >= $2 )); then
echo WARN
else
echo OK
fi
}
The first argument is a reading and the second is its limit. ((...)) compares numbers; >= includes equality. Both branches print a state, so a normal reading is explicitly OK rather than silent. Save with Ctrl+O, Enter, Ctrl+X.
source loads definitions. Run tests inside bash -c because the terminal's interactive shell is Zsh. The single-quoted argument preserves the commands for Bash:
bash -c 'source ./monitor-functions.sh; classify 79 80; classify 80 80; classify 81 80'
OK
WARN
WARN
These supplied readings exercise your rule; they are not current CPU measurements. An always-WARN or always-OK function is incorrect even if today's workstation happens to show that state.
Append a Complete Monitoring Record
In this step, you will record all readings and their separate states without replacing earlier history.
Stay in Terminal, in /home/labex/project/resource-watch. First read the existing operator history:
cat history.tsv
Its original row must remain byte-for-byte at the beginning. history.tsv is the real deliverable, not a report you fill in manually. Each new line has seven tab-separated fields: UTC timestamp, CPU, memory, disk, then the CPU, memory and disk states in that order.
Open the functions:
nano monitor-functions.sh
Replace only record_sample with:
record_sample() {
local stamp=$1 cpu=$2 memory=$3 disk=$4 logfile=$5
printf '%s\t%s\t%s\t%s\t%s\t%s\t%s\n' \
"$stamp" "$cpu" "$memory" "$disk" \
"$(classify "$cpu" "$CPU_LIMIT")" \
"$(classify "$memory" "$MEMORY_LIMIT")" \
"$(classify "$disk" "$DISK_LIMIT")" >> "$logfile"
}
printf substitutes each %s, \t writes a tab, and \n ends the row. A backslash at the end of a code line continues the same command. $(...) captures a function's output. Double quotes preserve each captured value and a log path containing spaces. >> appends; using > here would destroy earlier records. Save with Ctrl+O, Enter, Ctrl+X.
Try one supplied test record in a separate practice file. source ./policy.sh loads the supplied limit variables into this Bash process. These variables do not automatically persist in another terminal or a later bash -c call.
bash -c 'source ./policy.sh; source ./monitor-functions.sh; record_sample 2026-01-02T03:04:05Z 10 85 20 practice.tsv'
cat practice.tsv
2026-01-02T03:04:05Z 10 85 20 OK WARN OK
The memory warning belongs to 85 compared with 80; it does not cause the other two states to become WARN. A repeated practice call appends another practice row. Do not append supplied example readings to history.tsv: that file is reserved for actual sampling.
Use the practice example to read the seven fields from left to right:
| Field | Example | Meaning |
|---|---|---|
| 1 | 2026-01-02T03:04:05Z | Time in UTC; Z denotes UTC |
| 2 | 10 | CPU non-idle percentage |
| 3 | 85 | Memory-pressure percentage |
| 4 | 20 | Target-filesystem-used percentage |
| 5 | OK | CPU 10 is below its limit of 80 |
| 6 | WARN | Memory 85 is at or above its limit of 80 |
| 7 | OK | Disk 20 is below its limit of 50 |
Tabs may look like uneven spaces in Terminal. Keep the actual tab separators produced by the function; do not manually align the real history with spaces. The old operator row is prepared background, so its earlier date is expected. Only the separate practice file receives this supplied example.
Run a Bounded Watch and Keep Earlier History
In this step, you will repeat real sampling, inspect the saved result, and run again without losing progress.
Stay in Terminal, in /home/labex/project/resource-watch. The prepared monitor.sh supplies capture_once target logfile: it obtains one new observation, calls your recorder, and displays that saved row. Your loop must pass the requested paths unchanged and call this action exactly the requested number of times. One capture includes a fresh one-second CPU window; this is a bounded watch, not a precise scheduler.
nano monitor-functions.sh
Replace only run_monitor with:
run_monitor() {
local count=$1 target=$2 logfile=$3
local n
for ((n = 0; n < count; n++)); do
capture_once "$target" "$logfile"
done
}
The arithmetic loop starts at zero, continues while n is smaller than count, and increases n after each capture. Quotes preserve both paths. A while loop with the same behavior is also valid. Save with Ctrl+O, Enter, Ctrl+X.
Run three actual samples:
bash monitor.sh 3
Expect three new rows before the prompt returns. Each line should show a later UTC timestamp. Actual readings vary, and a normal run may contain no warnings. The prepared driver accepts counts from 1 to 30. For a longer watch, Ctrl+C stops the foreground script; already appended rows remain. You do not need to kill any other process.
Read the result and count its lines. wc -l counts newline-terminated rows:
cat history.tsv
wc -l history.tsv
After the first documented run it should contain the original row plus three new rows: four lines. If you ran more samples, the total will be larger. Keep those valid observations.
Now continue the watch for one sample:
bash monitor.sh 1
wc -l history.tsv
The count increases by one. Re-running is safe because your recorder appends instead of replacing. Compare every state with its reading and corresponding limit in policy.sh.
Try an ordinary input error intentionally. A count of zero is rejected before sampling:
bash monitor.sh 0
Use a sample count from 1 to 30.
This expected command exits with status 2 and leaves the history unchanged. Recover by running a valid count; do not reset the VM or edit the log:
bash monitor.sh 1
One new row is appended. The supplied sampler also rejects incomplete metric output instead of appending a plausible-looking empty observation.
Check your result
- The first operator row is still present at the beginning, followed by your new observations.
- The first run adds three rows; continuing with one sample adds one more. More valid rows are allowed if you repeated a command.
- Read the three percentages first, then compare each with its own limit. All three states being OK is a valid outcome; there is no need to generate load or delete files to make a warning appear.
- Each capture waits for a fresh CPU interval. A brief pause is expected; do not press Enter repeatedly while it is sampling. When the prompt returns, the bounded run has ended. Closing Terminal is not a way to keep a continuous monitor running.
Summary
You implemented an inclusive warning rule, appended complete records with three independent states, and repeated a real sampling action while preserving earlier history. You can now run a short watch, read its evidence, and continue it. The independent Challenge changes the target and policy while reusing these same tools and function contracts.



