⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 rb.erl

📁 OTP是开放电信平台的简称
💻 ERL
📖 第 1 页 / 共 2 页
字号:
%% ``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 via the world wide web 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.%% %% The Initial Developer of the Original Code is Ericsson Utvecklings AB.%% Portions created by Ericsson are Copyright 1999, Ericsson Utvecklings%% AB. All Rights Reserved.''%% %%     $Id$%%-module(rb).-behaviour(gen_server).%% External exports-export([start/0, start/1, stop/0, rescan/0, rescan/1]).-export([list/0, list/1, show/0, show/1, grep/1, start_log/1, stop_log/0]).-export([h/0, help/0]).%% Internal exports-export([start_link/1]).%% gen_server callbacks-export([init/1, terminate/2, handle_call/3,	 handle_cast/2, handle_info/2, code_change/3]).%%%-----------------------------------------------------------------%%% Report Browser Tool.%%% Formats Error reports written by log_mf_h%%%------------------------------------------------------------------record(state, {dir, data, device, max, type, abort, log}).%%-----------------------------------------------------------------%% Interface functions.%% For available options; see print_options().%%-----------------------------------------------------------------start() -> start([]).start(Options) ->    supervisor:start_child(sasl_sup, 			   {rb_server, {rb, start_link, [Options]},			    temporary, brutal_kill, worker, [rb]}).start_link(Options) ->    gen_server:start_link({local, rb_server}, rb, Options, []).stop() ->     gen_server:call(rb_server, stop),    supervisor:delete_child(sasl_sup, rb_server).rescan() -> rescan([]).rescan(Options) ->    gen_server:call(rb_server, {rescan, Options}, infinity).list() -> list(all).list(Type) -> gen_server:call(rb_server, {list, Type}, infinity).show() ->     gen_server:call(rb_server, show, infinity).show(Number) when is_integer(Number) ->     gen_server:call(rb_server, {show_number, Number}, infinity);show(Type) when is_atom(Type) ->    gen_server:call(rb_server, {show_type, Type}, infinity).grep(RegExp) -> gen_server:call(rb_server, {grep, RegExp}, infinity).start_log(FileName) -> gen_server:call(rb_server, {start_log, FileName}).stop_log() -> gen_server:call(rb_server, stop_log).h() -> help().help() ->    io:format("~nReport Browser Tool - usage~n"),    io:format("===========================~n"),    io:format("rb:start()         - start the rb_server with default options~n"),    io:format("rb:start(Options)  - where Options is a list of:~n"),    print_options(),    io:format("rb:h()             - print this help~n"),    io:format("rb:help()          - print this help~n"),    io:format("rb:list()          - list all reports~n"),    io:format("rb:list(Type)      - list all reports of type Type~n"),    io:format("      currently supported types are:~n"),    print_types(),    io:format("rb:grep(RegExp)    - print reports containing RegExp~n"),    io:format("rb:rescan()        - rescans the report directory with same~n"),    io:format("                     options.~n"),    io:format("rb:rescan(Options) - rescans the report directory with new~n"),    io:format("                     options. Options is same as in start/1.~n"),    io:format("rb:show(Number)    - print report no Number~n"),    io:format("rb:show(Type)      - print all reports of type Type~n"),    io:format("rb:show()          - print all reports~n"),    io:format("rb:start_log(File) - redirect all reports to file~n"),    io:format("rb:stop_log()      - close the log file and redirect to~n"),    io:format("                     standard_io~n"),    io:format("rb:stop            - stop the rb_server~n").%%-----------------------------------------------------------------%% Internal functions.%%-----------------------------------------------------------------%%-----------------------------------------------------------------%% MAKE SURE THESE TWO FUNCTIONS ARE UPDATED!%%-----------------------------------------------------------------print_options() ->    io:format("      {start_log, FileName}~n"),    io:format("         - default: standard_io~n"),    io:format("      {max, MaxNoOfReports}~n"),    io:format("         - MaxNoOfReports should be an integer or 'all'~n"),    io:format("         - default: all~n"),    io:format("      {report_dir, DirString}~n"),    io:format("         - DirString should be a string without trailing~n"),    io:format("         - directory delimiter.~n"),    io:format("         - default: {sasl, error_logger_mf_dir}~n"),    io:format("      {type, ReportType}~n"),    io:format("         - ReportType should be a supported type, 'all'~n"),    io:format("         - or a list of supported types~n"),    io:format("         - default: all~n"),    io:format("      {abort_on_error, Bool}~n"),    io:format("         - Bool: true | false~n"),    io:format("         - default: false~n").print_types() ->    io:format("         - crash_report~n"),    io:format("         - supervisor_report~n"),    io:format("         - progress~n"),    io:format("         - error~n").	init(Options) ->    process_flag(priority, low),    process_flag(trap_exit, true),    Log = get_option(Options, start_log, standard_io),    Device = open_log_file(Log),    Dir = get_report_dir(Options),    Max = get_option(Options, max, all),    Type = get_option(Options, type, all),    Abort = get_option(Options, abort_on_error, false),    Data = scan_files(Dir ++ "/", Max, Type),    {ok, #state{dir = Dir ++ "/", data = Data, device = Device,		max = Max, type = Type, abort = Abort, log = Log}}.handle_call({rescan, Options}, _From, State) ->    {Device,Log1} = 	case get_option(Options, start_log, {undefined}) of	    {undefined} -> 		{State#state.device,State#state.log};	    Log ->		close_device(State#state.device),		{open_log_file(Log),Log}	end,    Max = get_option(Options, max, State#state.max),    Type = get_option(Options, type, State#state.type),    Abort = get_option(Options, abort_on_error, false),    Data = scan_files(State#state.dir, Max, Type),    NewState = State#state{data = Data, max = Max, type = Type,			   device = Device, abort = Abort, log = Log1},    {reply, ok, NewState};handle_call(stop, _From, State) ->    {stop, normal, stopped, State};handle_call(_, _From, #state{data = undefined}) ->    {reply, {error, no_data}, #state{}};handle_call({list, Type}, _From, State) ->    print_list(State#state.data, Type),    {reply, ok, State};handle_call({start_log, FileName}, _From, State) ->    NewDevice = open_log_file(FileName),    {reply, ok, State#state{device = NewDevice}};handle_call(stop_log, _From, State) ->    close_device(State#state.device),    {reply, ok, State#state{device = standard_io}};handle_call({show_number, Number}, _From, State) ->    #state{dir = Dir, data = Data, device = Device, abort = Abort, log = Log} = State,    NewDevice = print_report_by_num(Dir, Data, Number, Device, Abort, Log),    {reply, ok, State#state{device = NewDevice}};handle_call({show_type, Type}, _From, State) ->    #state{dir = Dir, data = Data, device = Device, abort = Abort, log = Log} = State,    NewDevice = print_typed_reports(Dir, Data, Type, Device, Abort, Log),    {reply, ok, State#state{device = NewDevice}};handle_call(show, _From, State) ->    #state{dir = Dir, data = Data, device = Device, abort = Abort, log = Log} = State,    NewDevice = print_all_reports(Dir, Data, Device, Abort, Log),    {reply, ok, State#state{device = NewDevice}};handle_call({grep, RegExp}, _From, State) ->    #state{dir = Dir, data = Data, device = Device, abort = Abort, log = Log} = State,    NewDevice = print_grep_reports(Dir, Data, RegExp, Device, Abort, Log),    {reply, ok, State#state{device = NewDevice}}.terminate(_Reason, #state{device = Device}) ->    close_device(Device).handle_cast(_Msg, State) ->    {noreply, State}.handle_info(_Info, State) ->    {noreply, State}.code_change(_OldVsn, State, _Extra) ->    {ok, State}.%%-----------------------------------------------------------------%% Func: open_log_file/1%% Args: FileName | standard_io%% Returns: A Device for later use in call to io:format%%-----------------------------------------------------------------open_log_file(standard_io) -> standard_io;open_log_file(FileName) ->    case file:open(FileName, [write,append]) of	{ok, Fd} -> Fd;	Error -> 	    io:format("rb: Cannot open file '~s' (~w).~n",		      [FileName, Error]),	    io:format("rb: Using standard_io~n"),	    standard_io    end.close_device(Fd) when is_pid(Fd) ->    catch file:close(Fd);close_device(_) -> ok.get_option(Options, Key, Default) ->    case lists:keysearch(Key, 1, Options) of	{value, {_Key, Value}} -> Value;	_ -> Default    end.get_report_dir(Options) ->    case lists:keysearch(report_dir, 1, Options) of	{value, {_Key, RptDir}} -> RptDir;	_ ->	    case catch application:get_env(sasl, error_logger_mf_dir) of		{ok, Dir} -> Dir;		_ ->		    exit("cannot locate report directory")	    end    end.%%-----------------------------------------------------------------%% Func: scan_files(RptDir, Max, Type)%% Args: RptDir ::= string().%%       Max ::= integer() | all, describing how many reports%5               to read.%%       Type ::= atom(), describing which reports to read.%% Purpose: Scan all report files one time, and build a list of%%          small elements %% Returns: Data, where Data is a list of%%          {Number, Type, ShortDescr, Date, Fname, FilePosition}.%%-----------------------------------------------------------------scan_files(RptDir, Max, Type) ->    case file:open(RptDir ++ "/index", [raw, read]) of	{ok, Fd} ->	    case catch file:read(Fd, 1) of		{ok, [LastWritten]} -> 		    Files = make_file_list(RptDir, LastWritten),		    scan_files(RptDir, Files, Max, Type);				_ -> exit("cannot read the index file")	    end;	_ -> exit("cannot read the index file")    end.make_file_list(Dir, FirstFileNo) ->    case file:list_dir(Dir) of	{ok, FileNames} ->	    FileNumbers = lists:zf(fun(Name) ->					   case catch list_to_integer(Name) of					       Int when is_integer(Int) ->						   {true, Int};					       _ ->						   false					   end				   end,				   FileNames),	    shift(lists:sort(FileNumbers), FirstFileNo);	_ -> exit({bad_directory, Dir})    end.					  shift(List, First) ->     shift(List, First, []).shift([H | T], H, Res) ->    [H | Res] ++ lists:reverse(T);shift([H | T], First, Res) ->    shift(T, First, [H | Res]);shift([], _, Res) ->    Res.%%-----------------------------------------------------------------%% Func: scan_files(Dir, Files, Max, Type)%% Args: Files is a list of FileName.%% Purpose: Scan the report files in the index variable.%% Returns: {Number, Type, ShortDescr, Date, FileName, FilePosition}%%-----------------------------------------------------------------scan_files(Dir, Files, Max, Type) ->    scan_files(Dir, 1, Files, [], Max, Type).scan_files(_Dir, _, [], Res, _Max, _Type) -> Res;scan_files(_Dir, _, _Files, Res, Max, _Type) when Max =< 0 -> Res;scan_files(Dir, No, [H|T], Res, Max, Type) ->    Data = get_report_data_from_file(Dir, No, H, Max, Type),    Len = length(Data),    NewMax = dec_max(Max, Len),    NewNo = No + Len,    NewData = Data ++ Res,    scan_files(Dir, NewNo, T, NewData, NewMax, Type).dec_max(all, _) -> all;dec_max(X,Y) -> X-Y.get_report_data_from_file(Dir, No, FileNr, Max, Type) ->	    Fname = integer_to_list(FileNr),    FileName = lists:concat([Dir, Fname]),    case file:open(FileName, read) of	{ok, Fd} when is_pid(Fd) -> read_reports(No, Fd, Fname, Max, Type);	_ -> [{No, unknown, "Can't open file " ++ Fname, "???", Fname, 0}]    end.%%-----------------------------------------------------------------%% Func: read_reports(No, Fd, Fname, Max, Type)%% Purpose: Read reports from one report file.%% Returns: A list of {No, Type, ShortDescr, Date, FileName, FilePosition}%% Note: We have to read all reports, and then check the max-%%       variable, because the reports are reversed on the file, and%%       we may need the last ones.%%-----------------------------------------------------------------read_reports(No, Fd, Fname, Max, Type) ->    io:format("rb: reading report..."),    case catch read_reports(Fd, [], Type) of	{ok, Res} -> 	    file:close(Fd),	    io:format("done.~n"),	    NewRes = 		if		    length(Res) > Max ->			lists:sublist(Res, 1, Max);		    true ->			Res		end,	    add_report_data(NewRes, No, Fname);	{error, [Problem | Res]} ->	    file:close(Fd),	    io:format("Error: ~p~n",[Problem]),	    io:format("Salvaged ~p entries from corrupt report file ~s...~n",		      [length(Res),Fname]),	    NewRes = 		if		    length([Problem|Res]) > Max ->

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -