Racket: Logging to a file
Asked Answered
B

4

5

I was writing a Racket program that needed to log information but I wanted to store the logs in a file. My first attempt was to use "with-logging-to-port" and use "open-output-file" to create an output-port.

#lang racket
(require racket/logging)
(define (identity/log x)
  (log-info "returning ~a" x) x)

(with-logging-to-port (open-output-file "testing.txt")
  (λ () (identity/log 4)) 'info)

However when I open the file afterwards it is blank! In addition, I can't run this more than once because "open-output-file" gives me an error that the file already exists.

Bab answered 26/8, 2016 at 12:39 Comment(0)
D
4

I'm pretty sure the reason is that you don't close the file properly. This should work:

(let ((out (open-output-file "testing.txt"
                             ; just to not get an error on consecutive runs
                             #:exists 'append))) 
  (with-logging-to-port out
    (λ () (identity/log 4)) 'info)
  (close-output-port out))

Instead of doing housekeeping you can use call-with-output-file

(call-with-output-file "testing.txt"
  (λ (out) 
    (with-logging-to-port out
      (λ () (identity/log 4)) 'info))
  #:exists 'append)
Dedifferentiation answered 26/8, 2016 at 13:59 Comment(0)
P
2

If log information is in a list of strings, say lst, one can also use following function:

(display-lines-to-file  lst "mylog.txt" 
    #:exists 'append)

See: https://docs.racket-lang.org/reference/Filesystem.html?q=lines-file#%28def._%28%28lib._racket%2Ffile..rkt%29._display-lines-to-file%29%29

(require racket/file)
(display-lines-to-file   lst     path                
     [  #:separator separator                
        #:mode mode-flag                 
        #:exists exists-flag])      →       void?
Pruitt answered 27/8, 2016 at 8:34 Comment(0)
M
2

I give you my log func's source :

(define my_logger (make-logger 'my-log))

(define logger_thread #f)

(define (log fmt . content)
  (log-message my_logger 'info "" (string-append (format-time (now)) " " (apply format (cons fmt content)))))

(define (start-logger log_path)
  (let ([r (make-log-receiver my_logger 'info)]
        [riqi (format-riqi (now))])
    (set! logger_thread
          (thread
           (lambda ()
             (let ([log_dir (build-path log_path (substring riqi 0 4))])
               (when (not (directory-exists? log_dir))
                 (make-directory log_dir))
               (with-output-to-file 
                   (build-path log_path (substring riqi 0 4) riqi) #:exists 'append
                   (lambda ()
                     (let loop ()
                       (match (sync r)
                         [(vector l m v v1)
                          (printf "~a\n" v)
                          (flush-output)])
                       (loop))))))))))

(define (restart-logger)
  (kill-thread logger_thread)
  (start-logger))

(define (launch-log-daemon log_path)
  (start-logger log_path)
  (thread
   (lambda ()
     (let loop ()
       (sync
        (alarm-evt (+ (current-inexact-milliseconds) (* 1000 60 60))))
       (when (= 0 (date-hour (seconds->date (current-seconds))))
         (restart-logger))
       (loop)))))

At the beginning of the app, you should run:

(launch-log-daemon log_path)

then you can use it like this:

(log "~a:~a" "some1" "some2")

I use the date as the log file directory and name,

it will automatically start a new log file when date changed.

foramt-riqi and format-time is here:

(define (format-riqi the_date)
  (format "~a~a~a" 
          (date-year the_date) 
          (~a (date-month the_date) #:min-width 2 #:pad-string "0" #:align 'right)
          (~a (number->string (date-day the_date)) #:min-width 2 #:pad-string "0" #:align 'right)))

(define (format-time the_date)
  (format "~a:~a:~a" 
          (~a (date-hour the_date) #:min-width 2 #:pad-string "0" #:align 'right)
          (~a (date-minute the_date) #:min-width 2 #:pad-string "0" #:align 'right)
          (~a (date-second the_date) #:min-width 2 #:pad-string "0" #:align 'right)))
Merino answered 27/8, 2016 at 12:18 Comment(1)
sorry, please forgive me, a long time not to check the message, format-riqi and format-time is my chinglish function, means format date and time.Merino
J
1

Open your file with flag 'append. For example:

    (open-output-file "testing.txt" #:exists 'append )
Jollify answered 26/8, 2016 at 12:58 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.