aboutsummaryrefslogtreecommitdiffstats
path: root/lib
diff options
context:
space:
mode:
authorErlang/OTP <[email protected]>2010-02-16 07:37:52 +0000
committerErlang/OTP <[email protected]>2010-02-16 07:37:52 +0000
commitad8ff2174e6ed4becb0a267f82c9f0163142f147 (patch)
tree1fd439d39d21fcfb5ea45d7f90f6dc4bf08aa291 /lib
parent7aa2cb2e64cd404f8a9f388d85ab287ced95f139 (diff)
parent242c70ed5f0e2b84e9608bace183052e745614ed (diff)
downloadotp-ad8ff2174e6ed4becb0a267f82c9f0163142f147.tar.gz
otp-ad8ff2174e6ed4becb0a267f82c9f0163142f147.tar.bz2
otp-ad8ff2174e6ed4becb0a267f82c9f0163142f147.zip
Merge branch 'va/rb-improvements' into ccase/r13b04_dev
* va/rb-improvements: New rb:filter/2 to filter reports by date New rb:filter/1 function to ease report filtering Modify rb:grep/1 to grep reports using the re module Fix minor typo in read_report/1 OTP-8443 The re:grep/1 function now uses the 're' module instead of the deprecated 'regexp' module. There are new functions rb:filter/1 and rb:filter/2 for easier filtering of reports. (Thanks to Alvaro Videla.)
Diffstat (limited to 'lib')
-rw-r--r--lib/sasl/doc/src/rb.xml86
-rw-r--r--lib/sasl/src/rb.erl234
2 files changed, 287 insertions, 33 deletions
diff --git a/lib/sasl/doc/src/rb.xml b/lib/sasl/doc/src/rb.xml
index 5b49a7bced..f35ceb5777 100644
--- a/lib/sasl/doc/src/rb.xml
+++ b/lib/sasl/doc/src/rb.xml
@@ -4,23 +4,21 @@
<erlref>
<header>
<copyright>
- <year>1996</year>
- <year>2007</year>
- <holder>Ericsson AB, All Rights Reserved</holder>
+ <year>1996</year><year>2010</year>
+ <holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
- 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/.
+ 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.
+ 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 AB.
</legalnotice>
<title>rb</title>
@@ -43,20 +41,70 @@
</description>
<funcs>
<func>
+ <name>filter(Filters)</name>
+ <name>filter(Filters, Dates)</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>
+ <v>Dates = {DateFrom, DateTo} | {DateFrom, from} | {DateTo, to}</v>
+ <v>DateFrom = DateTo = {date(), time()}</v>
+ <v>date() and time() are the same type as in the <c>calendar</c> module</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>
+ <p>
+ If the Dates parameter is provided, then the reports are filtered according to the date
+ when they occurred. If Dates is of the form <c>{DateFrom, from}</c> then reports that occurred
+ after DateFrom are displayed.
+ </p>
+ <p>
+ If Dates is of the form <c>{DateTo, to}</c> then reports that occurred before DateTo
+ are displayed.
+ </p>
+ <p>
+ If two Dates are provided, then reports that occurred between those dates are returned.
+ </p>
+ <p>
+ If you only want to filter only by dates, then you can provide the empty list as the Filters
+ parameter.
+ </p>
+ <p>
+ See <c>rb:grep/1</c> for more information on the RegExp parameter.
+ </p>
+ </desc>
+ </func>
+ <func>
<name>grep(RegExp)</name>
<fsummary>Search the reports for a regular expression</fsummary>
<type>
- <v>RegExp = string()</v>
+ <v>RegExp = string() | {string, Options} | mp(), {mp(), Options}</v>
</type>
<desc>
<p>All reports containing the regular expression <c>RegExp</c>
are printed.
</p>
- <p><c>RegExp</c> is a string containing the regular
- expression. Refer to the module <c>regexp</c> in the STDLIB
- reference manual
- for a definition of valid regular expressions. They are
- essentially the same as the UNIX command <c>egrep</c>.
+ <p><c>RegExp</c> can be a string containing the regular
+ expression; a tuple with the string and the options for
+ compilation; a compiled regular expression; a compiled
+ regular expression and the options for running it.
+ Refer to the module <c>re</c> and specially the function <c>re:run/3</c>
+ for a definition of valid regular expressions and options.
</p>
</desc>
</func>
diff --git a/lib/sasl/src/rb.erl b/lib/sasl/src/rb.erl
index 00d86285e5..332a99c6f9 100644
--- a/lib/sasl/src/rb.erl
+++ b/lib/sasl/src/rb.erl
@@ -1,19 +1,19 @@
%%
%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 1996-2009. All Rights Reserved.
-%%
+%%
+%% Copyright Ericsson AB 1996-2010. 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(rb).
@@ -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, filter/2, start_log/1, stop_log/0]).
-export([h/0, help/0]).
%% Internal exports
@@ -73,6 +73,12 @@ 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).
+
+filter(Filters, FDates) when is_list(Filters) andalso is_tuple(FDates) ->
+ gen_server:call(rb_server, {filter, {Filters, FDates}}, infinity).
+
start_log(FileName) -> gen_server:call(rb_server, {start_log, FileName}).
stop_log() -> gen_server:call(rb_server, stop_log).
@@ -90,7 +96,17 @@ help() ->
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: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:filter(Filters, Dates) -~n"),
+ io:format(" same as rb:filter/1 but accepts date ranges to filter reports.~n"),
+ io:format(" Dates must be of the following form:~n"),
+ print_dates(),
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"),
@@ -133,7 +149,26 @@ 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").
+
+print_dates() ->
+ io:format(" - {StartDate, EndDate}~n"),
+ io:format(" StartDate = EndDate = {{Y-M-D},{H,M,S}} ~n"),
+ io:format(" prints the reports with date between StartDate and EndDate~n"),
+ io:format(" - {StartDate, from}~n"),
+ io:format(" prints the reports with date greater than StartDate~n"),
+ io:format(" - {EndDate, to}~n"),
+ io:format(" prints the reports with date lesser than StartDate~n").
+
init(Options) ->
process_flag(priority, low),
process_flag(trap_exit, true),
@@ -190,8 +225,22 @@ handle_call(show, _From, State) ->
{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}}.
+ try print_grep_reports(Dir, Data, RegExp, Device, Abort, Log) of
+ NewDevice ->
+ {reply, ok, State#state{device = NewDevice}}
+ catch
+ error:Error ->
+ {reply, {error, Error}, State}
+ end;
+handle_call({filter, Filters}, _From, State) ->
+ #state{dir = Dir, data = Data, device = Device, abort = Abort, log = Log} = State,
+ try filter_all_reports(Dir, Data, Filters, Device, Abort, Log) of
+ NewDevice ->
+ {reply, ok, State#state{device = NewDevice}}
+ catch
+ error:Error ->
+ {reply, {error, Error}, State}
+ end.
terminate(_Reason, #state{device = Device}) ->
close_device(Device).
@@ -415,7 +464,7 @@ read_report(Fd) ->
Ref = make_ref(),
case (catch {Ref,binary_to_term(Bin)}) of
{'EXIT',_} ->
- {error, "Inclomplete erlang term in log"};
+ {error, "Incomplete erlang term in log"};
{Ref,Term} ->
{ok, Term}
end
@@ -622,21 +671,178 @@ check_rep(Fd, FilePosition, Device, RegExp, Number, Abort, Log) ->
case read_rep_msg(Fd, FilePosition) of
{Date, Msg} ->
MsgStr = lists:flatten(io_lib:format("~p",[Msg])),
- case regexp:match(MsgStr, RegExp) of
- {match, _, _} ->
+ case run_re(MsgStr, RegExp) of
+ match ->
io:format("Found match in report number ~w~n", [Number]),
case catch rb_format_supp:print(Date, Msg, Device) of
{'EXIT', _} ->
handle_bad_form(Date, Msg, Device, Abort, Log);
_ ->
{proceed,Device}
- end;
+ end;
+ _ ->
+ {proceed,Device}
+ end;
+ _ ->
+ io:format("rb: Cannot read from file~n"),
+ {proceed,Device}
+ end.
+
+run_re(Subject, {Regexp, Options}) ->
+ run_re(Subject, Regexp, Options);
+run_re(Subject, Regexp) ->
+ run_re(Subject, Regexp, []).
+
+run_re(Subject, Regexp, Options) ->
+ case re:run(Subject, Regexp, Options) of
+ nomatch ->
+ nomatch;
+ _ ->
+ 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, FDates}, Fd, FilePosition, Device, Abort, Log) ->
+ RepMsg = read_rep_msg(Fd, FilePosition),
+ case RepMsg of
+ {_DateStr, {Date, _Msg}} ->
+ case compare_dates(Date, FDates) of
+ true ->
+ print_filter_report(RepMsg, Filters, Device, Abort, Log);
_ ->
{proceed,Device}
end;
_ ->
io:format("rb: Cannot read from file~n"),
{proceed,Device}
+ end;
+filter_rep(Filters, Fd, FilePosition, Device, Abort, Log) ->
+ RepMsg = read_rep_msg(Fd, FilePosition),
+ case RepMsg of
+ {Date, Msg} ->
+ print_filter_report({Date, Msg}, Filters, Device, Abort, Log);
+ _ ->
+ 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 ->
+ Subject = lists:flatten(io_lib:format("~p",[Value])),
+ case run_re(Subject, 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 ->
+ Subject = lists:flatten(io_lib:format("~p",[Value])),
+ case run_re(Subject, RegExp) of
+ match -> false;
+ _ -> filter_report(T, Msg)
+ end
+ end.
+
+get_compare_dates(Date, CompareDate) ->
+ case application:get_env(sasl, utc_log) of
+ {ok, true} ->
+ {local_time_to_universal_time(Date),
+ local_time_to_universal_time(CompareDate)};
+ _ ->
+ {Date, CompareDate}
+ end.
+get_compare_dates(Date, From, To) ->
+ case application:get_env(sasl, utc_log) of
+ {ok, true} ->
+ {local_time_to_universal_time(Date),
+ local_time_to_universal_time(From),
+ local_time_to_universal_time(To)};
+ _ ->
+ {Date, From, To}
+ end.
+
+compare_dates(Date, {CompareDate, from}) ->
+ {Date2, DateFrom} = get_compare_dates(Date, CompareDate),
+ calendar:datetime_to_gregorian_seconds(Date2) >=
+ calendar:datetime_to_gregorian_seconds(DateFrom);
+compare_dates(Date, {CompareDate, to}) ->
+ {Date2, DateTo} = get_compare_dates(Date, CompareDate),
+ calendar:datetime_to_gregorian_seconds(Date2) =<
+ calendar:datetime_to_gregorian_seconds(DateTo);
+compare_dates(Date, {From, To}) ->
+ {Date2, DateFrom, DateTo} = get_compare_dates(Date, From, To),
+ calendar:datetime_to_gregorian_seconds(Date2) >=
+ calendar:datetime_to_gregorian_seconds(DateFrom)
+ andalso
+ calendar:datetime_to_gregorian_seconds(Date2) =<
+ calendar:datetime_to_gregorian_seconds(DateTo).
+
+print_filter_report({Date, Msg}, Filters, Device, Abort, Log) ->
+ {_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.
read_rep(Fd, FilePosition, Device, Abort, Log) ->