diff --git a/apps/iot/src/iot_logger.erl b/apps/iot/src/iot_logger.erl index 003d645..138a909 100644 --- a/apps/iot/src/iot_logger.erl +++ b/apps/iot/src/iot_logger.erl @@ -12,7 +12,7 @@ -behaviour(gen_server). %% API --export([start_link/1, write/2]). +-export([start_link/1, start_link/2, write/2]). %% gen_server callbacks -export([init/1, handle_call/3, handle_cast/2, handle_info/2, terminate/2, code_change/3]). @@ -22,6 +22,9 @@ -record(state, { file_name :: string(), date :: calendar:date(), + %% 用来保存历史文件信息 + queue = queue:new(), + counter = 5, file }). @@ -36,7 +39,12 @@ write(Pid, Data) when is_pid(Pid) -> -spec(start_link(FileName :: string()) -> {ok, Pid :: pid()} | ignore | {error, Reason :: term()}). start_link(FileName) when is_list(FileName) -> - gen_server:start_link(?MODULE, [FileName], []). + start_link(FileName, 5). + +-spec(start_link(FileName :: string(), Counter :: integer()) -> + {ok, Pid :: pid()} | ignore | {error, Reason :: term()}). +start_link(FileName, Counter) when is_list(FileName), is_integer(Counter) -> + gen_server:start_link(?MODULE, [FileName, Counter], []). %%%=================================================================== %%% gen_server callbacks @@ -47,12 +55,12 @@ start_link(FileName) when is_list(FileName) -> -spec(init(Args :: term()) -> {ok, State :: #state{}} | {ok, State :: #state{}, timeout() | hibernate} | {stop, Reason :: term()} | ignore). -init([FileName]) -> +init([FileName, Counter]) -> ensure_dir(), FilePath = make_file(FileName, erlang:date()), - {ok, File} = file:open(FilePath, [append, binary]), + {ok, IoDevice} = file:open(FilePath, [append, binary]), - {ok, #state{file = File, file_name = FileName, date = get_date()}}. + {ok, #state{file = {IoDevice, FilePath}, queue = queue:from_list([FilePath]), file_name = FileName, counter = Counter, date = get_date()}}. %% @private %% @doc Handling call messages @@ -73,22 +81,34 @@ handle_call(_Request, _From, State = #state{}) -> {noreply, NewState :: #state{}} | {noreply, NewState :: #state{}, timeout() | hibernate} | {stop, Reason :: term(), NewState :: #state{}}). -handle_cast({write, Data}, State = #state{file = OldFile, file_name = FileName, date = Date}) -> +handle_cast({write, Data}, State = #state{file = {OldIoDevice, OldFilePath}, queue = Q, counter = Counter, file_name = FileName, date = Date}) -> Line = iolist_to_binary([time_prefix(), <<" ">>, format(Data), <<$\n>>]), NDate = erlang:date(), + case maybe_new_file(Date, NDate) of true -> - file:close(OldFile), + ok = file:close(OldIoDevice), + %% 压缩文件 + ok = erl_tar:create(OldFilePath ++ ".tar", [OldFilePath], [compressed]), + %% 删除原来的文件 + ok = file:delete(OldFilePath), - FilePath = make_file(FileName, NDate), - {ok, File} = file:open(FilePath, [append, binary]), - ok = file:write(File, Line), - %% 清理历史的文件, 日志文件保留一个月的 - delete_old_files(FileName, 30), + %% 开启新的文件 + NewFilePath = make_file(FileName, NDate), + {ok, NewIoDevice} = file:open(NewFilePath, [append, binary]), + ok = file:write(NewIoDevice, Line), - {noreply, State#state{file = File, date = get_date()}}; + NQ = case queue:len(Q) >= Counter - 1 of + true -> + {{value, ExpiredFilePath}, Q2} = queue:out(Q), + ok = file:delete(ExpiredFilePath), + queue:in(NewFilePath, Q2); + false -> + queue:in(NewFilePath, Q) + end, + {noreply, State#state{file = {NewIoDevice, NewFilePath}, queue = NQ, date = get_date()}}; false -> - ok = file:write(OldFile, Line), + ok = file:write(OldIoDevice, Line), {noreply, State} end. @@ -158,12 +178,12 @@ get_date() -> maybe_new_file({Y, M, D}, {Y0, M0, D0}) -> not (Y =:= Y0 andalso M =:= M0 andalso D =:= D0). --spec delete_old_files(FileName :: string(), Days :: integer()) -> no_return(). -delete_old_files(FileName, Days) when is_list(FileName), is_integer(Days) -> - Seconds0 = calendar:datetime_to_gregorian_seconds(calendar:local_time()), - Seconds = Seconds0 - Days * 86400, - lists:foreach(fun(Day) -> - {Date, _} = calendar:gregorian_seconds_to_datetime(Seconds - Day * 86400), - FilePath = make_file(FileName, Date), - filelib:is_file(FilePath) andalso file:delete(FilePath) - end, lists:seq(1, 10)). \ No newline at end of file +%-spec delete_old_files(FileName :: string(), Days :: integer()) -> no_return(). +%delete_old_files(FileName, Days) when is_list(FileName), is_integer(Days) -> +% Seconds0 = calendar:datetime_to_gregorian_seconds(calendar:local_time()), +% Seconds = Seconds0 - Days * 86400, +% lists:foreach(fun(Day) -> +% {Date, _} = calendar:gregorian_seconds_to_datetime(Seconds - Day * 86400), +% FilePath = make_file(FileName, Date), +% filelib:is_file(FilePath) andalso file:delete(FilePath) +% end, lists:seq(1, 10)). \ No newline at end of file