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.