From e394819231cff2f673abb4ffa016fc450797c116 Mon Sep 17 00:00:00 2001 From: SisMaker <1713699517@qq.com> Date: Thu, 11 Mar 2021 16:13:18 +0800 Subject: [PATCH] =?UTF-8?q?ft:=20backend=E7=9B=B8=E5=85=B3=E4=BF=AE?= =?UTF-8?q?=E6=94=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- include/eRum.hrl | 16 ++ src/backend/rumBkdConsole.erl | 6 +- src/backend/rumBkdFile.erl | 448 +++++++++++++--------------------- src/eRum.erl | 4 +- src/utils/rumUtil.erl | 2 +- 5 files changed, 190 insertions(+), 286 deletions(-) diff --git a/include/eRum.hrl b/include/eRum.hrl index 46a7a15..dc4b9ac 100644 --- a/include/eRum.hrl +++ b/include/eRum.hrl @@ -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 %% 默认日志文件选项 diff --git a/src/backend/rumBkdConsole.erl b/src/backend/rumBkdConsole.erl index acb6291..8cf9044 100644 --- a/src/backend/rumBkdConsole.erl +++ b/src/backend/rumBkdConsole.erl @@ -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 -> diff --git a/src/backend/rumBkdFile.erl b/src/backend/rumBkdFile.erl index 7946fba..a2ec615 100644 --- a/src/backend/rumBkdFile.erl +++ b/src/backend/rumBkdFile.erl @@ -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 -> - {ok, 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}])) } ]. diff --git a/src/eRum.erl b/src/eRum.erl index b2a7b90..57c47f7 100644 --- a/src/eRum.erl +++ b/src/eRum.erl @@ -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) -> diff --git a/src/utils/rumUtil.erl b/src/utils/rumUtil.erl index 05e79a0..235cc36 100644 --- a/src/utils/rumUtil.erl +++ b/src/utils/rumUtil.erl @@ -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}.