%% This Source Code Form is subject to the terms of the Mozilla Public %% License, v. 2.0. If a copy of the MPL was not distributed with this %% file, You can obtain one at https://mozilla.org/MPL/2.0/. %% %% Copyright (c) 2007-2021 VMware, Inc. or its affiliates. All rights reserved. %% -module(lager_forwarder_backend). -behaviour(gen_event). -export([init/1, handle_call/2, handle_event/2, handle_info/2, terminate/2, code_change/3]). -record(state, { next_sink :: atom(), level :: {'mask', integer()} | inherit }). %% @private init(Sink) when is_atom(Sink) -> init([Sink]); init([Sink]) when is_atom(Sink) -> init([Sink, inherit]); init([Sink, inherit]) when is_atom(Sink) -> {ok, #state{ next_sink = Sink, level = inherit }}; init([Sink, Level]) when is_atom(Sink) -> try Mask = lager_util:config_to_mask(Level), {ok, #state{ next_sink = Sink, level = Mask }} catch _:_ -> {error, {fatal, bad_log_level}} end; init(_) -> {error, {fatal, bad_config}}. %% @private handle_call(get_loglevel, #state{next_sink = Sink, level = inherit} = State) -> SinkPid = whereis(Sink), Mask = case self() of SinkPid -> %% Avoid direct loops, defaults to 'info'. 127; _ -> try Levels = [gen_event:call(SinkPid, Handler, get_loglevel, infinity) || Handler <- gen_event:which_handlers(SinkPid)], lists:foldl(fun ({mask, Mask}, Acc) -> Mask bor Acc; (Level, Acc) when is_integer(Level) -> {mask, Mask} = lager_util:config_to_mask( lager_util:num_to_level(Level)), Mask bor Acc; (_, Acc) -> Acc end, 0, Levels) catch exit:noproc -> 127 end end, {ok, {mask, Mask}, State}; handle_call(get_loglevel, #state{level = Mask} = State) -> {ok, Mask, State}; handle_call({set_loglevel, inherit}, State) -> {ok, ok, State#state{level = inherit}}; handle_call({set_loglevel, Level}, State) -> try lager_util:config_to_mask(Level) of Mask -> {ok, ok, State#state{level = Mask}} catch _:_ -> {ok, {error, bad_log_level}, State} end; handle_call(_Request, State) -> {ok, ok, State}. %% @private handle_event({log, LagerMsg}, #state{next_sink = Sink, level = Mask} = State) -> SinkPid = whereis(Sink), case self() of SinkPid -> %% Avoid direct loops. ok; _ -> case Mask =:= inherit orelse lager_util:is_loggable(LagerMsg, Mask, ?MODULE) of true -> case lager_config:get({Sink, async}, false) of true -> gen_event:notify(SinkPid, {log, LagerMsg}); false -> gen_event:sync_notify(SinkPid, {log, LagerMsg}) end; false -> ok end end, {ok, State}; handle_event(_Event, State) -> {ok, State}. %% @private handle_info(_Info, State) -> {ok, State}. %% @private terminate(_Reason, _State) -> ok. %% @private code_change(_OldVsn, State, _Extra) -> {ok, State}.