浏览代码

ft: 命令修改整理

master
SisMaker 4 年前
父节点
当前提交
0c109f50e1
共有 14 个文件被更改,包括 135 次插入1019 次删除
  1. +7
    -7
      README.md
  2. +7
    -9
      include/eRum.hrl
  3. +40
    -52
      include/rumDef.hrl
  4. +5
    -1
      include/rumMsg.hrl
  5. +10
    -10
      src/backend/rumBkdConsole.erl
  6. +44
    -44
      src/backend/rumBkdFile.erl
  7. +8
    -8
      src/crashLog/rumCrashLog.erl
  8. +5
    -5
      src/eRum.erl
  9. +2
    -4
      src/eRum1.erl
  10. +1
    -1
      src/errLogger/rumErrLoggerH.erl
  11. +2
    -2
      src/formatter/rumFormatTer.erl
  12. +3
    -6
      src/utils/rumStdlib.erl
  13. +0
    -869
      src/utils/rumTruncIo.erl
  14. +1
    -1
      src/utils/rumUtil.erl

+ 7
- 7
README.md 查看文件

@ -121,16 +121,16 @@ below). If async values are not configured, no overload protection will be appli
自定义格式 自定义格式
----------------- -----------------
All loggers have a default formatting that can be overriden. A formatter is any module that
All loggers have a default formatting that can be overriden. A formatTer is any module that
exports `format(#lager_log_message{},Config#any())`. It is specified as part of the configuration for the backend: exports `format(#lager_log_message{},Config#any())`. It is specified as part of the configuration for the backend:
```erlang ```erlang
{eRum, [ {eRum, [
{handlers, [ {handlers, [
{lager_console_backend, [{level, info}, {formatter, lager_default_formatter},
{formatter_config, [time, " [",severity, "] ", message, "\n"]}]},
{lager_file_backend, [{file, "error.log"}, {level, error}, {formatter, lager_default_formatter},
{formatter_config, [date, " ", time, " [", severity, "] ",pid, " ", message, "\n"]}]},
{lager_console_backend, [{level, info}, {formatTer, lager_default_formatter},
{formatCfg, [time, " [",severity, "] ", message, "\n"]}]},
{lager_file_backend, [{file, "error.log"}, {level, error}, {formatTer, lager_default_formatter},
{formatCfg, [date, " ", time, " [", severity, "] ",pid, " ", message, "\n"]}]},
{lager_file_backend, [{file, "console.log"}, {level, info}]} {lager_file_backend, [{file, "console.log"}, {level, info}]}
]} ]}
]}. ]}.
@ -438,8 +438,8 @@ If you don't like the default colors, they are also configurable; see the `.app.
The output will be colored from the first occurrence of the atom color in the formatting configuration. For example: The output will be colored from the first occurrence of the atom color in the formatting configuration. For example:
```erlang ```erlang
{lager_console_backend, [{level, info}, {formatter, lager_default_formatter},
{formatter_config, [time, color, " [", severity, "] ", message, "\e[0m\r\n"]}]]}
{lager_console_backend, [{level, info}, {formatTer, lager_default_formatter},
{formatCfg, [time, color, " [", severity, "] ", message, "\e[0m\r\n"]}]]}
``` ```
This will make the entire log message, except time, colored. The escape sequence before the line break is needed in This will make the entire log message, except time, colored. The escape sequence before the line break is needed in

+ 7
- 9
include/eRum.hrl 查看文件

@ -3,15 +3,13 @@
%% eRumCfg模块初始化了 使eRum的App启动后请调用一次 %% eRumCfg模块初始化了 使eRum的App启动后请调用一次
-define(eRumInit(), ?eRumInit(?RumDefSink)). -define(eRumInit(), ?eRumInit(?RumDefSink)).
-define(eRumInit(Sink), -define(eRumInit(Sink),
begin
case ets:info(?eRumEts) of
undefined ->
ets:new(?eRumEts, [named_table]),
ets:insert(?eRumEts, {Sink, ?none}),
rumKvsToBeam:load(?eRumCfg, [{Sink, ?none}]);
_ ->
ignore
end
case ets:info(?eRumEts) of
undefined ->
ets:new(?eRumEts, [named_table]),
ets:insert(?eRumEts, {Sink, ?none}),
rumKvsToBeam:load(?eRumCfg, [{Sink, ?none}]);
_ ->
ignore
end). end).
%% %%

+ 40
- 52
include/rumDef.hrl 查看文件

@ -1,4 +1,5 @@
-include("rumCom.hrl"). -include("rumCom.hrl").
-include("rumMsg.hrl").
%% %%
-define(RumAppName, eRum). -define(RumAppName, eRum).
@ -19,16 +20,16 @@
-define(RumRotateTimeout, 100000). -define(RumRotateTimeout, 100000).
%% %%
-define(RumDefTracer, lager_default_tracer).
-define(RumErrLogSink, error_logger_lager_event).
-define(RumDefTracer, rumDefTracer).
-define(RumErrLogSink, errLoggerEvent).
%% rumBkdConsole的选项 %% rumBkdConsole的选项
-type rumConsoleOpt() :: -type rumConsoleOpt() ::
{id, atom() | {atom(), atom()}} | {id, atom() | {atom(), atom()}} |
{use_stderr, boolean()} | {use_stderr, boolean()} |
{group_leader, false | pid() | atom()} | {group_leader, false | pid() | atom()} |
{formatter, atom()} |
{formatter_config, list()}.
{formatTer, atom()} |
{formatCfg, list()}.
%% rumBkdFile的选项 %% rumBkdFile的选项
-type rumFileOpt() :: -type rumFileOpt() ::
@ -38,18 +39,18 @@
{date, string()} | {date, string()} |
{count, non_neg_integer()} | {count, non_neg_integer()} |
{rotator, atom()} | {rotator, atom()} |
{high_water_mark, non_neg_integer()} |
{hWM, non_neg_integer()} |
%% 使 %% 使
{flush_queue, boolean()} |
{flushQueue, boolean()} |
%% flush_queue为true0 %% flush_queue为true0
%% flush_queue为true %% flush_queue为true
{flush_threshold, non_neg_integer()} |
{sync_interval, non_neg_integer()} |
{sync_size, non_neg_integer()} |
{sync_on, rumAtomLevel()} |
{check_interval, non_neg_integer()} |
{formatter, atom()} |
{formatter_config, term()}.
{flushThr, non_neg_integer()} |
{syncInt, non_neg_integer()} |
{syncSize, non_neg_integer()} |
{syncOn, rumAtomLevel()} |
{checkInt, non_neg_integer()} |
{formatTer, atom()} |
{formatCfg, term()}.
%% BkdFile选项默认值 %% BkdFile选项默认值
-define(RumDefLogLevel, info). -define(RumDefLogLevel, info).
@ -58,13 +59,13 @@
-define(RumDefRotateCnt, 5). -define(RumDefRotateCnt, 5).
-define(RumDefRotateMod, rumRotatorIns). -define(RumDefRotateMod, rumRotatorIns).
-define(RumDefSyncLevel, error). -define(RumDefSyncLevel, error).
-define(RumDefSyncInterval, 1000).
-define(RumDefSyncInt, 1000).
-define(RumDefSyncSize, 1024 * 64). %% 64kb -define(RumDefSyncSize, 1024 * 64). %% 64kb
-define(RumDefCheckInterval, 1000).
-define(RumDefCheckInt, 1000).
-define(RumDefCheckHWM, 1000). %% IMY-todo修正该默认值 -define(RumDefCheckHWM, 1000). %% IMY-todo修正该默认值
-define(RumDefFlushQueue, true). -define(RumDefFlushQueue, true).
-define(RumDefFlushThreshold, 0). %% IMY-todo修正该默认值
-define(RumDefFormatter, rumFormatter).
-define(RumDefFlushThr, 0). %% IMY-todo修正该默认值
-define(RumDefFormatTer, rumFormatTer).
-define(RumDefFormatterCfg, []). -define(RumDefFormatterCfg, []).
%% %%
@ -88,7 +89,7 @@
%% If true, flush notify messages from msg queue at overload %% If true, flush notify messages from msg queue at overload
%% true %% true
, flushQueue = true :: boolean() , flushQueue = true :: boolean()
, flushThreshold = 0 :: integer()
, flushThr = 0 :: integer()
%% timer %% timer
, timer = make_ref() :: reference() , timer = make_ref() :: reference()
%% optional filter fun to avoid counting suppressed messages against HWM totals %% optional filter fun to avoid counting suppressed messages against HWM totals
@ -101,51 +102,38 @@
-type rumAtomLevel() :: none | debug | info | notice | warning | error | critical | alert | emergency. -type rumAtomLevel() :: none | debug | info | notice | warning | error | critical | alert | emergency.
-type rumMaskLevel() :: 0..256. -type rumMaskLevel() :: 0..256.
%% %%
-define(RumLevels, [debug, info, notice, warning, error, critical, alert, emergency, none]). -define(RumLevels, [debug, info, notice, warning, error, critical, alert, emergency, none]).
%% 使
-define(RumLevelsUnsafe, [{debug_unsafe, debug}, {info_unsafe, info}, {notice_unsafe, notice}, {warning_unsafe, warning}, {error_unsafe, error}, {critical_unsafe, critical}, {alert_unsafe, alert}, {emergency_unsafe, emergency}]).
-define(RunShouldLog(Sink, Level), (rumUtil:levelToNum(Level) band ?eRumCfg:get(Sink)) /= 0).
-define(RunShouldLog(Sink, Level), (rumUtil:levelToNum(Level) band element(1, rumConfig:get({Sink, loglevel}, {?none, []}))) /= 0).
-define(RunShouldLog(Level), (rumUtil:levelToNum(Level) band element(1, rumConfig:get(loglevel, {?none, []}))) /= 0).
-define(RunShouldLog(Level), (rumUtil:levelToNum(Level) band rumConfig:get(?RumDefSink)) /= 0).
-define(RunNotify(Level, Pid, Format, Args), -define(RunNotify(Level, Pid, Format, Args),
gen_emm:info_notify(rumEvent, {mWriteLog, rumMsg:new(io_lib:format(Format, Args), Level, [{pid, Pid}, {line, ?LINE}, {file, ?FILE}, {module, ?MODULE}], [])})).
LagerMsg = ?newMsg(Level, Pid, node(), ?MODULE, ?FUNCTION_NAME, ?LINE, [], [], rumUtil:nowMs(), eFmt:formatBin(Format, Args)),
gen_emm:info_notify(?RumDefSink, {mWriteLog, LagerMsg})).
%%使 %%使
-ifdef(TEST).
-define(INT_LOG(Level, Format, Args),
case ?RunShouldLog(Level) of
true ->
?RunNotify(Level, self(), Format, Args);
_ ->
ok
end).
-else.
-define(INT_LOG(Level, Format, Args), -define(INT_LOG(Level, Format, Args),
Self = self(), Self = self(),
%%gen_event处理程序调用gen_eventwhich_handlers的死锁 %%gen_event处理程序调用gen_eventwhich_handlers的死锁
spawn(fun() ->
case catch (gen_event:which_handlers(rumEvent)) of
X when X == []; X == {'EXIT', noproc}; X == [rumBkdThrottle] ->
%% there's no handlers yet or lager isn't running, try again
%% in half a second.
timer:sleep(500),
?RunNotify(Level, Self, Format, Args);
_ ->;
case ?RunShouldLog(Level) of
true ->
?RunNotify(Level, Self, Format, Args);
_ ->;
ok
end
end
end)).
-endif.
spawn(
fun() ->
case catch (gen_emm:which_epm(?RumDefSink)) of
X when X == []; X == {'EXIT', noproc}; X == [rumBkdThrottle] ->
%% there's no handlers yet or lager isn't running, try again
%% in half a second.
timer:sleep(500),
?RunNotify(Level, Self, Format, Args);
_ ->
case ?RunShouldLog(Level) of
true ->;
?RunNotify(Level, Self, Format, Args);
_ ->
ok
end
end
end)).

+ 5
- 1
include/rumMsg.hrl 查看文件

@ -1,3 +1,6 @@
-ifndef(__RumMsg__).
-define(__RumMsg__, 1).
-record(rumMsg, { -record(rumMsg, {
severity :: rumAtomLevel() severity :: rumAtomLevel()
, pid :: pid() , pid :: pid()
@ -26,4 +29,5 @@
, timestamp = TimeMs , timestamp = TimeMs
, message = Msg , message = Msg
, destinations = Destinations , destinations = Destinations
}).
}).
-endif.

+ 10
- 10
src/backend/rumBkdConsole.erl 查看文件

@ -2,8 +2,8 @@
%% Configuration is a proplist with the following keys: %% Configuration is a proplist with the following keys:
%%`level' - log level to use %%`level' - log level to use
%%`use_stderr' - either `true' or `false', defaults to false. If set to true, use standard error to output console log messages %%`use_stderr' - either `true' or `false', defaults to false. If set to true, use standard error to output console log messages
%%`formatter' - the module to use when formatting log messages. Defaults to `rumFormatter'
%%`formatter_config' - the format configuration string. Defaults to `time [ severity ] message'
%%`formatTer' - the module to use when formatting log messages. Defaults to `rumFormatTer'
%%`formatCfg' - the format configuration string. Defaults to `time [ severity ] message'
-behaviour(gen_emm). -behaviour(gen_emm).
@ -14,7 +14,7 @@
-define(TERSE_FORMAT, [time, " ", color, "[", severity, "] ", message]). -define(TERSE_FORMAT, [time, " ", color, "[", severity, "] ", message]).
-define(RumDefConsoleFmtCfg, ?TERSE_FORMAT ++ [eol()]). -define(RumDefConsoleFmtCfg, ?TERSE_FORMAT ++ [eol()]).
-define(RumDefConsoleOpts, [{use_stderr, false}, {group_leader, false}, {id, ?MODULE}, {formatter, rumFormatter}, {formatter_config, ?RumDefConsoleFmtCfg}]).
-define(RumDefConsoleOpts, [{use_stderr, false}, {group_leader, false}, {id, ?MODULE}, {formatTer, ?RumDefFormatTer}, {formatCfg, ?RumDefConsoleFmtCfg}]).
-export([ -export([
init/1 init/1
@ -29,7 +29,7 @@
id :: atom() | {atom(), any()} id :: atom() | {atom(), any()}
, level :: rumMaskLevel() , level :: rumMaskLevel()
, out = user :: user | standard_error | pid() , out = user :: user | standard_error | pid()
, formatter :: atom()
, formatTer :: atom()
, formatCfg :: any() , formatCfg :: any()
, colors = [] :: list() , colors = [] :: list()
}). }).
@ -52,9 +52,9 @@ init(Opts) ->
Colors = ?IIF(rumUtil:get_env(colored, false), rumUtil:get_env(colors, []), []), Colors = ?IIF(rumUtil:get_env(colored, false), rumUtil:get_env(colors, []), []),
Level = rumUtil:get_opt(level, Opts, undefined), Level = rumUtil:get_opt(level, Opts, undefined),
LevelMask = rumUtil:configToMask(Level), LevelMask = rumUtil:configToMask(Level),
[UseErr, GroupLeader, Id, Formatter, Config] = [rumUtil:get_opt(Key, Opts, Def) || {Key, Def} <- ?RumDefConsoleOpts],
[UseErr, GroupLeader, Id, FormatTer, FormatCfg] = [rumUtil:get_opt(Key, Opts, Def) || {Key, Def} <- ?RumDefConsoleOpts],
Out = ?IIF(UseErr, standard_error, ?IIF(GroupLeader == false, user, begin erlang:monitor(process, GroupLeader), GroupLeader end)), Out = ?IIF(UseErr, standard_error, ?IIF(GroupLeader == false, user, begin erlang:monitor(process, GroupLeader), GroupLeader end)),
{ok, #state{level = LevelMask, id = Id, out = Out, formatter = Formatter, formatCfg = Config, colors = Colors}}
{ok, #state{level = LevelMask, id = Id, out = Out, formatTer = FormatTer, formatCfg = FormatCfg, colors = Colors}}
end. end.
checkOpts([]) -> true; checkOpts([]) -> true;
@ -64,9 +64,9 @@ checkOpts([{level, Level} | T]) ->
?IIF(rumUtil:validateLogLevel(Level) /= false, checkOpts(T), {error, {bad_level, Level}}); ?IIF(rumUtil:validateLogLevel(Level) /= false, checkOpts(T), {error, {bad_level, Level}});
checkOpts([{use_stderr, Flag} | T]) when is_boolean(Flag) -> checkOpts([{use_stderr, Flag} | T]) when is_boolean(Flag) ->
checkOpts(T); checkOpts(T);
checkOpts([{formatter, M} | T]) when is_atom(M) ->
checkOpts([{formatTer, M} | T]) when is_atom(M) ->
checkOpts(T); checkOpts(T);
checkOpts([{formatter_config, C} | T]) when is_list(C) ->
checkOpts([{formatCfg, C} | T]) when is_list(C) ->
checkOpts(T); checkOpts(T);
checkOpts([{group_leader, L} | T]) when is_pid(L) -> checkOpts([{group_leader, L} | T]) when is_pid(L) ->
checkOpts(T); checkOpts(T);
@ -86,10 +86,10 @@ handleCall(_Msg, State) ->
?ERR("~p call receive unexpect msg ~p ~n ", [?MODULE, _Msg]), ?ERR("~p call receive unexpect msg ~p ~n ", [?MODULE, _Msg]),
{reply, ok, State}. {reply, ok, State}.
handleEvent({mWriteLog, Message}, #state{level = Level, out = Out, formatter = Formatter, formatCfg = FormatConfig, colors = Colors, id = ID}) ->
handleEvent({mWriteLog, Message}, #state{level = Level, out = Out, formatTer = FormatTer, formatCfg = FormatCfg, colors = Colors, id = ID}) ->
case rumUtil:isLoggAble(Message, Level, ID) of case rumUtil:isLoggAble(Message, Level, ID) of
true -> true ->
io:put_chars(Out, Formatter:format(Message, FormatConfig, Colors)),
io:put_chars(Out, FormatTer:format(Message, FormatCfg, Colors)),
kpS; kpS;
_ -> _ ->
kpS kpS

+ 44
- 44
src/backend/rumBkdFile.erl 查看文件

@ -6,7 +6,7 @@
%% This backend supports external and internal log rotation and will re-open handles to files if the inode changes. %% This backend supports external and internal log rotation and will re-open handles to files if the inode changes.
%% It will also rotate the files itself if the size of the file exceeds the `size' and keep `count' rotated files. %% It will also rotate the files itself if the size of the file exceeds the `size' and keep `count' rotated files.
%% `date' is an alternate rotation trigger, based on time. See the README for documentation. %% `date' is an alternate rotation trigger, based on time. See the README for documentation.
%% For performance, the file backend does delayed writes, although it will sync at specific log levels, configured via the `sync_on' option.
%% For performance, the file backend does delayed writes, although it will sync at specific log levels, configured via the `syncOn' option.
%% By default the error level or above will trigger a sync. %% By default the error level or above will trigger a sync.
-behaviour(gen_emm). -behaviour(gen_emm).
@ -33,18 +33,18 @@
level :: rumMaskLevel(), level :: rumMaskLevel(),
fd :: file:io_device() | undefined, fd :: file:io_device() | undefined,
inode :: integer() | undefined, inode :: integer() | undefined,
ctime :: file:date_time() | undefined,
cTime :: file:date_time() | undefined,
flap = false :: boolean(), flap = false :: boolean(),
size = 0 :: integer(), size = 0 :: integer(),
date :: undefined | string(), date :: undefined | string(),
count = 10 :: integer(), count = 10 :: integer(),
rotator = lager_util :: atom(), rotator = lager_util :: atom(),
shaper :: rumShaper(), shaper :: rumShaper(),
formatter :: atom(),
formatterConfig :: any(),
formatTer :: atom(),
formatCfg :: any(),
syncOn :: integer(), syncOn :: integer(),
checkInterval = ?RumDefCheckInterval :: non_neg_integer(), %%
syncInterval = ?RumDefSyncInterval :: non_neg_integer(),
checkInt = ?RumDefCheckInt :: non_neg_integer(), %%
syncInt = ?RumDefSyncInt :: non_neg_integer(),
syncSize = ?RumDefSyncSize :: non_neg_integer(), syncSize = ?RumDefSyncSize :: non_neg_integer(),
lastCheck = rumTime:nowMs() :: erlang:timestamp(), %% lastCheck = rumTime:nowMs() :: erlang:timestamp(), %%
osType :: atom() osType :: atom()
@ -59,35 +59,35 @@ init(Opts) ->
Size = rumUtil:get_opt(size, Opts, ?RumDefRotateSize), Size = rumUtil:get_opt(size, Opts, ?RumDefRotateSize),
Count = rumUtil:get_opt(count, Opts, ?RumDefRotateCnt), Count = rumUtil:get_opt(count, Opts, ?RumDefRotateCnt),
Rotator = rumUtil:get_opt(rotator, Opts, ?RumDefRotateMod), Rotator = rumUtil:get_opt(rotator, Opts, ?RumDefRotateMod),
HighWaterMark = rumUtil:get_opt(high_water_mark, Opts, ?RumDefCheckHWM),
Flush = rumUtil:get_opt(flush_queue, Opts, ?RumDefFlushQueue),
FlushThr = rumUtil:get_opt(flush_threshold, Opts, ?RumDefFlushThreshold),
SyncInterval = rumUtil:get_opt(sync_interval, Opts, ?RumDefSyncInterval),
CfgCheckInterval = rumUtil:get_opt(check_interval, Opts, ?RumDefCheckInterval),
SyncSize = rumUtil:get_opt(sync_size, Opts, ?RumDefSyncSize),
CfgSyncOn = rumUtil:get_opt(sync_on, Opts, ?RumDefSyncLevel),
Formatter = rumUtil:get_opt(formatter, Opts, ?RumDefFormatter),
FormatterConfig = rumUtil:get_opt(formatter_config, Opts, ?RumDefFormatterCfg),
HWM = rumUtil:get_opt(hWM, Opts, ?RumDefCheckHWM),
Flush = rumUtil:get_opt(flushQueue, Opts, ?RumDefFlushQueue),
FlushThr = rumUtil:get_opt(flushThr, Opts, ?RumDefFlushThr),
SyncInt = rumUtil:get_opt(syncInt, Opts, ?RumDefSyncInt),
CfgCheckInterval = rumUtil:get_opt(checkInt, Opts, ?RumDefCheckInt),
SyncSize = rumUtil:get_opt(syncSize, Opts, ?RumDefSyncSize),
CfgSyncOn = rumUtil:get_opt(syncOn, Opts, ?RumDefSyncLevel),
FormatTer = rumUtil:get_opt(formatTer, Opts, ?RumDefFormatTer),
FormatCfg = rumUtil:get_opt(formatCfg, Opts, ?RumDefFormatterCfg),
%% %%
Level = rumUtil:configToMask(CfgLevel), Level = rumUtil:configToMask(CfgLevel),
SyncOn = rumUtil:configToMask(CfgSyncOn), SyncOn = rumUtil:configToMask(CfgSyncOn),
CheckInterval = ?IIF(CfgCheckInterval == always, 0, CfgCheckInterval),
CheckInt = ?IIF(CfgCheckInterval == always, 0, CfgCheckInterval),
{ok, Date} = rumUtil:parseRotateSpec(CfgDate), {ok, Date} = rumUtil:parseRotateSpec(CfgDate),
FileName = rumUtil:parsePath(RelName), FileName = rumUtil:parsePath(RelName),
scheduleRotation(Date, FileName), scheduleRotation(Date, FileName),
Shaper = rumUtil:maybeFlush(Flush, #rumShaper{hwm = HighWaterMark, flushThreshold = FlushThr, id = FileName}),
Shaper = rumUtil:maybeFlush(Flush, #rumShaper{hwm = HWM, flushThr = FlushThr, id = FileName}),
TemState = #state{ TemState = #state{
fileName = FileName, level = Level, size = Size, date = Date fileName = FileName, level = Level, size = Size, date = Date
, count = Count, rotator = Rotator, shaper = Shaper , count = Count, rotator = Rotator, shaper = Shaper
, formatter = Formatter, formatterConfig = FormatterConfig
, syncOn = SyncOn, syncInterval = SyncInterval
, syncSize = SyncSize, checkInterval = CheckInterval
, formatTer = FormatTer, formatCfg = FormatCfg
, syncOn = SyncOn, syncInt = SyncInt
, syncSize = SyncSize, checkInt = CheckInt
}, },
case Rotator:createLogFile(FileName, {SyncSize, SyncInterval}) of
case Rotator:createLogFile(FileName, {SyncSize, SyncInt}) of
{ok, Fd, Inode, CTime, _Size} -> {ok, Fd, Inode, CTime, _Size} ->
{ok, TemState#state{fd = Fd, inode = Inode, ctime = CTime}};
{ok, TemState#state{fd = Fd, inode = Inode, cTime = CTime}};
{error, Reason} -> {error, Reason} ->
?INT_LOG(error, "Failed to open log file ~ts with error ~s", [FileName, file:format_error(Reason)]), ?INT_LOG(error, "Failed to open log file ~ts with error ~s", [FileName, file:format_error(Reason)]),
{ok, TemState#state{flap = true}} {ok, TemState#state{flap = true}}
@ -95,17 +95,17 @@ init(Opts) ->
handleCall(mGetLogLevel, #state{level = Level} = State) -> handleCall(mGetLogLevel, #state{level = Level} = State) ->
{reply, Level, State}; {reply, Level, State};
handleCall({mSetLogLevel, Level}, #state{fileName = Ident} = State) ->
handleCall({mSetLogLevel, Level}, #state{fileName = FileName} = State) ->
case rumUtil:validateLogLevel(Level) of case rumUtil:validateLogLevel(Level) of
false -> false ->
{reply, {error, bad_loglevel}, State}; {reply, {error, bad_loglevel}, State};
LevelMask -> LevelMask ->
?INT_LOG(notice, "Changed loglevel of ~s to ~p", [Ident, Level]),
?INT_LOG(notice, "Changed loglevel of ~s to ~p", [FileName, Level]),
{reply, ok, State#state{level = LevelMask}} {reply, ok, State#state{level = LevelMask}}
end; end;
handleCall({mSetLogHwm, Hwm}, #state{shaper = Shaper, fileName = FileName} = State) -> handleCall({mSetLogHwm, Hwm}, #state{shaper = Shaper, fileName = FileName} = State) ->
case checkOpts([{high_water_mark, Hwm}], true) of
case checkOpts([{hWM, Hwm}], true) of
false -> false ->
{reply, {error, bad_log_hwm}, State}; {reply, {error, bad_log_hwm}, State};
_ -> _ ->
@ -120,12 +120,12 @@ handleCall(_Msg, State) ->
?ERR("~p call receive unexpect msg ~p ~n ", [?MODULE, _Msg]), ?ERR("~p call receive unexpect msg ~p ~n ", [?MODULE, _Msg]),
{reply, ok, State}. {reply, ok, State}.
handleEvent({mWriteLog, Message}, #state{fileName = FileName, level = Level, shaper = Shaper, formatter = Formatter, formatterConfig = FormatConfig} = State) ->
handleEvent({mWriteLog, Message}, #state{fileName = FileName, level = Level, shaper = Shaper, formatTer = FormatTer, formatCfg = FormatCfg} = State) ->
case rumUtil:isLoggAble(Message, Level, {rumBkdFile, FileName}) of case rumUtil:isLoggAble(Message, Level, {rumBkdFile, FileName}) of
true -> true ->
case rumUtil:checkHwm(Shaper) of case rumUtil:checkHwm(Shaper) of
{true, _Drop, NewShaper} -> {true, _Drop, NewShaper} ->
{ok, writeLog(State#state{shaper = NewShaper}, rumMsg:timestamp(Message), rumMsg:severity_as_int(Message), Formatter:format(Message, FormatConfig))};
{ok, writeLog(State#state{shaper = NewShaper}, rumMsg:timestamp(Message), rumMsg:severity_as_int(Message), FormatTer:format(Message, FormatCfg))};
{drop, Drop, NewShaper} -> {drop, Drop, NewShaper} ->
TemState = TemState =
case Drop =< 0 of case Drop =< 0 of
@ -134,9 +134,9 @@ handleEvent({mWriteLog, Message}, #state{fileName = FileName, level = Level, sha
_ -> _ ->
Report = eFmt:format(<<"rumBkdFile dropped ~p messages in the last second that exceeded the limit of ~p messages/sec">>, [Drop, NewShaper#rumShaper.hwm]), Report = eFmt:format(<<"rumBkdFile dropped ~p messages in the last second that exceeded the limit of ~p messages/sec">>, [Drop, NewShaper#rumShaper.hwm]),
ReportMsg = rumMsg:new(Report, warning, [], []), ReportMsg = rumMsg:new(Report, warning, [], []),
writeLog(State, rumMsg:timestamp(ReportMsg), rumMsg:severity_as_int(ReportMsg), Formatter:format(ReportMsg, FormatConfig))
writeLog(State, rumMsg:timestamp(ReportMsg), rumMsg:severity_as_int(ReportMsg), FormatTer:format(ReportMsg, FormatCfg))
end, end,
{ok, writeLog(TemState#state{shaper = NewShaper}, rumMsg:timestamp(Message), rumMsg:severity_as_int(Message), Formatter:format(Message, FormatConfig))};
{ok, writeLog(TemState#state{shaper = NewShaper}, rumMsg:timestamp(Message), rumMsg:severity_as_int(Message), FormatTer:format(Message, FormatCfg))};
{false, _, NewShaper} -> {false, _, NewShaper} ->
{ok, State#state{shaper = NewShaper}} {ok, State#state{shaper = NewShaper}}
end; end;
@ -152,14 +152,14 @@ handleInfo({mRotate, File}, #state{fileName = File, count = Count, date = Date,
_ = Rotator:rotateLogFile(File, Count), _ = Rotator:rotateLogFile(File, Count),
scheduleRotation(File, Date), scheduleRotation(File, Date),
{ok, NewState}; {ok, NewState};
handleInfo({mShaperExpired, Name}, #state{shaper = Shaper, fileName = Name, formatter = Formatter, formatterConfig = FormatConfig} = State) ->
handleInfo({mShaperExpired, Name}, #state{shaper = Shaper, fileName = Name, formatTer = FormatTer, formatCfg = FormatCfg} = State) ->
case Shaper#rumShaper.dropped of case Shaper#rumShaper.dropped of
0 -> 0 ->
ignore; ignore;
Dropped -> Dropped ->
Report = eFmt:format(<<"rumBkdFile dropped ~p messages in the last second that exceeded the limit of ~p messages/sec">>, [Dropped, Shaper#rumShaper.hwm]), Report = eFmt:format(<<"rumBkdFile dropped ~p messages in the last second that exceeded the limit of ~p messages/sec">>, [Dropped, Shaper#rumShaper.hwm]),
ReportMsg = rumMsg:new(Report, warning, [], []), ReportMsg = rumMsg:new(Report, warning, [], []),
writeLog(State, rumMsg:timestamp(ReportMsg), rumMsg:severity_as_int(ReportMsg), Formatter:format(ReportMsg, FormatConfig))
writeLog(State, rumMsg:timestamp(ReportMsg), rumMsg:severity_as_int(ReportMsg), FormatTer:format(ReportMsg, FormatCfg))
end, end,
{ok, State#state{shaper = Shaper#rumShaper{dropped = 0, mps = 0, lastTime = rumTime:now()}}}; {ok, State#state{shaper = Shaper#rumShaper{dropped = 0, mps = 0, lastTime = rumTime:now()}}};
handleInfo(_Msg, _State) -> handleInfo(_Msg, _State) ->
@ -174,11 +174,11 @@ terminate(_Reason, State) ->
code_change(_OldVsn, State, _Extra) -> code_change(_OldVsn, State, _Extra) ->
{ok, State}. {ok, State}.
writeLog(#state{fileName = FileName, fd = Fd, inode = Inode, ctime = CTime, flap = Flap, size = RotSize, count = Count, rotator = Rotator, lastCheck = LastCheck, checkInterval = CheckInterval, syncSize = SyncSize, syncInterval = SyncInterval} = State, Timestamp, Level, Msg) ->
case isWriteCheck(Fd, LastCheck, CheckInterval, FileName, Inode, CTime, Timestamp) of
writeLog(#state{fileName = FileName, fd = Fd, inode = Inode, cTime = CTime, flap = Flap, size = RotSize, count = Count, rotator = Rotator, lastCheck = LastCheck, checkInt = CheckInt, syncSize = SyncSize, syncInt = SyncInt} = State, Timestamp, Level, Msg) ->
case isWriteCheck(Fd, LastCheck, CheckInt, FileName, Inode, CTime, Timestamp) of
true -> true ->
%% need to check for rotation %% need to check for rotation
case Rotator:ensureLogFile(FileName, Fd, Inode, CTime, {SyncSize, SyncInterval}) of
case Rotator:ensureLogFile(FileName, Fd, Inode, CTime, {SyncSize, SyncInt}) of
{ok, NewFD, NewInode, NewCTime, FileSize} -> {ok, NewFD, NewInode, NewCTime, FileSize} ->
case RotSize > 0 andalso FileSize > RotSize of case RotSize > 0 andalso FileSize > RotSize of
true -> true ->
@ -192,7 +192,7 @@ writeLog(#state{fileName = FileName, fd = Fd, inode = Inode, ctime = CTime, flap
end; end;
_ -> _ ->
%% update our last check and try again %% update our last check and try again
TemState = State#state{lastCheck = Timestamp, fd = NewFD, inode = NewInode, ctime = NewCTime},
TemState = State#state{lastCheck = Timestamp, fd = NewFD, inode = NewInode, cTime = NewCTime},
writeFile(TemState, Level, Msg) writeFile(TemState, Level, Msg)
end; end;
{error, Reason} -> {error, Reason} ->
@ -255,25 +255,25 @@ checkOpts([{count, Count} | Tail], IsFile) when is_integer(Count), Count >= 0 ->
checkOpts(Tail, IsFile); checkOpts(Tail, IsFile);
checkOpts([{rotator, Rotator} | Tail], IsFile) when is_atom(Rotator) -> checkOpts([{rotator, Rotator} | Tail], IsFile) when is_atom(Rotator) ->
checkOpts(Tail, IsFile); checkOpts(Tail, IsFile);
checkOpts([{high_water_mark, HighWaterMark} | Tail], IsFile) when is_integer(HighWaterMark), HighWaterMark >= 0 ->
checkOpts([{hWM, HighWaterMark} | Tail], IsFile) when is_integer(HighWaterMark), HighWaterMark >= 0 ->
checkOpts(Tail, IsFile); checkOpts(Tail, IsFile);
checkOpts([{date, _Date} | Tail], IsFile) -> checkOpts([{date, _Date} | Tail], IsFile) ->
checkOpts(Tail, IsFile); checkOpts(Tail, IsFile);
checkOpts([{sync_interval, SyncInt} | Tail], IsFile) when is_integer(SyncInt), SyncInt >= 0 ->
checkOpts([{syncInt, SyncInt} | Tail], IsFile) when is_integer(SyncInt), SyncInt >= 0 ->
checkOpts(Tail, IsFile); checkOpts(Tail, IsFile);
checkOpts([{sync_size, SyncSize} | Tail], IsFile) when is_integer(SyncSize), SyncSize >= 0 ->
checkOpts([{syncSize, SyncSize} | Tail], IsFile) when is_integer(SyncSize), SyncSize >= 0 ->
checkOpts(Tail, IsFile); checkOpts(Tail, IsFile);
checkOpts([{check_interval, CheckInt} | Tail], IsFile) when is_integer(CheckInt), CheckInt >= 0; CheckInt == always ->
checkOpts([{checkInt, CheckInt} | Tail], IsFile) when is_integer(CheckInt), CheckInt >= 0; CheckInt == always ->
checkOpts(Tail, IsFile); checkOpts(Tail, IsFile);
checkOpts([{sync_on, Level} | Tail], IsFile) ->
checkOpts([{syncOn, Level} | Tail], IsFile) ->
?IIF(rumUtil:validateLogLevel(Level) /= false, checkOpts(Tail, IsFile), {error, {invalid_sync_on, Level}}); ?IIF(rumUtil:validateLogLevel(Level) /= false, checkOpts(Tail, IsFile), {error, {invalid_sync_on, Level}});
checkOpts([{formatter, Fmt} | Tail], IsFile) when is_atom(Fmt) ->
checkOpts([{formatTer, Fmt} | Tail], IsFile) when is_atom(Fmt) ->
checkOpts(Tail, IsFile); checkOpts(Tail, IsFile);
checkOpts([{formatter_config, FmtCfg} | Tail], IsFile) when is_list(FmtCfg) ->
checkOpts([{formatCfg, FmtCfg} | Tail], IsFile) when is_list(FmtCfg) ->
checkOpts(Tail, IsFile); checkOpts(Tail, IsFile);
checkOpts([{flush_queue, FlushCfg} | Tail], IsFile) when is_boolean(FlushCfg) ->
checkOpts([{flushQueue, FlushCfg} | Tail], IsFile) when is_boolean(FlushCfg) ->
checkOpts(Tail, IsFile); checkOpts(Tail, IsFile);
checkOpts([{flush_threshold, Thr} | Tail], IsFile) when is_integer(Thr), Thr >= 0 ->
checkOpts([{flushThr, Thr} | Tail], IsFile) when is_integer(Thr), Thr >= 0 ->
checkOpts(Tail, IsFile); checkOpts(Tail, IsFile);
checkOpts([Other | _Tail], _IsFile) -> checkOpts([Other | _Tail], _IsFile) ->
{error, {invalid_opt, Other}}. {error, {invalid_opt, Other}}.

+ 8
- 8
src/crashLog/rumCrashLog.erl 查看文件

@ -34,7 +34,7 @@
fileName :: string() %% fileName :: string() %%
, fd :: pid() | undefined %% , fd :: pid() | undefined %%
, inode :: integer() | undefined %% inode信息 , inode :: integer() | undefined %% inode信息
, ctime :: file:date_time() | undefined %%
, cTime :: file:date_time() | undefined %%
, maxFmtSize :: integer() %% , maxFmtSize :: integer() %%
, maxFileSize :: integer() %% , maxFileSize :: integer() %%
, date :: undefined | string() %% , date :: undefined | string() %%
@ -55,7 +55,7 @@ init({RelFilename, MaxFmtSize, MaxFileSize, CfgDate, Count, Rotator}) ->
case Rotator:openLogFile(Filename, false) of case Rotator:openLogFile(Filename, false) of
{ok, Fd, Inode, CTime, _Size} -> {ok, Fd, Inode, CTime, _Size} ->
scheduleRotation(Date), scheduleRotation(Date),
{ok, #state{fileName = Filename, fd = Fd, inode = Inode, ctime = CTime, maxFmtSize = MaxFmtSize, maxFileSize = MaxFileSize, date = Date, count = Count, rotator = Rotator}};
{ok, #state{fileName = Filename, fd = Fd, inode = Inode, cTime = CTime, maxFmtSize = MaxFmtSize, maxFileSize = MaxFileSize, date = Date, count = Count, rotator = Rotator}};
{error, Reason} -> {error, Reason} ->
?INT_LOG(error, "Failed to open crash log file ~ts with error: ~s", [Filename, file:format_error(Reason)]), ?INT_LOG(error, "Failed to open crash log file ~ts with error: ~s", [Filename, file:format_error(Reason)]),
{ok, #state{fileName = Filename, maxFmtSize = MaxFmtSize, maxFileSize = MaxFileSize, date = Date, count = Count, flap = true, rotator = Rotator}} {ok, #state{fileName = Filename, maxFmtSize = MaxFmtSize, maxFileSize = MaxFileSize, date = Date, count = Count, flap = true, rotator = Rotator}}
@ -146,7 +146,7 @@ saslLimitedStr(progress, Report, FmtMaxBytes) ->
saslLimitedStr(crash_report, Report, FmtMaxBytes) -> saslLimitedStr(crash_report, Report, FmtMaxBytes) ->
rumStdlib:proc_lib_format(Report, FmtMaxBytes). rumStdlib:proc_lib_format(Report, FmtMaxBytes).
writeLog(Event, #state{fileName = FileName, fd = FD, inode = Inode, ctime = Ctime, flap = Flap, maxFmtSize = FmtMaxBytes, maxFileSize = RotSize, count = Count, rotator = Rotator} = State) ->
writeLog(Event, #state{fileName = FileName, fd = FD, inode = Inode, cTime = CTime, flap = Flap, maxFmtSize = FmtMaxBytes, maxFileSize = RotSize, count = Count, rotator = Rotator} = State) ->
%% borrowed from riak_err %% borrowed from riak_err
{ReportStr, Pid, MsgStr, _ErrorP} = {ReportStr, Pid, MsgStr, _ErrorP} =
case Event of case Event of
@ -163,8 +163,8 @@ writeLog(Event, #state{fileName = FileName, fd = FD, inode = Inode, ctime = Ctim
ignore -> ignore ->
{ok, State}; {ok, State};
_ -> _ ->
case Rotator:ensureLogFile(FileName, FD, Inode, Ctime, false) of
{ok, NewFD, NewInode, NewCtime, FileSize} ->
case Rotator:ensureLogFile(FileName, FD, Inode, CTime, false) of
{ok, NewFD, NewInode, NewCTime, FileSize} ->
case RotSize > 0 andalso FileSize > RotSize of case RotSize > 0 andalso FileSize > RotSize of
true -> true ->
_ = Rotator:rotateLogFile(FileName, Count), _ = Rotator:rotateLogFile(FileName, Count),
@ -177,11 +177,11 @@ writeLog(Event, #state{fileName = FileName, fd = FD, inode = Inode, ctime = Ctim
case file:write(NewFD, unicode:characters_to_binary(Msg)) of case file:write(NewFD, unicode:characters_to_binary(Msg)) of
{error, Reason} when Flap == false -> {error, Reason} when Flap == false ->
?INT_LOG(error, "Failed to write log message to file ~ts: ~s", [FileName, file:format_error(Reason)]), ?INT_LOG(error, "Failed to write log message to file ~ts: ~s", [FileName, file:format_error(Reason)]),
{ok, State#state{fd = NewFD, inode = NewInode, ctime = NewCtime, flap = true}};
{ok, State#state{fd = NewFD, inode = NewInode, cTime = NewCTime, flap = true}};
ok -> ok ->
{ok, State#state{fd = NewFD, inode = NewInode, ctime = NewCtime, flap = false}};
{ok, State#state{fd = NewFD, inode = NewInode, cTime = NewCTime, flap = false}};
_ -> _ ->
{ok, State#state{fd = NewFD, inode = NewInode, ctime = NewCtime}}
{ok, State#state{fd = NewFD, inode = NewInode, cTime = NewCTime}}
end end
end; end;
{error, Reason} -> {error, Reason} ->

+ 5
- 5
src/eRum.erl 查看文件

@ -532,17 +532,17 @@ minLogLevel(Levels) ->
%% arguments. The caller is NOT crashed. %% arguments. The caller is NOT crashed.
safe_format(Fmt, Args, Limit) -> safe_format(Fmt, Args, Limit) ->
safe_format(Fmt, Args, Limit, []).
safe_format_2(Fmt, Args, Limit).
safe_format(Fmt, Args, Limit, Options) ->
try rumTruncIo:format(Fmt, Args, Limit, Options)
safe_format_2(Fmt, Args, Limit) ->
try eFmt:formatBin(Fmt, Args, [{charsLimit, Limit}])
catch catch
_:_ -> rumTruncIo:format("FORMAT ERROR: ~p ~p", [Fmt, Args], Limit)
_:_ -> eFmt:formatBin(<<"FORMAT ERROR: ~p ~p">>, [Fmt, Args], [{charsLimit, Limit}])
end. end.
%% @private %% @private
safe_format_chop(Fmt, Args, Limit) -> safe_format_chop(Fmt, Args, Limit) ->
safe_format(Fmt, Args, Limit, [{chomp, true}]).
safe_format_2(Fmt, Args, Limit).
%% @private Print the format string `Fmt' with `Args' without a size limit. %% @private Print the format string `Fmt' with `Args' without a size limit.
%% This is unsafe because the output of this function is unbounded. %% This is unsafe because the output of this function is unbounded.

+ 2
- 4
src/eRum1.erl 查看文件

@ -4,9 +4,6 @@
-include("rumMsg.hrl"). -include("rumMsg.hrl").
-include("rumCom.hrl"). -include("rumCom.hrl").
-ifdef(TEST).
-include_lib("eunit/include/eunit.hrl").
-endif.
%% API %% API
-export([ -export([
@ -18,6 +15,7 @@
, dispatch_log/13 , dispatch_log/13
, do_log/16 , do_log/16
, do_log_unsafe/16 , do_log_unsafe/16
, do_log_impl/16
, safe_format/3 , safe_format/3
, safe_format_chop/3 , safe_format_chop/3
, unsafe_format/2 , unsafe_format/2
@ -125,7 +123,7 @@ do_log_impl(Severity, Pid, Node, Module, Function, _File, Line, Metadata, Format
case rumConfig:get({Sink, async}, false) of case rumConfig:get({Sink, async}, false) of
true -> true ->
gen_emm:info_notify(SinkPid, {mWriteLog, LagerMsg}); gen_emm:info_notify(SinkPid, {mWriteLog, LagerMsg});
false ->
_ ->
gen_emm:call_notify(SinkPid, {mWriteLog, LagerMsg}) gen_emm:call_notify(SinkPid, {mWriteLog, LagerMsg})
end, end,
case TraceSinkPid /= undefined of case TraceSinkPid /= undefined of

+ 1
- 1
src/errLogger/rumErrLoggerH.erl 查看文件

@ -67,7 +67,7 @@ setHighWater(N) ->
init([HighWaterMark, GlStrategy]) -> init([HighWaterMark, GlStrategy]) ->
Flush = rumUtil:get_env(errLoggerFlushQueue, true), Flush = rumUtil:get_env(errLoggerFlushQueue, true),
FlushThr = rumUtil:get_env(errLoggerFlushThreshold, 0), FlushThr = rumUtil:get_env(errLoggerFlushThreshold, 0),
Shaper = #rumShaper{hwm = HighWaterMark, flushQueue = Flush, flushThreshold = FlushThr, filter = shaperFun(), id = ?MODULE},
Shaper = #rumShaper{hwm = HighWaterMark, flushQueue = Flush, flushThr = FlushThr, filter = shaperFun(), id = ?MODULE},
Raw = rumUtil:get_env(errLoggerFormatRaw, false), Raw = rumUtil:get_env(errLoggerFormatRaw, false),
Sink = configSink(), Sink = configSink(),
{ok, #state{sink = Sink, shaper = Shaper, groupleader_strategy = GlStrategy, raw = Raw}}. {ok, #state{sink = Sink, shaper = Shaper, groupleader_strategy = GlStrategy, raw = Raw}}.

src/formatter/rumFormatter.erl → src/formatter/rumFormatTer.erl 查看文件

@ -1,4 +1,4 @@
-module(rumFormatter).
-module(rumFormatTer).
-include("rumDef.hrl"). -include("rumDef.hrl").
@ -18,7 +18,7 @@
%% elements in the configuration are printed verbatim. Atoms in the configuration are treated as metadata properties %% elements in the configuration are printed verbatim. Atoms in the configuration are treated as metadata properties
%% and extracted from the log message. Optionally, a tuple of {atom(),semi-iolist()} can be used. The atom will look %% and extracted from the log message. Optionally, a tuple of {atom(),semi-iolist()} can be used. The atom will look
%% up the property, but if not found it will use the semi-iolist() instead. These fallbacks can be similarly nested %% up the property, but if not found it will use the semi-iolist() instead. These fallbacks can be similarly nested
%% or refer to other properties, if desired. You can also use a {atom, semi-iolist(), semi-iolist()} formatter, which
%% or refer to other properties, if desired. You can also use a {atom, semi-iolist(), semi-iolist()} formatTer, which
%% acts like a ternary operator's true/false branches. %% acts like a ternary operator's true/false branches.
%% %%
%% The metadata properties date,time, message, severity, and sev will always exist. %% The metadata properties date,time, message, severity, and sev will always exist.

+ 3
- 6
src/utils/rumStdlib.erl 查看文件

@ -42,8 +42,7 @@ proc_lib_format([OwnReport, LinkReport], FmtMaxBytes) ->
format_report(Rep, FmtMaxBytes) when is_list(Rep) -> format_report(Rep, FmtMaxBytes) when is_list(Rep) ->
format_rep(Rep, FmtMaxBytes); format_rep(Rep, FmtMaxBytes);
format_report(Rep, FmtMaxBytes) -> format_report(Rep, FmtMaxBytes) ->
{Str, _} = rumTruncIo:print(Rep, FmtMaxBytes),
io_lib:format("~p~n", [Str]).
eFmt:formatBin(<<"~p~n">>, [Rep], [{charsLimit, FmtMaxBytes}]).
format_rep([{initial_call, InitialCall} | Rep], FmtMaxBytes) -> format_rep([{initial_call, InitialCall} | Rep], FmtMaxBytes) ->
[format_mfa(InitialCall, FmtMaxBytes) | format_rep(Rep, FmtMaxBytes)]; [format_mfa(InitialCall, FmtMaxBytes) | format_rep(Rep, FmtMaxBytes)];
@ -74,13 +73,11 @@ format_mfa({M, F, Args} = StartF, FmtMaxBytes) ->
pp_fun(FmtMaxBytes) -> pp_fun(FmtMaxBytes) ->
fun(Term, _I) -> fun(Term, _I) ->
{Str, _} = rumTruncIo:print(Term, FmtMaxBytes),
io_lib:format("~s", [Str])
eFmt:formatBin(<<"~p">>, [Term], [{charsLimit ,FmtMaxBytes}])
end. end.
format_tag(Tag, Data, FmtMaxBytes) -> format_tag(Tag, Data, FmtMaxBytes) ->
{Str, _} = rumTruncIo:print(Data, FmtMaxBytes),
io_lib:format(" ~p: ~s~n", [Tag, Str]).
eFmt:formatBin(<<"~p: ~p~n">>, [Tag, Data], [{charsLimit ,FmtMaxBytes}]).
%% From OTP stdlib's lib.erl ... These functions aren't exported. %% From OTP stdlib's lib.erl ... These functions aren't exported.

+ 0
- 869
src/utils/rumTruncIo.erl 查看文件

@ -1,869 +0,0 @@
%%
%% @doc Module to print out terms for logging. Limits by length rather than depth.
%%
%% The resulting string may be slightly larger than the limit; the intention
%% is to provide predictable CPU and memory consumption for formatting
%% terms, not produce precise string lengths.
%%
%% Typical use:
%%
%% trunc_io:print(Term, 500).
%%
%% Source license: Erlang Public License.
%% Original author: Matthias Lang, <tt>matthias@corelatus.se</tt>
%%
%% Various changes to this module, most notably the format/3 implementation
%% were added by Andrew Thompson `<andrew@basho.com>'. The module has been renamed
%% to avoid conflicts with the vanilla module.
-module(rumTruncIo).
-author('matthias@corelatus.se').
%% And thanks to Chris Newcombe for a bug fix
-export([format/3, format/4, print/2, print/3, fprint/2, fprint/3, safe/2]). % interface functions
-version("$Id: trunc_io.erl,v 1.11 2009-02-23 12:01:06 matthias Exp $").
-ifdef(TEST).
-export([perf/0, perf/3, perf1/0, test/0, test/2]). % testing functions
-include_lib("eunit/include/eunit.hrl").
-endif.
-type option() :: {'depth', integer()}
| {'lists_as_strings', boolean()}
| {'force_strings', boolean()}.
-type options() :: [option()].
-record(print_options, {
%% negative depth means no depth limiting
depth = -1 :: integer(),
%% whether to print lists as strings, if possible
lists_as_strings = true :: boolean(),
%% force strings, or binaries to be printed as a string,
%% even if they're not printable
force_strings = false :: boolean()
}).
format(Fmt, Args, Max) ->
format(Fmt, Args, Max, []).
format(Fmt, Args, Max, Options) ->
try rumFormat:format(Fmt, Args, Max, Options)
catch
_What:_Why ->
erlang:error(badarg, [Fmt, Args])
end.
%% @doc Returns an flattened list containing the ASCII representation of the given
%% term.
-spec fprint(term(), pos_integer()) -> string().
fprint(Term, Max) ->
fprint(Term, Max, []).
%% @doc Returns an flattened list containing the ASCII representation of the given
%% term.
-spec fprint(term(), pos_integer(), options()) -> string().
fprint(T, Max, Options) ->
{L, _} = print(T, Max, prepare_options(Options, #print_options{})),
lists:flatten(L).
%% @doc Same as print, but never crashes.
%%
%% This is a tradeoff. Print might conceivably crash if it's asked to
%% print something it doesn't understand, for example some new data
%% type in a future version of Erlang. If print crashes, we fall back
%% to io_lib to format the term, but then the formatting is
%% depth-limited instead of length limited, so you might run out
%% memory printing it. Out of the frying pan and into the fire.
%%
-spec safe(term(), pos_integer()) -> {string(), pos_integer()} | {string()}.
safe(What, Len) ->
case catch print(What, Len) of
{L, Used} when is_list(L) -> {L, Used};
_ -> {"unable to print" ++ io_lib:write(What, 99)}
end.
%% @doc Returns {List, Length}
-spec print(term(), pos_integer()) -> {iolist(), pos_integer()}.
print(Term, Max) ->
print(Term, Max, []).
%% @doc Returns {List, Length}
-spec print(term(), pos_integer(), options() | #print_options{}) -> {iolist(), pos_integer()}.
print(Term, Max, Options) when is_list(Options) ->
%% need to convert the proplist to a record
print(Term, Max, prepare_options(Options, #print_options{}));
print(Term, _Max, #print_options{force_strings = true}) when not is_list(Term), not is_binary(Term), not is_atom(Term) ->
erlang:error(badarg);
print(_, Max, _Options) when Max < 0 -> {"...", 3};
print(_, _, #print_options{depth = 0}) -> {"...", 3};
%% @doc We assume atoms, floats, funs, integers, PIDs, ports and refs never need
%% to be truncated. This isn't strictly true, someone could make an
%% arbitrarily long bignum. Let's assume that won't happen unless someone
%% is being malicious.
%%
print(Atom, _Max, #print_options{force_strings = NoQuote}) when is_atom(Atom) ->
L = atom_to_list(Atom),
R = case atom_needs_quoting_start(L) andalso not NoQuote of
true -> lists:flatten([$', L, $']);
false -> L
end,
{R, length(R)};
print(<<>>, _Max, #print_options{depth = 1}) ->
{"<<>>", 4};
print(Bin, _Max, #print_options{depth = 1}) when is_binary(Bin) ->
{"<<...>>", 7};
print(<<>>, _Max, Options) ->
case Options#print_options.force_strings of
true ->
{"", 0};
false ->
{"<<>>", 4}
end;
print(Binary, 0, _Options) when is_bitstring(Binary) ->
{"<<..>>", 6};
print(Bin, Max, _Options) when is_binary(Bin), Max < 2 ->
{"<<...>>", 7};
print(Binary, Max, Options) when is_binary(Binary) ->
B = binary_to_list(Binary, 1, lists:min([Max, byte_size(Binary)])),
{Res, Length} =
case Options#print_options.lists_as_strings orelse Options#print_options.force_strings of
true ->
Depth = Options#print_options.depth,
MaxSize = (Depth - 1) * 4,
%% check if we need to truncate based on depth
In =
case Depth > -1 andalso MaxSize < length(B) andalso
not Options#print_options.force_strings of
true ->
string:substr(B, 1, MaxSize);
false -> B
end,
MaxLen =
case Options#print_options.force_strings of
true ->
Max;
false ->
%% make room for the leading doublequote
Max - 1
end,
try alist(In, MaxLen, Options) of
{L0, Len0} ->
case Options#print_options.force_strings of
false ->
case B /= In of
true ->
{[$", L0, "..."], Len0 + 4};
false ->
{[$" | L0], Len0 + 1}
end;
true ->
{L0, Len0}
end
catch
throw:{unprintable, C} ->
Index = string:chr(In, C),
case Index > 1 andalso Options#print_options.depth =< Index andalso
Options#print_options.depth > -1 andalso
not Options#print_options.force_strings of
true ->
%% print first Index-1 characters followed by ...
{L0, Len0} = alist_start(string:substr(In, 1, Index - 1), Max - 1, Options),
{L0 ++ "...", Len0 + 3};
false ->
list_body(In, Max - 4, dec_depth(Options), true)
end
end;
_ ->
list_body(B, Max - 4, dec_depth(Options), true)
end,
case Options#print_options.force_strings of
true ->
{Res, Length};
_ ->
{["<<", Res, ">>"], Length + 4}
end;
%% bitstrings are binary's evil brother who doesn't end on an 8 bit boundary.
%% This makes printing them extremely annoying, so list_body/list_bodyc has
%% some magic for dealing with the output of bitstring_to_list, which returns
%% a list of integers (as expected) but with a trailing binary that represents
%% the remaining bits.
print({inline_bitstring, B}, _Max, _Options) when is_bitstring(B) ->
Size = bit_size(B),
<<Value:Size>> = B,
ValueStr = integer_to_list(Value),
SizeStr = integer_to_list(Size),
{[ValueStr, $:, SizeStr], length(ValueStr) + length(SizeStr) + 1};
print(BitString, Max, Options) when is_bitstring(BitString) ->
BL =
case byte_size(BitString) > Max of
true ->
binary_to_list(BitString, 1, Max);
_ ->
R = erlang:bitstring_to_list(BitString),
{Bytes, [Bits]} = lists:splitwith(fun erlang:is_integer/1, R),
%% tag the trailing bits with a special tuple we catch when
%% list_body calls print again
Bytes ++ [{inline_bitstring, Bits}]
end,
{X, Len0} = list_body(BL, Max - 4, dec_depth(Options), true),
{["<<", X, ">>"], Len0 + 4};
print(Float, _Max, _Options) when is_float(Float) ->
%% use the same function io_lib:format uses to print floats
%% float_to_list is way too verbose.
L = io_lib_format:fwrite_g(Float),
{L, length(L)};
print(Fun, Max, _Options) when is_function(Fun) ->
L = erlang:fun_to_list(Fun),
case length(L) > Max of
true ->
S = erlang:max(5, Max),
Res = string:substr(L, 1, S) ++ "..>",
{Res, length(Res)};
_ ->
{L, length(L)}
end;
print(Integer, _Max, _Options) when is_integer(Integer) ->
L = integer_to_list(Integer),
{L, length(L)};
print(Pid, _Max, _Options) when is_pid(Pid) ->
L = pid_to_list(Pid),
{L, length(L)};
print(Ref, _Max, _Options) when is_reference(Ref) ->
L = erlang:ref_to_list(Ref),
{L, length(L)};
print(Port, _Max, _Options) when is_port(Port) ->
L = erlang:port_to_list(Port),
{L, length(L)};
print({'$lager_record', Name, Fields}, Max, Options) ->
Leader = "#" ++ atom_to_list(Name) ++ "{",
{RC, Len} = record_fields(Fields, Max - length(Leader) + 1, dec_depth(Options)),
{[Leader, RC, "}"], Len + length(Leader) + 1};
print(Tuple, Max, Options) when is_tuple(Tuple) ->
{TC, Len} = tuple_contents(Tuple, Max - 2, Options),
{[${, TC, $}], Len + 2};
print(List, Max, Options) when is_list(List) ->
case Options#print_options.lists_as_strings orelse
Options#print_options.force_strings of
true ->
alist_start(List, Max, dec_depth(Options));
_ ->
{R, Len} = list_body(List, Max - 2, dec_depth(Options), false),
{[$[, R, $]], Len + 2}
end;
print(Map, Max, Options) when is_map(Map) ->
{MapBody, Len} = map_body(Map, Max - 3, dec_depth(Options)),
{[$#, ${, MapBody, $}], Len + 3};
print(Term, Max, Options) ->
error(badarg, [Term, Max, Options]).
%% Returns {List, Length}
tuple_contents(Tuple, Max, Options) ->
L = tuple_to_list(Tuple),
list_body(L, Max, dec_depth(Options), true).
%% Format the inside of a list, i.e. do not add a leading [ or trailing ].
%% Returns {List, Length}
list_body([], _Max, _Options, _Tuple) -> {[], 0};
list_body(_, Max, _Options, _Tuple) when Max < 4 -> {"...", 3};
list_body(_, _Max, #print_options{depth = 0}, _Tuple) -> {"...", 3};
list_body([H], Max, Options = #print_options{depth = 1}, _Tuple) ->
print(H, Max, Options);
list_body([H | _], Max, Options = #print_options{depth = 1}, Tuple) ->
{List, Len} = print(H, Max - 4, Options),
Sep =
case Tuple of
true -> $,;
false -> $|
end,
{[List ++ [Sep | "..."]], Len + 4};
list_body([H | T], Max, Options, Tuple) ->
{List, Len} = print(H, Max, Options),
{Final, FLen} = list_bodyc(T, Max - Len, Options, Tuple),
{[List | Final], FLen + Len};
list_body(X, Max, Options, _Tuple) -> %% improper list
{List, Len} = print(X, Max - 1, Options),
{[$|, List], Len + 1}.
list_bodyc([], _Max, _Options, _Tuple) -> {[], 0};
list_bodyc(_, Max, _Options, _Tuple) when Max < 5 -> {",...", 4};
list_bodyc(_, _Max, #print_options{depth = 1}, true) -> {",...", 4};
list_bodyc(_, _Max, #print_options{depth = 1}, false) -> {"|...", 4};
list_bodyc([H | T], Max, #print_options{depth = Depth} = Options, Tuple) ->
{List, Len} = print(H, Max, dec_depth(Options)),
{Final, FLen} = list_bodyc(T, Max - Len - 1, dec_depth(Options), Tuple),
Sep =
case Depth == 1 andalso not Tuple of
true -> $|;
_ -> $,
end,
{[Sep, List | Final], FLen + Len + 1};
list_bodyc(X, Max, Options, _Tuple) -> %% improper list
{List, Len} = print(X, Max - 1, Options),
{[$|, List], Len + 1}.
map_body(Map, Max, #print_options{depth = Depth}) when Max < 4; Depth =:= 0 ->
case erlang:map_size(Map) of
0 -> {[], 0};
_ -> {"...", 3}
end;
map_body(Map, Max, Options) ->
case maps:to_list(Map) of
[] ->
{[], 0};
[{Key, Value} | Rest] ->
{KeyStr, KeyLen} = print(Key, Max - 4, Options),
DiffLen = KeyLen + 4,
{ValueStr, ValueLen} = print(Value, Max - DiffLen, Options),
DiffLen2 = DiffLen + ValueLen,
{Final, FLen} = map_bodyc(Rest, Max - DiffLen2, dec_depth(Options)),
{[KeyStr, " => ", ValueStr | Final], DiffLen2 + FLen}
end.
map_bodyc([], _Max, _Options) ->
{[], 0};
map_bodyc(_Rest, Max, #print_options{depth = Depth}) when Max < 5; Depth =:= 0 ->
{",...", 4};
map_bodyc([{Key, Value} | Rest], Max, Options) ->
{KeyStr, KeyLen} = print(Key, Max - 5, Options),
DiffLen = KeyLen + 5,
{ValueStr, ValueLen} = print(Value, Max - DiffLen, Options),
DiffLen2 = DiffLen + ValueLen,
{Final, FLen} = map_bodyc(Rest, Max - DiffLen2, dec_depth(Options)),
{[$,, KeyStr, " => ", ValueStr | Final], DiffLen2 + FLen}.
%% The head of a list we hope is ascii. Examples:
%%
%% [65,66,67] -> "ABC"
%% [65,0,67] -> "A"[0,67]
%% [0,65,66] -> [0,65,66]
%% [65,b,66] -> "A"[b,66]
%%
alist_start([], _Max, #print_options{force_strings = true}) -> {"", 0};
alist_start([], _Max, _Options) -> {"[]", 2};
alist_start(_, Max, _Options) when Max < 4 -> {"...", 3};
alist_start(_, _Max, #print_options{depth = 0}) -> {"[...]", 5};
alist_start(L, Max, #print_options{force_strings = true} = Options) ->
alist(L, Max, Options);
%alist_start([H|_T], _Max, #print_options{depth=1}) when is_integer(H) -> {[$[, H, $|, $., $., $., $]], 7};
alist_start([H | T], Max, Options) when is_integer(H), H >= 16#20, H =< 16#7e -> % definitely printable
try alist([H | T], Max - 1, Options) of
{L, Len} ->
{[$" | L], Len + 1}
catch
throw:{unprintable, _} ->
{R, Len} = list_body([H | T], Max - 2, Options, false),
{[$[, R, $]], Len + 2}
end;
alist_start([H | T], Max, Options) when is_integer(H), H >= 16#a0, H =< 16#ff -> % definitely printable
try alist([H | T], Max - 1, Options) of
{L, Len} ->
{[$" | L], Len + 1}
catch
throw:{unprintable, _} ->
{R, Len} = list_body([H | T], Max - 2, Options, false),
{[$[, R, $]], Len + 2}
end;
alist_start([H | T], Max, Options) when H =:= $\t; H =:= $\n; H =:= $\r; H =:= $\v; H =:= $\e; H =:= $\f; H =:= $\b ->
try alist([H | T], Max - 1, Options) of
{L, Len} ->
{[$" | L], Len + 1}
catch
throw:{unprintable, _} ->
{R, Len} = list_body([H | T], Max - 2, Options, false),
{[$[, R, $]], Len + 2}
end;
alist_start(L, Max, Options) ->
{R, Len} = list_body(L, Max - 2, Options, false),
{[$[, R, $]], Len + 2}.
alist([], _Max, #print_options{force_strings = true}) -> {"", 0};
alist([], _Max, _Options) -> {"\"", 1};
alist(_, Max, #print_options{force_strings = true}) when Max < 4 -> {"...", 3};
alist(_, Max, #print_options{force_strings = false}) when Max < 5 -> {"...\"", 4};
alist([H | T], Max, Options = #print_options{force_strings = false, lists_as_strings = true}) when H =:= $"; H =:= $\\ ->
%% preserve escaping around quotes
{L, Len} = alist(T, Max - 1, Options),
{[$\\, H | L], Len + 2};
alist([H | T], Max, Options) when is_integer(H), H >= 16#20, H =< 16#7e -> % definitely printable
{L, Len} = alist(T, Max - 1, Options),
{[H | L], Len + 1};
alist([H | T], Max, Options) when is_integer(H), H >= 16#a0, H =< 16#ff -> % definitely printable
{L, Len} = alist(T, Max - 1, Options),
{[H | L], Len + 1};
alist([H | T], Max, Options) when H =:= $\t; H =:= $\n; H =:= $\r; H =:= $\v; H =:= $\e; H =:= $\f; H =:= $\b ->
{L, Len} = alist(T, Max - 1, Options),
case Options#print_options.force_strings of
true ->
{[H | L], Len + 1};
_ ->
{[escape(H) | L], Len + 1}
end;
alist([H | T], Max, #print_options{force_strings = true} = Options) when is_integer(H) ->
{L, Len} = alist(T, Max - 1, Options),
{[H | L], Len + 1};
alist([H | T], Max, Options = #print_options{force_strings = true}) when is_binary(H); is_list(H) ->
{List, Len} = print(H, Max, Options),
case (Max - Len) =< 0 of
true ->
%% no more room to print anything
{List, Len};
false ->
%% no need to decrement depth, as we're in printable string mode
{Final, FLen} = alist(T, Max - Len, Options),
{[List | Final], FLen + Len}
end;
alist(_, _, #print_options{force_strings = true}) ->
erlang:error(badarg);
alist([H | _L], _Max, _Options) ->
throw({unprintable, H});
alist(H, _Max, _Options) ->
%% improper list
throw({unprintable, H}).
%% is the first character in the atom alphabetic & lowercase?
atom_needs_quoting_start([H | T]) when H >= $a, H =< $z ->
atom_needs_quoting(T);
atom_needs_quoting_start(_) ->
true.
atom_needs_quoting([]) ->
false;
atom_needs_quoting([H | T]) when (H >= $a andalso H =< $z);
(H >= $A andalso H =< $Z);
(H >= $0 andalso H =< $9);
H == $@; H == $_ ->
atom_needs_quoting(T);
atom_needs_quoting(_) ->
true.
-spec prepare_options(options(), #print_options{}) -> #print_options{}.
prepare_options([], Options) ->
Options;
prepare_options([{depth, Depth} | T], Options) when is_integer(Depth) ->
prepare_options(T, Options#print_options{depth = Depth});
prepare_options([{lists_as_strings, Bool} | T], Options) when is_boolean(Bool) ->
prepare_options(T, Options#print_options{lists_as_strings = Bool});
prepare_options([{force_strings, Bool} | T], Options) when is_boolean(Bool) ->
prepare_options(T, Options#print_options{force_strings = Bool}).
dec_depth(#print_options{depth = Depth} = Options) when Depth > 0 ->
Options#print_options{depth = Depth - 1};
dec_depth(Options) ->
Options.
escape($\t) -> "\\t";
escape($\n) -> "\\n";
escape($\r) -> "\\r";
escape($\e) -> "\\e";
escape($\f) -> "\\f";
escape($\b) -> "\\b";
escape($\v) -> "\\v".
record_fields([], _, _) ->
{"", 0};
record_fields(_, Max, #print_options{depth = D}) when Max < 4; D == 0 ->
{"...", 3};
record_fields([{Field, Value} | T], Max, Options) ->
{ExtraChars, Terminator} = case T of
[] ->
{1, []};
_ ->
{2, ","}
end,
{FieldStr, FieldLen} = print(Field, Max - ExtraChars, Options),
{ValueStr, ValueLen} = print(Value, Max - (FieldLen + ExtraChars), Options),
{Final, FLen} = record_fields(T, Max - (FieldLen + ValueLen + ExtraChars), dec_depth(Options)),
{[FieldStr ++ "=" ++ ValueStr ++ Terminator | Final], FLen + FieldLen + ValueLen + ExtraChars}.
-ifdef(TEST).
%%--------------------
%% The start of a test suite. So far, it only checks for not crashing.
-spec test() -> ok.
test() ->
test(trunc_io, print).
-spec test(atom(), atom()) -> ok.
test(Mod, Func) ->
Simple_items = [atom, 1234, 1234.0, {tuple}, [], [list], "string", self(),
<<1, 2, 3>>, make_ref(), fun() -> ok end],
F = fun(A) ->
Mod:Func(A, 100),
Mod:Func(A, 2),
Mod:Func(A, 20)
end,
G = fun(A) ->
case catch F(A) of
{'EXIT', _} -> exit({failed, A});
_ -> ok
end
end,
lists:foreach(G, Simple_items),
Tuples = [{1, 2, 3, a, b, c}, {"abc", def, 1234},
{{{{a}, b, c, {d}, e}}, f}],
Lists = [[1, 2, 3, 4, 5, 6, 7], lists:seq(1, 1000),
[{a}, {a, b}, {a, [b, c]}, "def"], [a | b], [$a | $b]],
lists:foreach(G, Tuples),
lists:foreach(G, Lists).
-spec perf() -> ok.
perf() ->
{New, _} = timer:tc(trunc_io, perf, [trunc_io, print, 1000]),
{Old, _} = timer:tc(trunc_io, perf, [io_lib, write, 1000]),
io:fwrite("New code took ~p us, old code ~p\n", [New, Old]).
-spec perf(atom(), atom(), integer()) -> done.
perf(M, F, Reps) when Reps > 0 ->
test(M, F),
perf(M, F, Reps - 1);
perf(_, _, _) ->
done.
%% Performance test. Needs a particularly large term I saved as a binary...
-spec perf1() -> {non_neg_integer(), non_neg_integer()}.
perf1() ->
{ok, Bin} = file:read_file("bin"),
A = binary_to_term(Bin),
{N, _} = timer:tc(trunc_io, print, [A, 1500]),
{M, _} = timer:tc(io_lib, write, [A]),
{N, M}.
format_test() ->
%% simple format strings
?assertEqual("foobar", lists:flatten(format("~s", [["foo", $b, $a, $r]], 50))),
?assertEqual("[\"foo\",98,97,114]", lists:flatten(format("~p", [["foo", $b, $a, $r]], 50))),
?assertEqual("[\"foo\",98,97,114]", lists:flatten(format("~P", [["foo", $b, $a, $r], 10], 50))),
?assertEqual("[[102,111,111],98,97,114]", lists:flatten(format("~w", [["foo", $b, $a, $r]], 50))),
%% complex ones
?assertEqual(" foobar", lists:flatten(format("~10s", [["foo", $b, $a, $r]], 50))),
?assertEqual("f", lists:flatten(format("~1s", [["foo", $b, $a, $r]], 50))),
?assertEqual("[\"foo\",98,97,114]", lists:flatten(format("~22p", [["foo", $b, $a, $r]], 50))),
?assertEqual("[\"foo\",98,97,114]", lists:flatten(format("~22P", [["foo", $b, $a, $r], 10], 50))),
?assertEqual("**********", lists:flatten(format("~10W", [["foo", $b, $a, $r], 10], 50))),
?assertEqual("[[102,111,111],98,97,114]", lists:flatten(format("~25W", [["foo", $b, $a, $r], 10], 50))),
% Note these next two diverge from io_lib:format; the field width is
% ignored, when it should be used as max line length.
?assertEqual("[\"foo\",98,97,114]", lists:flatten(format("~10p", [["foo", $b, $a, $r]], 50))),
?assertEqual("[\"foo\",98,97,114]", lists:flatten(format("~10P", [["foo", $b, $a, $r], 10], 50))),
ok.
atom_quoting_test() ->
?assertEqual("hello", lists:flatten(format("~p", [hello], 50))),
?assertEqual("'hello world'", lists:flatten(format("~p", ['hello world'], 50))),
?assertEqual("'Hello world'", lists:flatten(format("~p", ['Hello world'], 50))),
?assertEqual("hello_world", lists:flatten(format("~p", ['hello_world'], 50))),
?assertEqual("'node@127.0.0.1'", lists:flatten(format("~p", ['node@127.0.0.1'], 50))),
?assertEqual("node@nohost", lists:flatten(format("~p", [node@nohost], 50))),
?assertEqual("abc123", lists:flatten(format("~p", [abc123], 50))),
ok.
sane_float_printing_test() ->
?assertEqual("1.0", lists:flatten(format("~p", [1.0], 50))),
?assertEqual("1.23456789", lists:flatten(format("~p", [1.23456789], 50))),
?assertEqual("1.23456789", lists:flatten(format("~p", [1.234567890], 50))),
?assertEqual("0.3333333333333333", lists:flatten(format("~p", [1 / 3], 50))),
?assertEqual("0.1234567", lists:flatten(format("~p", [0.1234567], 50))),
ok.
float_inside_list_test() ->
?assertEqual("[97,38.233913133184835,99]", lists:flatten(format("~p", [[$a, 38.233913133184835, $c]], 50))),
?assertError(badarg, lists:flatten(format("~s", [[$a, 38.233913133184835, $c]], 50))),
ok.
quote_strip_test() ->
?assertEqual("\"hello\"", lists:flatten(format("~p", ["hello"], 50))),
?assertEqual("hello", lists:flatten(format("~s", ["hello"], 50))),
?assertEqual("hello", lists:flatten(format("~s", [hello], 50))),
?assertEqual("hello", lists:flatten(format("~p", [hello], 50))),
?assertEqual("'hello world'", lists:flatten(format("~p", ['hello world'], 50))),
?assertEqual("hello world", lists:flatten(format("~s", ['hello world'], 50))),
ok.
binary_printing_test() ->
?assertEqual("<<>>", lists:flatten(format("~p", [<<>>], 50))),
?assertEqual("", lists:flatten(format("~s", [<<>>], 50))),
?assertEqual("<<..>>", lists:flatten(format("~p", [<<"hi">>], 0))),
?assertEqual("<<...>>", lists:flatten(format("~p", [<<"hi">>], 1))),
?assertEqual("<<\"hello\">>", lists:flatten(format("~p", [<<$h, $e, $l, $l, $o>>], 50))),
?assertEqual("<<\"hello\">>", lists:flatten(format("~p", [<<"hello">>], 50))),
?assertEqual("<<104,101,108,108,111>>", lists:flatten(format("~w", [<<"hello">>], 50))),
?assertEqual("<<1,2,3,4>>", lists:flatten(format("~p", [<<1, 2, 3, 4>>], 50))),
?assertEqual([1, 2, 3, 4], lists:flatten(format("~s", [<<1, 2, 3, 4>>], 50))),
?assertEqual("hello", lists:flatten(format("~s", [<<"hello">>], 50))),
?assertEqual("hello\nworld", lists:flatten(format("~s", [<<"hello\nworld">>], 50))),
?assertEqual("<<\"hello\\nworld\">>", lists:flatten(format("~p", [<<"hello\nworld">>], 50))),
?assertEqual("<<\"\\\"hello world\\\"\">>", lists:flatten(format("~p", [<<"\"hello world\"">>], 50))),
?assertEqual("<<\"hello\\\\world\">>", lists:flatten(format("~p", [<<"hello\\world">>], 50))),
?assertEqual("<<\"hello\\\\\world\">>", lists:flatten(format("~p", [<<"hello\\\world">>], 50))),
?assertEqual("<<\"hello\\\\\\\\world\">>", lists:flatten(format("~p", [<<"hello\\\\world">>], 50))),
?assertEqual("<<\"hello\\bworld\">>", lists:flatten(format("~p", [<<"hello\bworld">>], 50))),
?assertEqual("<<\"hello\\tworld\">>", lists:flatten(format("~p", [<<"hello\tworld">>], 50))),
?assertEqual("<<\"hello\\nworld\">>", lists:flatten(format("~p", [<<"hello\nworld">>], 50))),
?assertEqual("<<\"hello\\rworld\">>", lists:flatten(format("~p", [<<"hello\rworld">>], 50))),
?assertEqual("<<\"hello\\eworld\">>", lists:flatten(format("~p", [<<"hello\eworld">>], 50))),
?assertEqual("<<\"hello\\fworld\">>", lists:flatten(format("~p", [<<"hello\fworld">>], 50))),
?assertEqual("<<\"hello\\vworld\">>", lists:flatten(format("~p", [<<"hello\vworld">>], 50))),
?assertEqual(" hello", lists:flatten(format("~10s", [<<"hello">>], 50))),
?assertEqual("[a]", lists:flatten(format("~s", [<<"[a]">>], 50))),
?assertEqual("[a]", lists:flatten(format("~s", [[<<"[a]">>]], 50))),
ok.
bitstring_printing_test() ->
?assertEqual("<<1,2,3,1:7>>", lists:flatten(format("~p",
[<<1, 2, 3, 1:7>>], 100))),
?assertEqual("<<1:7>>", lists:flatten(format("~p",
[<<1:7>>], 100))),
?assertEqual("<<1,2,3,...>>", lists:flatten(format("~p",
[<<1, 2, 3, 1:7>>], 12))),
?assertEqual("<<1,2,3,...>>", lists:flatten(format("~p",
[<<1, 2, 3, 1:7>>], 13))),
?assertEqual("<<1,2,3,1:7>>", lists:flatten(format("~p",
[<<1, 2, 3, 1:7>>], 14))),
?assertEqual("<<..>>", lists:flatten(format("~p", [<<1:7>>], 0))),
?assertEqual("<<...>>", lists:flatten(format("~p", [<<1:7>>], 1))),
?assertEqual("[<<1>>,<<2>>]", lists:flatten(format("~p", [[<<1>>, <<2>>]],
100))),
?assertEqual("{<<1:7>>}", lists:flatten(format("~p", [{<<1:7>>}], 50))),
ok.
list_printing_test() ->
?assertEqual("[]", lists:flatten(format("~p", [[]], 50))),
?assertEqual("[]", lists:flatten(format("~w", [[]], 50))),
?assertEqual("", lists:flatten(format("~s", [[]], 50))),
?assertEqual("...", lists:flatten(format("~s", [[]], -1))),
?assertEqual("[[]]", lists:flatten(format("~p", [[[]]], 50))),
?assertEqual("[13,11,10,8,5,4]", lists:flatten(format("~p", [[13, 11, 10, 8, 5, 4]], 50))),
?assertEqual("\"\\rabc\"", lists:flatten(format("~p", [[13, $a, $b, $c]], 50))),
?assertEqual("[1,2,3|4]", lists:flatten(format("~p", [[1, 2, 3 | 4]], 50))),
?assertEqual("[...]", lists:flatten(format("~p", [[1, 2, 3, 4]], 4))),
?assertEqual("[1,...]", lists:flatten(format("~p", [[1, 2, 3, 4]], 6))),
?assertEqual("[1,...]", lists:flatten(format("~p", [[1, 2, 3, 4]], 7))),
?assertEqual("[1,2,...]", lists:flatten(format("~p", [[1, 2, 3, 4]], 8))),
?assertEqual("[1|4]", lists:flatten(format("~p", [[1 | 4]], 50))),
?assertEqual("[1]", lists:flatten(format("~p", [[1]], 50))),
?assertError(badarg, lists:flatten(format("~s", [[1 | 4]], 50))),
?assertEqual("\"hello...\"", lists:flatten(format("~p", ["hello world"], 10))),
?assertEqual("hello w...", lists:flatten(format("~s", ["hello world"], 10))),
?assertEqual("hello world\r\n", lists:flatten(format("~s", ["hello world\r\n"], 50))),
?assertEqual("\rhello world\r\n", lists:flatten(format("~s", ["\rhello world\r\n"], 50))),
?assertEqual("\"\\rhello world\\r\\n\"", lists:flatten(format("~p", ["\rhello world\r\n"], 50))),
?assertEqual("[13,104,101,108,108,111,32,119,111,114,108,100,13,10]", lists:flatten(format("~w", ["\rhello world\r\n"], 60))),
?assertEqual("...", lists:flatten(format("~s", ["\rhello world\r\n"], 3))),
?assertEqual("[22835963083295358096932575511191922182123945984,...]",
lists:flatten(format("~p", [
[22835963083295358096932575511191922182123945984,
22835963083295358096932575511191922182123945984]], 9))),
?assertEqual("[22835963083295358096932575511191922182123945984,...]",
lists:flatten(format("~p", [
[22835963083295358096932575511191922182123945984,
22835963083295358096932575511191922182123945984]], 53))),
%%improper list
?assertEqual("[1,2,3|4]", lists:flatten(format("~P", [[1 | [2 | [3 | 4]]], 5], 50))),
?assertEqual("[1|1]", lists:flatten(format("~P", [[1 | 1], 5], 50))),
?assertEqual("[9|9]", lists:flatten(format("~p", [[9 | 9]], 50))),
ok.
iolist_printing_test() ->
?assertEqual("iolist: HelloIamaniolist",
lists:flatten(format("iolist: ~s", [[$H, $e, $l, $l, $o, "I", ["am", [<<"an">>], [$i, $o, $l, $i, $s, $t]]]], 1000))),
?assertEqual("123...",
lists:flatten(format("~s", [[<<"123456789">>, "HellIamaniolist"]], 6))),
?assertEqual("123456...",
lists:flatten(format("~s", [[<<"123456789">>, "HellIamaniolist"]], 9))),
?assertEqual("123456789H...",
lists:flatten(format("~s", [[<<"123456789">>, "HellIamaniolist"]], 13))),
?assertEqual("123456789HellIamaniolist",
lists:flatten(format("~s", [[<<"123456789">>, "HellIamaniolist"]], 30))),
ok.
tuple_printing_test() ->
?assertEqual("{}", lists:flatten(format("~p", [{}], 50))),
?assertEqual("{}", lists:flatten(format("~w", [{}], 50))),
?assertError(badarg, lists:flatten(format("~s", [{}], 50))),
?assertEqual("{...}", lists:flatten(format("~p", [{foo}], 1))),
?assertEqual("{...}", lists:flatten(format("~p", [{foo}], 2))),
?assertEqual("{...}", lists:flatten(format("~p", [{foo}], 3))),
?assertEqual("{...}", lists:flatten(format("~p", [{foo}], 4))),
?assertEqual("{...}", lists:flatten(format("~p", [{foo}], 5))),
?assertEqual("{foo,...}", lists:flatten(format("~p", [{foo, bar}], 6))),
?assertEqual("{foo,...}", lists:flatten(format("~p", [{foo, bar}], 7))),
?assertEqual("{foo,...}", lists:flatten(format("~p", [{foo, bar}], 9))),
?assertEqual("{foo,bar}", lists:flatten(format("~p", [{foo, bar}], 10))),
?assertEqual("{22835963083295358096932575511191922182123945984,...}",
lists:flatten(format("~w", [
{22835963083295358096932575511191922182123945984,
22835963083295358096932575511191922182123945984}], 10))),
?assertEqual("{22835963083295358096932575511191922182123945984,...}",
lists:flatten(format("~w", [
{22835963083295358096932575511191922182123945984,
bar}], 10))),
?assertEqual("{22835963083295358096932575511191922182123945984,...}",
lists:flatten(format("~w", [
{22835963083295358096932575511191922182123945984,
22835963083295358096932575511191922182123945984}], 53))),
ok.
map_printing_test() ->
?assertEqual("#{}", lists:flatten(format("~p", [maps:new()], 50))),
?assertEqual("#{}", lists:flatten(format("~p", [maps:new()], 3))),
?assertEqual("#{}", lists:flatten(format("~w", [maps:new()], 50))),
?assertError(badarg, lists:flatten(format("~s", [maps:new()], 50))),
?assertEqual("#{...}", lists:flatten(format("~p", [maps:from_list([{bar, foo}])], 1))),
?assertEqual("#{...}", lists:flatten(format("~p", [maps:from_list([{bar, foo}])], 6))),
?assertEqual("#{bar => ...}", lists:flatten(format("~p", [maps:from_list([{bar, foo}])], 7))),
?assertEqual("#{bar => ...}", lists:flatten(format("~p", [maps:from_list([{bar, foo}])], 9))),
?assertEqual("#{bar => foo}", lists:flatten(format("~p", [maps:from_list([{bar, foo}])], 10))),
?assertEqual("#{bar => ...,...}", lists:flatten(format("~p", [maps:from_list([{bar, foo}, {foo, bar}])], 9))),
?assertEqual("#{bar => foo,...}", lists:flatten(format("~p", [maps:from_list([{bar, foo}, {foo, bar}])], 10))),
?assertEqual("#{bar => foo,...}", lists:flatten(format("~p", [maps:from_list([{bar, foo}, {foo, bar}])], 17))),
?assertEqual("#{bar => foo,foo => ...}", lists:flatten(format("~p", [maps:from_list([{bar, foo}, {foo, bar}])], 18))),
?assertEqual("#{bar => foo,foo => ...}", lists:flatten(format("~p", [maps:from_list([{bar, foo}, {foo, bar}])], 19))),
?assertEqual("#{bar => foo,foo => ...}", lists:flatten(format("~p", [maps:from_list([{bar, foo}, {foo, bar}])], 20))),
?assertEqual("#{bar => foo,foo => bar}", lists:flatten(format("~p", [maps:from_list([{bar, foo}, {foo, bar}])], 21))),
?assertEqual("#{22835963083295358096932575511191922182123945984 => ...}",
lists:flatten(format("~w", [
maps:from_list([{22835963083295358096932575511191922182123945984,
22835963083295358096932575511191922182123945984}])], 10))),
?assertEqual("#{22835963083295358096932575511191922182123945984 => ...}",
lists:flatten(format("~w", [
maps:from_list([{22835963083295358096932575511191922182123945984,
bar}])], 10))),
?assertEqual("#{22835963083295358096932575511191922182123945984 => ...}",
lists:flatten(format("~w", [
maps:from_list([{22835963083295358096932575511191922182123945984,
bar}])], 53))),
?assertEqual("#{22835963083295358096932575511191922182123945984 => bar}",
lists:flatten(format("~w", [
maps:from_list([{22835963083295358096932575511191922182123945984,
bar}])], 54))),
ok.
unicode_test() ->
?assertEqual([231, 167, 129], lists:flatten(format("~s", [<<231, 167, 129>>], 50))),
?assertEqual([31169], lists:flatten(format("~ts", [<<231, 167, 129>>], 50))),
ok.
depth_limit_test() ->
?assertEqual("{...}", lists:flatten(format("~P", [{a, [b, [c, [d]]]}, 1], 50))),
?assertEqual("{a,...}", lists:flatten(format("~P", [{a, [b, [c, [d]]]}, 2], 50))),
?assertEqual("{a,[...]}", lists:flatten(format("~P", [{a, [b, [c, [d]]]}, 3], 50))),
?assertEqual("{a,[b|...]}", lists:flatten(format("~P", [{a, [b, [c, [d]]]}, 4], 50))),
?assertEqual("{a,[b,[...]]}", lists:flatten(format("~P", [{a, [b, [c, [d]]]}, 5], 50))),
?assertEqual("{a,[b,[c|...]]}", lists:flatten(format("~P", [{a, [b, [c, [d]]]}, 6], 50))),
?assertEqual("{a,[b,[c,[...]]]}", lists:flatten(format("~P", [{a, [b, [c, [d]]]}, 7], 50))),
?assertEqual("{a,[b,[c,[d]]]}", lists:flatten(format("~P", [{a, [b, [c, [d]]]}, 8], 50))),
?assertEqual("{a,[b,[c,[d]]]}", lists:flatten(format("~P", [{a, [b, [c, [d]]]}, 9], 50))),
?assertEqual("{a,{...}}", lists:flatten(format("~P", [{a, {b, {c, {d}}}}, 3], 50))),
?assertEqual("{a,{b,...}}", lists:flatten(format("~P", [{a, {b, {c, {d}}}}, 4], 50))),
?assertEqual("{a,{b,{...}}}", lists:flatten(format("~P", [{a, {b, {c, {d}}}}, 5], 50))),
?assertEqual("{a,{b,{c,...}}}", lists:flatten(format("~P", [{a, {b, {c, {d}}}}, 6], 50))),
?assertEqual("{a,{b,{c,{...}}}}", lists:flatten(format("~P", [{a, {b, {c, {d}}}}, 7], 50))),
?assertEqual("{a,{b,{c,{d}}}}", lists:flatten(format("~P", [{a, {b, {c, {d}}}}, 8], 50))),
?assertEqual("#{a => #{...}}",
lists:flatten(format("~P",
[maps:from_list([{a, maps:from_list([{b, maps:from_list([{c, d}])}])}]), 2], 50))),
?assertEqual("#{a => #{b => #{...}}}",
lists:flatten(format("~P",
[maps:from_list([{a, maps:from_list([{b, maps:from_list([{c, d}])}])}]), 3], 50))),
?assertEqual("#{a => #{b => #{c => d}}}",
lists:flatten(format("~P",
[maps:from_list([{a, maps:from_list([{b, maps:from_list([{c, d}])}])}]), 4], 50))),
?assertEqual("#{}", lists:flatten(format("~P", [maps:new(), 1], 50))),
?assertEqual("#{...}", lists:flatten(format("~P", [maps:from_list([{1, 1}, {2, 2}, {3, 3}]), 1], 50))),
?assertEqual("#{1 => 1,...}", lists:flatten(format("~P", [maps:from_list([{1, 1}, {2, 2}, {3, 3}]), 2], 50))),
?assertEqual("#{1 => 1,2 => 2,...}", lists:flatten(format("~P", [maps:from_list([{1, 1}, {2, 2}, {3, 3}]), 3], 50))),
?assertEqual("#{1 => 1,2 => 2,3 => 3}", lists:flatten(format("~P", [maps:from_list([{1, 1}, {2, 2}, {3, 3}]), 4], 50))),
?assertEqual("{\"a\",[...]}", lists:flatten(format("~P", [{"a", ["b", ["c", ["d"]]]}, 3], 50))),
?assertEqual("{\"a\",[\"b\",[[...]|...]]}", lists:flatten(format("~P", [{"a", ["b", ["c", ["d"]]]}, 6], 50))),
?assertEqual("{\"a\",[\"b\",[\"c\",[\"d\"]]]}", lists:flatten(format("~P", [{"a", ["b", ["c", ["d"]]]}, 9], 50))),
?assertEqual("[...]", lists:flatten(format("~P", [[1, 2, 3], 1], 50))),
?assertEqual("[1|...]", lists:flatten(format("~P", [[1, 2, 3], 2], 50))),
?assertEqual("[1,2|...]", lists:flatten(format("~P", [[1, 2, 3], 3], 50))),
?assertEqual("[1,2,3]", lists:flatten(format("~P", [[1, 2, 3], 4], 50))),
?assertEqual("{1,...}", lists:flatten(format("~P", [{1, 2, 3}, 2], 50))),
?assertEqual("{1,2,...}", lists:flatten(format("~P", [{1, 2, 3}, 3], 50))),
?assertEqual("{1,2,3}", lists:flatten(format("~P", [{1, 2, 3}, 4], 50))),
?assertEqual("{1,...}", lists:flatten(format("~P", [{1, 2, 3}, 2], 50))),
?assertEqual("[1,2|...]", lists:flatten(format("~P", [[1, 2, <<3>>], 3], 50))),
?assertEqual("[1,2,<<...>>]", lists:flatten(format("~P", [[1, 2, <<3>>], 4], 50))),
?assertEqual("[1,2,<<3>>]", lists:flatten(format("~P", [[1, 2, <<3>>], 5], 50))),
?assertEqual("<<...>>", lists:flatten(format("~P", [<<0, 0, 0, 0>>, 1], 50))),
?assertEqual("<<0,...>>", lists:flatten(format("~P", [<<0, 0, 0, 0>>, 2], 50))),
?assertEqual("<<0,0,...>>", lists:flatten(format("~P", [<<0, 0, 0, 0>>, 3], 50))),
?assertEqual("<<0,0,0,...>>", lists:flatten(format("~P", [<<0, 0, 0, 0>>, 4], 50))),
?assertEqual("<<0,0,0,0>>", lists:flatten(format("~P", [<<0, 0, 0, 0>>, 5], 50))),
%% this is a seriously weird edge case
?assertEqual("<<\" \"...>>", lists:flatten(format("~P", [<<32, 32, 32, 0>>, 2], 50))),
?assertEqual("<<\" \"...>>", lists:flatten(format("~P", [<<32, 32, 32, 0>>, 3], 50))),
?assertEqual("<<\" \"...>>", lists:flatten(format("~P", [<<32, 32, 32, 0>>, 4], 50))),
?assertEqual("<<32,32,32,0>>", lists:flatten(format("~P", [<<32, 32, 32, 0>>, 5], 50))),
?assertEqual("<<32,32,32,0>>", lists:flatten(format("~p", [<<32, 32, 32, 0>>], 50))),
%% depth limiting for some reason works in 4 byte chunks on printable binaries?
?assertEqual("<<\"hell\"...>>", lists:flatten(format("~P", [<<"hello world">>, 2], 50))),
?assertEqual("<<\"abcd\"...>>", lists:flatten(format("~P", [<<$a, $b, $c, $d, $e, 0>>, 2], 50))),
%% I don't even know...
?assertEqual("<<>>", lists:flatten(format("~P", [<<>>, 1], 50))),
?assertEqual("<<>>", lists:flatten(format("~W", [<<>>, 1], 50))),
?assertEqual("{abc,<<\"abc\\\"\">>}", lists:flatten(format("~P", [{abc, <<"abc\"">>}, 4], 50))),
ok.
print_terms_without_format_string_test() ->
?assertError(badarg, format({hello, world}, [], 50)),
?assertError(badarg, format([{google, bomb}], [], 50)),
?assertEqual([$h, $e, $l, $l, $o, 3594], format([$h, $e, $l, $l, $o, 3594], [], 50)),
?assertError(badarg, format([$h, $e, $l, $l, $o, 65535], [], 50)),
?assertEqual("helloworld", lists:flatten(format([$h, $e, $l, $l, $o, "world"], [], 50))),
?assertEqual("hello", lists:flatten(format(<<"hello">>, [], 50))),
?assertEqual("hello", lists:flatten(format('hello', [], 50))),
?assertError(badarg, format(<<1, 2, 3, 1:7>>, [], 100)),
?assertError(badarg, format(65535, [], 50)),
ok.
improper_io_list_test() ->
?assertEqual(">hello", lists:flatten(format('~s', [[$> | <<"hello">>]], 50))),
?assertEqual(">hello", lists:flatten(format('~ts', [[$> | <<"hello">>]], 50))),
?assertEqual("helloworld", lists:flatten(format('~ts', [[<<"hello">> | <<"world">>]], 50))),
ok.
-endif.

+ 1
- 1
src/utils/rumUtil.erl 查看文件

@ -526,7 +526,7 @@ checkHwm(Shaper = #rumShaper{filter = Filter}, Event) ->
end. end.
%% S i.e. %% S i.e.
checkHwm(#rumShaper{id = Id, hwm = Hwm, mps = Mps, lastTime = LastTime, dropped = Drop, flushQueue = FlushQueue, flushThreshold = FlushThreshold, timer = Timer, filter = Filter} = Shaper) ->
checkHwm(#rumShaper{id = Id, hwm = Hwm, mps = Mps, lastTime = LastTime, dropped = Drop, flushQueue = FlushQueue, flushThr = FlushThreshold, timer = Timer, filter = Filter} = Shaper) ->
if if
Hwm == undefined -> Hwm == undefined ->
{true, 0, Shaper}; {true, 0, Shaper};

正在加载...
取消
保存