1(c-include "<syslog.h>")
2
3(defconstant LOG_LOCAL0 #x80)
4(defconstant LOG_PID #x01)
5(defconstant LOG_ALERT 1)
6(defconstant LOG_CRIT 2)
7(defconstant LOG_ERR 3)
8(defconstant LOG_WARNING 4)
9(defconstant LOG_NOTICE 5)
10(defconstant LOG_INFO 6)
11(defconstant LOG_DEBUG 7)
12
13(defconstant +priorities+ (list (cons 'debug LOG_DEBUG)
14                                (cons 'info LOG_INFO)
15                                (cons 'notice LOG_NOTICE)
16                                (cons 'warning LOG_WARNING)
17                                (cons 'err LOG_ERR)
18                                (cons 'crit LOG_CRIT)
19                                (cons 'alert LOG_ALERT)))
20
21;; Clang doesn't support nested C functions.
22(defun openlog--calc-logopt-flags (logopts)
23   (the <list> logopts)
24   (let ((res 0))
25        (for ((xs logopts (cdr xs)))
26             ((null xs) res)
27             (setq res (+ res (car xs))))))
28(defun openlog (ident logopts facility)
29   (the <string> ident)(the <list> logopts) (the <fixnum> facility)
30   (let ((logopt-flags (openlog--calc-logopt-flags logopts)))
31        (c-lang "res = 0; openlog(Fgetname(IDENT), LOGOPT_FLAGS & INT_MASK, FACILITY & INT_MASK);")))
32(openlog "eisl" (list LOG_PID) LOG_LOCAL0)
33
34(defun syslog (priority message)
35   (the <fixnum> priority)(the <string> message)
36   (c-lang "res = 0; syslog(PRIORITY & INT_MASK, \"%s\", Fgetname(MESSAGE));"))
37(defun log-add (level fmt &rest args)
38   ;; Try to add a log entry.
39   (the <symbol> level)(the <string> fmt)(the <list> args)
40   (let ((str (create-string-output-stream)))
41        (format str "[~C] " (elt (convert level <string>) 0))
42        (apply #'format str fmt args)
43        (syslog (+ (cdr (assoc level +priorities+)) LOG_LOCAL0) (get-output-stream-string str))))
44
45(defun closelog ()
46   (c-lang "res = 0; closelog();"))
47
48;; Doesn't seem to work, on macOS at least?
49(defun log-set-level (level)
50   (the <symbol> level)
51   (let ((intlvl (cdr (assoc level +priorities+))))
52        (c-lang "res = setlogmask(LOG_UPTO(INTLVL & INT_MASK)) | INT_FLAG;")))
53
54;; Test code:
55
56#|
57;; Low-level UNIX syslog interface, not recommended:
58(defun my-test ()
59   (openlog "test" (list LOG_PID) LOG_LOCAL0)
60   (syslog LOG_INFO "This is a test")
61   (closelog))
62;; The OpenLisp-compatible interface is recommended instead:
63(log-add 'debug "f: x ~A y ~A" x y)
64|#
65;; To see the result of the above on macOS, run
66;;   log stream --level debug --predicate "process == 'eisl'"
67;; in a Terminal beforehand. Or use Console.app
68;;
69;; On Linux, messages will probably appear in /var/log/messages,
70;; but ensure that they're not filtered out by /etc/*syslog.conf because of low priority.
71