iNew syntax allowing the use of code in parameters - reed-alert - Lightweight agentless alerting system for server Err bitreich.org 70 hgit clone git://bitreich.org/reed-alert/ git://enlrupgkhuxnvlhsf6lc3fziv5h2hhfrinws65d7roiv6bfj7d652fid.onion/reed-alert/ URL:git://bitreich.org/reed-alert/ git://enlrupgkhuxnvlhsf6lc3fziv5h2hhfrinws65d7roiv6bfj7d652fid.onion/reed-alert/ bitreich.org 70 1Log /scm/reed-alert/log.gph bitreich.org 70 1Files /scm/reed-alert/files.gph bitreich.org 70 1Refs /scm/reed-alert/refs.gph bitreich.org 70 1Tags /scm/reed-alert/tag bitreich.org 70 1README /scm/reed-alert/file/README.gph bitreich.org 70 1LICENSE /scm/reed-alert/file/LICENSE.gph bitreich.org 70 i--- Err bitreich.org 70 1commit 3f03224030fd0b48e2de384f56c78834da14643b /scm/reed-alert/commit/3f03224030fd0b48e2de384f56c78834da14643b.gph bitreich.org 70 1parent 01a3f1cc34988cd7ad739d41186c4362ede1fdf8 /scm/reed-alert/commit/01a3f1cc34988cd7ad739d41186c4362ede1fdf8.gph bitreich.org 70 hAuthor: Solene Rapenne URL:mailto:solene@perso.pw bitreich.org 70 iDate: Thu, 11 Jan 2018 15:03:46 +0100 Err bitreich.org 70 i Err bitreich.org 70 iNew syntax allowing the use of code in parameters Err bitreich.org 70 i Err bitreich.org 70 iDiffstat: Err bitreich.org 70 i M README | 44 ++++++++++++++++---------------- Err bitreich.org 70 i M config.lisp.sample | 16 ++++++++-------- Err bitreich.org 70 i M example.lisp | 56 +++++++++++++++++-------------- Err bitreich.org 70 i M functions.lisp | 31 +++++++++++++++++-------------- Err bitreich.org 70 i Err bitreich.org 70 i4 files changed, 77 insertions(+), 70 deletions(-) Err bitreich.org 70 i--- Err bitreich.org 70 1diff --git a/README b/README /scm/reed-alert/file/README.gph bitreich.org 70 i@@ -144,7 +144,7 @@ Check if the actual number of processes of the system exceeds a specific limit. Err bitreich.org 70 i > Set the limit that will trigger an alert when exceeded. Err bitreich.org 70 i :limit INTEGER Err bitreich.org 70 i Err bitreich.org 70 i-Example : `(=> alert number-of-processes (:limit 200))` Err bitreich.org 70 i+Example : `(=> alert number-of-processes :limit 200)` Err bitreich.org 70 i Err bitreich.org 70 i Err bitreich.org 70 i pid-running Err bitreich.org 70 i@@ -154,7 +154,7 @@ Check if the PID number found in a .pid file is alive. Err bitreich.org 70 i > Set the path of the pid file. If $USER doesn't have permission to open it, return "file not found". Err bitreich.org 70 i :path "STRING" Err bitreich.org 70 i Err bitreich.org 70 i-Example : `(=> alert pid-running (:path "/var/run/nginx.pid"))` Err bitreich.org 70 i+Example : `(=> alert pid-running :path "/var/run/nginx.pid")` Err bitreich.org 70 i Err bitreich.org 70 i Err bitreich.org 70 i disk-usage Err bitreich.org 70 i@@ -167,7 +167,7 @@ Check if the disk-usage of a chosen partition does exceed a specific limit. Err bitreich.org 70 i > Set the limit that will trigger an alert when exceeded. Err bitreich.org 70 i :limit INTEGER Err bitreich.org 70 i Err bitreich.org 70 i-Example : `(=> alert disk-usage (:path "/tmp" :limit 50))` Err bitreich.org 70 i+Example : `(=> alert disk-usage :path "/tmp" :limit 50)` Err bitreich.org 70 i Err bitreich.org 70 i Err bitreich.org 70 i file-exists Err bitreich.org 70 i@@ -177,7 +177,7 @@ Check if a file exists. Err bitreich.org 70 i > Set the path of the file to check. Err bitreich.org 70 i :path "STRING" Err bitreich.org 70 i Err bitreich.org 70 i-Example : `(=> alert file-exists (:path "/var/postgresql/standby"))` Err bitreich.org 70 i+Example : `(=> alert file-exists :path "/var/postgresql/standby")` Err bitreich.org 70 i Err bitreich.org 70 i Err bitreich.org 70 i file-updated Err bitreich.org 70 i@@ -190,7 +190,7 @@ Check if a file exists and has been updated since a defined time. Err bitreich.org 70 i > Set the limit in minutes since the last modification time before triggering an alert. Err bitreich.org 70 i :limit INTEGER Err bitreich.org 70 i Err bitreich.org 70 i-Example : `(=> alert file-updated (:path "/var/log/nginx/access.log" :limit 60))` Err bitreich.org 70 i+Example : `(=> alert file-updated :path "/var/log/nginx/access.log" :limit 60)` Err bitreich.org 70 i Err bitreich.org 70 i Err bitreich.org 70 i load-average-1 Err bitreich.org 70 i@@ -200,7 +200,7 @@ Check if the load average during the last minute exceeds a specific limit. Err bitreich.org 70 i > Set the limit not to exceed. Err bitreich.org 70 i :limit INTEGER Err bitreich.org 70 i Err bitreich.org 70 i-Example : `(=> alert load-average-1 (:limit 2))` Err bitreich.org 70 i+Example : `(=> alert load-average-1 :limit 2)` Err bitreich.org 70 i Err bitreich.org 70 i Err bitreich.org 70 i load-average-5 Err bitreich.org 70 i@@ -210,7 +210,7 @@ Check if the load average during the last five minutes exceeds a specific limit. Err bitreich.org 70 i > Set the limit not to exceed. Err bitreich.org 70 i :limit INTEGER Err bitreich.org 70 i Err bitreich.org 70 i-Example : `(=> alert load-average-5 (:limit 2))` Err bitreich.org 70 i+Example : `(=> alert load-average-5 :limit 2)` Err bitreich.org 70 i Err bitreich.org 70 i Err bitreich.org 70 i load-average-15 Err bitreich.org 70 i@@ -220,7 +220,7 @@ Check if the load average during the last fifteen minutes exceeds a specific lim Err bitreich.org 70 i > Set the limit not to exceed. Err bitreich.org 70 i :limit INTEGER Err bitreich.org 70 i Err bitreich.org 70 i-Example : `(=> alert load-average-15 (:limit 2))` Err bitreich.org 70 i+Example : `(=> alert load-average-15 :limit 2)` Err bitreich.org 70 i Err bitreich.org 70 i Err bitreich.org 70 i ping Err bitreich.org 70 i@@ -230,7 +230,7 @@ Check if a remote host answers the 2 ICMP ping. Err bitreich.org 70 i > Set the host to ping. Return an error if ping command returns non-zero. Err bitreich.org 70 i :host "STRING" (can be IP or hostname) Err bitreich.org 70 i Err bitreich.org 70 i-Example : `(=> alert ping (:host "8.8.8.8"))` Err bitreich.org 70 i+Example : `(=> alert ping :host "8.8.8.8")` Err bitreich.org 70 i Err bitreich.org 70 i Err bitreich.org 70 i command Err bitreich.org 70 i@@ -241,7 +241,7 @@ This may be the most useful probe because it let the user do any check needed. Err bitreich.org 70 i > Command to execute, accept commands with pipes. Err bitreich.org 70 i :command "STRING" Err bitreich.org 70 i Err bitreich.org 70 i-Example : `(=> alert command (:command "tail -n 10 /var/log/messages | grep -v CRITICAL"))` Err bitreich.org 70 i+Example : `(=> alert command :command "tail -n 10 /var/log/messages | grep -v CRITICAL")` Err bitreich.org 70 i Err bitreich.org 70 i service Err bitreich.org 70 i ------- Err bitreich.org 70 i@@ -250,7 +250,7 @@ Check if a service is started on the system. Err bitreich.org 70 i > Set the name of the service to test Err bitreich.org 70 i :name STRING Err bitreich.org 70 i Err bitreich.org 70 i-Example : `(=> alert service (:name "mysql-server"))` Err bitreich.org 70 i+Example : `(=> alert service :name "mysql-server")` Err bitreich.org 70 i Err bitreich.org 70 i file-less-than Err bitreich.org 70 i -------------- Err bitreich.org 70 i@@ -262,7 +262,7 @@ Check if a file has a size less than a specified limit. Err bitreich.org 70 i > Set the limit in bytes before triggering an alert. Err bitreich.org 70 i :limit INTEGER Err bitreich.org 70 i Err bitreich.org 70 i-Example : `(=> alert file-less-than (:path "/var/log/nginx.log" :limit 60))` Err bitreich.org 70 i+Example : `(=> alert file-less-than :path "/var/log/nginx.log" :limit 60)` Err bitreich.org 70 i Err bitreich.org 70 i Err bitreich.org 70 i The configuration file Err bitreich.org 70 i@@ -278,13 +278,13 @@ It's possible to write loops if you don't want to repeat code Err bitreich.org 70 i Err bitreich.org 70 i (loop for host in '("bitreich.org" "dataswamp.org" "floodgap.com") Err bitreich.org 70 i do Err bitreich.org 70 i- (=> mail ping (:host host))) Err bitreich.org 70 i+ (=> mail ping :host host)) Err bitreich.org 70 i Err bitreich.org 70 i or another example Err bitreich.org 70 i Err bitreich.org 70 i (loop for service in '("smtpd" "nginx" "mysqld" "postgresql") Err bitreich.org 70 i do Err bitreich.org 70 i- (=> mail service (:name service))) Err bitreich.org 70 i+ (=> mail service :name service)) Err bitreich.org 70 i Err bitreich.org 70 i and another example using rows from a file to check remote hosts Err bitreich.org 70 i Err bitreich.org 70 i@@ -292,7 +292,7 @@ and another example using rows from a file to check remote hosts Err bitreich.org 70 i (loop for line = (read-line stream nil) Err bitreich.org 70 i while line Err bitreich.org 70 i do Err bitreich.org 70 i- (=> mail ping (:host line)))) Err bitreich.org 70 i+ (=> mail ping :host line))) Err bitreich.org 70 i Err bitreich.org 70 i Err bitreich.org 70 i Conditional Err bitreich.org 70 i@@ -310,9 +310,9 @@ router, probes requiring the router to work will trigger errors so we Err bitreich.org 70 i should skip them. Err bitreich.org 70 i Err bitreich.org 70 i (stop-if-error Err bitreich.org 70 i- (=> mail ping (:host "192.168.1.1" :desc "My local router")) Err bitreich.org 70 i- (=> mail ping (:host "89.89.89.89" :desc "My ISP DNS server")) Err bitreich.org 70 i- (=> mail ping (:host "kernel.org" :desc "Remote website"))) Err bitreich.org 70 i+ (=> mail ping :host "192.168.1.1" :desc "My local router") Err bitreich.org 70 i+ (=> mail ping :host "89.89.89.89" :desc "My ISP DNS server") Err bitreich.org 70 i+ (=> mail ping :host "kernel.org" :desc "Remote website")) Err bitreich.org 70 i Err bitreich.org 70 i Note : stop-if-error is an alias for the **and** function. Err bitreich.org 70 i Err bitreich.org 70 i@@ -326,10 +326,10 @@ the detection and fixing it. You could want to receive a mail when Err bitreich.org 70 i things need to be fixed on spare time, but mail another people if Err bitreich.org 70 i things aren't fixed after some level. Err bitreich.org 70 i Err bitreich.org 70 i-(escalation Err bitreich.org 70 i- (=> mail-me disk-usage (:path "/" :limit 70)) Err bitreich.org 70 i- (=> sms-me disk-usage (:path "/" :limit 90)) Err bitreich.org 70 i- (=> buzzer disk-usage (:path "/" :limit 98))) Err bitreich.org 70 i+ (escalation Err bitreich.org 70 i+ (=> mail-me disk-usage :path "/" :limit 70) Err bitreich.org 70 i+ (=> sms-me disk-usage :path "/" :limit 90) Err bitreich.org 70 i+ (=> buzzer disk-usage :path "/" :limit 98)) Err bitreich.org 70 i Err bitreich.org 70 i In this example, we check the disk usage, I will get a mail through Err bitreich.org 70 i "mail-me" alert if the disk usage go get more than 70%. Once it goes Err bitreich.org 70 1diff --git a/config.lisp.sample b/config.lisp.sample /scm/reed-alert/file/config.lisp.sample.gph bitreich.org 70 i@@ -3,17 +3,17 @@ Err bitreich.org 70 i (alert mail "echo -n 'Problem with %function% %date% %params%' | mail -s alarm mail@isp.net") Err bitreich.org 70 i (alert sms "/home/user/sms.sh '%date% %function% %params% %hostname%") Err bitreich.org 70 i (alert available-variables "REMINDER : %function% %params% %date% %hostname% %desc% %level% %os% %newline% %result%") Err bitreich.org 70 i-(alert void "") Err bitreich.org 70 i+(alert empty "") Err bitreich.org 70 i Err bitreich.org 70 i Err bitreich.org 70 i ;; this is a comment Err bitreich.org 70 i ; this is also a comment Err bitreich.org 70 i-(=> mail disk-usage (:path "/" :limit 90)) Err bitreich.org 70 i+(=> mail disk-usage :path "/" :limit 90) Err bitreich.org 70 i Err bitreich.org 70 i-(=> mail service (:name "dovecot")) Err bitreich.org 70 i-(=> mail service (:name "httpd")) Err bitreich.org 70 i-(=> sms service (:name "smtpd")) Err bitreich.org 70 i-(=> mail number-of-processes (:limit 100)) Err bitreich.org 70 i+(=> mail service :name "dovecot") Err bitreich.org 70 i+(=> mail service :name "httpd") Err bitreich.org 70 i+(=> sms service :name "smtpd") Err bitreich.org 70 i+(=> mail number-of-processes :limit 100) Err bitreich.org 70 i Err bitreich.org 70 i-(=> mail ping (:host "bitreich.org" :desc "Ping Bitreich")) Err bitreich.org 70 i-(=> mail ping (:host "openbsd.org" :desc "Ping OpenBSD.org")) Err bitreich.org 70 i+(=> mail ping :host "bitreich.org" :desc "Ping Bitreich") Err bitreich.org 70 i+(=> mail ping :host "openbsd.org" :desc "Ping OpenBSD.org") Err bitreich.org 70 1diff --git a/example.lisp b/example.lisp /scm/reed-alert/file/example.lisp.gph bitreich.org 70 i@@ -1,58 +1,62 @@ Err bitreich.org 70 i (load "functions.lisp") Err bitreich.org 70 i Err bitreich.org 70 i (alert dont-use-it "REMINDER %function% %params% %date% %hostname% %desc% %level% %os% %newline% _ %space% %result%") Err bitreich.org 70 i-(alert void "") Err bitreich.org 70 i+(alert empty "") Err bitreich.org 70 i (alert mail "") Err bitreich.org 70 i+(alert peroket "echo 'problem at %date% with %function% %params%'") Err bitreich.org 70 i (alert sms "echo -n '%date% %function% CRITICAL on %hostname%' | curl http://somewebservice") Err bitreich.org 70 i ;(alert mail "echo -n '%date% %hostname% had problem on %function% %newline% %params% values %result% %newline% Err bitreich.org 70 i ; %desc%' | mail -s '[Error] %function% - %hostname%' foo@bar.com") Err bitreich.org 70 i Err bitreich.org 70 i Err bitreich.org 70 i ;; check if used percent :path partition is more than :limit Err bitreich.org 70 i-(=> mail disk-usage (:path "/" :limit 90)) Err bitreich.org 70 i-(=> mail disk-usage (:path "/usr" :limit 85)) Err bitreich.org 70 i-(=> mail disk-usage (:path "/tmp" :limit 1)) ;; failure Err bitreich.org 70 i+(=> peroket disk-usage :path "/" :limit 90) Err bitreich.org 70 i+(=> peroket disk-usage :path "/usr" :limit 85) Err bitreich.org 70 i+(=> peroket disk-usage :path "/tmp" :limit 0) ;; failure Err bitreich.org 70 i Err bitreich.org 70 i ;; check if :path file exists Err bitreich.org 70 i-(=> mail file-exists (:path "/bsd.rd" :desc "OpenBSD kernel /bsd.rd")) Err bitreich.org 70 i-(=> void file-exists (:path "/non-existant-file")) ;; failure file not found Err bitreich.org 70 i+(=> mail file-exists :path "/bsd.rd" :desc "OpenBSD kernel /bsd.rd") Err bitreich.org 70 i+(=> empty file-exists :path "/non-existant-file") ;; failure file not found Err bitreich.org 70 i Err bitreich.org 70 i ;; check if :path file exists and has been updated since :limit minutes Err bitreich.org 70 i-(=> void file-updated (:path "/var/log/messages" :limit 400)) Err bitreich.org 70 i-(=> mail file-updated (:path "/bsd.rd" :limit 1 :desc "OpenBSD kernel")) ;; failure Err bitreich.org 70 i+(=> empty file-updated :path "/var/log/messages" :limit 400) Err bitreich.org 70 i+(=> mail file-updated :path "/bsd.rd" :limit 1 :desc "OpenBSD kernel") ;; failure Err bitreich.org 70 i Err bitreich.org 70 i ;; check if :path pid file process is running Err bitreich.org 70 i-(=> mail pid-running (:path "/var/run/xdm.pid" :desc "XDM pid")) Err bitreich.org 70 i-(=> mail pid-running (:path "/home/user/test.pid")) ;; failure Err bitreich.org 70 i+(=> mail pid-running :path "/var/run/xdm.pid" :desc "XDM pid") Err bitreich.org 70 i+(=> mail pid-running :path "/home/user/test.pid") ;; failure Err bitreich.org 70 i Err bitreich.org 70 i ;; check if number of processes on the system is more than :limit Err bitreich.org 70 i-(=> mail number-of-processes (:limit 200)) Err bitreich.org 70 i-(=> mail number-of-processes (:limit 1)) ;; failure Err bitreich.org 70 i+(=> mail number-of-processes :limit 200) Err bitreich.org 70 i+(=> mail number-of-processes :limit 1) ;; failure Err bitreich.org 70 i Err bitreich.org 70 i ;; check if service is running Err bitreich.org 70 i-(=> mail service (:name "httpd")) Err bitreich.org 70 i-(=> mail service (:name "ospfd")) ;; failure : not started Err bitreich.org 70 i-(=> mail service (:name "unknown")) ;; failure : not known Err bitreich.org 70 i+(=> mail service :name "httpd") Err bitreich.org 70 i+(=> mail service :name "ospfd") ;; failure : not started Err bitreich.org 70 i+(=> mail service :name "unknown") ;; failure : not known Err bitreich.org 70 i Err bitreich.org 70 i ;; check if load average on (1/5/15) minutes is more than :limit Err bitreich.org 70 i-(=> mail load-average-1 (:limit 4)) Err bitreich.org 70 i-;;(=> mail load-average-5 (:limit 2)) Err bitreich.org 70 i-;;(=> mail load-average-15 (:limit 1)) Err bitreich.org 70 i-(=> mail load-average-1 (:limit 0.2)) ;; should trigger error Err bitreich.org 70 i+(=> mail load-average-1 :limit 4) Err bitreich.org 70 i+;;(=> mail load-average-5 :limit 2) Err bitreich.org 70 i+;;(=> mail load-average-15 :limit 1) Err bitreich.org 70 i+(=> mail load-average-1 :limit 0.2) ;; should trigger error Err bitreich.org 70 i Err bitreich.org 70 i ;; check if :host host is reachable Err bitreich.org 70 i-;;(=> mail ping (:host "8.8.8.8" :desc "Google DNS")) Err bitreich.org 70 i-;;(=> void ping (:host "127.40.30.21" :desc "Certainly not used address")) ;; fail time out Err bitreich.org 70 i+;;(=> mail ping :host "8.8.8.8" :desc "Google DNS") Err bitreich.org 70 i+;;(=> empty ping :host "127.40.30.21" :desc "Certainly not used address") ;; fail time out Err bitreich.org 70 i+(loop for host in (list "8.8.8.8" "8.8.4.4" "127.0.0.1") Err bitreich.org 70 i+ do Err bitreich.org 70 i+ (=> empty ping :host host)) Err bitreich.org 70 i Err bitreich.org 70 i ;; check if :command command return 0 (success) or something else (error) Err bitreich.org 70 i-(=> void command (:command "echo hello")) ;; success Err bitreich.org 70 i-(=> void command (:command "ls /non-existent-file")) ;; fail Err bitreich.org 70 i+(=> empty command :command "echo hello") ;; success Err bitreich.org 70 i+(=> empty command :command "ls /non-existent-file") ;; fail Err bitreich.org 70 i Err bitreich.org 70 i ;; check if web page :url answer under :limit Err bitreich.org 70 i-(=> void command (:command "curl -m 10 http://google.fr/")) Err bitreich.org 70 i+(=> empty command :command "curl -m 10 http://google.fr/") Err bitreich.org 70 i Err bitreich.org 70 i ;; check if the web page :url contains the text regex :pattern Err bitreich.org 70 i-(=> void command (:command "curl http://google.fr/ | grep html")) Err bitreich.org 70 i-(=> void command (:command "curl http://google.fr/ | grep hello")) ;; error Err bitreich.org 70 i+(=> empty command :command "curl http://google.fr/ | grep html") Err bitreich.org 70 i+(=> empty command :command "curl http://google.fr/ | grep hello") ;; error Err bitreich.org 70 i Err bitreich.org 70 i (quit) Err bitreich.org 70 1diff --git a/functions.lisp b/functions.lisp /scm/reed-alert/file/functions.lisp.gph bitreich.org 70 i@@ -25,7 +25,9 @@ Err bitreich.org 70 i while pos))) Err bitreich.org 70 i Err bitreich.org 70 i (defmacro create-probe(name &body code) Err bitreich.org 70 i- `(progn (defun ,name(params) ,@code))) Err bitreich.org 70 i+ `(progn Err bitreich.org 70 i+ (defparameter ,name ',name) Err bitreich.org 70 i+ (defun ,name(params) ,@code))) Err bitreich.org 70 i Err bitreich.org 70 i (defun get-file-size(path) Err bitreich.org 70 i (with-open-file (stream path) Err bitreich.org 70 i@@ -38,7 +40,9 @@ Err bitreich.org 70 i (list nil (format nil "return code = ~a" code))))) Err bitreich.org 70 i Err bitreich.org 70 i (defmacro alert(name string) Err bitreich.org 70 i- `(progn (push (list ',name ,string) Err bitreich.org 70 i+ `(progn Err bitreich.org 70 i+ (defparameter ,name ',name) Err bitreich.org 70 i+ (push (list ',name ,string) Err bitreich.org 70 i *alerts*))) Err bitreich.org 70 i Err bitreich.org 70 i (defun trigger-alert(level function params result) Err bitreich.org 70 i@@ -67,17 +71,16 @@ Err bitreich.org 70 i `(progn Err bitreich.org 70 i (or ,@body))) Err bitreich.org 70 i Err bitreich.org 70 i-(defmacro =>(level fonction params) Err bitreich.org 70 i- `(progn Err bitreich.org 70 i- (format t "[~a~a ~20A~a] ~35A" *yellow* ',level ',fonction *white* (getf ',params :desc ',params)) Err bitreich.org 70 i- (let ((result (funcall ',fonction ',params))) Err bitreich.org 70 i- (if (not (listp result)) Err bitreich.org 70 i- (progn Err bitreich.org 70 i- (format t " => ~asuccess~a~%" *green* *white*) Err bitreich.org 70 i- t) Err bitreich.org 70 i- (progn Err bitreich.org 70 i- (format t " => ~aerror~a~%" *red* *white*) Err bitreich.org 70 i- (uiop:run-program (trigger-alert ',level ',fonction ',params (cadr result)) :output t) Err bitreich.org 70 i- nil))))) Err bitreich.org 70 i+(defun =>(level fonction &rest params) Err bitreich.org 70 i+ (format t "[~a~a ~20A~a] ~35A" *yellow* level fonction *white* (getf params :desc params)) Err bitreich.org 70 i+ (let ((result (funcall fonction params))) Err bitreich.org 70 i+ (if (not (listp result)) Err bitreich.org 70 i+ (progn Err bitreich.org 70 i+ (format t " => ~asuccess~a~%" *green* *white*) Err bitreich.org 70 i+ t) Err bitreich.org 70 i+ (progn Err bitreich.org 70 i+ (format t " => ~aerror~a~%" *red* *white*) Err bitreich.org 70 i+ (uiop:run-program (trigger-alert level fonction params (cadr result)) :output t) Err bitreich.org 70 i+ nil)))) Err bitreich.org 70 i Err bitreich.org 70 i (load "probes.lisp") Err bitreich.org 70 .