开发者

Writing log statements to standard output with Matlab

开发者 https://www.devze.com 2023-04-11 19:34 出处:网络
We\'re starting Matlab from our Jenkins buildserver. As the build may take some time it would be nice to get some log-outputs while matlab is running. Is there a way to print text to standard output?

We're starting Matlab from our Jenkins buildserver. As the build may take some time it would be nice to get some log-outputs while matlab is running. Is there a way to print text to standard output? disp, fprintf and java.lang.System.out.printline only write to t开发者_JAVA技巧he matlab console, not to standard output.

Using a logfile or a pipe won't help, as Jenkins only reads from standard-output during a build step.

How can we write log-statements to the standard output while matlab is running?

EDIT: We're running Matlab 2010b on Windows


Depending what you are doing with Matlab you could probably launch it in command line without GUI. I used this on a server and it behaves pretty much like a shell script and writes to standards outputs.

See the startup options.

I used the following:

/path/to/matlab -nojvm -nodisplay -nosplash -nodesktop -r /path/to/mfile

EDIT: forgot to mention one very important little detail, place an exit command at the end of your mfile or Matlab will hang there waiting.


It seems that the combination of -wait and -log (not -logfile) clones the command window output to the parent console's stdout, but only if you call the MATLAB executable in [MATLABROOT]\bin, not [MATLABROOT]\bin\win64 (the subdirectory for current arch).

Tested on Windows with R2015b and R2016b:

C:\MATLAB\bin\matlab.exe -wait -log

NOT

C:\MATLAB\win64\bin\matlab.exe -wait -log

Remember to put an exit/quit in your script if you are running with -r.

The only trouble is that I can't seem to find any documentation for the -log option! Meh.


There don't seem to be any good ways to do this from within MATLAB. The easiest way I can think of doing this is by using a shell script. You could write a small shell script which would simply print any input to stdout, and then call that shell script from within matlab using the unix (or system) commands. Jenkins should be able to read the command-line output of the script and work with that.


I figured out a way to do this and am also doing it for Jenkins Matlab interface on windows.

Basic idea is that you will use diary command, but then tail -f the file, but you need a smart way to kill the tail command if you open multiple matlab instances because there will be name collisions. So the method I'm using is to name the file log.txt where the PID used is MATLAB's PID it is using when it opens.

There is an undocumented feature in MATLAB that allows you to get its PID. So now, both your batch file and MATLAB know the PID without having to read/write to a random text file that will get messy when executing multiple jobs. So the PID you use that as your unique identifier. The PID of "tail -f" is also used by MATLAB to kill tail -f to make the batch file die and is found by MATLAB using the commandline details associated with the process invocation since it uses again the unique PID log file name.

This uses some wmic commands and needs Windows Vista/7 or above. With XP you probably have to work harder to get the process ID's but should be still possible.

Here is what to do:

1) Get gnu awk for windows: http://gnuwin32.sourceforge.net/packages/gawk.htm

2) Get tail.exe from windows resource kit: http://www.microsoft.com/en-us/download/details.aspx?id=17657

3) Make sure tail and awk are in your path (the windows resourece kit I don't think automatically puts them in the path)

3) Create a batch file called matlabrun.bat as follows, (note: you need the @echo off, also the entire command is quite long, scroll right..)

@echo off
wmic process call create "c:\matlab\bin\win64\matlab.exe -r \"cd('c:\jenkins\workspace\test'); workdir=pwd; outpath=[pwd '\output'] ; try; run('C:\MATLAB\work\test_run'); end; quit; \" "  | findstr ProcessId | awk "{print $3}" | awk -F";" "{ print $1 }"

4) Create another batch file called run.bat with:

for /f %%i in ('matlabrun.bat') do (

 echo MATLAB Log... > log%%i.txt

 tail -f log%%i.txt

 set logfilename=log%%i.txt

 goto next

)

:next

del /f %logfilename%

5) The run.bat file will execute matlabrun.bat and since -wait is not passed, matlab will immediately return to the command line and execute the tail -f command. That will block the batch file from completing until you kill it. matlabrun.bat returns the PID of matlab.

6) Another important note: since you are using "wmic process create" which will provide you with a PID that MATLAB is using, but will default to a working directory of c:\windows\system32. So that is why I pass the work directory to matlab. wmic process create is also a bit particular about what parameters you put into your command string for matlab to run. So it appears to have a problem with using commas in your command string. So I suggest not to use those, or figure out how to escape them (it might be that ^, works, but I just removed my commas anyway in my matlab run command).

6) The "test_run.m" file contains the following code to write to the correct log file and to kill correct tail -f instance.

matlabpid=feature('getpid');
filename=['log',num2str(matlabpid),'.txt'];
filenamefull=[workdir,'\',filename];

diary(filenamefull);
disp('Script starting...')


%%% put your code here %%%


disp('Script completed...');
diary off;

%%% FIND PID of tail.exe and kill it 
%%% by using the name of the log file in the process command line
[a,b]=dos(['wmic process get Commandline,ProcessId']);
C=textscan(b,'%s','delimiter','\n');C=C{1};
for jj=1:size(C,1),
    if strfind(C{jj},filename),
        D=textscan(C{jj},'%s');D=D{1};
        dos(['taskkill /f /pid ',D{4}]) %kills tail.exe which is the log watcher
        break
    end
end

7) You start it by doing run.bat. It will go and execute matlab, then start tailing the output while MATLAB runs in real-time. Then when done it will delete the log file.

8) My directory structure / files are in these locations (I'm using win7 64bit):

c:\jenkins\workspace\test\tail.exe

c:\jenkins\workspace\test\awk.exe

c:\jenkins\workspace\test\matlabrun.bat

c:\jenkins\workspace\test\run.bat

c:\matlab\work\test_run.m

c:\matlab\bin\win64\matlab.exe

If you are using 32bit matlab, point it to the win32 directory. To get the correct PID, you need to specify the actualy matlab.exe binary in the win32 or win64 directory.


You can do this by pointing the -logfile option to the Jenkins log file. Something like the following:

"C:\path\to\matlab.exe" "-r" "functionToRun" "-logfile" "%JENKINS_HOME%\jobs\%JOB_NAME%\builds\%BUILD_NUMBER%\log" /wait


You can use the diary mode. Not sure if it will fit your specific implementation.

http://www.mathworks.com/help/techdoc/ref/diary.html


I didn't find a real solution. Mathworks created some wrapper tool. But this will only output the results after matlab has exited. You won't get any ouput during execution.

http://www.mathworks.de/support/solutions/en/data/1-ACT3YN/index.html?product=ML&solution=1-ACT3YN

So I'll have live without real live-output...


Or try using '-logfile' option in matlab.

matlab.exe -nodisplay -nosplash -nodesktop -wait -logfile logfile.txt -r "try script.m ;catch err; disp(err.message); end ; exit"

I prefer using bash (Execute shell) in Jenkins, then you can tail the log-file while matlab is running.

matlab.exe <...> &
matpid=$!
tail -f logfile.txt &
tailpid=$!
wait $matpid
matexit=$?
kill $tailpid
sleep 1 # Just to make sure kill is done before Jenkins step ends and no zombie processes
exit $matexit
0

精彩评论

暂无评论...
验证码 换一张
取 消