Build a Linux Health Report

Build a Bash tool that creates versioned Linux health reports.

Introduction

30 Second Summary

When a computer feels slow or unstable, useful clues are scattered across terminal output. An administrator still has to turn those clues into something another person can review.

In this project, you will build a local Bash utility that turns live Linux health data into a structured Markdown report. Its Git history, README, and runbook will give another administrator a clear way to run each check and interpret the results.

What You'll Build

Picture running one command in Visual Studio Code and opening a fresh report that highlights the machine's resource pressure, service health, and recent warnings.

By the end of this project, you'll have:

  • A repeatable health snapshot in reports/health-report.md that shows the current host, kernel, uptime, memory, and filesystem data.
  • A clear disk finding that reports a PASS or WARNING against the project's 80 percent threshold. The same report shows systemd health, failed units, and accessible journal warnings when those tools are available.
  • A version-controlled operations guide that another administrator can use to run the monitor, interpret findings, investigate warnings, and review sensitive details before sharing.
  • Secret Mission: Replace the fixed disk threshold with a validated command-line option while keeping 80 percent as the default.

Are there any prerequisites?

This project needs an Ubuntu or Debian Linux machine with Bash, Git, and Visual Studio Code already installed. Basic shell command experience is enough because each command, flag, pipe, and redirect is explained before you use it.

Before We Start

A useful health report starts with a clear machine and audience. This is your moment to identify the Ubuntu or Debian Linux machine you are auditing and the administrator who needs to understand its health.

Verify the Workstation and Create the Repository

Your report will rely on local commands every time it runs. A missing command could stop the audit before it writes any evidence.

This step proves that Bash, Git, Visual Studio Code, GNU Coreutils, and procps-ng are available. You will also create the Git-backed workspace that holds the report.

In this step, get ready to:
  • Verify the commands required by the health report.
  • Create the linux-health-report directory tree.
  • Initialize the repository before opening it in Visual Studio Code.
Verify the required commands

A command-line program returns an exit status after it finishes. A status of zero signals success.

  • Open a terminal from your Linux application menu.

The bash executable starts the Bash shell. The --version option requests information about the installed release.

  • Check your installed Bash version by running this command:
bash --version

How to read this command

  • The first word selects the Bash executable.
  • The --version option prints release information before Bash exits successfully.
  • Successful output begins with the Bash product name plus a version number.

The git executable manages version-controlled repositories. Its --version option prints the installed Git release.

  • Check your installed Git version by running this command:
git --version

How to read this command

  • The first word selects the Git command-line program.
  • The --version option requests its installed release.
  • Successful output includes the Git product name plus a version number.

The code executable controls Visual Studio Code from the terminal. Its --version option prints the installed version plus build details.

  • Check your installed Visual Studio Code version by running this command:
code --version

How to read this command

  • The first word selects the Visual Studio Code command-line interface.
  • The --version option requests the installed version plus its commit identifier plus its architecture.
  • Several lines of version information confirm that the terminal can find Visual Studio Code.

The report also depends on six Linux utilities. A command-discovery check confirms that Bash can find each executable through its search path.

  • Check the six required utilities by running these commands:
command -v date
command -v uname
command -v df
command -v tail
command -v uptime
command -v free

What do these checks do?

  • The command built-in asks Bash to inspect a command name.
  • The -v option prints the word or path Bash uses for that command.
  • A found command returns an exit status of zero. A missing command returns an exit status of one.
  • The date, uname, df, and tail utilities come from the coreutils package.
  • The uptime plus free utilities come from the procps package.

✔️ I see a path for every command

Every required utility is available. Each line points to the executable that Bash runs.

ⓧ One or more commands are missing

The sudo command requests administrator approval. Your password stays hidden while you type it.

The apt package manager uses the install action to add packages. The accepted response is y if APT asks for confirmation.

  • Install the missing command packages by running this command:
sudo apt install coreutils procps

What does this command do?

  • The sudo command grants the package operation administrator privileges.
  • The apt command manages software on Ubuntu plus Debian systems.
  • The install action adds the requested packages.
  • The coreutils package supplies the filesystem plus text utilities used by the report.
  • The procps package supplies the process plus memory utilities used by the report.

Package installation failed?

Check that the machine has an internet connection. Confirm that your account can use administrator approval.

If another package operation is already running, wait for it to finish before retrying.

Help me diagnose an APT installation failure on Ubuntu or Debian.

  • Repeat the command-discovery checks by running these commands:
command -v date
command -v uname
command -v df
command -v tail
command -v uptime
command -v free

What should you see now?

Each check should now print a word or path for its executable. Six results confirm that both packages supply the required commands.

The final utility check prints version information from the filesystem plus process-reporting packages. It proves that the commands can run after discovery.

  • Print the installed utility versions by running these commands:
df --version
uptime --version
free --version

How to read these version checks

  • The df command reports filesystem space. Its --version option identifies the installed GNU Coreutils release.
  • The uptime command reports how long the machine has run. Its --version option identifies the installed procps-ng release.
  • The free command reports memory usage. Its --version option identifies the installed procps-ng release.
  • Three version results confirm that the future monitoring commands are executable.

A version check still fails?

Repeat the package installation from the missing-command tab. Start a new terminal afterward if the executable search path has not refreshed.

Help me troubleshoot a missing Linux monitoring command.

That proves the workstation can supply every required resource command. Your future report now has a dependable local foundation.

Create the repository structure

The repository needs separate locations for operational documentation plus generated reports. Relative paths create those locations beneath the directory where your terminal is currently positioned.

  • Move to your Desktop by running this command:
cd ~/Desktop

What does this command do?

  • The cd command changes the terminal's current directory.
  • The ~ character expands to your home directory.
  • The Desktop segment selects the Desktop directory inside your home directory.
  • Create the repository directory tree by running this command:
mkdir -p linux-health-report/docs linux-health-report/reports

How is the directory tree created?

  • The mkdir command creates directories.
  • The -p option creates missing parent directories as needed.
  • The linux-health-report/docs relative path creates the project directory plus its documentation directory.
  • The linux-health-report/reports relative path creates the generated-report directory under the same project.
  • Confirm that both subdirectories exist by running this command:
ls linux-health-report

What should you see?

  • The ls command lists directory contents.
  • The linux-health-report argument selects the directory to inspect.
  • You should see docs plus reports in the output.

Directories missing from the list?

Confirm that the creation command uses the exact linux-health-report spelling. Check that your terminal is still positioned on the Desktop.

Help me find my Linux project directories.

  • Enter the project directory by running this command:
cd linux-health-report

How does this path work?

The cd command changes into the named directory. The relative name selects linux-health-report beneath the current Desktop location.

A Git repository stores version history in hidden metadata. Initializing the repository creates that metadata without changing the new directories.

  • Initialize the current directory as a Git repository by running this command:
git init

What does repository initialization do?

  • The git executable selects Git.
  • The init subcommand creates an empty repository in the current directory.
  • Git prints confirmation that it initialized the repository.
  • The empty docs plus reports directories remain on disk.

Repository initialization failed?

Confirm that the terminal is inside linux-health-report. Check that your account can write to the Desktop directory.

Help me troubleshoot git init in my project directory.

The directory tree is now a local repository. Git can track every script plus document you add from this point forward.

Open the workspace and check Git

Opening the repository as one workspace keeps its scripts plus documentation together. The terminal command uses your current directory as the workspace location.

  • Open the current repository in Visual Studio Code by running this command:
code .

What does this command do?

  • The code executable launches Visual Studio Code.
  • The . argument represents the terminal's current directory.
  • Visual Studio Code should open the linux-health-report workspace.
  • The Explorer sidebar should show the docs plus reports directories.

Workspace did not open?

Return to the terminal from earlier. Confirm that code --version still prints version information.

Help me troubleshoot the Visual Studio Code workspace command.

Git attaches an author name plus email address to future commits. Querying both keys now reveals the identity Git can currently read.

  • Switch back to the terminal from earlier.
  • Read both Git identity values by running these queries:
git config --get user.name
git config --get user.email

What do these queries read?

  • The git config command reads Git configuration.
  • The --get option requests the value of one configuration key.
  • The user.name key stores the author name used for commits.
  • The user.email key stores the author email used for commits.
  • A missing key returns an exit status of one.

✔️ I see my name and email

Git can read both identity values. Your later commit can use this author information.

ⓧ One or both values are missing

The missing result confirms that Git has no value for that identity key. Configure the missing identity before the commit in Step 5.

Before you run the final check, do you expect Git to list the two empty directories as untracked content?

  • Inspect the repository state by running this command:
git status

What does the final status prove?

  • The git executable selects Git.
  • The status subcommand compares the repository history with its staging area plus working tree.
  • You should see an empty repository with no commits.
  • Git does not track empty directories. The clean result confirms that no files are waiting to be staged.

✔️ Awesome, I've got everything!

Your workstation checks passed. Your repository structure is ready for the first health snapshot.

ⓧ I'd like to double check the workspace

  • The linux-health-report directory is a local Git repository initialized with git init plus opened in Visual Studio Code.
  • The docs/ directory exists for project documentation.
  • The reports/ directory exists for generated health reports.

Your tools are verified. Next, you will capture live machine data in the first manual health report.

Capture a Manual Health Snapshot

Your Git repository is ready for its first piece of operational evidence. The reports directory is waiting in Visual Studio Code.

A Linux health snapshot records one machine at one moment. Building it manually gives you a baseline for judging terminal output as a reusable report.

In this step, get ready to:
  • Capture a manual Markdown resource snapshot.
  • Record the available service-manager status.
  • Assess the snapshot as an on-call report.
Capture resource output

You will collect each reading from the Bash terminal from earlier. Simple Markdown headings will keep the copied results in recognizable sections.

  • In the Visual Studio Code file tree from earlier, select the reports directory.
  • Use the new-file control above the file tree to create health-report.md inside reports.

You'll see the empty reports/health-report.md file open in the editor.

  • Enter # Manual Linux Health Snapshot at the top of reports/health-report.md.
  • Enter ## Uptime two lines below the title.

The uptime executable reads how long the machine has been running. The -p option requests a readable duration.

  • Switch back to the terminal panel from earlier.
  • Print a human-readable uptime summary by running this command:
uptime -p

What Does the Uptime Result Show?

  • The result states how long the machine has been running in readable units.
  • A short duration can point to a recent restart.
  • Copy the output line from the terminal.
  • Return to reports/health-report.md.
  • Paste the copied output directly below ## Uptime.
  • Save reports/health-report.md.

You should now see the machine's current uptime beneath its matching heading.

  • Enter ## Memory below the uptime output.

The free executable reports physical memory plus swap usage. The -h option scales byte values into readable units.

  • Print the machine's readable memory summary by running this command:
free -h

How Do I Read the Memory Table?

  • The physical-memory row compares total capacity with used space.
  • The later fields distinguish cache use from memory still available to applications.
  • The swap row reports overflow memory configured on disk.
  • Copy the complete memory table from the terminal.
  • Return to reports/health-report.md.
  • Paste the copied table directly below ## Memory.
  • Save reports/health-report.md.

You should now see the current physical-memory summary plus the current swap summary.

  • Enter ## Filesystems below the memory output.

The df executable reports filesystem capacity. Its rows separate consumed space from remaining space.

The -h option formats sizes with readable units.

  • Print a readable filesystem table by running this command:
df -h

How Do I Read the Filesystem Table?

  • Each row represents one mounted filesystem.
  • The size fields compare total capacity with consumed space.
  • The percentage shows how full that filesystem is.
  • The final field identifies its mount location.
  • Copy the complete filesystem table from the terminal.
  • Return to reports/health-report.md.
  • Paste the copied table directly below ## Filesystems.
  • Save reports/health-report.md.

Your report now shows live evidence for uptime plus memory usage plus mounted filesystem capacity.

Add service-manager status

The systemctl executable communicates with the systemd service manager. The status subcommand requests a human-readable system summary.

A working manager returns state details. An unavailable check means systemd cannot provide status on this machine.

  • Enter ## Service Manager below the filesystem output.
  • Switch back to the terminal panel.
  • Request the current service-manager status by running this command:
systemctl status

What Does This Result Mean?

  • A working systemd manager returns a human-readable summary of the current system state.
  • An unavailable result indicates that systemd cannot report the state on this machine.
  • The systemctl status output is designed for a person reading a terminal.

✔️ systemd returned a status

The command returned live service-manager details.

  • Copy the complete status output from the terminal.
  • Return to reports/health-report.md.
  • Paste the copied output directly below ## Service Manager.
  • Save reports/health-report.md.

Your report now contains the live service-manager output.

ⓧ The status is unavailable

The command could not return a usable systemd status. The resource readings remain valid.

  • Return to reports/health-report.md.
  • Enter Service-manager status is unavailable on this machine. directly below ## Service Manager.
  • Save reports/health-report.md.

Your report now records the service-manager limitation explicitly.

Report Missing an Output Section?

  • Check that every copied result sits below its matching Markdown heading.
  • Rerun only the missing command if your clipboard replaced its output.

Ask for help with your copied output: Help me identify which section is missing from my manual Linux health snapshot.

Assess the manual report

The snapshot now contains current readings from this machine. The final check tests whether those copied sections work as one operational report.

Before you read the file from top to bottom, do you expect four copied command outputs to feel like one consistent report?

  • Return to the reports/health-report.md tab from earlier.
  • Read the snapshot from the title to the service-manager section.
  • Confirm the report contains live uptime output.
  • Confirm the report contains live memory output.
  • Confirm the report contains live filesystem output.
  • Confirm the report contains service-manager output or an explicit unavailable message.

You'll see current evidence in every section. The format shifts from a sentence to aligned tables to a terminal status dump.

The snapshot also leaves the reader to decide whether any value needs attention.

Why Does the Manual Snapshot Fall Short?

Copied output has no shared structure for conclusions. Another administrator must interpret every value.

That manual interpretation makes repeated reporting slow.

Your manual snapshot now captures live machine evidence. Record this baseline before automation replaces its hand-built structure.

  • Create a checkpoint for the manual report and verify the repository state by running these commands:
git add reports/health-report.md
git commit -m "Add manual health snapshot"
git status

What does this checkpoint record?

  • The git add command stages the manual report.
  • The git commit command records that staged baseline with a descriptive message.
  • The git status command checks for files left outside the checkpoint.

You should see a commit summary followed by a clean working tree. Your manual snapshot now has a recoverable point in Git history.

Commit not created?

Save reports/health-report.md before rerunning the commands. If Git requests an identity, return to the local name and email configuration from Step 1.

Help me troubleshoot the manual snapshot commit.

You have a real health snapshot built from live machine data. Next, you'll turn these checks into one repeatable Bash command with consistent sections.

Generate a Structured Resource Report

Your manual snapshot proved that the machine's health data is available. Rebuilding it by hand would make every new snapshot slow.

Manual copying also makes formatting inconsistent. A Bash script can collect current values into the same Markdown structure on every run.

In this step, get ready to:
  • Build a runnable monitoring script.
  • Capture machine identity plus resource summaries.
  • Replace the manual snapshot with a structured report.
Create the script foundation

The script needs predictable shell behavior before it collects machine data. It also needs one place to define the report path.

How does the shell setup work?

  • The set shell command changes how the current Bash process behaves.
  • The -u option stops the script when it tries to expand an unset variable.
  • The -o option selects a named shell setting.
  • The pipefail setting makes a pipeline report a failure when one of its commands fails.
  • The assignment lines store the report directory plus file path in reusable variables.
  • The dollar sign in $REPORT_DIR expands the variable to its stored value.
  • The quotation marks keep each expanded path together as one shell value.
  • The mkdir command creates a directory.
  • The -p option keeps the command safe when reports already exists.
  • Select the Explorer view in Visual Studio Code.
  • Select the New File control.
  • Enter monitor.sh as the file name.
  • Press Enter.
  • Place the shell settings at the top of monitor.sh by pasting this code:
set -u
set -o pipefail

REPORT_DIR="reports"
REPORT_FILE="$REPORT_DIR/health-report.md"

mkdir -p "$REPORT_DIR"

What does this foundation do?

This foundation gives the script one authoritative output path. The shell settings also make later collection failures easier to notice.

  • Save monitor.sh with Cmd+S on macOS or Ctrl+S on Windows and Linux.
  • Confirm that monitor.sh appears beside the existing docs plus reports directories.

Can't find the new script?

  • Check that you created monitor.sh inside linux-health-report.
  • Check the file name for an extra extension added after monitor.sh.

Help me check why monitor.sh is missing from my repository.

Linux distributions expose a standard operating-system identification file. The script checks the preferred location before trying the fallback location.

How does machine identification work?

  • The os_release_file="" assignment starts with an empty path.
  • The [[ ]] syntax evaluates a Bash condition.
  • The -r test succeeds when the named file is readable.
  • The if keyword starts the first condition.
  • The elif keyword tries the fallback path when the first condition fails.
  • The fi keyword closes each conditional block.
  • The -n test succeeds when os_release_file contains at least one character.
  • The dot command reads the selected file into the current shell.
  • The ${PRETTY_NAME:-Linux} expansion uses the identified operating-system name when it exists. It falls back to Linux when that value is unavailable.
  • The $(...) syntax runs a command. It stores that command's output in a variable.
  • The date command returns the current system date plus time.
  • The ${HOSTNAME:-unknown} expansion uses the current Bash hostname. It supplies unknown when the variable is unavailable.
  • The uname command reports system information.
  • The -s option selects the kernel name.
  • The -r option selects the kernel release.
  • The uptime command reports how long the system has been running.
  • The -p option requests a readable uptime description.
  • The 2>&1 redirect sends standard error to the same destination as standard output.
  • Place the cursor below the mkdir -p "$REPORT_DIR" line.
  • Add the machine-identification logic by pasting this code:
os_release_file=""
if [[ -r /etc/os-release ]]; then
  os_release_file="/etc/os-release"
elif [[ -r /usr/lib/os-release ]]; then
  os_release_file="/usr/lib/os-release"
fi

if [[ -n "$os_release_file" ]]; then
  . "$os_release_file"
fi

os_name="${PRETTY_NAME:-Linux}"
generated_at="$(date)"
host_name="${HOSTNAME:-unknown}"
kernel_summary="$(uname -sr)"
uptime_summary="$(uptime -p 2>&1)"

What does this identity logic do?

The script now chooses the documented operating-system file that exists on the current machine. It captures a fresh identity snapshot every time Bash executes the file.

  • Save monitor.sh.

The word bash starts the Bash interpreter. The monitor.sh argument names the file that Bash reads.

  • Check the script foundation by running this command:
bash monitor.sh

What does this check prove?

Bash executes the setup plus identity logic from top to bottom. When your prompt returns without a shell error, the foundation is runnable.

Script stops during identity capture?

  • Compare each opening if with its closing fi.
  • Check that the dot command appears inside the -n conditional.
  • Check every variable assignment for spaces around the equals sign.

Help me debug my monitor.sh identity logic.

Capture resource summaries

Memory plus filesystem tools print tables designed for a terminal. Command substitution lets the script preserve those tables for the report.

How are the resource tables collected?

  • The free command reports physical memory plus swap memory.
  • The -h option scales memory values into readable units.
  • The df command reports filesystem space usage.
  • The -h option formats filesystem sizes with readable units.
  • The -P option requests a portable table layout.
  • Each -x option excludes the filesystem type that follows it.
  • The tmpfs plus devtmpfs exclusions remove temporary memory-backed filesystems.
  • The squashfs exclusion removes read-only squash filesystems from the main storage view.
  • Command substitution stores each complete table in one variable.
  • The 2>&1 redirect preserves an accessible error message when a resource command fails.
  • Find this existing line near the bottom of monitor.sh:
uptime_summary="$(uptime -p 2>&1)"

Why find this line?

This line marks the end of the identity values you already capture. The resource values belong directly below it.

  • Add the memory plus filesystem assignments below that line so the section looks like this:
uptime_summary="$(uptime -p 2>&1)"
memory_summary="$(free -h 2>&1)"
filesystem_summary="$(df -hP -x tmpfs -x devtmpfs -x squashfs 2>&1)"

What changed?

The script now stores three current resource summaries before it writes the report. Each value comes from the machine running the script.

  • Save monitor.sh.

Resource assignments look different?

  • Check that each assignment starts at the left edge of the file.
  • Check that every command substitution has matching parentheses.
  • Check that df includes all three -x exclusions.

Help me compare my resource-summary assignments with the intended monitor.sh structure.

Generate the Markdown report

A here-document lets the script send a multi-line template into one command. Output redirection sends that completed template to the report file.

How does the report writer work?

  • The cat command receives the complete report template through standard input.
  • The greater-than operator replaces the file named by $REPORT_FILE with the new output.
  • The <<EOF operator starts the here-document.
  • The matching EOF line closes the here-document.
  • The unquoted delimiter allows each dollar-prefixed variable to expand inside the template.
  • The Markdown headings keep host data separate from resource tables.
  • The text fences preserve the spacing in command output.
  • The echo command prints a completion message after the file is written.
  • Place the cursor below the filesystem_summary assignment.
  • Add the report writer by pasting this code:
cat > "$REPORT_FILE" <<EOF
# Linux Infrastructure Health Report

Generated: $generated_at

## Host

- Hostname: $host_name
- Operating system: $os_name
- Kernel: $kernel_summary
- Uptime: $uptime_summary

## Memory

~~~text
$memory_summary
~~~

## Filesystems

~~~text
$filesystem_summary
~~~
EOF

echo "Created $REPORT_FILE"

What does this report contain?

The report begins with its generation time. It follows with named host fields.

Memory plus filesystem tables sit inside text fences. Their original column spacing stays readable in Markdown.

  • Save monitor.sh.

✔️ Awesome, I've got everything!

  • Confirm that monitor.sh is saved.

ⓧ I'd like to double check the full code

set -u
set -o pipefail

REPORT_DIR="reports"
REPORT_FILE="$REPORT_DIR/health-report.md"

mkdir -p "$REPORT_DIR"

os_release_file=""
if [[ -r /etc/os-release ]]; then
  os_release_file="/etc/os-release"
elif [[ -r /usr/lib/os-release ]]; then
  os_release_file="/usr/lib/os-release"
fi

if [[ -n "$os_release_file" ]]; then
  . "$os_release_file"
fi

os_name="${PRETTY_NAME:-Linux}"
generated_at="$(date)"
host_name="${HOSTNAME:-unknown}"
kernel_summary="$(uname -sr)"
uptime_summary="$(uptime -p 2>&1)"
memory_summary="$(free -h 2>&1)"
filesystem_summary="$(df -hP -x tmpfs -x devtmpfs -x squashfs 2>&1)"

cat > "$REPORT_FILE" <<EOF
# Linux Infrastructure Health Report

Generated: $generated_at

## Host

- Hostname: $host_name
- Operating system: $os_name
- Kernel: $kernel_summary
- Uptime: $uptime_summary

## Memory

~~~text
$memory_summary
~~~

## Filesystems

~~~text
$filesystem_summary
~~~
EOF

echo "Created $REPORT_FILE"

How should the full file look?

This reference shows the exact cumulative script for this step. The final line sits outside the here-document so its message appears in the terminal.

The bash command starts the interpreter. The monitor.sh argument tells Bash which file to execute.

Before you run it, do you expect the old manual snapshot to remain or be replaced?

  • Generate the structured report by running this command:
bash monitor.sh

What happened?

Bash collected fresh values before expanding the report template. The terminal prints Created reports/health-report.md after the manual snapshot has been replaced.

  • Select the reports directory in the Visual Studio Code Explorer.
  • Select health-report.md.
  • Confirm that the report shows a current generation time.
  • Confirm that the Host section shows the current hostname.
  • Confirm that the operating-system field names the current Linux distribution.
  • Confirm that the kernel plus uptime fields contain current values.
  • Confirm that the Memory section contains the readable memory table.
  • Confirm that the Filesystems section contains the filtered filesystem table.

That repeatable report is working. One command now turns the machine's current state into a consistent document.

Report missing a section?

  • Check that the opening cat line points to $REPORT_FILE.
  • Check that the closing EOF begins at the left edge of monitor.sh.
  • Check that each report variable begins with a dollar sign inside the template.

Help me debug a missing section in my generated reports/health-report.md file.

The scripted resource report is now reproducible. Preserve this working automation before adding diagnostic decisions.

  • Create a checkpoint for the script and generated report by running these commands:
git add monitor.sh reports/health-report.md
git commit -m "Automate resource health report"
git status

What does this checkpoint record?

  • The git add command stages both the automation and its generated result.
  • The git commit command records the reproducible resource-report milestone.
  • The git status command confirms whether any saved project changes remain.

You should see a commit summary followed by a clean working tree. Git can now restore the first automated version of your report.

Commit not created?

Save monitor.sh and reports/health-report.md before rerunning the commands. Confirm that your terminal is inside the linux-health-report repository.

Help me troubleshoot the automated report commit.

Your resource report is now reproducible. Next, you'll turn raw system data into findings that tell an administrator where to investigate.

Add Findings, Service Health, and Logs

Your script now turns live Linux resource data into a consistent Markdown snapshot. The report still leaves the reader to judge every filesystem row.

This step adds an 80 percent project policy that converts disk usage into a clear finding.

You will also replace the awkward service status dump with concise systemd health. The report will finish with accessible warning-or-higher journal entries.

In this step, get ready to:
  • Add a disk PASS or WARNING finding.
  • Report the systemd state with failed-unit evidence.
  • Capture the latest ten accessible warning-or-higher journal entries.
Add a disk finding

An operations report needs a policy that turns raw usage into a decision. This project treats any reported filesystem at or above 80 percent as a warning.

The DISK_WARNING_PERCENT variable stores the threshold as a whole number. Leaving out the percent sign lets Bash use the value in an arithmetic comparison.

  • Return to monitor.sh in Visual Studio Code.
  • Find the REPORT_FILE="$REPORT_DIR/health-report.md" assignment near the top of the file.
  • Copy this threshold assignment directly below it:
DISK_WARNING_PERCENT=80

What does this assignment do?

The assignment gives DISK_WARNING_PERCENT the numeric value 80. Bash assignments have no spaces around the equals sign.

This value is an explicit project policy. It is not a universal Linux threshold.

  • Save monitor.sh.

Before you run the script, do you expect this assignment to preserve the existing report run?

The bash executable starts the Bash interpreter. The monitor.sh argument names the script that Bash reads.

  • Confirm the script still runs by executing this command:
bash monitor.sh

What should you see?

The terminal prints Created reports/health-report.md. This confirms Bash accepted the new threshold assignment.

Seeing an assignment error?

Check that the line uses DISK_WARNING_PERCENT=80 with no spaces around the equals sign.

Make sure the assignment sits on its own line below REPORT_FILE.

Ask for help with the threshold assignment.

How will the disk parser work?

The new df command requests only the percentage and mount-target fields. The --output=pcent,target option selects those fields.

Each -x option excludes one filesystem type. The 2>&1 redirect sends standard error to the same captured stream as standard output.

A while loop feeds each row into read -r. The here-string operator <<< supplies the captured table as the loop input.

The parser removes the percent sign before testing digits with =~. The (( )) expression then performs the numeric threshold comparison.

  • Find the filesystem_summary assignment in monitor.sh.
  • Copy this disk-policy logic directly below that assignment:
disk_findings=""
disk_table="$(df --output=pcent,target -x tmpfs -x devtmpfs -x squashfs 2>&1)"

while read -r use_percent target; do
  if [[ "$use_percent" == "Use%" ]]; then
    continue
  fi

  usage="${use_percent%\%}"
  if [[ "$usage" =~ ^[0-9]+$ ]] && (( usage >= DISK_WARNING_PERCENT )); then
    disk_findings+="- WARNING: ${target} is ${usage}% full. Project threshold: ${DISK_WARNING_PERCENT}%."$'\n'
  fi
done <<< "$disk_table"

if [[ -z "$disk_findings" ]]; then
  disk_findings="- PASS: All reported filesystems are below the ${DISK_WARNING_PERCENT}% project threshold."
fi

What does this code do?

  • The $(...) command substitution captures the filtered df table inside disk_table.
  • The read -r use_percent target command places the two fields from each row into separate variables.
  • The continue command skips the Use% header row.
  • The ${use_percent%\%} expansion removes the shortest matching percent-sign suffix.
  • The && operator requires both the numeric test and threshold comparison to succeed.
  • The $'\n' value appends a real newline after each warning.
  • The final empty-string test creates one PASS finding when no filesystem reaches the threshold.
  • Find the blank space between Generated: $generated_at and ## Host inside the report here-document.
  • Insert this findings section into that space:
## Findings

$disk_findings

How does the finding reach the report?

The here-document expands $disk_findings while writing reports/health-report.md. The generated Markdown now shows the policy result near the top.

  • Save monitor.sh.

Before you regenerate the report, do you expect your machine to receive a disk PASS or a disk WARNING?

  • Regenerate the report by running this command:
bash monitor.sh

What happens during this run?

Bash reads the live filesystem table before comparing every numeric usage value with DISK_WARNING_PERCENT. The script replaces the previous report after completing the comparison.

The code command opens a path in Visual Studio Code. The relative path starts from the current linux-health-report directory.

  • Open the regenerated report by running this command:
code reports/health-report.md

What should the report show?

Visual Studio Code opens reports/health-report.md. The Findings section contains either a disk PASS or a warning for each mount at or above the project threshold.

Missing the disk finding?

Confirm that the disk parser sits after the filesystem_summary assignment. Code placed inside the report here-document becomes report text instead of executable Bash.

Check that $disk_findings appears below the ## Findings heading.

Ask for help with the missing disk result.

Report systemd health

A full status dump is designed for a person at a terminal. A reusable report needs a short overall state with focused failed-unit evidence.

How will the service check work?

The command -v check asks Bash whether systemctl is available. The >/dev/null redirect discards normal discovery output.

The 2>&1 redirect sends discovery errors to the discarded stream. The conditional uses the command's exit status to select the available or fallback branch.

The systemctl is-system-running command returns a short operational state. The systemctl list-units --state=failed command filters the unit list to failed units.

The temporary SYSTEMD_PAGER=cat assignment disables interactive paging for the captured unit output. It applies only to that command.

  • Find the final fi in the disk-policy logic.
  • Copy this service-health logic directly below it:
if command -v systemctl >/dev/null 2>&1; then
  system_state="$(systemctl is-system-running 2>&1)"
  failed_units="$(SYSTEMD_PAGER=cat systemctl list-units --state=failed 2>&1)"

  if [[ "$system_state" == "running" ]]; then
    system_finding="- PASS: systemd reports the system state as running."
  else
    system_finding="- WARNING: systemd reports the system state as ${system_state}. Review the failed-unit section."
  fi
else
  system_state="unavailable"
  failed_units="systemctl is not available on this machine."
  system_finding="- INFO: systemd checks are unavailable; resource reporting still completed."
fi

What does this code do?

  • The outer conditional detects whether the service-management command exists.
  • The available branch captures the overall state in system_state.
  • The same branch captures failed-unit details in failed_units.
  • The nested conditional creates a PASS only for the exact running state.
  • Every other returned state becomes a warning with an investigation pointer.
  • The fallback branch records explicit unavailable values while preserving resource reporting.
  • Save monitor.sh.

The next run checks whether the service-health branch completes without interrupting the existing report.

  • Run the updated script with this command:
bash monitor.sh

What should you see?

The terminal prints Created reports/health-report.md again. This confirms the available or fallback branch completed.

  • Find $disk_findings inside the report here-document.
  • Copy this service finding directly below it:
$system_finding

Why add this to Findings?

The report places the overall service result beside the disk policy result. An operator can scan both findings before reading the evidence sections.

  • Find the closing text fence for the Filesystems section.
  • Copy this service-health section below that fence:
## systemd Health

- Overall state: $system_state

### Failed Units

~~~text
$failed_units
~~~

How is the evidence organized?

The overall state gives the reader a quick health signal. The fenced failed-unit output preserves command formatting for investigation.

  • Save monitor.sh.

Before you run the script, do you expect your machine to report a running state, another state, or an unavailable result?

  • Regenerate the report by running this command:
bash monitor.sh

What should the run prove?

The command replaces the report with the current service state. It still prints Created reports/health-report.md when the resource report completes.

  • Return to reports/health-report.md in Visual Studio Code.

You will see a systemd finding near the top. The dedicated health section shows the overall state with failed-unit output or an explicit unavailable result.

Service section stopping the script?

Check that the entire service block sits before the cat > "$REPORT_FILE" <<EOF line.

Confirm that the outer if and nested if each have their own closing fi.

Ask for help with the service branch.

Capture recent journal warnings

The overall service state tells you whether to investigate. Recent journal messages provide evidence that can point toward the cause.

How will the journal pipeline work?

The availability check looks for journalctl. The -p warning option selects warning entries with more severe priorities.

The pipe operator | sends journal output into tail. The -n 10 option keeps the latest ten lines from that input.

The existing set -o pipefail setting preserves a non-zero status from the rightmost failing command in a pipeline. This keeps pipeline failures visible to Bash.

Journal access depends on the current user's permissions. The report captures only entries that the current user can read.

  • Find the closing fi for the service-health block.
  • Copy this journal logic directly below it:
if command -v journalctl >/dev/null 2>&1; then
  journal_warnings="$(SYSTEMD_PAGER=cat journalctl -p warning 2>&1 | tail -n 10)"
  if [[ -z "$journal_warnings" ]]; then
    journal_warnings="No accessible warning-or-higher journal entries were returned."
  fi
else
  journal_warnings="journalctl is not available on this machine."
fi

What does this code do?

  • The available branch captures the pipeline output in journal_warnings.
  • The empty-string check replaces a blank result with an explicit message.
  • The fallback branch records that journalctl is unavailable.
  • The pager setting keeps captured output suitable for a generated file.
  • Find the closing text fence for the Failed Units section inside the report here-document.
  • Copy this journal section below that fence:
## Recent Accessible Warning-or-Higher Journal Entries

~~~text
$journal_warnings
~~~

Why label the entries accessible?

The current user might have access to only part of the system journal. The heading states that limit without asking the learner to elevate privileges.

  • Save monitor.sh.

Before the final run, do you expect live journal lines, an empty-result message, or an unavailable message on this machine?

The complete bash monitor.sh run now collects resources, applies the disk policy, checks service health, and captures accessible journal evidence.

  • Generate the completed health report by running this command:
bash monitor.sh

What should the terminal show?

The terminal prints Created reports/health-report.md. That message confirms the script reached the final echo after replacing the report.

The final inspection command uses code to open the generated file. The path points to the report inside the existing reports directory.

  • Inspect the completed report by running this command:
code reports/health-report.md

What should the completed report contain?

  • The Findings section shows a disk PASS or WARNING.
  • The same section shows the overall systemd finding.
  • The systemd Health section shows the state with failed-unit evidence.
  • The final section shows the latest ten accessible warning-or-higher journal lines or an explicit fallback message.

That is the diagnostic layer working. Your report now tells another operator where attention may be needed.

Missing journal evidence?

Confirm that the journal logic sits before the report here-document. The journal_warnings variable must be assigned before Bash expands it.

Check that the pipeline contains the pipe between journalctl -p warning 2>&1 and tail -n 10.

Ask for help with the journal pipeline.

Your monitor now produces findings with service and journal evidence. Capture this diagnostic milestone before the documentation handoff.

  • Create a checkpoint for the completed monitor and its latest report by running these commands:
git add monitor.sh reports/health-report.md
git commit -m "Add diagnostic findings and logs"
git status

What does this checkpoint record?

  • The git add command stages the completed monitor and its evidence.
  • The git commit command records the disk findings, systemd health, and journal support.
  • The git status command checks that the checkpoint includes every saved change.

You should see a commit summary followed by a clean working tree. The completed diagnostic monitor now has its own recoverable Git version.

Commit not created?

Save monitor.sh before rerunning the commands. Regenerate reports/health-report.md if Git shows only the script as changed.

Help me troubleshoot the diagnostic monitor commit.

✔️ Awesome, I've got everything!

Great work. Save monitor.sh before moving on.

ⓧ I'd like to double check the full code

set -u
set -o pipefail

REPORT_DIR="reports"
REPORT_FILE="$REPORT_DIR/health-report.md"
DISK_WARNING_PERCENT=80

mkdir -p "$REPORT_DIR"

os_release_file=""
if [[ -r /etc/os-release ]]; then
  os_release_file="/etc/os-release"
elif [[ -r /usr/lib/os-release ]]; then
  os_release_file="/usr/lib/os-release"
fi

if [[ -n "$os_release_file" ]]; then
  . "$os_release_file"
fi

os_name="${PRETTY_NAME:-Linux}"
generated_at="$(date)"
host_name="${HOSTNAME:-unknown}"
kernel_summary="$(uname -sr)"
uptime_summary="$(uptime -p 2>&1)"
memory_summary="$(free -h 2>&1)"
filesystem_summary="$(df -hP -x tmpfs -x devtmpfs -x squashfs 2>&1)"

disk_findings=""
disk_table="$(df --output=pcent,target -x tmpfs -x devtmpfs -x squashfs 2>&1)"

while read -r use_percent target; do
  if [[ "$use_percent" == "Use%" ]]; then
    continue
  fi

  usage="${use_percent%\%}"
  if [[ "$usage" =~ ^[0-9]+$ ]] && (( usage >= DISK_WARNING_PERCENT )); then
    disk_findings+="- WARNING: ${target} is ${usage}% full. Project threshold: ${DISK_WARNING_PERCENT}%."$'\n'
  fi
done <<< "$disk_table"

if [[ -z "$disk_findings" ]]; then
  disk_findings="- PASS: All reported filesystems are below the ${DISK_WARNING_PERCENT}% project threshold."
fi

if command -v systemctl >/dev/null 2>&1; then
  system_state="$(systemctl is-system-running 2>&1)"
  failed_units="$(SYSTEMD_PAGER=cat systemctl list-units --state=failed 2>&1)"

  if [[ "$system_state" == "running" ]]; then
    system_finding="- PASS: systemd reports the system state as running."
  else
    system_finding="- WARNING: systemd reports the system state as ${system_state}. Review the failed-unit section."
  fi
else
  system_state="unavailable"
  failed_units="systemctl is not available on this machine."
  system_finding="- INFO: systemd checks are unavailable; resource reporting still completed."
fi

if command -v journalctl >/dev/null 2>&1; then
  journal_warnings="$(SYSTEMD_PAGER=cat journalctl -p warning 2>&1 | tail -n 10)"
  if [[ -z "$journal_warnings" ]]; then
    journal_warnings="No accessible warning-or-higher journal entries were returned."
  fi
else
  journal_warnings="journalctl is not available on this machine."
fi

cat > "$REPORT_FILE" <<EOF
# Linux Infrastructure Health Report

Generated: $generated_at

## Findings

$disk_findings
$system_finding

## Host

- Hostname: $host_name
- Operating system: $os_name
- Kernel: $kernel_summary
- Uptime: $uptime_summary

## Memory

~~~text
$memory_summary
~~~

## Filesystems

~~~text
$filesystem_summary
~~~

## systemd Health

- Overall state: $system_state

### Failed Units

~~~text
$failed_units
~~~

## Recent Accessible Warning-or-Higher Journal Entries

~~~text
$journal_warnings
~~~
EOF

echo "Created $REPORT_FILE"

Your monitor now converts raw Linux state into findings with supporting evidence. Next, you will write the README and runbook that help another administrator operate it safely.

Write the Runbook and Version the Result

Your Bash utility now converts live Linux state into a structured Markdown health snapshot. Another operator still needs a reliable handoff.

You will create a README and an operational runbook in Visual Studio Code. These documents explain how to run the monitor and interpret its findings.

You will regenerate the final report. You will then preserve the complete result in Git.

In this step, get ready to:
  • Document the repository purpose and report coverage in README.md.
  • Write an operational runbook with interpretation guidance and follow-up commands.
  • Regenerate the report and commit the complete repository to Git.
Document the repository

A README gives another administrator a quick entry point into the repository. It should answer what the project does and where its important files live.

  • Return to the linux-health-report workspace in Visual Studio Code.
  • Select the linux-health-report folder in the Explorer sidebar.
  • Click the New File control in the Explorer sidebar.
  • Enter README.md as the file name.
  • Press Enter.
  • Add the project overview and run instructions by pasting this first section:
# Linux Infrastructure Health Report

This repository contains a Bash-based health snapshot and the runbook needed to interpret it.

## Repository Layout

- `monitor.sh`: collects current host and resource data and writes the report
- `reports/health-report.md`: generated report for the current machine
- `docs/runbook.md`: operating and troubleshooting guidance

## Run

~~~sh
bash monitor.sh
~~~

Command breakdown:

- `bash` starts the Bash interpreter.
- `monitor.sh` is the script file Bash reads and executes.

The terminal should print `Created reports/health-report.md`.

What does this section document?

  • The opening sentence identifies the repository as a Bash-based health snapshot.
  • The repository layout gives each important file a clear operational purpose.
  • The run section gives the command that regenerates the report.
  • The command breakdown explains that bash starts the interpreter. It also explains that monitor.sh is the script Bash executes.
  • Save README.md.
  • Select the Markdown preview control in the top-right corner of the editor.

You should see the report title followed by the repository layout and a formatted Run section.

README Preview Missing Sections?

Confirm that you pasted the content into README.md. Check that the opening heading begins with one hash character.

Make sure each command fence uses three tilde characters. Help me fix the formatting in my README preview.

The second half of the README tells readers what evidence the report contains. It also records the graceful fallback for machines where systemd is unavailable.

  • Return to the README.md editor tab.
  • Place your cursor after the line describing the expected terminal output.
  • Add the report coverage and sharing guidance by pasting this section:
## What the Report Covers

- Host, operating system, kernel, and uptime
- Memory and filesystem usage
- Disk findings using an 80 percent project threshold
- Overall systemd state and failed-unit details when systemd is available
- The ten most recent accessible warning-or-higher journal entries

If systemd is unavailable or is not the active service manager, the report records that limitation and still completes the resource sections.

Review the generated report before sharing because it can contain hostnames, mount paths, service names, and log messages.

Why include report coverage?

The coverage list sets expectations before an administrator runs the monitor. The fallback note confirms that resource reporting still completes when service-manager checks are unavailable.

The final warning treats the generated report as operational data. A sharing review protects machine details that should remain private.

  • Save README.md.
  • Return to the Markdown preview.

You should now see a What the Report Covers section with five coverage items and a sharing warning.

Coverage Section in the Wrong Place?

Confirm that the new section comes after the expected terminal-output sentence. Add a blank line before its heading if the preview merges it into the previous paragraph.

Check that all five coverage lines begin with a hyphen. Help me repair the section order in README.md.

✔️ Awesome, I've got everything!

Your README now explains the project purpose, repository layout, run command, report coverage, fallback behavior, and sharing risk.

ⓧ I'd like to double check the full code

# Linux Infrastructure Health Report

This repository contains a Bash-based health snapshot and the runbook needed to interpret it.

## Repository Layout

- `monitor.sh`: collects current host and resource data and writes the report
- `reports/health-report.md`: generated report for the current machine
- `docs/runbook.md`: operating and troubleshooting guidance

## Run

~~~sh
bash monitor.sh
~~~

Command breakdown:

- `bash` starts the Bash interpreter.
- `monitor.sh` is the script file Bash reads and executes.

The terminal should print `Created reports/health-report.md`.

## What the Report Covers

- Host, operating system, kernel, and uptime
- Memory and filesystem usage
- Disk findings using an 80 percent project threshold
- Overall systemd state and failed-unit details when systemd is available
- The ten most recent accessible warning-or-higher journal entries

If systemd is unavailable or is not the active service manager, the report records that limitation and still completes the resource sections.

Review the generated report before sharing because it can contain hostnames, mount paths, service names, and log messages.
Write the operational runbook

The README gets an operator started. The runbook helps that operator interpret findings and choose a safe next check.

  • Return to the Explorer sidebar.
  • Expand the existing docs directory.
  • Select the docs directory.
  • Click the New File control in the Explorer sidebar.
  • Enter runbook.md as the file name.
  • Press Enter.
  • Add the runbook purpose and generation instructions by pasting this first section:
# Linux Health Report Runbook

## Purpose

Use this runbook to generate and interpret a point-in-time health report for one Linux machine.

## Generate a Fresh Report

From the repository root, run:

~~~sh
bash monitor.sh
~~~

Command breakdown:

- `bash` starts the Bash interpreter.
- `monitor.sh` is the script file Bash reads and executes.

The command replaces `reports/health-report.md` with current data.

What does this runbook establish?

  • The Purpose section defines the report as a point-in-time view of one Linux machine.
  • The generation section tells the operator where to run the monitor.
  • The command breakdown explains both words in the run command.
  • The final sentence warns that each run replaces the previous report with current data.
  • Save docs/runbook.md.
  • Select the Markdown preview control in the top-right corner of the editor.

You should see a Linux Health Report Runbook title followed by Purpose and Generate a Fresh Report sections.

Runbook Preview Empty?

Confirm that runbook.md sits inside the docs directory. Save the file before reopening its preview.

Check that the command fence has matching opening and closing tildes. Help me fix the first part of docs/runbook.md.

Interpretation guidance converts status labels into decisions. It tells the operator which findings are healthy and which findings require investigation.

  • Return to the docs/runbook.md editor tab.
  • Place your cursor after the sentence about replacing the generated report.
  • Add the interpretation guidance by pasting this section:
## Interpret the Findings

- A disk PASS means every reported filesystem is below the project threshold.
- A disk WARNING identifies a mount at or above the project threshold. Confirm growth and available space before deleting data.
- A systemd state of `running` means the manager reports the system as fully operational.
- A different systemd state needs investigation. Read the failed-unit section and relevant journal messages.
- An unavailable systemd result means the machine does not expose the expected tools or systemd is not active. Resource sections are still valid.

How should an operator use this guidance?

Disk PASS and WARNING findings apply the fixed project policy to each reported filesystem. A warning begins an investigation before any files are removed.

The systemd guidance separates a healthy state from degraded or unavailable checks. Resource data remains useful even when service-manager evidence is limited.

  • Save docs/runbook.md.
  • Return to the Markdown preview.

You should see five interpretation points covering disk findings and systemd states.

Interpretation Bullets Not Rendering?

Add a blank line after the Interpret the Findings heading. Confirm that each interpretation begins with one hyphen.

Make sure the running value keeps its surrounding backticks. Help me fix the interpretation list.

Follow-up commands turn a warning into a focused investigation. Each command needs a nearby explanation so another administrator can understand it before running it.

  • Return to the docs/runbook.md editor tab.
  • Place your cursor after the final interpretation point.
  • Add the uptime follow-up command and its breakdown by pasting this section:
## Follow-Up Commands

Check uptime and load:

~~~sh
uptime -p
~~~

Command breakdown:

- `uptime` reports how long the system has been running and includes load information in its normal output.
- `-p` requests a human-friendly uptime description.

What does the uptime command mean?

  • The uptime command reports how long the machine has been running.
  • The -p option requests a readable uptime description.
  • The runbook also notes that normal uptime output includes load information.
  • Save docs/runbook.md.
  • Return to the Markdown preview.

You should see a Follow-Up Commands heading with a formatted uptime command and two explanation bullets.

Uptime Command Outside Its Fence?

Confirm that uptime -p sits between matching tilde fences. Keep a blank line between the fence and Command breakdown.

Check that the Follow-Up Commands heading uses two hash characters. Help me repair the uptime section.

  • Return to the docs/runbook.md editor tab.
  • Place your cursor after the uptime command breakdown.
  • Add the memory follow-up command and its breakdown by pasting this section:
Check memory:

~~~sh
free -h
~~~

Command breakdown:

- `free` displays used and available system memory.
- `-h` formats byte values with readable units.

What does the memory command mean?

  • The free command displays used and available system memory.
  • The -h option converts byte values into readable units.
  • Save docs/runbook.md.
  • Return to the Markdown preview.

You should see a Check memory label with a formatted command and two explanation bullets.

Memory Breakdown Merged Together?

Keep a blank line before Command breakdown. Confirm that both explanation lines begin with a hyphen.

Make sure the -h option remains inside backticks. Help me fix the memory section.

  • Return to the docs/runbook.md editor tab.
  • Place your cursor after the memory command breakdown.
  • Add the filesystem follow-up command and its breakdown by pasting this section:
Check filesystems:

~~~sh
df -h
~~~

Command breakdown:

- `df` reports used and available filesystem space.
- `-h` formats sizes with readable units.

What does the filesystem command mean?

  • The df command reports used and available filesystem space.
  • The -h option formats filesystem sizes with readable units.
  • Save docs/runbook.md.
  • Return to the Markdown preview.

You should see a Check filesystems label with its formatted command and breakdown.

Filesystem Section Missing?

Confirm that the filesystem section follows the memory breakdown. Check that df -h has its own complete command fence.

Keep the command explanation outside the fence. Help me restore the filesystem section.

  • Return to the docs/runbook.md editor tab.
  • Place your cursor after the filesystem command breakdown.
  • Add the failed-unit follow-up command and its breakdown by pasting this section:
List failed systemd units:

~~~sh
systemctl list-units --state=failed
~~~

Command breakdown:

- `systemctl` communicates with the systemd service manager.
- `list-units` requests the units currently known to systemd.
- `--state=failed` filters the result to units in the failed state.

What does the failed-unit command mean?

  • The systemctl command communicates with the systemd service manager.
  • The list-units subcommand requests known units.
  • The --state=failed option filters the result to failed units.
  • Save docs/runbook.md.
  • Return to the Markdown preview.

You should see the failed-unit command followed by explanations for the command name, subcommand, and filter.

Failed-Unit Filter Wrapped Incorrectly?

Keep the full failed-unit command on one line inside its fence. Confirm that the option uses two leading hyphens.

Check that all three breakdown lines remain separate bullets. Help me fix the failed-unit command section.

  • Return to the docs/runbook.md editor tab.
  • Place your cursor after the failed-unit command breakdown.
  • Add the journal follow-up command and its breakdown by pasting this section:
Read warning-or-higher journal entries:

~~~sh
journalctl -p warning
~~~

Command breakdown:

- `journalctl` reads entries from the systemd journal.
- `-p warning` selects the warning priority and more severe priorities.

What does the journal command mean?

  • The journalctl command reads systemd journal entries.
  • The -p warning option selects warnings and more severe priorities.
  • Save docs/runbook.md.
  • Return to the Markdown preview.

You should see the journal command followed by a two-part explanation of its command name and priority option.

Journal Option Split Across Lines?

Keep -p warning together inside one pair of backticks in the breakdown. Keep the complete command on one line inside its fence.

Add a blank line after the command fence if the breakdown joins the code block. Help me repair the journal section.

The runbook ends with guardrails for escalation and sharing. These notes keep an operator from taking a destructive action without understanding the workload.

  • Return to the docs/runbook.md editor tab.
  • Place your cursor after the journal command breakdown.
  • Complete the runbook by pasting these final sections:
## Escalation Notes

Record the affected mount or unit, the observation time, the matching journal messages, and any action taken. Do not restart services or remove files until you understand the workload and recovery path.

## Sharing Safety

Before attaching the report to a ticket or repository, review it for hostnames, mount paths, usernames, service names, and log content that should remain private.

Why end with safety guidance?

The escalation note preserves evidence before an operator changes the system. It also blocks impulsive restarts or file deletion.

The sharing note lists the operational details that need review. This gives the administrator a concrete privacy check before distribution.

  • Save docs/runbook.md.
  • Return to the Markdown preview.

You should see Escalation Notes and Sharing Safety as the final two sections of the runbook.

Final Sections Joined Together?

Keep a blank line before each level-two heading. Confirm that Escalation Notes comes before Sharing Safety.

Check that both headings begin with two hash characters. Help me fix the final runbook sections.

✔️ Awesome, I've got everything!

Your runbook now covers operation, interpretation, investigation, escalation, and sharing safety.

ⓧ I'd like to double check the full code

# Linux Health Report Runbook

## Purpose

Use this runbook to generate and interpret a point-in-time health report for one Linux machine.

## Generate a Fresh Report

From the repository root, run:

~~~sh
bash monitor.sh
~~~

Command breakdown:

- `bash` starts the Bash interpreter.
- `monitor.sh` is the script file Bash reads and executes.

The command replaces `reports/health-report.md` with current data.

## Interpret the Findings

- A disk PASS means every reported filesystem is below the project threshold.
- A disk WARNING identifies a mount at or above the project threshold. Confirm growth and available space before deleting data.
- A systemd state of `running` means the manager reports the system as fully operational.
- A different systemd state needs investigation. Read the failed-unit section and relevant journal messages.
- An unavailable systemd result means the machine does not expose the expected tools or systemd is not active. Resource sections are still valid.

## Follow-Up Commands

Check uptime and load:

~~~sh
uptime -p
~~~

Command breakdown:

- `uptime` reports how long the system has been running and includes load information in its normal output.
- `-p` requests a human-friendly uptime description.

Check memory:

~~~sh
free -h
~~~

Command breakdown:

- `free` displays used and available system memory.
- `-h` formats byte values with readable units.

Check filesystems:

~~~sh
df -h
~~~

Command breakdown:

- `df` reports used and available filesystem space.
- `-h` formats sizes with readable units.

List failed systemd units:

~~~sh
systemctl list-units --state=failed
~~~

Command breakdown:

- `systemctl` communicates with the systemd service manager.
- `list-units` requests the units currently known to systemd.
- `--state=failed` filters the result to units in the failed state.

Read warning-or-higher journal entries:

~~~sh
journalctl -p warning
~~~

Command breakdown:

- `journalctl` reads entries from the systemd journal.
- `-p warning` selects the warning priority and more severe priorities.

## Escalation Notes

Record the affected mount or unit, the observation time, the matching journal messages, and any action taken. Do not restart services or remove files until you understand the workload and recovery path.

## Sharing Safety

Before attaching the report to a ticket or repository, review it for hostnames, mount paths, usernames, service names, and log content that should remain private.
Commit the completed handoff

The documentation now explains how to operate the monitor. A final run makes the generated evidence current before Git records the repository.

Before you run the monitor, do you expect the report timestamp and live machine data to stay unchanged?

  • Regenerate the current health report by running this command:
bash monitor.sh

What does this command do?

  • The bash executable starts the Bash interpreter.
  • The monitor.sh argument tells Bash which script file to read and execute.
  • The script replaces reports/health-report.md with a fresh snapshot from the current machine.
  • Confirm that the terminal returns to its prompt.
  • Select reports/health-report.md in the Explorer sidebar.
  • Review the Findings section for the current disk and systemd results.
  • Review the report for hostnames and operational details before committing it.

You should see Created reports/health-report.md in the terminal. The report should contain current host data and a disk PASS or WARNING finding.

Report Not Regenerated?

Confirm that the terminal is still inside the linux-health-report repository. Check that monitor.sh appears in the Explorer sidebar.

Compare the command with the run command documented in your README. Help me troubleshoot the final monitor run.

The staging area collects the exact file versions that the next commit records. Using a dot stages the repository content beneath your current location.

  • Stage the monitoring script, documentation, and generated report by running this command:
git add .

What does this command do?

  • The git executable runs Git.
  • The add subcommand copies new and changed content into the staging area.
  • The . argument represents the current repository directory and its contents.

The command returns to the prompt without printing a success message. The repository content is now staged for the commit.

Git Add Failed?

Confirm that your terminal is inside the Git-initialized linux-health-report repository. A different directory will not contain the repository metadata.

Check that a space separates add from the dot. Help me troubleshoot staging this repository.

A commit stores the staged snapshot in the repository history. The message gives that snapshot a short description.

  • Commit the staged project with a descriptive message by running this command:
git commit -m "Document Linux health report"

What does this command do?

  • The git executable runs Git.
  • The commit subcommand records the current staging-area contents.
  • The -m option supplies the commit message from the terminal.
  • The quoted text is the message attached to this repository snapshot.

You should see a commit summary with a commit identifier and counts for the recorded files. Your script, documentation, and generated evidence now share one versioned snapshot.

Commit Rejected?

If Git asks for an identity, return to the local name and email configuration you checked earlier. The repository needs that identity before it can create a commit.

If Git reports no staged changes, confirm that README.md and docs/runbook.md are saved. Help me troubleshoot the final Git commit.

Before the final check, do you expect Git to find any changes outside the commit?

  • Verify the final repository state by running this command:
git status

What does this command show?

  • The git executable runs Git.
  • The status subcommand compares the latest commit with the staging area and working tree.
  • A clean result confirms that every saved project file is included in the commit.

You should see that there are no remaining changes to commit. That clean working tree confirms the monitoring script, current report, README, and runbook are versioned together.

Working Tree Still Has Changes?

Read the status output to identify the remaining file. Save that file if Visual Studio Code still shows an unsaved-change indicator.

Stage the corrected file before creating another commit. Help me reach a clean Git working tree.

That is the operational handoff complete. Another administrator can now run the monitor, interpret its findings, investigate warnings, and review the report safely.

Secret mission

Make the Disk Policy Configurable

Turn the fixed disk threshold into a validated command-line option. You will preserve the default policy while letting an operator generate the report with a threshold that fits the machine.

Clean Up Your Resources

Clean Up Your Resources

This local monitoring project has no ongoing costs. Choose whether to keep the repository available, pause your work, or delete it entirely.

Resources you used:

  • The local linux-health-report Git repository.
  • The monitor.sh Bash utility inside linux-health-report.
  • The generated reports/health-report.md file inside linux-health-report.
  • The README.md documentation inside linux-health-report.
  • The docs/runbook.md documentation inside linux-health-report.

Keep everything running

No action is needed. Choose this if you are still using the report or refining its configurable disk policy.

  • Keep the linux-health-report folder on your machine.
  • Review reports/health-report.md for sensitive operational details before sharing it.

Pause - I'll come back to this later

The monitor exits after writing the report. Pausing means closing your Visual Studio Code workspace while preserving the repository.

  • Save any unsaved project files in Visual Studio Code.
  • Close the Visual Studio Code window that contains linux-health-report.
  • Leave the linux-health-report folder on your machine for your next session.

Delete - I don't want to use this again

Remove the local repository if you no longer need the monitor or its documentation. This also removes the generated report with its tested 70 percent threshold.

  • Close the Visual Studio Code window that contains linux-health-report.
  • Switch back to the terminal from earlier.

The cd command changes the terminal's current directory. The .. value identifies the folder directly above linux-health-report.

  • Move to the parent folder by running this command:
cd ..

What Did This Command Do?

The terminal now works from the folder containing linux-health-report. This position lets you remove the repository as one complete directory.

The rm command removes local files or directories. The command below names only the linux-health-report directory.

The -r option includes nested directories. The -f option suppresses confirmation prompts.

Deletion Is Permanent

Deleting the repository permanently removes the script, report, documentation, Git history, and Secret Mission changes. Take a moment to confirm that you no longer need those files.

  • Delete the complete linux-health-report repository by running this command:
rm -rf linux-health-report

What Did This Command Do?

The command removes linux-health-report with every file inside it. Other items in the parent folder remain untouched.

The ls command lists the items that remain in the current parent folder.

  • Confirm the repository is gone by running this command:
ls

What Should I See?

You should see the remaining items in the parent folder. You should no longer see linux-health-report.

Still See the Repository?

Confirm that the terminal moved out of linux-health-report before you ran the removal command. A permissions restriction can also prevent deletion.

Ask for help checking the current directory before trying another removal command.

Nice Work!

Nice Work!

Strong finish! You've built a Bash utility that converts live Linux state into a structured Markdown report. Another administrator can now run the audit without reverse-engineering your commands.

You've learned how to:

  • Generate a repeatable health snapshot containing host identity, kernel details, uptime, memory usage, and filesystem usage.
  • Turn raw system data into actionable findings for disk pressure, systemd health, failed units, and accessible journal warnings.
  • Preserve the script, generated report, README, and operational runbook in Git so another administrator can run, interpret, troubleshoot, and safely share the audit.
  • Complete the optional Secret Mission by adding a validated --disk-warning option that accepts thresholds from 1 through 100 while preserving the default run path.

Ready to quiz yourself?