aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--lib/sasl/doc/src/rb.xml26
-rw-r--r--lib/sasl/src/rb.erl117
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} ->