Procházet zdrojové kódy

ft: backend相关修改

master
SisMaker před 4 roky
rodič
revize
e394819231
5 změnil soubory, kde provedl 190 přidání a 286 odebrání
  1. +16
    -0
      include/eRum.hrl
  2. +3
    -3
      src/backend/rumBkdConsole.erl
  3. +168
    -280
      src/backend/rumBkdFile.erl
  4. +2
    -2
      src/eRum.erl
  5. +1
    -1
      src/utils/rumUtil.erl

+ 16
- 0
include/eRum.hrl Zobrazit soubor

@ -14,6 +14,22 @@
-define(RumDefSink, rumEvent).
-define(RumErrLogSink, error_logger_lager_event).
%% BkdFile默认配置
-define(RumDefLogLevel, info).
-define(RumDefRotateSize, 10485760). %% 10mb
-define(RumDefRotateDate, "$D0"). %% midnight
-define(RumDefRotateCnt, 5).
-define(RumDefRotateMod, rumRotatorIns).
-define(RumDefSyncLevel, error).
-define(RumDefSyncInterval, 1000).
-define(RumDefSyncSize, 1024 * 64). %% 64kb
-define(RumDefCheckInterval, 1000).
-define(RumDefCheckHWM, 0). %% IMY-todo修正该默认值
-define(RumDefFlushQueue, true).
-define(RumDefFlushThreshold, 0). %% IMY-todo修正该默认值
-define(RumDefFormatter, rumFormatter).
-define(RumDefFormatterCfg, []).
%% Key
%%

+ 3
- 3
src/backend/rumBkdConsole.erl Zobrazit soubor

@ -64,7 +64,7 @@ init(Opts) ->
checkOpts([]) -> true;
checkOpts([{level, L} | T]) when is_atom(L) ->
?IIF(lists:member(L, ?RumLevels) == false, throw({error, {fatal, {bad_level, L}}}), checkOpts(T));
?IIF(lists:member(L, ?RumLevels) == false, {error, {bad_level, L}}, checkOpts(T));
checkOpts([{use_stderr, true} | T]) ->
checkOpts(T);
checkOpts([{use_stderr, false} | T]) ->
@ -78,10 +78,10 @@ checkOpts([{group_leader, L} | T]) when is_pid(L) ->
checkOpts([{id, {?MODULE, _}} | T]) ->
checkOpts(T);
checkOpts([H | _]) ->
throw({error, {fatal, {bad_console_config, H}}}).
{error, {invalid_opt, H}}.
handleCall(mGetLogLevel, #state{level = Level} = State) ->
{ok, Level, State};
{reply, Level, State};
handleCall({mSetLogLevel, Level}, State) ->
try rumUtil:config_to_mask(Level) of
Levels ->

+ 168
- 280
src/backend/rumBkdFile.erl Zobrazit soubor

@ -23,25 +23,15 @@
-export([
init/1
, handle_call/2
, handle_event/2
, handle_info/2
, handleCall/2
, handleEvent/2
, handleInfo/2
, terminate/2
, code_change/3
]).
-define(DEFAULT_LOG_LEVEL, info).
-define(DEFAULT_ROTATION_SIZE, 10485760). %% 10mb
-define(DEFAULT_ROTATION_DATE, "$D0"). %% midnight
-define(DEFAULT_ROTATION_COUNT, 5).
-define(DEFAULT_ROTATION_MOD, lager_rotator_default).
-define(DEFAULT_SYNC_LEVEL, error).
-define(DEFAULT_SYNC_INTERVAL, 1000).
-define(DEFAULT_SYNC_SIZE, 1024 * 64). %% 64kb
-define(DEFAULT_CHECK_INTERVAL, 1000).
-record(state, {
name :: string(),
fileName :: string(),
level :: {'mask', integer()},
fd :: file:io_device() | undefined,
inode :: integer() | undefined,
@ -53,13 +43,13 @@
rotator = lager_util :: atom(),
shaper :: rumShaper(),
formatter :: atom(),
formatter_config :: any(),
formatterConfig :: any(),
sync_on :: {'mask', integer()},
check_interval = ?DEFAULT_CHECK_INTERVAL :: non_neg_integer(),
sync_interval = ?DEFAULT_SYNC_INTERVAL :: non_neg_integer(),
sync_size = ?DEFAULT_SYNC_SIZE :: non_neg_integer(),
last_check = os:timestamp() :: erlang:timestamp(),
os_type :: atom()
checkInterval = ?RumDefCheckInterval :: non_neg_integer(),
syncInterval = ?RumDefSyncInterval :: non_neg_integer(),
sync_size = ?RumDefSyncSize :: non_neg_integer(),
lastCheck = os:timestamp() :: erlang:timestamp(),
osType :: atom()
}).
-type option() ::
@ -80,110 +70,108 @@
{formatter_config, term()}.
-spec init([option(), ...]) -> {ok, #state{}} | {error, {fatal, bad_config}}.
init({FileName, LogLevel}) when is_list(FileName), is_atom(LogLevel) ->
%% backwards compatibility hack
init([{file, FileName}, {level, LogLevel}]);
init({FileName, LogLevel, Size, Date, Count}) when is_list(FileName), is_atom(LogLevel) ->
%% backwards compatibility hack
init([{file, FileName}, {level, LogLevel}, {size, Size}, {date, Date}, {count, Count}]);
init([{FileName, LogLevel, Size, Date, Count}, {Formatter, FormatterConfig}]) when is_list(FileName), is_atom(LogLevel), is_atom(Formatter) ->
%% backwards compatibility hack
init([{file, FileName}, {level, LogLevel}, {size, Size}, {date, Date}, {count, Count}, {formatter, Formatter}, {formatter_config, FormatterConfig}]);
init([LogFile, {Formatter}]) ->
%% backwards compatibility hack
init([LogFile, {Formatter, []}]);
init([{FileName, LogLevel}, {Formatter, FormatterConfig}]) when is_list(FileName), is_atom(LogLevel), is_atom(Formatter) ->
%% backwards compatibility hack
init([{file, FileName}, {level, LogLevel}, {formatter, Formatter}, {formatter_config, FormatterConfig}]);
init(LogFileConfig) when is_list(LogFileConfig) ->
case validate_logfile_proplist(LogFileConfig) of
false ->
%% falied to validate config
{error, {fatal, bad_config}};
Config ->
%% probabably a better way to do this, but whatever
[RelName, Level, Date, Size, Count, Rotator, HighWaterMark, Flush, SyncInterval, SyncSize, SyncOn, CheckInterval, Formatter, FormatterConfig] =
[proplists:get_value(Key, Config) || Key <- [file, level, date, size, count, rotator, high_water_mark, flush_queue, sync_interval, sync_size, sync_on, check_interval, formatter, formatter_config]],
FlushThr = proplists:get_value(flush_threshold, Config, 0),
Name = rumUtil:parsePath(RelName),
schedule_rotation(Name, Date),
Shaper = rumUtil:maybe_flush(Flush, #rumShaper{hwm = HighWaterMark, flushThreshold = FlushThr, id = Name}),
State0 = #state{name = Name, level = Level, size = Size, date = Date, count = Count, rotator = Rotator,
shaper = Shaper, formatter = Formatter, formatter_config = FormatterConfig,
sync_on = SyncOn, sync_interval = SyncInterval, sync_size = SyncSize, check_interval = CheckInterval},
State = case Rotator:createLogfile(Name, {SyncSize, SyncInterval}) of
{ok, {FD, Inode, Ctime, _Size}} ->
State0#state{fd = FD, inode = Inode, ctime = Ctime};
{error, Reason} ->
?INT_LOG(error, "Failed to open log file ~ts with error ~s", [Name, file:format_error(Reason)]),
State0#state{flap = true}
end,
{ok, State}
init(Opts) ->
true = checkOpts(Opts, false),
RelName = rumUtil:get_opt(file, Opts, undefined),
CfgLevel = rumUtil:get_opt(level, Opts, ?RumDefLogLevel),
CfgDate = rumUtil:get_opt(date, Opts, ?RumDefRotateDate),
Size = rumUtil:get_opt(size, Opts, ?RumDefRotateSize),
Count = rumUtil:get_opt(count, Opts, ?RumDefRotateCnt),
Rotator = rumUtil:get_opt(rotator, Opts, ?RumDefRotateMod),
HighWaterMark = rumUtil:get_opt(high_water_mark, Opts, ?RumDefCheckHWM),
Flush = rumUtil:get_opt(flush_queue, Opts, ?RumDefFlushQueue),
FlushThr = rumUtil:get_opt(flush_threshold, Opts, ?RumDefFlushThreshold),
SyncInterval = rumUtil:get_opt(sync_interval, Opts, ?RumDefSyncInterval),
CfgCheckInterval = rumUtil:get_opt(check_interval, Opts, ?RumDefCheckInterval),
SyncSize = rumUtil:get_opt(sync_size, Opts, ?RumDefSyncSize),
CfgSyncOn = rumUtil:get_opt(sync_on, Opts, ?RumDefSyncLevel),
Formatter = rumUtil:get_opt(formatter, Opts, ?RumDefFormatter),
FormatterConfig = rumUtil:get_opt(formatter_config, Opts, ?RumDefFormatterCfg),
%%
Level = validate_loglevel(CfgLevel),
SyncOn = validate_loglevel(CfgSyncOn),
CheckInterval = ?IIF(CfgCheckInterval == always, 0, CfgCheckInterval),
{ok, Date} = rumUtil:parseRotateSpec(CfgDate),
FileName = rumUtil:parsePath(RelName),
scheduleRotation(Date, FileName),
Shaper = rumUtil:maybe_flush(Flush, #rumShaper{hwm = HighWaterMark, flushThreshold = FlushThr, id = FileName}),
TemState = #state{
fileName = FileName, level = Level, size = Size, date = Date
, count = Count, rotator = Rotator, shaper = Shaper
, formatter = Formatter, formatterConfig = FormatterConfig
, sync_on = SyncOn, syncInterval = SyncInterval
, sync_size = SyncSize, checkInterval = CheckInterval
},
case Rotator:createLogfile(FileName, {SyncSize, SyncInterval}) of
{ok, Fd, Inode, Ctime, _Size} ->
{ok, TemState#state{fd = Fd, inode = Inode, ctime = Ctime}};
{error, Reason} ->
?INT_LOG(error, "Failed to open log file ~ts with error ~s", [FileName, file:format_error(Reason)]),
{ok, TemState#state{flap = true}}
end.
%% @private
handle_call({mSetLogLevel, Level}, #state{name = Ident} = State) ->
handleCall(mGetLogLevel, #state{level = Level} = State) ->
{reply, Level, State};
handleCall({mSetLogLevel, Level}, #state{fileName = Ident} = State) ->
case validate_loglevel(Level) of
false ->
{ok, {error, bad_loglevel}, State};
{reply, {error, bad_loglevel}, State};
Levels ->
?INT_LOG(notice, "Changed loglevel of ~s to ~p", [Ident, Level]),
{ok, ok, State#state{level = Levels}}
{reply, ok, State#state{level = Levels}}
end;
handle_call(mGetLogLevel, #state{level = Level} = State) ->
{ok, Level, State};
handle_call({set_loghwm, Hwm}, #state{shaper = Shaper, name = Name} = State) ->
case validate_logfile_proplist([{file, Name}, {high_water_mark, Hwm}]) of
handleCall({mSetLogHwm, Hwm}, #state{shaper = Shaper, fileName = FileName} = State) ->
case checkOpts([{high_water_mark, Hwm}], true) of
false ->
{ok, {error, bad_log_hwm}, State};
{reply, {error, bad_log_hwm}, State};
_ ->
NewShaper = Shaper#rumShaper{hwm = Hwm},
?INT_LOG(notice, "Changed loghwm of ~ts to ~p", [Name, Hwm]),
{ok, {last_loghwm, Shaper#rumShaper.hwm}, State#state{shaper = NewShaper}}
?INT_LOG(notice, "Changed loghwm of ~ts to ~p", [FileName, Hwm]),
{reply, {last_loghwm, Shaper#rumShaper.hwm}, State#state{shaper = NewShaper}}
end;
handle_call(mRotate, State = #state{name = File}) ->
{ok, NewState} = handle_info({mRotate, File}, State),
{ok, ok, NewState};
handle_call(_Request, State) ->
{ok, ok, State}.
%% @private
handle_event({mWriteLog, Message},
#state{name = Name, level = L, shaper = Shaper, formatter = Formatter, formatter_config = FormatConfig} = State) ->
case rumUtil:is_loggable(Message, L, {lager_file_backend, Name}) of
handleCall(mRotate, State = #state{fileName = File}) ->
{ok, NewState} = handleInfo({mRotate, File}, State),
{reply, ok, NewState};
handleCall(_Msg, State) ->
?ERR("~p call receive unexpect msg ~p ~n ", [?MODULE, _Msg]),
{reply, ok, State}.
handleEvent({mWriteLog, Message}, #state{fileName = FileName, level = L, shaper = Shaper, formatter = Formatter, formatterConfig = FormatConfig} = State) ->
case rumUtil:is_loggable(Message, L, {rumBkdFile, FileName}) of
true ->
case rumUtil:check_hwm(Shaper) of
{true, Drop, #rumShaper{hwm = Hwm} = NewShaper} ->
NewState = case Drop > 0 of
true ->
Report = io_lib:format(
"lager_file_backend dropped ~p messages in the last second that exceeded the limit of ~p messages/sec",
[Drop, Hwm]),
ReportMsg = rumMsg:new(Report, warning, [], []),
write(State, rumMsg:timestamp(ReportMsg),
rumMsg:severity_as_int(ReportMsg), Formatter:format(ReportMsg, FormatConfig));
false ->
State
end,
NewState =
case Drop > 0 of
true ->
Report = io_lib:format("lager_file_backend dropped ~p messages in the last second that exceeded the limit of ~p messages/sec", [Drop, Hwm]),
ReportMsg = rumMsg:new(Report, warning, [], []),
write(State, rumMsg:timestamp(ReportMsg), rumMsg:severity_as_int(ReportMsg), Formatter:format(ReportMsg, FormatConfig));
_ ->
State
end,
{ok, write(NewState#state{shaper = NewShaper},
rumMsg:timestamp(Message), rumMsg:severity_as_int(Message),
Formatter:format(Message, FormatConfig))};
{false, _, #rumShaper{dropped = D} = NewShaper} ->
{ok, State#state{shaper = NewShaper#rumShaper{dropped = D + 1}}}
end;
false ->
{okpan>, State}
_ ->
kpS
end;
handle_event(_Event, State) ->
{ok, State}.
handleEvent(_Msg, _State) ->
?ERR("~p event receive unexpect msg ~p ~n ", [?MODULE, _Msg]),
kpS.
%% @private
handle_info({mRotate, File}, #state{name = File, count = Count, date = Date, rotator = Rotator} = State0) ->
handleInfo({mRotate, File}, #state{fileName = File, count = Count, date = Date, rotator = Rotator} = State0) ->
State1 = close_file(State0),
_ = Rotator:rotateLogfile(File, Count),
schedule_rotation(File, Date),
scheduleRotation(File, Date),
{ok, State1};
handle_info({shaper_expired, Name}, #state{shaper = Shaper, name = Name, formatter = Formatter, formatter_config = FormatConfig} = State) ->
handleInfo({shaper_expired, Name}, #state{shaper = Shaper, fileName = Name, formatter = Formatter, formatterConfig = FormatConfig} = State) ->
_ = case Shaper#rumShaper.dropped of
0 ->
ok;
@ -196,16 +184,14 @@ handle_info({shaper_expired, Name}, #state{shaper = Shaper, name = Name, formatt
rumMsg:severity_as_int(ReportMsg), Formatter:format(ReportMsg, FormatConfig))
end,
{ok, State#state{shaper = Shaper#rumShaper{dropped = 0, mps = 0, lastTime = os:timestamp()}}};
handle_info(_Info, State) ->
handleInfo(_Info, State) ->
{ok, State}.
%% @private
terminate(_Reason, State) ->
%% leaving this function call unmatched makes dialyzer cranky
_ = close_file(State),
ok.
%% @private
code_change(_OldVsn, State, _Extra) ->
{ok, State}.
@ -226,14 +212,14 @@ config_to_id(Config) ->
{?MODULE, File}
end.
write(#state{name = Name, fd = FD,
write(#state{fileName = Name, fd = FD,
inode = Inode, ctime = Ctime,
flap = Flap, size = RotSize,
count = Count, rotator = Rotator} = State0, Timestamp, Level, Msg) ->
case write_should_check(State0, Timestamp) of
true ->
%% need to check for rotation
Buffer = {State0#state.sync_size, State0#state.sync_interval},
Buffer = {State0#state.sync_size, State0#state.syncInterval},
case Rotator:ensureLogfile(Name, FD, Inode, Ctime, Buffer) of
{ok, {_FD, _Inode, _Ctime, Size}} when RotSize > 0, Size > RotSize ->
State1 = close_file(State0),
@ -252,7 +238,7 @@ write(#state{name = Name, fd = FD,
end;
{ok, {NewFD, NewInode, NewCtime, _Size}} ->
%% update our last check and try again
State1 = State0#state{last_check = Timestamp, fd = NewFD, inode = NewInode, ctime = NewCtime},
State1 = State0#state{lastCheck = Timestamp, fd = NewFD, inode = NewInode, ctime = NewCtime},
do_write(State1, Level, Msg);
{error, Reason} ->
case Flap of
@ -269,8 +255,8 @@ write(#state{name = Name, fd = FD,
write_should_check(#state{fd = undefined}, _Timestamp) ->
true;
write_should_check(#state{last_check = LastCheck0, check_interval = CheckInterval,
name = Name, inode = Inode0, ctime = Ctime0}, Timestamp) ->
write_should_check(#state{lastCheck = LastCheck0, checkInterval = CheckInterval,
fileName = Name, inode = Inode0, ctime = Ctime0}, Timestamp) ->
LastCheck1 = timer:now_diff(Timestamp, LastCheck0) div 1000,
case LastCheck1 >= CheckInterval of
true ->
@ -282,7 +268,7 @@ write_should_check(#state{last_check = LastCheck0, check_interval = CheckInterva
Result
end.
do_write(#state{fd = FD, name = Name, flap = Flap} = State, Level, Msg) ->
do_write(#state{fd = FD, fileName = Name, flap = Flap} = State, Level, Msg) ->
%% delayed_write doesn't report errors
_ = file:write(FD, unicode:characters_to_binary(Msg)),
{mask, SyncLevel} = State#state.sync_on,
@ -313,146 +299,48 @@ validate_loglevel(Level) ->
false
end.
validate_logfile_proplist(List) ->
try validate_logfile_proplist(List, []) of
Res ->
case proplists:get_value(file, Res) of
undefined ->
?INT_LOG(error, "Missing required file option", []),
false;
_File ->
%% merge with the default options
{ok, DefaultRotationDate} = rumUtil:parseRotateSpec(?DEFAULT_ROTATION_DATE),
lists:keymerge(1, lists:sort(Res), lists:sort([
{level, validate_loglevel(?DEFAULT_LOG_LEVEL)}, {date, DefaultRotationDate},
{size, ?DEFAULT_ROTATION_SIZE}, {count, ?DEFAULT_ROTATION_COUNT},
{rotator, ?DEFAULT_ROTATION_MOD},
{sync_on, validate_loglevel(?DEFAULT_SYNC_LEVEL)}, {sync_interval, ?DEFAULT_SYNC_INTERVAL},
{sync_size, ?DEFAULT_SYNC_SIZE}, {check_interval, ?DEFAULT_CHECK_INTERVAL},
{formatter, lager_default_formatter}, {formatter_config, []}
]))
end
catch
{bad_config, Msg, Value} ->
?INT_LOG(error, "~s ~p for file ~tp",
[Msg, Value, proplists:get_value(file, List)]),
false
end.
validate_logfile_proplist([], Acc) ->
Acc;
validate_logfile_proplist([{file, File} | Tail], Acc) ->
checkOpts([], IsFile) ->
?IIF(IsFile, true, {error, no_file_name});
checkOpts([{file, _File} | Tail], _IsFile) ->
%% is there any reasonable validation we can do here?
validate_logfile_proplist(Tail, [{file, File} | Acc]);
validate_logfile_proplist([{level, Level} | Tail], Acc) ->
case validate_loglevel(Level) of
false ->
throw({bad_config, "Invalid loglevel", Level});
Res ->
validate_logfile_proplist(Tail, [{level, Res} | Acc])
end;
validate_logfile_proplist([{size, Size} | Tail], Acc) ->
case Size of
S when is_integer(S), S >= 0 ->
validate_logfile_proplist(Tail, [{size, Size} | Acc]);
_ ->
throw({bad_config, "Invalid rotation size", Size})
end;
validate_logfile_proplist([{count, Count} | Tail], Acc) ->
case Count of
C when is_integer(C), C >= 0 ->
validate_logfile_proplist(Tail, [{count, Count} | Acc]);
_ ->
throw({bad_config, "Invalid rotation count", Count})
end;
validate_logfile_proplist([{rotator, Rotator} | Tail], Acc) ->
case is_atom(Rotator) of
true ->
validate_logfile_proplist(Tail, [{rotator, Rotator} | Acc]);
false ->
throw({bad_config, "Invalid rotation module", Rotator})
end;
validate_logfile_proplist([{high_water_mark, HighWaterMark} | Tail], Acc) ->
case HighWaterMark of
Hwm when is_integer(Hwm), Hwm >= 0 ->
validate_logfile_proplist(Tail, [{high_water_mark, Hwm} | Acc]);
_ ->
throw({bad_config, "Invalid high water mark", HighWaterMark})
end;
validate_logfile_proplist([{date, Date} | Tail], Acc) ->
case rumUtil:parseRotateSpec(Date) of
{ok, Spec} ->
validate_logfile_proplist(Tail, [{date, Spec} | Acc]);
{error, _} when Date == "" ->
%% legacy config allowed blanks
validate_logfile_proplist(Tail, [{date, undefined} | Acc]);
{error, _} ->
throw({bad_config, "Invalid rotation date", Date})
end;
validate_logfile_proplist([{sync_interval, SyncInt} | Tail], Acc) ->
case SyncInt of
Val when is_integer(Val), Val >= 0 ->
validate_logfile_proplist(Tail, [{sync_interval, Val} | Acc]);
_ ->
throw({bad_config, "Invalid sync interval", SyncInt})
end;
validate_logfile_proplist([{sync_size, SyncSize} | Tail], Acc) ->
case SyncSize of
Val when is_integer(Val), Val >= 0 ->
validate_logfile_proplist(Tail, [{sync_size, Val} | Acc]);
_ ->
throw({bad_config, "Invalid sync size", SyncSize})
end;
validate_logfile_proplist([{check_interval, CheckInt} | Tail], Acc) ->
case CheckInt of
Val when is_integer(Val), Val >= 0 ->
validate_logfile_proplist(Tail, [{check_interval, Val} | Acc]);
always ->
validate_logfile_proplist(Tail, [{check_interval, 0} | Acc]);
_ ->
throw({bad_config, "Invalid check interval", CheckInt})
end;
validate_logfile_proplist([{sync_on, Level} | Tail], Acc) ->
case validate_loglevel(Level) of
false ->
throw({bad_config, "Invalid sync on level", Level});
Res ->
validate_logfile_proplist(Tail, [{sync_on, Res} | Acc])
end;
validate_logfile_proplist([{formatter, Fmt} | Tail], Acc) ->
case is_atom(Fmt) of
true ->
validate_logfile_proplist(Tail, [{formatter, Fmt} | Acc]);
false ->
throw({bad_config, "Invalid formatter module", Fmt})
end;
validate_logfile_proplist([{formatter_config, FmtCfg} | Tail], Acc) ->
case is_list(FmtCfg) of
true ->
validate_logfile_proplist(Tail, [{formatter_config, FmtCfg} | Acc]);
false ->
throw({bad_config, "Invalid formatter config", FmtCfg})
end;
validate_logfile_proplist([{flush_queue, FlushCfg} | Tail], Acc) ->
case is_boolean(FlushCfg) of
true ->
validate_logfile_proplist(Tail, [{flush_queue, FlushCfg} | Acc]);
false ->
throw({bad_config, "Invalid queue flush flag", FlushCfg})
end;
validate_logfile_proplist([{flush_threshold, Thr} | Tail], Acc) ->
case Thr of
_ when is_integer(Thr), Thr >= 0 ->
validate_logfile_proplist(Tail, [{flush_threshold, Thr} | Acc]);
_ ->
throw({bad_config, "Invalid queue flush threshold", Thr})
end;
validate_logfile_proplist([Other | _Tail], _Acc) ->
throw({bad_config, "Invalid option", Other}).
schedule_rotation(_, undefined) ->
checkOpts(Tail, true);
checkOpts([{level, Level} | Tail], IsFile) ->
?IIF(validate_loglevel(Level), checkOpts(Tail, IsFile), ({error, {invalid_log_level, Level}}));
checkOpts([{size, Size} | Tail], IsFile) when is_integer(Size), Size >= 0 ->
checkOpts(Tail, IsFile);
checkOpts([{count, Count} | Tail], IsFile) when is_integer(Count), Count >= 0 ->
checkOpts(Tail, IsFile);
checkOpts([{rotator, Rotator} | Tail], IsFile) when is_atom(Rotator) ->
checkOpts(Tail, IsFile);
checkOpts([{high_water_mark, HighWaterMark} | Tail], IsFile) when is_integer(HighWaterMark), HighWaterMark >= 0 ->
checkOpts(Tail, IsFile);
checkOpts([{date, _Date} | Tail], IsFile) ->
%% IMY-todo 使 rumUtil:parseRotateSpec(_Date)
checkOpts(Tail, IsFile);
checkOpts([{sync_interval, SyncInt} | Tail], IsFile) when is_integer(SyncInt), SyncInt >= 0 ->
checkOpts(Tail, IsFile);
checkOpts([{sync_size, SyncSize} | Tail], IsFile) when is_integer(SyncSize), SyncSize >= 0 ->
checkOpts(Tail, IsFile);
checkOpts([{check_interval, CheckInt} | Tail], IsFile) when is_integer(CheckInt), CheckInt >= 0; CheckInt == always ->
%% IMY-todo 使 always ->{check_interval, 0};
checkOpts(Tail, IsFile);
checkOpts([{sync_on, _Level} | Tail], IsFile) ->
%% IMY-todo 使 validate_loglevel(Level)
checkOpts(Tail, IsFile);
checkOpts([{formatter, Fmt} | Tail], IsFile) when is_atom(Fmt) ->
checkOpts(Tail, IsFile);
checkOpts([{formatter_config, FmtCfg} | Tail], IsFile) when is_list(FmtCfg) ->
checkOpts(Tail, IsFile);
checkOpts([{flush_queue, FlushCfg} | Tail], IsFile) when is_boolean(FlushCfg) ->
checkOpts(Tail, IsFile);
checkOpts([{flush_threshold, Thr} | Tail], IsFile) when is_integer(Thr), Thr >= 0 ->
checkOpts(Tail, IsFile);
checkOpts([Other | _Tail], _IsFile) ->
{error, {invalid_opt, Other}}.
scheduleRotation(undefined, _FileName) ->
ok;
schedule_rotation(Name, Date) ->
scheduleRotation(Date, Name) ->
erlang:send_after(rumUtil:calcNextRotateMs(Date), self(), {mRotate, Name}),
ok.
@ -469,37 +357,37 @@ close_file(#state{fd = FD} = State) ->
-ifdef(TEST).
get_loglevel_test() ->
{ok, Level, _} = handle_call(mGetLogLevel,
#state{name = "bar", level = rumUtil:config_to_mask(info), fd = 0, inode = 0, ctime = undefined}),
{ok, Level, _} = handleCall(mGetLogLevel,
#state{fileName = "bar", level = rumUtil:config_to_mask(info), fd = 0, inode = 0, ctime = undefined}),
?assertEqual(Level, rumUtil:config_to_mask(info)),
{ok, Level2, _} = handle_call(mGetLogLevel,
#state{name = "foo", level = rumUtil:config_to_mask(warning), fd = 0, inode = 0, ctime = undefined}),
{ok, Level2, _} = handleCall(mGetLogLevel,
#state{fileName = "foo", level = rumUtil:config_to_mask(warning), fd = 0, inode = 0, ctime = undefined}),
?assertEqual(Level2, rumUtil:config_to_mask(warning)).
rotation_test_() ->
{foreach,
fun() ->
SyncLevel = validate_loglevel(?DEFAULT_SYNC_LEVEL),
SyncSize = ?DEFAULT_SYNC_SIZE,
SyncInterval = ?DEFAULT_SYNC_INTERVAL,
Rotator = ?DEFAULT_ROTATION_MOD,
SyncLevel = validate_loglevel(?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{name = TestLog,
#state{fileName = TestLog,
level = ?DEBUG,
sync_on = SyncLevel,
sync_size = SyncSize,
sync_interval = SyncInterval,
check_interval = CheckInterval,
syncInterval = SyncInterval,
checkInterval = CheckInterval,
rotator = Rotator,
os_type = OsType}
osType = OsType}
end,
fun(#state{}) ->
ok = rumUtil:delete_test_dir()
end, [
fun(DefaultState = #state{name = TestLog, os_type = OsType, sync_size = SyncSize, sync_interval = SyncInterval, rotator = Rotator}) ->
fun(DefaultState = #state{fileName = TestLog, osType = OsType, sync_size = SyncSize, syncInterval = SyncInterval, rotator = Rotator}) ->
{"External rotation should work",
fun() ->
case OsType of
@ -511,23 +399,23 @@ rotation_test_() ->
{ok, FD, Inode, Ctime, _Size} = Rotator:openLogfile(TestLog, {SyncSize, SyncInterval}),
State0 = DefaultState#state{fd = FD, inode = Inode, ctime = Ctime},
State1 = write(State0, os:timestamp(), ?DEBUG, "hello world"),
?assertMatch(#state{name = TestLog, level = ?DEBUG, fd = FD, inode = Inode, ctime = Ctime}, State1),
?assertMatch(#state{fileName = TestLog, level = ?DEBUG, fd = FD, inode = Inode, ctime = Ctime}, State1),
?assertEqual(ok, file:delete(TestLog)),
State2 = write(State0, os:timestamp(), ?DEBUG, "hello world"),
%% assert file has changed
ExpState1 = #state{name = TestLog, level = ?DEBUG, fd = FD, inode = Inode, ctime = Ctime},
ExpState1 = #state{fileName = TestLog, level = ?DEBUG, fd = FD, inode = Inode, ctime = Ctime},
?assertNotEqual(ExpState1, State2),
?assertMatch(#state{name = TestLog, level = ?DEBUG}, State2),
?assertMatch(#state{fileName = TestLog, level = ?DEBUG}, State2),
?assertEqual(ok, file:rename(TestLog, TestLog ++ ".1")),
State3 = write(State2, os:timestamp(), ?DEBUG, "hello world"),
%% assert file has changed
?assertNotEqual(State3, State2),
?assertMatch(#state{name = TestLog, level = ?DEBUG}, State3),
?assertMatch(#state{fileName = TestLog, level = ?DEBUG}, State3),
ok
end
end}
end,
fun(DefaultState = #state{name = TestLog, sync_size = SyncSize, sync_interval = SyncInterval, rotator = Rotator}) ->
fun(DefaultState = #state{fileName = TestLog, sync_size = SyncSize, syncInterval = SyncInterval, rotator = Rotator}) ->
{"Internal rotation and delayed write",
fun() ->
TestLog0 = TestLog ++ ".0",
@ -538,7 +426,7 @@ rotation_test_() ->
{ok, FD, Inode, Ctime, _Size} = Rotator:openLogfile(TestLog, {SyncSize, SyncInterval}),
State0 = DefaultState#state{
fd = FD, inode = Inode, ctime = Ctime, size = RotationSize,
check_interval = CheckInterval, last_check = PreviousCheck},
checkInterval = CheckInterval, lastCheck = PreviousCheck},
%% new message within check interval with sync_on level
Msg1Timestamp = add_secs(PreviousCheck, 1),
@ -566,7 +454,7 @@ rotation_test_() ->
{ok, FInfo} = file:read_file_info(TestLog, [raw]),
?assert(RotationSize < FInfo#file_info.size),
%% ...no rotation yet
?assertEqual(PreviousCheck, State2#state.last_check),
?assertEqual(PreviousCheck, State2#state.lastCheck),
?assertNot(filelib:is_regular(TestLog0)),
%% new message after check interval
@ -1122,59 +1010,59 @@ config_validation_test_() ->
[
{"missing file",
?_assertEqual(false,
validate_logfile_proplist([{level, info}, {size, 10}]))
checkOpts([{level, info}, {size, 10}]))
},
{"bad level",
?_assertEqual(false,
validate_logfile_proplist([{file, "test.log"}, {level, blah}, {size, 10}]))
checkOpts([{file, "test.log"}, {level, blah}, {size, 10}]))
},
{"bad size",
?_assertEqual(false,
validate_logfile_proplist([{file, "test.log"}, {size, infinity}]))
checkOpts([{file, "test.log"}, {size, infinity}]))
},
{"bad count",
?_assertEqual(false,
validate_logfile_proplist([{file, "test.log"}, {count, infinity}]))
checkOpts([{file, "test.log"}, {count, infinity}]))
},
{"bad high water mark",
?_assertEqual(false,
validate_logfile_proplist([{file, "test.log"}, {high_water_mark, infinity}]))
checkOpts([{file, "test.log"}, {high_water_mark, infinity}]))
},
{"bad date",
?_assertEqual(false,
validate_logfile_proplist([{file, "test.log"}, {date, "midnight"}]))
checkOpts([{file, "test.log"}, {date, "midnight"}]))
},
{"blank date is ok",
?_assertMatch([_ | _],
validate_logfile_proplist([{file, "test.log"}, {date, ""}]))
checkOpts([{file, "test.log"}, {date, ""}]))
},
{"bad sync_interval",
?_assertEqual(false,
validate_logfile_proplist([{file, "test.log"}, {sync_interval, infinity}]))
checkOpts([{file, "test.log"}, {sync_interval, infinity}]))
},
{"bad sync_size",
?_assertEqual(false,
validate_logfile_proplist([{file, "test.log"}, {sync_size, infinity}]))
checkOpts([{file, "test.log"}, {sync_size, infinity}]))
},
{"bad check_interval",
?_assertEqual(false,
validate_logfile_proplist([{file, "test.log"}, {check_interval, infinity}]))
checkOpts([{file, "test.log"}, {check_interval, infinity}]))
},
{"bad sync_on level",
?_assertEqual(false,
validate_logfile_proplist([{file, "test.log"}, {sync_on, infinity}]))
checkOpts([{file, "test.log"}, {sync_on, infinity}]))
},
{"bad formatter module",
?_assertEqual(false,
validate_logfile_proplist([{file, "test.log"}, {formatter, "io:format"}]))
checkOpts([{file, "test.log"}, {formatter, "io:format"}]))
},
{"bad formatter config",
?_assertEqual(false,
validate_logfile_proplist([{file, "test.log"}, {formatter_config, blah}]))
checkOpts([{file, "test.log"}, {formatter_config, blah}]))
},
{"unknown option",
?_assertEqual(false,
validate_logfile_proplist([{file, "test.log"}, {rhubarb, spicy}]))
checkOpts([{file, "test.log"}, {rhubarb, spicy}]))
}
].

+ 2
- 2
src/eRum.erl Zobrazit soubor

@ -522,11 +522,11 @@ set_loghwm(Handler, Hwm) when is_integer(Hwm) ->
%% @doc Set the loghwm for a particular backend.
set_loghwm(Sink, Handler, Hwm) when is_integer(Hwm) ->
gen_event:call(Sink, Handler, {set_loghwm, Hwm}, infinity).
gen_event:call(Sink, Handler, {mSetLogHwm, Hwm}, infinity).
%% @doc Set the loghwm (log high water mark) for file backends with multiple identifiers
set_loghwm(Sink, Handler, Ident, Hwm) when is_integer(Hwm) ->
gen_event:call(Sink, {Handler, Ident}, {set_loghwm, Hwm}, infinity).
gen_event:call(Sink, {Handler, Ident}, {mSetLogHwm, Hwm}, infinity).
%% @private
add_trace_to_loglevel_config(Trace, Sink) ->

+ 1
- 1
src/utils/rumUtil.erl Zobrazit soubor

@ -607,7 +607,7 @@ makeInnerSinkName(Sink) ->
maybe_flush(undefined, #rumShaper{} = S) ->
S;
maybe_flush(Flag, #rumShaper{} = S) when is_boolean(Flag) ->
maybe_flush(Flag, #rumShaper{} = S) ->
S#rumShaper{flushQueue = Flag}.
-spec isFileChanged(FileName :: file:name_all(), Inode :: pos_integer(), Ctime :: file:date_time()) -> {boolean(), file:file_info() | undefined}.

Načítá se…
Zrušit
Uložit