diff options
-rw-r--r-- | lib/sasl/doc/src/rb.xml | 26 | ||||
-rw-r--r-- | lib/sasl/src/rb.erl | 117 |
2 files changed, 141 insertions, 2 deletions
diff --git a/lib/sasl/doc/src/rb.xml b/lib/sasl/doc/src/rb.xml index 810f7dca6b..0b5df29333 100644 --- a/lib/sasl/doc/src/rb.xml +++ b/lib/sasl/doc/src/rb.xml @@ -43,6 +43,32 @@ </description> <funcs> <func> + <name>filter(Filters)</name> + <fsummary>Filter reports and displays them on the screen</fsummary> + <type> + <v>Filters = [filter()]</v> + <v>filter() = {Key, Value} | {Key, Value, no} | {Key, RegExp, re} | {Key, RegExp, re, no}</v> + <v>Key = term()</v> + <v>Value = term()</v> + <v>RegExp = string() | {string, Options} | mp(), {mp(), Options}</v> + </type> + <desc> + <p>This function displays the reports that match the provided filters.</p> + <p> + When a filter includes the <c>no</c> atom it will exclude the reports that match + that filter. + </p> + <p> + The reports are matched using the <c>proplists</c> module. The report must be a proplist + to be matched against any of the <c>filters()</c>. + </p> + <p> + If the filter is of the form <c>{Key, RegExp, re}</c> the report must contain an element with + <c>key = Key</c> and <c>Value</c> must match the RegExp regular expression. + </p> + </desc> + </func> + <func> <name>grep(RegExp)</name> <fsummary>Search the reports for a regular expression</fsummary> <type> diff --git a/lib/sasl/src/rb.erl b/lib/sasl/src/rb.erl index 05f1230dd1..5167f961ec 100644 --- a/lib/sasl/src/rb.erl +++ b/lib/sasl/src/rb.erl @@ -22,7 +22,7 @@ %% 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([list/0, list/1, show/0, show/1, grep/1, filter/1, start_log/1, stop_log/0]). -export([h/0, help/0]). %% Internal exports @@ -73,6 +73,9 @@ show(Type) when is_atom(Type) -> grep(RegExp) -> gen_server:call(rb_server, {grep, RegExp}, infinity). +filter(Filters) when is_list(Filters) -> + gen_server:call(rb_server, {filter, Filters}, infinity). + start_log(FileName) -> gen_server:call(rb_server, {start_log, FileName}). stop_log() -> gen_server:call(rb_server, stop_log). @@ -93,6 +96,10 @@ help() -> io:format("rb:grep(RegExp) - print reports containing RegExp.~n"), io:format(" RegExp must be a valid argument for ~n"), io:format(" the function re:run/2 or re:run/3.~n"), + io:format("rb:filter(Filters) - print reports matching Filters.~n"), + io:format(" reports must be proplists.~n"), + io:format(" Filters is a list of tuples of the following form:~n"), + print_filters(), 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"), @@ -135,6 +142,17 @@ print_types() -> io:format(" - progress~n"), io:format(" - error~n"). +print_filters() -> + io:format(" - {Key, Value}~n"), + io:format(" includes report containing {Key, Value}~n"), + io:format(" - {Key, Value, no}~n"), + io:format(" excludes report containing {Key, Value}~n"), + io:format(" - {Key, RegExp, re}~n"), + io:format(" RegExp must be a valid argument for ~n"), + io:format(" the function re:run/2 or re:run/3.~n"), + io:format(" - {Key, RegExp, re, no}~n"), + io:format(" excludes report containing {Key, RegExp}~n"). + init(Options) -> process_flag(priority, low), process_flag(trap_exit, true), @@ -197,7 +215,11 @@ handle_call({grep, RegExp}, _From, State) -> catch error:Error -> {reply, {error, Error}, State} - end. + end; +handle_call({filter, Filters}, _From, State) -> + #state{dir = Dir, data = Data, device = Device, abort = Abort, log = Log} = State, + NewDevice = filter_all_reports(Dir, Data, Filters, Device, Abort, Log), + {reply, ok, State#state{device = NewDevice}}. terminate(_Reason, #state{device = Device}) -> close_device(Device). @@ -658,6 +680,97 @@ run_re(Subject, Regexp, Options) -> match end. +filter_all_reports(_Dir, [], _Filters, Device, _Abort, _Log) -> + Device; +filter_all_reports(Dir, Data, Filters, Device, Abort, Log) -> + {Next,Device1} = filter_report(Dir, Data, Filters, element(1, hd(Data)), + Device, Abort, Log), + if Next == abort -> + Device1; + true -> + filter_all_reports(Dir, tl(Data), Filters, Device1, Abort, Log) + end. + +filter_report(Dir, Data, Filters, Number, Device, Abort, Log) -> + case find_report(Data, Number) of + {Fname, FilePosition} -> + FileName = lists:concat([Dir, Fname]), + case file:open(FileName, [read]) of + {ok, Fd} -> + filter_rep(Filters, Fd, FilePosition, Device, Abort, Log); + _ -> + io:format("rb: can't open file ~p~n", [Fname]), + {proceed,Device} + end; + no_report -> + {proceed,Device} + end. + +filter_rep(Filters, Fd, FilePosition, Device, Abort, Log) -> + case read_rep_msg(Fd, FilePosition) of + {Date, Msg} -> + % io:format("Date: ~p Message: ~p~n", [Date, Msg]), + {_D, M} = Msg, + {_, _, M2} = M, + case M2 of + {_, _, Report} -> + case filter_report(Filters, Report) of + true -> + case catch rb_format_supp:print(Date, Msg, Device) of + {'EXIT', _} -> + handle_bad_form(Date, Msg, Device, Abort, Log); + _ -> + {proceed,Device} + end; + _ -> + {proceed, Device} + end; + _ -> + {proceed,Device} + end; + _ -> + io:format("rb: Cannot read from file~n"), + {proceed,Device} + end. + +filter_report([], _Msg) -> + true; +filter_report([{Key, Value}|T], Msg) -> + case proplists:get_value(Key, Msg) of + Value -> + filter_report(T, Msg); + _ -> + false + end; +filter_report([{Key, Value, no}|T], Msg) -> + case proplists:get_value(Key, Msg) of + Value -> + false; + _ -> + filter_report(T, Msg) + end; +filter_report([{Key, RegExp, re}|T], Msg) -> + case proplists:get_value(Key, Msg) of + undefined -> + false; + Value -> + case re:run(Value, RegExp) of + {match, _} -> + filter_report(T, Msg); + _ -> false + end + end; +filter_report([{Key, RegExp, re, no}|T], Msg) -> + case proplists:get_value(Key, Msg) of + undefined -> + false; + Value -> + case re:run(Value, RegExp) of + {match, _} -> false; + _ -> filter_report(T, Msg) + end + end. + read_rep(Fd, FilePosition, Device, Abort, Log) -> case read_rep_msg(Fd, FilePosition) of {Date, Msg} -> |