1

I am trying to permanently redirect stdout to a file but all of the examples I can find about doing this involve doing so inside a let or inside a with-open-file using the standard-output global. Is there a way can do an application wide redirect?

EDIT: Here is how I've tried to do the redirect with standard output:

(Setf *log* (open "/Users/Mike/Desktop/some.txt" :direction :output :if-exists :append))
(Setf *standard-output* *log*)
(print "Test")

This stops output to the REPL but nothing shows up in the file (which does exists and is seen by probe-file) from the print call.

EDIT: I've tried using the Dribble function:

(Dribble "/Users/Mike/Desktop/some.txt")

(format t "hello")

But I get the following error:

Error: There is no applicable method for the generic function: #STANDARD-GENERIC-FUNCTION CCL::STREAM-SET-COLUMN #x30200006557F when called with arguments: (# 0) While executing: #, in process Listener(11). Type cmd-/ to continue, cmd-. to abort, cmd-\ for a list of available restarts. If continued: Try calling it again Type :? for other options.

Mike2012
  • 7,629
  • 15
  • 84
  • 135
  • Does `(setf *standard-output* ...)` not work? – Joshua Taylor Jun 18 '14 at 21:16
  • @JoshuaTaylor Yes, I've added what I tried to my questions. It stops output to the repel but nothing shows up int he file. – Mike2012 Jun 18 '14 at 21:36
  • Um, that doesn't show anything that should produce any output though. What forms, after doing that, don't produce output? Are you doing something with multiple threads? (E.g., if you're using SLIME, then you might be using multiple threads without knowing it. You may only be setting \*standard-output* to \*log* in one of those threads.) – Joshua Taylor Jun 18 '14 at 21:44
  • Also, if you're looking to do a REPL transcript (not clear whether you want that, or to direct other stuff), you might consider using the standard function [dribble](http://www.lispworks.com/documentation/HyperSpec/Body/f_dribbl.htm). – Joshua Taylor Jun 18 '14 at 21:50

1 Answers1

5

I think your problem has to do with buffering. Try force-output:

(force-output *log*)

Note that closing streams automatically flushes the buffers, and lisps usually close streams on normal exit, so nothing is actually lost, it just takes time to appear on disk.

Additionally, please note that the Common Lisp REPL interaction is done over many different stream variables, not just one (although many of them are aliases of others).

Actually, if you want to save the log of your session (i.e., keep the REPL on the screen and save the transcript to a file), the standard facility is provided by dribble - try it!

sds
  • 58,617
  • 29
  • 161
  • 278
  • Thanks! This does work but one problem I still have is that I need to flush the buffer before things actually get pushed to the file. I would like to use this functionality for error logging and this work fine for caught error (because I could flush the buffer from the error handler) but if there was an uncaught error it might get totally missed in the log. Is there anyway to force all standard output to get flushed? – Mike2012 Jun 19 '14 at 16:49
  • 1
    Buffers are flushed on `close`, so nothing is lost. I _really_ recommend that you give `dribble` a try before proceeding with home-brewed solutions. – sds Jun 19 '14 at 16:55
  • Thanks again for all your advice. I've tried using dribble but I get an error (I posted in another edit). I'm guessing this might have something to do with the specific implementation of dribble, unless I'm using dribble wrong? It seems like you just pass it a path to a log file. – Mike2012 Jun 19 '14 at 17:09
  • Please [report the `dribble` error to your CL vendor](http://trac.clozure.com/ccl/newticket). Please do not edit your question but start a new one. It is hard to chase a moving target. – sds Jun 19 '14 at 17:12