# Temporarily redirect the output of Print[ ] to a second file

I have started using Mathematica to automate file backup operations. The logistics I need make Mathematica a good choice. I am testing and developing the Notebook manually, and Print outputs document the operational events. The saved Notebook provides a record of the process for that day.

I would like to have an easy way to direct Print output to a separate file, for example, by adding

DirectPrintOutputTo["filename "<>DateList["Year","Month","Day"]<>".txt"]


at the beginning of a Notebook. The advantages of this approach seem obvious. I assume I would need to load my function from a package before calling it. Is something like this this possible? Any suggestions about how to do it?

Alternatively, maybe I could write a print function called PrintTo that would, on first use, open an output file with the name assigned to printToFileName, and I could use the editor to change all the Print functions to PrintTo functions. Not so fancy, but I think I know how to how to do it.

I think that I answered my own question, in the sense that my alternative idea seems straightforward and pretty implementable.

-
My current scripting approach used Print statements to print results to the scripting notebook. I don't think PutAppend would work (but I may not understand your suggestion). – George Wolfe Jul 26 '13 at 19:34
I have missunderstood the question, I thought you are going to write this not to change Print. So it is not good suggestion then :) – Kuba Jul 26 '13 at 19:54
Possible duplicates: (5040), (7081), (22584) – Mr.Wizard Jul 26 '13 at 20:31
I wonder if one could use 'TagSet' to make extend the functionality of 'Print' to your specific needs. I don't have much time to think through this now (heading away for a week). May I can work something up later tonight. – Jagra Jul 27 '13 at 17:30

From the documentation for Print: "Print sends its output to the channel $Output." Therefore you can just do this: $Output = OpenWrite["filename " <> DateList["Year", "Month", "Day"] <> ".txt"];


before you run the file.

Something more structured would be like this:

stream = OpenWrite["c:/users/gre/desktop/derp.txt"];
AppendTo[$Output, stream]; (* run your file here *) Close[stream];$Output = Most[$Output];  Since Print by default outputs to stdout, you could also pipe the output by running the notebook as a script. - I tried using Block[{$Output = ..., but this didn't seem to work for $Output. – amr Jul 26 '13 at 20:20 Beat me to the punch about $Output. However, I was working on a generic environment. – rcollyer Jul 26 '13 at 20:21
@rcollyer Well you both beat me, so... – Mr.Wizard Jul 26 '13 at 20:23
@rcollyer agreed. usually i go the lazy route :D – amr Jul 26 '13 at 20:23
@Mr.Wizard I beat both of you a long time ago, and Leonid. :) – rcollyer Jul 26 '13 at 20:24

I don't recommend modifying Print to redirect the output when it is not necessary. Instead, you can build up a custom solution that suits your needs. I use a variant of the following for logging in my projects and you should be able to tweak them to your application.

Clear[logFile, writeLog, showLog];
logFile := "project-" <> DateString[##, {"Year", "Month", "Day"}] <> ".log" &;

writeLog[message_String] :=
Module[{str = OpenAppend[logFile[]], date = DateString[]},
WriteString[str, StringJoin @@ Riffle[{date, message, "\n"}, "\t"]];
Close[str];
]

showLog := FilePrint@logFile@## &;
clearLog := Module[{str = OpenWrite[logFile@##]}, Close@str;] &


Note the use of OpenAppend and OpenWrite in the above functions. OpenAppend creates a new file if none exists, but appends to an already existing file. OpenWrite, on the other hand, simply creates a new empty file regardless of whether a file already exists with that name (thus erasing data, which is what we want here).

Since writeLog just takes a string as input, you can simply replace your Print commands with writeLog and it should work fine.

logFile[]
(* "project-20130726.log" *)

writeLog["Hello world"];
showLog[]
(* Fri 26 Jul 2013 12:51:31 Hello world *)

clearLog[]
showLog[]
(* crickets *)

-

This is already built-in; Print directs all output to the $Output channel where a channel is just a list of open streams. So, to redirect it, simply oldout =$Output;
strm = OpenAppend["filename "<>DateString[]<>".txt"];
$Output = {strm};  and to switch it back $Output = oldout;
Close[strm];


Assuming you just want an environment where Print is re-directed, you could do something like this

ClearAll[RedirectPrint];
SetAttributes[RedirectPrint, HoldRest];
Options[RedirectPrint] = {OpenMethod -> OpenAppend};
RedirectPrint[filename_String, body_, opts:OptionsPattern[]] :=
Block[{old, strm, open},
open = OptionValue[OpenMethod]; (* needs error checking here *)
old = $Output; InternalWithLocalSettings[ strm = open[filename];$Output = {strm},
body,
\$Output = old;
Close[strm]
]
]
`
-
@Mike the change is good, I was taking the OP's code directly without looking at it ... – rcollyer Jul 28 '13 at 3:09