;;; GNU Guix --- Functional package management for GNU ;;; Copyright © 2023, 2024 Maxim Cournoyer ;;; ;;; This file is part of GNU Guix. ;;; ;;; GNU Guix 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. ;;; ;;; GNU Guix 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 GNU Guix. If not, see . (define-module (guix logging) #:use-module (logging logger) #:use-module (logging port-log) #:use-module (oop goops) #:use-module (srfi srfi-209) #:export (setup-logging shutdown-logging log-level log-debug log-info log-warning log-error log-critical)) (define-syntax define-log-level ;; This macro defines a log-level enum type bound to ENUM-NAME for the ;; provided levels. The levels should be specified in increasing order of ;; severity. It also defines 'log-LEVEL' syntax to more conveniently log at ;; LEVEL, with location information. (lambda (x) (define-syntax-rule (id parts ...) ;; Assemble PARTS into a raw (unhygienic) identifier. (datum->syntax x (symbol-append (syntax->datum parts) ...))) (syntax-case x () ((_ enum-name (level ...)) #`(begin (define enum-name (make-enum-type '(level ...))) #,@(map (lambda (lvl) (with-syntax ((log (id 'log- lvl)) (lvl lvl)) #'(define-syntax log (lambda (y) (syntax-case y () ((log . args) #`(log-msg '#,(datum->syntax y (syntax-source #'log)) 'lvl #,@#'args))))))) #'(level ...))))))) (define-log-level log-level (debug info warning error critical)) (define* (setup-logging #:key (level 'warning)) "Configure and open logger at LEVEL)." (let* ((level-enum (or (enum-name->enum log-level level) (begin (format (current-error-port) "error: invalid log level~%") (exit 1)))) (lgr (make )) (console (make #:port (current-error-port))) (levels-count (enum-type-size log-level))) ;; Register logging handlers. (add-handler! lgr console) ;; Configure the log level. (let loop ((enum (enum-min log-level))) (let ((lvl (enum-name enum))) (unless (eq? level lvl) (disable-log-level! lgr lvl) (loop (enum-next enum))))) ;; Activate the configured logger. (set-default-logger! lgr) (open-log! lgr) (log-debug "logging initialized"))) (define (shutdown-logging) "Flush and destroy logger." (flush-log) (close-log!) (set-default-logger! #f))