implemented some comments
diff --git a/src/recon_lib.erl b/src/recon_lib.erl
index 2dd9a25..7726b64 100644
--- a/src/recon_lib.erl
+++ b/src/recon_lib.erl
@@ -13,7 +13,7 @@
term_to_port/1,
time_map/5, time_fold/6,
scheduler_usage_diff/2,
- sublist_top_n_attrs/2, format/1]).
+ sublist_top_n_attrs/2, format_trace_output/1]).
%% private exports
-export([binary_memory/1]).
@@ -245,16 +245,19 @@
binary_memory(Bins) ->
lists:foldl(fun({_,Mem,_}, Tot) -> Mem+Tot end, 0, Bins).
-format(Args) when is_tuple(Args) ->
+%% @doc formats call arguments and return values - most types are just printed out, except for
+%% tuples recognised as records, which mimic the source code syntax
+%% @end
+format_trace_output(Args) when is_tuple(Args) ->
recon_rec:format_tuple(Args);
-format(Args) when is_list(Args) ->
- case is_printable(Args) of
+format_trace_output(Args) when is_list(Args) ->
+ case io_lib:printable_list(Args) of
true -> io_lib:format("~p", [Args]);
false ->
- L = lists:map(fun format/1, Args),
+ L = lists:map(fun format_trace_output/1, Args),
"[" ++ string:join(L, ", ") ++ "]"
end;
-format(Args) ->
+format_trace_output(Args) ->
io_lib:format("~p", [Args]).
%%%%%%%%%%%%%%%
@@ -294,5 +297,4 @@
merge_pairs([H]) -> H;
merge_pairs([A, B|T]) -> merge(merge(A, B), merge_pairs(T)).
-is_printable(List) ->
- lists:all(fun(I) -> I > 31 andalso I < 128 end, List).
+
diff --git a/src/recon_rec.erl b/src/recon_rec.erl
index 1cf51b3..3c14883 100644
--- a/src/recon_rec.erl
+++ b/src/recon_rec.erl
@@ -4,14 +4,17 @@
%%% This module handles formatting records for known record types.
%%% Record definitions are imported from modules by user. Definitions are
%%% distinguished by record name and its arity, if you have multiple records
-%%% of the same name and size, you must be careful.
+%%% of the same name and size, you have to choose one of them and some of your
+%% records may be wrongly labelled. You can manipulate your definition list by
+%% using import/1 and clear/1, and check which definitions are in use by executing
+%% list/0.
%%% @end
%%%-------------------------------------------------------------------
-module(recon_rec).
-author("bartlomiej.gorny@erlang-solutions.com").
%% API
--export([import/1, format_tuple/1, clear/1, clear/0, list/0, limit/3]).
+-export([import/1, format_tuple/1, clear/1, clear/0, list/0, get_list/0, limit/3]).
-export([lookup_record/2]). %% for testing
@@ -22,12 +25,9 @@
%% an argument).
%% @end
import(Modules) when is_list(Modules) ->
- lists:map(fun import/1, Modules);
+ lists:foldl(fun import/2, [], Modules);
import(Module) ->
- ensure_table_exists(),
- Res = lists:map(fun(Rec) -> store_record(Rec, Module) end,
- get_record_defs(Module)),
- lists:all(fun(I) -> I == ok end, Res).
+ import(Module, []).
%% @private if a tuple is a known record, formats is as "#recname{field=value}", otherwise returns
%% just a printout of a tuple.
@@ -40,9 +40,11 @@
clear(Module) ->
lists:map(fun(R) -> rem_for_module(R, Module) end, ets:tab2list(ets_table_name())).
-%% @doc remove all imported definitions
+%% @doc remove all imported definitions, destroy the table, clean up
clear() ->
- catch ets:delete_all_objects(ets_table_name()).
+ catch ets:delete_all_objects(ets_table_name()),
+ catch whereis(recon_ets) ! stop,
+ ok.
%% @doc prints out all "known" (imported) record definitions and their limit settings.
%% Print out tells module a record originates from, its name and a list of field names,
@@ -50,15 +52,17 @@
%% limits its output to, if set.
%% @end
list() ->
- ensure_table_exists(),
- FmtLimit = fun([]) -> all; (List) -> List end,
F = fun({Module, Name, Fields, Limits}) ->
- Fnames = lists:map(fun atom_to_list/1, field_names(Fields)),
+ Fnames = lists:map(fun atom_to_list/1, Fields),
Flds = string:join(Fnames, ", "),
- io:format("~p: #~p{~s} (~p) ~p~n", [Module, Name, Flds, length(Fields), FmtLimit(Limits)])
+ io:format("~p: #~p(~p){~s} ~p~n", [Module, Name, length(Fields), Flds, Limits])
end,
- Lst = [{Module, Name, Fields, Limits} || {{Name, _}, Fields, Module, Limits} <- ets:tab2list(ets_table_name())],
- lists:foreach(F, lists:sort(Lst)).
+ lists:foreach(F, get_list()).
+
+get_list() ->
+ ensure_table_exists(),
+ Lst = lists:map(fun make_list_entry/1, ets:tab2list(ets_table_name())),
+ lists:sort(Lst).
%% @doc Limit output to selected fields of a record (set to 'all' to reset).
limit(Name, Arity, all) ->
@@ -68,7 +72,6 @@
limit(Name, Arity, FieldList) ->
case lookup_record(Name, Arity) of
[] ->
- io:format("~nRecord ~p/~p not imported~n~n", [Name, Arity]),
{error, record_unknown};
[{Key, Fields, Mod, _}] ->
ets:insert(ets_table_name(), {Key, Fields, Mod, FieldList}),
@@ -79,23 +82,33 @@
%% PRIVATE
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-store_record(Rec, Module) ->
+make_list_entry({{Name, _}, Fields, Module, Limits}) ->
+ FmtLimit = case Limits of
+ [] -> all;
+ Other -> Other
+ end,
+ {Module, Name, field_names(Fields), FmtLimit}.
+
+import(Module, ResultList) ->
+ ensure_table_exists(),
+ lists:foldl(fun(Rec, Res) -> store_record(Rec, Module, Res) end,
+ ResultList,
+ get_record_defs(Module)).
+
+store_record(Rec, Module, ResultList) ->
{Name, Fields} = Rec,
Arity = length(Fields),
- case lookup_record(Name, Arity) of
+ Result = case lookup_record(Name, Arity) of
[] ->
- io:format("importing ~p:~p/~p~n", [Module, Name, Arity]),
ets:insert(ets_table_name(), rec_info(Rec, Module)),
- ok;
+ {imported, Module, Name, Arity};
[{_, _, Module, _}] ->
- io:format("importing ~p:~p/~p~n", [Module, Name, Arity]),
ets:insert(ets_table_name(), rec_info(Rec, Module)),
- ok;
+ {overwritten, Module, Name, Arity};
[{_, _, Mod, _}] ->
- io:format("~nWARNING: record ~p/~p already present (imported from ~p), ignoring~n~n",
- [Name, Arity, Mod]),
- failed
- end.
+ {ignored, Module, Name, Arity, Mod}
+ end,
+ [Result | ResultList].
get_record_defs(Module) ->
Path = code:which(Module),
@@ -156,7 +169,7 @@
[RecDef] -> format_record(Rec, RecDef);
_ ->
List = tuple_to_list(Rec),
- "{" ++ string:join([recon_lib:format(El) || El <- List], ", ") ++ "}"
+ "{" ++ string:join([recon_lib:format_trace_output(El) || El <- List], ", ") ++ "}"
end;
format_tuple(_, Tuple) ->
format_default(Tuple).
@@ -164,9 +177,9 @@
format_default(Val) ->
io_lib:format("~p", [Val]).
-format_record(Rec, {{Name, _}, Fields, _, Limits}) ->
- ExpectedLength = length(Fields) + 1,
- case size(Rec) of
+format_record(Rec, {{Name, Arity}, Fields, _, Limits}) ->
+ ExpectedLength = Arity + 1,
+ case tuple_size(Rec) of
ExpectedLength ->
[_ | Values] = tuple_to_list(Rec),
FieldNames = field_names(Fields),
@@ -179,7 +192,7 @@
end.
format_kv(Key, Val) ->
- recon_lib:format(Key) ++ "=" ++ recon_lib:format(Val).
+ recon_lib:format_trace_output(Key) ++ "=" ++ recon_lib:format_trace_output(Val).
apply_limits(List, []) -> List;
apply_limits(List, Limits) ->
diff --git a/src/recon_trace.erl b/src/recon_trace.erl
index b74568c..0d91af7 100644
--- a/src/recon_trace.erl
+++ b/src/recon_trace.erl
@@ -523,7 +523,7 @@
{" '--> ~p:~p/~p", [M,F,Arity]};
%% {trace, Pid, return_from, {M, F, Arity}, ReturnValue}
{return_from, [{M,F,Arity}, Return]} ->
- {"~p:~p/~p --> ~s", [M,F,Arity, recon_lib:format(Return)]};
+ {"~p:~p/~p --> ~s", [M,F,Arity, recon_lib:format_trace_output(Return)]};
%% {trace, Pid, exception_from, {M, F, Arity}, {Class, Value}}
{exception_from, [{M,F,Arity}, {Class,Val}]} ->
{"~p:~p/~p ~p ~p", [M,F,Arity, Class, Val]};
@@ -600,7 +600,7 @@
format_args(Arity) when is_integer(Arity) ->
"/"++integer_to_list(Arity);
format_args(Args) when is_list(Args) ->
- "("++string:join([recon_lib:format(Arg) || Arg <- Args], ", ")++")".
+ "("++string:join([recon_lib:format_trace_output(Arg) || Arg <- Args], ", ")++")".
%%%%%%%%%%%%%%%
%%% HELPERS %%%
diff --git a/test/recon_rec_SUITE.erl b/test/recon_rec_SUITE.erl
index bf7bda2..f800090 100644
--- a/test/recon_rec_SUITE.erl
+++ b/test/recon_rec_SUITE.erl
@@ -5,14 +5,14 @@
%%%%%%%%%% SETUP
-all() -> [record_defs].
+all() -> [record_defs, lists_and_limits].
init_per_suite(Config) ->
- true = recon_rec:import(records1),
+ Res = recon_rec:import(records1),
+ [{imported, records1, another, 3}, {imported, records1, state, 3}] = lists:sort(Res),
Config.
end_per_suite(C) ->
- whereis(recon_ets) ! stop,
C.
init_per_testcase(_, Config) -> Config.
@@ -26,7 +26,8 @@
record_defs(_Config) ->
has_record(state, 3), % make sure table was not wiped out
has_record(another, 3),
- false = recon_rec:import(records2), %% one record is a duplicate
+ ImportRes = recon_rec:import(records2), %% one record is a duplicate
+ [{imported,records2,another,4}, {ignored,records2,state,3,records1}] = lists:sort(ImportRes),
has_record(state, 3),
has_record(another, 3),
has_record(another, 4),
@@ -36,7 +37,8 @@
no_record(state, 3),
no_record(another, 3),
has_record(another, 4),
- true = recon_rec:import(records2),
+ ImportRes2 = recon_rec:import(records2),
+ [{imported,records2,state,3}, {overwritten,records2,another,4}] = lists:sort(ImportRes2),
[Res1] = recon_rec:lookup_record(state, 3),
check_first_field(one, Res1),
recon_rec:clear(),
@@ -45,6 +47,23 @@
no_record(another, 4),
ok.
+lists_and_limits(_Config) ->
+ recon_rec:import(records1),
+ recon_rec:import(records2),
+ List = recon_rec:get_list(),
+ [{records1,another,[ddd,eee,fff],all},
+ {records1,state,[aaa,bbb,ccc],all},
+ {records2,another,[one,two,three,four],all}] = List,
+ recon_rec:limit(another, 3, ddd),
+ {records1,another,[ddd,eee,fff], [ddd]} = hd(recon_rec:get_list()),
+ recon_rec:limit(another, 3, [ddd, eee]),
+ {records1,another,[ddd,eee,fff], [ddd, eee]} = hd(recon_rec:get_list()),
+ recon_rec:limit(another, 3, all),
+ {records1,another,[ddd,eee,fff], all} = hd(recon_rec:get_list()),
+ recon_rec:clear(record2),
+ {error, record_unknown} = recon_rec:limit(another, 4, all),
+ ok.
+
%%%%%%%%%% HELPERS
has_record(Name, Count) ->