Move part of unstable/logging to racket/logging.
... and improve and extend its interface at the same time.
This commit is contained in:
parent
46a8506f99
commit
0f2d02cdd2
|
@ -84,7 +84,7 @@ otherwise.}
|
||||||
|
|
||||||
@defproc[(make-logger [topic (or/c symbol? #f) #f]
|
@defproc[(make-logger [topic (or/c symbol? #f) #f]
|
||||||
[parent (or/c logger? #f) #f]
|
[parent (or/c logger? #f) #f]
|
||||||
[propagate-level (or/c 'none 'fatal 'error 'warning 'info 'debug) 'debug]
|
[propagate-level log-level/c 'debug]
|
||||||
[propagate-topic (or/c #f symbol?) #f]
|
[propagate-topic (or/c #f symbol?) #f]
|
||||||
... ...)
|
... ...)
|
||||||
logger?]{
|
logger?]{
|
||||||
|
@ -134,7 +134,7 @@ created when @racket[define-logger] is evaluated.}
|
||||||
@section{Logging Events}
|
@section{Logging Events}
|
||||||
|
|
||||||
@defproc[(log-message [logger logger?]
|
@defproc[(log-message [logger logger?]
|
||||||
[level (or/c 'fatal 'error 'warning 'info 'debug)]
|
[level log-level/c]
|
||||||
[topic (or/c symbol? #f) (logger-name logger)]
|
[topic (or/c symbol? #f) (logger-name logger)]
|
||||||
[message string?]
|
[message string?]
|
||||||
[data any/c]
|
[data any/c]
|
||||||
|
@ -155,7 +155,7 @@ by @racket[": "] before it is sent to receivers.
|
||||||
|
|
||||||
|
|
||||||
@defproc[(log-level? [logger logger?]
|
@defproc[(log-level? [logger logger?]
|
||||||
[level (or/c 'fatal 'error 'warning 'info 'debug)]
|
[level log-level/c]
|
||||||
[topic (or/c symbol? #f) #f])
|
[topic (or/c symbol? #f) #f])
|
||||||
boolean?]{
|
boolean?]{
|
||||||
|
|
||||||
|
@ -180,7 +180,7 @@ that any event information it receives will never become accessible).
|
||||||
|
|
||||||
@defproc[(log-max-level [logger logger?]
|
@defproc[(log-max-level [logger logger?]
|
||||||
[topic (or/c symbol? #f) #f])
|
[topic (or/c symbol? #f) #f])
|
||||||
(or/c #f 'fatal 'error 'warning 'info 'debug)]{
|
(or/c log-level/c #f)]{
|
||||||
|
|
||||||
Similar to @racket[log-level?], but reports the maximum-detail level of logging for
|
Similar to @racket[log-level?], but reports the maximum-detail level of logging for
|
||||||
which @racket[log-level?] on @racket[logger] and @racket[topic] returns @racket[#t]. The
|
which @racket[log-level?] on @racket[logger] and @racket[topic] returns @racket[#t]. The
|
||||||
|
@ -191,7 +191,7 @@ currently returns @racket[#f] for all levels.
|
||||||
|
|
||||||
|
|
||||||
@defproc[(log-all-levels [logger logger?])
|
@defproc[(log-all-levels [logger logger?])
|
||||||
(list/c (or/c #f 'fatal 'error 'warning 'info 'debug)
|
(list/c (or/c #f log-level/c)
|
||||||
(or/c #f symbol?)
|
(or/c #f symbol?)
|
||||||
... ...)]{
|
... ...)]{
|
||||||
|
|
||||||
|
@ -289,7 +289,7 @@ Returns @racket[#t] if @racket[v] is a @tech{log receiver}, @racket[#f]
|
||||||
otherwise.}
|
otherwise.}
|
||||||
|
|
||||||
@defproc[(make-log-receiver [logger logger?]
|
@defproc[(make-log-receiver [logger logger?]
|
||||||
[level (or/c 'none 'fatal 'error 'warning 'info 'debug)]
|
[level log-level/c]
|
||||||
[topic (or/c #f symbol?) #f]
|
[topic (or/c #f symbol?) #f]
|
||||||
... ...)
|
... ...)
|
||||||
log-receiver?]{
|
log-receiver?]{
|
||||||
|
@ -316,3 +316,75 @@ the last given @racket[level]). A @racket[level] for a @racket[#f]
|
||||||
provided @racket[topic]. If the same @racket[topic] is provided multiple
|
provided @racket[topic]. If the same @racket[topic] is provided multiple
|
||||||
times, the @racket[level] provided with the last instance in the
|
times, the @racket[level] provided with the last instance in the
|
||||||
argument list takes precedence.}
|
argument list takes precedence.}
|
||||||
|
|
||||||
|
|
||||||
|
@; ----------------------------------------
|
||||||
|
@section{Additional Logging Functions}
|
||||||
|
|
||||||
|
@note-lib[racket/logging]
|
||||||
|
@(require (for-label racket/logging))
|
||||||
|
@(define log-eval (make-base-eval))
|
||||||
|
@(interaction-eval #:eval log-eval
|
||||||
|
(require racket/logging))
|
||||||
|
|
||||||
|
@defproc[(log-level/c [v any/c])
|
||||||
|
boolean?]{
|
||||||
|
Returns @racket[#t] if @racket[v] is a valid logging level (@racket['none],
|
||||||
|
@racket['fatal], @racket['error], @racket['warning], @racket['info], or
|
||||||
|
@racket['debug]), @racket[#f] otherwise.
|
||||||
|
|
||||||
|
@history[#:added "6.2.900.5"]{}
|
||||||
|
}
|
||||||
|
|
||||||
|
@defproc[(with-intercepted-logging
|
||||||
|
[interceptor (-> (vector/c
|
||||||
|
log-level/c
|
||||||
|
string?
|
||||||
|
any/c
|
||||||
|
(or/c symbol? #f))
|
||||||
|
any)]
|
||||||
|
[proc (-> any)]
|
||||||
|
[log-spec (or/c log-level/c #f)] ...)
|
||||||
|
any]{
|
||||||
|
|
||||||
|
Runs @racket[proc], calling @racket[interceptor] on any log event that would
|
||||||
|
be received by @racket[(make-log-receiver (current-logger) log-spec ...)].
|
||||||
|
Returns whatever @racket[proc] returns.
|
||||||
|
|
||||||
|
@defexamples[
|
||||||
|
#:eval log-eval
|
||||||
|
(let ([warning-counter 0])
|
||||||
|
(with-intercepted-logging
|
||||||
|
(lambda (l)
|
||||||
|
(when (eq? (vector-ref l 0) ; actual level
|
||||||
|
'warning)
|
||||||
|
(set! warning-counter (add1 warning-counter))))
|
||||||
|
(lambda ()
|
||||||
|
(log-warning "Warning!")
|
||||||
|
(log-warning "Warning again!")
|
||||||
|
(+ 2 2))
|
||||||
|
'warning)
|
||||||
|
warning-counter)]
|
||||||
|
|
||||||
|
@history[#:added "6.2.900.5"]{}}
|
||||||
|
|
||||||
|
@defproc[(with-logging-to-port
|
||||||
|
[port output-port?] [proc (-> any)]
|
||||||
|
[log-spec (or/c 'fatal 'error 'warning 'info 'debug symbol? #f)] ...)
|
||||||
|
any]{
|
||||||
|
|
||||||
|
Runs @racket[proc], outputting any logging that would be received by
|
||||||
|
@racket[(make-log-receiver (current-logger) log-spec ...)] to @racket[port].
|
||||||
|
Returns whatever @racket[proc] returns.
|
||||||
|
|
||||||
|
@defexamples[
|
||||||
|
#:eval log-eval
|
||||||
|
(let ([my-log (open-output-string)])
|
||||||
|
(with-logging-to-port my-log
|
||||||
|
(lambda ()
|
||||||
|
(log-warning "Warning World!")
|
||||||
|
(+ 2 2))
|
||||||
|
'warning)
|
||||||
|
(get-output-string my-log))]
|
||||||
|
|
||||||
|
@history[#:added "6.2.900.5"]{}}
|
||||||
|
|
|
@ -238,6 +238,24 @@
|
||||||
(test #f sync/timeout 0 r2)
|
(test #f sync/timeout 0 r2)
|
||||||
(test #f sync/timeout 0 r22))
|
(test #f sync/timeout 0 r22))
|
||||||
|
|
||||||
|
; --------------------
|
||||||
|
; racket/logging
|
||||||
|
|
||||||
|
(require racket/logging)
|
||||||
|
(define (test-intercepted-logging)
|
||||||
|
(define log '())
|
||||||
|
(cons (with-intercepted-logging
|
||||||
|
(lambda (v) (set! log (cons (vector-ref v 1) log)))
|
||||||
|
(lambda ()
|
||||||
|
(log-warning "1")
|
||||||
|
(log-warning "2")
|
||||||
|
(log-warning "3")
|
||||||
|
(log-info "4")
|
||||||
|
#t)
|
||||||
|
'warning)
|
||||||
|
log))
|
||||||
|
(test '(#t "3" "2" "1") test-intercepted-logging)
|
||||||
|
|
||||||
; --------------------
|
; --------------------
|
||||||
|
|
||||||
(report-errs)
|
(report-errs)
|
||||||
|
|
60
racket/collects/racket/logging.rkt
Normal file
60
racket/collects/racket/logging.rkt
Normal file
|
@ -0,0 +1,60 @@
|
||||||
|
#lang racket/base
|
||||||
|
|
||||||
|
(require racket/contract/base)
|
||||||
|
|
||||||
|
(provide log-level/c)
|
||||||
|
|
||||||
|
(define log-level/c (or/c 'none 'fatal 'error 'warning 'info 'debug))
|
||||||
|
(define log-spec? (listof (or/c symbol? #f)))
|
||||||
|
(define log-event? (vector-immutable/c log-level/c string? any/c (or/c symbol? #f)))
|
||||||
|
|
||||||
|
(provide/contract [with-intercepted-logging
|
||||||
|
(->* ((-> log-event? any)
|
||||||
|
(-> any))
|
||||||
|
#:rest log-spec?
|
||||||
|
any)]
|
||||||
|
[with-logging-to-port
|
||||||
|
(->* (output-port? (-> any))
|
||||||
|
#:rest log-spec?
|
||||||
|
any)])
|
||||||
|
|
||||||
|
(define (receiver-thread receiver stop-chan intercept)
|
||||||
|
(thread
|
||||||
|
(lambda ()
|
||||||
|
(define (clear-events)
|
||||||
|
(let ([l (sync/timeout 0 receiver)])
|
||||||
|
(when l ; still something to read
|
||||||
|
(intercept l) ; interceptor gets the whole vector
|
||||||
|
(clear-events))))
|
||||||
|
(let loop ()
|
||||||
|
(let ([l (sync receiver stop-chan)])
|
||||||
|
(cond [(eq? l 'stop)
|
||||||
|
;; we received all the events we were supposed
|
||||||
|
;; to get, read them all (w/o waiting), then
|
||||||
|
;; stop
|
||||||
|
(clear-events)]
|
||||||
|
[else ; keep going
|
||||||
|
(intercept l)
|
||||||
|
(loop)]))))))
|
||||||
|
|
||||||
|
(define (with-intercepted-logging interceptor proc . log-spec)
|
||||||
|
(let* ([orig-logger (current-logger)]
|
||||||
|
;; We use a local logger to avoid getting messages that didn't
|
||||||
|
;; originate from proc. Since it's a child of the original logger,
|
||||||
|
;; the rest of the program still sees the log entries.
|
||||||
|
[logger (make-logger #f orig-logger)]
|
||||||
|
[receiver (apply make-log-receiver logger log-spec)]
|
||||||
|
[stop-chan (make-channel)]
|
||||||
|
[t (receiver-thread receiver stop-chan interceptor)])
|
||||||
|
(begin0
|
||||||
|
(parameterize ([current-logger logger])
|
||||||
|
(proc))
|
||||||
|
(channel-put stop-chan 'stop) ; stop the receiver thread
|
||||||
|
(thread-wait t))))
|
||||||
|
|
||||||
|
(define (with-logging-to-port port proc . log-spec)
|
||||||
|
(apply with-intercepted-logging
|
||||||
|
(lambda (l) (displayln (vector-ref l 1) ; actual message
|
||||||
|
port))
|
||||||
|
proc
|
||||||
|
log-spec))
|
Loading…
Reference in New Issue
Block a user