1:- module(log4p,[
    2  fatal/1,
    3  error/1,
    4  warn/1,
    5  info/1,
    6  debug/1,
    7  trace/1,
    8
    9  fatal/2,
   10  error/2,
   11  warn/2,
   12  info/2,
   13  debug/2,
   14  trace/2,
   15
   16  set_log_level/2,
   17  log_levels/1,
   18
   19  add_log_handler/1,
   20  remove_log_handler/1,
   21
   22  logf/3,
   23  log/2
   24  ]).   25
   26fatal(Message) :- logf(fatal,Message,[]).
   27error(Message) :- logf(error,Message,[]).
   28warn(Message) :- logf(warn,Message,[]).
   29info(Message) :- logf(info,Message,[]).
   30debug(Message) :- logf(debug,Message,[]).
   31trace(Message) :- logf(trace,Message,[]).
   32
   33
   34fatal(Message,Arguments) :- logf(fatal,Message,Arguments).
   35error(Message,Arguments) :- logf(error,Message,Arguments).
   36warn(Message,Arguments) :- logf(warn,Message,Arguments).
   37info(Message,Arguments) :- logf(info,Message,Arguments).
   38debug(Message,Arguments) :- logf(debug,Message,Arguments).
   39trace(Message,Arguments) :- logf(trace,Message,Arguments).
   40
   41:- dynamic log_level/1.   42:- thread_local log_level/1.   43
   44log_level(info).
   45
   46:- dynamic log_handler/1.   47:- thread_local log_handler/1.   48
   49log_handler(default_log_handler).
   50
   51add_log_handler(new_handler) :-
   52  Clause = log_handler(new_handler),
   53  Clause ; assertz(log_handler(new_handler)).
   54
   55remove_log_handler(new_handler) :-
   56  retractall(log_handler(new_handler)).
   57
   58default_log_handler(Level,Message) :-
   59  writef('%w: %w\n',[Level, Message]),
   60  flush_output.
   61
   62set_log_level(NewLevel,OldLevel) :-
   63  log_level(OldLevel),
   64  retractall(log_level(OldLevel)),
   65  asserta(log_level(NewLevel)).
   66
   67log_levels([trace,debug,info,warn,error,fatal]).
   68
   69valid_log_levels(ValidLevels) :-
   70  log_level(Level),
   71  log_levels(Levels),
   72  valid_log_levels(Level,Levels,ValidLevels).
   73
   74valid_log_levels(LogLevel,[LogLevel | Rest],[LogLevel | Rest]).
   75
   76valid_log_levels(LogLevel,[_Head|Rest],ValidLevels) :-
   77  valid_log_levels(LogLevel,Rest,ValidLevels).
   78
   79logf(Level,Message,Arguments) :-
   80  swritef(FullMessage,Message,Arguments),
   81  log(Level,FullMessage).
   82
   83% We don't log if the level is not valid
   84log(Level,_Message) :-
   85  log_levels(Levels),
   86  \+member(Level,Levels),
   87  !.
   88
   89% We also don't log if the level is too low
   90log(Level,_Message) :-
   91  log_levels(Levels),
   92  \+member(Level,Levels),
   93  !.
   94
   95log(Level,Message) :-
   96  forall(log_handler(Handler),apply(Handler,[Level,Message]))