rewrite from lager
Du kan inte välja fler än 25 ämnen Ämnen måste starta med en bokstav eller siffra, kan innehålla bindestreck ('-') och vara max 35 tecken långa.
 

207 rader
7.4 KiB

-module(eRum_app).
-behaviour(application).
-include("rumCom.hrl").
-include("rumDef.hrl").
-include("eRum.hrl").
-export([
start/2
, stop/1
, doStart/0
, startSink/1
, startSink/2
, startHandler/3
]).
start(_StartType, _StartArgs) ->
{ok, Pid} = eRum_sup:start_link(),
SavedHandlers = doStart(),
doStartExtraSink(),
doStartTraces(),
?eRumInit(),
{ok, Pid, SavedHandlers}.
%% 启动默认的接收器(sink)
doStart() ->
%% 尝试起送异步管理者
tryStartAsyncMgr(rumUtil:get_env(asyncThreshold, undefined), rumUtil:get_env(asyncThresholdWindow, undefined), ?RumDefSink),
%%尝试安装killer
tryInstallKiller(rumUtil:get_env(killerHwm, undefined), rumUtil:get_env(killerReTime, undefined), ?RumDefSink),
%%尝试启动各个handler
tryStartHandlers(rumUtil:get_env(handlers, ?RumDefHandler), ?RumDefSink),
%% 尝试替换error logger
SavedHandlers = tryStartErrLoggerHandler(rumUtil:get_env(errLoggerRedirect, true), rumUtil:get_env(errLoggerHwm, 0), rumUtil:get_env(errLoggerWhitelist, [])),
eRum:updateLogevelCfg(?RumDefSink),
SavedHandlers.
startSink(?RumDefSink) -> doStart();
startSink(Sink) ->
AllSinksDef = rumUtil:get_env(extraSinks, []),
SinkValue = lists:keyfind(Sink, 1, AllSinksDef),
SinkOpts = ?IIF(SinkValue == false, [], element(2, SinkValue)),
startSink(Sink, SinkOpts).
startSink(Sink, Opts) ->
rumConfig:initSink(Sink),
ChildId = rumUtil:makeInnerSinkName(Sink),
SinkSpec = #{
id => ChildId,
start => {gen_event, start_link, [{local, Sink}]},
restart => permanent,
shutdown => 5000,
type => worker,
modules => [dynamic]},
_ = supervisor:start_child(eRum_sup, SinkSpec),
tryStartAsyncMgr(proplists:get_value(asyncThreshold, Opts, undefined), proplists:get_value(asyncThresholdWindow, Opts, undefined), Sink),
tryInstallKiller(proplists:get_value(killerHwm, Opts, undefined), proplists:get_value(killerReTime, Opts, undefined), Sink),
tryStartHandlers(proplists:get_value(handlers, Opts, []), Sink),
eRum:updateLogevelCfg(Sink).
doStartExtraSink() ->
doStartExtraSinks(rumUtil:get_env(extraSinks, [])).
doStartExtraSinks(Sinks) ->
[startSink(Sink, Opts) || {Sink, Opts} <- Sinks],
ok.
doStartTraces() ->
_ = rumUtil:trace_filter(none),
ok = addTraces().
addTraces() ->
Traces = rumUtil:get_env(traces, []),
[startTrace(One) || One <- Traces],
ok.
startTrace({Handler, Filter}) ->
{ok, _} = eRum:trace(Handler, Filter);
startTrace({Handler, Filter, Level}) when is_atom(Level) ->
{ok, _} = eRum:trace(Handler, Filter, Level).
stop(Handlers) ->
[error_logger:add_report_handler(Handler) || Handler <- Handlers],
rumConfig:cleanup().
tryStartAsyncMgr(undefined, _Window, _Sink) ->
ignore;
tryStartAsyncMgr(Threshold, Window, Sink) ->
case Window of
undefined ->
supervisor:start_child(rumHWatcherSup, [Sink, rumBkdThrottle, [Threshold, erlang:trunc(Threshold * 0.2)]]);
_ ->
supervisor:start_child(rumHWatcherSup, [Sink, rumBkdThrottle, [Threshold, Window]])
end,
ok.
tryInstallKiller(undefined, _ReTime, _Sink) -> ok;
tryInstallKiller(HWM, ReTime, Sink) ->
case ReTime of
undefined ->
_ = supervisor:start_child(rumHWatcherSup, [Sink, rumMgrKiller, [HWM, 5000]]);
_ ->
_ = supervisor:start_child(rumHWatcherSup, [Sink, rumMgrKiller, [HWM, ReTime]])
end,
ok.
tryStartHandlers(undefined, _Sink) -> ok;
tryStartHandlers(Handlers, Sink) ->
%% 启动失败的处理程序将在handler_watcher中处理
NewHandler = doStartHandlers(Handlers, Sink, [], []),
rumConfig:global_set(handlers, rumConfig:global_get(handlers, []) ++ NewHandler),
ok.
doStartHandlers([], _Sink, _NameAcc, HandlerAcc) ->
HandlerAcc;
doStartHandlers([OneHandler | Handlers], Sink, NameAcc, HandlerAcc) ->
{Module, Options} = parseHandlers(OneHandler),
NewNameAcc =
case Module of
{rumBkFile, F} ->
case lists:member(F, NameAcc) of
true ->
error_logger:error_msg("Cannot have same file (~p) in multiple file backends~n", [F]),
throw({error, bad_config});
_ ->
[F | NameAcc]
end;
_ ->
NameAcc
end,
HandlerRet = startHandler(Sink, Module, Options),
doStartHandlers(Handlers, Sink, NewNameAcc, [HandlerRet | HandlerAcc]).
startHandler(Sink, Module, Config) ->
{ok, Watcher} = supervisor:start_child(rumHWatcherSup, [Sink, Module, Config]),
{Module, Watcher, Sink}.
-spec tryStartErrLoggerHandler(boolean(), pos_integer(), list()) -> list().
tryStartErrLoggerHandler(false, _HWM, _Whitelist) -> [];
tryStartErrLoggerHandler(_ErrLoggerRedirect, HWM, WhiteList) ->
case whereis(error_logger) of
undefined ->
%% 在OTP 21及以上版本中,error_logger已弃用,而改用 'logger'
%% 作为一个修补, 启动error_logger并将其安装为 logger handler
%% 我们不能使用 error_logger:add_report_handler 因为我们想要监视这个handler
%% 因此,我们必须手动添加这个 logger handler
%%
%% 从长远来看,我们应该安装一个日志处理程序, but this will bridge the gap for now.
_ = error_logger:start(),
_ = logger:add_handler(error_logger, error_logger, #{level => info, filter_default => log}),
ok = tryRemoveLoggerHandler();
_ ->
ok
end,
%% capture which handlers we removed from error_logger so we can restore them when lager stops
%% 捕获从error_logger中删除的处理程序,以便在lager停止时恢复它们
OldHandlers =
case supervisor:start_child(rumHWatcherSup, [error_logger, rumErrLoggerH, [HWM, rumUtil:get_env(errLoggerGroupLeaderStrategy, handle)]]) of
{ok, _} ->
[begin error_logger:delete_report_handler(X), X end || X <- gen_event:which_handlers(error_logger) -- [rumErrLoggerH | WhiteList]];
{error, _} ->
[]
end,
OldHandlers.
%% 在OTP 21.1及更高版本上,我们需要删除`default' handler。但是它可能不存在,因此我们将其包装在try-catch块中
tryRemoveLoggerHandler() ->
try
ok = logger:remove_handler(default)
catch
error:undef -> ok;
Err:Reason ->
error_logger:error_msg("calling logger:remove_handler(default) failed: ~p ~p", [Err, Reason])
end.
parseHandlers([]) ->
[];
parseHandlers({rumBkdFile, Config}) ->
%% this is definitely a new-style config, no expansion needed
maybe_make_handler_id(rumBkdFile, Config);
parseHandlers({Mod, Config}) ->
maybe_make_handler_id(Mod, Config).
maybe_make_handler_id(Mod, Config) ->
%% Allow the backend to generate a gen_event handler id, if it wants to.
%% We don't use erlang:function_exported here because that requires the module
%% already be loaded, which is unlikely at this phase of startup. Using code:load
%% caused undesirable side-effects with generating code-coverage reports.
%%允许后端生成gen_event处理程序id,如果它愿意的话。
%%这里我们没有使用erlang:function_exported,因为这需要用到模块
%%已经加载,这在启动阶段是不太可能的。使用代码:负载
%%会在生成代码覆盖率报告时产生不良的副作用。
try Mod:configToId(Config) of
Id ->
{Id, Config}
catch
error:undef ->
{Mod, Config}
end.