|
| 1 | +;; Logger library for R7RS Scheme |
| 2 | + |
| 3 | +;; The Logger library can be used to output messages to an output port. |
| 4 | +;; Each message is given a level, and only messages above a certain set |
| 5 | +;; level will be output to the port. This allows the developer to control |
| 6 | +;; the level of detail output by the program. |
| 7 | +;; This logger library uses the same levels as Ruby's Logger class. |
| 8 | + |
| 9 | +;; Written by Peter Lane, 2017 |
| 10 | + |
| 11 | +;; # Open Works License |
| 12 | +;; |
| 13 | +;; This is version 0.9.4 of the Open Works License |
| 14 | +;; |
| 15 | +;; ## Terms |
| 16 | +;; |
| 17 | +;; Permission is hereby granted by the holder(s) of copyright or other legal |
| 18 | +;; privileges, author(s) or assembler(s), and contributor(s) of this work, to any |
| 19 | +;; person who obtains a copy of this work in any form, to reproduce, modify, |
| 20 | +;; distribute, publish, sell, sublicense, use, and/or otherwise deal in the |
| 21 | +;; licensed material without restriction, provided the following conditions are |
| 22 | +;; met: |
| 23 | +;; |
| 24 | +;; Redistributions, modified or unmodified, in whole or in part, must retain |
| 25 | +;; applicable copyright and other legal privilege notices, the above license |
| 26 | +;; notice, these conditions, and the following disclaimer. |
| 27 | +;; |
| 28 | +;; NO WARRANTY OF ANY KIND IS IMPLIED BY, OR SHOULD BE INFERRED FROM, THIS LICENSE |
| 29 | +;; OR THE ACT OF DISTRIBUTION UNDER THE TERMS OF THIS LICENSE, INCLUDING BUT NOT |
| 30 | +;; LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, |
| 31 | +;; AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS, ASSEMBLERS, OR HOLDERS OF |
| 32 | +;; COPYRIGHT OR OTHER LEGAL PRIVILEGE BE LIABLE FOR ANY CLAIM, DAMAGES, OR OTHER |
| 33 | +;; LIABILITY, WHETHER IN ACTION OF CONTRACT, TORT, OR OTHERWISE ARISING FROM, OUT |
| 34 | +;; OF, OR IN CONNECTION WITH THE WORK OR THE USE OF OR OTHER DEALINGS IN THE WORK. |
| 35 | + |
| 36 | +(library |
| 37 | + (logger logger) |
| 38 | + (export new-logger |
| 39 | + logger? |
| 40 | + log-close |
| 41 | + log-unknown |
| 42 | + log-fatal |
| 43 | + log-error |
| 44 | + log-warn |
| 45 | + log-info |
| 46 | + log-debug |
| 47 | + log-add |
| 48 | + log-level |
| 49 | + log-unknown? |
| 50 | + log-fatal? |
| 51 | + log-error? |
| 52 | + log-warn? |
| 53 | + log-info? |
| 54 | + log-debug?) |
| 55 | + (import (scheme)) |
| 56 | + |
| 57 | + |
| 58 | + (define-record-type (logger make-logger logger?) |
| 59 | + (fields |
| 60 | + (immutable port port-get) |
| 61 | + (mutable level level-get level-set!) |
| 62 | + (immutable flag created-file?))) |
| 63 | + |
| 64 | + (define *levels* (list (cons 'unknown 1) |
| 65 | + (cons 'fatal 2) |
| 66 | + (cons 'error 3) |
| 67 | + (cons 'warn 4) |
| 68 | + (cons 'info 5) |
| 69 | + (cons 'debug 6))) |
| 70 | + |
| 71 | + (define (valid-level? level) |
| 72 | + (memq level (map car *levels*))) |
| 73 | + |
| 74 | + (define (level<=? level1 level2) |
| 75 | + (let ((l1 (cdr (assq level1 *levels*))) |
| 76 | + (l2 (cdr (assq level2 *levels*)))) |
| 77 | + (<= l1 l2))) |
| 78 | + |
| 79 | + ;; construct a logger object from an output port |
| 80 | + (define (new-logger out) |
| 81 | + (cond ((output-port? out) |
| 82 | + (make-logger out 'debug #f)) |
| 83 | + ((string? out) |
| 84 | + (make-logger (open-output-file out) 'debug #t)) |
| 85 | + (else |
| 86 | + (error #f "new-logger requires an output port or filename")))) |
| 87 | + |
| 88 | + ;; close logger if created a file |
| 89 | + (define (log-close logger) |
| 90 | + (when (created-file? logger) |
| 91 | + (close-output-port (port-get logger)))) |
| 92 | + |
| 93 | + ;; change level of logger |
| 94 | + (define (log-level logger level) |
| 95 | + (if (valid-level? level) |
| 96 | + (level-set! logger level) |
| 97 | + (error #f "log-level given invalid level"))) |
| 98 | + |
| 99 | + ;; if given level is not lower than logger's level |
| 100 | + ;; outputs message to logger's port |
| 101 | + (define (log-add logger msg level) |
| 102 | + (if (valid-level? level) |
| 103 | + (when (level<=? level (level-get logger)) |
| 104 | + (let ((p (port-get logger))) |
| 105 | + (display level p) |
| 106 | + (display ": " p) |
| 107 | + (display msg p) |
| 108 | + (newline p))) |
| 109 | + (error #f "log-add given invalid level"))) |
| 110 | + |
| 111 | + ;; log messages at a known level |
| 112 | + (define (log-unknown logger msg) (log-add logger msg 'unknown)) |
| 113 | + (define (log-fatal logger msg) (log-add logger msg 'fatal)) |
| 114 | + (define (log-error logger msg) (log-add logger msg 'error)) |
| 115 | + (define (log-warn logger msg) (log-add logger msg 'warn)) |
| 116 | + (define (log-info logger msg) (log-add logger msg 'info)) |
| 117 | + (define (log-debug logger msg) (log-add logger msg 'debug)) |
| 118 | + |
| 119 | + ;; check if level permits message at given level to be logged |
| 120 | + (define (log-unknown? logger) (level<=? 'unknown (level-get logger))) |
| 121 | + (define (log-fatal? logger) (level<=? 'fatal (level-get logger))) |
| 122 | + (define (log-error? logger) (level<=? 'error (level-get logger))) |
| 123 | + (define (log-warn? logger) (level<=? 'warn (level-get logger))) |
| 124 | + (define (log-info? logger) (level<=? 'info (level-get logger))) |
| 125 | + (define (log-debug? logger) (level<=? 'debug (level-get logger))) |
| 126 | + |
| 127 | +) |
| 128 | + |
| 129 | + |
0 commit comments