tags:

views:

4290

answers:

6

I have a batch file that executes a java application. I'm trying to modify it so that whenever an exception occurs, it'll write the STDERR out to a file.

It looks something like this:

start java something.jar method %1 %2 2>> log.txt

Is there a way I can write the arguments %1 and %2 to the log.txt file as well? I don't want to write it to the log file everytime this batch file gets called, only when an exception occurs.

I tried searching for a way to redirect STDERR into a variable, but I couldn't figure it out. Ideally I'd like the log file to look something like:

Batch file called with parameters:
- "first arg"
- "second arg"
Exception: 
java.io.exception etc...

------------------------------------

Batch file called with parameters:
- "first arg"
- "second arg"
Exception: 
java.io.exception etc...
A: 

How about something like this (untested):

@echo off
@echo Batch file called with parameters: >> log.txt
@echo - %1 >> log.txt
@echo - %2 >> log.txt
start java something.jar method %1 %2 2>> log.txt
cdonner
But that would log the output each time the batch file was called wouldn't it? I'd like to avoid that if possible and just have it log if the java app throws an exception.
nivlam
A: 

I don't get exactly what you are asking, but here's some info that may help...

You can redirect stderr separately from stdout in a .cmd or .bat file. To redirect stderr, use something like this:

MyCommand.exe > command.stdout.txt  2> command.stderr.txt

Then, you can check the command.stderr.txt for content, and if any is present, concatenate it to the command.stdout.txt into your log file. Or you could concat it in any case. If you like you could also echo the command that you ran, into the final log file.

You can also check for the exit code in a batch file, using the %ERRORLEVEL% env var. Exe files are expected to set ERRORLEVEL in case of an error. I don't know if java.exe does this. It should, if it is a good citizen on Windows. This might be an alternative way of finding out if the Java app exited with an error condition. But this is no guarantee that stderr got nothing. For example, a Java app might print out an exception and stack trace, and then exit with code 0, which indicates success. In which case stderr would have gunk in it, but ERRORLEVEL would be zero.

EDIT: s/ERROR_LEVEL/ERRORLEVEL

Cheeso
I'm trying to avoid writing to a file every time this batch file is called. This batch file gets called very often and it lives on an already IO saturated server.
nivlam
Misread your answer a little bit. I'm already writing the stderr out to a log file, but I want to try and write out the parameters that were passed to the batch file as well. I only want to log these parameters when it writes stderr to the log.
nivlam
It's called %ERRORLEVEL%, not %ERROR_LEVEL%. Furthermore you should check for it with "if errorlevel 1 ..." not comparing to %errorlevel% which doesn't actually exist.
Joey
A: 

Try using ERRORLEVEL

java something.jar method %1 %2 2>> log.txt
IF %ERRORLEVEL% NEQ 0 GOTO Error

Error:
@ECHO There was an error
@ECHO Arg 1: %1 >> log.txt
@ECHO Arg 2: %2 >> log.txt
SpliFF
I just tried this and errorlevel is always zero, even when java throws an exception.
nivlam
If the java main class is written by you, you can wrap the whole stuff in a try/catch and use exit(1) in catch block to set error level in the environment
Tahir Akhtar
A: 

The only working solution I see would be to redirect stderr to a temporary file

java blah.jar %1 %2 2>stderr

and afterwards looking whether something has been written to the file and writing to the log in that case.

for %%i in (stderr) do if %%~zi GTR 0 (
    echo Parameters: %1 %2 >>log.txt
    type stderr >> log.txt
)

If the batches aren't run in sequence but rather simultaneously you need to find something to uniquify the temp variable:

set file=%time::=%
set /a file=file
set file=%file%%random%
java blah.jar %1 %2 2>stderr_%file%
for %%i in (stderr) do if %%~zi GTR 0 (
    echo Parameters: %1 %2 >>log.txt
    type stderr >> log.txt
)

This will avoid clashes between multiple running batches. However, you are currently not using anything to lock writing to your log file and things may appear out of place when other things get written to it (with other batches you might get interleaving in the echo and type commands or, when you're redirecting output of java to that file as well, then it may get mixed up with regular output of the java program:

Parameters: foo bar
Some regular output
Parameters: foo2 bar2
More output
NullPointerException at Blah: What we really wanted to have right after the parameters
IOException at Blah: This exception belongs to the parameters foo2 bar2

You can use another file as semaphore for writing to the log to avoid the batch outputs getting mixed: create the file [copy nul file] when you want to write to the log, delete it afterwards and before you attempt to create it check whether it is actually there and wait until it disappears. You can't do anything about the stdout log being mixed into the file, though, except you use that temp file approach for stdout as well (and simply type the stdout log to log.txt when the Java program finished, but, again with using the semaphore.

Joey
A: 

A batch file like this should do the trick.

start_prog.cmd

CALL :Start_Prog arg1 arg2
GOTO :EOF

:Start_Prog
    something.py %1 %2 2>&1 1>nul | "C:\Python26\python.exe" format_output.py %1 %2 >>log.txt
    GOTO :EOF

Here I'm passing stderr via a pipe and passing arguments as arguments. The output is then appended to a log.txt file.

Throw away stdout

1>nul

Redirect stderr to stdout

2>&1

Pipe the stderr into a script to format the output, and pass arguments as arguments.

| "C:\Python26\python.exe" format_output.py %1 %2

Append output to a "log.txt".

>>log.txt

On my system I need to call python.exe otherwise the pipe doesn't work.

Here are the two files I used "something.py" and *"format_output.py"*.

something.py

import sys
print >>sys.stdout, " ".join(sys.argv[1:])
print >>sys.stderr, "java.io.exception etc..."

format_output.py

import sys

print "Batch file called with parameters:"
for arg in sys.argv[1:]:
    print '- "{0}"'.format(arg)

print "Exception:"
for line in sys.stdin:
    print line

And finaly here's the output.

log.txt

Batch file called with parameters:
- "arg1"
- "arg2"
Exception:
java.io.exception etc...

The only thing missing is that something is always written to the "log.txt" file.

To tidy this up further I would move writing the log file into *"format_output.py"*.

You could then add a check to see if the stderr from your program is blank.

William B-R
Jay
+1  A: 

Something like this might work:

javastart.cmd

@echo off
set params=%*
for /f "delims=" %%e in ('java something.jar method %1 %2 ^>nul') do (
    echo Batch file called with parameters:>>log.txt
    echo - Args[]: %*>>log.txt
    echo - Arg[1]: %1>>log.txt
    echo - Arg[2]: %2>>log.txt
    echo Exception: %%e
)

I am not a java programmer myself, I cannot test this output/situation but:

1: %* means every parameters, from 1st to last (even %12 although it's not directly available.. ) whatever the formating. Might be better to use this than delimit those. In the even of bad spacing/quoting, you would have the full parameters too. I added a line in the log, to show the full line then the parameters. You can see where the problem was if it's a matter of bad arguments.

2: sending the stdout to null (^>nul) will only keep the stderr output, set into %%e

3: Whatever is in the do part will only happen is the for test statement actually has anything as an output, i.e. if %%e is set.

With those being said, you have to test the script and see if the exception is actually sent to stderr or, like some other softwares, to stdout even if an error occured.

I hope this helps.

Jay