Docs · Log signals
A security control that fails loudly gets fixed the same day. The ones worth watching are the controls that keep reporting themselves as running while doing nothing — a brute-force blocker whose log format changed underneath it, a signature updater that stopped reaching its mirrors, a scanner whose cron entry went missing during a migration. All of it is already written down, in logs on the host that nobody opens. Log signals is the agent reading those logs on every fire and shipping counts and control facts — never the lines themselves — so the platform can tell you when something that should be moving has stopped.
Where this came from
We built this while producing auditor evidence for a customer. Every gap we had to explain turned out to be the same kind of thing: a control that had silently stopped, visible only in a log nobody read. A brute-force blocker that had blocked nothing for 47 days. Malware signatures months out of date. A malware monitor in a failed state. Log rotation that had stopped running. Alerts delivering, on schedule, into root's unread mailbox. None of it was a missing tool; all of it was a tool that had quietly stopped.
The Linux agent you already have installed does this work on its normal 30-second fire — there is nothing new to install. On each fire it reads, read-only and as root:
Alongside the counters it collects a small set of control facts: systemd unit states for each watched security control, the ClamAV database date, the maldet signature date, the size and rotation age of each tailed file, and when the agent last completed a full scan.
Log lines. What the agent uploads is hourly counters — how many SSH failures, how many blocks, how many bans, how many drops, in each hour — and the control facts above. The platform evaluates ten rules against those counters every 15 minutes and opens findings in the existing category, so they arrive in the same inbox, with the same severities, routed to the same per-server alert recipients as everything else. A finding auto-resolves when the condition that opened it clears.
This is deliberately not log management. We do not ship your logs, we do not index them, and you cannot search them here. If you need to read the line, you read it on the host — Astrari's job is to tell you which host and which hour.
blocker-idleHighlfd or fail2ban reports itself as active, the auth log shows 200 or more failed or invalid-user SSH attempts in 24 hours, and the blocker has recorded zero blocks in 48 hours. This is the exact shape of the csf 14.02 failure, where lfd's regex still expected sshd[pid] and OpenSSH 9.8 had started logging as sshd-session[pid] — the daemon ran, matched nothing, and blocked nobody. It is also what a fail2ban jail pointed at a rotated-away log looks like. If two blockers are running and only one is idle, nothing fires: the other one is still doing the work.
service-failedHigh (Medium for logrotate.timer)systemd reports lfd, csf, fail2ban, clamav-freshclam, clamav-daemon/clamd@scan, cron/crond, maldet or logrotate.timer as failed — or, for the units that should always be running once installed, as inactive — and it has stayed that way for at least 20 minutes. The 20-minute floor is there so a package upgrade or a deliberate restart does not page anyone. logrotate.timer is scored one step lower because a missed rotation fills a disk slowly rather than leaving something unprotected, and because RHEL-family hosts legitimately drive logrotate from cron.daily with the timer inactive.
scanner-staleMediummaldet's event log shows no completed scan in 7 days, or the Astrari agent's own full scan last finished more than 48 hours ago. Both are the quiet version of a scanner failure: the tool is installed, the cron entry may still exist, and nothing has completed. The maldet check waits until we have observed the host for the whole 7-day window, so a fresh install never fires on day one.
sigs-staleMediumThe ClamAV database is more than 7 days old, or maldet's newest signature file is more than 21 days old. The two windows differ because the two tools update at different rates — ClamAV publishes several times a day, maldet once a day from its own cron. A scanner running to completion every night against a database from three months ago produces a clean result and a false sense of the estate.
log-quietMediumThe auth log has produced nothing for 6 hours; lfd, fail2ban or the kernel firewall log for 24 hours; maldet's event log for 7 days. Silence only counts against a baseline: we need at least 24 prior hourly buckets averaging at least one line an hour, and at least 48 hours of observed history on the host, before this can fire. A log that was always empty is not a finding — a log that stopped is.
rotation-deadLowA file the agent tails has passed 100 MB and either has no rotated sibling at all, or the newest rotated copy is more than 7 days old. logrotate has stopped somewhere. The practical cost arrives later, when the disk fills or someone truncates the file by hand and takes the evidence with it.
mailbox-growingLowroot's local mailbox has grown across three consecutive hourly samples and is past 1 MB. Cron output, lfd alerts, freshclam and logwatch all deliver to root by default. A spool that only grows means those alerts have been written faithfully for months and read by nobody — the remediation is an /etc/aliases entry, not a new tool.
new-source-ipMediumA successful SSH login for a user from a source address not seen for that user in the observed history. It needs 7 days of observation on the host before it can fire at all, so the first week does not produce a wall of first-sightings. Most of these are a new office, a VPN exit or a replaced laptop — the point is that you see them, and that the one that is not gets read by a person.
malware-hitHighLinux Malware Detect's own event log recorded a hit or a quarantine in the last 24 hours from its real-time inotify monitor, its daily cron scan, or a scan an administrator started by hand. The agent runs maldet itself as part of its malware pass and reports those hits as its own "Web malware detected" finding, with the file paths; this rule deliberately excludes the agent's own scans (it knows their process IDs) so the same file is not reported twice as an "independent" detection. It exists for the detections the agent's scan window would miss: a file written and caught by the monitor between passes, or a cron scan of a path the agent does not cover. When maldet trims its own event log, the lines it keeps were already counted and are not counted again (agent 0.2.124; on hosts upgraded from an earlier agent, this takes effect after maldet's next trim). The remediation lists the exact grep for the flagged paths.
history-gapInfoThe agent could not read a log, could not keep up with one, found it truncated, or could not persist its own state under /var/lib/astrari. Informational rather than urgent, but it is recorded as a finding rather than swallowed, because every rule above is quieter than reality for as long as it is true. A liveness check that cannot say when it stopped working is worth no more than the control it watches.
The dashboard is the primary surface. Each server has a Signals tab showing its hourly counters, the state of each watched control, and any findings the rules have opened.
Every threshold quoted above is a default, not a constant. From Settings → Log signals you can set them for the whole organisation:
/var/log/, /usr/local/, /home/, /srv/, /opt/, /var/www/ — so a config typo cannot walk the agent out of the log trees into /etc or /proc.Log signals is included on every plan, at no extra cost.
The counters are also exposed in Prometheus text format, so you can put them on a board you already look at. Authenticate with an organisation API key (Professional and Agency plans) as a bearer token:
curl -s https://api.astrari.io/metrics \ -H "Authorization: Bearer iw_live_…"
The endpoint returns, per server, the hourly line and event counts, the state of each watched systemd unit, ClamAV and maldet signature ages, and root's mailbox size. Scrape it like any other target. The dashboard remains the primary surface — the findings, the severities and the alert routing all live there, and /metrics is for the numbers underneath them.
See the privacy policy for how this sits within the rest of the data we process.