Search code examples
loggingprologhookinterpreterswi-prolog

Logging interactive queries in SWI-Prolog


I would like to intercept the queries handed to the interactive Prolog interpreter, in order to do some extra processing, e.g. to log the queries.

So far I have the following code that relies on the goal_expansion hook.

start_logging :-
    open('queries.log', write, _, [alias(querylog)]),
    assert(goal_expansion(X,X):-log(X)).

log(X) :-
    X==stop_logging -> % do not log stop command
        true
    ;
    prolog_load_context(source,_) -> % do not log queries in loaded files
        true
    ;
    write_term(querylog,:- X,[fullstop,nl]).

stop_logging :-
    close(querylog,[]),
    retract(goal_expansion(X,X):-log(X)).

After loading these clauses, start_logging will make the interpreter write the queries to queries.log, until stop_logging is executed.

My questions:

  • Is there an even more direct way of intercepting the goals handed to the interpreter, such that e.g. variable names are preserved? In my version, the query has already been parsed, so variable names are printed as an underscore followed by a number. Is it e.g. possible to obtain the string entered on the command line?
  • How robust is this solution? Does it reliably distinguish between interpreter goals and other goals? It seems that prolog_load_context(source,_) fails for goals not read from a file. Are there other cases to take care of?

Solution

  • If you specifically want to log your interactive session, with SWI-Prolog, you can use protocol/1:

    ?- protocol('my_queries.txt').
    true.
    
    ?- between(1, 3, X).
    X = 1 ;
    X = 2 ;
    X = 3.
    
    ?- ^D
    % halt
    $ cat my_queries.txt 
    true.
    
    between(1, 3, X).
    
    
    X = 1 ;;
    X = 2 ;;
    X = 3.
    
    
    % halt
    

    This will create a record of what happened, but as you see it also keeps your input.

    Is that your use case? There are many other things you could do but it really depends on what you need.