Setting user_error for a thread pool

When making web services in SWI-Prolog, I typically set up a thread pool for the handlers as follows:

:- multifile thread_pool:create_pool/1.

thread_pool:create_pool(handler_pool) :-
    thread_pool_create(handler_pool, 20, []).

:- http_handler(root(.), home_page_handler,
                [method(get), id(home_page), 
                 spawn(handler_pool)]).

However, it seems that user_error isn’t visible for threads created in the thread pool, so I can’t see messages from debug/3.

e.g.


?- thread_create_in_pool(handler_pool, format(user_error, "hello from other thread", []),  Id, []), 
   thread_join(Id).
% no message?
Id = <thread>(15,0x2a8553f20).

?- thread_create(format(user_error, "hello from other thread", []), Id, []),
   thread_join(Id).
hello from other thread
Id = <thread>(15,0x13af49e00).

This obviously makes debugging handlers annoying. Is there a way to set the user_error stream for thread-pool-created threads?

This doesn’t reproduce (tried with my local copy of the website). I fear I need a complete example. This was a problem long ago when the pool manager was (lazily) created from a thread that had I/O connected to something unusable. As is, the pool manager should inherit its streams from the main thread and threads created in the pool inherit from the pool manager.

Ah, I see. Indeed, I see that it acts as expected when I run a normal top-level from the terminal. I suspect then this is because I’m running the top-level from sweep, inside Emacs, so the initial streams are pointing somewhere else.

Is there any way then to change the streams of the thread manager thread? I tried doing thread_exit('__thread_pool_manager'), in the hopes of restarting the manager thread with the correct streams, but that seems to have broken everything :sweat_smile:

Update: A workaround is to specifically set the output for the debugging, e.g. stream_property(S, alias(user_output)), debug(myserver > S).

I see. I wrote something for that when trying to get debug messages from a server in an SSH login (see the libssh pack, which allows using SWI-Prolog as ssh server such that you can safely get a remote console). Here is the code:

:- module(msg, [capture_messages/1]).

:- dynamic
       captured_messages/3.
:- thread_local
       thread_error_stream/1.

user:message_property(Level, stream(S)) :-
    captured_messages(Level, S, _).

%!  capture_messages(+Level) is det.
%
%   Redirect all messages of the indicated level to the console of the
%   current thread.  This is part of  the SSH library as it is notably
%   practical when  connected through SSH.  Consider  using trace/1 on
%   some predicate.  We catch capture the output using:
%
%       ?- capture_messages(debug).
%       ?- trace(p/1).

capture_messages(Level) :-
    (   thread_error_stream(S)
    ->  true
    ;   thread_self(Me),
	stream_property(S, alias(user_error)),
	asserta(thread_error_stream(S)),
	thread_at_exit(cleanup_message_capture)
    ),
    asserta(captured_messages(Level, S, Me)).

cleanup_message_capture :-
    thread_self(Me),
    retractall(captured_messages(_,_,Me)).

1 Like