diff --git a/apps/emqx_modules/include/emqx_modules.hrl b/apps/emqx_modules/include/emqx_modules.hrl index 8d505969c..244b4c0cf 100644 --- a/apps/emqx_modules/include/emqx_modules.hrl +++ b/apps/emqx_modules/include/emqx_modules.hrl @@ -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). diff --git a/apps/emqx_modules/src/emqx_telemetry.erl b/apps/emqx_modules/src/emqx_telemetry.erl index 3da9a6d9d..6fdccc3d6 100644 --- a/apps/emqx_modules/src/emqx_telemetry.erl +++ b/apps/emqx_modules/src/emqx_telemetry.erl @@ -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). @@ -85,23 +83,17 @@ -define(TELEMETRY, emqx_telemetry). -%%-------------------------------------------------------------------- -%% Mnesia bootstrap -%%-------------------------------------------------------------------- - -mnesia(boot) -> - ok = mria:create_table(?TELEMETRY, - [{type, set}, - {storage, disc_copies}, - {local_content, true}, - {record_name, telemetry}, - {attributes, record_info(fields, telemetry)}]). - %%-------------------------------------------------------------------- %% API %%-------------------------------------------------------------------- start_link() -> + ok = mria:create_table(?TELEMETRY, + [{type, set}, + {storage, disc_copies}, + {local_content, true}, + {record_name, telemetry}, + {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) -> diff --git a/apps/emqx_modules/test/emqx_telemetry_SUITE.erl b/apps/emqx_modules/test/emqx_telemetry_SUITE.erl index 43c262989..efb258853 100644 --- a/apps/emqx_modules/test/emqx_telemetry_SUITE.erl +++ b/apps/emqx_modules/test/emqx_telemetry_SUITE.erl @@ -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]), diff --git a/apps/emqx_modules/test/emqx_telemetry_SUITE_data/BUILD_INFO b/apps/emqx_modules/test/emqx_telemetry_SUITE_data/BUILD_INFO new file mode 120000 index 000000000..adb156dee --- /dev/null +++ b/apps/emqx_modules/test/emqx_telemetry_SUITE_data/BUILD_INFO @@ -0,0 +1 @@ +../../../../rel/BUILD_INFO \ No newline at end of file