|
|
- -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.
|