diff options
Diffstat (limited to 'lib/stdlib/src/log_mf_h.erl')
-rw-r--r-- | lib/stdlib/src/log_mf_h.erl | 202 |
1 files changed, 202 insertions, 0 deletions
diff --git a/lib/stdlib/src/log_mf_h.erl b/lib/stdlib/src/log_mf_h.erl new file mode 100644 index 0000000000..2729f27e51 --- /dev/null +++ b/lib/stdlib/src/log_mf_h.erl @@ -0,0 +1,202 @@ +%% +%% %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(log_mf_h). + +-behaviour(gen_event). + +-export([init/3, init/4]). + +-export([init/1, handle_event/2, handle_info/2, terminate/2]). +-export([handle_call/2, code_change/3]). + +%%----------------------------------------------------------------- + +-type dir() :: file:filename(). +-type b() :: non_neg_integer(). +-type f() :: 1..255. +-type pred() :: fun((term()) -> boolean()). + +%%----------------------------------------------------------------- + +-record(state, {dir :: dir(), + maxB :: b(), + maxF :: f(), + curB :: b(), + curF :: f(), + cur_fd :: file:fd(), + index = [], %% Seems unused - take out?? + pred :: pred()}). + +%%%----------------------------------------------------------------- +%%% This module implements an event handler that writes events +%%% to multiple files (configurable). +%%%----------------------------------------------------------------- +%% Func: init/3, init/4 +%% Args: Dir = string() +%% MaxB = integer() +%% MaxF = byte() +%% Pred = fun(Event) -> boolean() +%% Purpose: An event handler. Writes binary events +%% to files in the directory Dir. Each file is called +%% 1, 2, 3, ..., MaxF. Writes MaxB bytes on each file. +%% Creates a file called 'index' in the Dir. +%% This file contains the last written FileName. +%% On startup, this file is read, and the next available +%% filename is used as first logfile. +%% Each event is filtered with the predicate function Pred. +%% Reports can be browsed with Report Browser Tool (rb). +%% Returns: Args = term() +%% The Args term should be used in a call to +%% gen_event:add_handler(EventMgr, log_mf_h, Args) +%% EventMgr = pid() | atom(). +%%----------------------------------------------------------------- + +-spec init(dir(), b(), f()) -> {dir(), b(), f(), pred()}. + +init(Dir, MaxB, MaxF) -> init(Dir, MaxB, MaxF, fun(_) -> true end). + +-spec init(dir(), b(), f(), pred()) -> {dir(), b(), f(), pred()}. + +init(Dir, MaxB, MaxF, Pred) -> {Dir, MaxB, MaxF, Pred}. + +%%----------------------------------------------------------------- +%% Call-back functions from gen_event +%%----------------------------------------------------------------- + +-spec init({dir(), b(), f(), pred()}) -> {'ok', #state{}} | {'error', term()}. + +init({Dir, MaxB, MaxF, Pred}) when is_integer(MaxF), MaxF > 0, MaxF < 256 -> + First = + case read_index_file(Dir) of + {ok, LastWritten} -> inc(LastWritten, MaxF); + _ -> 1 + end, + case catch file_open(Dir, First) of + {ok, Fd} -> + {ok, #state{dir = Dir, maxB = MaxB, maxF = MaxF, pred = Pred, + curF = First, cur_fd = Fd, curB = 0}}; + Error -> Error + end. + +%%----------------------------------------------------------------- +%% The handle_event/2 function may crash! In this case, this +%% handler is removed by gen_event from the event handlers. +%% Fails: 'file_open' if file:open failed for a log file. +%% 'write_index_file' if file:write_file failed for the +%% index file. +%% {file_exit, Reason} if the current Fd crashes. +%%----------------------------------------------------------------- + +-spec handle_event(term(), #state{}) -> {'ok', #state{}}. + +handle_event(Event, State) -> + #state{curB = CurB, maxB = MaxB, curF = CurF, maxF = MaxF, + dir = Dir, cur_fd = CurFd, pred = Pred} = State, + case catch Pred(Event) of + true -> + Bin = term_to_binary(tag_event(Event)), + Size = byte_size(Bin), + NewState = + if + CurB + Size < MaxB -> State; + true -> + ok = file:close(CurFd), + NewF = inc(CurF, MaxF), + {ok, NewFd} = file_open(Dir, NewF), + State#state{cur_fd = NewFd, curF = NewF, curB = 0} + end, + [Hi,Lo] = put_int16(Size), + file:write(NewState#state.cur_fd, [Hi, Lo, Bin]), + {ok, NewState#state{curB = NewState#state.curB + Size + 2}}; + _ -> + {ok, State} + end. + +-spec handle_info(term(), #state{}) -> {'ok', #state{}}. + +handle_info({emulator, GL, Chars}, State) -> + handle_event({emulator, GL, Chars}, State); +handle_info(_, State) -> + {ok, State}. + +-spec terminate(term(), #state{}) -> #state{}. + +terminate(_, State) -> + ok = file:close(State#state.cur_fd), + State. + +-spec handle_call('null', #state{}) -> {'ok', 'null', #state{}}. + +handle_call(null, State) -> + {ok, null, State}. + +-spec code_change(term(), #state{}, term()) -> {'ok', #state{}}. + +code_change(_OldVsn, State, _Extra) -> + {ok, State}. + +%%----------------------------------------------------------------- +%% Misc local functions +%%----------------------------------------------------------------- + +file_open(Dir, FileNo) -> + case file:open(Dir ++ [$/ | integer_to_list(FileNo)], [raw, write]) of + {ok, Fd} -> + write_index_file(Dir, FileNo), + {ok, Fd}; + _ -> + exit({file, open}) + end. + +put_int16(I) -> + [((I band 16#ff00) bsr 8),I band 16#ff]. + +tag_event(Event) -> + {erlang:localtime(), Event}. + +read_index_file(Dir) -> + case file:open(Dir ++ "/index", [raw, read]) of + {ok, Fd} -> + Res = case catch file:read(Fd, 1) of + {ok, [Index]} -> {ok, Index}; + _ -> error + end, + ok = file:close(Fd), + Res; + _ -> error + end. + +%%----------------------------------------------------------------- +%% Write the index file. This file contains one binary with +%% the last used filename (an integer). +%%----------------------------------------------------------------- + +write_index_file(Dir, Index) -> + case file:open(Dir ++ "/index", [raw, write]) of + {ok, Fd} -> + file:write(Fd, [Index]), + ok = file:close(Fd); + _ -> exit(open_index_file) + end. + +inc(N, Max) -> + if + N < Max -> N + 1; + true -> 1 + end. |