OTP-21 support
- conditionally drop metrics related to error_logger queue length
when the process is not running
- deprecate recon:files/0 since the file implementation in OTP-21
works with NIFs and no longer allows listing descriptors
- updating tests to work with the new constraints -- apparently polling
a process increases its reduction count now as well
- move the CI to rebar3
- have the docsite script updated to deal with the removal of non-SMP
erlang
- bump minor version
- make support of R15 and R16 a best-effort thing
diff --git a/.travis.yml b/.travis.yml
index 8f55847..0267385 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -1,20 +1,14 @@
sudo: false
language: erlang
otp_release:
+ - 21.0
- 20.0
- 19.3
- 18.3
- 17.3
- 17.1
- 17.0
- - R16B03-1
- - R16B03
- - R16B02
- - R16B01
- - R16B
- - R15B03
- - R15B02
-script: "rm -rf deps ebin test/*.beam logs && ./rebar get-deps compile && ./rebar ct"
+script: "wget https://s3.amazonaws.com/rebar3/rebar3 && escript rebar3 do edoc, eunit, ct"
branches:
only:
- master
diff --git a/README.md b/README.md
index 02058e4..611e2e5 100644
--- a/README.md
+++ b/README.md
@@ -16,7 +16,7 @@
[![Build Status](https://travis-ci.org/ferd/recon.png)](https://travis-ci.org/ferd/recon)
-Versions supported: R15B02 and up
+Versions supported: OTP-17 and up. Support of R16B03-1 down to R15B02 is best effort.
Changelog
---------
@@ -27,6 +27,11 @@
*2.x*
+- 2.3.6
+ - Adapting for OTP-21. Includes the 'deprecation' of `recon:files/0`
+ since OTP-21 no longer supports listing all file descriptors, and
+ removing `error_logger_queue_len` from node stats since a new
+ logging mechanism was introduced in-process instead.
- 2.3.5
- fixing timefold's first iteration to prevent errors at call-site
by sleeping before sampling
diff --git a/docsite.erl b/docsite.erl
index a071002..5077904 100755
--- a/docsite.erl
+++ b/docsite.erl
@@ -1,6 +1,6 @@
#!/usr/bin/env escript
%% -*- erlang -*-
-%%! -smp disable
+%%!
%% This script takes the EDoc output page, and tries to bring them to
%% a more modern format suitable for a recon site.
%% Run with `escript docsite.erl' or as `./docsite.erl'. The script
diff --git a/rebar.config b/rebar.config
new file mode 100644
index 0000000..a417350
--- /dev/null
+++ b/rebar.config
@@ -0,0 +1,5 @@
+{profiles, [
+ {test, [
+ {erl_opts, [nowarn_export_all]}
+ ]}
+]}.
diff --git a/src/recon.app.src b/src/recon.app.src
index 8f0dcd6..b6da751 100644
--- a/src/recon.app.src
+++ b/src/recon.app.src
@@ -1,6 +1,6 @@
{application, recon,
[{description, "Diagnostic tools for production use"},
- {vsn, "2.3.5"},
+ {vsn, "2.3.6"},
{modules, [recon, recon_alloc, recon_lib, recon_trace]},
{registered, []},
{applications, [kernel, stdlib]},
diff --git a/src/recon.erl b/src/recon.erl
index 9b43ce0..c085cb0 100644
--- a/src/recon.erl
+++ b/src/recon.erl
@@ -376,7 +376,8 @@
%%
%% Absolutes are values that keep changing with time, and are useful to know
%% about as a datapoint: process count, size of the run queue, error_logger
-%% queue length, and the memory of the node (total, processes, atoms, binaries,
+%% queue length in versions before OTP-21 or those thar run it explicitely,
+%% and the memory of the node (total, processes, atoms, binaries,
%% and ets tables).
%%
%% Increments are values that are mostly useful when compared to a previous
@@ -392,6 +393,10 @@
Stats :: {[Absolutes::{atom(),term()}],
[Increments::{atom(),term()}]}.
node_stats(N, Interval, FoldFun, Init) ->
+ Logger = case whereis(error_logger) of
+ undefined -> logger;
+ _ -> error_logger
+ end,
%% Turn on scheduler wall time if it wasn't there already
FormerFlag = erlang:system_flag(scheduler_wall_time, true),
%% Stats is an ugly fun, but it does its thing.
@@ -399,7 +404,14 @@
%% Absolutes
ProcC = erlang:system_info(process_count),
RunQ = erlang:statistics(run_queue),
- {_,LogQ} = process_info(whereis(error_logger), message_queue_len),
+ LogQ = case Logger of
+ error_logger ->
+ {_,LogQLen} = process_info(whereis(error_logger),
+ message_queue_len),
+ LogQLen;
+ _ ->
+ undefined
+ end,
%% Mem (Absolutes)
Mem = erlang:memory(),
Tot = proplists:get_value(total, Mem),
@@ -418,8 +430,9 @@
SchedWallNew = erlang:statistics(scheduler_wall_time),
SchedUsage = recon_lib:scheduler_usage_diff(SchedWall, SchedWallNew),
%% Stats Results
- {{[{process_count,ProcC}, {run_queue,RunQ},
- {error_logger_queue_len,LogQ}, {memory_total,Tot},
+ {{[{process_count,ProcC}, {run_queue,RunQ}] ++
+ [{error_logger_queue_len,LogQ} || LogQ =/= undefined] ++
+ [{memory_total,Tot},
{memory_procs,ProcM}, {memory_atoms,Atom},
{memory_bin,Bin}, {memory_ets,Ets}],
[{bytes_in,BytesIn}, {bytes_out,BytesOut},
@@ -511,6 +524,9 @@
sctp() -> recon_lib:port_list(name, "sctp_inet").
%% @doc returns a list of all file handles open on the node.
+%% @deprecated Starting with OTP-21, files are implemented as NIFs
+%% and can no longer be listed. This function returns an empty list
+%% in such a case.
-spec files() -> [port()].
files() -> recon_lib:port_list(name, "efile").
diff --git a/test/recon_SUITE.erl b/test/recon_SUITE.erl
index 3122157..6cf63fb 100644
--- a/test/recon_SUITE.erl
+++ b/test/recon_SUITE.erl
@@ -7,6 +7,16 @@
-include_lib("eunit/include/eunit.hrl").
-compile(export_all).
+-ifdef(OTP_RELEASE).
+-define(FILES_IMPL, nif).
+-define(ERROR_LOGGER_MATCH(_), ).
+-define(REDUCTIONS_MATCH(X), X).
+-else.
+-define(FILES_IMPL, port).
+-define(ERROR_LOGGER_MATCH(X), X,).
+-define(REDUCTIONS_MATCH(_), []).
+-endif.
+
all() -> [{group,info}, proc_count, proc_window, bin_leak,
node_stats_list, get_state, source, tcp, udp, files, port_types,
inet_count, inet_window, binary_memory, scheduler_usage].
@@ -29,6 +39,17 @@
end_per_group(info, Config) ->
exit(?config(pid, Config), kill).
+init_per_testcase(files, Config) ->
+ case ?FILES_IMPL of
+ nif -> {skip, "files can no longer be listed in OTP-21 and above"};
+ port -> Config
+ end;
+init_per_testcase(_, Config) ->
+ Config.
+
+end_per_testcase(_, Config) ->
+ Config.
+
%%%%%%%%%%%%%
%%% TESTS %%%
%%%%%%%%%%%%%
@@ -36,15 +57,18 @@
info3(Config) ->
Pid = ?config(pid, Config),
{A,B,C} = pid_to_triple(Pid),
- Info = recon:info(Pid),
- Info = recon:info(A,B,C).
-
+ Info1 = recon:info(Pid),
+ Info2 = recon:info(A,B,C),
+ %% Reduction count is unreliable
+ ?assertMatch(?REDUCTIONS_MATCH(
+ [{work, [{reductions,_}]}, {work, [{reductions,_}]}]
+ ), (Info1 -- Info2) ++ (Info2 -- Info1)).
info4(Config) ->
Pid = ?config(pid, Config),
Keys = [meta, signals, location, memory_used, work,
- links, monitors, reductions, messages,
- [links, monitors, reductions, messages]],
+ links, monitors, messages,
+ [links, monitors, messages]],
{A,B,C} = pid_to_triple(Pid),
lists:map(fun(Key) ->
Info = recon:info(Pid, Key),
@@ -67,11 +91,25 @@
undefined == proplists:get_value(K, proplists:get_value(Cat,Info))
]),
register(info1, Pid),
- Res = recon:info(info1),
- Res = recon:info(whereis(info1)),
- Res = recon:info(pid_to_triple(whereis(info1))),
- Res = recon:info(lists:flatten(io_lib:format("~p",[Pid]))),
- unregister(info1).
+ Res1 = recon:info(info1),
+ Res2 = recon:info(whereis(info1)),
+ Res3 = recon:info(pid_to_triple(whereis(info1))),
+ Res4 = recon:info(lists:flatten(io_lib:format("~p",[Pid]))),
+ unregister(info1),
+ L = lists:usort(Res1 ++ Res2 ++ Res3 ++ Res4),
+ ?assertMatch(?REDUCTIONS_MATCH([{work,[{reductions,_}]},
+ {work,[{reductions,_}]},
+ {work,[{reductions,_}]}]), L -- Res1),
+ ?assertMatch(?REDUCTIONS_MATCH([{work,[{reductions,_}]},
+ {work,[{reductions,_}]},
+ {work,[{reductions,_}]}]), L -- Res2),
+ ?assertMatch(?REDUCTIONS_MATCH([{work,[{reductions,_}]},
+ {work,[{reductions,_}]},
+ {work,[{reductions,_}]}]), L -- Res3),
+ ?assertMatch(?REDUCTIONS_MATCH([{work,[{reductions,_}]},
+ {work,[{reductions,_}]},
+ {work,[{reductions,_}]}]), L -- Res4),
+ ok.
info2(Config) ->
Pid = ?config(pid, Config),
@@ -82,7 +120,7 @@
total_heap_size, garbage_collection]},
{work, [reductions]}],
%% registered_name is special -- only returns
- %% [] when passed through by info/2. Because we pass terms through
+ %% [] when passed through by info/2. Because we pass terms through
%% according to the docs, we have to respect that
[] = recon:info(Pid, registered_name),
%% Register to get the expected tuple
@@ -138,7 +176,7 @@
Res = recon:node_stats_list(2,100),
2 = length([1 || {[{process_count,_},
{run_queue,_},
- {error_logger_queue_len,_},
+ ?ERROR_LOGGER_MATCH({error_logger_queue_len,_})
{memory_total,_},
{memory_procs,_},
{memory_atoms,_},