The program I am making is designed to be run unattended, because of this I have redirected the stdout and stderr streams to a log file. While this works without any problems, while I am still making and debugging the software I would like it to show on the screen as well. Is this possible?
To redirect the streams I have used
System.setErr(logWriter);
System.setOut(logWriter);
Thanks.
a bit crude perhaps, but you could try this:
private static final isDebugMode = true;
...
if (!isDebugMode) {
System.setErr(logWriter);
System.setOut(logWriter);
}
Alternatively you could write your own PrintStream implementation which simultaneously writes to both your log file and the screen. It doesn't sound like you need this behaviour except in development though so the latter whilst actually a more accurate answer to your question is probably not what you actually want.
Yes. Logging frameworks (i.e. log4j) are best, isDebugMode
is handy in a development environment but if you really need to "tee" your stdout you can like so.
import java.io.PrintStream;
import java.io.File;
public class TeeStream extends PrintStream {
PrintStream out;
public TeeStream(PrintStream out1, PrintStream out2) {
super(out1);
this.out = out2;
}
public void write(byte buf[], int off, int len) {
try {
super.write(buf, off, len);
out.write(buf, off, len);
} catch (Exception e) {
}
}
public void flush() {
super.flush();
out.flush();
}
}
http://www.exampledepot.com/egs/java.lang/Redirect.html
// import java.io.FileOutputStream;
String dateString = new SimpleDateFormat("yyyyMMdd").format(new Date());
File logFile = new File("mylogfile_" + dateString +".log");
PrintStream logOut = new PrintStream(new FileOutputStream(logFile, true));
PrintStream teeStdOut = new TeeStream(System.out, logOut);
PrintStream teeStdErr = new TeeStream(System.err, logOut);
System.setOut(teeStdOut);
System.setErr(teeStdErr);
You'll soon find LOG.somelevel(msg)
much more manageable than System.out.println(msg)
. It is great to raise the log level when things are working well and lower the level when they aren't without deploying a debug build.
If you're on a Unix-like platform (anything except Windows) you can use the tee
program:
java myprogram | tee output
This will write the standard output to the console as well as the file called output
.
No, with your setup this is not possible. Possible solutions:
- Use some software to monitor the log file. On Linux/Unix,
less
has a "follow"-mode (Shift-F), which tracks the log file. Other systems should have similar code. This has the advantage of using the same setup in debugging & production.
- You should really consider using a proper logging framework (java.util.logging, Log4j or similar). This makes your logging setup much more flexible. Among many advantages, you can flexibly configure (without code changes), where your logs should go.
If you're on UNIX you could use tail -f logfile
to see lines as they are written to your logfile
If you don't want a proper logging framework
Standard Unix way is to redirect the output streams
ie run the program exex as
exe > log
will redirect stdout to log
but
exe
on its own will leave the output to the console.
If you want to do this in the program you would need a variable to test on and only redirect the streams if not testing
On both Linux and Windows (with cygwin installed) I always use log4j to log to a file and then use "tail" to display it. By default, tail -f (and less -F) update every second which I find too slow. Also, there are often several interesting log files that are worth looking at, and some of them include the date as part of their name. Here's the command I use on one of my systems:
( cd /var/log/myapp/; tail -Fq --lines=0 -s 0.05 $(find . -type f -name "*$(date '+%Y-%m-%d').log" ) ) &
This simultaneously tails each log file under /var/log/myapp/ which contains today's date in the file name. Very handy with log4j rolling log files. And -s 0.05 means only pause 0.05 seconds between checks for new output.