I have a racket CLI application that used to be a single file and now spans multiple files. I added logging to that app based on what I'd learnt (see Logging With Racket // Grinning Cat). So in my main.rkt I have the following:
(define-logger agent) (define agent-logger-receiver (make-log-receiver agent-logger 'info 'agent)) (current-logger agent-logger) (define (write-to-file destination content) (with-output-to-file destination (λ () (displayln content)) #:mode 'text #:exists 'append)) (define (write-to-port destination content) (displayln content destination)) (define log-destinations (list (list write-to-file "pii_agent.log") (list write-to-port (current-error-port)))) (define (send-log-content content destinations) (unless (null? destinations) (let ([ destination (car destinations)]) ((car destination) (cadr destination) content)) (send-log-content content (cdr destinations)))) ; Listen for events on the log-receiver (void (thread (λ()(let loop () (define log-vector (sync agent-logger-receiver)) (define content (format "[~a] ~a\n" (vector-ref log-vector 0) (vector-ref log-vector 1))) (send-log-content content log-destinations) (loop)))))
Which roughly means that I have a logger setup to log to two places (a file and STDERR) and a thread that runs waiting for the logger to get called.
Then in another file I have a number of log statements like:
(log-info "Run completed.")
A couple of times (i.e. not consistently) I've received the following error toward the end of the applications' execution:
open-output-file: the current custodian has been shut down context...: /Users/robertpostill/software/pii_spider/main.rkt:30:2: send-log-content /Users/robertpostill/software/pii_spider/main.rkt:39:4
Which makes me worry that I've setup a race condition and that the thread is terminated by the GC before that final log message is sent to it. Am I correct? If so what should I do? Do I set up a thread per file/module? Is spinning off a thread like this the right thing to do?
Thanks in advance for any advice or help.