@@ -43,8 +43,16 @@ filter_config(Config) ->
4343log (#{meta  :=  #{mfa  :=  {? MODULE , _ , _ }}}, _ ) -> 
4444    ok ;
4545log (LogEvent , Config ) -> 
46+     % % Publishing the log message to an exchange might trigger more logging,
47+     % % triggering an infinite logging loop. To prevent that, we make use the
48+     % % process dictionary to record the fact that this logger was already
49+     % % entered. If that's the case when this function is called, we just drop
50+     % % the log event.
51+     Key  =  ? MODULE ,
52+     ReEntered  =  erlang :get (Key ) =/=  undefined ,
4653    case  rabbit_boot_state :get () of 
47-         ready  ->
54+         ready  when  not  ReEntered  ->
55+             erlang :put (Key , ? FUNCTION_NAME ),
4856            try 
4957                do_log (LogEvent , Config )
5058            catch 
@@ -53,22 +61,30 @@ log(LogEvent, Config) ->
5361                    % % removes the logger_exchange handler, which in
5462                    % % turn deletes the log exchange and its bindings
5563                    erlang :display ({? MODULE , crashed , {C , R , S }})
64+             after 
65+                 erlang :erase (Key )
5666            end ,
5767            ok ;
5868        _  -> ok 
5969    end .
6070
61- do_log (LogEvent , #{config  :=  #{exchange  :=  Exchange }} =  Config ) -> 
71+ do_log (
72+   LogEvent ,
73+   #{config  :=  #{exchange  :=  Exchange ,
74+                 setup_proc  :=  Pid }} =  Config ) -> 
6275    RoutingKey  =  make_routing_key (LogEvent , Config ),
6376    PBasic  =  log_event_to_amqp_msg (LogEvent , Config ),
6477    Body  =  try_format_body (LogEvent , Config ),
6578    Content  =  rabbit_basic :build_content (PBasic , Body ),
6679    case  mc_amqpl :message (Exchange , RoutingKey , Content ) of 
6780        {ok , Msg } ->
68-             case  rabbit_queue_type :publish_at_most_once (Exchange , Msg ) of 
69-                 ok  -> ok ;
70-                 {error , not_found } -> ok 
71-             end ;
81+             % % Publishing a message might involve a Erlang process, like a Ra
82+             % % server process, to log something and call itself. We need to
83+             % % publish the message asynchronously from a separate process and
84+             % % ignore the fate of that publish, to not block an Erlang
85+             % % process.
86+             Pid  !  {publish , Msg },
87+             ok ;
7288        {error , _Reason } ->
7389            % % it would be good to log this error but can we?
7490            ok 
@@ -164,12 +180,19 @@ wait_for_initial_pass(N) ->
164180    end .
165181
166182setup_proc (
167-   #{config  :=  #{exchange  :=  Exchange }} =  Config ) -> 
183+   #{id  :=  Id ,
184+     config  :=  #{exchange  :=  Exchange }} =  Config ) -> 
185+     % % We register this process using the logger handler ID. It makes
186+     % % debugging convenient but it's not critical. That's why we catch any
187+     % % exceptions and ignore the return value.
188+     _  =  catch  erlang :register (Id , self ()),
189+ 
168190    case  declare_exchange (Config ) of 
169191        ok  ->
170192            ? LOG_INFO (
171193               " Logging to ~ts  ready"  , [rabbit_misc :rs (Exchange )],
172-                #{domain  =>  ? RMQLOG_DOMAIN_GLOBAL });
194+                #{domain  =>  ? RMQLOG_DOMAIN_GLOBAL }),
195+             loop (Config );
173196        error  ->
174197            ? LOG_DEBUG (
175198               " Logging to ~ts  not ready, trying again in ~b  second(s)"  ,
@@ -182,6 +205,15 @@ setup_proc(
182205            end 
183206    end .
184207
208+ loop (#{config  :=  #{exchange  :=  Exchange }} =  Config ) -> 
209+     receive 
210+         {publish , Msg } ->
211+             _  =  rabbit_queue_type :publish_at_most_once (Exchange , Msg ),
212+             loop (Config );
213+         stop  ->
214+             ok 
215+     end .
216+ 
185217declare_exchange (#{config  :=  #{exchange  :=  Exchange }}) -> 
186218    try  rabbit_exchange :declare (
187219          Exchange , topic , true , false , true , [], ? INTERNAL_USER ) of 
0 commit comments