Mercurial > core / lisp/lib/log/log.lisp
changeset 698: |
96958d3eb5b0 |
parent: |
c4682fedd73d
|
author: |
Richard Westhaver <ellis@rwest.io> |
date: |
Fri, 04 Oct 2024 22:04:59 -0400 |
permissions: |
-rw-r--r-- |
description: |
fixes |
3 (deftype log-level-designator () '(member nil :fatal :error :warn :info :debug :trace t)) 5 (declaim (log-level-designator *log-level*)) 6 (defparameter *log-level* :debug 7 "Logging is performed dynamically based on this variable. When NIL, 8 logging is disabled, which is equivalent to a level of :FATAL. When T, 9 Logging is enabled for all levels, which is equivalent to :TRACE.") 13 (defvar *log-router* nil) 15 (defvar *log-timestamp* t 16 "If non-nil, print a timestamp with log output. The value may be a 17 function in which case it is used as the function value of 18 `log-timestamp-source', or a number which will be used as the input arg to GET-REAL-TIME-SINCE.") 20 (declaim (fixnum *log-indent*)) 21 (defvar *log-indent* 0 22 "Level of indentation to apply to multi-line log messages.") 24 (defun get-real-time-since (n) 25 "Return the numbers of seconds since a relative value offset N." 26 (- (get-internal-real-time) n)) 28 (defun init-log-timestamp () 29 (setq *log-timestamp* (get-internal-real-time))) 31 ;; TODO 2023-09-20: (declaim (inline log-timestamp-source)) ;; this 32 ;; probably shouldn't be inlined.. bench it 33 (defun log-timestamp-source () 34 (typecase *log-timestamp* 35 (function (funcall *log-timestamp*)) 36 (number (/ (get-real-time-since *log-timestamp*) #.internal-time-units-per-second)) 37 (t (/ (get-internal-real-time) #.internal-time-units-per-second)))) 39 (defun universal-timestamp () (get-universal-time)) 41 ;; the purpose of this struct is to route log messages to the 42 ;; appropriate output stream. It should be configured and bound to 45 fatal error warn info debug trace) 47 ;; TODO 2023-09-20: make-synonym-stream, make-synonym-stream-symbol 48 (defvar *default-log-router* 55 :trace *trace-output*)) 58 "The logger is responsible for intercepting log messages and either 59 printing them to a stream based on the router slot, or doing nothing 60 based on the level slot. Additionally, the appenders slot may contain 61 a list of functions taking a single log message as input. Each 62 appender in the list is called on each message intercepted wrt level." 63 (level *log-level* :type log-level-designator) 64 (timestamp *log-timestamp* :type (or boolean function number)) 65 (appenders nil :type list) 66 (router *default-log-router* :type log-router)) 68 ;; TODO: (defmacro generate-log-profile) 69 ;; (defmacro deflogger) ;; yalog 70 ;; (defmacro with-log-profile) 71 (defmacro with-logger ((logger) &body body) 72 "Activate the specified logger for the life-time of BODY. This is 73 useful if you don't want to dynamically overwrite the *LOGGER* 75 `(let ((*logger* ,logger)) 78 (defmacro define-log-level (name &body pred) 79 "Define a log-level of NAME with PRED being the body of the predicate 81 (let ((%name (string-upcase name))) 83 (defun ,(intern (concatenate 'string %name "-P")) () 84 ,@(or pred `((eql *log-level* ,(sb-int:keywordicate name))))) 85 (defun ,(intern (concatenate 'string %name "!")) (&rest args) 86 (when (,(symbolicate (concatenate 'string %name "-P"))) 87 (format t "#:~(~A~) ~@[~f~]" 89 (when *log-timestamp* (log-timestamp-source))) 90 (mapc (lambda (x) (format t "; ~A~%" x)) args)) 91 (if (= 1 (length args)) 94 (defun ,(intern (concatenate 'string %name "-DESCRIBE")) (&rest args) 95 (,(intern (concatenate 'string %name "!")) (apply #'describe args)))))) 97 (define-log-level trace (or (eql *log-level* :trace) (eql *log-level* t))) 98 (define-log-level debug (or (trace-p) (eql *log-level* :debug))) 99 (define-log-level info (or (debug-p) (eql *log-level* :info))) 100 (define-log-level warn (or (info-p) (eql *log-level* :warn))) 101 (define-log-level error (or (warn-p) (eql *log-level* :error))) 102 (define-log-level fatal t) ;; probably needs to be a special case 104 ;; TODO 2023-08-31: single format control string 105 ;; (defun debug! (&rest args) 108 ;; ;; RESEARCH 2023-08-31: what's better here.. loop, do, mapc+nil? 109 ;; (map nil (lambda (x) (format t "~X~%" x)) args))