Merge pull request #7333 from thalesmg/telemetry-revamp1

Telemetry revamp part 1

- Remove obsolete `active_modules`.
- Don't use `mnesia(boot)` callback for indirect initialization.
- Add build info and vm specs to the exported data.
This commit is contained in:
Thales Macedo Garitezi 2022-03-22 09:03:13 -03:00 committed by GitHub
commit 650683ac19
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 98 additions and 30 deletions

View File

@ -18,7 +18,7 @@
-define(TELEMETRY_URL, "https://telemetry.emqx.io/api/telemetry").
%% Interval for reporting telemetry data, Default: 7d
-define(REPORT_INTERVAR, 604800).
-define(REPORT_INTERVAL, 604800).
-define(API_TAG_MQTT, [<<"mqtt">>]).
-define(API_SCHEMA_MODULE, emqx_modules_schema).

View File

@ -26,11 +26,6 @@
-include("emqx_modules.hrl").
%% Mnesia bootstrap
-export([mnesia/1]).
-boot_mnesia({mnesia, [boot]}).
-export([ start_link/0
, stop/0
]).
@ -56,6 +51,9 @@
-export([official_version/1]).
%% internal export
-export([read_raw_build_info/0]).
-ifdef(TEST).
-compile(export_all).
-compile(nowarn_export_all).
@ -86,22 +84,16 @@
-define(TELEMETRY, emqx_telemetry).
%%--------------------------------------------------------------------
%% Mnesia bootstrap
%% API
%%--------------------------------------------------------------------
mnesia(boot) ->
start_link() ->
ok = mria:create_table(?TELEMETRY,
[{type, set},
{storage, disc_copies},
{local_content, true},
{record_name, telemetry},
{attributes, record_info(fields, telemetry)}]).
%%--------------------------------------------------------------------
%% API
%%--------------------------------------------------------------------
start_link() ->
{attributes, record_info(fields, telemetry)}]),
_ = mria:wait_for_tables([?TELEMETRY]),
Opts = emqx:get_config([telemetry], #{}),
gen_server:start_link({local, ?MODULE}, ?MODULE, [Opts], []).
@ -145,7 +137,7 @@ init(_Opts) ->
UUID
end,
{ok, #state{url = ?TELEMETRY_URL,
report_interval = timer:seconds(?REPORT_INTERVAR),
report_interval = timer:seconds(?REPORT_INTERVAL),
uuid = UUID1}}.
handle_call(enable, _From, State) ->
@ -272,10 +264,6 @@ active_plugins() ->
end
end, [], emqx_plugins:list()).
active_modules() ->
[].
% emqx_modules:list().
num_clients() ->
emqx_stats:getstat('connections.max').
@ -308,10 +296,11 @@ get_telemetry(#state{uuid = UUID}) ->
{uuid, UUID},
{nodes_uuid, nodes_uuid()},
{active_plugins, active_plugins()},
{active_modules, active_modules()},
{num_clients, num_clients()},
{messages_received, messages_received()},
{messages_sent, messages_sent()}].
{messages_sent, messages_sent()},
{build_info, build_info()},
{vm_specs, vm_specs()}].
report_telemetry(State = #state{url = URL}) ->
Data = get_telemetry(State),
@ -325,7 +314,9 @@ report_telemetry(State = #state{url = URL}) ->
end.
httpc_request(Method, URL, Headers, Body) ->
httpc:request(Method, {URL, Headers, "application/json", Body}, [], []).
HTTPOptions = [{timeout, 10_000}],
Options = [],
httpc:request(Method, {URL, Headers, "application/json", Body}, HTTPOptions, Options).
parse_os_release(FileContent) ->
lists:foldl(fun(Line, Acc) ->
@ -340,6 +331,27 @@ parse_os_release(FileContent) ->
end,
[], string:tokens(binary:bin_to_list(FileContent), "\n")).
build_info() ->
case ?MODULE:read_raw_build_info() of
{ok, BuildInfo} ->
%% running on EMQX release
{ok, Fields} = hocon:binary(BuildInfo),
Fields;
_ ->
#{}
end.
read_raw_build_info() ->
Filename = filename:join([code:root_dir(), "releases",
emqx_app:get_release(), "BUILD_INFO"]),
file:read_file(Filename).
vm_specs() ->
SysMemData = memsup:get_system_memory_data(),
[ {num_cpus, erlang:system_info(logical_processors)}
, {total_memory, proplists:get_value(available_memory, SysMemData)}
].
bin(L) when is_list(L) ->
list_to_binary(L);
bin(A) when is_atom(A) ->

View File

@ -28,14 +28,53 @@
all() -> emqx_common_test_helpers:all(?MODULE).
init_per_suite(Config) ->
ok = mria:start(),
ok = emqx_telemetry:mnesia(boot),
snabbkaffe:fix_ct_logging(),
emqx_common_test_helpers:start_apps([emqx_modules]),
Config.
end_per_suite(_Config) ->
emqx_common_test_helpers:stop_apps([emqx_modules]).
init_per_testcase(t_get_telemetry, Config) ->
DataDir = ?config(data_dir, Config),
TestPID = self(),
ok = meck:new(httpc, [non_strict, passthrough, no_history, no_link]),
ok = meck:expect(httpc, request, fun(Method, URL, Headers, Body) ->
TestPID ! {request, Method, URL, Headers, Body}
end),
ok = meck:new(emqx_telemetry, [non_strict, passthrough, no_history, no_link]),
ok = meck:expect(emqx_telemetry, read_raw_build_info,
fun() ->
{ok, Path} = file:read_link(filename:join([DataDir, "BUILD_INFO"])),
{ok, Template} = file:read_file(Path),
Vars0 = [ {build_info_arch, "arch"}
, {build_info_wordsize, "64"}
, {build_info_os, "os"}
, {build_info_erlang, "erlang"}
, {build_info_elixir, "elixir"}
, {build_info_relform, "relform"}
],
Vars = [{atom_to_list(K), iolist_to_binary(V)}
|| {K, V} <- Vars0],
Rendered = bbmustache:render(Template, Vars),
{ok, Rendered}
end),
Config;
init_per_testcase(_Testcase, Config) ->
TestPID = self(),
ok = meck:new(httpc, [non_strict, passthrough, no_history, no_link]),
ok = meck:expect(httpc, request, fun(Method, URL, Headers, Body) ->
TestPID ! {request, Method, URL, Headers, Body}
end),
Config.
end_per_testcase(t_get_telemetry, _Config) ->
meck:unload([httpc, emqx_telemetry]),
ok;
end_per_testcase(_Testcase, _Config) ->
meck:unload([httpc]),
ok.
t_uuid(_) ->
UUID = emqx_telemetry:generate_uuid(),
Parts = binary:split(UUID, <<"-">>, [global, trim]),
@ -65,13 +104,29 @@ t_official_version(_) ->
true = emqx_telemetry:official_version("1.1-rc.1"),
false = emqx_telemetry:official_version("1.1-alpha.a").
t_get_telemetry(_) ->
t_get_telemetry(_Config) ->
{ok, TelemetryData} = emqx_telemetry:get_telemetry(),
OTPVersion = bin(erlang:system_info(otp_release)),
?assertEqual(OTPVersion, get_value(otp_version, TelemetryData)),
{ok, UUID} = emqx_telemetry:get_uuid(),
?assertEqual(UUID, get_value(uuid, TelemetryData)),
?assertEqual(0, get_value(num_clients, TelemetryData)).
?assertEqual(0, get_value(num_clients, TelemetryData)),
BuildInfo = get_value(build_info, TelemetryData),
?assertMatch(
#{ <<"arch">> := <<_/binary>>
, <<"elixir">> := <<_/binary>>
, <<"erlang">> := <<_/binary>>
, <<"os">> := <<_/binary>>
, <<"relform">> := <<_/binary>>
, <<"wordsize">> := Wordsize
} when is_integer(Wordsize),
BuildInfo),
VMSpecs = get_value(vm_specs, TelemetryData),
?assert(is_integer(get_value(num_cpus, VMSpecs))),
?assert(0 =< get_value(num_cpus, VMSpecs)),
?assert(is_integer(get_value(total_memory, VMSpecs))),
?assert(0 =< get_value(total_memory, VMSpecs)),
ok.
t_enable(_) ->
ok = meck:new(emqx_telemetry, [non_strict, passthrough, no_history, no_link]),

View File

@ -0,0 +1 @@
../../../../rel/BUILD_INFO