Can I capture all terminal output with protocol/1?

Hi everyone!

I can use protocol/1 to create a log of my interaction with the Prolog session but if I call a shell command from inside Prolog I don’t get the output of the shell command in the protocol file.

See the example below:

% module protocol.pl
:- module(protocol, [say_hello/0
                    ]).
say_hello:-
        debug(hello,'About to say hello',[])
        ,shell('echo Hello',_S)
        ,debug(hello,'Just said hello',[])
        ,writeln('And hello again')
        ,debug(hello,'I did it again',[]).

% Load the module, start a protocol, call say_hello, stop protocolling (?) and exit.
?- use_module(protocol).
true.

?- protocol('hello.log').
true.

?- debug(hello).
true.

?- say_hello.
% About to say hello
Hello
% Just said hello
And hello again
% I did it again
true.

?- noprotocol.
true.

?- halt.

% See what we got in the protocol file.
stassaP@VARYS:/mnt/c/Users/Public/protocol$
cat hello.log
true.

debug(hello).


true.

say_hello.


% About to say hello
% Just said hello
And hello again
% I did it again
true.

noprotocol.

The first “Hello” that is output by the echo shell command is missing from the protocol file. I think that’s how it’s supposed to be - i.e. protocol/1 is meant to only capture the output of SWI-Prolog.

However I’d like to be able to keep everything that I see on my terminal during a SWI-Prolog session. Especially if I’m running shell commands with long output. I can possibly do that with a shell command but that won’t be portable between OSs.

Is there any way to do what I want?

Note I’m on swipl 9.3.18-36-g0650b4e37 64 bits running under WSL (ubuntu 22.04)

Hello,
Just to say that I did not know that the protocol module existed.
Thank you for this discovery :slight_smile:

1 Like

Not for shell/1 or any other code using the system I/O streams. protocol/1 captures the Prolog user streams. On some systems it is probably possible to also capture the underlying libc stdout, etc., but that is already hard. Capturing the output of other processes is yet another issue. Might be possible on some platforms, but not in general.

What you can do is to use process_create/3 instead, bind the output streams to a pipe and have a thread that copies these streams to the Prolog streams. That is done by pack_install/1 for running the build steps. See run_process/3 from library(build/tools).

1 Like

Thanks Jan. I’ll see if I can bodge something together like you suggest or I’ll find a different way to do it directly in the shell.