diff options
author | Erlang/OTP <[email protected]> | 2010-02-16 07:37:52 +0000 |
---|---|---|
committer | Erlang/OTP <[email protected]> | 2010-02-16 07:37:52 +0000 |
commit | ad8ff2174e6ed4becb0a267f82c9f0163142f147 (patch) | |
tree | 1fd439d39d21fcfb5ea45d7f90f6dc4bf08aa291 /lib/sasl | |
parent | 7aa2cb2e64cd404f8a9f388d85ab287ced95f139 (diff) | |
parent | 242c70ed5f0e2b84e9608bace183052e745614ed (diff) | |
download | otp-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/sasl')
-rw-r--r-- | lib/sasl/doc/src/rb.xml | 86 | ||||
-rw-r--r-- | lib/sasl/src/rb.erl | 234 |
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) -> |