aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAlvaro Videla <[email protected]>2009-12-22 22:54:07 +0800
committerBjörn Gustavsson <[email protected]>2010-02-14 12:15:09 +0100
commite99ec8e235beb16d35e5a940b814061fb87db989 (patch)
tree09e69df34ebaef9c380fdbb045abc755831bcba2
parent501b9236450bc1f38d3daf9d9f0dc60b72299d6c (diff)
downloadotp-e99ec8e235beb16d35e5a940b814061fb87db989.tar.gz
otp-e99ec8e235beb16d35e5a940b814061fb87db989.tar.bz2
otp-e99ec8e235beb16d35e5a940b814061fb87db989.zip
New rb:filter/1 function to ease report filtering
Currently in the rb module the only way to filter reports is by using the grep/1 or re/1 functions that use Regular Expressions. This new function allow us to specify detailed filters that will match against our reports. Since the reports are proplists the filters are tuples of the form {Key, Value}. If the report contains that tuple, it will be displayed. Usage: 1> rb:filter([{"foo", "bar"}, {"abc", "value"}]). 2> rb:filter([{"foo", "bar", no}]). % excludes reports containing {"foo", "bar"} 3> rb:filter([{"foo", RegExp, re}]). % the report must contain an element with Key = "foo" % and Value must match RegExp
-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} ->