Hardware Health
Watch the physical health of your servers from Monitor → Hardware (keyboard shortcut g h): SMART data
from disks, ECC memory errors, temperatures, fans, power supplies and network cards, plus
hardware events from the kernel log and the BMC. Available since LogTide 1.7.0, open source.
Prefer a walkthrough? Follow the step-by-step tutorial Monitor a home server's disks, RAM and fans with LogTide.
Overview
Hardware Health is early warning, not prediction. It reads the signals that hardware gives out before it fails (reallocated sectors, corrected memory errors, a fan slowing down, a PCIe link retraining) and turns them into a status per host and per component, with an incident and a notification when something gets worse.
A small agent runs on each server and sends two things to your LogTide project:
- Metrics named
hw.*, sent as OTLP gauges toPOST /v1/otlp/metrics. - Events from the kernel log and the BMC event log, sent as logs with service
hardware.
LogTide registers each host the first time it sees hw.* metrics from it,
evaluates it every two minutes and shows the result on Monitor → Hardware.
Nothing else is needed: the agent uses the same project API key as your logs.
Disks
HDD, SATA SSD and NVMe: SMART status and attributes, NVMe spare and media errors, wear, temperature.
Memory
Corrected and uncorrected ECC errors per memory controller, read from the kernel EDAC subsystem.
CPU and cooling
CPU temperature against its limits, thermal throttling, and fan speeds from the motherboard or the BMC.
Power and network
PSU status and voltages from the BMC, link flaps and error counters on physical network cards.
What It Can and Cannot See
Keep your backups
SMART does not catch every failing disk. Studies of large disk fleets (Google, Backblaze) found that roughly a third of drives that fail show no SMART warning beforehand. A green status here means no known warning signs, not that the hardware is guaranteed healthy.
- Bare metal, homelab and on-premises servers are the target. Disks, board sensors, EDAC and a BMC are all visible there.
- Virtual machines and most cloud instances expose no hardware sensors. The agent detects virtualization and reports it. Such hosts get a VM badge and the status No sensors instead of a health status, and the host page explains that sensors are not available. Run the agent on the hypervisor host, not inside the guests.
- A host that goes completely dark shows as stale. If no
hw.*data point arrives for more than 10 minutes, the host is marked stale. A stale host is shown but does not open an incident. To be told when a machine dies or loses power, pair it with a heartbeat monitor from Uptime that the server pings on a schedule. - Not covered in this release: RAID controller tools (MegaCLI, storcli), UPS (NUT), Redfish, per-host custom thresholds, and Windows or macOS hosts.
Requirements
- LogTide 1.7.0 or later (self-hosted or Cloud) and a project API key.
- A Linux host. The agent is a single Python 3 script with no dependencies.
smartmontoolsfor disk data. Included in the Docker image.ipmitooland a BMC (iDRAC, iLO, IPMI) for PSU, voltage and sensor data from the board. Optional, included in the Docker image.- The EDAC kernel modules loaded for ECC memory counters (
/sys/devices/system/edac/mcmust exist). Needs ECC RAM and a supporting platform. - Root or a privileged container, because SMART, IPMI and
/dev/kmsgneed it. See Permissions.
Each collector is independent. A host without a BMC still reports disks, memory and temperatures; the missing collector is listed as unavailable on the host page.
Install the Agent
Create a project API key first (Project settings → API keys). Use a
dedicated key for hardware agents so you can rotate it separately. The examples use the
LogTide Cloud API URL; for a self-hosted instance set LOGTIDE_URL to your own
API base URL.
The agent lives in its own repository,
logtide-dev/logtide-hw-agent
(MIT license), and is versioned separately from LogTide. Agent 1.x works with LogTide 1.7.0
and later. The Docker image is logtide/hw-agent.
Docker Compose
If the host that runs LogTide is the machine you want to monitor, enable the
hardware profile of the LogTide compose file. Put the key in
.env and start the profile:
# docker/.env
HW_AGENT_API_KEY=lp_your_ingestion_key_here
docker compose --profile hardware up -d
If HW_AGENT_API_KEY is empty, FLUENT_BIT_API_KEY is used. With
neither set, every request is rejected with 401 while the container still looks healthy.
The service is called hw-agent, runs privileged, and talks to the backend over
the compose network. Use HW_AGENT_IMAGE to pin a different image.
Standalone Docker
For every other server, run the agent as a single container and point it at your LogTide API with your own URL and key:
docker run -d --name logtide-hw-agent --restart unless-stopped --privileged \
-e LOGTIDE_URL=https://api.logtide.dev \
-e LOGTIDE_API_KEY=lp_your_key \
-e HOST_ROOT=/host \
-v /sys:/host/sys:ro \
-v /proc:/host/proc:ro \
-v /etc/hostname:/host/etc/hostname:ro \
-v logtide-hw-agent-state:/var/lib/logtide-hw-agent \
logtide/hw-agent:latest
The mounts and --privileged are explained under Permissions.
systemd
Without Docker, run the single-file agent as a systemd service. The example is for
Debian and Ubuntu; install ipmitool only on servers with a BMC.
sudo apt install -y python3 smartmontools ipmitool
sudo install -d /opt/logtide-hw-agent /etc/logtide
sudo curl -fsSL https://raw.githubusercontent.com/logtide-dev/logtide-hw-agent/main/logtide_hw_agent.py \
-o /opt/logtide-hw-agent/logtide_hw_agent.py
sudo curl -fsSL https://raw.githubusercontent.com/logtide-dev/logtide-hw-agent/main/logtide-hw-agent.service \
-o /etc/systemd/system/logtide-hw-agent.service
sudo tee /etc/logtide/hw-agent.env >/dev/null <<'ENV'
LOGTIDE_URL=https://api.logtide.dev
LOGTIDE_API_KEY=lp_your_key
ENV
sudo chmod 600 /etc/logtide/hw-agent.env
sudo systemctl daemon-reload
sudo systemctl enable --now logtide-hw-agent
The service runs as root and keeps its state in
/var/lib/logtide-hw-agent. Read its log with
journalctl -u logtide-hw-agent -f.
Verify
Before leaving the agent running, do a dry run. It collects once, prints the payloads and sends nothing, so you can see which collectors work on this machine:
# Docker
docker run --rm --privileged -e HOST_ROOT=/host -e LOGTIDE_HW_DRY_RUN=1 \
-v /sys:/host/sys:ro -v /proc:/host/proc:ro -v /etc/hostname:/host/etc/hostname:ro \
logtide/hw-agent:latest --once
# systemd
sudo sh -c 'set -a; . /etc/logtide/hw-agent.env; LOGTIDE_HW_DRY_RUN=1 python3 /opt/logtide-hw-agent/logtide_hw_agent.py --once'
Without LOGTIDE_HW_DRY_RUN, --once collects, sends one real batch
and exits with code 1 if delivery failed. That is the quickest way to test the URL and the
key. Then open Monitor → Hardware: the host appears within a minute or two.
Configuration
The agent is configured with environment variables.
| Variable | Default | Description |
|---|---|---|
LOGTIDE_URL | required | Base URL of the LogTide API, for example http://backend:8080. |
LOGTIDE_API_KEY | required | Project API key, sent as X-API-Key. |
LOGTIDE_HOSTNAME | $HOST_ROOT/etc/hostname, else the system hostname | Value of host.name, the name shown in Monitor → Hardware. |
HOST_ROOT | empty | Prefix for /sys, /proc and /etc reads. Set to /host in the container. |
LOGTIDE_HW_INTERVAL | 60 | Seconds between collections (minimum 5). |
LOGTIDE_HW_COLLECTORS | all | Comma-separated list of smart,edac,hwmon,thermal,ipmi,sel,net,kmsg. Use it to switch collectors off. |
LOGTIDE_HW_STATE_DIR | /var/lib/logtide-hw-agent | Where the last BMC event id is stored. |
LOGTIDE_HW_DRY_RUN | off | 1 prints payloads to stdout instead of sending them. |
LOGTIDE_HW_KMSG_PATH | /dev/kmsg | Kernel log device. Only useful for testing. |
The command line flag --once runs one collection, sends it and exits. In the
compose stack the agent reads HW_AGENT_API_KEY and HW_AGENT_IMAGE
from .env.
Permissions
The agent runs as root because SMART queries, /dev/kmsg and
/dev/ipmi0 need raw device access. It only reads: it does not write to disks,
change fan settings or modify the BMC. In the container, the setup is:
-
/sysand/procare mounted read-only under/hostand read throughHOST_ROOT. The container's own/sys/class/netonly shows the container's network namespace, so NIC counters would be wrong without the host mount. -
--privilegedgives the container the host's/dev(SATA and NVMe disks,/dev/kmsg,/dev/ipmi0) and the capabilitiessmartctlneeds. -
The
/etc/hostnamemount makes the host name match the real host instead of the container id. You can setLOGTIDE_HOSTNAMEinstead. - The state volume keeps the BMC event log position across restarts, so old events are not sent again.
Without --privileged you need --cap-add SYS_RAWIO --cap-add SYS_ADMIN
--cap-add SYSLOG plus one --device per disk (/dev/sda,
/dev/nvme0), --device /dev/kmsg, and --device /dev/ipmi0
if present. This is more fragile, because seccomp and AppArmor profiles vary between
distributions, and privileged is the tested path.
What Is Collected
Every data point carries the attributes host.name, hw.type and
hw.id (the device, sensor or controller it belongs to). All metrics are gauges.
For disks, hw.id is the drive's serial number (or its /dev/disk/by-id name when there is none), not sda, so a drive keeps its history when the kernel renames it after a reboot; the current kernel name is in the device attribute.
Counters such as error totals are sent as the raw cumulative value, and LogTide works on the
growth over a window, so a reboot that resets a counter does not look like an improvement or
a spike.
| Metric | Unit | Extra attributes | Source |
|---|---|---|---|
hw.host.info | 1 | hw.virtual, hw.vendor, hw.model, os.kernel, agent.version | DMI, /proc |
hw.agent.collector.status | 1 / 0 | collector: smart, edac, hwmon, ipmi, net, thermal, kmsg, sel | Agent |
hw.physical_disk.smart_status | 1 ok / 0 failed | device, model, serial, protocol (ata, nvme, scsi) | smartctl |
hw.physical_disk.smart | raw value | smart_attribute: reallocated_sector_count, current_pending_sector, offline_uncorrectable, reported_uncorrect, udma_crc_error_count, command_timeout, reallocated_event_count, power_on_hours | smartctl (ATA) |
hw.physical_disk.endurance_utilization | % | - | NVMe percentage used, ATA wear attributes |
hw.physical_disk.available_spare | % | - | NVMe |
hw.physical_disk.available_spare_threshold | % | - | NVMe |
hw.physical_disk.media_errors | count | - | NVMe |
hw.physical_disk.critical_warning | bitmask | - | NVMe |
hw.temperature | Cel | sensor; hw.type is cpu, physical_disk, memory, board, gpu or other | hwmon, smartctl, ipmitool |
hw.temperature.limit | Cel | sensor, limit_type (high, critical) | hwmon, ipmitool |
hw.fan.speed | rpm | sensor | hwmon, ipmitool |
hw.fan.speed.limit | rpm | sensor, limit_type (low.critical) | ipmitool |
hw.voltage | V | sensor | hwmon, ipmitool |
hw.voltage.limit | V | sensor, limit_type (low.critical, high.critical, low, high) | hwmon, ipmitool |
hw.power_supply.status | 1 / 0 | sensor | ipmitool |
hw.memory.errors | count (cumulative) | error_type (corrected, uncorrected); hw.id is the memory controller or DIMM label | EDAC |
hw.memory.size | By | - | /proc/meminfo |
hw.cpu.throttle_count | count (cumulative) | throttle_type (core, package) | sysfs thermal_throttle |
hw.network.errors | count (cumulative) | direction (receive, transmit), error_type (errors, crc, dropped) | sysfs, physical NICs only |
hw.network.carrier_changes | count (cumulative) | - | sysfs |
hw.network.up | 1 / 0 | speed_mbps | sysfs |
The metrics are ordinary OTLP metrics, so you can also chart them in the Metrics Explorer or
with a metric_chart panel on a custom dashboard.
Health Rules
Each host has six components: Disks, Memory,
CPU, Cooling, Power and
Network. A component is ok, warning,
critical or unknown (no data). The host status is the worst of its
components, or stale when the host stopped reporting. Every finding on the host page names the component, the device and the value that
crossed the threshold.
| Component | Warning | Critical |
|---|---|---|
| Disks | Any reallocated sector, pending sector or reported uncorrectable error. NVMe media errors grew in 7 days. UDMA CRC errors grew in 24 hours (usually a bad cable). Endurance used at 80% or more. Temperature at 55 C or more for HDD and SATA SSD, 70 C or more for NVMe. | SMART overall status failed. Offline uncorrectable sectors above 0. NVMe critical warning set. NVMe available spare below its threshold. Endurance used at 95% or more. Reallocated sectors grew by 10 or more in 7 days. Temperature at 65 C or more for HDD and SATA SSD, 80 C or more for NVMe. |
| Memory | Corrected ECC errors grew in the last 24 hours. | Any uncorrected ECC error since boot or in the last 7 days. Corrected errors grew by 100 or more in 24 hours (a DIMM degrading fast). |
| CPU | Temperature at or above the sensor's high limit. Thermal throttle count grew in 24 hours. | Temperature at or above the sensor's critical limit. When a sensor reports no limits, 85 C and 95 C are used. |
| Cooling | A board, memory or other (non-CPU, non-disk) temperature sensor at or above its own high limit. | A fan below its low-critical limit, or at 0 rpm after reporting a higher speed in the last 24 hours. A board, memory or other temperature sensor at or above its own critical limit. |
| Power | A voltage outside its low or high limit. | A power supply reporting failure. A voltage outside its low-critical or high-critical limit. |
| Network | CRC errors grew in 24 hours. 5 or more carrier changes (link flaps) in 24 hours. 100 or more errors in 24 hours. | - |
Two more checks raise a component to warning so that a silent failure is not
shown as healthy:
- Missing device. A disk, power supply, fan or network interface that
reported in the last 24 hours and is gone from the latest data (
disk.missing,power.psu_missing,cooling.fan_missing,network.interface_missing). A dead drive often disappears instead of reporting an error. - Collector down. A collector now reports 0 although its component had data
in the last 24 hours (
agent.collector_down), for example becausesmartctlstarted failing. The host page names the collector.
- Only physical network interfaces are evaluated. Bridges, VLANs, VPNs and container interfaces are ignored.
- Rules that look at growth need history. Right after you install the agent, growth-based findings can take up to 24 hours (or 7 days for the 7-day rules) to become meaningful.
- The thresholds are fixed in this release and shared by the backend and the UI. Per-host custom thresholds are not available yet.
Hardware Events
Besides metrics, the agent forwards hardware events as logs:
- Kernel log. The agent tails
/dev/kmsgfrom the moment it starts (no replay of old messages) and keeps only lines that look like hardware problems: disk I/O errors, ATA link resets, EDAC and machine check messages, PCIe AER errors, thermal throttling, NIC link changes. - BMC System Event Log. New entries from
ipmitool sel elistare forwarded once. The agent remembers the last entry it sent in its state directory.
Each event is a log with service hardware, the host name as hostname,
and metadata hw.event.source (kmsg or sel) and
hw.event.type (disk, memory, cpu,
pcie, power, thermal, network or
other). Kernel lines are at least warnings: priority 0 to 2 is
critical, 3 is error, anything else is warning. BMC entries are warnings, and critical when
the event mentions an uncorrectable error, a failure or a predictive failure. When the BMC
logs that a condition cleared (a Deasserted entry), the event is sent at info
level, with hw.sel.direction set to deasserted, and no detection
rule fires on it. BMC events also carry hw.sel.id and
hw.sel.timestamp. The host page lists the host's events from the last 7 days,
newest first, and you can search them in the log explorer by service
hardware.
Hardware Health Detection Pack
The Hardware Health Pack is a bundle of 21 Sigma rules, in the new
hardware pack category, that match hardware problems in kernel and BMC messages.
Open Alerts, choose Detection packs and enable it like any
other pack. Its detections show up in the recent detections on the Alerts page.
The rules match on the message text, case-insensitively and whatever the service name, so they fire on agent events and on plain kernel lines that reach LogTide some other way. If you already ship kernel logs through syslog, journald or Fluent Bit, the pack works without the agent; you just do not get the metrics and the host page. The rules carry no MITRE ATT&CK tags, because hardware faults are not attacks.
| Area | Rule (severity) | Matches messages such as |
|---|---|---|
| Memory | Corrected memory error (medium), Uncorrected memory error (critical) | EDAC lines with CE or UE, BMC Correctable ECC and Uncorrectable ECC |
| CPU | Machine check exception (high), APEI corrected (medium), recoverable (high) and fatal (critical), CPU IERR (critical) | mce: [Hardware Error], Machine check events logged, Hardware Error]: with an event severity, BMC IERR |
| Disk | Disk I/O error (high), ATA command failed (high), SATA link reset or down (medium), NVMe timeout or controller down (high), Drive fault from the BMC (high) | I/O error, dev, Buffer I/O error, Medium Error, failed command: READ FPDMA, hard resetting link, SATA link down, NVMe timeout and controller is down, Drive Fault |
| PCIe | Uncorrected error (high), corrected error (low), PCI parity or system error (high) | AER: Uncorrected, AER: Corrected error, BMC PCI PERR and PCI SERR |
| Thermal | CPU thermal throttling (high), critical temperature or threshold (critical) | temperature above threshold, cpu clock throttled, critical temperature reached, BMC upper critical thresholds |
| Power | Power supply fault (high), power supply removed (high) | Power supply or PSU with fail, fault or AC lost, redundancy lost, Presence detected | Deasserted |
| Network | NIC link down or hang (medium), NIC link not ready (low) | NIC Link is Down, Detected Tx Unit Hang, NETDEV WATCHDOG, link is not ready |
BMC recoveries are logged as ... | Deasserted. Every rule skips those lines,
except Power supply removed, which exists to catch a supply that is no longer
present. For general Sigma usage see the
security monitoring guide.
Notifications and Incidents
-
When a host gets worse (ok to
warningorcritical, or warning to critical), LogTide opens or updates an incident with source Hardware in the incidents inbox and sends a notification. A warning maps to medium severity, a critical to critical. There is at most one active hardware incident per host. - If the host improves from critical to warning, the incident drops to medium severity and no new notification is sent.
-
When the host returns to
ok, the incident is resolved and a recovery notification is sent. - The notification uses the Hardware health event type. Choose its destinations (email, Slack, Discord, Teams, PagerDuty, webhook) under Settings → Notifications → Routing, as described in Notification Routing. Without defaults, an email goes to your organization owners and admins when SMTP is configured. Owners and admins also get an in-app notification when a host degrades.
-
Webhook destinations receive
hardware.health.degradedandhardware.health.recoveredevents, see Webhooks. PagerDuty gets one PagerDuty incident per hardware incident, closed on recovery. - Mute a host on its detail page while you work on it (organization owners and admins can). A muted host is still evaluated and shown, but opens no incidents and sends no notifications. If it recovers while muted, its open incident is resolved silently.
- Forget host resolves the host's open incident and removes the host from the list. It comes back by itself if the agent keeps sending data.
- A stale host does not open an incident. Use a heartbeat monitor for that, see above.
Troubleshooting
No hosts appear
- Run the agent once in the foreground (see Verify) and read its output. It reports HTTP errors from LogTide.
- Check the URL and key. A 401 means the API key is wrong. The URL is the base URL of your instance, not a path.
- Make sure the key belongs to the project you are looking at in the project switcher.
- Allow a minute or two. A host is registered on the first batch and evaluated every two minutes.
A collector shows as unavailable
The host page lists every collector with its state. Unavailable means the agent could not
run it (if it had been working in the last 24 hours, the host also gets an
agent.collector_down warning): smart needs smartctl and privileges to open the devices,
ipmi and sel need ipmitool and a BMC device,
edac needs ECC memory and the EDAC modules, kmsg needs read access
to /dev/kmsg. On hardware without a BMC or without ECC, unavailable is expected.
The host is detected as a virtual machine
The agent reads DMI data and reports hw.virtual. Guests see virtual disks and
no sensors, so the host is listed as No sensors with a banner instead of component data. Install the agent on the
hypervisor host instead.
NVMe temperatures are missing
NVMe temperatures come from SMART and from the kernel hwmon interface. If they are missing,
check that smartctl -a /dev/nvme0 works as root on the host and that your
smartmontools is recent enough to support -j JSON output
(7.0 or newer).
IPMI permission errors
ipmitool talks to the BMC through /dev/ipmi0, which only root can
open, and the ipmi_devintf and ipmi_si kernel modules must be
loaded. Run sudo ipmitool sensor on the host: if that fails, the agent will fail
too. In a container, make sure the device is passed through.
A host turned stale
No hw.* data for 10 minutes. Check that the agent is running and that the
host and LogTide can still reach each other. Stale hosts do not notify; add a heartbeat
monitor if you need to know about it.