浏览代码

ft: 代码整理

master
SisMaker 4 年前
父节点
当前提交
e22b0c44c3
共有 35 个文件被更改,包括 65 次插入5694 次删除
  1. +5
    -5
      include/eRum.hrl
  2. +2
    -0
      include/rumCom.hrl
  3. +0
    -11
      include/rumDef.hrl
  4. +30
    -0
      include/rumMsg.hrl
  5. +0
    -378
      src/backend/rumBkdConsole.erl
  6. +0
    -719
      src/backend/rumBkdFile.erl
  7. +0
    -148
      src/crashLog/rumCrashLog.erl
  8. +21
    -52
      src/eRum.erl
  9. +1
    -0
      src/eRum_app.erl
  10. +3
    -171
      src/errLogger/rumErrLoggerH.erl
  11. +0
    -308
      src/formatter/rumFormatter.erl
  12. +0
    -91
      src/rotator/rumRotatorIns.erl
  13. +1
    -0
      src/utils/rumConfig.erl
  14. +1
    -11
      src/utils/rumMsg.erl
  15. +1
    -347
      src/utils/rumUtil.erl
  16. +0
    -101
      src/watcher/rumHWatcherSrv.erl
  17. +0
    -22
      test/compress_pr_record_test.erl
  18. +0
    -109
      test/crash.erl
  19. +0
    -35
      test/crash_fsm.erl
  20. +0
    -46
      test/crash_statem.erl
  21. +0
    -15
      test/lager_app_tests.erl
  22. +0
    -68
      test/lager_crash_backend.erl
  23. +0
    -125
      test/lager_manager_killer_test.erl
  24. +0
    -24
      test/lager_metadata_whitelist_test.erl
  25. +0
    -185
      test/lager_rotate.erl
  26. +0
    -34
      test/lager_slow_backend.erl
  27. +0
    -1927
      test/lager_test_backend.erl
  28. +0
    -193
      test/lager_test_function_transform.erl
  29. +0
    -55
      test/lager_trace_test.erl
  30. +0
    -47
      test/pr_composite_test.erl
  31. +0
    -63
      test/pr_stacktrace_test.erl
  32. +0
    -36
      test/special_process.erl
  33. +0
    -89
      test/sync_error_logger.erl
  34. +0
    -244
      test/trunc_io_eqc.erl
  35. +0
    -35
      test/zzzz_gh280_crash.erl

+ 5
- 5
include/eRum.hrl 查看文件

@ -1,6 +1,7 @@
-include("rumCom.hrl").
%% %%
%% Level, Pid, Node, Module, Function, FunctionArity, File, Line, Other %% Level, Pid, Node, Module, Function, FunctionArity, File, Line, Other
-define(RumDefSink, rumEvent).
%% %%
-define(RumMetadata(Extras), [ -define(RumMetadata(Extras), [
@ -15,14 +16,13 @@
]). ]).
-define(rumLog(Severity, Format, Args, Safety), -define(rumLog(Severity, Format, Args, Safety),
?rumLog(?RumDefSink, Severity, self(), node(), ?MODULE, ?FUNCTION_NAME, ?RumMetadata(eRum:md()), Format, Args, ?RumDefTruncation, Safety)).
?rumLog(?RumDefSink, Severity, self(), node(), ?MODULE, ?FUNCTION_NAME, ?FILE, ?LINE, eRum:md(), Format, Args, ?RumDefTruncation, Safety)).
-define(rumLog(Severity, Metadata, Format, Args, Safety), -define(rumLog(Severity, Metadata, Format, Args, Safety),
?rumLog(?RumDefSink, Severity, ?RumMetadata(Metadata ++ eRum:md()), Format, Args, ?RumDefTruncation, Safety)).
?rumLog(?RumDefSink, Severity, self(), node(), ?MODULE, ?FUNCTION_NAME, ?FILE, ?LINE, Metadata ++ eRum:md(), Format, Args, ?RumDefTruncation, Safety)).
-define(rumLog(Sink, Severity, Metadata, Format, Args, Size, Safety), -define(rumLog(Sink, Severity, Metadata, Format, Args, Size, Safety),
eRum:dispatch_log(Sink, Severity, Metadata, Format, Args, Size, Safety)).
eRum:dispatch_log(Sink, Severity, Pid, Node, Module, Function, File, Line, Metadata, Format, Args, Size, Safety)).
-define(rumNone(Format, Args), ?rumLog(none, Format, Args, safe)). -define(rumNone(Format, Args), ?rumLog(none, Format, Args, safe)).
-define(rumNone(Metadata, Format, Args), ?rumLog(none, Metadata, Format, Args, safe)). -define(rumNone(Metadata, Format, Args), ?rumLog(none, Metadata, Format, Args, safe)).

+ 2
- 0
include/rumCom.hrl 查看文件

@ -0,0 +1,2 @@
-define(RumDefSink, rumEvent).
-define(RumDefTruncation, 4096).

+ 0
- 11
include/rumDef.hrl 查看文件

@ -18,8 +18,6 @@
-define(RumRotateTimeout, 100000). -define(RumRotateTimeout, 100000).
%% %%
-define(RumDefSink, rumEvent).
-define(RumDefTruncation, 4096).
-define(RumDefTracer, lager_default_tracer). -define(RumDefTracer, lager_default_tracer).
-define(RumErrLogSink, error_logger_lager_event). -define(RumErrLogSink, error_logger_lager_event).
@ -94,15 +92,6 @@
, filter = fun(_) -> false end :: fun() , filter = fun(_) -> false end :: fun()
}). }).
-record(rumMsg, {
destinations :: list(),
metadata :: [tuple()],
severity :: rumAtomLevel(),
datetime :: binary(),
timestamp :: non_neg_integer(),
message :: list()
}).
-type rumShaper() :: #rumShaper{}. -type rumShaper() :: #rumShaper{}.
-type rumAtomLevel() :: none | debug | info | notice | warning | error | critical | alert | emergency. -type rumAtomLevel() :: none | debug | info | notice | warning | error | critical | alert | emergency.

+ 30
- 0
include/rumMsg.hrl 查看文件

@ -0,0 +1,30 @@
-record(rumMsg, {
severity :: rumAtomLevel()
, pid
, node
, module
, function
, file
, line
, metadata :: [tuple()]
, datetime :: binary()
, timestamp :: non_neg_integer()
, message :: list()
, destinations :: list()
}).
-define(newMsg(Severity, Pid, Node, Module, Function, File, Line, Metadata, Destinations, TimeMs, Msg),
#rumMsg{
severity = Severity
, pid =Pid
, node = Node
, module = Module
, function = Function
, file =File
, line =Line
, metadata =Metadata
, datetime = rumUtil:msToBinStr(TimeMs)
, timestamp = TimeMs
, message = Msg
, destinations = Destinations
}).

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

@ -9,11 +9,6 @@
-include("rumDef.hrl"). -include("rumDef.hrl").
-ifdef(TEST).
-include_lib("eunit/include/eunit.hrl").
-compile([{parse_transform, rumTransform}]).
-endif.
-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, rumFormatter}, {formatter_config, ?RumDefConsoleFmtCfg}]).
@ -131,376 +126,3 @@ isNewStyleConsole() ->
%% 'user_drv' is a registered proc name used by the "new" %% 'user_drv' is a registered proc name used by the "new"
%% console driver. %% console driver.
init:get_argument(noshell) /= error orelse element(1, os:type()) /= win32 orelse is_pid(whereis(user_drv)). init:get_argument(noshell) /= error orelse element(1, os:type()) /= win32 orelse is_pid(whereis(user_drv)).
-ifdef(TEST).
console_config_validation_test_() ->
Good = [{level, info}, {use_stderr, true}],
Bad1 = [{level, foo}, {use_stderr, flase}],
Bad2 = [{level, info}, {use_stderr, flase}],
AllGood = [{level, info}, {formatter, my_formatter},
{formatter_config, ["blort", "garbage"]},
{use_stderr, false}],
[
?_assertEqual(true, checkOpts(Good)),
?_assertThrow({error, {fatal, {bad_level, foo}}}, checkOpts(Bad1)),
?_assertThrow({error, {fatal, {bad_console_config, {use_stderr, flase}}}}, checkOpts(Bad2)),
?_assertEqual(true, checkOpts(AllGood))
].
console_log_test_() ->
%% tiny recursive fun that pretends to be a group leader
F = fun(Self) ->
fun() ->
YComb = fun(Fun) ->
receive
{io_request, From, ReplyAs, {put_chars, unicode, _Msg}} = Y ->
From ! {io_reply, ReplyAs, ok},
Self ! Y,
Fun(Fun);
Other ->
?debugFmt("unexpected message ~p~n", [Other]),
Self ! Other
end
end,
YComb(YComb)
end
end,
{foreach,
fun() ->
error_logger:tty(false),
application:load(lager),
application:set_env(lager, handlers, []),
application:set_env(lager, errLoggerRedirect, false),
eRum:start(),
whereis(user)
end,
fun(User) ->
unregister(user),
register(user, User),
application:stop(lager),
application:stop(goldrush),
error_logger:tty(true)
end,
[
{"regular console logging",
fun() ->
Pid = spawn(F(self())),
unregister(user),
register(user, Pid),
erlang:group_leader(Pid, whereis(rumEvent)),
gen_event:add_handler(rumEvent, lager_console_backend, [{level, info}]),
rumConfig:set({rumEvent, loglevel}, {rumUtil:configToMask(info), []}),
eRum:log(info, self(), "Test message"),
receive
{io_request, From, ReplyAs, {put_chars, unicode, Msg}} ->
From ! {io_reply, ReplyAs, ok},
TestMsg = "Test message" ++ eol(),
?assertMatch([_, "[info]", TestMsg], re:split(Msg, " ", [{return, list}, {parts, 3}]))
after
500 ->
?assert(false)
end
end
},
{"verbose console logging",
fun() ->
Pid = spawn(F(self())),
unregister(user),
register(user, Pid),
erlang:group_leader(Pid, whereis(rumEvent)),
gen_event:add_handler(rumEvent, lager_console_backend, [info, true]),
rumConfig:set({rumEvent, loglevel}, {rumUtil:configToMask(info), []}),
eRum:info("Test message"),
PidStr = pid_to_list(self()),
receive
{io_request, _, _, {put_chars, unicode, Msg}} ->
TestMsg = "Test message" ++ eol(),
?assertMatch([_, _, "[info]", PidStr, _, TestMsg], re:split(Msg, "[ @]", [{return, list}, {parts, 6}]))
after
500 ->
?assert(false)
end
end
},
{"custom format console logging",
fun() ->
Pid = spawn(F(self())),
unregister(user),
register(user, Pid),
erlang:group_leader(Pid, whereis(rumEvent)),
gen_event:add_handler(rumEvent, lager_console_backend,
[{level, info}, {formatter, lager_default_formatter}, {formatter_config, [date, "#", time, "#", severity, "#", node, "#", pid, "#",
module, "#", function, "#", file, "#", line, "#", message, "\r\n"]}]),
rumConfig:set({rumEvent, loglevel}, {?INFO, []}),
eRum:info("Test message"),
PidStr = pid_to_list(self()),
NodeStr = atom_to_list(node()),
ModuleStr = atom_to_list(?MODULE),
receive
{io_request, _, _, {put_chars, unicode, Msg}} ->
TestMsg = "Test message" ++ eol(),
?assertMatch([_, _, "info", NodeStr, PidStr, ModuleStr, _, _, _, TestMsg],
re:split(Msg, "#", [{return, list}, {parts, 10}]))
after
500 ->
?assert(false)
end
end
},
{"tracing should work",
fun() ->
Pid = spawn(F(self())),
unregister(user),
register(user, Pid),
gen_event:add_handler(rumEvent, lager_console_backend, [{level, info}]),
erlang:group_leader(Pid, whereis(rumEvent)),
rumConfig:set({rumEvent, loglevel}, {rumUtil:configToMask(info), []}),
eRum:debug("Test message"),
receive
{io_request, From, ReplyAs, {put_chars, unicode, _Msg}} ->
From ! {io_reply, ReplyAs, ok},
?assert(false)
after
500 ->
?assert(true)
end,
{ok, _} = eRum:trace_console([{module, ?MODULE}]),
eRum:debug("Test message"),
receive
{io_request, From1, ReplyAs1, {put_chars, unicode, Msg1}} ->
From1 ! {io_reply, ReplyAs1, ok},
TestMsg = "Test message" ++ eol(),
?assertMatch([_, "[debug]", TestMsg], re:split(Msg1, " ", [{return, list}, {parts, 3}]))
after
500 ->
?assert(false)
end
end
},
{"tracing doesn't duplicate messages",
fun() ->
Pid = spawn(F(self())),
unregister(user),
register(user, Pid),
gen_event:add_handler(rumEvent, lager_console_backend, [{level, info}]),
rumConfig:set({rumEvent, loglevel}, {rumUtil:configToMask(info), []}),
erlang:group_leader(Pid, whereis(rumEvent)),
eRum:debug("Test message"),
receive
{io_request, From, ReplyAs, {put_chars, unicode, _Msg}} ->
From ! {io_reply, ReplyAs, ok},
?assert(false)
after
500 ->
?assert(true)
end,
{ok, _} = eRum:trace_console([{module, ?MODULE}]),
eRum:error("Test message"),
receive
{io_request, From1, ReplyAs1, {put_chars, unicode, Msg1}} ->
From1 ! {io_reply, ReplyAs1, ok},
TestMsg = "Test message" ++ eol(),
?assertMatch([_, "[error]", TestMsg], re:split(Msg1, " ", [{return, list}, {parts, 3}]))
after
1000 ->
?assert(false)
end,
%% make sure this event wasn't duplicated
receive
{io_request, From2, ReplyAs2, {put_chars, unicode, _Msg2}} ->
From2 ! {io_reply, ReplyAs2, ok},
?assert(false)
after
500 ->
?assert(true)
end
end
},
{"blacklisting a loglevel works",
fun() ->
Pid = spawn(F(self())),
unregister(user),
register(user, Pid),
gen_event:add_handler(rumEvent, lager_console_backend, [{level, info}]),
rumConfig:set({rumEvent, loglevel}, {rumUtil:configToMask(info), []}),
eRum:setLogLevel(lager_console_backend, '!=info'),
erlang:group_leader(Pid, whereis(rumEvent)),
eRum:debug("Test message"),
receive
{io_request, From1, ReplyAs1, {put_chars, unicode, Msg1}} ->
From1 ! {io_reply, ReplyAs1, ok},
TestMsg = "Test message" ++ eol(),
?assertMatch([_, "[debug]", TestMsg], re:split(Msg1, " ", [{return, list}, {parts, 3}]))
after
1000 ->
?assert(false)
end,
%% info is blacklisted
eRum:info("Test message"),
receive
{io_request, From2, ReplyAs2, {put_chars, unicode, _Msg2}} ->
From2 ! {io_reply, ReplyAs2, ok},
?assert(false)
after
500 ->
?assert(true)
end
end
},
{"whitelisting a loglevel works",
fun() ->
Pid = spawn(F(self())),
unregister(user),
register(user, Pid),
gen_event:add_handler(rumEvent, lager_console_backend, [{level, info}]),
rumConfig:set({rumEvent, loglevel}, {rumUtil:configToMask(info), []}),
eRum:setLogLevel(lager_console_backend, '=debug'),
erlang:group_leader(Pid, whereis(rumEvent)),
eRum:debug("Test message"),
receive
{io_request, From1, ReplyAs1, {put_chars, unicode, Msg1}} ->
From1 ! {io_reply, ReplyAs1, ok},
TestMsg = "Test message" ++ eol(),
?assertMatch([_, "[debug]", TestMsg], re:split(Msg1, " ", [{return, list}, {parts, 3}]))
after
1000 ->
?assert(false)
end,
%% info is blacklisted
eRum:error("Test message"),
receive
{io_request, From2, ReplyAs2, {put_chars, unicode, _Msg2}} ->
From2 ! {io_reply, ReplyAs2, ok},
?assert(false)
after
500 ->
?assert(true)
end
end
},
{"console backend with custom group leader",
fun() ->
Pid = spawn(F(self())),
gen_event:add_handler(rumEvent, lager_console_backend, [{level, info}, {group_leader, Pid}]),
rumConfig:set({rumEvent, loglevel}, {rumUtil:configToMask(info), []}),
eRum:info("Test message"),
?assertNotEqual({group_leader, Pid}, erlang:process_info(whereis(rumEvent), group_leader)),
receive
{io_request, From1, ReplyAs1, {put_chars, unicode, Msg1}} ->
From1 ! {io_reply, ReplyAs1, ok},
TestMsg = "Test message" ++ eol(),
?assertMatch([_, "[info]", TestMsg], re:split(Msg1, " ", [{return, list}, {parts, 3}]))
after
1000 ->
?assert(false)
end,
%% killing the pid should prevent any new log messages (to prove we haven't accidentally redirected
%% the group leader some other way
exit(Pid, kill),
timer:sleep(100),
%% additionally, check the lager backend has been removed (because the group leader process died)
?assertNot(lists:member(lager_console_backend, gen_event:which_handlers(rumEvent))),
eRum:error("Test message"),
receive
{io_request, From2, ReplyAs2, {put_chars, unicode, _Msg2}} ->
From2 ! {io_reply, ReplyAs2, ok},
?assert(false)
after
500 ->
?assert(true)
end
end
},
{"console backend with custom group leader using a trace and an ID",
fun() ->
Pid = spawn(F(self())),
ID = {?MODULE, trace_test},
Handlers = rumConfig:global_get(handlers, []),
HandlerInfo = lager_app:start_handler(rumEvent, ID,
[{level, none}, {group_leader, Pid},
{id, ID}]),
rumConfig:global_set(handlers, [HandlerInfo | Handlers]),
eRum:info("Test message"),
?assertNotEqual({group_leader, Pid}, erlang:process_info(whereis(rumEvent), group_leader)),
receive
{io_request, From, ReplyAs, {put_chars, unicode, _Msg}} ->
From ! {io_reply, ReplyAs, ok},
?assert(false)
after
500 ->
?assert(true)
end,
eRum:trace(ID, [{module, ?MODULE}], debug),
eRum:info("Test message"),
receive
{io_request, From1, ReplyAs1, {put_chars, unicode, Msg1}} ->
From1 ! {io_reply, ReplyAs1, ok},
TestMsg = "Test message" ++ eol(),
?assertMatch([_, "[info]", TestMsg], re:split(Msg1, " ", [{return, list}, {parts, 3}]))
after
500 ->
?assert(false)
end,
?assertNotEqual({0, []}, rumConfig:get({rumEvent, loglevel})),
%% killing the pid should prevent any new log messages (to prove we haven't accidentally redirected
%% the group leader some other way
exit(Pid, kill),
timer:sleep(100),
%% additionally, check the lager backend has been removed (because the group leader process died)
?assertNot(lists:member(lager_console_backend, gen_event:which_handlers(rumEvent))),
%% finally, check the trace has been removed
?assertEqual({0, []}, rumConfig:get({rumEvent, loglevel})),
eRum:error("Test message"),
receive
{io_request, From3, ReplyAs3, {put_chars, unicode, _Msg3}} ->
From3 ! {io_reply, ReplyAs3, ok},
?assert(false)
after
500 ->
?assert(true)
end
end
}
]
}.
set_loglevel_test_() ->
{foreach,
fun() ->
error_logger:tty(false),
application:load(lager),
application:set_env(lager, handlers, [{lager_console_backend, [{level, info}]}]),
application:set_env(lager, errLoggerRedirect, false),
eRum:start()
end,
fun(_) ->
application:stop(lager),
application:stop(goldrush),
error_logger:tty(true)
end,
[
{"Get/set loglevel test",
fun() ->
?assertEqual(info, eRum:getLogLevel(lager_console_backend)),
eRum:setLogLevel(lager_console_backend, debug),
?assertEqual(debug, eRum:getLogLevel(lager_console_backend)),
eRum:setLogLevel(lager_console_backend, '!=debug'),
?assertEqual(info, eRum:getLogLevel(lager_console_backend)),
eRum:setLogLevel(lager_console_backend, '!=info'),
?assertEqual(debug, eRum:getLogLevel(lager_console_backend)),
ok
end
},
{"Get/set invalid loglevel test",
fun() ->
?assertEqual(info, eRum:getLogLevel(lager_console_backend)),
?assertEqual({error, bad_log_level},
eRum:setLogLevel(lager_console_backend, fatfinger)),
?assertEqual(info, eRum:getLogLevel(lager_console_backend))
end
}
]
}.
-endif.

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

@ -14,11 +14,6 @@
-behaviour(gen_emm). -behaviour(gen_emm).
-ifdef(TEST).
-include_lib("eunit/include/eunit.hrl").
-compile([{parse_transform, lager_transform}]).
-endif.
-export([configToId/1]). -export([configToId/1]).
-export([ -export([
@ -297,717 +292,3 @@ closeFile(#state{fd = Fd} = State) ->
_ = file:close(Fd), _ = file:close(Fd),
State#state{fd = undefined} State#state{fd = undefined}
end. end.
-ifdef(TEST).
get_loglevel_test() ->
{ok, Level, _} = handleCall(mGetLogLevel,
#state{fileName = "bar", level = rumUtil:configToMask(info), fd = 0, inode = 0, ctime = undefined}),
?assertEqual(Level, rumUtil:configToMask(info)),
{ok, Level2, _} = handleCall(mGetLogLevel,
#state{fileName = "foo", level = rumUtil:configToMask(warning), fd = 0, inode = 0, ctime = undefined}),
?assertEqual(Level2, rumUtil:configToMask(warning)).
rotation_test_() ->
{foreach,
fun() ->
SyncLevel = rumUtil:configToMask(?RumDefSyncLevel),
SyncSize = ?RumDefSyncSize,
SyncInterval = ?RumDefSyncInterval,
Rotator = ?RumDefRotateMod,
CheckInterval = 0, %% hard to test delayed mode
{ok, TestDir} = rumUtil:create_test_dir(),
TestLog = filename:join(TestDir, "test.log"),
{OsType, _} = os:type(),
#state{fileName = TestLog,
level = ?DEBUG,
syncOn = SyncLevel,
syncSize = SyncSize,
syncInterval = SyncInterval,
checkInterval = CheckInterval,
rotator = Rotator,
osType = OsType}
end,
fun(#state{}) ->
ok = rumUtil:delete_test_dir()
end, [
fun(DefaultState = #state{fileName = TestLog, osType = OsType, syncSize = SyncSize, syncInterval = SyncInterval, rotator = Rotator}) ->
{"External rotation should work",
fun() ->
case OsType of
win32 ->
% Note: test is skipped on win32 due to the fact that a file can't be deleted or renamed
% while a process has an open file handle referencing it
ok;
_ ->
{ok, FD, Inode, Ctime, _Size} = Rotator:openLogfile(TestLog, {SyncSize, SyncInterval}),
State0 = DefaultState#state{fd = FD, inode = Inode, ctime = Ctime},
State1 = writeLog(State0, os:timestamp(), ?DEBUG, "hello world"),
?assertMatch(#state{fileName = TestLog, level = ?DEBUG, fd = FD, inode = Inode, ctime = Ctime}, State1),
?assertEqual(ok, file:delete(TestLog)),
State2 = writeLog(State0, os:timestamp(), ?DEBUG, "hello world"),
%% assert file has changed
ExpState1 = #state{fileName = TestLog, level = ?DEBUG, fd = FD, inode = Inode, ctime = Ctime},
?assertNotEqual(ExpState1, State2),
?assertMatch(#state{fileName = TestLog, level = ?DEBUG}, State2),
?assertEqual(ok, file:rename(TestLog, TestLog ++ ".1")),
State3 = writeLog(State2, os:timestamp(), ?DEBUG, "hello world"),
%% assert file has changed
?assertNotEqual(State3, State2),
?assertMatch(#state{fileName = TestLog, level = ?DEBUG}, State3),
ok
end
end}
end,
fun(DefaultState = #state{fileName = TestLog, syncSize = SyncSize, syncInterval = SyncInterval, rotator = Rotator}) ->
{"Internal rotation and delayed write",
fun() ->
TestLog0 = TestLog ++ ".0",
CheckInterval = 3000, % 3 sec
RotationSize = 15,
PreviousCheck = os:timestamp(),
{ok, FD, Inode, Ctime, _Size} = Rotator:openLogfile(TestLog, {SyncSize, SyncInterval}),
State0 = DefaultState#state{
fd = FD, inode = Inode, ctime = Ctime, size = RotationSize,
checkInterval = CheckInterval, lastCheck = PreviousCheck},
%% new message within check interval with sync_on level
Msg1Timestamp = add_secs(PreviousCheck, 1),
State1 = writeLog(State0, Msg1Timestamp, ?ERROR, "big big message 1"),
?assertEqual(State0, State1),
%% new message within check interval under sync_on level
%% not written to disk yet
Msg2Timestamp = add_secs(PreviousCheck, 2),
State2 = writeLog(State1, Msg2Timestamp, ?DEBUG, "buffered message 2"),
?assertEqual(State0, State2),
% Note: we must ensure at least one second (DEFAULT_SYNC_INTERVAL) has passed
% for message 1 and 2 to be written to disk
ElapsedMs = timer:now_diff(os:timestamp(), PreviousCheck) div 1000,
case ElapsedMs > SyncInterval of
true ->
ok;
_ ->
S = SyncInterval - ElapsedMs,
timer:sleep(S)
end,
%% although file size is big enough...
{ok, FInfo} = file:read_file_info(TestLog, [raw]),
?assert(RotationSize < FInfo#file_info.size),
%% ...no rotation yet
?assertEqual(PreviousCheck, State2#state.lastCheck),
?assertNot(filelib:is_regular(TestLog0)),
%% new message after check interval
Msg3Timestamp = add_secs(PreviousCheck, 4),
_State3 = writeLog(State2, Msg3Timestamp, ?DEBUG, "message 3"),
%% rotation happened
?assert(filelib:is_regular(TestLog0)),
{ok, Bin1} = file:read_file(TestLog0),
{ok, Bin2} = file:read_file(TestLog),
%% message 1-2 written to file
?assertEqual(<<"big big message 1buffered message 2">>, Bin1),
%% message 3 buffered, not yet written to file
?assertEqual(<<"">>, Bin2),
ok
end}
end
]}.
add_secs({Mega, Secs, Micro}, Add) ->
NewSecs = Secs + Add,
{Mega + NewSecs div 10000000, NewSecs rem 10000000, Micro}.
filesystem_test_() ->
{foreach,
fun() ->
ok = error_logger:tty(false),
ok = rumUtil:safe_application_load(lager),
ok = application:set_env(lager, handlers, [{lager_test_backend, info}]),
ok = application:set_env(lager, errLoggerRedirect, false),
ok = application:set_env(lager, asyncThreshold, undefined),
{ok, _TestDir} = rumUtil:create_test_dir(),
ok = eRum:start(),
%% race condition where lager logs its own start up
%% makes several tests fail. See test/lager_test_backend
%% around line 800 for more information.
ok = timer:sleep(5),
ok = lager_test_backend:flush()
end,
fun(_) ->
ok = application:stop(lager),
ok = application:stop(goldrush),
ok = error_logger:tty(true),
ok = rumUtil:delete_test_dir()
end, [
{"under normal circumstances, file should be opened",
fun() ->
{ok, TestDir} = rumUtil:get_test_dir(),
TestLog = filename:join(TestDir, "test.log"),
gen_event:add_handler(rumEvent, lager_file_backend,
[{TestLog, info}, {lager_default_formatter}]),
eRum:log(error, self(), "Test message"),
{ok, Bin} = file:read_file(TestLog),
Pid = pid_to_list(self()),
?assertMatch([_, _, "[error]", Pid, "Test message\n"],
re:split(Bin, " ", [{return, list}, {parts, 5}]))
end},
{"don't choke on unicode",
fun() ->
{ok, TestDir} = rumUtil:get_test_dir(),
TestLog = filename:join(TestDir, "test.log"),
gen_event:add_handler(rumEvent, lager_file_backend,
[{TestLog, info}, {lager_default_formatter}]),
eRum:log(error, self(), "~ts", [[20013, 25991, 27979, 35797]]),
{ok, Bin} = file:read_file(TestLog),
Pid = pid_to_list(self()),
?assertMatch([_, _, "[error]", Pid,
[228, 184, 173, 230, 150, 135, 230, 181, 139, 232, 175, 149, $\n]],
re:split(Bin, " ", [{return, list}, {parts, 5}]))
end},
{"don't choke on latin-1",
fun() ->
{ok, TestDir} = rumUtil:get_test_dir(),
TestLog = filename:join(TestDir, "test.log"),
%% XXX if this test fails, check that this file is encoded latin-1, not utf-8!
gen_event:add_handler(rumEvent, lager_file_backend,
[{TestLog, info}, {lager_default_formatter}]),
eRum:log(error, self(), "~ts", [[76, 198, 221, 206, 78, $-, 239]]),
{ok, Bin} = file:read_file(TestLog),
Pid = pid_to_list(self()),
Res = re:split(Bin, " ", [{return, list}, {parts, 5}]),
?assertMatch([_, _, "[error]", Pid,
[76, 195, 134, 195, 157, 195, 142, 78, 45, 195, 175, $\n]], Res)
end},
{"file can't be opened on startup triggers an error message",
fun() ->
{ok, TestDir} = rumUtil:get_test_dir(),
TestLog = filename:join(TestDir, "test.log"),
?assertEqual(ok, rumUtil:safe_write_file(TestLog, [])),
{ok, FInfo0} = file:read_file_info(TestLog, [raw]),
FInfo1 = FInfo0#file_info{mode = 0},
?assertEqual(ok, file:write_file_info(TestLog, FInfo1)),
gen_event:add_handler(rumEvent, lager_file_backend,
{TestLog, info, 10 * 1024 * 1024, "$D0", 5}),
% Note: required on win32, do this early to prevent subsequent failures
% from preventing cleanup
?assertEqual(ok, file:write_file_info(TestLog, FInfo0)),
?assertEqual(1, lager_test_backend:count()),
{_Level, _Time, Message, _Metadata} = lager_test_backend:pop(),
MessageFlat = lists:flatten(Message),
?assertEqual(
"Failed to open log file " ++ TestLog ++ " with error permission denied",
MessageFlat)
end},
{"file that becomes unavailable at runtime should trigger an error message",
fun() ->
case os:type() of
{win32, _} ->
% Note: test is skipped on win32 due to the fact that a file can't be
% deleted or renamed while a process has an open file handle referencing it
ok;
_ ->
{ok, TestDir} = rumUtil:get_test_dir(),
TestLog = filename:join(TestDir, "test.log"),
gen_event:add_handler(rumEvent, lager_file_backend,
[{file, TestLog}, {level, info}, {check_interval, 0}]),
?assertEqual(0, lager_test_backend:count()),
eRum:log(error, self(), "Test message"),
?assertEqual(1, lager_test_backend:count()),
?assertEqual(ok, file:delete(TestLog)),
?assertEqual(ok, rumUtil:safe_write_file(TestLog, "")),
{ok, FInfo0} = file:read_file_info(TestLog, [raw]),
FInfo1 = FInfo0#file_info{mode = 0},
?assertEqual(ok, file:write_file_info(TestLog, FInfo1)),
eRum:log(error, self(), "Test message"),
lager_test_backend:pop(),
lager_test_backend:pop(),
{_Level, _Time, Message, _Metadata} = lager_test_backend:pop(),
?assertEqual(
"Failed to reopen log file " ++ TestLog ++ " with error permission denied",
lists:flatten(Message))
end
end},
{"unavailable files that are fixed at runtime should start having log messages written",
fun() ->
{ok, TestDir} = rumUtil:get_test_dir(),
TestLog = filename:join(TestDir, "test.log"),
?assertEqual(ok, rumUtil:safe_write_file(TestLog, [])),
{ok, FInfo} = file:read_file_info(TestLog, [raw]),
OldPerms = FInfo#file_info.mode,
?assertEqual(ok, file:write_file_info(TestLog, FInfo#file_info{mode = 0})),
gen_event:add_handler(rumEvent, lager_file_backend,
[{file, TestLog}, {check_interval, 0}]),
?assertEqual(1, lager_test_backend:count()),
{_Level, _Time, Message, _Metadata} = lager_test_backend:pop(),
?assertEqual(
"Failed to open log file " ++ TestLog ++ " with error permission denied",
lists:flatten(Message)),
?assertEqual(ok, file:write_file_info(TestLog, FInfo#file_info{mode = OldPerms})),
eRum:log(error, self(), "Test message"),
{ok, Bin} = file:read_file(TestLog),
Pid = pid_to_list(self()),
?assertMatch([_, _, "[error]", Pid, "Test message\n"],
re:split(Bin, " ", [{return, list}, {parts, 5}]))
end},
{"external logfile rotation/deletion should be handled",
fun() ->
case os:type() of
{win32, _} ->
% Note: test is skipped on win32 due to the fact that a file can't be deleted or renamed
% while a process has an open file handle referencing it
ok;
_ ->
{ok, TestDir} = rumUtil:get_test_dir(),
TestLog = filename:join(TestDir, "test.log"),
TestLog0 = TestLog ++ ".0",
gen_event:add_handler(rumEvent, lager_file_backend,
[{file, TestLog}, {level, info}, {check_interval, 0}]),
?assertEqual(0, lager_test_backend:count()),
eRum:log(error, self(), "Test message1"),
?assertEqual(1, lager_test_backend:count()),
?assertEqual(ok, file:delete(TestLog)),
?assertEqual(ok, rumUtil:safe_write_file(TestLog, "")),
eRum:log(error, self(), "Test message2"),
?assertEqual(2, lager_test_backend:count()),
{ok, Bin} = file:read_file(TestLog),
Pid = pid_to_list(self()),
?assertMatch([_, _, "[error]", Pid, "Test message2\n"],
re:split(Bin, " ", [{return, list}, {parts, 5}])),
?assertEqual(ok, file:rename(TestLog, TestLog0)),
eRum:log(error, self(), "Test message3"),
?assertEqual(3, lager_test_backend:count()),
{ok, Bin2} = file:read_file(TestLog),
?assertMatch([_, _, "[error]", Pid, "Test message3\n"],
re:split(Bin2, " ", [{return, list}, {parts, 5}]))
end
end},
{"internal size rotation should work",
fun() ->
{ok, TestDir} = rumUtil:get_test_dir(),
TestLog = filename:join(TestDir, "test.log"),
TestLog0 = TestLog ++ ".0",
gen_event:add_handler(rumEvent, lager_file_backend,
[{file, TestLog}, {level, info}, {check_interval, 0}, {size, 10}]),
eRum:log(error, self(), "Test message1"),
eRum:log(error, self(), "Test message1"),
?assert(filelib:is_regular(TestLog0))
end},
{"internal time rotation should work",
fun() ->
{ok, TestDir} = rumUtil:get_test_dir(),
TestLog = filename:join(TestDir, "test.log"),
TestLog0 = TestLog ++ ".0",
gen_event:add_handler(rumEvent, lager_file_backend,
[{file, TestLog}, {level, info}, {check_interval, 1000}]),
eRum:log(error, self(), "Test message1"),
eRum:log(error, self(), "Test message1"),
whereis(rumEvent) ! {mRotate, TestLog},
eRum:log(error, self(), "Test message1"),
?assert(filelib:is_regular(TestLog0))
end},
{"rotation call should work",
fun() ->
{ok, TestDir} = rumUtil:get_test_dir(),
TestLog = filename:join(TestDir, "test.log"),
TestLog0 = TestLog ++ ".0",
gen_event:add_handler(rumEvent, {lager_file_backend, TestLog},
[{file, TestLog}, {level, info}, {check_interval, 1000}]),
eRum:log(error, self(), "Test message1"),
eRum:log(error, self(), "Test message1"),
gen_event:call(rumEvent, {lager_file_backend, TestLog}, mRotate, infinity),
eRum:log(error, self(), "Test message1"),
?assert(filelib:is_regular(TestLog0))
end},
{"sync_on option should work",
fun() ->
{ok, TestDir} = rumUtil:get_test_dir(),
TestLog = filename:join(TestDir, "test.log"),
gen_event:add_handler(rumEvent, lager_file_backend, [{file, TestLog},
{level, info}, {sync_on, "=info"}, {check_interval, 5000}, {sync_interval, 5000}]),
eRum:log(error, self(), "Test message1"),
eRum:log(error, self(), "Test message1"),
?assertEqual({ok, <<>>}, file:read_file(TestLog)),
eRum:log(info, self(), "Test message1"),
{ok, Bin} = file:read_file(TestLog),
?assert(<<>> /= Bin)
end},
{"sync_on none option should work (also tests sync_interval)",
fun() ->
{ok, TestDir} = rumUtil:get_test_dir(),
TestLog = filename:join(TestDir, "test.log"),
gen_event:add_handler(rumEvent, lager_file_backend, [{file, TestLog},
{level, info}, {sync_on, "none"}, {check_interval, 5000}, {sync_interval, 1000}]),
eRum:log(error, self(), "Test message1"),
eRum:log(error, self(), "Test message1"),
?assertEqual({ok, <<>>}, file:read_file(TestLog)),
eRum:log(info, self(), "Test message1"),
?assertEqual({ok, <<>>}, file:read_file(TestLog)),
timer:sleep(2000),
{ok, Bin} = file:read_file(TestLog),
?assert(<<>> /= Bin)
end},
{"sync_size option should work",
fun() ->
{ok, TestDir} = rumUtil:get_test_dir(),
TestLog = filename:join(TestDir, "test.log"),
gen_event:add_handler(rumEvent, lager_file_backend, [{file, TestLog}, {level, info},
{sync_on, "none"}, {check_interval, 5001}, {sync_size, 640}, {sync_interval, 5001}]),
eRum:log(error, self(), "Test messageis64bytes"),
eRum:log(error, self(), "Test messageis64bytes"),
eRum:log(error, self(), "Test messageis64bytes"),
eRum:log(error, self(), "Test messageis64bytes"),
eRum:log(error, self(), "Test messageis64bytes"),
?assertEqual({ok, <<>>}, file:read_file(TestLog)),
eRum:log(error, self(), "Test messageis64bytes"),
eRum:log(error, self(), "Test messageis64bytes"),
eRum:log(error, self(), "Test messageis64bytes"),
eRum:log(error, self(), "Test messageis64bytes"),
?assertEqual({ok, <<>>}, file:read_file(TestLog)),
%% now we've written enough bytes
eRum:log(error, self(), "Test messageis64bytes"),
{ok, Bin} = file:read_file(TestLog),
?assert(<<>> /= Bin)
end},
{"runtime level changes",
fun() ->
{ok, TestDir} = rumUtil:get_test_dir(),
TestLog = filename:join(TestDir, "test.log"),
gen_event:add_handler(rumEvent, {lager_file_backend, TestLog}, {TestLog, info}),
?assertEqual(0, lager_test_backend:count()),
eRum:log(info, self(), "Test message1"),
eRum:log(error, self(), "Test message2"),
{ok, Bin} = file:read_file(TestLog),
Lines = length(re:split(Bin, "\n", [{return, list}, trim])),
?assertEqual(Lines, 2),
?assertEqual(ok, eRum:setLogLevel(lager_file_backend, TestLog, warning)),
eRum:log(info, self(), "Test message3"), %% this won't get logged
eRum:log(error, self(), "Test message4"),
{ok, Bin2} = file:read_file(TestLog),
Lines2 = length(re:split(Bin2, "\n", [{return, list}, trim])),
?assertEqual(Lines2, 3)
end},
{"invalid runtime level changes",
fun() ->
{ok, TestDir} = rumUtil:get_test_dir(),
TestLog = filename:join(TestDir, "test.log"),
TestLog3 = filename:join(TestDir, "test3.log"),
gen_event:add_handler(rumEvent, lager_file_backend,
[{TestLog, info, 10 * 1024 * 1024, "$D0", 5}, {lager_default_formatter}]),
gen_event:add_handler(rumEvent, lager_file_backend, {TestLog3, info}),
?assertEqual({error, bad_module}, eRum:setLogLevel(lager_file_backend, TestLog, warning))
end},
{"tracing should work",
fun() ->
{ok, TestDir} = rumUtil:get_test_dir(),
TestLog = filename:join(TestDir, "test.log"),
gen_event:add_handler(rumEvent, lager_file_backend, {TestLog, critical}),
eRum:error("Test message"),
?assertEqual({ok, <<>>}, file:read_file(TestLog)),
{Level, _} = rumConfig:get({rumEvent, loglevel}),
rumConfig:set({rumEvent, loglevel}, {Level,
[{[{module, ?MODULE}], ?DEBUG, {lager_file_backend, TestLog}}]}),
eRum:error("Test message"),
timer:sleep(1000),
{ok, Bin} = file:read_file(TestLog),
?assertMatch([_, _, "[error]", _, "Test message\n"],
re:split(Bin, " ", [{return, list}, {parts, 5}]))
end},
{"tracing should not duplicate messages",
fun() ->
case os:type() of
{win32, _} ->
% Note: test is skipped on win32 due to the fact that a file can't be
% deleted or renamed while a process has an open file handle referencing it
ok;
_ ->
{ok, TestDir} = rumUtil:get_test_dir(),
TestLog = filename:join(TestDir, "test.log"),
gen_event:add_handler(rumEvent, lager_file_backend,
[{file, TestLog}, {level, critical}, {check_interval, always}]),
timer:sleep(500),
eRum:critical("Test message"),
{ok, Bin1} = file:read_file(TestLog),
?assertMatch([_, _, "[critical]", _, "Test message\n"],
re:split(Bin1, " ", [{return, list}, {parts, 5}])),
?assertEqual(ok, file:delete(TestLog)),
{Level, _} = rumConfig:get({rumEvent, loglevel}),
rumConfig:set({rumEvent, loglevel},
{Level, [{[{module, ?MODULE}], ?DEBUG, {lager_file_backend, TestLog}}]}),
eRum:critical("Test message"),
{ok, Bin2} = file:read_file(TestLog),
?assertMatch([_, _, "[critical]", _, "Test message\n"],
re:split(Bin2, " ", [{return, list}, {parts, 5}])),
?assertEqual(ok, file:delete(TestLog)),
eRum:error("Test message"),
{ok, Bin3} = file:read_file(TestLog),
?assertMatch([_, _, "[error]", _, "Test message\n"],
re:split(Bin3, " ", [{return, list}, {parts, 5}]))
end
end},
{"tracing to a dedicated file should work",
fun() ->
{ok, TestDir} = rumUtil:get_test_dir(),
TestLog = filename:join(TestDir, "foo.log"),
{ok, _} = eRum:trace_file(TestLog, [{module, ?MODULE}]),
eRum:error("Test message"),
%% not eligible for trace
eRum:log(error, self(), "Test message"),
{ok, Bin3} = file:read_file(TestLog),
?assertMatch([_, _, "[error]", _, "Test message\n"],
re:split(Bin3, " ", [{return, list}, {parts, 5}]))
end},
{"tracing to a dedicated file should work even if root_log is set",
fun() ->
{ok, TestDir} = rumUtil:get_test_dir(),
LogName = "foo.log",
LogPath = filename:join(TestDir, LogName),
application:set_env(lager, logRoot, TestDir),
{ok, _} = eRum:trace_file(LogName, [{module, ?MODULE}]),
eRum:error("Test message"),
%% not eligible for trace
eRum:log(error, self(), "Test message"),
{ok, Bin3} = file:read_file(LogPath),
application:unset_env(lager, logRoot),
?assertMatch([_, _, "[error]", _, "Test message\n"],
re:split(Bin3, " ", [{return, list}, {parts, 5}]))
end},
{"tracing with options should work",
fun() ->
{ok, TestDir} = rumUtil:get_test_dir(),
TestLog = filename:join(TestDir, "foo.log"),
TestLog0 = TestLog ++ ".0",
{ok, _} = eRum:trace_file(TestLog, [{module, ?MODULE}],
[{size, 20}, {check_interval, 1}]),
eRum:error("Test message"),
?assertNot(filelib:is_regular(TestLog0)),
%% rotation is sensitive to intervals between
%% writes so we sleep to exceed the 1
%% millisecond interval specified by
%% check_interval above
timer:sleep(2),
eRum:error("Test message"),
timer:sleep(10),
?assert(filelib:is_regular(TestLog0))
end},
{"no silent hwm drops",
fun() ->
MsgCount = 15,
{ok, TestDir} = rumUtil:get_test_dir(),
TestLog = filename:join(TestDir, "test.log"),
gen_event:add_handler(rumEvent, lager_file_backend, [{file, TestLog}, {level, info},
{high_water_mark, 5}, {flushQueue, false}, {sync_on, "=warning"}]),
{_, _, MS} = os:timestamp(),
% start close to the beginning of a new second
?assertEqual(ok, timer:sleep((1000000 - MS) div 1000 + 1)),
[eRum:log(info, self(), "Foo ~p", [K]) || K <- lists:seq(1, MsgCount)],
?assertEqual(MsgCount, lager_test_backend:count()),
% Note: bumped from 1000 to 1250 to ensure delayed write flushes to disk
?assertEqual(ok, timer:sleep(1250)),
{ok, Bin} = file:read_file(TestLog),
Last = lists:last(re:split(Bin, "\n", [{return, list}, trim])),
?assertMatch([_, _, _, _, "lager_file_backend dropped 10 messages in the last second that exceeded the limit of 5 messages/sec"],
re:split(Last, " ", [{return, list}, {parts, 5}]))
end}
]}.
trace_files_test_() ->
{foreach,
fun() ->
{ok, TestDir} = rumUtil:get_test_dir(),
Log = filename:join(TestDir, "test.log"),
Debug = filename:join(TestDir, "debug.log"),
Events = filename:join(TestDir, "events.log"),
ok = error_logger:tty(false),
ok = rumUtil:safe_application_load(lager),
ok = application:set_env(lager, handlers, [
{lager_file_backend, [
{file, Log},
{level, error},
{formatter, lager_default_formatter},
{formatter_config, [message, "\n"]}
]}
]),
ok = application:set_env(lager, traces, [
{ % get default level of debug
{lager_file_backend, Debug}, [{module, ?MODULE}]
},
{ % Handler Filters Level
{lager_file_backend, Events}, [{module, ?MODULE}], notice
}
]),
ok = application:set_env(lager, asyncThreshold, undefined),
ok = eRum:start(),
{Log, Debug, Events}
end,
fun({_, _, _}) ->
catch ets:delete(lager_config),
ok = application:unset_env(lager, traces),
ok = application:stop(lager),
ok = rumUtil:delete_test_dir(),
ok = error_logger:tty(true)
end, [
fun({Log, Debug, Events}) ->
{"a trace using file backend set up in configuration should work",
fun() ->
eRum:error("trace test error message"),
eRum:info("info message"),
%% not eligible for trace
eRum:log(error, self(), "Not trace test message"),
{ok, BinInfo} = file:read_file(Events),
?assertMatch([_, _, "[error]", _, "trace test error message\n"],
re:split(BinInfo, " ", [{return, list}, {parts, 5}])),
?assert(filelib:is_regular(Log)),
{ok, BinInfo2} = file:read_file(Log),
?assertMatch(["trace test error message", "Not trace test message\n"],
re:split(BinInfo2, "\n", [{return, list}, {parts, 2}])),
?assert(filelib:is_regular(Debug)),
%% XXX Aughhhh, wish I could force this to flush somehow...
% should take about 1 second, try for 3 ...
?assertEqual(2, count_lines_until(2, add_secs(os:timestamp(), 3), Debug, 0))
end}
end
]}.
count_lines_until(Lines, Timeout, File, Last) ->
case timer:now_diff(Timeout, os:timestamp()) > 0 of
true ->
timer:sleep(333),
{ok, Bin} = file:read_file(File),
case erlang:length(re:split(Bin, "\n", [{return, list}, trim])) of
Count when Count < Lines ->
count_lines_until(Lines, Timeout, File, Count);
Count ->
Count
end;
_ ->
Last
end.
formatting_test_() ->
{foreach,
fun() ->
{ok, TestDir} = rumUtil:get_test_dir(),
Log1 = filename:join(TestDir, "test.log"),
Log2 = filename:join(TestDir, "test2.log"),
?assertEqual(ok, rumUtil:safe_write_file(Log1, [])),
?assertEqual(ok, rumUtil:safe_write_file(Log2, [])),
ok = error_logger:tty(false),
ok = rumUtil:safe_application_load(lager),
ok = application:set_env(lager, handlers, [{lager_test_backend, info}]),
ok = application:set_env(lager, errLoggerRedirect, false),
ok = eRum:start(),
%% same race condition issue
ok = timer:sleep(5),
{ok, Log1, Log2}
end,
fun({ok, _, _}) ->
ok = application:stop(lager),
ok = application:stop(goldrush),
ok = rumUtil:delete_test_dir(),
ok = error_logger:tty(true)
end, [
fun({ok, Log1, Log2}) ->
{"Should have two log files, the second prefixed with 2>",
fun() ->
gen_event:add_handler(rumEvent, lager_file_backend,
[{Log1, debug}, {lager_default_formatter, ["[", severity, "] ", message, "\n"]}]),
gen_event:add_handler(rumEvent, lager_file_backend,
[{Log2, debug}, {lager_default_formatter, ["2> [", severity, "] ", message, "\n"]}]),
eRum:log(error, self(), "Test message"),
?assertMatch({ok, <<"[error] Test message\n">>}, file:read_file(Log1)),
?assertMatch({ok, <<"2> [error] Test message\n">>}, file:read_file(Log2))
end}
end
]}.
config_validation_test_() ->
[
{"missing file",
?_assertEqual(false,
checkOpts([{level, info}, {size, 10}]))
},
{"bad level",
?_assertEqual(false,
checkOpts([{file, "test.log"}, {level, blah}, {size, 10}]))
},
{"bad size",
?_assertEqual(false,
checkOpts([{file, "test.log"}, {size, infinity}]))
},
{"bad count",
?_assertEqual(false,
checkOpts([{file, "test.log"}, {count, infinity}]))
},
{"bad high water mark",
?_assertEqual(false,
checkOpts([{file, "test.log"}, {high_water_mark, infinity}]))
},
{"bad date",
?_assertEqual(false,
checkOpts([{file, "test.log"}, {date, "midnight"}]))
},
{"blank date is ok",
?_assertMatch([_ | _],
checkOpts([{file, "test.log"}, {date, ""}]))
},
{"bad sync_interval",
?_assertEqual(false,
checkOpts([{file, "test.log"}, {sync_interval, infinity}]))
},
{"bad sync_size",
?_assertEqual(false,
checkOpts([{file, "test.log"}, {sync_size, infinity}]))
},
{"bad check_interval",
?_assertEqual(false,
checkOpts([{file, "test.log"}, {check_interval, infinity}]))
},
{"bad sync_on level",
?_assertEqual(false,
checkOpts([{file, "test.log"}, {sync_on, infinity}]))
},
{"bad formatter module",
?_assertEqual(false,
checkOpts([{file, "test.log"}, {formatter, "io:format"}]))
},
{"bad formatter config",
?_assertEqual(false,
checkOpts([{file, "test.log"}, {formatter_config, blah}]))
},
{"unknown option",
?_assertEqual(false,
checkOpts([{file, "test.log"}, {rhubarb, spicy}]))
}
].
-endif.

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

@ -11,11 +11,6 @@
-include("rumDef.hrl"). -include("rumDef.hrl").
-ifdef(TEST).
-include_lib("eunit/include/eunit.hrl").
-include_lib("kernel/include/file.hrl").
-endif.
-export([ -export([
start/6 start/6
, start_link/6 , start_link/6
@ -191,146 +186,3 @@ writeLog(Event, #state{fileName = FileName, fd = FD, inode = Inode, ctime = Ctim
end end
end. end.
-ifdef(TEST).
filesystem_test_() ->
{foreach,
fun() ->
{ok, TestDir} = rumUtil:create_test_dir(),
CrashLog = filename:join(TestDir, "crash_test.log"),
ok = rumUtil:safe_write_file(CrashLog, []),
ok = error_logger:tty(false),
ok = rumUtil:safe_application_load(lager),
ok = application:set_env(lager, handlers, [{lager_test_backend, info}]),
ok = application:set_env(lager, errLoggerRedirect, true),
ok = application:unset_env(lager, crash_log),
ok = eRum:start(),
ok = timer:sleep(1000),
ok = lager_test_backend:flush(),
CrashLog
end,
fun(_CrashLog) ->
case whereis(lager_crash_log) of
P when is_pid(P) ->
gen_server:stop(P);
_ ->
ok
end,
ok = application:stop(lager),
ok = application:stop(goldrush),
ok = rumUtil:delete_test_dir(),
ok = error_logger:tty(true)
end, [
fun(CrashLog) ->
{"under normal circumstances, file should be opened",
fun() ->
{ok, _} = ?MODULE:start_link(CrashLog, 65535, 0, undefined, 0, lager_rotator_default),
_ = gen_event:which_handlers(error_logger),
sync_error_logger:error_msg("Test message\n"),
{ok, Bin} = file:read_file(CrashLog),
?assertMatch([_, "Test message\n"], re:split(Bin, "\n", [{return, list}, {parts, 2}]))
end}
end,
fun(CrashLog) ->
{"file can't be opened on startup triggers an error message",
fun() ->
{ok, FInfo0} = file:read_file_info(CrashLog, [raw]),
FInfo1 = FInfo0#file_info{mode = 0},
?assertEqual(ok, file:write_file_info(CrashLog, FInfo1)),
{ok, _} = ?MODULE:start_link(CrashLog, 65535, 0, undefined, 0, lager_rotator_default),
% Note: required on win32, do this early to prevent subsequent failures
% from preventing cleanup
?assertEqual(ok, file:write_file_info(CrashLog, FInfo0)),
?assertEqual(1, lager_test_backend:count()),
{_Level, _Time, Message, _Metadata} = lager_test_backend:pop(),
?assertEqual(
"Failed to open crash log file " ++ CrashLog ++ " with error: permission denied",
lists:flatten(Message))
end}
end,
fun(CrashLog) ->
{"file that becomes unavailable at runtime should trigger an error message",
fun() ->
case os:type() of
{win32, _} ->
% Note: test is skipped on win32 due to the fact that a file can't be deleted or renamed
% while a process has an open file handle referencing it
ok;
_ ->
{ok, _} = ?MODULE:start_link(CrashLog, 65535, 0, undefined, 0, lager_rotator_default),
?assertEqual(0, lager_test_backend:count()),
sync_error_logger:error_msg("Test message\n"),
_ = gen_event:which_handlers(error_logger),
?assertEqual(1, lager_test_backend:count()),
?assertEqual(ok, file:delete(CrashLog)),
?assertEqual(ok, rumUtil:safe_write_file(CrashLog, "")),
{ok, FInfo0} = file:read_file_info(CrashLog, [raw]),
FInfo1 = FInfo0#file_info{mode = 0},
?assertEqual(ok, file:write_file_info(CrashLog, FInfo1)),
sync_error_logger:error_msg("Test message\n"),
_ = gen_event:which_handlers(error_logger),
% Note: required on win32, do this early to prevent subsequent failures
% from preventing cleanup
?assertEqual(ok, file:write_file_info(CrashLog, FInfo0)),
?assertEqual(3, lager_test_backend:count()),
lager_test_backend:pop(),
{_Level, _Time, Message, _Metadata} = lager_test_backend:pop(),
?assertEqual(
"Failed to reopen crash log " ++ CrashLog ++ " with error: permission denied",
lists:flatten(Message))
end
end}
end,
fun(CrashLog) ->
{"unavailable files that are fixed at runtime should start having log messages written",
fun() ->
{ok, FInfo} = file:read_file_info(CrashLog, [raw]),
OldPerms = FInfo#file_info.mode,
file:write_file_info(CrashLog, FInfo#file_info{mode = 0}),
{ok, _} = ?MODULE:start_link(CrashLog, 65535, 0, undefined, 0, lager_rotator_default),
?assertEqual(1, lager_test_backend:count()),
{_Level, _Time, Message, _Metadata} = lager_test_backend:pop(),
?assertEqual(
"Failed to open crash log file " ++ CrashLog ++ " with error: permission denied",
lists:flatten(Message)),
file:write_file_info(CrashLog, FInfo#file_info{mode = OldPerms}),
sync_error_logger:error_msg("Test message~n"),
_ = gen_event:which_handlers(error_logger),
{ok, Bin} = file:read_file(CrashLog),
?assertMatch([_, "Test message\n"], re:split(Bin, "\n", [{return, list}, {parts, 2}]))
end}
end,
fun(CrashLog) ->
{"external logfile rotation/deletion should be handled",
fun() ->
case os:type() of
{win32, _} ->
% Note: test is skipped on win32 due to the fact that a file can't be deleted or renamed
% while a process has an open file handle referencing it
ok;
_ ->
{ok, _} = ?MODULE:start_link(CrashLog, 65535, 0, undefined, 0, lager_rotator_default),
?assertEqual(0, lager_test_backend:count()),
sync_error_logger:error_msg("Test message~n"),
_ = gen_event:which_handlers(error_logger),
{ok, Bin} = file:read_file(CrashLog),
?assertMatch([_, "Test message\n"], re:split(Bin, "\n", [{return, list}, {parts, 2}])),
?assertEqual(ok, file:delete(CrashLog)),
?assertEqual(ok, rumUtil:safe_write_file(CrashLog, "")),
sync_error_logger:error_msg("Test message1~n"),
_ = gen_event:which_handlers(error_logger),
{ok, Bin1} = file:read_file(CrashLog),
?assertMatch([_, "Test message1\n"], re:split(Bin1, "\n", [{return, list}, {parts, 2}])),
file:rename(CrashLog, CrashLog ++ ".0"),
sync_error_logger:error_msg("Test message2~n"),
_ = gen_event:which_handlers(error_logger),
{ok, Bin2} = file:read_file(CrashLog),
?assertMatch([_, "Test message2\n"], re:split(Bin2, "\n", [{return, list}, {parts, 2}]))
end
end}
end
]}.
-endif.

+ 21
- 52
src/eRum.erl 查看文件

@ -1,6 +1,8 @@
-module(eRum). -module(eRum).
-include("rumDef.hrl"). -include("rumDef.hrl").
-include("rumMsg.hrl").
-include("rumCom.hrl").
-ifdef(TEST). -ifdef(TEST).
-include_lib("eunit/include/eunit.hrl"). -include_lib("eunit/include/eunit.hrl").
@ -13,16 +15,14 @@
, stop/0 , stop/0
%% log and log param %% log and log param
, log/3
, log/4 , log/4
, log/5 , log/5
, log_unsafe/4 , log_unsafe/4
, do_log/9
, do_log/10
, do_log_unsafe/10
, dispatch_log/5
, dispatch_log/7
, dispatch_log/9
, do_log/15
, do_log/16
, do_log_unsafe/16
, dispatch_log/11
, dispatch_log/13
, safe_format/3 , safe_format/3
, safe_format_chop/3 , safe_format_chop/3
, unsafe_format/2 , unsafe_format/2
@ -86,13 +86,6 @@ start() ->
stop() -> stop() ->
application:stop(eRum). application:stop(eRum).
%% @doc Manually log a message into eRum without using the parse transform.
-spec log(rumAtomLevel(), pid() | atom() | [tuple(), ...], list()) -> ok | {error, lager_not_running}.
log(Level, Pid, Message) when is_pid(Pid); is_atom(Pid) ->
dispatch_log(Level, [{pid, Pid}], Message, [], ?RumDefTruncation);
log(Level, Metadata, Message) when is_list(Metadata) ->
dispatch_log(Level, Metadata, Message, [], ?RumDefTruncation).
%% @doc Manually log a message into eRum without using the parse transform. %% @doc Manually log a message into eRum without using the parse transform.
-spec log(rumAtomLevel(), pid() | atom() | [tuple(), ...], string(), list()) -> ok | {error, lager_not_running}. -spec log(rumAtomLevel(), pid() | atom() | [tuple(), ...], string(), list()) -> ok | {error, lager_not_running}.
log(Level, Pid, Format, Args) when is_pid(Pid); is_atom(Pid) -> log(Level, Pid, Format, Args) when is_pid(Pid); is_atom(Pid) ->
@ -113,28 +106,28 @@ log_unsafe(Level, Metadata, Format, Args) when is_list(Metadata) ->
-spec dispatch_log(atom(), rumAtomLevel(), list(), string(), list() | none, pos_integer(), safe | unsafe) -> ok | {error, lager_not_running} | {error, {sink_not_configured, atom()}}. -spec dispatch_log(atom(), rumAtomLevel(), list(), string(), list() | none, pos_integer(), safe | unsafe) -> ok | {error, lager_not_running} | {error, {sink_not_configured, atom()}}.
%% this is the same check that the parse transform bakes into the module at compile time %% this is the same check that the parse transform bakes into the module at compile time
%% see rumTransform (lines 173-216) %% see rumTransform (lines 173-216)
dispatch_log(Sink, Severity, Metadata, Format, Args, Size, Safety) when is_atom(Severity) ->
dispatch_log(Sink, Severity, Pid, Node, Module, Function, File, Line, Metadata, Format, Args, Size, Safety) when is_atom(Severity) ->
SeverityAsInt = rumUtil:levelToNum(Severity), SeverityAsInt = rumUtil:levelToNum(Severity),
case {whereis(Sink), whereis(?RumDefSink), rumConfig:get({Sink, loglevel}, {?LOG_NONE, []})} of case {whereis(Sink), whereis(?RumDefSink), rumConfig:get({Sink, loglevel}, {?LOG_NONE, []})} of
{undefined, undefined, _} -> {error, lager_not_running}; {undefined, undefined, _} -> {error, lager_not_running};
{undefined, _LagerEventPid0, _} -> {error, {sink_not_configured, Sink}}; {undefined, _LagerEventPid0, _} -> {error, {sink_not_configured, Sink}};
{SinkPid, _LagerEventPid1, {Level, Traces}} when Safety =:= safe andalso ((Level band SeverityAsInt) /= 0 orelse Traces /= []) -> {SinkPid, _LagerEventPid1, {Level, Traces}} when Safety =:= safe andalso ((Level band SeverityAsInt) /= 0 orelse Traces /= []) ->
do_log(Severity, Metadata, Format, Args, Size, SeverityAsInt, Level, Traces, Sink, SinkPid);
do_log(Severity, Pid, Node, Module, Function, File, Line, Metadata, Format, Args, Size, SeverityAsInt, Level, Traces, Sink, SinkPid);
{SinkPid, _LagerEventPid1, {Level, Traces}} when Safety =:= unsafe andalso ((Level band SeverityAsInt) /= 0 orelse Traces /= []) -> {SinkPid, _LagerEventPid1, {Level, Traces}} when Safety =:= unsafe andalso ((Level band SeverityAsInt) /= 0 orelse Traces /= []) ->
do_log_unsafe(Severity, Metadata, Format, Args, Size, SeverityAsInt, Level, Traces, Sink, SinkPid);
do_log_unsafe(Severity, Pid, Node, Module, Function, File, Line, Metadata, Format, Args, Size, SeverityAsInt, Level, Traces, Sink, SinkPid);
_ -> ok _ -> ok
end. end.
%% 使eRum 2.x编译的梁 %% 使eRum 2.x编译的梁
do_log(Severity, Metadata, Format, Args, Size, SeverityAsInt, LevelThreshold, TraceFilters, SinkPid) ->
do_log(Severity, Metadata, Format, Args, Size, SeverityAsInt, LevelThreshold, TraceFilters, ?RumDefSink, SinkPid).
do_log(Severity, Pid, Node, Module, Function, File, Line, Metadata, Format, Args, Size, SeverityAsInt, LevelThreshold, TraceFilters, SinkPid) ->
do_log(Severity, Pid, Node, Module, Function, File, Line, Metadata, Format, Args, Size, SeverityAsInt, LevelThreshold, TraceFilters, ?RumDefSink, SinkPid).
%% @private Should only be called externally from code generated from the parse transform %% @private Should only be called externally from code generated from the parse transform
do_log(Severity, Metadata, Format, Args, Size, SeverityAsInt, LevelThreshold, TraceFilters, Sink, SinkPid) when is_atom(Severity) ->
do_log(Severity, Pid, Node, Module, Function, File, Line, Metadata, Format, Args, Size, SeverityAsInt, LevelThreshold, TraceFilters, Sink, SinkPid) when is_atom(Severity) ->
FormatFun = fun() -> safe_format_chop(Format, Args, Size) end, FormatFun = fun() -> safe_format_chop(Format, Args, Size) end,
do_log_impl(Severity, Metadata, Format, Args, SeverityAsInt, LevelThreshold, TraceFilters, Sink, SinkPid, FormatFun).
do_log_impl(Severity, Pid, Node, Module, Function, File, Line, Metadata, Format, Args, SeverityAsInt, LevelThreshold, TraceFilters, Sink, SinkPid, FormatFun).
do_log_impl(Severity, Metadata, Format, Args, SeverityAsInt, LevelThreshold, TraceFilters, Sink, SinkPid, FormatFun) ->
do_log_impl(Severity, Pid, Node, Module, Function, File, Line, Metadata, Format, Args, SeverityAsInt, LevelThreshold, TraceFilters, Sink, SinkPid, FormatFun) ->
{Destinations, TraceSinkPid} = {Destinations, TraceSinkPid} =
case TraceFilters of case TraceFilters of
[] -> [] ->
@ -151,8 +144,7 @@ do_log_impl(Severity, Metadata, Format, Args, SeverityAsInt, LevelThreshold, Tra
_ -> _ ->
Format Format
end, end,
LagerMsg = rumMsg:new(Msg,
Severity, Metadata, Destinations),
LagerMsg = ?newMsg(Severity, Pid, Node, Module, Function, File, Line, Metadata, Destinations, rumUtil:nowMs(), Msg),
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});
@ -171,18 +163,14 @@ do_log_impl(Severity, Metadata, Format, Args, SeverityAsInt, LevelThreshold, Tra
%% @private Should only be called externally from code generated from the parse transform %% @private Should only be called externally from code generated from the parse transform
%% Specifically, it would be level ++ `_unsafe' as in `info_unsafe'. %% Specifically, it would be level ++ `_unsafe' as in `info_unsafe'.
do_log_unsafe(Severity, Metadata, Format, Args, _Size, SeverityAsInt, LevelThreshold, TraceFilters, Sink, SinkPid) when is_atom(Severity) ->
do_log_unsafe(Severity, Pid, Node, Module, Function, File, Line, Metadata, Format, Args, _Size, SeverityAsInt, LevelThreshold, TraceFilters, Sink, SinkPid) when is_atom(Severity) ->
FormatFun = fun() -> unsafe_format(Format, Args) end, FormatFun = fun() -> unsafe_format(Format, Args) end,
do_log_impl(Severity, Metadata, Format, Args, SeverityAsInt, LevelThreshold, TraceFilters, Sink, SinkPid, FormatFun).
do_log_impl(Severity, Pid, Node, Module, Function, File, Line, Metadata, Format, Args, SeverityAsInt, LevelThreshold, TraceFilters, Sink, SinkPid, FormatFun).
%% backwards compatible with beams compiled with lager 1.x
dispatch_log(Severity, _Module, _Function, _Line, _Pid, Metadata, Format, Args, Size) ->
dispatch_log(Severity, Metadata, Format, Args, Size).
%% backwards compatible with beams compiled with lager 2.x %% backwards compatible with beams compiled with lager 2.x
dispatch_log(Severity, Metadata, Format, Args, Size) ->
dispatch_log(?RumDefSink, Severity, Metadata, Format, Args, Size, safe).
dispatch_log(Severity, Pid, Node, Module, Function, File, Line, Metadata, Format, Args, Size) ->
dispatch_log(?RumDefSink, Severity, Pid, Node, Module, Function, File, Line, Metadata, Format, Args, Size, safe).
%% @doc Get lager metadata for current process %% @doc Get lager metadata for current process
-spec md() -> [{atom(), any()}]. -spec md() -> [{atom(), any()}].
@ -722,23 +710,4 @@ check_timeout(#trace_func_state_v1{timeout = Timeout, started = Started} = FuncS
done; done;
false -> false ->
FuncState FuncState
end.
-ifdef(TEST).
get_sink_handler_status_ascii_test() ->
File = "C:\\ProgramData\\Directory With Spaces\\lager.log",
validate_status(File).
get_sink_handler_status_latin_test() ->
File = "C:\\ProgramData\\Tést Directory\\lager.log",
validate_status(File).
get_sink_handler_status_unicode_test() ->
File = "C:\\ProgramData\\찦차를 타고 온 펲시맨과 쑛다리 똠방각하 (Korean)\\lager.log",
validate_status(File).
validate_status(File) ->
Handler = {rumBkdFile, File},
Status = get_sink_handler_status(?RumDefSink, Handler, debug),
?assertNotEqual(nomatch, string:find(Status, File)).
-endif.
end.

+ 1
- 0
src/eRum_app.erl 查看文件

@ -2,6 +2,7 @@
-behaviour(application). -behaviour(application).
-include("rumCom.hrl").
-include("rumDef.hrl"). -include("rumDef.hrl").
-export([ -export([

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

@ -3,10 +3,11 @@
%% error_logger后端eRum %% error_logger后端eRum
%% @see rumCrashLog %% @see rumCrashLog
-include("rumDef.hrl").
-behaviour(gen_event). -behaviour(gen_event).
-include("rumDef.hrl").
-include("eRum.hrl").
-export([ -export([
setHighWater/1 setHighWater/1
, formatReason/1 , formatReason/1
@ -582,172 +583,3 @@ get_value(Key, List, Default) ->
supervisorName({local, Name}) -> Name; supervisorName({local, Name}) -> Name;
supervisorName(Name) -> Name. supervisorName(Name) -> Name.
-ifdef(TEST).
-include_lib("eunit/include/eunit.hrl").
no_silent_hwm_drops_test_() ->
{timeout, 10000,
[
fun() ->
error_logger:tty(false),
application:load(lager),
application:set_env(lager, handlers, [{lager_test_backend, warning}]),
application:set_env(lager, errLoggerRedirect, true),
application:set_env(lager, errLoggerHwm, 5),
application:set_env(lager, errLoggerFlushQueue, false),
application:set_env(lager, suppress_supervisor_start_stop, true),
application:set_env(lager, suppress_application_start_stop, true),
application:unset_env(lager, crash_log),
eRum:start(),
try
{_, _, MS} = os:timestamp(),
timer:sleep((1000000 - MS) div 1000 + 1),
% start close to the beginning of a new second
[error_logger:error_msg("Foo ~p~n", [K]) || K <- lists:seq(1, 15)],
wait_for_message("lager_error_logger_h dropped 10 messages in the last second that exceeded the limit of 5 messages/sec", 100, 50),
% and once again
[error_logger:error_msg("Foo1 ~p~n", [K]) || K <- lists:seq(1, 20)],
wait_for_message("lager_error_logger_h dropped 15 messages in the last second that exceeded the limit of 5 messages/sec", 100, 50)
after
application:stop(lager),
application:stop(goldrush),
error_logger:tty(true)
end
end
]
}.
shaper_does_not_forward_sup_progress_messages_to_info_level_backend_test_() ->
{timeout, 10000,
[fun() ->
error_logger:tty(false),
application:load(lager),
application:set_env(lager, handlers, [{lager_test_backend, info}]),
application:set_env(lager, errLoggerRedirect, true),
application:set_env(lager, errLoggerHwm, 5),
application:set_env(lager, suppress_supervisor_start_stop, false),
application:set_env(lager, suppress_application_start_stop, false),
application:unset_env(lager, crash_log),
eRum:start(),
try
PidPlaceholder = self(),
SupervisorMsg =
[{supervisor, {PidPlaceholder, rabbit_connection_sup}},
{started,
[{pid, PidPlaceholder},
{name, helper_sup},
{mfargs,
{rabbit_connection_helper_sup, start_link, []}},
{restart_type, intrinsic},
{shutdown, infinity},
{child_type, supervisor}]}],
ApplicationExit =
[{application, error_logger_lager_h_test},
{exited, stopped},
{type, permanent}],
error_logger:info_report("This is not a progress message"),
error_logger:info_report(ApplicationExit),
[error_logger:info_report(progress, SupervisorMsg) || _K <- lists:seq(0, 100)],
error_logger:info_report("This is not a progress message 2"),
% Note: this gets logged in slow environments:
% Application lager started on node nonode@nohost
wait_for_count(fun lager_test_backend:count/0, [3, 4], 100, 50),
% Note: this debug msg gets ignored in slow environments:
% Lager installed handler lager_test_backend into lager_event
wait_for_count(fun lager_test_backend:count_ignored/0, [0, 1], 100, 50)
after
application:stop(lager),
application:stop(goldrush),
error_logger:tty(true)
end
end
]
}.
supressed_messages_are_not_counted_for_hwm_test_() ->
{timeout, 10000,
[fun() ->
error_logger:tty(false),
application:load(lager),
application:set_env(lager, handlers, [{lager_test_backend, debug}]),
application:set_env(lager, errLoggerRedirect, true),
application:set_env(lager, errLoggerHwm, 5),
application:set_env(lager, suppress_supervisor_start_stop, true),
application:set_env(lager, suppress_application_start_stop, true),
application:unset_env(lager, crash_log),
eRum:start(),
try
PidPlaceholder = self(),
SupervisorMsg =
[{supervisor, {PidPlaceholder, rabbit_connection_sup}},
{started,
[{pid, PidPlaceholder},
{name, helper_sup},
{mfargs,
{rabbit_connection_helper_sup, start_link, []}},
{restart_type, intrinsic},
{shutdown, infinity},
{child_type, supervisor}]}],
ApplicationExit =
[{application, error_logger_lager_h_test},
{exited, stopped},
{type, permanent}],
lager_test_backend:flush(),
error_logger:info_report("This is not a progress message"),
[error_logger:info_report(ApplicationExit) || _K <- lists:seq(0, 100)],
[error_logger:info_report(progress, SupervisorMsg) || _K <- lists:seq(0, 100)],
error_logger:info_report("This is not a progress message 2"),
wait_for_count(fun lager_test_backend:count/0, 2, 100, 50),
wait_for_count(fun lager_test_backend:count_ignored/0, 0, 100, 50)
after
application:stop(lager),
application:stop(goldrush),
error_logger:tty(true)
end
end
]
}.
wait_for_message(Expected, Tries, Sleep) ->
maybe_find_expected_message(lager_test_backend:get_buffer(), Expected, Tries, Sleep).
maybe_find_expected_message(_Buffer, Expected, 0, _Sleep) ->
throw({not_found, Expected});
maybe_find_expected_message([], Expected, Tries, Sleep) ->
timer:sleep(Sleep),
maybe_find_expected_message(lager_test_backend:get_buffer(), Expected, Tries - 1, Sleep);
maybe_find_expected_message([{_Severity, _Date, Msg, _Metadata} | T], Expected, Tries, Sleep) ->
case lists:flatten(Msg) of
Expected ->
ok;
_ ->
maybe_find_expected_message(T, Expected, Tries, Sleep)
end.
wait_for_count(Fun, _Expected, 0, _Sleep) ->
Actual = Fun(),
Msg = io_lib:format("wait_for_count: fun ~p final value: ~p~n", [Fun, Actual]),
throw({failed, Msg});
wait_for_count(Fun, Expected, Tries, Sleep) when is_list(Expected) ->
Actual = Fun(),
case lists:member(Actual, Expected) of
true ->
ok;
false ->
timer:sleep(Sleep),
wait_for_count(Fun, Expected, Tries - 1, Sleep)
end;
wait_for_count(Fun, Expected, Tries, Sleep) ->
case Fun() of
Expected ->
ok;
_ ->
timer:sleep(Sleep),
wait_for_count(Fun, Expected, Tries - 1, Sleep)
end.
-endif.

+ 0
- 308
src/formatter/rumFormatter.erl 查看文件

@ -2,10 +2,6 @@
-include("rumDef.hrl"). -include("rumDef.hrl").
-ifdef(TEST).
-include_lib("eunit/include/eunit.hrl").
-endif.
-export([ -export([
format/2 format/2
, format/3 , format/3
@ -237,307 +233,3 @@ uppercase_severity(error) -> "ERROR";
uppercase_severity(critical) -> "CRITICAL"; uppercase_severity(critical) -> "CRITICAL";
uppercase_severity(alert) -> "ALERT"; uppercase_severity(alert) -> "ALERT";
uppercase_severity(emergency) -> "EMERGENCY". uppercase_severity(emergency) -> "EMERGENCY".
-ifdef(TEST).
basic_test_() ->
Date = {1, 1, 1},
Time = {1, 1, 1},
Now = 11,
[{"Default formatting test",
?_assertEqual(iolist_to_binary([Date, " ", Time, " [error] ", pid_to_list(self()), " Message\n"]),
iolist_to_binary(format(rumMsg:new("Message",
Now,
error,
[{pid, self()}],
[]),
[])))
},
{"Basic Formatting",
?_assertEqual(<<"Simplist Format">>,
iolist_to_binary(format(rumMsg:new("Message",
Now,
error,
[{pid, self()}],
[]),
["Simplist Format"])))
},
{"Default equivalent formatting test",
?_assertEqual(iolist_to_binary([Date, " ", Time, " [error] ", pid_to_list(self()), " Message\n"]),
iolist_to_binary(format(rumMsg:new("Message",
Now,
error,
[{pid, self()}],
[]),
[date, " ", time, " [", severity, "] ", pid, " ", message, "\n"]
)))
},
{"Non existent metadata can default to string",
?_assertEqual(iolist_to_binary([Date, " ", Time, " [error] Fallback Message\n"]),
iolist_to_binary(format(rumMsg:new("Message",
Now,
error,
[{pid, self()}],
[]),
[date, " ", time, " [", severity, "] ", {does_not_exist, "Fallback"}, " ", message, "\n"]
)))
},
{"Non existent metadata can default to other metadata",
?_assertEqual(iolist_to_binary([Date, " ", Time, " [error] Fallback Message\n"]),
iolist_to_binary(format(rumMsg:new("Message",
Now,
error,
[{pid, "Fallback"}],
[]),
[date, " ", time, " [", severity, "] ", {does_not_exist, pid}, " ", message, "\n"]
)))
},
{"Non existent metadata can default to a string2",
?_assertEqual(iolist_to_binary(["Unknown Pid"]),
iolist_to_binary(format(rumMsg:new("Message",
Now,
error,
[],
[]),
[{pid, ["My pid is ", pid], ["Unknown Pid"]}]
)))
},
{"Metadata can have extra formatting",
?_assertEqual(iolist_to_binary(["My pid is hello"]),
iolist_to_binary(format(rumMsg:new("Message",
Now,
error,
[{pid, hello}],
[]),
[{pid, ["My pid is ", pid], ["Unknown Pid"]}]
)))
},
{"Metadata can have extra formatting1",
?_assertEqual(iolist_to_binary(["servername"]),
iolist_to_binary(format(rumMsg:new("Message",
Now,
error,
[{pid, hello}, {server, servername}],
[]),
[{server, {pid, ["(", pid, ")"], ["(Unknown Server)"]}}]
)))
},
{"Metadata can have extra formatting2",
?_assertEqual(iolist_to_binary(["(hello)"]),
iolist_to_binary(format(rumMsg:new("Message",
Now,
error,
[{pid, hello}],
[]),
[{server, {pid, ["(", pid, ")"], ["(Unknown Server)"]}}]
)))
},
{"Metadata can have extra formatting3",
?_assertEqual(iolist_to_binary(["(Unknown Server)"]),
iolist_to_binary(format(rumMsg:new("Message",
Now,
error,
[],
[]),
[{server, {pid, ["(", pid, ")"], ["(Unknown Server)"]}}]
)))
},
{"Metadata can be printed in its enterity",
?_assertEqual(iolist_to_binary(["bar=2 baz=3 foo=1"]),
iolist_to_binary(format(rumMsg:new("Message",
Now,
error,
[{foo, 1}, {bar, 2}, {baz, 3}],
[]),
[metadata]
)))
},
{"Metadata can be printed in its enterity with custom seperators",
?_assertEqual(iolist_to_binary(["bar->2, baz->3, foo->1"]),
iolist_to_binary(format(rumMsg:new("Message",
Now,
error,
[{foo, 1}, {bar, 2}, {baz, 3}],
[]),
[{metadata, "->", ", "}]
)))
},
{"Metadata can have extra formatting with width 1",
?_assertEqual(iolist_to_binary(["(hello )(hello )(hello)(hello)(hello)"]),
iolist_to_binary(format(rumMsg:new("Message",
Now,
error,
[{pid, hello}],
[]),
["(", {pid, [pid], "", 10}, ")",
"(", {pid, [pid], "", {bad_align, 10}}, ")",
"(", {pid, [pid], "", bad10}, ")",
"(", {pid, [pid], "", {right, bad20}}, ")",
"(", {pid, [pid], "", {bad_align, bad20}}, ")"]
)))
},
{"Metadata can have extra formatting with width 2",
?_assertEqual(iolist_to_binary(["(hello )"]),
iolist_to_binary(format(rumMsg:new("Message",
Now,
error,
[{pid, hello}],
[]),
["(", {pid, [pid], "", {left, 10}}, ")"]
)))
},
{"Metadata can have extra formatting with width 3",
?_assertEqual(iolist_to_binary(["( hello)"]),
iolist_to_binary(format(rumMsg:new("Message",
Now,
error,
[{pid, hello}],
[]),
["(", {pid, [pid], "", {right, 10}}, ")"]
)))
},
{"Metadata can have extra formatting with width 4",
?_assertEqual(iolist_to_binary(["( hello )"]),
iolist_to_binary(format(rumMsg:new("Message",
Now,
error,
[{pid, hello}],
[]),
["(", {pid, [pid], "", {centre, 10}}, ")"]
)))
},
{"Metadata can have extra formatting with width 5",
?_assertEqual(iolist_to_binary(["error |hello ! ( hello )"]),
iolist_to_binary(format(rumMsg:new("Message",
Now,
error,
[{pid, hello}],
[]),
[{x, "", [severity, {blank, "|"}, pid], 10}, "!", blank, "(", {pid, [pid], "", {centre, 10}}, ")"]
)))
},
{"Metadata can have extra formatting with width 6",
?_assertEqual(iolist_to_binary([Time, Date, " bar=2 baz=3 foo=1 pid=hello EMessage"]),
iolist_to_binary(format(rumMsg:new("Message",
Now,
error,
[{pid, hello}, {foo, 1}, {bar, 2}, {baz, 3}],
[]),
[{x, "", [time]}, {x, "", [date], 20}, blank, {x, "", [metadata], 30}, blank, {x, "", [sev], 10}, message, {message, message, "", {right, 20}}]
)))
},
{"Uppercase Severity Formatting - DEBUG",
?_assertEqual(<<"DEBUG Simplist Format">>,
iolist_to_binary(format(rumMsg:new("Message",
Now,
debug,
[{pid, self()}],
[]),
[severity_upper, " Simplist Format"])))
},
{"Uppercase Severity Formatting - INFO",
?_assertEqual(<<"INFO Simplist Format">>,
iolist_to_binary(format(rumMsg:new("Message",
Now,
info,
[{pid, self()}],
[]),
[severity_upper, " Simplist Format"])))
},
{"Uppercase Severity Formatting - NOTICE",
?_assertEqual(<<"NOTICE Simplist Format">>,
iolist_to_binary(format(rumMsg:new("Message",
Now,
notice,
[{pid, self()}],
[]),
[severity_upper, " Simplist Format"])))
},
{"Uppercase Severity Formatting - WARNING",
?_assertEqual(<<"WARNING Simplist Format">>,
iolist_to_binary(format(rumMsg:new("Message",
Now,
warning,
[{pid, self()}],
[]),
[severity_upper, " Simplist Format"])))
},
{"Uppercase Severity Formatting - ERROR",
?_assertEqual(<<"ERROR Simplist Format">>,
iolist_to_binary(format(rumMsg:new("Message",
Now,
error,
[{pid, self()}],
[]),
[severity_upper, " Simplist Format"])))
},
{"Uppercase Severity Formatting - CRITICAL",
?_assertEqual(<<"CRITICAL Simplist Format">>,
iolist_to_binary(format(rumMsg:new("Message",
Now,
critical,
[{pid, self()}],
[]),
[severity_upper, " Simplist Format"])))
},
{"Uppercase Severity Formatting - ALERT",
?_assertEqual(<<"ALERT Simplist Format">>,
iolist_to_binary(format(rumMsg:new("Message",
Now,
alert,
[{pid, self()}],
[]),
[severity_upper, " Simplist Format"])))
},
{"Uppercase Severity Formatting - EMERGENCY",
?_assertEqual(<<"EMERGENCY Simplist Format">>,
iolist_to_binary(format(rumMsg:new("Message",
Now,
emergency,
[{pid, self()}],
[]),
[severity_upper, " Simplist Format"])))
},
{"pterm presence test",
%% skip test on OTP < 21
case list_to_integer(erlang:system_info(otp_release)) >= 21 of
true ->
?_assertEqual(<<"Pterm is: something">>,
begin
persistent_term:put(thing, something),
Ret = iolist_to_binary(format(rumMsg:new("Message",
Now,
emergency,
[{pid, self()}],
[]),
["Pterm is: ", {pterm, thing}])),
persistent_term:erase(thing),
Ret
end);
false -> ?_assert(true)
end
},
{"pterm absence test",
?_assertEqual(<<"Pterm is: nothing">>,
iolist_to_binary(format(rumMsg:new("Message",
Now,
emergency,
[{pid, self()}],
[]),
["Pterm is: ", {pterm, thing, "nothing"}])))
},
{"node formatting basic",
begin
[N, "foo"] = format(rumMsg:new("Message",
Now,
info,
[{pid, self()}],
[]),
[node, "foo"]),
?_assertNotMatch(nomatch, re:run(N, <<"@">>))
end
}
].
-endif.

+ 0
- 91
src/rotator/rumRotatorIns.erl 查看文件

@ -11,10 +11,6 @@
, rotateLogFile/2 , rotateLogFile/2
]). ]).
-ifdef(TEST).
-include_lib("eunit/include/eunit.hrl").
-endif.
createLogFile(FileName, Buffer) -> createLogFile(FileName, Buffer) ->
openLogFile(FileName, Buffer). openLogFile(FileName, Buffer).
@ -104,90 +100,3 @@ tryUpdateCTime(Name, FileInfo) ->
_ -> _ ->
element(#file_info.ctime, FileInfo) element(#file_info.ctime, FileInfo)
end. end.
-ifdef(TEST).
rotate_file_test() ->
RotCount = 10,
{ok, TestDir} = rumUtil:create_test_dir(),
TestLog = filename:join(TestDir, "rotation.log"),
Outer = fun(N) ->
?assertEqual(ok, rumUtil:safe_write_file(TestLog, erlang:integer_to_list(N))),
Inner = fun(M) ->
File = lists:flatten([TestLog, $., erlang:integer_to_list(M)]),
?assert(filelib:is_regular(File)),
%% check the expected value is in the file
Number = erlang:list_to_binary(integer_to_list(N - M - 1)),
?assertEqual({ok, Number}, file:read_file(File))
end,
Count = erlang:min(N, RotCount),
% The first time through, Count == 0, so the sequence is empty,
% effectively skipping the inner loop so a rotation can occur that
% creates the file that Inner looks for.
% Don't shoot the messenger, it was worse before this refactoring.
lists:foreach(Inner, lists:seq(0, Count - 1)),
rotateLogFile(TestLog, RotCount)
end,
lists:foreach(Outer, lists:seq(0, (RotCount * 2))),
rumUtil:delete_test_dir(TestDir).
rotate_file_zero_count_test() ->
%% Test that a rotation count of 0 simply truncates the file
{ok, TestDir} = rumUtil:create_test_dir(),
TestLog = filename:join(TestDir, "rotation.log"),
?assertMatch(ok, rotateLogFile(TestLog, 0)),
?assertNot(filelib:is_regular(TestLog ++ ".0")),
?assertEqual(true, filelib:is_regular(TestLog)),
?assertEqual(1, length(filelib:wildcard(TestLog ++ "*"))),
%% assert the new file is 0 size:
case file:read_file_info(TestLog, [raw]) of
{ok, FInfo} ->
?assertEqual(0, FInfo#file_info.size);
_ ->
?assert(false)
end,
rumUtil:delete_test_dir(TestDir).
rotate_file_fail_test() ->
{ok, TestDir} = rumUtil:create_test_dir(),
TestLog = filename:join(TestDir, "rotation.log"),
%% set known permissions on it
ok = rumUtil:set_dir_permissions("u+rwx", TestDir),
%% write a file
?assertEqual(ok, rumUtil:safe_write_file(TestLog, "hello")),
case os:type() of
{win32, _} -> ok;
_ ->
%% hose up the permissions
ok = rumUtil:set_dir_permissions("u-w", TestDir),
?assertMatch({error, _}, rotateLogFile(TestLog, 10))
end,
%% check we still only have one file, rotation.log
?assertEqual([TestLog], filelib:wildcard(TestLog ++ "*")),
?assert(filelib:is_regular(TestLog)),
%% fix the permissions
ok = rumUtil:set_dir_permissions("u+w", TestDir),
?assertMatch(ok, rotateLogFile(TestLog, 10)),
?assert(filelib:is_regular(TestLog ++ ".0")),
?assertEqual(true, filelib:is_regular(TestLog)),
?assertEqual(2, length(filelib:wildcard(TestLog ++ "*"))),
%% assert the new file is 0 size:
case file:read_file_info(TestLog, [raw]) of
{ok, FInfo} ->
?assertEqual(0, FInfo#file_info.size);
_ ->
?assert(false)
end,
%% check that the .0 file now has the contents "hello"
?assertEqual({ok, <<"hello">>}, file:read_file(TestLog ++ ".0")),
rumUtil:delete_test_dir(TestDir).
-endif.

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

@ -1,6 +1,7 @@
-module(rumConfig). -module(rumConfig).
-include("rumDef.hrl"). -include("rumDef.hrl").
-include("rumCom.hrl").
-export([ -export([
init/0 init/0

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

@ -1,6 +1,7 @@
-module(rumMsg). -module(rumMsg).
-include("rumDef.hrl"). -include("rumDef.hrl").
-include("rumMsg.hrl").
-export([new/4, new/5]). -export([new/4, new/5]).
-export([message/1]). -export([message/1]).
@ -11,46 +12,35 @@
-export([metadata/1]). -export([metadata/1]).
-export([destinations/1]). -export([destinations/1]).
-opaque rumMsg() :: #rumMsg{}.
-export_type([rumMsg/0]).
%% create with provided timestamp, handy for testing mostly %% create with provided timestamp, handy for testing mostly
-spec new(list(), erlang:timestamp(), rumAtomLevel(), [tuple()], list()) -> rumMsg().
new(Msg, MsTick, Severity, Metadata, Destinations) -> new(Msg, MsTick, Severity, Metadata, Destinations) ->
TimeBinStr = rumUtil:msToBinStr(MsTick), TimeBinStr = rumUtil:msToBinStr(MsTick),
#rumMsg{message = Msg, datetime = TimeBinStr, timestamp = MsTick, severity = Severity, #rumMsg{message = Msg, datetime = TimeBinStr, timestamp = MsTick, severity = Severity,
metadata = Metadata, destinations = Destinations}. metadata = Metadata, destinations = Destinations}.
-spec new(list(), rumAtomLevel(), [tuple()], list()) -> rumMsg().
new(Msg, Severity, Metadata, Destinations) -> new(Msg, Severity, Metadata, Destinations) ->
NowMs = rumUtil:nowMs(), NowMs = rumUtil:nowMs(),
new(Msg, NowMs, Severity, Metadata, Destinations). new(Msg, NowMs, Severity, Metadata, Destinations).
-spec message(rumMsg()) -> list().
message(Msg) -> message(Msg) ->
Msg#rumMsg.message. Msg#rumMsg.message.
-spec timestamp(rumMsg()) -> erlang:timestamp().
timestamp(Msg) -> timestamp(Msg) ->
Msg#rumMsg.timestamp. Msg#rumMsg.timestamp.
-spec datetime(rumMsg()) -> {string(), string()}.
datetime(Msg) -> datetime(Msg) ->
Msg#rumMsg.datetime. Msg#rumMsg.datetime.
-spec severity(rumMsg()) -> rumAtomLevel().
severity(Msg) -> severity(Msg) ->
Msg#rumMsg.severity. Msg#rumMsg.severity.
-spec severity_as_int(rumMsg()) -> rumMaskLevel().
severity_as_int(Msg) -> severity_as_int(Msg) ->
rumUtil:levelToNum(Msg#rumMsg.severity). rumUtil:levelToNum(Msg#rumMsg.severity).
-spec metadata(rumMsg()) -> [tuple()].
metadata(Msg) -> metadata(Msg) ->
Msg#rumMsg.metadata. Msg#rumMsg.metadata.
-spec destinations(rumMsg()) -> list().
destinations(Msg) -> destinations(Msg) ->
Msg#rumMsg.destinations. Msg#rumMsg.destinations.

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

@ -637,350 +637,4 @@ get_opt(Key, Opts, Def) ->
Def; Def;
V -> V ->
element(2, V) element(2, V)
end.
-ifdef(TEST).
parse_test() ->
?assertEqual({ok, {undefined, undefined, 0, undefined}}, rumUtil:parseRotateSpec("$H0")),
?assertEqual({ok, {undefined, undefined, 59, undefined}}, rumUtil:parseRotateSpec("$H59")),
?assertEqual({ok, {undefined, 0, 0, undefined}}, rumUtil:parseRotateSpec("$D0")),
?assertEqual({ok, {undefined, 23, 0, undefined}}, rumUtil:parseRotateSpec("$D23")),
?assertEqual({ok, {day, 23, 0, 7}}, rumUtil:parseRotateSpec("$W7D23")),
?assertEqual({ok, {day, 16, 0, 5}}, rumUtil:parseRotateSpec("$W5D16")),
?assertEqual({ok, {day, 12, 30, 7}}, rumUtil:parseRotateSpec("$W7D12H30")),
?assertEqual({ok, {date, 0, 0, 1}}, rumUtil:parseRotateSpec("$M1D0")),
?assertEqual({ok, {date, 6, 0, 5}}, rumUtil:parseRotateSpec("$M5D6")),
?assertEqual({ok, {date, 0, 0, 5}}, rumUtil:parseRotateSpec("$M5")),
?assertEqual({ok, {date, 0, 0, 31}}, rumUtil:parseRotateSpec("$M31")),
?assertEqual({ok, {date, 1, 0, 31}}, rumUtil:parseRotateSpec("$M31D1")),
?assertEqual({ok, {last, 0, 0, undefined}}, rumUtil:parseRotateSpec("$ML")),
?assertEqual({ok, {last, 0, 0, undefined}}, rumUtil:parseRotateSpec("$Ml")),
?assertEqual({ok, {day, 0, 0, 5}}, rumUtil:parseRotateSpec("$W5")),
?assertEqual({ok, {date, 12, 36, 5}}, rumUtil:parseRotateSpec("$M5D12H36")),
ok.
parse_fail_test() ->
?assertEqual({error, invalid_date_spec}, rumUtil:parseRotateSpec("$H")),
?assertEqual({error, invalid_date_spec}, rumUtil:parseRotateSpec("$H60")),
?assertEqual({error, invalid_date_spec}, rumUtil:parseRotateSpec("$D")),
?assertEqual({error, invalid_date_spec}, rumUtil:parseRotateSpec("$D24")),
?assertEqual({error, invalid_date_spec}, rumUtil:parseRotateSpec("$W0")),
?assertEqual({error, invalid_date_spec}, rumUtil:parseRotateSpec("$W0D1")),
?assertEqual({error, invalid_date_spec}, rumUtil:parseRotateSpec("$M32")),
?assertEqual({error, invalid_date_spec}, rumUtil:parseRotateSpec("$M32D1")),
?assertEqual({error, invalid_date_spec}, rumUtil:parseRotateSpec("$")),
?assertEqual({error, invalid_date_spec}, rumUtil:parseRotateSpec("")),
?assertEqual({error, invalid_date_spec}, rumUtil:parseRotateSpec("$D15M5")),
?assertEqual({error, invalid_date_spec}, rumUtil:parseRotateSpec("$M5W5")),
ok.
rotation_calculation_test() ->
?assertMatch({{2000, 1, 1}, {13, 0, 0}},
rumUtil:calcNextRotateDt({undefined, undefined, 0, 0}, {{2000, 1, 1}, {12, 34, 43}})),
?assertMatch({{2000, 1, 1}, {12, 45, 0}},
rumUtil:calcNextRotateDt({undefined, undefined, 45, 0}, {{2000, 1, 1}, {12, 34, 43}})),
?assertMatch({{2000, 1, 2}, {0, 0, 0}},
rumUtil:calcNextRotateDt({undefined, undefined, 0, 0}, {{2000, 1, 1}, {23, 45, 43}})),
?assertMatch({{2000, 1, 2}, {0, 0, 0}},
rumUtil:calcNextRotateDt({undefined, 0, 0, 0}, {{2000, 1, 1}, {12, 34, 43}})),
?assertMatch({{2000, 1, 1}, {16, 0, 0}},
rumUtil:calcNextRotateDt({undefined, 16, 0, 0}, {{2000, 1, 1}, {12, 34, 43}})),
?assertMatch({{2000, 1, 2}, {12, 0, 0}},
rumUtil:calcNextRotateDt({undefined, 12, 0, 0}, {{2000, 1, 1}, {12, 34, 43}})),
?assertMatch({{2000, 2, 1}, {12, 0, 0}},
rumUtil:calcNextRotateDt({date, 12, 0, 1}, {{2000, 1, 1}, {12, 34, 43}})),
?assertMatch({{2000, 2, 1}, {12, 0, 0}},
rumUtil:calcNextRotateDt({date, 12, 0, 1}, {{2000, 1, 15}, {12, 34, 43}})),
?assertMatch({{2000, 2, 1}, {12, 0, 0}},
rumUtil:calcNextRotateDt({date, 12, 0, 1}, {{2000, 1, 2}, {12, 34, 43}})),
?assertMatch({{2000, 2, 1}, {12, 0, 0}},
rumUtil:calcNextRotateDt({date, 12, 0, 1}, {{2000, 1, 31}, {12, 34, 43}})),
?assertMatch({{2000, 1, 1}, {16, 0, 0}},
rumUtil:calcNextRotateDt({date, 16, 0, 1}, {{2000, 1, 1}, {12, 34, 43}})),
?assertMatch({{2000, 1, 15}, {16, 0, 0}},
rumUtil:calcNextRotateDt({date, 16, 0, 15}, {{2000, 1, 1}, {12, 34, 43}})),
?assertMatch({{2000, 1, 31}, {16, 0, 0}},
rumUtil:calcNextRotateDt({last, 16, 0, 0}, {{2000, 1, 1}, {12, 34, 43}})),
?assertMatch({{2000, 1, 31}, {16, 0, 0}},
rumUtil:calcNextRotateDt({last, 16, 0, 0}, {{2000, 1, 31}, {12, 34, 43}})),
?assertMatch({{2000, 2, 29}, {16, 0, 0}},
rumUtil:calcNextRotateDt({last, 16, 0, 0}, {{2000, 1, 31}, {17, 34, 43}})),
?assertMatch({{2001, 2, 28}, {16, 0, 0}},
rumUtil:calcNextRotateDt({last, 16, 0, 0}, {{2001, 1, 31}, {17, 34, 43}})),
?assertMatch({{2000, 1, 1}, {16, 0, 0}},
rumUtil:calcNextRotateDt({day, 16, 0, 6}, {{2000, 1, 1}, {12, 34, 43}})),
?assertMatch({{2000, 1, 8}, {16, 0, 0}},
rumUtil:calcNextRotateDt({day, 16, 0, 6}, {{2000, 1, 1}, {17, 34, 43}})),
?assertMatch({{2000, 1, 7}, {16, 0, 0}},
rumUtil:calcNextRotateDt({day, 16, 0, 5}, {{2000, 1, 1}, {17, 34, 43}})),
?assertMatch({{2000, 1, 3}, {16, 0, 0}},
rumUtil:calcNextRotateDt({day, 16, 0, 1}, {{2000, 1, 1}, {17, 34, 43}})),
?assertMatch({{2000, 1, 2}, {16, 0, 0}},
rumUtil:calcNextRotateDt({day, 16, 0, 7}, {{2000, 1, 1}, {17, 34, 43}})),
?assertMatch({{2000, 1, 9}, {16, 0, 0}},
rumUtil:calcNextRotateDt({day, 16, 0, 7}, {{2000, 1, 2}, {17, 34, 43}})),
?assertMatch({{2000, 2, 3}, {16, 0, 0}},
rumUtil:calcNextRotateDt({day, 16, 0, 4}, {{2000, 1, 29}, {17, 34, 43}})),
?assertMatch({{2000, 1, 7}, {16, 0, 0}},
rumUtil:calcNextRotateDt({day, 16, 0, 5}, {{2000, 1, 3}, {17, 34, 43}})),
?assertMatch({{2000, 1, 3}, {16, 0, 0}},
rumUtil:calcNextRotateDt({day, 16, 0, 1}, {{1999, 12, 28}, {17, 34, 43}})),
ok.
check_trace_test() ->
eRum:start(),
trace_filter(none),
%% match by module
?assertEqual([foo], check_traces([{module, ?MODULE}], ?EMERGENCY, [
{[{module, ?MODULE}], configToMask(emergency), foo},
{[{module, test}], configToMask(emergency), bar}], [])),
%% match by module, but other unsatisfyable attribute
?assertEqual([], check_traces([{module, ?MODULE}], ?EMERGENCY, [
{[{module, ?MODULE}, {foo, bar}], configToMask(emergency), foo},
{[{module, test}], configToMask(emergency), bar}], [])),
%% match by wildcard module
?assertEqual([bar], check_traces([{module, ?MODULE}], ?EMERGENCY, [
{[{module, ?MODULE}, {foo, bar}], configToMask(emergency), foo},
{[{module, '*'}], configToMask(emergency), bar}], [])),
%% wildcard module, one trace with unsatisfyable attribute
?assertEqual([bar], check_traces([{module, ?MODULE}], ?EMERGENCY, [
{[{module, '*'}, {foo, bar}], configToMask(emergency), foo},
{[{module, '*'}], configToMask(emergency), bar}], [])),
%% wildcard but not present custom trace attribute
?assertEqual([bar], check_traces([{module, ?MODULE}], ?EMERGENCY, [
{[{module, '*'}, {foo, '*'}], configToMask(emergency), foo},
{[{module, '*'}], configToMask(emergency), bar}], [])),
%% wildcarding a custom attribute works when it is present
?assertEqual([bar, foo], check_traces([{module, ?MODULE}, {foo, bar}], ?EMERGENCY, [
{[{module, '*'}, {foo, '*'}], configToMask(emergency), foo},
{[{module, '*'}], configToMask(emergency), bar}], [])),
%% denied by level
?assertEqual([], check_traces([{module, ?MODULE}, {foo, bar}], ?INFO, [
{[{module, '*'}, {foo, '*'}], configToMask(emergency), foo},
{[{module, '*'}], configToMask(emergency), bar}], [])),
%% allowed by level
?assertEqual([foo], check_traces([{module, ?MODULE}, {foo, bar}], ?INFO, [
{[{module, '*'}, {foo, '*'}], configToMask(debug), foo},
{[{module, '*'}], configToMask(emergency), bar}], [])),
?assertEqual([anythingbutnotice, infoandbelow, infoonly], check_traces([{module, ?MODULE}], ?INFO, [
{[{module, '*'}], configToMask('=debug'), debugonly},
{[{module, '*'}], configToMask('=info'), infoonly},
{[{module, '*'}], configToMask('<=info'), infoandbelow},
{[{module, '*'}], configToMask('!=info'), anythingbutinfo},
{[{module, '*'}], configToMask('!=notice'), anythingbutnotice}
], [])),
application:stop(lager),
application:stop(goldrush),
ok.
is_loggable_test_() ->
[
{"Loggable by severity only", ?_assert(isLoggAble(rumMsg:new("", alert, [], []), 2, me))},
{"Not loggable by severity only", ?_assertNot(isLoggAble(rumMsg:new("", critical, [], []), 1, me))},
{"Loggable by severity with destination", ?_assert(isLoggAble(rumMsg:new("", alert, [], [you]), 2, me))},
{"Not loggable by severity with destination", ?_assertNot(isLoggAble(rumMsg:new("", critical, [], [you]), 1, me))},
{"Loggable by destination overriding severity", ?_assert(isLoggAble(rumMsg:new("", critical, [], [me]), 1, me))}
].
format_time_test_() ->
[
?_assertEqual("2012-10-04 11:16:23.002",
begin
{D, T} = msToBinStr({{2012, 10, 04}, {11, 16, 23, 2}}),
lists:flatten([D, $ , T])
end),
?_assertEqual("2012-10-04 11:16:23.999",
begin
{D, T} = msToBinStr({{2012, 10, 04}, {11, 16, 23, 999}}),
lists:flatten([D, $ , T])
end),
?_assertEqual("2012-10-04 11:16:23",
begin
{D, T} = msToBinStr({{2012, 10, 04}, {11, 16, 23}}),
lists:flatten([D, $ , T])
end),
?_assertEqual("2012-10-04 00:16:23.092 UTC",
begin
{D, T} = msToBinStr({utc, {{2012, 10, 04}, {0, 16, 23, 92}}}),
lists:flatten([D, $ , T])
end),
?_assertEqual("2012-10-04 11:16:23 UTC",
begin
{D, T} = msToBinStr({utc, {{2012, 10, 04}, {11, 16, 23}}}),
lists:flatten([D, $ , T])
end)
].
config_to_levels_test() ->
?assertEqual([none], atomCfgToLevels('none')),
?assertEqual(0, configToMask('none')),
?assertEqual([debug], atomCfgToLevels('=debug')),
?assertEqual([debug], atomCfgToLevels('<info')),
?assertEqual(levels() -- [debug], atomCfgToLevels('!=debug')),
?assertEqual(levels() -- [debug], atomCfgToLevels('>debug')),
?assertEqual(levels() -- [debug], atomCfgToLevels('>=info')),
?assertEqual(levels() -- [debug], atomCfgToLevels('=>info')),
?assertEqual([debug, info, notice], atomCfgToLevels('<=notice')),
?assertEqual([debug, info, notice], atomCfgToLevels('=<notice')),
?assertEqual([debug], atomCfgToLevels('<info')),
?assertEqual([debug], atomCfgToLevels('!info')),
?assertError(badarg, atomCfgToLevels(ok)),
?assertError(badarg, atomCfgToLevels('<=>info')),
?assertError(badarg, atomCfgToLevels('=<=info')),
?assertError(badarg, atomCfgToLevels('<==>=<=>info')),
%% double negatives DO work, however
?assertEqual([debug], atomCfgToLevels('!!=debug')),
?assertEqual(levels() -- [debug], atomCfgToLevels('!!!=debug')),
ok.
config_to_mask_test() ->
?assertEqual(0, configToMask('none')),
?assertEqual(?DEBUG bor ?INFO bor ?NOTICE bor ?WARNING bor ?ERROR bor ?CRITICAL bor ?ALERT bor ?EMERGENCY, configToMask('debug')),
?assertEqual(?WARNING bor ?ERROR bor ?CRITICAL bor ?ALERT bor ?EMERGENCY, configToMask('warning')),
?assertEqual(?DEBUG bor ?NOTICE bor ?WARNING bor ?ERROR bor ?CRITICAL bor ?ALERT bor ?EMERGENCY, configToMask('!=info')),
ok.
mask_to_levels_test() ->
?assertEqual([], maskToLevels(0)),
?assertEqual([debug], maskToLevels(2#10000000)),
?assertEqual([debug, info], maskToLevels(2#11000000)),
?assertEqual([debug, info, emergency], maskToLevels(2#11000001)),
?assertEqual([debug, notice, error], maskToLevels(?DEBUG bor ?NOTICE bor ?ERROR)),
ok.
expand_path_test() ->
OldRootVal = application:get_env(lager, logRoot),
ok = application:unset_env(lager, logRoot),
?assertEqual(filename:absname("/foo/bar"), parsePath("/foo/bar")),
?assertEqual(filename:absname("foo/bar"), parsePath("foo/bar")),
ok = application:set_env(lager, logRoot, "log/dir"),
?assertEqual(filename:absname("/foo/bar"), parsePath("/foo/bar")), % Absolute path should not be changed
?assertEqual(filename:absname("log/dir/foo/bar"), parsePath("foo/bar")),
?assertEqual(filename:absname("log/dir/foo/bar"), parsePath("log/dir/foo/bar")), %% gh #304
case OldRootVal of
undefined -> application:unset_env(lager, logRoot);
{ok, Root} -> application:set_env(lager, logRoot, Root)
end,
ok.
sink_name_test_() ->
[
?_assertEqual(rumEvent, makeInnerSinkName(lager)),
?_assertEqual(audit_lager_event, makeInnerSinkName(audit))
].
create_test_dir() ->
{ok, Tmp} = get_temp_dir(),
Dir = filename:join([Tmp, "lager_test",
erlang:integer_to_list(erlang:phash2(os:timestamp()))]),
?assertEqual(ok, filelib:ensure_dir(Dir)),
TestDir = case file:make_dir(Dir) of
ok ->
Dir;
Err ->
?assertEqual({error, eexist}, Err),
create_test_dir()
end,
ok = application:set_env(lager, test_dir, TestDir),
{ok, TestDir}.
get_test_dir() ->
case application:get_env(lager, test_dir) of
undefined ->
create_test_dir();
{ok, _} = Res ->
Res
end.
get_temp_dir() ->
Tmp = case os:getenv("TEMP") of
false ->
case os:getenv("TMP") of
false -> "/tmp";
Dir1 -> Dir1
end;
Dir0 -> Dir0
end,
?assertEqual(true, filelib:is_dir(Tmp)),
{ok, Tmp}.
delete_test_dir() ->
{ok, TestDir} = get_test_dir(),
ok = delete_test_dir(TestDir).
delete_test_dir(TestDir) ->
ok = application:unset_env(lager, test_dir),
ok =
case os:type() of
{win32, _} ->
application:stop(lager),
do_delete_test_dir(TestDir);
{_, _} ->
do_delete_test_dir(TestDir)
end.
do_delete_test_dir(Dir) ->
ListRet = file:list_dir_all(Dir),
?assertMatch({ok, _}, ListRet),
{_, Entries} = ListRet,
lists:foreach(
fun(Entry) ->
FsElem = filename:join(Dir, Entry),
case filelib:is_dir(FsElem) of
true ->
delete_test_dir(FsElem);
_ ->
case file:delete(FsElem) of
ok -> ok;
Error ->
io:format(standard_error, "[ERROR]: error deleting file ~p~n", [FsElem]),
?assertEqual(ok, Error)
end
end
end, Entries),
?assertEqual(ok, file:del_dir(Dir)).
do_delete_file(_FsElem, 0) ->
?assert(false);
do_delete_file(FsElem, Attempts) ->
case file:delete(FsElem) of
ok -> ok;
_Error ->
do_delete_file(FsElem, Attempts - 1)
end.
set_dir_permissions(Perms, Dir) ->
do_set_dir_permissions(os:type(), Perms, Dir).
do_set_dir_permissions({win32, _}, _Perms, _Dir) ->
ok;
do_set_dir_permissions({unix, _}, Perms, Dir) ->
os:cmd("chmod -R " ++ Perms ++ " " ++ Dir),
ok.
safe_application_load(App) ->
case application:load(App) of
ok ->
ok;
{error, {already_loaded, App}} ->
ok;
Error ->
?assertEqual(ok, Error)
end.
safe_write_file(File, Content) ->
% Note: ensures that the new creation time is at least one second
% in the future
?assertEqual(ok, file:write_file(File, Content)),
Ctime0 = calendar:local_time(),
Ctime0Sec = calendar:datetime_to_gregorian_seconds(Ctime0),
Ctime1Sec = Ctime0Sec + 1,
Ctime1 = calendar:gregorian_seconds_to_datetime(Ctime1Sec),
{ok, FInfo0} = file:read_file_info(File, [raw]),
FInfo1 = FInfo0#file_info{ctime = Ctime1},
?assertEqual(ok, file:write_file_info(File, FInfo1, [raw])).
-endif.
end.

+ 0
- 101
src/watcher/rumHWatcherSrv.erl 查看文件

@ -120,104 +120,3 @@ installHandler(Module, Config, Sink) ->
erlang:send_after(5000, self(), mReinstallHandler), erlang:send_after(5000, self(), mReinstallHandler),
ok ok
end. end.
-ifdef(TEST).
from_now(Seconds) ->
{Mega, Secs, Micro} = os:timestamp(),
{Mega, Secs + Seconds, Micro}.
reinstall_on_initial_failure_test_() ->
{timeout, 60000,
[
fun() ->
error_logger:tty(false),
application:load(lager),
application:set_env(lager, handlers, [{lager_test_backend, info}, {lager_crash_backend, [from_now(2), undefined]}]),
application:set_env(lager, errLoggerRedirect, false),
application:unset_env(lager, crash_log),
eRum:start(),
try
{_Level, _Time, Message, _Metadata} = lager_test_backend:pop(),
?assertMatch("Lager failed to install handler lager_crash_backend into lager_event, retrying later :" ++ _, lists:flatten(Message)),
timer:sleep(6000),
lager_test_backend:flush(),
?assertEqual(0, lager_test_backend:count()),
?assert(lists:member(lager_crash_backend, gen_event:which_handlers(rumEvent)))
after
application:stop(lager),
application:stop(goldrush),
error_logger:tty(true)
end
end
]
}.
reinstall_on_runtime_failure_test_() ->
{timeout, 60000,
[
fun() ->
error_logger:tty(false),
application:load(lager),
application:set_env(lager, handlers, [{lager_test_backend, info}, {lager_crash_backend, [undefined, from_now(5)]}]),
application:set_env(lager, errLoggerRedirect, false),
application:unset_env(lager, crash_log),
eRum:start(),
try
?assert(lists:member(lager_crash_backend, gen_event:which_handlers(rumEvent))),
timer:sleep(6000),
pop_until("Lager event handler lager_crash_backend exited with reason crash", fun lists:flatten/1),
pop_until("Lager failed to install handler lager_crash_backend into lager_event, retrying later",
fun(Msg) -> string:substr(lists:flatten(Msg), 1, 84) end),
?assertEqual(false, lists:member(lager_crash_backend, gen_event:which_handlers(rumEvent)))
after
application:stop(lager),
application:stop(goldrush),
error_logger:tty(true)
end
end
]
}.
reinstall_handlers_after_killer_hwm_test_() ->
{timeout, 60000,
[
fun() ->
error_logger:tty(false),
application:load(lager),
application:set_env(lager, handlers, [{lager_manager_killer, [1000, 5000]}]),
application:set_env(lager, errLoggerRedirect, false),
application:set_env(lager, killerReTime, 5000),
application:unset_env(lager, crash_log),
eRum:start(),
eRum:trace_file("foo", [{foo, "bar"}], error),
L = length(gen_event:which_handlers(rumEvent)),
try
rumMgrKiller:kill_me(),
timer:sleep(6000),
?assertEqual(L, length(gen_event:which_handlers(rumEvent))),
file:delete("foo")
after
application:stop(lager),
application:stop(goldrush),
error_logger:tty(true)
end
end
]
}.
pop_until(String, Fun) ->
try_backend_pop(lager_test_backend:pop(), String, Fun).
try_backend_pop(undefined, String, _Fun) ->
throw("Not found: " ++ String);
try_backend_pop({_Severity, _Date, Msg, _Metadata}, String, Fun) ->
case Fun(Msg) of
String ->
ok;
_ ->
try_backend_pop(lager_test_backend:pop(), String, Fun)
end.
-endif.

+ 0
- 22
test/compress_pr_record_test.erl 查看文件

@ -1,22 +0,0 @@
-module(compress_pr_record_test).
-compile([{parse_transform, lager_transform}]).
-record(a, {field1 :: term(),
field2 :: term(),
foo :: term(),
bar :: term(),
baz :: term(),
zyu :: term(),
zix :: term()}).
-ifdef(TEST).
-include_lib("eunit/include/eunit.hrl").
-endif.
nested_record_test() ->
A = #a{field1 = "Notice me senpai"},
Pr_A = eRum:pr(A, ?MODULE),
Pr_A_Comp = eRum:pr(A, ?MODULE, [compress]),
?assertMatch({'$lager_record', a, [{field1, "Notice me senpai"}, {field2, undefined} | _]}, Pr_A),
?assertEqual({'$lager_record', a, [{field1, "Notice me senpai"}]}, Pr_A_Comp).

+ 0
- 109
test/crash.erl 查看文件

@ -1,109 +0,0 @@
%% a module that crashes in just about every way possible
-module(crash).
-behaviour(gen_server).
-export([init/1, handle_call/3, handle_cast/2, handle_info/2, terminate/2, code_change/3]).
-export([start/0]).
-record(state, {
host :: term(),
port :: term()
}).
start() ->
gen_server:start({local, ?MODULE}, ?MODULE, [], []).
init(_) ->
{ok, {}}.
handle_call(undef, _, State) ->
{reply, ?MODULE:booger(), State};
handle_call(badfun, _, State) ->
M = booger,
{reply, M(), State};
handle_call(bad_return, _, _) ->
bleh;
handle_call(bad_return_string, _, _) ->
{tuple, {tuple, "string"}};
handle_call(case_clause, _, State) ->
case State of
goober ->
{reply, ok, State}
end;
handle_call(case_clause_string, _, State) ->
Foo = atom_to_list(?MODULE),
case Foo of
State ->
{reply, ok, State}
end;
handle_call(if_clause, _, State) ->
if State == 1 ->
{reply, ok, State}
end;
handle_call(try_clause, _, State) ->
Res = try tuple_to_list(State) of
[_A, _B] -> ok
catch
_:_ -> ok
end,
{reply, Res, State};
handle_call(badmatch, _, State) ->
{A, B, C} = State,
{reply, [A, B, C], State};
handle_call(badrecord, _, State) ->
Host = State#state.host,
{reply, Host, State};
handle_call(function_clause, _, State) ->
{reply, function(State), State};
handle_call(badarith, _, State) ->
Res = 1 / length(tuple_to_list(State)),
{reply, Res, State};
handle_call(badarg1, _, State) ->
Res = list_to_binary(["foo", bar]),
{reply, Res, State};
handle_call(badarg2, _, State) ->
Res = erlang:iolist_to_binary(["foo", bar]),
{reply, Res, State};
handle_call(system_limit, _, State) ->
Res = list_to_atom(lists:flatten(lists:duplicate(256, "a"))),
{reply, Res, State};
handle_call(process_limit, _, State) ->
%% run with +P 300 to make this crash
[erlang:spawn(fun() -> timer:sleep(5000) end) || _ <- lists:seq(0, 500)],
{reply, ok, State};
handle_call(port_limit, _, State) ->
[erlang:open_port({spawn, "ls"}, []) || _ <- lists:seq(0, 1024)],
{reply, ok, State};
handle_call(noproc, _, State) ->
Res = gen_event:call(foo, bar, baz),
{reply, Res, State};
handle_call(noproc_proc_lib, _, State) ->
Res = proc_lib:stop(foo),
{reply, Res, State};
handle_call(badarity, _, State) ->
F = fun(A, B, C) -> A + B + C end,
Res = F(State),
{reply, Res, State};
handle_call(throw, _, _State) ->
throw(a_ball);
handle_call(_Call, _From, State) ->
{reply, ok, State}.
handle_cast(_Cast, State) ->
{noreply, State}.
handle_info(_Info, State) ->
{noreply, State}.
terminate(_, _) ->
ok.
code_change(_, State, _) ->
{ok, State}.
function(X) when is_list(X) ->
ok.

+ 0
- 35
test/crash_fsm.erl 查看文件

@ -1,35 +0,0 @@
-module(crash_fsm).
-behaviour(gen_fsm).
-compile([{nowarn_deprecated_function, [{gen_fsm, start, 4}, {gen_fsm, sync_send_event, 2}]}]).
-export([start/0, crash/0, state1/2]).
%% gen_fsm callbacks
-export([init/1, handle_event/3, handle_sync_event/4, handle_info/3,
terminate/3, code_change/4]).
-record(state, {}).
start() ->
gen_fsm:start({local, ?MODULE}, ?MODULE, [], []).
crash() ->
gen_fsm:sync_send_event(?MODULE, crash).
%% gen_fsm callbacks
init([]) ->
{ok, state1, #state{}}.
handle_event(_Event, StateName, State) ->
{next_state, StateName, State}.
handle_sync_event(_Event, _From, StateName, State) ->
Reply = ok,
{reply, Reply, StateName, State}.
handle_info(_Info, StateName, State) ->
{next_state, StateName, State}.
terminate(_Reason, _StateName, _State) ->
ok.
code_change(_OldVersion, StateName, State, _Extra) ->
{ok, StateName, State}.
state1(_Event, S) -> {next_state, state1, S}.

+ 0
- 46
test/crash_statem.erl 查看文件

@ -1,46 +0,0 @@
-module(crash_statem).
%% we're only going to compile this on OTP 19+
-behaviour(gen_statem).
-export([
start/0,
crash/0,
stop/1,
timeout/0,
handle_event/4
]).
-export([terminate/3, code_change/4, init/1, callback_mode/0]).
start() ->
gen_statem:start({local, ?MODULE}, ?MODULE, [], []).
crash() ->
gen_statem:call(?MODULE, boom).
stop(Reason) ->
gen_statem:call(?MODULE, {stop, Reason}).
timeout() ->
gen_statem:call(?MODULE, timeout).
%% Mandatory callback functions
terminate(_Reason, _State, _Data) -> ok.
code_change(_Vsn, State, Data, _Extra) -> {ok, State, Data}.
init([]) ->
%% insert rant here about breaking changes in minor versions...
case erlang:system_info(version) of
"8.0" -> {callback_mode(), state1, undefined};
_ -> {ok, state1, undefined}
end.
callback_mode() -> handle_event_function.
%%% state callback(s)
handle_event(state_timeout, timeout, state1, _) ->
{stop, timeout};
handle_event({call, _From}, timeout, _Arg, _Data) ->
{keep_state_and_data, [{state_timeout, 0, timeout}]};
handle_event({call, _From}, {stop, Reason}, state1, _Data) ->
{stop, Reason}.

+ 0
- 15
test/lager_app_tests.erl 查看文件

@ -1,15 +0,0 @@
-module(lager_app_tests).
-compile([{parse_transform, lager_transform}]).
-include_lib("eunit/include/eunit.hrl").
get_env_test() ->
application:set_env(myapp, mykey1, <<"Value">>),
?assertEqual(<<"Some">>, lager_app:get_env(myapp, mykey0, <<"Some">>)),
?assertEqual(<<"Value">>, lager_app:get_env(myapp, mykey1, <<"Some">>)),
ok.

+ 0
- 68
test/lager_crash_backend.erl 查看文件

@ -1,68 +0,0 @@
%% Copyright (c) 2011-2012 Basho Technologies, Inc. All Rights Reserved.
%%
%% This file is provided to you under the Apache License,
%% Version 2.0 (the "License"); you may not use this file
%% except in compliance with the License. You may obtain
%% a copy of the License at
%%
%% http://www.apache.org/licenses/LICENSE-2.0
%%
%% Unless required by applicable law or agreed to in writing,
%% software distributed under the License is distributed on an
%% "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
%% KIND, either express or implied. See the License for the
%% specific language governing permissions and limitations
%% under the License.
-module(lager_crash_backend).
-include("rumDef.hrl").
-behaviour(gen_event).
-export([init/1, handle_call/2, handle_event/2, handle_info/2, terminate/2,
code_change/3]).
-ifdef(TEST).
-include_lib("eunit/include/eunit.hrl").
-endif.
init([CrashBefore, CrashAfter]) ->
case is_tuple(CrashBefore) andalso (timer:now_diff(CrashBefore, os:timestamp()) > 0) of
true ->
%?debugFmt("crashing!~n", []),
{error, crashed};
_ ->
%?debugFmt("Not crashing!~n", []),
case is_tuple(CrashAfter) of
true ->
CrashTime = timer:now_diff(CrashAfter, os:timestamp()) div 1000,
case CrashTime > 0 of
true ->
%?debugFmt("crashing in ~p~n", [CrashTime]),
erlang:send_after(CrashTime, self(), crash),
{ok, {}};
_ -> {error, crashed}
end;
_ ->
{ok, {}}
end
end.
handle_call(_Request, State) ->
{ok, ok, State}.
handle_event(_Event, State) ->
{ok, State}.
handle_info(crash, _State) ->
%?debugFmt("Time to crash!~n", []),
crash;
handle_info(_Info, State) ->
{ok, State}.
terminate(_Reason, _State) ->
ok.
code_change(_OldVsn, State, _Extra) ->
{ok, State}.

+ 0
- 125
test/lager_manager_killer_test.erl 查看文件

@ -1,125 +0,0 @@
-module(lager_manager_killer_test).
-author("Sungjin Park <jinni.park@gmail.com>").
-compile([{parse_transform, lager_transform}]).
-ifdef(TEST).
-include_lib("eunit/include/eunit.hrl").
-define(TEST_SINK_NAME, '__lager_test_sink'). %% <-- used by parse transform
-define(TEST_SINK_EVENT, '__lager_test_sink_lager_event'). %% <-- used by lager API calls and internals for gen_event
overload_test_() ->
{timeout, 60,
fun() ->
application:stop(lager),
application:load(lager),
Delay = 1000, % sleep 1 sec on every log
KillerHWM = 10, % kill the manager if there are more than 10 pending logs
KillerReinstallAfter = 1000, % reinstall killer after 1 sec
application:set_env(lager, handlers, [{lager_slow_backend, [{delay, Delay}]}]),
application:set_env(lager, asyncThreshold, undefined),
application:set_env(lager, errLoggerRedirect, true),
application:set_env(lager, killerHwm, KillerHWM),
application:set_env(lager, killerReTime, KillerReinstallAfter),
ensure_started(lager),
rumConfig:set(async, true),
Manager = whereis(rumEvent),
erlang:trace(all, true, [procs]),
[eRum:info("~p'th message", [N]) || N <- lists:seq(1, KillerHWM + 2)],
Margin = 100,
ok = confirm_manager_exit(Manager, Delay + Margin),
ok = confirm_sink_reregister(rumEvent, Margin),
erlang:trace(all, false, [procs]),
wait_until(fun() ->
case proplists:get_value(lager_manager_killer, gen_event:which_handlers(rumEvent)) of
[] -> false;
_ -> true
end
end, Margin, 15),
wait_until(fun() ->
case gen_event:call(rumEvent, lager_manager_killer, get_settings) of
[KillerHWM, KillerReinstallAfter] -> true;
_Other -> false
end
end, Margin, 15),
application:stop(lager)
end}.
overload_alternate_sink_test_() ->
{timeout, 60,
fun() ->
application:stop(lager),
application:load(lager),
Delay = 1000, % sleep 1 sec on every log
KillerHWM = 10, % kill the manager if there are more than 10 pending logs
KillerReinstallAfter = 1000, % reinstall killer after 1 sec
application:set_env(lager, handlers, []),
application:set_env(lager, extraSinks, [{?TEST_SINK_EVENT, [
{handlers, [{lager_slow_backend, [{delay, Delay}]}]},
{killerHwm, KillerHWM},
{killerReTime, KillerReinstallAfter},
{asyncThreshold, undefined}
]}]),
application:set_env(lager, errLoggerRedirect, true),
ensure_started(lager),
rumConfig:set({?TEST_SINK_EVENT, async}, true),
Manager = whereis(?TEST_SINK_EVENT),
erlang:trace(all, true, [procs]),
[?TEST_SINK_NAME:info("~p'th message", [N]) || N <- lists:seq(1, KillerHWM + 2)],
Margin = 100,
ok = confirm_manager_exit(Manager, Delay + Margin),
ok = confirm_sink_reregister(?TEST_SINK_EVENT, Margin),
erlang:trace(all, false, [procs]),
wait_until(fun() ->
case proplists:get_value(lager_manager_killer, gen_event:which_handlers(?TEST_SINK_EVENT)) of
[] -> false;
_ -> true
end
end, Margin, 15),
wait_until(fun() ->
case gen_event:call(?TEST_SINK_EVENT, lager_manager_killer, get_settings) of
[KillerHWM, KillerReinstallAfter] -> true;
_Other -> false
end
end, Margin, 15),
application:stop(lager)
end}.
ensure_started(App) ->
case application:start(App) of
ok ->
ok;
{error, {not_started, Dep}} ->
ensure_started(Dep),
ensure_started(App)
end.
confirm_manager_exit(Manager, Delay) ->
receive
{trace, Manager, exit, killed} ->
?debugFmt("Manager ~p killed", [Manager]);
Other ->
?debugFmt("OTHER MSG: ~p", [Other]),
confirm_manager_exit(Manager, Delay)
after Delay ->
?assert(false)
end.
confirm_sink_reregister(Sink, Delay) ->
receive
{trace, _Pid, register, Sink} ->
?assertNot(lists:member(lager_manager_killer, gen_event:which_handlers(Sink)))
after Delay ->
?assert(false)
end.
wait_until(_Fun, _Delay, 0) ->
{error, too_many_retries};
wait_until(Fun, Delay, Retries) ->
case Fun() of
true -> ok;
false -> timer:sleep(Delay), wait_until(Fun, Delay, Retries - 1)
end.
-endif.

+ 0
- 24
test/lager_metadata_whitelist_test.erl 查看文件

@ -1,24 +0,0 @@
-module(lager_metadata_whitelist_test).
-ifdef(TEST).
-include_lib("eunit/include/eunit.hrl").
setup() ->
ok = error_logger:tty(false),
ok = rumUtil:safe_application_load(lager),
ok = application:set_env(lager, handlers, [{lager_common_test_backend, info}]),
ok = application:set_env(lager, errLoggerRedirect, false),
ok = application:unset_env(lager, traces),
ok = eRum:start(),
ok = timer:sleep(250),
ok.
cleanup(_) ->
ok = application:unset_env(lager, metadataWhitelist),
catch ets:delete(lager_config), %% kill the ets config table with fire
ok = application:stop(lager),
ok = application:stop(goldrush),
ok = error_logger:tty(true).
-endif.

+ 0
- 185
test/lager_rotate.erl 查看文件

@ -1,185 +0,0 @@
%% -------------------------------------------------------------------
%%
%% Copyright (c) 2016-2017 Basho Technologies, Inc.
%%
%% This file is provided to you under the Apache License,
%% Version 2.0 (the "License"); you may not use this file
%% except in compliance with the License. You may obtain
%% a copy of the License at
%%
%% http://www.apache.org/licenses/LICENSE-2.0
%%
%% Unless required by applicable law or agreed to in writing,
%% software distributed under the License is distributed on an
%% "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
%% KIND, either express or implied. See the License for the
%% specific language governing permissions and limitations
%% under the License.
%%
%% -------------------------------------------------------------------
-module(lager_rotate).
-ifdef(TEST).
-include_lib("eunit/include/eunit.hrl").
-endif.
-record(state, {
dir :: string(),
log1 :: string(),
log1r :: string(),
log2 :: string(),
log2r :: string(),
sink :: string(),
sinkr :: string()
}).
rotate_test_() ->
{foreach,
fun() ->
{ok, Dir} = rumUtil:create_test_dir(),
Log1 = filename:join(Dir, "test1.log"),
Log2 = filename:join(Dir, "test2.log"),
Sink = filename:join(Dir, "sink.log"),
State = #state{
dir = Dir,
log1 = Log1,
log1r = Log1 ++ ".0",
log2 = Log2,
log2r = Log2 ++ ".0",
sink = Sink,
sinkr = Sink ++ ".0"
},
file:write_file(Log1, []),
file:write_file(Log2, []),
file:write_file(Sink, []),
error_logger:tty(false),
application:load(lager),
application:set_env(lager, handlers, [
{lager_file_backend, [{file, Log1}, {level, info}]},
{lager_file_backend, [{file, Log2}, {level, info}]}]),
application:set_env(lager, extraSinks, [
{sink_event,
[{handlers,
[{lager_file_backend, [{file, Sink}, {level, info}]}]}
]}]),
application:set_env(lager, errLoggerRedirect, false),
application:set_env(lager, asyncThreshold, undefined),
eRum:start(),
timer:sleep(1000),
State
end,
fun(#state{}) ->
ok = application:stop(lager),
ok = application:stop(goldrush),
ok = rumUtil:delete_test_dir(),
ok = error_logger:tty(true)
end, [
fun(State) ->
{"Rotate single file",
fun() ->
eRum:log(error, self(), "Test message 1"),
eRum:log(sink_event, error, self(), "Sink test message 1", []),
eRum:rotate_handler({lager_file_backend, State#state.log1}),
ok = wait_until(fun() -> filelib:is_regular(State#state.log1r) end, 10),
eRum:log(error, self(), "Test message 2"),
eRum:log(sink_event, error, self(), "Sink test message 2", []),
{ok, File1} = file:read_file(State#state.log1),
{ok, File2} = file:read_file(State#state.log2),
{ok, SinkFile} = file:read_file(State#state.sink),
{ok, File1Old} = file:read_file(State#state.log1r),
have_no_log(File1, <<"Test message 1">>),
have_log(File1, <<"Test message 2">>),
have_log(File2, <<"Test message 1">>),
have_log(File2, <<"Test message 2">>),
have_log(File1Old, <<"Test message 1">>),
have_no_log(File1Old, <<"Test message 2">>),
have_log(SinkFile, <<"Sink test message 1">>),
have_log(SinkFile, <<"Sink test message 2">>)
end}
end,
fun(State) ->
{"Rotate sink",
fun() ->
eRum:log(error, self(), "Test message 1"),
eRum:log(sink_event, error, self(), "Sink test message 1", []),
eRum:rotate_sink(sink_event),
ok = wait_until(fun() -> filelib:is_regular(State#state.sinkr) end, 10),
eRum:log(error, self(), "Test message 2"),
eRum:log(sink_event, error, self(), "Sink test message 2", []),
{ok, File1} = file:read_file(State#state.log1),
{ok, File2} = file:read_file(State#state.log2),
{ok, SinkFile} = file:read_file(State#state.sink),
{ok, SinkFileOld} = file:read_file(State#state.sinkr),
have_log(File1, <<"Test message 1">>),
have_log(File1, <<"Test message 2">>),
have_log(File2, <<"Test message 1">>),
have_log(File2, <<"Test message 2">>),
have_log(SinkFileOld, <<"Sink test message 1">>),
have_no_log(SinkFileOld, <<"Sink test message 2">>),
have_no_log(SinkFile, <<"Sink test message 1">>),
have_log(SinkFile, <<"Sink test message 2">>)
end}
end,
fun(State) ->
{"Rotate all",
fun() ->
eRum:log(error, self(), "Test message 1"),
eRum:log(sink_event, error, self(), "Sink test message 1", []),
eRum:rotate_all(),
ok = wait_until(fun() -> filelib:is_regular(State#state.sinkr) end, 10),
eRum:log(error, self(), "Test message 2"),
eRum:log(sink_event, error, self(), "Sink test message 2", []),
{ok, File1} = file:read_file(State#state.log1),
{ok, File2} = file:read_file(State#state.log2),
{ok, SinkFile} = file:read_file(State#state.sink),
{ok, File1Old} = file:read_file(State#state.log1r),
{ok, File2Old} = file:read_file(State#state.log2r),
{ok, SinkFileOld} = file:read_file(State#state.sinkr),
have_no_log(File1, <<"Test message 1">>),
have_log(File1, <<"Test message 2">>),
have_no_log(File2, <<"Test message 1">>),
have_log(File2, <<"Test message 2">>),
have_no_log(SinkFile, <<"Sink test message 1">>),
have_log(SinkFile, <<"Sink test message 2">>),
have_log(SinkFileOld, <<"Sink test message 1">>),
have_no_log(SinkFileOld, <<"Sink test message 2">>),
have_log(File1Old, <<"Test message 1">>),
have_no_log(File1Old, <<"Test message 2">>),
have_log(File2Old, <<"Test message 1">>),
have_no_log(File2Old, <<"Test message 2">>)
end}
end
]}.
have_log(Data, Log) ->
{_, _} = binary:match(Data, Log).
have_no_log(Data, Log) ->
nomatch = binary:match(Data, Log).
wait_until(_Fun, 0) -> {error, too_many_retries};
wait_until(Fun, Retry) ->
case Fun() of
true -> ok;
false ->
timer:sleep(500),
wait_until(Fun, Retry - 1)
end.

+ 0
- 34
test/lager_slow_backend.erl 查看文件

@ -1,34 +0,0 @@
-module(lager_slow_backend).
-author("Sungjin Park <jinni.park@gmail.com>").
-behavior(gen_event).
-export([init/1, handle_call/2, handle_event/2, handle_info/2, terminate/2, code_change/3]).
-include("rumDef.hrl").
-record(state, {
delay :: non_neg_integer()
}).
init([{delay, Delay}]) ->
{ok, #state{delay = Delay}}.
handle_call(mGetLogLevel, State) ->
{ok, rumUtil:configToMask(debug), State};
handle_call(_Request, State) ->
{ok, ok, State}.
handle_event({mWriteLog, _Message}, State) ->
timer:sleep(State#state.delay),
{ok, State};
handle_event(_Event, State) ->
{ok, State}.
handle_info(_Info, State) ->
{ok, State}.
terminate(_Reason, _State) ->
ok.
code_change(_OldVsn, State, _Extra) ->
{ok, State}.

+ 0
- 1927
test/lager_test_backend.erl
文件差异内容过多而无法显示
查看文件


+ 0
- 193
test/lager_test_function_transform.erl 查看文件

@ -1,193 +0,0 @@
%% -------------------------------------------------------------------
%%
%% Copyright (c) 2011-2017 Basho Technologies, Inc.
%%
%% This file is provided to you under the Apache License,
%% Version 2.0 (the "License"); you may not use this file
%% except in compliance with the License. You may obtain
%% a copy of the License at
%%
%% http://www.apache.org/licenses/LICENSE-2.0
%%
%% Unless required by applicable law or agreed to in writing,
%% software distributed under the License is distributed on an
%% "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
%% KIND, either express or implied. See the License for the
%% specific language governing permissions and limitations
%% under the License.
%%
%% -------------------------------------------------------------------
-module(lager_test_function_transform).
-include("rumDef.hrl").
-compile([{nowarn_deprecated_function, [{erlang, now, 0}]}]).
-lager_function_transforms([
{returns_static_emit, on_emit, {lager_test_function_transform, transform_static}},
{returns_dynamic_emit, on_emit, {lager_test_function_transform, transform_dynamic}},
{returns_undefined_emit, on_emit, {not_real_module_fake, fake_not_real_function}},
{returns_static_log, on_log, {lager_test_function_transform, transform_static}},
{returns_dynamic_log, on_log, {lager_test_function_transform, transform_dynamic}}
]).
-compile({parse_transform, lager_transform}).
-ifdef(TEST).
-include_lib("eunit/include/eunit.hrl").
-export([
transform_static/0,
transform_dynamic/0
]).
-endif.
-ifdef(TEST).
transform_static() ->
static_result.
transform_dynamic() ->
erlang:now().
not_running_test() ->
?assertEqual({error, lager_not_running}, eRum:log(info, self(), "not running")).
setup() ->
ok = error_logger:tty(false),
ok = rumUtil:safe_application_load(lager),
ok = application:set_env(lager, handlers, [{lager_test_backend, info}]),
ok = application:set_env(lager, errLoggerRedirect, false),
ok = application:unset_env(lager, traces),
ok = eRum:start(),
%% There is a race condition between the application start up, lager logging its own
%% start up condition and several tests that count messages or parse the output of
%% tests. When the lager start up message wins the race, it causes these tests
%% which parse output or count message arrivals to fail.
%%
%% We introduce a sleep here to allow `flush' to arrive *after* the start up
%% message has been received and processed.
%%
%% This race condition was first exposed during the work on
%% 4b5260c4524688b545cc12da6baa2dfa4f2afec9 which introduced the lager
%% manager killer PR.
ok = timer:sleep(250),
ok = gen_event:call(rumEvent, lager_test_backend, flush).
cleanup(_) ->
catch ets:delete(lager_config), %% kill the ets config table with fire
ok = application:stop(lager),
ok = application:stop(goldrush),
ok = error_logger:tty(true).
transform_function_test_() ->
{foreach,
fun setup/0,
fun cleanup/1,
[
{"observe that there is nothing up my sleeve",
fun() ->
?assertEqual(undefined, lager_test_backend:pop()),
?assertEqual(0, lager_test_backend:count())
end
},
{"logging works",
fun() ->
eRum:warning("test message"),
?assertEqual(1, lager_test_backend:count()),
{Level, _Time, Message, _Metadata} = lager_test_backend:pop(),
?assertMatch(Level, rumUtil:levelToNum(warning)),
?assertEqual("test message", Message),
ok
end
},
{"Testing calling a function returns the same content on emit",
fun() ->
eRum:warning("static message"),
?assertEqual(1, lager_test_backend:count()),
{_Level, _Time, _Message, Metadata} = lager_test_backend:pop(),
Function = proplists:get_value(returns_static_emit, Metadata),
?assertEqual(transform_static(), Function()),
ok
end
},
{"Testing calling a function which returns content which can change on emit",
fun() ->
eRum:warning("dynamic message"),
?assertEqual(1, lager_test_backend:count()),
{_Level, _Time, _Message, Metadata} = lager_test_backend:pop(),
Function = proplists:get_value(returns_dynamic_emit, Metadata),
?assert(Function() =< Function()),
?assert(Function() =< Function()),
?assert(Function() =< Function()),
?assert(Function() =< Function()),
ok
end
},
{"Testing a undefined function returns undefined on emit",
fun() ->
eRum:warning("Undefined error"),
?assertEqual(1, lager_test_backend:count()),
{_Level, _Time, _Message, Metadata} = lager_test_backend:pop(),
Function = proplists:get_value(returns_undefined_emit, Metadata),
[{module, Module}, {name, Name} | _] = erlang:fun_info(Function),
?assertNot(erlang:function_exported(Module, Name, 0)),
ok
end
},
{"Testing calling a function returns the same content on log",
fun() ->
eRum:warning("static message"),
?assertEqual(1, lager_test_backend:count()),
{_Level, _Time, _Message, Metadata} = lager_test_backend:pop(),
?assertEqual(transform_static(), proplists:get_value(returns_static_log, Metadata)),
ok
end
},
{"Testing calling a dynamic function on log which returns the same value",
fun() ->
eRum:warning("dynamic message"),
?assertEqual(1, lager_test_backend:count()),
{_Level, _Time, _Message, Metadata} = lager_test_backend:pop(),
Value = proplists:get_value(returns_dynamic_log, Metadata),
?assert(Value =< transform_dynamic()),
?assert(Value =< transform_dynamic()),
?assert(Value =< transform_dynamic()),
?assert(Value =< transform_dynamic()),
?assert(Value =< transform_dynamic()),
ok
end
},
{"Testing differences in results for on_log vs on emit from dynamic function",
fun() ->
eRum:warning("on_log vs on emit"),
?assertEqual(1, lager_test_backend:count()),
{_Level, _Time, _Message, Metadata} = lager_test_backend:pop(),
Value = proplists:get_value(returns_dynamic_log, Metadata),
Function = proplists:get_value(returns_dynamic_emit, Metadata),
FunctionResult = Function(),
?assert(Value =< FunctionResult),
?assert(Value =< Function()),
?assert(FunctionResult =< Function()),
ok
end
},
{"Testing a function provided via metadata",
fun() ->
Provided = fun() ->
provided_metadata
end,
eRum:md([{provided, Provided}]),
eRum:warning("Provided metadata"),
?assertEqual(1, lager_test_backend:count()),
{_Level, _Time, _Message, Metadata} = lager_test_backend:pop(),
Function = proplists:get_value(provided, Metadata),
?assertEqual(Provided(), Function()),
ok
end
}
]
}.
-endif.

+ 0
- 55
test/lager_trace_test.erl 查看文件

@ -1,55 +0,0 @@
-module(pr_stacktrace_test).
-compile([{parse_transform, lager_transform}]).
-include_lib("eunit/include/eunit.hrl").
make_throw() ->
throw({test, exception}).
bad_arity() ->
lists:concat([], []).
bad_arg() ->
integer_to_list(1.0).
pr_stacktrace_throw_test() ->
Got = try
make_throw()
catch
Class:Reason:Stacktrace ->
lager:pr_stacktrace(Stacktrace, {Class, Reason})
end,
Want = "pr_stacktrace_test:pr_stacktrace_throw_test/0 line 26\n pr_stacktrace_test:make_throw/0 line 16\nthrow:{test,exception}",
?assertNotEqual(nomatch, string:find(Got, Want)).
pr_stacktrace_bad_arg_test() ->
Got = try
bad_arg()
catch
Class:Reason:Stacktrace ->
lager:pr_stacktrace(Stacktrace, {Class, Reason})
end,
Want = "pr_stacktrace_test:pr_stacktrace_bad_arg_test/0 line 36\n pr_stacktrace_test:bad_arg/0 line 22\nerror:badarg",
?assertNotEqual(nomatch, string:find(Got, Want)).
pr_stacktrace_bad_arity_test() ->
Got = try
bad_arity()
catch
Class:Reason:Stacktrace ->
lager:pr_stacktrace(Stacktrace, {Class, Reason})
end,
Want = "pr_stacktrace_test:pr_stacktrace_bad_arity_test/0 line 46\n lists:concat([], [])\nerror:undef",
?assertNotEqual(nomatch, string:find(Got, Want)).
pr_stacktrace_no_reverse_test() ->
application:set_env(lager, reverse_pretty_stacktrace, false),
Got = try
bad_arity()
catch
Class:Reason:Stacktrace ->
lager:pr_stacktrace(Stacktrace, {Class, Reason})
end,
Want = "error:undef\n lists:concat([], [])\n pr_stacktrace_test:pr_stacktrace_bad_arity_test/0 line 57",
?assertEqual(nomatch, string:find(Got, Want)).

+ 0
- 47
test/pr_composite_test.erl 查看文件

@ -1,47 +0,0 @@
-module(pr_composite_test).
-compile([{parse_transform, lager_transform}]).
-record(a, {field1 :: term(), field2 :: term()}).
-record(b, {field1 :: term(), field2 :: term()}).
-include_lib("eunit/include/eunit.hrl").
nested_record_test() ->
A = #a{field1 = x, field2 = y},
B = #b{field1 = A, field2 = {}},
Pr_B = eRum:pr(B, ?MODULE),
?assertEqual({'$lager_record', b,
[{field1, {'$lager_record', a,
[{field1, x}, {field2, y}]}},
{field2, {}}]},
Pr_B).
list_field_test() ->
As = [#a{field1 = 1, field2 = a2},
#a{field1 = 2, field2 = a2}],
B = #b{field1 = As, field2 = b2},
Pr_B = eRum:pr(B, ?MODULE),
?assertEqual({'$lager_record', b,
[{field1, [{'$lager_record', a,
[{field1, 1}, {field2, a2}]},
{'$lager_record', a,
[{field1, 2}, {field2, a2}]}]},
{field2, b2}]},
Pr_B).
list_of_records_test() ->
As = [#a{field1 = 1, field2 = a2},
#a{field1 = 2, field2 = a2}],
Pr_As = eRum:pr(As, ?MODULE),
?assertEqual([{'$lager_record', a, [{field1, 1}, {field2, a2}]},
{'$lager_record', a, [{field1, 2}, {field2, a2}]}],
Pr_As).
improper_list_test() ->
A = #a{field1 = [1 | 2], field2 = a2},
Pr_A = eRum:pr(A, ?MODULE),
?assertEqual({'$lager_record', a,
[{field1, [1 | 2]}, {field2, a2}]},
Pr_A).

+ 0
- 63
test/pr_stacktrace_test.erl 查看文件

@ -1,63 +0,0 @@
-module(pr_stacktrace_test).
-compile([{parse_transform, lager_transform}]).
-ifdef(OTP_RELEASE). %% this implies 21 or higher
-define(EXCEPTION(Class, Reason, Stacktrace), Class:Reason:Stacktrace).
-define(GET_STACK(Stacktrace), Stacktrace).
-else.
-define(EXCEPTION(Class, Reason, _), Class:Reason).
-define(GET_STACK(_), erlang:get_stacktrace()).
-endif.
-include_lib("eunit/include/eunit.hrl").
make_throw() ->
throw({test, exception}).
bad_arity() ->
lists:concat([], []).
bad_arg() ->
integer_to_list(1.0).
pr_stacktrace_throw_test() ->
Got = try
make_throw()
catch
?EXCEPTION(Class, Reason, Stacktrace) ->
eRum:pr_stacktrace(?GET_STACK(Stacktrace), {Class, Reason})
end,
Want = "pr_stacktrace_test:pr_stacktrace_throw_test/0 line 26\n pr_stacktrace_test:make_throw/0 line 16\nthrow:{test,exception}",
?assertNotEqual(nomatch, string:find(Got, Want)).
pr_stacktrace_bad_arg_test() ->
Got = try
bad_arg()
catch
?EXCEPTION(Class, Reason, Stacktrace) ->
eRum:pr_stacktrace(?GET_STACK(Stacktrace), {Class, Reason})
end,
Want = "pr_stacktrace_test:pr_stacktrace_bad_arg_test/0 line 36\n pr_stacktrace_test:bad_arg/0 line 22\nerror:badarg",
?assertNotEqual(nomatch, string:find(Got, Want)).
pr_stacktrace_bad_arity_test() ->
Got = try
bad_arity()
catch
?EXCEPTION(Class, Reason, Stacktrace) ->
eRum:pr_stacktrace(?GET_STACK(Stacktrace), {Class, Reason})
end,
Want = "pr_stacktrace_test:pr_stacktrace_bad_arity_test/0 line 46\n lists:concat([], [])\nerror:undef",
?assertNotEqual(nomatch, string:find(Got, Want)).
pr_stacktrace_no_reverse_test() ->
application:set_env(lager, reverse_pretty_stacktrace, false),
Got = try
bad_arity()
catch
?EXCEPTION(Class, Reason, Stacktrace) ->
eRum:pr_stacktrace(?GET_STACK(Stacktrace), {Class, Reason})
end,
Want = "error:undef\n lists:concat([], [])\n pr_stacktrace_test:pr_stacktrace_bad_arity_test/0 line 57",
?assertEqual(nomatch, string:find(Got, Want)).

+ 0
- 36
test/special_process.erl 查看文件

@ -1,36 +0,0 @@
-module(special_process).
-export([start/0, init/1]).
start() ->
proc_lib:start_link(?MODULE, init, [self()]).
init(Parent) ->
proc_lib:init_ack(Parent, {ok, self()}),
loop().
loop() ->
receive
function_clause ->
foo(bar),
loop();
exit ->
exit(byebye),
loop();
error ->
erlang:error(mybad),
loop();
{case_clause, X} ->
case X of
notgonnamatch ->
ok;
notthiseither ->
error
end,
loop();
_ ->
loop()
end.
foo(baz) ->
ok.

+ 0
- 89
test/sync_error_logger.erl 查看文件

@ -1,89 +0,0 @@
%%
%% %CopyrightBegin%
%%
%% Copyright Ericsson AB 1996-2009. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
%% compliance with the License. You should have received a copy of the
%% Erlang Public License along with this software. If not, it can be
%% retrieved online at http://www.erlang.org/.
%%
%% Software distributed under the License is distributed on an "AS IS"
%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
%% the License for the specific language governing rights and limitations
%% under the License.
%%
%% %CopyrightEnd%
%%
-module(sync_error_logger).
%% The error_logger API, but synchronous!
%% This is helpful for tests, otherwise you need lots of nasty timer:sleep.
%% Additionally, the warning map can be set on a per-process level, for
%% convienience, via the process dictionary value `warning_map'.
-export([
info_msg/1, info_msg/2,
warning_msg/1, warning_msg/2,
error_msg/1, error_msg/2
]).
-export([
info_report/1, info_report/2,
warning_report/1, warning_report/2,
error_report/1, error_report/2
]).
info_msg(Format) ->
info_msg(Format, []).
info_msg(Format, Args) ->
gen_event:sync_notify(error_logger, {info_msg, group_leader(), {self(), Format, Args}}).
warning_msg(Format) ->
warning_msg(Format, []).
warning_msg(Format, Args) ->
gen_event:sync_notify(error_logger, {warning_msg_tag(), group_leader(), {self(), Format, Args}}).
error_msg(Format) ->
error_msg(Format, []).
error_msg(Format, Args) ->
gen_event:sync_notify(error_logger, {error, group_leader(), {self(), Format, Args}}).
info_report(Report) ->
info_report(std_info, Report).
info_report(Type, Report) ->
gen_event:sync_notify(error_logger, {info_report, group_leader(), {self(), Type, Report}}).
warning_report(Report) ->
warning_report(std_warning, Report).
warning_report(Type, Report) ->
{Tag, NType} = warning_report_tag(Type),
gen_event:sync_notify(error_logger, {Tag, group_leader(), {self(), NType, Report}}).
error_report(Report) ->
error_report(std_error, Report).
error_report(Type, Report) ->
gen_event:sync_notify(error_logger, {error_report, group_leader(), {self(), Type, Report}}).
warning_msg_tag() ->
case get(warning_map) of
warning -> warning_msg;
info -> info_msg;
_ -> error
end.
warning_report_tag(Type) ->
case {get(warning_map), Type == std_warning} of
{warning, _} -> {warning_report, Type};
{info, true} -> {info_report, std_info};
{info, false} -> {info_report, Type};
{_, true} -> {error_report, std_error};
{_, false} -> {error_report, Type}
end.

+ 0
- 244
test/trunc_io_eqc.erl 查看文件

@ -1,244 +0,0 @@
%% -------------------------------------------------------------------
%%
%% trunc_io_eqc: QuickCheck test for trunc_io:format with maxlen
%%
%% Copyright (c) 2011-2012 Basho Technologies, Inc. All Rights Reserved.
%%
%% This file is provided to you under the Apache License,
%% Version 2.0 (the "License"); you may not use this file
%% except in compliance with the License. You may obtain
%% a copy of the License at
%%
%% http://www.apache.org/licenses/LICENSE-2.0
%%
%% Unless required by applicable law or agreed to in writing,
%% software distributed under the License is distributed on an
%% "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
%% KIND, either express or implied. See the License for the
%% specific language governing permissions and limitations
%% under the License.
%%
%% -------------------------------------------------------------------
-module(trunc_io_eqc).
-ifdef(TEST).
-ifdef(EQC).
-export([test/0, test/1, check/0, prop_format/0, prop_equivalence/0]).
-include_lib("eqc/include/eqc.hrl").
-include_lib("eunit/include/eunit.hrl").
-define(QC_OUT(P),
eqc:on_output(fun(Str, Args) -> io:format(user, Str, Args) end, P)).
%%====================================================================
%% eunit test
%%====================================================================
eqc_test_() ->
{timeout, 60,
{spawn,
[
{timeout, 30, ?_assertEqual(true, eqc:quickcheck(eqc:testing_time(14, ?QC_OUT(prop_format()))))},
{timeout, 30, ?_assertEqual(true, eqc:quickcheck(eqc:testing_time(14, ?QC_OUT(prop_equivalence()))))}
]
}}.
%%====================================================================
%% Shell helpers
%%====================================================================
test() ->
test(100).
test(N) ->
quickcheck(numtests(N, prop_format())).
check() ->
check(prop_format(), current_counterexample()).
%%====================================================================
%% Generators
%%====================================================================
gen_fmt_args() ->
list(oneof([gen_print_str(),
"~~",
{"~10000000.p", gen_any(5)},
{"~w", gen_any(5)},
{"~s", oneof([gen_print_str(), gen_atom(), gen_quoted_atom(), gen_print_bin(), gen_iolist(5)])},
{"~1000000.P", gen_any(5), 4},
{"~W", gen_any(5), 4},
{"~i", gen_any(5)},
{"~B", nat()},
{"~b", nat()},
{"~X", nat(), "0x"},
{"~x", nat(), "0x"},
{"~.10#", nat()},
{"~.10+", nat()},
{"~.36B", nat()},
{"~1000000.62P", gen_any(5), 4},
{"~c", gen_char()},
{"~tc", gen_char()},
{"~f", real()},
{"~10.f", real()},
{"~g", real()},
{"~10.g", real()},
{"~e", real()},
{"~10.e", real()}
])).
%% Generates a printable string
gen_print_str() ->
?LET(Xs, list(char()), [X || X <- Xs, io_lib:printable_list([X]), X /= $~, X < 256]).
gen_print_bin() ->
?LET(Xs, gen_print_str(), list_to_binary(Xs)).
gen_any(MaxDepth) ->
oneof([largeint(),
gen_atom(),
gen_quoted_atom(),
nat(),
%real(),
binary(),
gen_bitstring(),
gen_pid(),
gen_port(),
gen_ref(),
gen_fun()] ++
[?LAZY(list(gen_any(MaxDepth - 1))) || MaxDepth /= 0] ++
[?LAZY(gen_tuple(gen_any(MaxDepth - 1))) || MaxDepth /= 0]).
gen_iolist(0) ->
[];
gen_iolist(Depth) ->
list(oneof([gen_char(), gen_print_str(), gen_print_bin(), gen_iolist(Depth - 1)])).
gen_atom() ->
elements([abc, def, ghi]).
gen_quoted_atom() ->
elements(['abc@bar', '@bar', '10gen']).
gen_bitstring() ->
?LET(XS, binary(), <<XS/binary, 1:7>>).
gen_tuple(Gen) ->
?LET(Xs, list(Gen), list_to_tuple(Xs)).
gen_max_len() -> %% Generate length from 3 to whatever. Needs space for ... in output
?LET(Xs, int(), 3 + abs(Xs)).
gen_pid() ->
?LAZY(spawn(fun() -> ok end)).
gen_port() ->
?LAZY(begin
Port = erlang:open_port({spawn, "true"}, []),
catch (erlang:port_close(Port)),
Port
end).
gen_ref() ->
?LAZY(make_ref()).
gen_fun() ->
?LAZY(fun() -> ok end).
gen_char() ->
oneof(lists:seq($A, $z)).
%%====================================================================
%% Property
%%====================================================================
%% Checks that trunc_io:format produces output less than or equal to MaxLen
prop_format() ->
?FORALL({FmtArgs, MaxLen}, {gen_fmt_args(), gen_max_len()},
begin
%% Because trunc_io will print '...' when its running out of
%% space, even if the remaining space is less than 3, it
%% doesn't *exactly* stick to the specified limit.
%% Also, since we don't truncate terms not printed with
%% ~p/~P/~w/~W/~s, we also need to calculate the wiggle room
%% for those. Hence the fudge factor calculated below.
FudgeLen = calculate_fudge(FmtArgs, 50),
{FmtStr, Args} = build_fmt_args(FmtArgs),
try
Str = lists:flatten(rumTruncIo:format(FmtStr, Args, MaxLen)),
?WHENFAIL(begin
io:format(user, "FmtStr: ~p\n", [FmtStr]),
io:format(user, "Args: ~p\n", [Args]),
io:format(user, "FudgeLen: ~p\n", [FudgeLen]),
io:format(user, "MaxLen: ~p\n", [MaxLen]),
io:format(user, "ActLen: ~p\n", [length(Str)]),
io:format(user, "Str: ~p\n", [Str])
end,
%% Make sure the result is a printable list
%% and if the format string is less than the length,
%% the result string is less than the length.
conjunction([{printable, Str == "" orelse
io_lib:printable_list(Str)},
{length, length(FmtStr) > MaxLen orelse
length(Str) =< MaxLen + FudgeLen}]))
catch
_:Err ->
io:format(user, "\nException: ~p\n", [Err]),
io:format(user, "FmtStr: ~p\n", [FmtStr]),
io:format(user, "Args: ~p\n", [Args]),
false
end
end).
%% Checks for equivalent formatting to io_lib
prop_equivalence() ->
?FORALL(FmtArgs, gen_fmt_args(),
begin
{FmtStr, Args} = build_fmt_args(FmtArgs),
Expected = lists:flatten(io_lib:format(FmtStr, Args)),
Actual = lists:flatten(rumTruncIo:format(FmtStr, Args, 10485760)),
?WHENFAIL(begin
io:format(user, "FmtStr: ~p\n", [FmtStr]),
io:format(user, "Args: ~p\n", [Args]),
io:format(user, "Expected: ~p\n", [Expected]),
io:format(user, "Actual: ~p\n", [Actual])
end,
Expected == Actual)
end).
%%====================================================================
%% Internal helpers
%%====================================================================
%% Build a tuple of {Fmt, Args} from a gen_fmt_args() return
build_fmt_args(FmtArgs) ->
F = fun({Fmt, Arg}, {FmtStr0, Args0}) ->
{FmtStr0 ++ Fmt, Args0 ++ [Arg]};
({Fmt, Arg1, Arg2}, {FmtStr0, Args0}) ->
{FmtStr0 ++ Fmt, Args0 ++ [Arg1, Arg2]};
(Str, {FmtStr0, Args0}) ->
{FmtStr0 ++ Str, Args0}
end,
lists:foldl(F, {"", []}, FmtArgs).
calculate_fudge([], Acc) ->
Acc;
calculate_fudge([{"~62P", _Arg, _Depth} | T], Acc) ->
calculate_fudge(T, Acc + 62);
calculate_fudge([{Fmt, Arg} | T], Acc) when
Fmt == "~f"; Fmt == "~10.f";
Fmt == "~g"; Fmt == "~10.g";
Fmt == "~e"; Fmt == "~10.e";
Fmt == "~x"; Fmt == "~X";
Fmt == "~B"; Fmt == "~b"; Fmt == "~36B";
Fmt == "~.10#"; Fmt == "~10+" ->
calculate_fudge(T, Acc + length(lists:flatten(io_lib:format(Fmt, [Arg]))));
calculate_fudge([_ | T], Acc) ->
calculate_fudge(T, Acc).
-endif. % (EQC).
-endif. % (TEST).

+ 0
- 35
test/zzzz_gh280_crash.erl 查看文件

@ -1,35 +0,0 @@
%% @doc This test is named zzzz_gh280_crash because it has to be run first and tests are run in
%% reverse alphabetical order.
%%
%% The problem we are attempting to detect here is when log_mf_h is installed as a handler for error_logger
%% and lager starts up to replace the current handlers with its own. This causes a start up crash because
%% OTP error logging modules do not have any notion of a lager-style log level.
-module(zzzz_gh280_crash).
-include_lib("eunit/include/eunit.hrl").
gh280_crash_test() ->
{timeout, 30, fun() -> gh280_impl() end}.
gh280_impl() ->
application:stop(lager),
application:stop(goldrush),
error_logger:tty(false),
%% see https://github.com/erlang/otp/blob/maint/lib/stdlib/src/log_mf_h.erl#L81
%% for an explanation of the init arguments to log_mf_h
ok = gen_event:add_sup_handler(error_logger, log_mf_h, log_mf_h:init("/tmp", 10000, 5)),
eRum:start(),
Result = receive
{gen_event_EXIT, log_mf_h, normal} ->
true;
{gen_event_EXIT, Handler, Reason} ->
{Handler, Reason};
X ->
X
after 10000 ->
timeout
end,
?assert(Result),
application:stop(lager),
application:stop(goldrush).

正在加载...
取消
保存