rewrite from lager
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

564 regels
18 KiB

4 jaren geleden
4 jaren geleden
4 jaren geleden
4 jaren geleden
4 jaren geleden
4 jaren geleden
4 jaren geleden
4 jaren geleden
4 jaren geleden
4 jaren geleden
4 jaren geleden
4 jaren geleden
4 jaren geleden
4 jaren geleden
4 jaren geleden
4 jaren geleden
4 jaren geleden
4 jaren geleden
4 jaren geleden
4 jaren geleden
4 jaren geleden
4 jaren geleden
4 jaren geleden
4 jaren geleden
4 jaren geleden
4 jaren geleden
4 jaren geleden
4 jaren geleden
4 jaren geleden
4 jaren geleden
4 jaren geleden
4 jaren geleden
4 jaren geleden
4 jaren geleden
4 jaren geleden
4 jaren geleden
4 jaren geleden
4 jaren geleden
4 jaren geleden
4 jaren geleden
4 jaren geleden
4 jaren geleden
4 jaren geleden
4 jaren geleden
4 jaren geleden
4 jaren geleden
4 jaren geleden
4 jaren geleden
4 jaren geleden
4 jaren geleden
4 jaren geleden
4 jaren geleden
4 jaren geleden
4 jaren geleden
4 jaren geleden
4 jaren geleden
4 jaren geleden
4 jaren geleden
4 jaren geleden
4 jaren geleden
4 jaren geleden
4 jaren geleden
4 jaren geleden
4 jaren geleden
4 jaren geleden
4 jaren geleden
4 jaren geleden
4 jaren geleden
4 jaren geleden
4 jaren geleden
4 jaren geleden
4 jaren geleden
4 jaren geleden
4 jaren geleden
4 jaren geleden
4 jaren geleden
4 jaren geleden
4 jaren geleden
4 jaren geleden
4 jaren geleden
4 jaren geleden
4 jaren geleden
4 jaren geleden
4 jaren geleden
4 jaren geleden
4 jaren geleden
4 jaren geleden
4 jaren geleden
4 jaren geleden
4 jaren geleden
4 jaren geleden
4 jaren geleden
4 jaren geleden
4 jaren geleden
4 jaren geleden
4 jaren geleden
4 jaren geleden
4 jaren geleden
4 jaren geleden
4 jaren geleden
4 jaren geleden
4 jaren geleden
4 jaren geleden
4 jaren geleden
4 jaren geleden
4 jaren geleden
4 jaren geleden
4 jaren geleden
4 jaren geleden
4 jaren geleden
4 jaren geleden
4 jaren geleden
4 jaren geleden
4 jaren geleden
4 jaren geleden
4 jaren geleden
4 jaren geleden
4 jaren geleden
4 jaren geleden
4 jaren geleden
4 jaren geleden
4 jaren geleden
4 jaren geleden
4 jaren geleden
4 jaren geleden
4 jaren geleden
4 jaren geleden
4 jaren geleden
4 jaren geleden
4 jaren geleden
4 jaren geleden
4 jaren geleden
4 jaren geleden
4 jaren geleden
4 jaren geleden
4 jaren geleden
4 jaren geleden
4 jaren geleden
4 jaren geleden
4 jaren geleden
4 jaren geleden
4 jaren geleden
4 jaren geleden
4 jaren geleden
4 jaren geleden
4 jaren geleden
4 jaren geleden
4 jaren geleden
4 jaren geleden
4 jaren geleden
4 jaren geleden
4 jaren geleden
4 jaren geleden
4 jaren geleden
4 jaren geleden
4 jaren geleden
4 jaren geleden
4 jaren geleden
4 jaren geleden
4 jaren geleden
4 jaren geleden
4 jaren geleden
4 jaren geleden
4 jaren geleden
4 jaren geleden
4 jaren geleden
4 jaren geleden
4 jaren geleden
4 jaren geleden
4 jaren geleden
4 jaren geleden
4 jaren geleden
4 jaren geleden
4 jaren geleden
4 jaren geleden
4 jaren geleden
4 jaren geleden
4 jaren geleden
4 jaren geleden
4 jaren geleden
4 jaren geleden
4 jaren geleden
4 jaren geleden
4 jaren geleden
4 jaren geleden
4 jaren geleden
4 jaren geleden
4 jaren geleden
4 jaren geleden
4 jaren geleden
4 jaren geleden
4 jaren geleden
4 jaren geleden
4 jaren geleden
4 jaren geleden
4 jaren geleden
4 jaren geleden
4 jaren geleden
4 jaren geleden
4 jaren geleden
4 jaren geleden
4 jaren geleden
4 jaren geleden
  1. -module(eRum).
  2. -include("rumDef.hrl").
  3. -include("rumCom.hrl").
  4. -compile(inline).
  5. -compile({inline_size, 150}).
  6. %% API
  7. -export([
  8. %% start stop
  9. start/0
  10. , stop/0
  11. %% log and log param
  12. , dispatchLog/12
  13. , doLogImpl/13
  14. , safeFormat/3
  15. , unsafeFormat/2
  16. , getMd/0
  17. , setMd/1
  18. , getLogLevel/1
  19. , getLogLevel/2
  20. , setLogLevel/2
  21. , setLogLevel/3
  22. , setLogLevel/4
  23. , getLogLevels/1
  24. , upLogLevelCfg/1
  25. , setLogHwm/2
  26. , setLogHwm/3
  27. , setLogHwm/4
  28. , rotateHandler/1
  29. , rotateHandler/2
  30. , rotateSink/1
  31. , rotateAll/0
  32. %% stack parse
  33. , parseStack/1
  34. , parseStack/3
  35. %% trace
  36. , trace/2
  37. , trace/3
  38. , traceFile/2
  39. , trace_file/3
  40. , trace_file/4
  41. , trace_console/1
  42. , trace_console/2
  43. , install_trace/2
  44. , install_trace/3
  45. , remove_trace/1
  46. , trace_state/3
  47. , trace_func/3
  48. , list_all_sinks/0
  49. , clear_all_traces/0
  50. , clear_trace_by_destination/1
  51. , stop_trace/1
  52. , stop_trace/3
  53. , status/0
  54. ]).
  55. -record(trace_func_state_v1, {
  56. pid :: undefined | pid(),
  57. level :: rumAtomLevel(),
  58. count :: infinity | pos_integer(),
  59. format_string :: string(),
  60. timeout :: infinity | pos_integer(),
  61. started = os:timestamp() :: erlang:timestamp() %% use os:timestamp for compatability
  62. }).
  63. start() ->
  64. application:ensure_all_started(eRum).
  65. stop() ->
  66. application:stop(eRum).
  67. -spec dispatchLog(atom(), rumAtomLevel(), pid(), node(), atom(), atom(), integer(), list(), string(), list() | none, pos_integer(), safe | unsafe) -> ok | {error, lager_not_running} | {error, {sink_not_configured, atom()}}.
  68. %% this is the same check that the parse transform bakes into the module at compile time see rumTransform (lines 173-216)
  69. dispatchLog(Sink, Severity, Pid, Node, Module, Function, Line, Metadata, Format, Args, Size, Safety) ->
  70. case ?eRumCfg:get(Sink) band Severity /= 0 of
  71. true ->
  72. doLogImpl(Severity, Pid, Node, Module, Function, Line, Metadata, Format, Args, Severity, Size, Sink, Safety);
  73. _ ->
  74. ok
  75. end.
  76. doLogImpl(Severity, Pid, Node, Module, Function, Line, Metadata, Format, Args, Severity, Size, Sink, Safety) ->
  77. TraceFilters = rumConfig:ptGet({Sink, trace}, []),
  78. Destinations = ?IIF(TraceFilters /= [], rumUtil:check_traces(Metadata, Severity, TraceFilters, []), []),
  79. MsgStr = ?IIF(Args /= [] andalso Args /= undefined, ?IIF(Safety == safe, safeFormat(Format, [Args], [{charsLimit, Size}]), unsafeFormat(Format, [Args])), Format),
  80. NowMs = rumTime:nowMs(),
  81. NowStr = rumUtil:msToBinStr(NowMs),
  82. RumMsg = #rumMsg{severity = Severity, pid = Pid, node = Node, module = Module, function = Function, line = Line, metadata = Metadata, datetime = NowStr, timestamp = NowMs, message = MsgStr, destinations = Destinations},
  83. case rumConfig:ptGet({Sink, async}, false) of
  84. true ->
  85. gen_emm:info_notify(Sink, {mWriteLog, RumMsg});
  86. false ->
  87. gen_emm:call_notify(Sink, {mWriteLog, RumMsg})
  88. end,
  89. case whereis(?RumTrackSink) of
  90. undefined ->
  91. ok;
  92. TraceSinkPid ->
  93. gen_emm:info_notify(TraceSinkPid, {mWriteLog, RumMsg})
  94. end.
  95. %% @doc Get lager metadata for current process
  96. -spec getMd() -> [{atom(), any()}].
  97. getMd() ->
  98. case erlang:get(?PdMdKey) of
  99. undefined -> [];
  100. MD -> MD
  101. end.
  102. %% @doc Set lager metadata for current process.
  103. %% Will badarg if you don't supply a list of {key, value} tuples keyed by atoms.
  104. -spec setMd([{atom(), any()}, ...]) -> ok.
  105. setMd(NewMD) when is_list(NewMD) ->
  106. %% make sure its actually a real proplist
  107. case lists:all(
  108. fun({Key, _Value}) when is_atom(Key) -> true;
  109. (_) -> false
  110. end, NewMD) of
  111. true ->
  112. erlang:put(?PdMdKey, NewMD),
  113. ok;
  114. _ ->
  115. erlang:error(badarg)
  116. end;
  117. setMd(_) ->
  118. erlang:error(badarg).
  119. %% @doc Set the loglevel for a particular backend.
  120. setLogLevel(Handler, Level) when is_atom(Level) ->
  121. setLogLevel(?RumDefSink, Handler, undefined, Level).
  122. %% @doc Set the loglevel for a particular backend that has multiple identifiers
  123. %% (eg. the file backend).
  124. setLogLevel(Handler, Ident, Level) when is_atom(Level) ->
  125. setLogLevel(?RumDefSink, Handler, Ident, Level).
  126. %% @doc Set the loglevel for a particular sink's backend that potentially has
  127. %% multiple identifiers. (Use `undefined' if it doesn't have any.)
  128. setLogLevel(Sink, Handler, Ident, Level) when is_atom(Level) ->
  129. HandlerArg =
  130. case Ident of
  131. undefined -> Handler;
  132. _ -> {Handler, Ident}
  133. end,
  134. Reply = gen_emm:call(Sink, HandlerArg, {mSetLogLevel, Level}, infinity),
  135. upLogLevelCfg(Sink),
  136. Reply.
  137. %% @doc Get the loglevel for a particular backend on the default sink. In the case that the backend has multiple identifiers, the lowest is returned.
  138. getLogLevel(Handler) ->
  139. getLogLevel(?RumDefSink, Handler).
  140. %% @doc Get the loglevel for a particular sink's backend. In the case that the backend
  141. %% has multiple identifiers, the lowest is returned.
  142. getLogLevel(Sink, Handler) ->
  143. case gen_emm:call(Sink, Handler, mGetLogLevel, infinity) of
  144. Mask when is_integer(Mask) ->
  145. case rumUtil:maskToLevels(Mask) of
  146. [] -> none;
  147. Levels -> hd(Levels)
  148. end;
  149. Y -> Y
  150. end.
  151. getLogLevels(Sink) ->
  152. [gen_emm:call(Sink, Handler, mGetLogLevel, infinity) || Handler <- gen_emm:which_epm(Sink)].
  153. %% @doc Set the loghwm for the default sink.
  154. setLogHwm(Handler, Hwm) when is_integer(Hwm) ->
  155. setLogHwm(?RumDefSink, Handler, Hwm).
  156. %% @doc Set the loghwm for a particular backend.
  157. setLogHwm(Sink, Handler, Hwm) when is_integer(Hwm) ->
  158. gen_emm:call(Sink, Handler, {mSetLogHwm, Hwm}, infinity).
  159. %% @doc Set the loghwm (log high water mark) for file backends with multiple identifiers
  160. setLogHwm(Sink, Handler, Ident, Hwm) when is_integer(Hwm) ->
  161. gen_emm:call(Sink, {Handler, Ident}, {mSetLogHwm, Hwm}, infinity).
  162. %% @doc recalculate min log level
  163. upLogLevelCfg(error_logger) ->
  164. %% Not a sink under our control, part of the Erlang logging
  165. %% utility that error_logger_lager_h attaches to
  166. true;
  167. upLogLevelCfg(Sink) ->
  168. Traces = rumConfig:ptGet({Sink, trace}, []),
  169. AllLogLevel = allLogLevel(getLogLevels(Sink), 0),
  170. case Traces /= [] of
  171. true ->
  172. ets:insert(?eRumEts, {Sink, 16#ff}),
  173. AllSinks = ets:tab2list(?eRumEts),
  174. rumKvsToBeam:load(?eRumCfg, AllSinks);
  175. _ ->
  176. ets:insert(?eRumEts, {Sink, AllLogLevel}),
  177. AllSinks = ets:tab2list(?eRumEts),
  178. rumKvsToBeam:load(?eRumCfg, AllSinks)
  179. end.
  180. allLogLevel([], Acc) ->
  181. Acc;
  182. allLogLevel([OneLv | Levels], Acc) ->
  183. allLogLevel(Levels, OneLv bor Acc).
  184. rotateSink(Sink) ->
  185. Handlers = rumConfig:ptGet(handlers, []),
  186. RotateHandlers = lists:filtermap(
  187. fun({Handler, _, S}) when S == Sink -> {true, {Handler, Sink}};
  188. (_) -> false
  189. end,
  190. Handlers),
  191. rotateHandlers(RotateHandlers).
  192. rotateAll() ->
  193. rotateHandlers(lists:map(fun({H, _, S}) -> {H, S} end,
  194. rumConfig:ptGet(handlers, []))).
  195. rotateHandlers(Handlers) ->
  196. [rotateHandler(Handler, Sink) || {Handler, Sink} <- Handlers].
  197. rotateHandler(Handler) ->
  198. Handlers = rumConfig:ptGet(handlers, []),
  199. case lists:keyfind(Handler, 1, Handlers) of
  200. {Handler, _, Sink} -> rotateHandler(Handler, Sink);
  201. false -> ok
  202. end.
  203. rotateHandler(Handler, Sink) ->
  204. gen_emm:call(Sink, Handler, mRotate, ?RumRotateTimeout).
  205. %% @doc Print stacktrace in human readable form
  206. parseStack(Stacktrace) ->
  207. <<
  208. begin
  209. case Location of
  210. [] ->
  211. <<" ", (atom_to_binary(Mod, utf8))/binary, ":", (atom_to_binary(Func, utf8))/binary, "(", (eFmt:formatBin("~w", [Arity]))/binary, ")\n">>;
  212. [{file, File}, {line, Line}] ->
  213. <<" ", (atom_to_binary(Mod, utf8))/binary, ":", (atom_to_binary(Func, utf8))/binary, "/", (integer_to_binary(Arity))/binary, "(", (unicode:characters_to_binary(File))/binary, ":", (integer_to_binary(Line))/binary, ")\n">>;
  214. _ ->
  215. <<" ", (atom_to_binary(Mod, utf8))/binary, ":", (atom_to_binary(Func, utf8))/binary, "(", (eFmt:formatBin("~w", [Arity]))/binary, ")", (eFmt:formatBin("~w", [Location]))/binary, "\n">>
  216. end
  217. end || {Mod, Func, Arity, Location} <- Stacktrace
  218. >>.
  219. parseStack(Class, Reason, Stacktrace) ->
  220. eFmt:formatBin(<<"~n Class:~s~n Reason:~p~n Stacktrace:~s">>, [Class, Reason, parseStack(Stacktrace)]).
  221. trace(BkdMod, Filter) ->
  222. trace(BkdMod, Filter, debug).
  223. trace({rumBkdFile, File}, Filter, Level) ->
  224. trace_file(File, Filter, Level);
  225. trace(Backend, Filter, Level) ->
  226. case validateTraceFilters(Filter, Level, Backend) of
  227. {Sink, {ok, Trace}} ->
  228. add_trace_to_loglevel_config(Trace, Sink),
  229. {ok, {Backend, Filter, Level}};
  230. {_Sink, Error} ->
  231. Error
  232. end.
  233. traceFile(File, Filter) ->
  234. trace_file(File, Filter, debug, []).
  235. trace_file(File, Filter, Level) when is_atom(Level) ->
  236. trace_file(File, Filter, Level, []);
  237. trace_file(File, Filter, Options) when is_list(Options) ->
  238. trace_file(File, Filter, debug, Options).
  239. trace_file(File, Filter, Level, Options) ->
  240. FileName = rumUtil:parsePath(File),
  241. case validateTraceFilters(Filter, Level, {rumBkdFile, FileName}) of
  242. {Sink, {ok, Trace}} ->
  243. Handlers = rumConfig:ptGet(handlers, []),
  244. %% check if this file backend is already installed
  245. Res =
  246. case rumUtil:find_file(FileName, Handlers) of
  247. false ->
  248. %% install the handler
  249. LogFileConfig =
  250. lists:keystore(level, 1,
  251. lists:keystore(file, 1,
  252. Options,
  253. {file, FileName}),
  254. {level, none}),
  255. HandlerInfo =
  256. eRum_app:startHandler(Sink, {rumBkdFile, FileName}, LogFileConfig),
  257. rumConfig:ptSet(handlers, [HandlerInfo | Handlers]),
  258. {ok, installed};
  259. {_Watcher, _Handler, Sink} ->
  260. {ok, exists};
  261. {_Watcher, _Handler, _OtherSink} ->
  262. {error, file_in_use}
  263. end,
  264. case Res of
  265. {ok, _} ->
  266. add_trace_to_loglevel_config(Trace, Sink),
  267. {ok, {{rumBkdFile, FileName}, Filter, Level}};
  268. {error, _} = E ->
  269. E
  270. end;
  271. {_Sink, Error} ->
  272. Error
  273. end.
  274. trace_console(Filter) ->
  275. trace_console(Filter, debug).
  276. trace_console(Filter, Level) ->
  277. trace(rumBkdConsole, Filter, Level).
  278. stop_trace(Backend, Filter, Level) ->
  279. case validateTraceFilters(Filter, Level, Backend) of
  280. {Sink, {ok, Trace}} ->
  281. stop_trace_int(Trace, Sink);
  282. {_Sink, Error} ->
  283. Error
  284. end.
  285. stop_trace({Backend, Filter, Level}) ->
  286. stop_trace(Backend, Filter, Level).
  287. validateTraceFilters(Filters, Level, Backend) ->
  288. Sink = proplists:get_value(sink, Filters, ?RumDefSink),
  289. {Sink,
  290. rumUtil:validate_trace({
  291. proplists:delete(sink, Filters),
  292. Level,
  293. Backend
  294. })
  295. }.
  296. %% Important: validate_trace_filters orders the arguments of
  297. %% trace tuples differently than the way outside callers have
  298. %% the trace tuple.
  299. %%
  300. %% That is to say, outside they are represented as
  301. %% `{Backend, Filter, Level}'
  302. %%
  303. %% and when they come back from validation, they're
  304. %% `{Filter, Level, Backend}'
  305. stop_trace_int({_Filter, _Level, Backend} = Trace, Sink) ->
  306. Traces = rumConfig:ptGet({Sink, trace}, []),
  307. NewTraces = lists:delete(Trace, Traces),
  308. _ = rumUtil:trace_filter([element(1, T) || T <- NewTraces]),
  309. %MinLevel = minimum_loglevel(get_loglevels() ++ get_trace_levels(NewTraces)),
  310. rumConfig:ptSet({Sink, trace}, NewTraces),
  311. eRum:upLogLevelCfg(Sink),
  312. case getLogLevel(Sink, Backend) of
  313. none ->
  314. %% check no other traces point here
  315. case lists:keyfind(Backend, 3, NewTraces) of
  316. false ->
  317. gen_emm:delEpm(Sink, Backend, []),
  318. rumConfig:ptSet(handlers,
  319. lists:keydelete(Backend, 1,
  320. rumConfig:ptGet(handlers, [])));
  321. _ ->
  322. ok
  323. end;
  324. _ ->
  325. ok
  326. end,
  327. ok.
  328. %% @doc installs a lager trace handler into the target process (using sys:install) at the specified level.
  329. -spec install_trace(pid(), rumAtomLevel()) -> ok.
  330. install_trace(Pid, Level) ->
  331. install_trace(Pid, Level, []).
  332. -spec install_trace(pid(), rumAtomLevel(), [{count, infinity | pos_integer()} | {format_string, string()} | {timeout, timeout()}]) -> ok.
  333. install_trace(Pid, Level, Options) ->
  334. sys:install(Pid, {fun ?MODULE:trace_func/3, trace_state(Pid, Level, Options)}).
  335. %% @doc remove a previously installed lager trace handler from the target process.
  336. -spec remove_trace(pid()) -> ok.
  337. remove_trace(Pid) ->
  338. sys:remove(Pid, fun ?MODULE:trace_func/3).
  339. list_all_sinks() ->
  340. sets:to_list(
  341. lists:foldl(fun({_Watcher, _Handler, Sink}, Set) ->
  342. sets:add_element(Sink, Set)
  343. end,
  344. sets:new(),
  345. rumConfig:ptGet(handlers, []))).
  346. clear_traces_by_sink(Sinks) ->
  347. lists:foreach(
  348. fun(S) ->
  349. rumConfig:ptSet({S, trace}, []),
  350. eRum:upLogLevelCfg(S)
  351. end,
  352. Sinks).
  353. clear_trace_by_destination(ID) ->
  354. Sinks = lists:sort(list_all_sinks()),
  355. Traces = find_traces(Sinks),
  356. [stop_trace_int({Filter, Level, Destination}, Sink) || {Sink, {Filter, Level, Destination}} <- Traces, Destination == ID].
  357. clear_all_traces() ->
  358. Handlers = rumConfig:ptGet(handlers, []),
  359. clear_traces_by_sink(list_all_sinks()),
  360. _ = rumUtil:trace_filter(none),
  361. rumConfig:ptSet(handlers,
  362. lists:filter(
  363. fun({Handler, _Watcher, Sink}) ->
  364. case getLogLevel(Sink, Handler) of
  365. none ->
  366. gen_emm:delEpm(Sink, Handler, []),
  367. false;
  368. _ ->
  369. true
  370. end
  371. end, Handlers)).
  372. find_traces(Sinks) ->
  373. lists:foldl(fun(S, Acc) ->
  374. Traces = rumConfig:ptGet({S, trace}, []),
  375. Acc ++ lists:map(fun(T) -> {S, T} end, Traces)
  376. end,
  377. [],
  378. Sinks).
  379. status() ->
  380. Handlers = rumConfig:ptGet(handlers, []),
  381. Sinks = lists:sort(list_all_sinks()),
  382. Traces = find_traces(Sinks),
  383. TraceCount = case length(Traces) of
  384. 0 -> 1;
  385. N -> N
  386. end,
  387. Status = ["Lager status:\n",
  388. [begin
  389. Level = getLogLevel(Sink, Handler),
  390. get_sink_handler_status(Sink, Handler, Level)
  391. end || {Handler, _Watcher, Sink} <- lists:sort(fun({_, _, S1},
  392. {_, _, S2}) -> S1 =< S2 end,
  393. Handlers)],
  394. "Active Traces:\n",
  395. [begin
  396. LevelName =
  397. case rumUtil:maskToLevels(Level) of
  398. [] -> none;
  399. Levels -> hd(Levels)
  400. end,
  401. io_lib:format("Tracing messages matching ~p (sink ~s) at level ~p to ~p\n",
  402. [Filter, Sink, LevelName, Destination])
  403. end || {Sink, {Filter, Level, Destination}} <- Traces],
  404. [
  405. "Tracing Reductions:\n",
  406. case ?RumDefTracer:info('query') of
  407. {null, false} -> "";
  408. Query -> io_lib:format("~p~n", [Query])
  409. end
  410. ],
  411. [
  412. "Tracing Statistics:\n ",
  413. [begin
  414. [" ", atom_to_list(Table), ": ",
  415. integer_to_list(?RumDefTracer:info(Table) div TraceCount),
  416. "\n"]
  417. end || Table <- [input, output, filter]]
  418. ]],
  419. io:put_chars(Status).
  420. get_sink_handler_status(Sink, Handler, Level) ->
  421. case Handler of
  422. {rumBkdFile, File} ->
  423. io_lib:format("File ~ts (~s) at level ~p\n", [File, Sink, Level]);
  424. rumBkdConsole ->
  425. io_lib:format("Console (~s) at level ~p\n", [Sink, Level]);
  426. _ ->
  427. []
  428. end.
  429. %% @private
  430. add_trace_to_loglevel_config(Trace, Sink) ->
  431. Traces = rumConfig:ptGet({Sink, trace}, []),
  432. case lists:member(Trace, Traces) of
  433. false ->
  434. NewTraces = [Trace | Traces],
  435. _ = rumUtil:trace_filter([element(1, T) || T <- NewTraces]),
  436. rumConfig:ptSet({Sink, trace}, [Trace | Traces]),
  437. eRum:upLogLevelCfg(Sink);
  438. _ ->
  439. ok
  440. end.
  441. %% @doc Print the format string `Fmt' with `Args' safely with a size
  442. %% limit of `Limit'. If the format string is invalid, or not enough
  443. %% arguments are supplied 'FORMAT ERROR' is printed with the offending
  444. %% arguments. The caller is NOT crashed.
  445. unsafeFormat(Fmt, Args) ->
  446. try io_lib:format(Fmt, Args)
  447. catch
  448. _:_ -> io_lib:format("FORMAT ERROR: ~p ~p", [Fmt, Args])
  449. end.
  450. safeFormat(Fmt, Args, Limit) ->
  451. try eFmt:formatBin(Fmt, Args, [{charsLimit, Limit}])
  452. catch
  453. _:_ -> eFmt:formatBin(<<"FORMAT ERROR: ~p ~p">>, [Fmt, Args], [{charsLimit, Limit}])
  454. end.
  455. %% @private Print the format string `Fmt' with `Args' without a size limit.
  456. %% This is unsafe because the output of this function is unbounded.
  457. %%
  458. %% Log messages with unbounded size will kill your application dead as
  459. %% OTP mechanisms stuggle to cope with them. So this function is
  460. %% intended <b>only</b> for messages which have a reasonable bounded
  461. %% size before they're formatted.
  462. %%
  463. %% If the format string is invalid or not enough arguments are
  464. %% supplied a 'FORMAT ERROR' message is printed instead with the
  465. %% offending arguments. The caller is NOT crashed.
  466. %% @private
  467. trace_func(#trace_func_state_v1{pid = Pid, level = Level, format_string = Fmt} = FuncState, Event, ProcState) ->
  468. _ = eRum:log(Level, Pid, Fmt, [Event, ProcState]),
  469. check_timeout(decrement_count(FuncState)).
  470. %% @private
  471. trace_state(Pid, Level, Options) ->
  472. #trace_func_state_v1{pid = Pid,
  473. level = Level,
  474. count = proplists:get_value(count, Options, infinity),
  475. timeout = proplists:get_value(timeout, Options, infinity),
  476. format_string = proplists:get_value(format_string, Options, "TRACE ~p ~p")}.
  477. decrement_count(#trace_func_state_v1{count = infinity} = FuncState) ->
  478. FuncState;
  479. decrement_count(#trace_func_state_v1{count = 1}) ->
  480. %% hit the counter limit
  481. done;
  482. decrement_count(#trace_func_state_v1{count = Count} = FuncState) ->
  483. FuncState#trace_func_state_v1{count = Count - 1}.
  484. check_timeout(#trace_func_state_v1{timeout = infinity} = FuncState) ->
  485. FuncState;
  486. check_timeout(#trace_func_state_v1{timeout = Timeout, started = Started} = FuncState) ->
  487. case (timer:now_diff(os:timestamp(), Started) / 1000) > Timeout of
  488. true ->
  489. done;
  490. false ->
  491. FuncState
  492. end.