From 77b40155ddfa6657a62d6b5cf4ab49084ff6ed3e Mon Sep 17 00:00:00 2001
From: Anders Svensson
Date: Wed, 19 Mar 2014 12:53:54 +0100
Subject: Remove release note unrelated to functionality
---
lib/diameter/doc/src/notes.xml | 8 +-------
1 file changed, 1 insertion(+), 7 deletions(-)
(limited to 'lib')
diff --git a/lib/diameter/doc/src/notes.xml b/lib/diameter/doc/src/notes.xml
index 18c712ec3d..caedb890d0 100644
--- a/lib/diameter/doc/src/notes.xml
+++ b/lib/diameter/doc/src/notes.xml
@@ -11,7 +11,7 @@
2011
-2013
+2014
Ericsson AB. All Rights Reserved.
@@ -73,12 +73,6 @@ first.
Date: Thu, 27 Jun 2013 12:41:03 +0200
Subject: Fix doc typo: required -> requires
---
lib/diameter/doc/src/diameter_make.xml | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
(limited to 'lib')
diff --git a/lib/diameter/doc/src/diameter_make.xml b/lib/diameter/doc/src/diameter_make.xml
index 1c1eff6c6a..95f91ff3b2 100644
--- a/lib/diameter/doc/src/diameter_make.xml
+++ b/lib/diameter/doc/src/diameter_make.xml
@@ -52,7 +52,7 @@ under the License.
The function &codec; is used to compile a diameter
&dictionary; into Erlang source.
-The resulting source implements the interface diameter required
+The resulting source implements the interface diameter requires
to encode and decode the dictionary's messages and AVPs.
--
cgit v1.2.3
From 2411e900e70c2d66433227e0ee7605e71fbf8d75 Mon Sep 17 00:00:00 2001
From: Anders Svensson
Date: Tue, 25 Mar 2014 18:34:52 +0100
Subject: Remove case expecting a pre-R16B return value from os:type/1
The documented return value changed in commit c37a9761.
---
lib/diameter/src/base/diameter_dbg.erl | 4 ++++
lib/diameter/src/base/diameter_info.erl | 14 +++++++-------
2 files changed, 11 insertions(+), 7 deletions(-)
(limited to 'lib')
diff --git a/lib/diameter/src/base/diameter_dbg.erl b/lib/diameter/src/base/diameter_dbg.erl
index 5b0ac3a3b6..6b92234b0b 100644
--- a/lib/diameter/src/base/diameter_dbg.erl
+++ b/lib/diameter/src/base/diameter_dbg.erl
@@ -17,6 +17,10 @@
%% %CopyrightEnd%
%%
+%%
+%% Information and debug functions.
+%%
+
-module(diameter_dbg).
-export([table/1,
diff --git a/lib/diameter/src/base/diameter_info.erl b/lib/diameter/src/base/diameter_info.erl
index 39d32d07cd..10972f3231 100644
--- a/lib/diameter/src/base/diameter_info.erl
+++ b/lib/diameter/src/base/diameter_info.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2010-2011. All Rights Reserved.
+%% Copyright Ericsson AB 2010-2014. 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
@@ -17,6 +17,11 @@
%% %CopyrightEnd%
%%
+%%
+%% Generic functions for formatting table listings and more. Used by
+%% diameter_dbg.
+%%
+
-module(diameter_info).
-export([usage/1,
@@ -573,12 +578,7 @@ sys_info() ->
{A,V}.
os_info() ->
- {os:version(), case os:type() of
- {_Fam, _Name} = T ->
- T;
- Fam ->
- {Fam, ""}
- end}.
+ {os:version(), os:type()}.
chomp(S) ->
string:strip(S, right, $\n).
--
cgit v1.2.3
From 888504300eb9b3f87de8243bbd8fa7e4dbf97f1d Mon Sep 17 00:00:00 2001
From: Anders Svensson
Date: Sat, 29 Mar 2014 18:22:02 +0100
Subject: Remove unused diameter_dbg:log/4
It was intended to replace diameter_lib:log/4 at some point but that was
a bad idea since diameter_dbg isn't included in the app file.
---
lib/diameter/src/base/diameter_dbg.erl | 8 ++------
1 file changed, 2 insertions(+), 6 deletions(-)
(limited to 'lib')
diff --git a/lib/diameter/src/base/diameter_dbg.erl b/lib/diameter/src/base/diameter_dbg.erl
index 6b92234b0b..5edbabedeb 100644
--- a/lib/diameter/src/base/diameter_dbg.erl
+++ b/lib/diameter/src/base/diameter_dbg.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2010-2011. All Rights Reserved.
+%% Copyright Ericsson AB 2010-2014. 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
@@ -33,8 +33,7 @@
compiled/0,
procs/0,
latest/0,
- nl/0,
- log/4]).
+ nl/0]).
-export([diameter_config/0,
diameter_peer/0,
@@ -72,9 +71,6 @@
-define(VALUES(Rec), tl(tuple_to_list(Rec))).
-log(_Slogan, _Mod, _Line, _Details) ->
- ok.
-
%%% ----------------------------------------------------------
%%% # help()
%%% ----------------------------------------------------------
--
cgit v1.2.3
From c23b242d0d634d10b03412c19768d381906578ab Mon Sep 17 00:00:00 2001
From: Anders Svensson
Date: Sat, 29 Mar 2014 13:21:11 +0100
Subject: Include compiler and info modules in app file
Albeit as comments. This is just to make it more obvious that these
aren't include in the modules list, since they typically aren't
needed/wanted on a target system. Also add comments for the
corresponding dependencies on syntax_tools and runtime_tools, as well as
the optional runtime dependency on ssl.
---
lib/diameter/src/Makefile | 17 ++++++++++++-----
lib/diameter/src/diameter.app.src | 15 ++++++++++++---
lib/diameter/src/modules.mk | 12 +++++++-----
3 files changed, 31 insertions(+), 13 deletions(-)
(limited to 'lib')
diff --git a/lib/diameter/src/Makefile b/lib/diameter/src/Makefile
index 578bbaee2e..fa5f4c41ce 100644
--- a/lib/diameter/src/Makefile
+++ b/lib/diameter/src/Makefile
@@ -1,7 +1,7 @@
#
# %CopyrightBegin%
#
-# Copyright Ericsson AB 2010-2013. All Rights Reserved.
+# Copyright Ericsson AB 2010-2014. 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
@@ -55,13 +55,13 @@ DICT_ERLS = $(DICT_MODULES:%=%.erl)
DICT_HRLS = $(DICT_MODULES:%=%.hrl)
# Modules to build before compiling dictionaries.
-COMPILER_MODULES = $(notdir $(filter compiler/%, $(CT_MODULES))) \
- $(DICT_YRL)
+COMPILER_MODULES = $(notdir $(CT_MODULES)) $(DICT_YRL)
# All handwritten modules from which a depend.mk is generated.
MODULES = \
$(RT_MODULES) \
- $(CT_MODULES)
+ $(CT_MODULES) \
+ $(INFO_MODULES)
# Modules whose names are inserted into the app file.
APP_MODULES = \
@@ -72,6 +72,7 @@ APP_MODULES = \
TARGET_MODULES = \
$(APP_MODULES) \
$(CT_MODULES) \
+ $(INFO_MODULES) \
$(DICT_YRL:%=gen/%)
# What to build for the 'opt' target.
@@ -150,9 +151,13 @@ gen/$(DICT_YRL).erl: compiler/$(DICT_YRL).yrl
$(APP_TARGET): $(APP_SRC) ../vsn.mk modules.mk
$(gen_verbose) \
M=`echo $(notdir $(APP_MODULES)) | tr ' ' ,`; \
+ C=`echo $(COMPILER_MODULES) | tr ' ' ,`; \
+ I=`echo $(notdir $(INFO_MODULES)) | tr ' ' ,`; \
R=`echo $(REGISTERED) | tr ' ' ,`; \
sed -e 's;%VSN%;$(VSN);' \
-e "s;%MODULES%;$$M;" \
+ -e "s;%COMPILER%;$$C;" \
+ -e "s;%INFO%;$$I;" \
-e "s;%REGISTERED%;$$R;" \
$< > $@
@@ -177,6 +182,8 @@ info:
@echo
@$(call list,CT_MODULES)
@echo
+ @$(call list,INFO_MODULES)
+ @echo
@$(call list,TARGET_MODULES)
@echo
@$(call list,TARGET_DIRS)
@@ -216,7 +223,7 @@ dialyze: opt $(PLT)
-Wno_improper_lists \
$(EBIN)/diameter_gen_base_rfc3588.$(EMULATOR) \
$(patsubst %, $(EBIN)/%.$(EMULATOR), \
- $(notdir $(RT_MODULES) $(CT_MODULES)))
+ $(notdir $(RT_MODULES) $(CT_MODULES) $(INFO_MODULES)))
# Omit all but the common dictionary module since these
# (diameter_gen_relay in particular) generate warning depending on how
# much of the included diameter_gen.hrl they use.
diff --git a/lib/diameter/src/diameter.app.src b/lib/diameter/src/diameter.app.src
index ceefb9b398..0eb9e26a44 100644
--- a/lib/diameter/src/diameter.app.src
+++ b/lib/diameter/src/diameter.app.src
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2010-2013. All Rights Reserved.
+%% Copyright Ericsson AB 2010-2014. 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
@@ -20,9 +20,18 @@
{application, diameter,
[{description, "Diameter protocol"},
{vsn, "%VSN%"},
- {modules, [%MODULES%]},
+ {modules, [
+ %MODULES%
+ %,%COMPILER%
+ %,%INFO%
+ ]},
{registered, [%REGISTERED%]},
- {applications, [stdlib, kernel]},
+ {applications, [
+ stdlib, kernel
+ %, syntax_tools
+ %, runtime_tools
+ %, ssl
+ ]},
{env, []},
{mod, {diameter_app, []}}
]}.
diff --git a/lib/diameter/src/modules.mk b/lib/diameter/src/modules.mk
index f8d3cf1d6f..9f9b6d3308 100644
--- a/lib/diameter/src/modules.mk
+++ b/lib/diameter/src/modules.mk
@@ -1,8 +1,7 @@
-#-*-makefile-*- ; force emacs to enter makefile-mode
# %CopyrightBegin%
#
-# Copyright Ericsson AB 2010-2013. All Rights Reserved.
+# Copyright Ericsson AB 2010-2014. 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
@@ -64,16 +63,19 @@ RT_MODULES = \
transport/diameter_transport \
transport/diameter_transport_sup
-# Handwritten (compile time) modules not included in the app file.
+# Handwritten compiler modules not included in the app file.
CT_MODULES = \
- base/diameter_dbg \
- base/diameter_info \
compiler/diameter_codegen \
compiler/diameter_exprecs \
compiler/diameter_dict_scanner \
compiler/diameter_dict_util \
compiler/diameter_make
+# Info/debug modules, also not included in the app file.
+INFO_MODULES = \
+ base/diameter_dbg \
+ base/diameter_info
+
# Released hrl files in ../include intended for public consumption.
EXTERNAL_HRLS = \
diameter.hrl \
--
cgit v1.2.3
From 5ca206af45b3195233991dfe820e9fb636800a33 Mon Sep 17 00:00:00 2001
From: Anders Svensson
Date: Sat, 29 Mar 2014 18:34:38 +0100
Subject: Move info modules into own subdirectory
Possibly overkill for two modules but it mirrors their different
treatment by the makefile.
---
lib/diameter/src/Makefile | 2 +-
lib/diameter/src/base/diameter_dbg.erl | 516 -------------------
lib/diameter/src/base/diameter_info.erl | 869 --------------------------------
lib/diameter/src/info/diameter_dbg.erl | 515 +++++++++++++++++++
lib/diameter/src/info/diameter_info.erl | 869 ++++++++++++++++++++++++++++++++
lib/diameter/src/modules.mk | 4 +-
6 files changed, 1387 insertions(+), 1388 deletions(-)
delete mode 100644 lib/diameter/src/base/diameter_dbg.erl
delete mode 100644 lib/diameter/src/base/diameter_info.erl
create mode 100644 lib/diameter/src/info/diameter_dbg.erl
create mode 100644 lib/diameter/src/info/diameter_info.erl
(limited to 'lib')
diff --git a/lib/diameter/src/Makefile b/lib/diameter/src/Makefile
index fa5f4c41ce..127406ae23 100644
--- a/lib/diameter/src/Makefile
+++ b/lib/diameter/src/Makefile
@@ -41,7 +41,7 @@ INCDIR = ../include
ABS_EBIN := $(shell cd $(EBIN) && pwd)
# Where make should look for dependencies.
-VPATH = .:base:compiler:transport:gen
+VPATH = .:base:compiler:transport:gen:info
# ----------------------------------------------------
# Target specs
diff --git a/lib/diameter/src/base/diameter_dbg.erl b/lib/diameter/src/base/diameter_dbg.erl
deleted file mode 100644
index 5edbabedeb..0000000000
--- a/lib/diameter/src/base/diameter_dbg.erl
+++ /dev/null
@@ -1,516 +0,0 @@
-%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 2010-2014. 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%
-%%
-
-%%
-%% Information and debug functions.
-%%
-
--module(diameter_dbg).
-
--export([table/1,
- tables/0,
- fields/1,
- help/0,
- modules/0,
- versions/0,
- version_info/0,
- compiled/0,
- procs/0,
- latest/0,
- nl/0]).
-
--export([diameter_config/0,
- diameter_peer/0,
- diameter_reg/0,
- diameter_request/0,
- diameter_sequence/0,
- diameter_service/0,
- diameter_stats/0]).
-
--export([pp/1,
- subscriptions/0,
- children/0]).
-
-%% Trace help.
--export([tracer/0, tracer/1,
- p/0, p/1,
- stop/0,
- tpl/1,
- tp/1]).
-
--include_lib("diameter/include/diameter.hrl").
--include("diameter_internal.hrl").
-
-
--define(INFO, diameter_info).
--define(SEP(), ?INFO:sep()).
-
--define(LOCAL, [diameter_config,
- diameter_peer,
- diameter_reg,
- diameter_request,
- diameter_sequence,
- diameter_service,
- diameter_stats]).
-
--define(VALUES(Rec), tl(tuple_to_list(Rec))).
-
-%%% ----------------------------------------------------------
-%%% # help()
-%%% ----------------------------------------------------------
-
-help() ->
- not_yet_implemented.
-
-%%% ----------------------------------------------------------
-%%% # table(TableName)
-%%%
-%%% Input: TableName = diameter table containing record entries.
-%%%
-%%% Output: Count | undefined
-%%% ----------------------------------------------------------
-
-table(T)
- when (T == diameter_peer) orelse (T == diameter_reg) ->
- ?INFO:format(collect(T), fields(T), fun ?INFO:split/2);
-
-table(Table)
- when is_atom(Table) ->
- case fields(Table) of
- undefined = No ->
- No;
- Fields ->
- ?INFO:format(Table, Fields, fun split/2)
- end.
-
-split([started, name | Fs], [S, N | Vs]) ->
- {name, [started | Fs], N, [S | Vs]};
-split([[F|FT]|Fs], [Rec|Vs]) ->
- [_, V | VT] = tuple_to_list(Rec),
- {F, FT ++ Fs, V, VT ++ Vs};
-split([F|Fs], [V|Vs]) ->
- {F, Fs, V, Vs}.
-
-%%% ----------------------------------------------------------
-%%% # TableName()
-%%% ----------------------------------------------------------
-
--define(TABLE(Name), Name() -> table(Name)).
-
-?TABLE(diameter_config).
-?TABLE(diameter_peer).
-?TABLE(diameter_reg).
-?TABLE(diameter_request).
-?TABLE(diameter_sequence).
-?TABLE(diameter_service).
-?TABLE(diameter_stats).
-
-%%% ----------------------------------------------------------
-%%% # tables()
-%%%
-%%% Output: Number of records output.
-%%%
-%%% Description: Pretty-print records in diameter tables from all nodes.
-%%% ----------------------------------------------------------
-
-tables() ->
- ?INFO:format(field(?LOCAL), fun split/3, fun collect/1).
-
-field(Tables) ->
- lists:map(fun(T) -> {T, fields(T)} end, lists:sort(Tables)).
-
-split(_, Fs, Vs) ->
- split(Fs, Vs).
-
-%%% ----------------------------------------------------------
-%%% # modules()
-%%% ----------------------------------------------------------
-
-modules() ->
- Path = filename:join([appdir(), atom_to_list(?APPLICATION) ++ ".app"]),
- {ok, [{application, ?APPLICATION, Attrs}]} = file:consult(Path),
- {modules, Mods} = lists:keyfind(modules, 1, Attrs),
- Mods.
-
-appdir() ->
- [_|_] = code:lib_dir(?APPLICATION, ebin).
-
-%%% ----------------------------------------------------------
-%%% # versions()
-%%% ----------------------------------------------------------
-
-versions() ->
- ?INFO:versions(modules()).
-
-%%% ----------------------------------------------------------
-%%% # versions()
-%%% ----------------------------------------------------------
-
-version_info() ->
- ?INFO:version_info(modules()).
-
-%%% ----------------------------------------------------------
-%%% # compiled()
-%%% ----------------------------------------------------------
-
-compiled() ->
- ?INFO:compiled(modules()).
-
-%%% ----------------------------------------------------------
-%%% procs()
-%%% ----------------------------------------------------------
-
-procs() ->
- ?INFO:procs(?APPLICATION).
-
-%%% ----------------------------------------------------------
-%%% # latest()
-%%% ----------------------------------------------------------
-
-latest() ->
- ?INFO:latest(modules()).
-
-%%% ----------------------------------------------------------
-%%% # nl()
-%%% ----------------------------------------------------------
-
-nl() ->
- lists:foreach(fun(M) -> abcast = c:nl(M) end, modules()).
-
-%%% ----------------------------------------------------------
-%%% # pp(Bin)
-%%%
-%%% Description: Pretty-print a message binary.
-%%% ----------------------------------------------------------
-
-%% Network byte order = big endian.
-
-pp(<>) ->
- ?SEP(),
- ppp(["Version",
- "Message length",
- "[Actual length]",
- "R(equest)",
- "P(roxiable)",
- "E(rror)",
- "T(Potential retrans)",
- "Reserved bits",
- "Command code",
- "Application id",
- "Hop by hop id",
- "End to end id"],
- [Version, MsgLength, size(AVPs) + 20,
- Rbit, Pbit, Ebit, Tbit, Reserved,
- CmdCode,
- ApplId,
- HbHid,
- E2Eid]),
- N = avp_loop({AVPs, MsgLength - 20}, 0),
- ?SEP(),
- N;
-
-pp(<<_Version:8, MsgLength:24, _/binary>> = Bin) ->
- {bad_message_length, MsgLength, size(Bin)};
-
-pp(Bin)
- when is_binary(Bin) ->
- {truncated_binary, size(Bin)};
-
-pp(_) ->
- not_binary.
-
-%% avp_loop/2
-
-avp_loop({Bin, Size}, N) ->
- avp_loop(avp(Bin, Size), N+1);
-avp_loop(ok, N) ->
- N;
-avp_loop([_E, _Rest] = L, N) ->
- io:format("! ~s: ~p~n", L),
- N;
-avp_loop([E, Rest, Fmt | Values], N)
- when is_binary(Rest) ->
- io:format("! ~s (" ++ Fmt ++ "): ~p~n", [E|Values] ++ [Rest]),
- N.
-
-%% avp/2
-
-avp(<<>>, 0) ->
- ok;
-avp(<>,
- Size) ->
- avp(Code, Flags, Length, Rest, Size);
-avp(Bin, _) ->
- ["truncated AVP header", Bin].
-
-%% avp/5
-
-avp(Code, Flags, Length, Rest, Size) ->
- <>
- = Flags,
- b(),
- ppp(["AVP Code",
- "V(endor)",
- "M(andatory)",
- "P(Security)",
- "R(eserved)",
- "Length"],
- [Code, V, M, P, Res, Length]),
- avp(V, Rest, Length - 8, Size - 8).
-
-%% avp/4
-
-avp(1, <>, Length, Size) ->
- ppp({"Vendor-ID", V}),
- data(Data, Length - 4, Size - 4);
-avp(1, Bin, _, _) ->
- ["truncated Vendor-ID", Bin];
-avp(0, Data, Length, Size) ->
- data(Data, Length, Size).
-
-data(Bin, Length, Size)
- when size(Bin) >= Length ->
- <> = Bin,
- ppp({"Data", AVP}),
- unpad(Rest, Size - Length, Length rem 4);
-
-data(Bin, _, _) ->
- ["truncated AVP data", Bin].
-
-%% Remove padding bytes up to the next word boundary.
-unpad(Bin, Size, 0) ->
- {Bin, Size};
-unpad(Bin, Size, N) ->
- un(Bin, Size, 4 - N).
-
-un(Bin, Size, N)
- when size(Bin) >= N ->
- ppp({"Padding bytes", N}),
- <> = Bin,
- Bits = N*8,
- case Pad of
- <<0:Bits>> ->
- {Rest, Size - N};
- _ ->
- ["non-zero padding", Bin, "~p", N]
- end;
-
-un(Bin, _, _) ->
- ["truncated padding", Bin].
-
-b() ->
- io:format("#~n").
-
-ppp(Fields, Values) ->
- lists:foreach(fun ppp/1, lists:zip(Fields, Values)).
-
-ppp({Field, Value}) ->
- io:format(": ~-22s : ~p~n", [Field, Value]).
-
-%%% ----------------------------------------------------------
-%%% # subscriptions()
-%%%
-%%% Output: list of {SvcName, Pid}
-%%% ----------------------------------------------------------
-
-subscriptions() ->
- diameter_service:subscriptions().
-
-%%% ----------------------------------------------------------
-%%% # children()
-%%% ----------------------------------------------------------
-
-children() ->
- diameter_sup:tree().
-
-%%% ----------------------------------------------------------
-
-%% tracer/[12]
-
-tracer(Port)
- when is_integer(Port) ->
- dbg:tracer(port, dbg:trace_port(ip, Port));
-
-tracer(Path)
- when is_list(Path) ->
- dbg:tracer(port, dbg:trace_port(file, Path)).
-
-tracer() ->
- dbg:tracer(process, {fun p/2, ok}).
-
-p(T,_) ->
- io:format("+ ~p~n", [T]).
-
-%% p/[01]
-
-p() ->
- p([c,timestamp]).
-
-p(T) ->
- dbg:p(all,T).
-
-%% stop/0
-
-stop() ->
- dbg:ctp(),
- dbg:stop_clear().
-
-%% tpl/1
-%% tp/1
-
-tpl(T) ->
- dbg(tpl, T).
-
-tp(T) ->
- dbg(tp, T).
-
-%% dbg/2
-
-dbg(F, L)
- when is_list(L) ->
- [dbg(F, X) || X <- L];
-
-dbg(F, M)
- when is_atom(M) ->
- apply(dbg, F, [M, x]);
-
-dbg(F, T)
- when is_tuple(T) ->
- apply(dbg, F, tuple_to_list(T)).
-
-%% ===========================================================================
-%% ===========================================================================
-
-%% collect/1
-
-collect(diameter_peer) ->
- lists:flatmap(fun peers/1, diameter:services());
-
-collect(diameter_reg) ->
- diameter_reg:terms();
-
-collect(Name) ->
- c(ets:info(Name), Name).
-
-c(undefined, _) ->
- [];
-c(_, Name) ->
- ets:tab2list(Name).
-
-%% peers/1
-
-peers(Name) ->
- peers(Name, diameter:service_info(Name, transport)).
-
-peers(_, undefined) ->
- [];
-peers(Name, Ts) ->
- lists:flatmap(fun(T) -> mk_peers(Name, T) end, Ts).
-
-mk_peers(Name, [_, {type, connect} | _] = Ts) ->
- [[Name | mk_peer(Ts)]];
-mk_peers(Name, [R, {type, listen}, O, {accept = A, As}]) ->
- [[Name | mk_peer([R, {type, A}, O | Ts])] || Ts <- As].
-%% This is a bit lame: service_info works to build this list and out
-%% of something like what we want here and then we take it apart.
-
-mk_peer(Vs) ->
- [Type, Ref, State, Opts, WPid, TPid, SApps, Caps]
- = get_values(Vs, [type,ref,state,options,watchdog,peer,apps,caps]),
- [Ref, State, [{type, Type} | Opts], s(WPid), s(TPid), SApps, Caps].
-
-get_values(Vs, Ks) ->
- [proplists:get_value(K, Vs) || K <- Ks].
-
-s(undefined = T) ->
- T;
-s({Pid, _Started, _State}) ->
- state(Pid);
-s({Pid, _Started}) ->
- state(Pid).
-
-%% Collect states from watchdog/transport pids.
-state(Pid) ->
- MRef = erlang:monitor(process, Pid),
- Pid ! {state, self()},
- receive
- {'DOWN', MRef, process, _, _} ->
- Pid;
- {Pid, _} = T ->
- erlang:demonitor(MRef, [flush]),
- T
- end.
-
-%% fields/1
-
--define(FIELDS(Table), fields(Table) -> record_info(fields, Table)).
-
-fields(diameter_config) ->
- [];
-
-fields(T)
- when T == diameter_request;
- T == diameter_sequence ->
- fun kv/1;
-
-fields(diameter_stats) ->
- fun({Ctr, N}) when not is_pid(Ctr) ->
- {[counter, value], [Ctr, N]};
- (_) ->
- []
- end;
-
-fields(diameter_service) ->
- [started,
- name,
- record_info(fields, diameter_service),
- peerT,
- connT,
- share_peers,
- use_shared_peers,
- shared_peers,
- local_peers,
- monitor];
-
-?FIELDS(diameter_event);
-?FIELDS(diameter_uri);
-?FIELDS(diameter_avp);
-?FIELDS(diameter_header);
-?FIELDS(diameter_packet);
-?FIELDS(diameter_app);
-?FIELDS(diameter_caps);
-
-fields(diameter_peer) ->
- [service, ref, state, options, watchdog, peer, applications, capabilities];
-
-fields(diameter_reg) ->
- [property, pids];
-
-fields(_) ->
- undefined.
-
-kv({_,_}) ->
- [key, value];
-kv(_) ->
- [].
diff --git a/lib/diameter/src/base/diameter_info.erl b/lib/diameter/src/base/diameter_info.erl
deleted file mode 100644
index 10972f3231..0000000000
--- a/lib/diameter/src/base/diameter_info.erl
+++ /dev/null
@@ -1,869 +0,0 @@
-%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 2010-2014. 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%
-%%
-
-%%
-%% Generic functions for formatting table listings and more. Used by
-%% diameter_dbg.
-%%
-
--module(diameter_info).
-
--export([usage/1,
- format/1,
- format/2,
- format/3,
- format/4,
- table/2,
- tables/1,
- tables/2,
- split/2,
- split/3,
- tab2list/1,
- modules/1,
- versions/1,
- version_info/1,
- attrs/2,
- compiled/1,
- procs/1,
- latest/1,
- list/1]).
-
-%% Support for rolling your own.
--export([sep/0,
- sep/1,
- widest/1,
- p/1,
- p/3]).
-
--compile({no_auto_import,[max/2]}).
-
--export([collect/2]).
-
--define(LONG_TIMEOUT, 30000).
--define(VALUES(Rec), tl(tuple_to_list(Rec))).
-
-%%% ----------------------------------------------------------
-%%% # usage(String)
-%%% ----------------------------------------------------------
-
-usage(Usage) ->
- sep($+),
- io:format("+ ~p~n", [?MODULE]),
- io:format("~n~s~n~n", [compact(Usage)]),
- sep($+).
-
-%%%
-%%% The function format/3, for pretty-printing tables, comes in
-%%% several flavours.
-%%%
-
-%%% ----------------------------------------------------------
-%%% # format(TableName, Fields, SplitFun)
-%%%
-%%% Input: TableName = atom() name of table.
-%%%
-%%% Fields = List of field names for the records maintained
-%%% in the specified table. Can be empty, in which
-%%% case entries are listed unadorned of field names
-%%% and SplitFun is unused.
-%%% | Integer, equivalent to a list with this many '' atoms.
-%%% | Arity 1 fun mapping a table entry to a Fields list
-%%% or a tuple {Fields, Values} of lists of the same
-%%% length.
-%%%
-%%% If Fields is a list then its length must be the same
-%%% as or one less than the size of the tuples contained
-%%% in the table. (The values printed then being those
-%%% in the tuple or record in question.)
-%%%
-%%% SplitFun = Arity 3 fun applied as
-%%%
-%%% SplitFun(TableName, Fields, Values)
-%%%
-%%% in order to obtain a tuple
-%%%
-%%% {Field, RestFields, Value, RestValues}
-%%%
-%%% for which Field/Value will be formatted on
-%%% STDOUT. (This is to allow a value to be
-%%% transformed before being output by returning a
-%%% new value and/or replacing the remainder of
-%%% the list.) The returned lists must have the
-%%% same length and Field here is an atom, '' causing
-%%% a value to be listed unadorned of the field name.
-%%%
-%%% Field can also be list of field names, in
-%%% which case Value must be a record of the
-%%% corresponding type.
-%%%
-%%% | Arity 2 fun applied as SplitFun(Fields, Values).
-%%%
-%%% Output: Count | undefined
-%%%
-%%% Count = Number of entries output.
-%%%
-%%% Description: Pretty-print records in a named table.
-%%% ----------------------------------------------------------
-
-format(Table, Fields, SFun)
- when is_atom(Table), is_function(SFun, 2) ->
- ft(ets:info(Table), Table, SFun, Fields);
-
-format(Table, Fields, SFun)
- when is_atom(Table), is_function(SFun, 3) ->
- format(Table, Fields, fun(Fs,Vs) -> SFun(Table, Fs, Vs) end);
-
-%%% ----------------------------------------------------------
-%%% # format(Recs, Fields, SplitFun)
-%%%
-%%% Input: Recs = list of records/tuples
-%%% Fields = As for format(Table, Fields, SplitFun), a table
-%%% entry there being a member of Recs.
-%%% SplitFun = Arity 3 fun applied as above but with the TableName
-%%% replaced by the first element of the records in
-%%% question.
-%%% | Arity 2 fun as for format/3.
-%%%
-%%% Output: length(Recs)
-%%%
-%%% Description: Pretty print records/tuples.
-%%% ----------------------------------------------------------
-
-format(Recs, Fields, SFun)
- when is_list(Recs), is_function(SFun, 3) ->
- lists:foldl(fun(R,A) -> f(recsplit(SFun, R), 0, Fields, R, A) end,
- 0,
- Recs);
-
-format(Recs, Fields, SFun)
- when is_list(Recs), is_function(SFun, 2) ->
- lists:foldl(fun(R,A) -> f(SFun, 0, Fields, R, A) end,
- 0,
- Recs);
-
-%%% ----------------------------------------------------------
-%%% # format(Tables, SplitFun, CollectFun)
-%%%
-%%% Input: Tables = list of {TableName, Fields}.
-%%% SplitFun = As for format(Table, Fields, SplitFun).
-%%% CollectFun = arity 1 fun mapping a table name to a list
-%%% of elements. A non-list can be returned to indicate
-%%% that the table in question doesn't exist.
-%%%
-%%% Output: Number of entries output.
-%%%
-%%% Description: Pretty-print records in a named tables as collected
-%%% from known nodes. Each table listing is preceeded by
-%%% a banner.
-%%% ----------------------------------------------------------
-
-format(Tables, SFun, CFun)
- when is_list(Tables), is_function(CFun, 1) ->
- format_remote(Tables,
- SFun,
- rpc:multicall(nodes(known),
- ?MODULE,
- collect,
- [CFun, lists:map(fun({T,_}) -> T end, Tables)],
- ?LONG_TIMEOUT));
-
-%%% ----------------------------------------------------------
-%%% # format(LocalTables, RemoteTables, SplitFun, CollectFun)
-%%% # format(LocalTables, RemoteTables, SplitFun)
-%%%
-%%% Input: LocalTables = list of {TableName, Fields}.
-%%% | list of {TableName, Recs, Fields}
-%%% RemoteTable = list of {TableName, Fields}.
-%%% SplitFun, CollectFun = As for format(Table, CollectFun, SplitFun).
-%%%
-%%% Output: Number of entries output.
-%%%
-%%% Description: Pretty-print records in a named tables as collected
-%%% from local and remote nodes. Each table listing is
-%%% preceeded by a banner.
-%%% ----------------------------------------------------------
-
-format(Local, Remote, SFun) ->
- format(Local, Remote, SFun, fun tab2list/1).
-
-format(Local, Remote, SFun, CFun)
- when is_list(Local), is_list(Remote), is_function(CFun, 1) ->
- format_local(Local, SFun) + format(Remote, SFun, CFun).
-
-%%% ----------------------------------------------------------
-%%% # format(Tables, SplitFun)
-%%% ----------------------------------------------------------
-
-format(Tables, SFun)
- when is_list(Tables), (is_function(SFun, 2) or is_function(SFun, 3)) ->
- format(Tables, SFun, fun tab2list/1);
-
-format(Tables, CFun)
- when is_list(Tables), is_function(CFun, 1) ->
- format(Tables, fun split/2, CFun).
-
-%%% ----------------------------------------------------------
-%%% # format(Table|Tables)
-%%% ----------------------------------------------------------
-
-format(Table)
- when is_atom(Table) ->
- format(Table, [], fun split/2);
-
-format(Tables)
- when is_list(Tables) ->
- format(Tables, fun split/2, fun tab2list/1).
-
-%%% ----------------------------------------------------------
-%%% # split(TableName, Fields, Values)
-%%%
-%%% Description: format/3 SplitFun that does nothing special.
-%%% ----------------------------------------------------------
-
-split([F|FT], [V|VT]) ->
- {F, FT, V, VT}.
-
-split(_, Fs, Vs) ->
- split(Fs, Vs).
-
-%%% ----------------------------------------------------------
-%%% # tab2list(TableName)
-%%%
-%%% Description: format/4 CollectFun that extracts records from an
-%%% existing ets table.
-%%% ----------------------------------------------------------
-
-tab2list(Table) ->
- case ets:info(Table) of
- undefined = No ->
- No;
- _ ->
- ets:tab2list(Table)
- end.
-
-list(Table) ->
- l(tab2list(Table)).
-
-l(undefined = No) ->
- No;
-l(List)
- when is_list(List) ->
- io:format("~p~n", [List]),
- length(List).
-
-%%% ----------------------------------------------------------
-%%% # table(TableName, Fields)
-%%% ----------------------------------------------------------
-
-table(Table, Fields) ->
- format(Table, Fields, fun split/2).
-
-%%% ----------------------------------------------------------
-%%% # tables(LocalTables, RemoteTables)
-%%% ----------------------------------------------------------
-
-tables(Local, Remote) ->
- format(Local, Remote, fun split/2).
-
-%%% ----------------------------------------------------------
-%%% # tables(Tables)
-%%% ----------------------------------------------------------
-
-tables(Tables) ->
- format(Tables, fun split/2).
-
-%%% ----------------------------------------------------------
-%%% # modules(Prefix|Prefixes)
-%%%
-%%% Input: Prefix = atom()
-%%%
-%%% Description: Return the list of all loaded modules with the
-%%% specified prefix.
-%%% ----------------------------------------------------------
-
-modules(Prefix)
- when is_atom(Prefix) ->
- lists:sort(mods(Prefix));
-
-modules(Prefixes)
- when is_list(Prefixes) ->
- lists:sort(lists:flatmap(fun modules/1, Prefixes)).
-
-mods(Prefix) ->
- P = atom_to_list(Prefix),
- lists:filter(fun(M) ->
- lists:prefix(P, atom_to_list(M))
- end,
- erlang:loaded()).
-
-%%% ----------------------------------------------------------
-%%% # versions(Modules|Prefix)
-%%%
-%%% Output: Number of modules listed.
-%%%
-%%% Description: List the versions of the specified modules.
-%%% ----------------------------------------------------------
-
-versions(Modules) ->
- {SysInfo, OsInfo, ModInfo} = version_info(Modules),
- sep(),
- print_sys_info(SysInfo),
- sep(),
- print_os_info(OsInfo),
- sep(),
- print_mod_info(ModInfo),
- sep().
-
-%%% ----------------------------------------------------------
-%%% # attrs(Modules|Prefix, Attr|FormatFun)
-%%%
-%%% Output: Number of modules listed.
-%%%
-%%% Description: List an attribute from module_info.
-%%% ----------------------------------------------------------
-
-attrs(Modules, Attr)
- when is_atom(Attr) ->
- attrs(Modules, fun(W,M) -> attr(W, M, Attr, fun attr/1) end);
-
-attrs(Modules, Fun)
- when is_list(Modules) ->
- sep(),
- W = 2 + widest(Modules),
- N = lists:foldl(fun(M,A) -> Fun(W,M), A+1 end, 0, Modules),
- sep(),
- N;
-
-attrs(Prefix, Fun) ->
- attrs(modules(Prefix), Fun).
-
-%% attr/1
-
-attr(T) when is_atom(T) ->
- atom_to_list(T);
-attr(N) when is_integer(N) ->
- integer_to_list(N);
-attr(V) ->
- case is_list(V) andalso lists:all(fun is_char/1, V) of
- true -> %% string
- V;
- false ->
- io_lib:format("~p", [V])
- end.
-
-is_char(C) ->
- 0 =< C andalso C < 256.
-
-%% attr/4
-
-attr(Width, Mod, Attr, VFun) ->
- io:format(": ~*s~s~n", [-Width, Mod, attr(Mod, Attr, VFun)]).
-
-attr(Mod, Attr, VFun) ->
- Key = key(Attr),
- try
- VFun(val(Attr, keyfetch(Attr, Mod:module_info(Key))))
- catch
- _:_ ->
- "-"
- end.
-
-attr(Mod, Attr) ->
- attr(Mod, Attr, fun attr/1).
-
-key(time) -> compile;
-key(_) -> attributes.
-
-val(time, {_,_,_,_,_,_} = T) ->
- lists:flatten(io_lib:format("~p-~2..0B-~2..0B ~2..0B:~2..0B:~2..0B",
- tuple_to_list(T)));
-val(_, [V]) ->
- V.
-
-%%% ----------------------------------------------------------
-%%% # compiled(Modules|Prefix)
-%%%
-%%% Output: Number of modules listed.
-%%%
-%%% Description: List the compile times of the specified modules.
-%%% ----------------------------------------------------------
-
-compiled(Modules)
- when is_list(Modules) ->
- attrs(Modules, fun compiled/2);
-
-compiled(Prefix) ->
- compiled(modules(Prefix)).
-
-compiled(Width, Mod) ->
- io:format(": ~*s~19s ~s~n", [-Width,
- Mod,
- attr(Mod, time),
- opt(attr(Mod, date))]).
-
-opt("-") ->
- "";
-opt(D) ->
- "(" ++ D ++ ")".
-
-%%% ----------------------------------------------------------
-%%% # procs(Pred|Prefix|Prefixes|Pid|Pids)
-%%%
-%%% Input: Pred = arity 2 fun returning true|false when applied to a
-%%% pid and its process info.
-%%%
-%%% Output: Number of processes listed.
-%%%
-%%% Description: List process info for all local processes that test
-%%% true with the specified predicate. With the prefix
-%%% form, those processes that are either currently
-%%% executing in, started executing in, or have a
-%%% registered name with a specified prefix are listed.
-%%% With the pid forms, only those process that are local
-%%% are listed and those that are dead list only the pid
-%%% itself.
-%%% ----------------------------------------------------------
-
-procs(Pred)
- when is_function(Pred, 2) ->
- procs(Pred, erlang:processes());
-
-procs([]) ->
- 0;
-
-procs(Prefix)
- when is_atom(Prefix) ->
- procs(fun(_,I) -> info(fun pre1/2, I, atom_to_list(Prefix)) end);
-
-procs(Prefixes)
- when is_atom(hd(Prefixes)) ->
- procs(fun(_,I) -> info(fun pre/2, I, Prefixes) end);
-
-procs(Pid)
- when is_pid(Pid) ->
- procs(fun true2/2, [Pid]);
-
-procs(Pids)
- when is_list(Pids) ->
- procs(fun true2/2, Pids).
-
-true2(_,_) ->
- true.
-
-%% procs/2
-
-procs(Pred, Pids) ->
- Procs = lists:foldl(fun(P,A) ->
- procs_acc(Pred, P, catch process_info(P), A)
- end,
- [],
- Pids),
- sep(0 < length(Procs)),
- lists:foldl(fun(T,N) -> p(T), sep(), N+1 end, 0, Procs).
-
-procs_acc(_, Pid, undefined, Acc) -> %% dead
- [[{pid, Pid}] | Acc];
-procs_acc(Pred, Pid, Info, Acc)
- when is_list(Info) ->
- p_acc(Pred(Pid, Info), Pid, Info, Acc);
-procs_acc(_, _, _, Acc) ->
- Acc.
-
-p_acc(true, Pid, Info, Acc) ->
- [[{pid, Pid} | Info] | Acc];
-p_acc(false, _, _, Acc) ->
- Acc.
-
-%% info/3
-
-info(Pred, Info, T) ->
- lists:any(fun(I) -> i(Pred, I, T) end, Info).
-
-i(Pred, {K, {M,_,_}}, T)
- when K == current_function;
- K == initial_call ->
- Pred(M,T);
-i(Pred, {registered_name, N}, T) ->
- Pred(N,T);
-i(_,_,_) ->
- false.
-
-pre1(A, Pre) ->
- lists:prefix(Pre, atom_to_list(A)).
-
-pre(A, Prefixes) ->
- lists:any(fun(P) -> pre1(A, atom_to_list(P)) end, Prefixes).
-
-%%% ----------------------------------------------------------
-%%% # latest(Modules|Prefix)
-%%%
-%%% Output: {Mod, {Y,M,D,HH,MM,SS}, Version}
-%%%
-%%% Description: Return the compile time of the most recently compiled
-%%% module from the specified non-empty list. The modules
-%%% are assumed to exist.
-%%% ----------------------------------------------------------
-
-latest(Prefix)
- when is_atom(Prefix) ->
- latest(modules(Prefix));
-
-latest([_|_] = Modules) ->
- {Mod, T}
- = hd(lists:sort(fun latest/2, lists:map(fun compile_time/1, Modules))),
- {Mod, T, app_vsn(Mod)}.
-
-app_vsn(Mod) ->
- keyfetch(app_vsn, Mod:module_info(attributes)).
-
-compile_time(Mod) ->
- T = keyfetch(time, Mod:module_info(compile)),
- {Mod, T}.
-
-latest({_,T1},{_,T2}) ->
- T1 > T2.
-
-%%% ----------------------------------------------------------
-%%% version_info(Modules|Prefix)
-%%%
-%%% Output: {SysInfo, OSInfo, [ModInfo]}
-%%%
-%%% SysInfo = {Arch, Vers}
-%%% OSInfo = {Vers, {Fam, Name}}
-%%% ModInfo = {Vsn, AppVsn, Time, CompilerVsn}
-%%% ----------------------------------------------------------
-
-version_info(Prefix)
- when is_atom(Prefix) ->
- version_info(modules(Prefix));
-
-version_info(Mods)
- when is_list(Mods) ->
- {sys_info(), os_info(), [{M, mod_version_info(M)} || M <- Mods]}.
-
-mod_version_info(Mod) ->
- try
- Info = Mod:module_info(),
- [[Vsn], AppVsn] = get_values(attributes, [vsn, app_vsn], Info),
- [Ver, Time] = get_values(compile, [version, time], Info),
- [Vsn, AppVsn, Ver, Time]
- catch
- _:_ ->
- []
- end.
-
-get_values(Attr, Keys, Info) ->
- As = proplists:get_value(Attr, Info),
- [proplists:get_value(K, As, "?") || K <- Keys].
-
-sys_info() ->
- [A,V] = [chomp(erlang:system_info(K)) || K <- [system_architecture,
- system_version]],
- {A,V}.
-
-os_info() ->
- {os:version(), os:type()}.
-
-chomp(S) ->
- string:strip(S, right, $\n).
-
-print_sys_info({Arch, Ver}) ->
- io:format("System info:~n"
- " architecture : ~s~n"
- " version : ~s~n",
- [Arch, Ver]).
-
-print_os_info({Vsn, {Fam, Name}}) ->
- io:format("OS info:~n"
- " family : ~s ~s~n"
- " version : ~s~n",
- [str(Fam), bkt(str(Name)), vsn(Vsn)]).
-
-print_mod_info(Mods) ->
- io:format("Module info:~n", []),
- lists:foreach(fun print_mod/1, Mods).
-
-print_mod({Mod, []}) ->
- io:format(" ~w:~n", [Mod]);
-print_mod({Mod, [Vsn, AppVsn, Ver, {Year, Month, Day, Hour, Min, Sec}]}) ->
- Time = io_lib:format("~w-~2..0w-~2..0w ~2..0w:~2..0w:~2..0w",
- [Year, Month, Day, Hour, Min, Sec]),
- io:format(" ~w:~n"
- " vsn : ~s~n"
- " app_vsn : ~s~n"
- " compiled : ~s~n"
- " compiler : ~s~n",
- [Mod, str(Vsn), str(AppVsn), Time, Ver]).
-
-str(A)
- when is_atom(A) ->
- atom_to_list(A);
-str(S)
- when is_list(S) ->
- S;
-str(T) ->
- io_lib:format("~p", [T]).
-
-bkt("" = S) ->
- S;
-bkt(S) ->
- [$[, S, $]].
-
-vsn(T) when is_tuple(T) ->
- case [[$., integer_to_list(N)] || N <- tuple_to_list(T)] of
- [[$.,S] | Rest] ->
- [S | Rest];
- [] = S ->
- S
- end;
-vsn(T) ->
- str(T).
-
-%%% ----------------------------------------------------------
-%%% ----------------------------------------------------------
-
-%% p/1
-
-p(Info) ->
- W = 2 + widest([K || {K,_} <- Info]),
- lists:foreach(fun({K,V}) -> p(W,K,V) end, Info).
-
-p(Width, Key, Value) ->
- io:format(": ~*s: ~p~n", [-Width, Key, Value]).
-
-%% sep/[01]
-
-sep() ->
- sep($#).
-
-sep(true) ->
- sep();
-sep(false) ->
- ok;
-
-sep(Ch) ->
- io:format("~c~65c~n", [Ch, $-]).
-
-%% widest/1
-
-widest(List) ->
- lists:foldl(fun widest/2, 0, List).
-
-widest(T, Max)
- when is_atom(T) ->
- widest(atom_to_list(T), Max);
-
-widest(T, Max)
- when is_integer(T) ->
- widest(integer_to_list(T), Max);
-
-widest(T, Max)
- when is_list(T) -> %% string
- max(length(T), Max).
-
-pt(T) ->
- io:format(": ~p~n", [T]).
-
-recsplit(SFun, Rec) ->
- fun(Fs,Vs) -> SFun(element(1, Rec), Fs, Vs) end.
-
-max(A, B) ->
- if A > B -> A; true -> B end.
-
-keyfetch(Key, List) ->
- {Key,V} = lists:keyfind(Key, 1, List),
- V.
-
-%% ft/4
-
-ft(undefined = No, _, _, _) ->
- No;
-
-ft(_, Table, SFun, Fields) ->
- ets:foldl(fun(R,A) ->
- f(SFun, 0, Fields, R, A)
- end,
- 0,
- Table).
-
-%% f/5
-
-f(SFun, Width, Fields, Rec, Count) ->
- ff(SFun, Width, fields(Fields, Rec), Rec, Count).
-
-ff(SFun, Width, Fields, Rec, Count) ->
- sep(0 == Count),
- f(SFun, Width, Fields, Rec),
- sep(),
- Count+1.
-
-fields(N, _)
- when is_integer(N), N >= 0 ->
- lists:duplicate(N, ''); %% list values unadorned
-fields(Fields, R)
- when is_function(Fields, 1) ->
- fields(Fields(R), R);
-fields({Fields, Values} = T, _)
- when length(Fields) == length(Values) ->
- T;
-fields(Fields, _)
- when is_list(Fields) ->
- Fields. %% list field/value pairs, or tuples if []
-
-%% f/4
-
-%% Empty fields list: just print the entry.
-f(_, _, [], Rec)
- when is_tuple(Rec) ->
- pt(Rec);
-
-%% Otherwise list field names/values.
-f(SFun, Width, {Fields, Values}, _) ->
- f(SFun, Width, Fields, Values);
-
-f(SFun, Width, Fields, Rec)
- when is_tuple(Rec) ->
- f(SFun, Width, Fields, values(Fields, Rec));
-
-f(_, _, [], []) ->
- ok;
-
-f(SFun, Width, [HF | _] = Fields, Values) ->
- {F, FT, V, VT} = SFun(Fields, Values),
- if is_list(F) -> %% V is a record
- break($>, HF),
- f(SFun, Width, F, values(F,V)),
- break($<, HF),
- f(SFun, Width, FT, VT);
- F == '' -> %% no field name: just list value
- pt(V),
- f(SFun, Width, FT, VT);
- true -> %% list field/value.
- W = max(Width, 1 + widest(Fields)),
- p(W, F, V),
- f(SFun, W, FT, VT)
- end.
-
-values(Fields, Rec)
- when length(Fields) == size(Rec) - 1 ->
- ?VALUES(Rec);
-values(Fields, T)
- when length(Fields) == size(T) ->
- tuple_to_list(T).
-
-%% format_local/2
-
-format_local(Tables, SFun) ->
- lists:foldl(fun(T,A) -> fl(SFun, T, A) end, 0, Tables).
-
-fl(SFun, {Table, Recs, Fields}, Count) ->
- sep(),
- io:format("# ~p~n", [Table]),
- N = fmt(Recs, Fields, SFun),
- sep(0 == N),
- Count + N;
-
-fl(SFun, {Table, Fields}, Count) ->
- fl(SFun, {Table, Table, Fields}, Count).
-
-%% fmt/3
-
-fmt(T, Fields, SFun) ->
- case format(T, Fields, SFun) of
- undefined ->
- 0;
- N ->
- N
- end.
-
-%% break/2
-
-break(C, T) ->
- io:format("~c ~p~n", [C, T]).
-
-%% collect/2
-%%
-%% Output: {[{TableName, Recs}, ...], node()}
-
-collect(CFun, TableNames) ->
- {lists:foldl(fun(N,A) -> c(CFun, N, A) end, [], TableNames), node()}.
-
-c(CFun, TableName, Acc) ->
- case CFun(TableName) of
- Recs when is_list(Recs) ->
- [{TableName, Recs} | Acc];
- _ ->
- Acc
- end.
-
-%% format_remote/3
-
-format_remote(Tables, SFun, {Replies, BadNodes}) ->
- N = lists:foldl(fun(T,A) -> fr(Tables, SFun, T, A) end,
- 0,
- Replies),
- sep(0 == N andalso [] /= BadNodes),
- lists:foreach(fun(Node) -> io:format("# no reply from ~p~n", [Node]) end,
- BadNodes),
- sep([] /= BadNodes),
- N.
-
-fr(Tables, SFun, {List, Node}, Count)
- when is_list(List) -> %% guard against {badrpc, Reason}
- lists:foldl(fun({T,Recs}, C) -> fr(Tables, SFun, Node, T, Recs,C) end,
- Count,
- List);
-fr(_, _, _, Count) ->
- Count.
-
-fr(Tables, SFun, Node, Table, Recs, Count) ->
- Fields = keyfetch(Table, Tables),
- sep(),
- io:format("# ~p@~p~n", [Table, Node]),
- N = format(Recs, Fields, tblsplit(SFun, Table)),
- sep(0 == N),
- Count + N.
-
-tblsplit(SFun, Table)
- when is_function(SFun, 3) ->
- fun(Fs,Vs) -> SFun(Table, Fs, Vs) end;
-tblsplit(SFun, _)
- when is_function(SFun, 2) ->
- SFun.
-
-%% compact/1
-%%
-%% Strip whitespace from both ends of a string.
-
-compact(Str) ->
- compact(Str, true).
-
-compact([Ch|Rest], B)
- when Ch == $\n;
- Ch == $ ;
- Ch == $\t;
- Ch == $\v;
- Ch == $\r ->
- compact(Rest, B);
-
-compact(Str, false) ->
- Str;
-
-compact(Str, true) ->
- lists:reverse(compact(lists:reverse(Str), false)).
diff --git a/lib/diameter/src/info/diameter_dbg.erl b/lib/diameter/src/info/diameter_dbg.erl
new file mode 100644
index 0000000000..1237007a75
--- /dev/null
+++ b/lib/diameter/src/info/diameter_dbg.erl
@@ -0,0 +1,515 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2010-2014. 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%
+%%
+
+%%
+%% Information and debug functions.
+%%
+
+-module(diameter_dbg).
+
+-export([table/1,
+ tables/0,
+ fields/1,
+ help/0,
+ modules/0,
+ versions/0,
+ version_info/0,
+ compiled/0,
+ procs/0,
+ latest/0,
+ nl/0]).
+
+-export([diameter_config/0,
+ diameter_peer/0,
+ diameter_reg/0,
+ diameter_request/0,
+ diameter_sequence/0,
+ diameter_service/0,
+ diameter_stats/0]).
+
+-export([pp/1,
+ subscriptions/0,
+ children/0]).
+
+%% Trace help.
+-export([tracer/0, tracer/1,
+ p/0, p/1,
+ stop/0,
+ tpl/1,
+ tp/1]).
+
+-include_lib("diameter/include/diameter.hrl").
+
+-define(APPLICATION, diameter).
+-define(INFO, diameter_info).
+-define(SEP(), ?INFO:sep()).
+
+-define(LOCAL, [diameter_config,
+ diameter_peer,
+ diameter_reg,
+ diameter_request,
+ diameter_sequence,
+ diameter_service,
+ diameter_stats]).
+
+-define(VALUES(Rec), tl(tuple_to_list(Rec))).
+
+%%% ----------------------------------------------------------
+%%% # help()
+%%% ----------------------------------------------------------
+
+help() ->
+ not_yet_implemented.
+
+%%% ----------------------------------------------------------
+%%% # table(TableName)
+%%%
+%%% Input: TableName = diameter table containing record entries.
+%%%
+%%% Output: Count | undefined
+%%% ----------------------------------------------------------
+
+table(T)
+ when (T == diameter_peer) orelse (T == diameter_reg) ->
+ ?INFO:format(collect(T), fields(T), fun ?INFO:split/2);
+
+table(Table)
+ when is_atom(Table) ->
+ case fields(Table) of
+ undefined = No ->
+ No;
+ Fields ->
+ ?INFO:format(Table, Fields, fun split/2)
+ end.
+
+split([started, name | Fs], [S, N | Vs]) ->
+ {name, [started | Fs], N, [S | Vs]};
+split([[F|FT]|Fs], [Rec|Vs]) ->
+ [_, V | VT] = tuple_to_list(Rec),
+ {F, FT ++ Fs, V, VT ++ Vs};
+split([F|Fs], [V|Vs]) ->
+ {F, Fs, V, Vs}.
+
+%%% ----------------------------------------------------------
+%%% # TableName()
+%%% ----------------------------------------------------------
+
+-define(TABLE(Name), Name() -> table(Name)).
+
+?TABLE(diameter_config).
+?TABLE(diameter_peer).
+?TABLE(diameter_reg).
+?TABLE(diameter_request).
+?TABLE(diameter_sequence).
+?TABLE(diameter_service).
+?TABLE(diameter_stats).
+
+%%% ----------------------------------------------------------
+%%% # tables()
+%%%
+%%% Output: Number of records output.
+%%%
+%%% Description: Pretty-print records in diameter tables from all nodes.
+%%% ----------------------------------------------------------
+
+tables() ->
+ ?INFO:format(field(?LOCAL), fun split/3, fun collect/1).
+
+field(Tables) ->
+ lists:map(fun(T) -> {T, fields(T)} end, lists:sort(Tables)).
+
+split(_, Fs, Vs) ->
+ split(Fs, Vs).
+
+%%% ----------------------------------------------------------
+%%% # modules()
+%%% ----------------------------------------------------------
+
+modules() ->
+ Path = filename:join([appdir(), atom_to_list(?APPLICATION) ++ ".app"]),
+ {ok, [{application, ?APPLICATION, Attrs}]} = file:consult(Path),
+ {modules, Mods} = lists:keyfind(modules, 1, Attrs),
+ Mods.
+
+appdir() ->
+ [_|_] = code:lib_dir(?APPLICATION, ebin).
+
+%%% ----------------------------------------------------------
+%%% # versions()
+%%% ----------------------------------------------------------
+
+versions() ->
+ ?INFO:versions(modules()).
+
+%%% ----------------------------------------------------------
+%%% # versions()
+%%% ----------------------------------------------------------
+
+version_info() ->
+ ?INFO:version_info(modules()).
+
+%%% ----------------------------------------------------------
+%%% # compiled()
+%%% ----------------------------------------------------------
+
+compiled() ->
+ ?INFO:compiled(modules()).
+
+%%% ----------------------------------------------------------
+%%% procs()
+%%% ----------------------------------------------------------
+
+procs() ->
+ ?INFO:procs(?APPLICATION).
+
+%%% ----------------------------------------------------------
+%%% # latest()
+%%% ----------------------------------------------------------
+
+latest() ->
+ ?INFO:latest(modules()).
+
+%%% ----------------------------------------------------------
+%%% # nl()
+%%% ----------------------------------------------------------
+
+nl() ->
+ lists:foreach(fun(M) -> abcast = c:nl(M) end, modules()).
+
+%%% ----------------------------------------------------------
+%%% # pp(Bin)
+%%%
+%%% Description: Pretty-print a message binary.
+%%% ----------------------------------------------------------
+
+%% Network byte order = big endian.
+
+pp(<>) ->
+ ?SEP(),
+ ppp(["Version",
+ "Message length",
+ "[Actual length]",
+ "R(equest)",
+ "P(roxiable)",
+ "E(rror)",
+ "T(Potential retrans)",
+ "Reserved bits",
+ "Command code",
+ "Application id",
+ "Hop by hop id",
+ "End to end id"],
+ [Version, MsgLength, size(AVPs) + 20,
+ Rbit, Pbit, Ebit, Tbit, Reserved,
+ CmdCode,
+ ApplId,
+ HbHid,
+ E2Eid]),
+ N = avp_loop({AVPs, MsgLength - 20}, 0),
+ ?SEP(),
+ N;
+
+pp(<<_Version:8, MsgLength:24, _/binary>> = Bin) ->
+ {bad_message_length, MsgLength, size(Bin)};
+
+pp(Bin)
+ when is_binary(Bin) ->
+ {truncated_binary, size(Bin)};
+
+pp(_) ->
+ not_binary.
+
+%% avp_loop/2
+
+avp_loop({Bin, Size}, N) ->
+ avp_loop(avp(Bin, Size), N+1);
+avp_loop(ok, N) ->
+ N;
+avp_loop([_E, _Rest] = L, N) ->
+ io:format("! ~s: ~p~n", L),
+ N;
+avp_loop([E, Rest, Fmt | Values], N)
+ when is_binary(Rest) ->
+ io:format("! ~s (" ++ Fmt ++ "): ~p~n", [E|Values] ++ [Rest]),
+ N.
+
+%% avp/2
+
+avp(<<>>, 0) ->
+ ok;
+avp(<>,
+ Size) ->
+ avp(Code, Flags, Length, Rest, Size);
+avp(Bin, _) ->
+ ["truncated AVP header", Bin].
+
+%% avp/5
+
+avp(Code, Flags, Length, Rest, Size) ->
+ <>
+ = Flags,
+ b(),
+ ppp(["AVP Code",
+ "V(endor)",
+ "M(andatory)",
+ "P(Security)",
+ "R(eserved)",
+ "Length"],
+ [Code, V, M, P, Res, Length]),
+ avp(V, Rest, Length - 8, Size - 8).
+
+%% avp/4
+
+avp(1, <>, Length, Size) ->
+ ppp({"Vendor-ID", V}),
+ data(Data, Length - 4, Size - 4);
+avp(1, Bin, _, _) ->
+ ["truncated Vendor-ID", Bin];
+avp(0, Data, Length, Size) ->
+ data(Data, Length, Size).
+
+data(Bin, Length, Size)
+ when size(Bin) >= Length ->
+ <> = Bin,
+ ppp({"Data", AVP}),
+ unpad(Rest, Size - Length, Length rem 4);
+
+data(Bin, _, _) ->
+ ["truncated AVP data", Bin].
+
+%% Remove padding bytes up to the next word boundary.
+unpad(Bin, Size, 0) ->
+ {Bin, Size};
+unpad(Bin, Size, N) ->
+ un(Bin, Size, 4 - N).
+
+un(Bin, Size, N)
+ when size(Bin) >= N ->
+ ppp({"Padding bytes", N}),
+ <> = Bin,
+ Bits = N*8,
+ case Pad of
+ <<0:Bits>> ->
+ {Rest, Size - N};
+ _ ->
+ ["non-zero padding", Bin, "~p", N]
+ end;
+
+un(Bin, _, _) ->
+ ["truncated padding", Bin].
+
+b() ->
+ io:format("#~n").
+
+ppp(Fields, Values) ->
+ lists:foreach(fun ppp/1, lists:zip(Fields, Values)).
+
+ppp({Field, Value}) ->
+ io:format(": ~-22s : ~p~n", [Field, Value]).
+
+%%% ----------------------------------------------------------
+%%% # subscriptions()
+%%%
+%%% Output: list of {SvcName, Pid}
+%%% ----------------------------------------------------------
+
+subscriptions() ->
+ diameter_service:subscriptions().
+
+%%% ----------------------------------------------------------
+%%% # children()
+%%% ----------------------------------------------------------
+
+children() ->
+ diameter_sup:tree().
+
+%%% ----------------------------------------------------------
+
+%% tracer/[12]
+
+tracer(Port)
+ when is_integer(Port) ->
+ dbg:tracer(port, dbg:trace_port(ip, Port));
+
+tracer(Path)
+ when is_list(Path) ->
+ dbg:tracer(port, dbg:trace_port(file, Path)).
+
+tracer() ->
+ dbg:tracer(process, {fun p/2, ok}).
+
+p(T,_) ->
+ io:format("+ ~p~n", [T]).
+
+%% p/[01]
+
+p() ->
+ p([c,timestamp]).
+
+p(T) ->
+ dbg:p(all,T).
+
+%% stop/0
+
+stop() ->
+ dbg:ctp(),
+ dbg:stop_clear().
+
+%% tpl/1
+%% tp/1
+
+tpl(T) ->
+ dbg(tpl, T).
+
+tp(T) ->
+ dbg(tp, T).
+
+%% dbg/2
+
+dbg(F, L)
+ when is_list(L) ->
+ [dbg(F, X) || X <- L];
+
+dbg(F, M)
+ when is_atom(M) ->
+ apply(dbg, F, [M, x]);
+
+dbg(F, T)
+ when is_tuple(T) ->
+ apply(dbg, F, tuple_to_list(T)).
+
+%% ===========================================================================
+%% ===========================================================================
+
+%% collect/1
+
+collect(diameter_peer) ->
+ lists:flatmap(fun peers/1, diameter:services());
+
+collect(diameter_reg) ->
+ diameter_reg:terms();
+
+collect(Name) ->
+ c(ets:info(Name), Name).
+
+c(undefined, _) ->
+ [];
+c(_, Name) ->
+ ets:tab2list(Name).
+
+%% peers/1
+
+peers(Name) ->
+ peers(Name, diameter:service_info(Name, transport)).
+
+peers(_, undefined) ->
+ [];
+peers(Name, Ts) ->
+ lists:flatmap(fun(T) -> mk_peers(Name, T) end, Ts).
+
+mk_peers(Name, [_, {type, connect} | _] = Ts) ->
+ [[Name | mk_peer(Ts)]];
+mk_peers(Name, [R, {type, listen}, O, {accept = A, As}]) ->
+ [[Name | mk_peer([R, {type, A}, O | Ts])] || Ts <- As].
+%% This is a bit lame: service_info works to build this list and out
+%% of something like what we want here and then we take it apart.
+
+mk_peer(Vs) ->
+ [Type, Ref, State, Opts, WPid, TPid, SApps, Caps]
+ = get_values(Vs, [type,ref,state,options,watchdog,peer,apps,caps]),
+ [Ref, State, [{type, Type} | Opts], s(WPid), s(TPid), SApps, Caps].
+
+get_values(Vs, Ks) ->
+ [proplists:get_value(K, Vs) || K <- Ks].
+
+s(undefined = T) ->
+ T;
+s({Pid, _Started, _State}) ->
+ state(Pid);
+s({Pid, _Started}) ->
+ state(Pid).
+
+%% Collect states from watchdog/transport pids.
+state(Pid) ->
+ MRef = erlang:monitor(process, Pid),
+ Pid ! {state, self()},
+ receive
+ {'DOWN', MRef, process, _, _} ->
+ Pid;
+ {Pid, _} = T ->
+ erlang:demonitor(MRef, [flush]),
+ T
+ end.
+
+%% fields/1
+
+-define(FIELDS(Table), fields(Table) -> record_info(fields, Table)).
+
+fields(diameter_config) ->
+ [];
+
+fields(T)
+ when T == diameter_request;
+ T == diameter_sequence ->
+ fun kv/1;
+
+fields(diameter_stats) ->
+ fun({Ctr, N}) when not is_pid(Ctr) ->
+ {[counter, value], [Ctr, N]};
+ (_) ->
+ []
+ end;
+
+fields(diameter_service) ->
+ [started,
+ name,
+ record_info(fields, diameter_service),
+ peerT,
+ connT,
+ share_peers,
+ use_shared_peers,
+ shared_peers,
+ local_peers,
+ monitor];
+
+?FIELDS(diameter_event);
+?FIELDS(diameter_uri);
+?FIELDS(diameter_avp);
+?FIELDS(diameter_header);
+?FIELDS(diameter_packet);
+?FIELDS(diameter_app);
+?FIELDS(diameter_caps);
+
+fields(diameter_peer) ->
+ [service, ref, state, options, watchdog, peer, applications, capabilities];
+
+fields(diameter_reg) ->
+ [property, pids];
+
+fields(_) ->
+ undefined.
+
+kv({_,_}) ->
+ [key, value];
+kv(_) ->
+ [].
diff --git a/lib/diameter/src/info/diameter_info.erl b/lib/diameter/src/info/diameter_info.erl
new file mode 100644
index 0000000000..10972f3231
--- /dev/null
+++ b/lib/diameter/src/info/diameter_info.erl
@@ -0,0 +1,869 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2010-2014. 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%
+%%
+
+%%
+%% Generic functions for formatting table listings and more. Used by
+%% diameter_dbg.
+%%
+
+-module(diameter_info).
+
+-export([usage/1,
+ format/1,
+ format/2,
+ format/3,
+ format/4,
+ table/2,
+ tables/1,
+ tables/2,
+ split/2,
+ split/3,
+ tab2list/1,
+ modules/1,
+ versions/1,
+ version_info/1,
+ attrs/2,
+ compiled/1,
+ procs/1,
+ latest/1,
+ list/1]).
+
+%% Support for rolling your own.
+-export([sep/0,
+ sep/1,
+ widest/1,
+ p/1,
+ p/3]).
+
+-compile({no_auto_import,[max/2]}).
+
+-export([collect/2]).
+
+-define(LONG_TIMEOUT, 30000).
+-define(VALUES(Rec), tl(tuple_to_list(Rec))).
+
+%%% ----------------------------------------------------------
+%%% # usage(String)
+%%% ----------------------------------------------------------
+
+usage(Usage) ->
+ sep($+),
+ io:format("+ ~p~n", [?MODULE]),
+ io:format("~n~s~n~n", [compact(Usage)]),
+ sep($+).
+
+%%%
+%%% The function format/3, for pretty-printing tables, comes in
+%%% several flavours.
+%%%
+
+%%% ----------------------------------------------------------
+%%% # format(TableName, Fields, SplitFun)
+%%%
+%%% Input: TableName = atom() name of table.
+%%%
+%%% Fields = List of field names for the records maintained
+%%% in the specified table. Can be empty, in which
+%%% case entries are listed unadorned of field names
+%%% and SplitFun is unused.
+%%% | Integer, equivalent to a list with this many '' atoms.
+%%% | Arity 1 fun mapping a table entry to a Fields list
+%%% or a tuple {Fields, Values} of lists of the same
+%%% length.
+%%%
+%%% If Fields is a list then its length must be the same
+%%% as or one less than the size of the tuples contained
+%%% in the table. (The values printed then being those
+%%% in the tuple or record in question.)
+%%%
+%%% SplitFun = Arity 3 fun applied as
+%%%
+%%% SplitFun(TableName, Fields, Values)
+%%%
+%%% in order to obtain a tuple
+%%%
+%%% {Field, RestFields, Value, RestValues}
+%%%
+%%% for which Field/Value will be formatted on
+%%% STDOUT. (This is to allow a value to be
+%%% transformed before being output by returning a
+%%% new value and/or replacing the remainder of
+%%% the list.) The returned lists must have the
+%%% same length and Field here is an atom, '' causing
+%%% a value to be listed unadorned of the field name.
+%%%
+%%% Field can also be list of field names, in
+%%% which case Value must be a record of the
+%%% corresponding type.
+%%%
+%%% | Arity 2 fun applied as SplitFun(Fields, Values).
+%%%
+%%% Output: Count | undefined
+%%%
+%%% Count = Number of entries output.
+%%%
+%%% Description: Pretty-print records in a named table.
+%%% ----------------------------------------------------------
+
+format(Table, Fields, SFun)
+ when is_atom(Table), is_function(SFun, 2) ->
+ ft(ets:info(Table), Table, SFun, Fields);
+
+format(Table, Fields, SFun)
+ when is_atom(Table), is_function(SFun, 3) ->
+ format(Table, Fields, fun(Fs,Vs) -> SFun(Table, Fs, Vs) end);
+
+%%% ----------------------------------------------------------
+%%% # format(Recs, Fields, SplitFun)
+%%%
+%%% Input: Recs = list of records/tuples
+%%% Fields = As for format(Table, Fields, SplitFun), a table
+%%% entry there being a member of Recs.
+%%% SplitFun = Arity 3 fun applied as above but with the TableName
+%%% replaced by the first element of the records in
+%%% question.
+%%% | Arity 2 fun as for format/3.
+%%%
+%%% Output: length(Recs)
+%%%
+%%% Description: Pretty print records/tuples.
+%%% ----------------------------------------------------------
+
+format(Recs, Fields, SFun)
+ when is_list(Recs), is_function(SFun, 3) ->
+ lists:foldl(fun(R,A) -> f(recsplit(SFun, R), 0, Fields, R, A) end,
+ 0,
+ Recs);
+
+format(Recs, Fields, SFun)
+ when is_list(Recs), is_function(SFun, 2) ->
+ lists:foldl(fun(R,A) -> f(SFun, 0, Fields, R, A) end,
+ 0,
+ Recs);
+
+%%% ----------------------------------------------------------
+%%% # format(Tables, SplitFun, CollectFun)
+%%%
+%%% Input: Tables = list of {TableName, Fields}.
+%%% SplitFun = As for format(Table, Fields, SplitFun).
+%%% CollectFun = arity 1 fun mapping a table name to a list
+%%% of elements. A non-list can be returned to indicate
+%%% that the table in question doesn't exist.
+%%%
+%%% Output: Number of entries output.
+%%%
+%%% Description: Pretty-print records in a named tables as collected
+%%% from known nodes. Each table listing is preceeded by
+%%% a banner.
+%%% ----------------------------------------------------------
+
+format(Tables, SFun, CFun)
+ when is_list(Tables), is_function(CFun, 1) ->
+ format_remote(Tables,
+ SFun,
+ rpc:multicall(nodes(known),
+ ?MODULE,
+ collect,
+ [CFun, lists:map(fun({T,_}) -> T end, Tables)],
+ ?LONG_TIMEOUT));
+
+%%% ----------------------------------------------------------
+%%% # format(LocalTables, RemoteTables, SplitFun, CollectFun)
+%%% # format(LocalTables, RemoteTables, SplitFun)
+%%%
+%%% Input: LocalTables = list of {TableName, Fields}.
+%%% | list of {TableName, Recs, Fields}
+%%% RemoteTable = list of {TableName, Fields}.
+%%% SplitFun, CollectFun = As for format(Table, CollectFun, SplitFun).
+%%%
+%%% Output: Number of entries output.
+%%%
+%%% Description: Pretty-print records in a named tables as collected
+%%% from local and remote nodes. Each table listing is
+%%% preceeded by a banner.
+%%% ----------------------------------------------------------
+
+format(Local, Remote, SFun) ->
+ format(Local, Remote, SFun, fun tab2list/1).
+
+format(Local, Remote, SFun, CFun)
+ when is_list(Local), is_list(Remote), is_function(CFun, 1) ->
+ format_local(Local, SFun) + format(Remote, SFun, CFun).
+
+%%% ----------------------------------------------------------
+%%% # format(Tables, SplitFun)
+%%% ----------------------------------------------------------
+
+format(Tables, SFun)
+ when is_list(Tables), (is_function(SFun, 2) or is_function(SFun, 3)) ->
+ format(Tables, SFun, fun tab2list/1);
+
+format(Tables, CFun)
+ when is_list(Tables), is_function(CFun, 1) ->
+ format(Tables, fun split/2, CFun).
+
+%%% ----------------------------------------------------------
+%%% # format(Table|Tables)
+%%% ----------------------------------------------------------
+
+format(Table)
+ when is_atom(Table) ->
+ format(Table, [], fun split/2);
+
+format(Tables)
+ when is_list(Tables) ->
+ format(Tables, fun split/2, fun tab2list/1).
+
+%%% ----------------------------------------------------------
+%%% # split(TableName, Fields, Values)
+%%%
+%%% Description: format/3 SplitFun that does nothing special.
+%%% ----------------------------------------------------------
+
+split([F|FT], [V|VT]) ->
+ {F, FT, V, VT}.
+
+split(_, Fs, Vs) ->
+ split(Fs, Vs).
+
+%%% ----------------------------------------------------------
+%%% # tab2list(TableName)
+%%%
+%%% Description: format/4 CollectFun that extracts records from an
+%%% existing ets table.
+%%% ----------------------------------------------------------
+
+tab2list(Table) ->
+ case ets:info(Table) of
+ undefined = No ->
+ No;
+ _ ->
+ ets:tab2list(Table)
+ end.
+
+list(Table) ->
+ l(tab2list(Table)).
+
+l(undefined = No) ->
+ No;
+l(List)
+ when is_list(List) ->
+ io:format("~p~n", [List]),
+ length(List).
+
+%%% ----------------------------------------------------------
+%%% # table(TableName, Fields)
+%%% ----------------------------------------------------------
+
+table(Table, Fields) ->
+ format(Table, Fields, fun split/2).
+
+%%% ----------------------------------------------------------
+%%% # tables(LocalTables, RemoteTables)
+%%% ----------------------------------------------------------
+
+tables(Local, Remote) ->
+ format(Local, Remote, fun split/2).
+
+%%% ----------------------------------------------------------
+%%% # tables(Tables)
+%%% ----------------------------------------------------------
+
+tables(Tables) ->
+ format(Tables, fun split/2).
+
+%%% ----------------------------------------------------------
+%%% # modules(Prefix|Prefixes)
+%%%
+%%% Input: Prefix = atom()
+%%%
+%%% Description: Return the list of all loaded modules with the
+%%% specified prefix.
+%%% ----------------------------------------------------------
+
+modules(Prefix)
+ when is_atom(Prefix) ->
+ lists:sort(mods(Prefix));
+
+modules(Prefixes)
+ when is_list(Prefixes) ->
+ lists:sort(lists:flatmap(fun modules/1, Prefixes)).
+
+mods(Prefix) ->
+ P = atom_to_list(Prefix),
+ lists:filter(fun(M) ->
+ lists:prefix(P, atom_to_list(M))
+ end,
+ erlang:loaded()).
+
+%%% ----------------------------------------------------------
+%%% # versions(Modules|Prefix)
+%%%
+%%% Output: Number of modules listed.
+%%%
+%%% Description: List the versions of the specified modules.
+%%% ----------------------------------------------------------
+
+versions(Modules) ->
+ {SysInfo, OsInfo, ModInfo} = version_info(Modules),
+ sep(),
+ print_sys_info(SysInfo),
+ sep(),
+ print_os_info(OsInfo),
+ sep(),
+ print_mod_info(ModInfo),
+ sep().
+
+%%% ----------------------------------------------------------
+%%% # attrs(Modules|Prefix, Attr|FormatFun)
+%%%
+%%% Output: Number of modules listed.
+%%%
+%%% Description: List an attribute from module_info.
+%%% ----------------------------------------------------------
+
+attrs(Modules, Attr)
+ when is_atom(Attr) ->
+ attrs(Modules, fun(W,M) -> attr(W, M, Attr, fun attr/1) end);
+
+attrs(Modules, Fun)
+ when is_list(Modules) ->
+ sep(),
+ W = 2 + widest(Modules),
+ N = lists:foldl(fun(M,A) -> Fun(W,M), A+1 end, 0, Modules),
+ sep(),
+ N;
+
+attrs(Prefix, Fun) ->
+ attrs(modules(Prefix), Fun).
+
+%% attr/1
+
+attr(T) when is_atom(T) ->
+ atom_to_list(T);
+attr(N) when is_integer(N) ->
+ integer_to_list(N);
+attr(V) ->
+ case is_list(V) andalso lists:all(fun is_char/1, V) of
+ true -> %% string
+ V;
+ false ->
+ io_lib:format("~p", [V])
+ end.
+
+is_char(C) ->
+ 0 =< C andalso C < 256.
+
+%% attr/4
+
+attr(Width, Mod, Attr, VFun) ->
+ io:format(": ~*s~s~n", [-Width, Mod, attr(Mod, Attr, VFun)]).
+
+attr(Mod, Attr, VFun) ->
+ Key = key(Attr),
+ try
+ VFun(val(Attr, keyfetch(Attr, Mod:module_info(Key))))
+ catch
+ _:_ ->
+ "-"
+ end.
+
+attr(Mod, Attr) ->
+ attr(Mod, Attr, fun attr/1).
+
+key(time) -> compile;
+key(_) -> attributes.
+
+val(time, {_,_,_,_,_,_} = T) ->
+ lists:flatten(io_lib:format("~p-~2..0B-~2..0B ~2..0B:~2..0B:~2..0B",
+ tuple_to_list(T)));
+val(_, [V]) ->
+ V.
+
+%%% ----------------------------------------------------------
+%%% # compiled(Modules|Prefix)
+%%%
+%%% Output: Number of modules listed.
+%%%
+%%% Description: List the compile times of the specified modules.
+%%% ----------------------------------------------------------
+
+compiled(Modules)
+ when is_list(Modules) ->
+ attrs(Modules, fun compiled/2);
+
+compiled(Prefix) ->
+ compiled(modules(Prefix)).
+
+compiled(Width, Mod) ->
+ io:format(": ~*s~19s ~s~n", [-Width,
+ Mod,
+ attr(Mod, time),
+ opt(attr(Mod, date))]).
+
+opt("-") ->
+ "";
+opt(D) ->
+ "(" ++ D ++ ")".
+
+%%% ----------------------------------------------------------
+%%% # procs(Pred|Prefix|Prefixes|Pid|Pids)
+%%%
+%%% Input: Pred = arity 2 fun returning true|false when applied to a
+%%% pid and its process info.
+%%%
+%%% Output: Number of processes listed.
+%%%
+%%% Description: List process info for all local processes that test
+%%% true with the specified predicate. With the prefix
+%%% form, those processes that are either currently
+%%% executing in, started executing in, or have a
+%%% registered name with a specified prefix are listed.
+%%% With the pid forms, only those process that are local
+%%% are listed and those that are dead list only the pid
+%%% itself.
+%%% ----------------------------------------------------------
+
+procs(Pred)
+ when is_function(Pred, 2) ->
+ procs(Pred, erlang:processes());
+
+procs([]) ->
+ 0;
+
+procs(Prefix)
+ when is_atom(Prefix) ->
+ procs(fun(_,I) -> info(fun pre1/2, I, atom_to_list(Prefix)) end);
+
+procs(Prefixes)
+ when is_atom(hd(Prefixes)) ->
+ procs(fun(_,I) -> info(fun pre/2, I, Prefixes) end);
+
+procs(Pid)
+ when is_pid(Pid) ->
+ procs(fun true2/2, [Pid]);
+
+procs(Pids)
+ when is_list(Pids) ->
+ procs(fun true2/2, Pids).
+
+true2(_,_) ->
+ true.
+
+%% procs/2
+
+procs(Pred, Pids) ->
+ Procs = lists:foldl(fun(P,A) ->
+ procs_acc(Pred, P, catch process_info(P), A)
+ end,
+ [],
+ Pids),
+ sep(0 < length(Procs)),
+ lists:foldl(fun(T,N) -> p(T), sep(), N+1 end, 0, Procs).
+
+procs_acc(_, Pid, undefined, Acc) -> %% dead
+ [[{pid, Pid}] | Acc];
+procs_acc(Pred, Pid, Info, Acc)
+ when is_list(Info) ->
+ p_acc(Pred(Pid, Info), Pid, Info, Acc);
+procs_acc(_, _, _, Acc) ->
+ Acc.
+
+p_acc(true, Pid, Info, Acc) ->
+ [[{pid, Pid} | Info] | Acc];
+p_acc(false, _, _, Acc) ->
+ Acc.
+
+%% info/3
+
+info(Pred, Info, T) ->
+ lists:any(fun(I) -> i(Pred, I, T) end, Info).
+
+i(Pred, {K, {M,_,_}}, T)
+ when K == current_function;
+ K == initial_call ->
+ Pred(M,T);
+i(Pred, {registered_name, N}, T) ->
+ Pred(N,T);
+i(_,_,_) ->
+ false.
+
+pre1(A, Pre) ->
+ lists:prefix(Pre, atom_to_list(A)).
+
+pre(A, Prefixes) ->
+ lists:any(fun(P) -> pre1(A, atom_to_list(P)) end, Prefixes).
+
+%%% ----------------------------------------------------------
+%%% # latest(Modules|Prefix)
+%%%
+%%% Output: {Mod, {Y,M,D,HH,MM,SS}, Version}
+%%%
+%%% Description: Return the compile time of the most recently compiled
+%%% module from the specified non-empty list. The modules
+%%% are assumed to exist.
+%%% ----------------------------------------------------------
+
+latest(Prefix)
+ when is_atom(Prefix) ->
+ latest(modules(Prefix));
+
+latest([_|_] = Modules) ->
+ {Mod, T}
+ = hd(lists:sort(fun latest/2, lists:map(fun compile_time/1, Modules))),
+ {Mod, T, app_vsn(Mod)}.
+
+app_vsn(Mod) ->
+ keyfetch(app_vsn, Mod:module_info(attributes)).
+
+compile_time(Mod) ->
+ T = keyfetch(time, Mod:module_info(compile)),
+ {Mod, T}.
+
+latest({_,T1},{_,T2}) ->
+ T1 > T2.
+
+%%% ----------------------------------------------------------
+%%% version_info(Modules|Prefix)
+%%%
+%%% Output: {SysInfo, OSInfo, [ModInfo]}
+%%%
+%%% SysInfo = {Arch, Vers}
+%%% OSInfo = {Vers, {Fam, Name}}
+%%% ModInfo = {Vsn, AppVsn, Time, CompilerVsn}
+%%% ----------------------------------------------------------
+
+version_info(Prefix)
+ when is_atom(Prefix) ->
+ version_info(modules(Prefix));
+
+version_info(Mods)
+ when is_list(Mods) ->
+ {sys_info(), os_info(), [{M, mod_version_info(M)} || M <- Mods]}.
+
+mod_version_info(Mod) ->
+ try
+ Info = Mod:module_info(),
+ [[Vsn], AppVsn] = get_values(attributes, [vsn, app_vsn], Info),
+ [Ver, Time] = get_values(compile, [version, time], Info),
+ [Vsn, AppVsn, Ver, Time]
+ catch
+ _:_ ->
+ []
+ end.
+
+get_values(Attr, Keys, Info) ->
+ As = proplists:get_value(Attr, Info),
+ [proplists:get_value(K, As, "?") || K <- Keys].
+
+sys_info() ->
+ [A,V] = [chomp(erlang:system_info(K)) || K <- [system_architecture,
+ system_version]],
+ {A,V}.
+
+os_info() ->
+ {os:version(), os:type()}.
+
+chomp(S) ->
+ string:strip(S, right, $\n).
+
+print_sys_info({Arch, Ver}) ->
+ io:format("System info:~n"
+ " architecture : ~s~n"
+ " version : ~s~n",
+ [Arch, Ver]).
+
+print_os_info({Vsn, {Fam, Name}}) ->
+ io:format("OS info:~n"
+ " family : ~s ~s~n"
+ " version : ~s~n",
+ [str(Fam), bkt(str(Name)), vsn(Vsn)]).
+
+print_mod_info(Mods) ->
+ io:format("Module info:~n", []),
+ lists:foreach(fun print_mod/1, Mods).
+
+print_mod({Mod, []}) ->
+ io:format(" ~w:~n", [Mod]);
+print_mod({Mod, [Vsn, AppVsn, Ver, {Year, Month, Day, Hour, Min, Sec}]}) ->
+ Time = io_lib:format("~w-~2..0w-~2..0w ~2..0w:~2..0w:~2..0w",
+ [Year, Month, Day, Hour, Min, Sec]),
+ io:format(" ~w:~n"
+ " vsn : ~s~n"
+ " app_vsn : ~s~n"
+ " compiled : ~s~n"
+ " compiler : ~s~n",
+ [Mod, str(Vsn), str(AppVsn), Time, Ver]).
+
+str(A)
+ when is_atom(A) ->
+ atom_to_list(A);
+str(S)
+ when is_list(S) ->
+ S;
+str(T) ->
+ io_lib:format("~p", [T]).
+
+bkt("" = S) ->
+ S;
+bkt(S) ->
+ [$[, S, $]].
+
+vsn(T) when is_tuple(T) ->
+ case [[$., integer_to_list(N)] || N <- tuple_to_list(T)] of
+ [[$.,S] | Rest] ->
+ [S | Rest];
+ [] = S ->
+ S
+ end;
+vsn(T) ->
+ str(T).
+
+%%% ----------------------------------------------------------
+%%% ----------------------------------------------------------
+
+%% p/1
+
+p(Info) ->
+ W = 2 + widest([K || {K,_} <- Info]),
+ lists:foreach(fun({K,V}) -> p(W,K,V) end, Info).
+
+p(Width, Key, Value) ->
+ io:format(": ~*s: ~p~n", [-Width, Key, Value]).
+
+%% sep/[01]
+
+sep() ->
+ sep($#).
+
+sep(true) ->
+ sep();
+sep(false) ->
+ ok;
+
+sep(Ch) ->
+ io:format("~c~65c~n", [Ch, $-]).
+
+%% widest/1
+
+widest(List) ->
+ lists:foldl(fun widest/2, 0, List).
+
+widest(T, Max)
+ when is_atom(T) ->
+ widest(atom_to_list(T), Max);
+
+widest(T, Max)
+ when is_integer(T) ->
+ widest(integer_to_list(T), Max);
+
+widest(T, Max)
+ when is_list(T) -> %% string
+ max(length(T), Max).
+
+pt(T) ->
+ io:format(": ~p~n", [T]).
+
+recsplit(SFun, Rec) ->
+ fun(Fs,Vs) -> SFun(element(1, Rec), Fs, Vs) end.
+
+max(A, B) ->
+ if A > B -> A; true -> B end.
+
+keyfetch(Key, List) ->
+ {Key,V} = lists:keyfind(Key, 1, List),
+ V.
+
+%% ft/4
+
+ft(undefined = No, _, _, _) ->
+ No;
+
+ft(_, Table, SFun, Fields) ->
+ ets:foldl(fun(R,A) ->
+ f(SFun, 0, Fields, R, A)
+ end,
+ 0,
+ Table).
+
+%% f/5
+
+f(SFun, Width, Fields, Rec, Count) ->
+ ff(SFun, Width, fields(Fields, Rec), Rec, Count).
+
+ff(SFun, Width, Fields, Rec, Count) ->
+ sep(0 == Count),
+ f(SFun, Width, Fields, Rec),
+ sep(),
+ Count+1.
+
+fields(N, _)
+ when is_integer(N), N >= 0 ->
+ lists:duplicate(N, ''); %% list values unadorned
+fields(Fields, R)
+ when is_function(Fields, 1) ->
+ fields(Fields(R), R);
+fields({Fields, Values} = T, _)
+ when length(Fields) == length(Values) ->
+ T;
+fields(Fields, _)
+ when is_list(Fields) ->
+ Fields. %% list field/value pairs, or tuples if []
+
+%% f/4
+
+%% Empty fields list: just print the entry.
+f(_, _, [], Rec)
+ when is_tuple(Rec) ->
+ pt(Rec);
+
+%% Otherwise list field names/values.
+f(SFun, Width, {Fields, Values}, _) ->
+ f(SFun, Width, Fields, Values);
+
+f(SFun, Width, Fields, Rec)
+ when is_tuple(Rec) ->
+ f(SFun, Width, Fields, values(Fields, Rec));
+
+f(_, _, [], []) ->
+ ok;
+
+f(SFun, Width, [HF | _] = Fields, Values) ->
+ {F, FT, V, VT} = SFun(Fields, Values),
+ if is_list(F) -> %% V is a record
+ break($>, HF),
+ f(SFun, Width, F, values(F,V)),
+ break($<, HF),
+ f(SFun, Width, FT, VT);
+ F == '' -> %% no field name: just list value
+ pt(V),
+ f(SFun, Width, FT, VT);
+ true -> %% list field/value.
+ W = max(Width, 1 + widest(Fields)),
+ p(W, F, V),
+ f(SFun, W, FT, VT)
+ end.
+
+values(Fields, Rec)
+ when length(Fields) == size(Rec) - 1 ->
+ ?VALUES(Rec);
+values(Fields, T)
+ when length(Fields) == size(T) ->
+ tuple_to_list(T).
+
+%% format_local/2
+
+format_local(Tables, SFun) ->
+ lists:foldl(fun(T,A) -> fl(SFun, T, A) end, 0, Tables).
+
+fl(SFun, {Table, Recs, Fields}, Count) ->
+ sep(),
+ io:format("# ~p~n", [Table]),
+ N = fmt(Recs, Fields, SFun),
+ sep(0 == N),
+ Count + N;
+
+fl(SFun, {Table, Fields}, Count) ->
+ fl(SFun, {Table, Table, Fields}, Count).
+
+%% fmt/3
+
+fmt(T, Fields, SFun) ->
+ case format(T, Fields, SFun) of
+ undefined ->
+ 0;
+ N ->
+ N
+ end.
+
+%% break/2
+
+break(C, T) ->
+ io:format("~c ~p~n", [C, T]).
+
+%% collect/2
+%%
+%% Output: {[{TableName, Recs}, ...], node()}
+
+collect(CFun, TableNames) ->
+ {lists:foldl(fun(N,A) -> c(CFun, N, A) end, [], TableNames), node()}.
+
+c(CFun, TableName, Acc) ->
+ case CFun(TableName) of
+ Recs when is_list(Recs) ->
+ [{TableName, Recs} | Acc];
+ _ ->
+ Acc
+ end.
+
+%% format_remote/3
+
+format_remote(Tables, SFun, {Replies, BadNodes}) ->
+ N = lists:foldl(fun(T,A) -> fr(Tables, SFun, T, A) end,
+ 0,
+ Replies),
+ sep(0 == N andalso [] /= BadNodes),
+ lists:foreach(fun(Node) -> io:format("# no reply from ~p~n", [Node]) end,
+ BadNodes),
+ sep([] /= BadNodes),
+ N.
+
+fr(Tables, SFun, {List, Node}, Count)
+ when is_list(List) -> %% guard against {badrpc, Reason}
+ lists:foldl(fun({T,Recs}, C) -> fr(Tables, SFun, Node, T, Recs,C) end,
+ Count,
+ List);
+fr(_, _, _, Count) ->
+ Count.
+
+fr(Tables, SFun, Node, Table, Recs, Count) ->
+ Fields = keyfetch(Table, Tables),
+ sep(),
+ io:format("# ~p@~p~n", [Table, Node]),
+ N = format(Recs, Fields, tblsplit(SFun, Table)),
+ sep(0 == N),
+ Count + N.
+
+tblsplit(SFun, Table)
+ when is_function(SFun, 3) ->
+ fun(Fs,Vs) -> SFun(Table, Fs, Vs) end;
+tblsplit(SFun, _)
+ when is_function(SFun, 2) ->
+ SFun.
+
+%% compact/1
+%%
+%% Strip whitespace from both ends of a string.
+
+compact(Str) ->
+ compact(Str, true).
+
+compact([Ch|Rest], B)
+ when Ch == $\n;
+ Ch == $ ;
+ Ch == $\t;
+ Ch == $\v;
+ Ch == $\r ->
+ compact(Rest, B);
+
+compact(Str, false) ->
+ Str;
+
+compact(Str, true) ->
+ lists:reverse(compact(lists:reverse(Str), false)).
diff --git a/lib/diameter/src/modules.mk b/lib/diameter/src/modules.mk
index 9f9b6d3308..a2a7a51892 100644
--- a/lib/diameter/src/modules.mk
+++ b/lib/diameter/src/modules.mk
@@ -73,8 +73,8 @@ CT_MODULES = \
# Info/debug modules, also not included in the app file.
INFO_MODULES = \
- base/diameter_dbg \
- base/diameter_info
+ info/diameter_dbg \
+ info/diameter_info
# Released hrl files in ../include intended for public consumption.
EXTERNAL_HRLS = \
--
cgit v1.2.3