%% %% %CopyrightBegin% %% %% Copyright Ericsson AB 2018. All Rights Reserved. %% %% Licensed under the Apache License, Version 2.0 (the "License"); %% you may not use this file except in compliance with the License. %% You may obtain a copy of the License at %% %% http://www.apache.org/licenses/LICENSE-2.0 %% %% Unless required by applicable law or agreed to in writing, software %% distributed under the License is distributed on an "AS IS" BASIS, %% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. %% See the License for the specific language governing permissions and %% limitations under the License. %% %% %CopyrightEnd% %% -module(logger_handler_watcher). -behaviour(gen_server). %% API -export([start_link/0]). -export([register_handler/2]). %% gen_server callbacks -export([init/1, handle_call/3, handle_cast/2, handle_info/2, terminate/2]). -define(SERVER, ?MODULE). -record(state, {handlers}). %%%=================================================================== %%% API %%%=================================================================== -spec start_link() -> {ok, Pid :: pid()} | {error, Error :: {already_started, pid()}} | {error, Error :: term()} | ignore. start_link() -> gen_server:start_link({local, ?SERVER}, ?MODULE, [], []). -spec register_handler(Id::logger:handler_id(),Pid::pid()) -> ok. register_handler(Id,Pid) -> gen_server:call(?SERVER,{register,Id,Pid}). %%%=================================================================== %%% gen_server callbacks %%%=================================================================== -spec init(Args :: term()) -> {ok, State :: term()} | {ok, State :: term(), Timeout :: timeout()} | {ok, State :: term(), hibernate} | {stop, Reason :: term()} | ignore. init([]) -> process_flag(trap_exit, true), {ok, #state{handlers=[]}}. -spec handle_call(Request :: term(), From :: {pid(), term()}, State :: term()) -> {reply, Reply :: term(), NewState :: term()} | {reply, Reply :: term(), NewState :: term(), Timeout :: timeout()} | {reply, Reply :: term(), NewState :: term(), hibernate} | {noreply, NewState :: term()} | {noreply, NewState :: term(), Timeout :: timeout()} | {noreply, NewState :: term(), hibernate} | {stop, Reason :: term(), Reply :: term(), NewState :: term()} | {stop, Reason :: term(), NewState :: term()}. handle_call({register,Id,Pid}, _From, #state{handlers=Hs}=State) -> Ref = erlang:monitor(process,Pid), Hs1 = lists:keystore(Id,1,Hs,{Id,Ref}), {reply, ok, State#state{handlers=Hs1}}. -spec handle_cast(Request :: term(), State :: term()) -> {noreply, NewState :: term()} | {noreply, NewState :: term(), Timeout :: timeout()} | {noreply, NewState :: term(), hibernate} | {stop, Reason :: term(), NewState :: term()}. handle_cast(_Request, State) -> {noreply, State}. -spec handle_info(Info :: timeout() | term(), State :: term()) -> {noreply, NewState :: term()} | {noreply, NewState :: term(), Timeout :: timeout()} | {noreply, NewState :: term(), hibernate} | {stop, Reason :: normal | term(), NewState :: term()}. handle_info({'DOWN',Ref,process,_,shutdown}, #state{handlers=Hs}=State) -> case lists:keytake(Ref,2,Hs) of {value,{Id,Ref},Hs1} -> %% Probably terminated by supervisor. Remove the handler to avoid %% error printouts due to failing handler. _ = case logger:get_handler_config(Id) of {ok,_} -> logger:remove_handler(Id); _ -> ok end, {noreply,State#state{handlers=Hs1}}; false -> {noreply, State} end; handle_info({'DOWN',Ref,process,_,_OtherReason}, #state{handlers=Hs}=State) -> {noreply,State#state{handlers=lists:keydelete(Ref,2,Hs)}}; handle_info(_Other,State) -> {noreply,State}. -spec terminate(Reason :: normal | shutdown | {shutdown, term()} | term(), State :: term()) -> any(). terminate(_Reason, _State) -> ok.