;;; Monitoring --- Server monitoring ;;; Copyright © 2021 Masaya Tojo <masaya@tojo.tokyo> ;;; ;;; This file is part of Monitoring. ;;; ;;; Monitoring is free software; you can redistribute it and/or modify it ;;; under the terms of the GNU General Public License as published by ;;; the Free Software Foundation; either version 3 of the License, or ;;; (at your option) any later version. ;;; ;;; Monitoring is distributed in the hope that it will be useful, but ;;; WITHOUT ANY WARRANTY; without even the implied warranty of ;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ;;; General Public License for more details. ;;; ;;; You should have received a copy of the GNU General Public License ;;; along with Monitoring. If not, see <http://www.gnu.org/licenses/>. (define-module (tojo-tokyo monitoring) #:use-module (ice-9 popen) #:use-module (ice-9 textual-ports) #:use-module (ice-9 regex) #:use-module ((srfi srfi-1) #:select (any)) #:use-module ((srfi srfi-26)) #:use-module (web client)) (define-public current-heartbeat-url (make-parameter (let ((heartbeat-file "/etc/heartbeat-url")) (or (and (file-exists? heartbeat-file) (call-with-input-file heartbeat-file get-line)) "https://heartbeat.test")))) (define (split-with-spaces x) (map match:substring (list-matches "[^ ]+" x))) (define (command->table command header) (let ((port (open-input-pipe command))) (get-line port) ; skip a header line. (let loop ((line (get-line port)) (table '())) (cond ((eof-object? line) (close-pipe port) table) (else (loop (get-line port) (cons (map cons header (split-with-spaces line)) table))))))) (define (df) (command->table "df" '(filesystem 1k-blocks used available use% mounted-on))) (define (prefix-/dev/? x) (and (string? x) (<= 5 (string-length x)) (string=? (substring x 0 5) "/dev/"))) (define (use%->number x) (string->number (string-delete #\% x))) (define-public (disk-use%-over? threshold) (any (cut < threshold <>) (map (compose use%->number (cut assoc-ref <> 'use%)) (filter (compose prefix-/dev/? (cut assoc-ref <> 'filesystem)) (df))))) (define (df-i) (command->table "df -i" '(filesystem inodes iused ifree iuse% mounted-on))) (define (iuse%->number x) (or (string->number (string-delete #\% x)) 0)) (define-public (disk-iuse%-over? threshold) (any (cut < threshold <>) (map (compose iuse%->number (cut assoc-ref <> 'iuse%)) (filter (compose prefix-/dev/? (cut assoc-ref <> 'filesystem)) (df-i))))) (define-syntax-rule (heartbeat (p? body ...) ...) (let ((heartbeat-cancel? #f)) (when p? body ... (set! heartbeat-cancel? #t)) ... (unless heartbeat-cancel? (http-request (current-heartbeat-url))))) (export-syntax heartbeat)