-- -- (C) 2020-22 - ntop.org -- -- -- This module implements an internet download bandwidth monitor. -- local json = require("dkjson") local ts_utils = require("ts_utils_core") local do_trace = false local collected_results = {} -- ################################################################# -- The function called periodically to send the host probes. -- hosts contains the list of hosts to probe, The table keys are -- the hosts identifiers, whereas the table values contain host information -- see (am_utils.key2host for the details on such format). local function run_speedtest(hosts, granularity) local rsp if(trace) then print("[run_speedtest] "..hosts.." ["..granularity.."]\n") end rsp = ntop.speedtest() if(not rsp) then return end if do_trace then tprint(hosts) end if do_trace then print(rsp) end rsp = json.decode(rsp) if(not rsp) then return end -- NOTE: force_host is set, only a single host will be available for key, host in pairs(hosts) do if(rsp["download.speed"] ~= nil) then local isp = nil local download_mbit = rsp["download.speed"] if(type(rsp["client.isp"] == "string")) then isp = noHtml(rsp["client.isp"]) end collected_results[key] = { value = download_mbit, resolved_addr = isp, } end if(rsp["upload.speed"]) then ts_utils.append("am_host:upload_" .. granularity, { ifid = getSystemInterfaceId(), speed = rsp["upload.speed"] * 1000000, host = host.host, }) end if(rsp["server.latency"]) then ts_utils.append("am_host:latency_" .. granularity, { ifid = getSystemInterfaceId(), latency = rsp["server.latency"], host = host.host, }) end end end -- ################################################################# -- The function responsible for collecting the results. -- It must return a table containing a list of hosts along with their retrieved -- measurement. The keys of the table are the host key. The values have the following format: -- table -- resolved_addr: (optional) the resolved IP address of the host -- value: (optional) the measurement numeric value. If unspecified, the host is still considered unreachable. local function collect_speedtest(granularity) if(trace) then print("[collect_speedtest] called\n") end return(collected_results) end -- ################################################################# -- This function checks whether the speedtest support has been compiled and available local function check_speedtest_support() if(trace) then print("[check_speedtest_support] called\n") end return ntop.hasSpeedtestSupport() end -- ################################################################# return { -- Defines a list of measurements implemented by this script. -- The probing logic is implemented into the check() and collect_results(). -- -- Here is how the probing occurs: -- 1. The check function is called with the list of hosts to probe. Ideally this -- call should not block (e.g. should not wait for the results) -- 2. The active_monitoring.lua code sleeps for some seconds -- 3. The collect_results function is called. This should retrieve the results -- for the hosts checked in the check() function and return the results. -- -- The alerts for non-responding hosts and the Active Monitoring timeseries are automatically -- generated by active_monitoring.lua . The timeseries are saved in the following schemas: -- "am_host:val_min", "am_host:val_5mins", "am_host:val_hour". measurements = { { -- The unique key for the measurement key = "speedtest", -- The localization string for this measurement i18n_label = "active_monitoring_stats.speedtest", -- The function called periodically to send the host probes check = run_speedtest, -- The function responsible for collecting the results collect_results = collect_speedtest, -- The granularities allowed for the probe. See supported_granularities in am_utils.lua granularities = { "hour" }, -- The localization string for the measurement unit (e.g. "ms", "Mbits") i18n_unit = "field_units.mbits", -- The localization string for the Jitter unit (e.g. "ms", "Mbits") i18n_jitter_unit = nil, -- The localization string for the Active Monitoring timeseries menu entry i18n_am_ts_label = "active_monitoring_stats.download_speed", -- The localization string for the Active Monitoring metric in the chart i18n_am_ts_metric = "active_monitoring_stats.download_speed", -- The operator to use when comparing the measurement with the threshold, "gt" for ">" or "lt" for "<". operator = "lt", -- If set, indicates a maximum threshold value max_threshold = 10000, -- If set, indicates the default threshold value default_threshold = nil, -- A list of additional timeseries (the am_host:val_* is always shown) to show in the charts. -- See https://www.ntop.org/guides/ntopng/api/timeseries/adding_new_timeseries.html#charting-new-metrics . additional_timeseries = {{ schema="am_host:upload", label=i18n("active_monitoring_stats.upload_speed"), metrics_labels = { i18n("active_monitoring_stats.upload_speed"), }, value_formatter = {"NtopUtils.fbits", "NtopUtils.fbits"}, show_unreachable = true, -- Show the unreachable host status as a red line }, { schema="am_host:latency", label=i18n("flow_details.round_trip_time"), metrics_labels = { i18n("graphs.num_ms_rtt"), }, value_formatter = {"NtopUtils.fmillis", "NtopUtils.fmillis"}, show_unreachable = true, -- Show the unreachable host status as a red line }}, -- Js function to call to format the measurement value. See ntopng_utils.js . value_js_formatter = "NtopUtils.fbits", -- The raw measurement value is multiplied by this factor before being written into the chart chart_scaling_value = 1000000, -- A list of additional notes (localization strings) to show into the timeseries charts i18n_chart_notes = {}, -- If set, the user cannot change the host force_host = "speedtest.net", -- An alternative localization string for the unrachable alert message unreachable_alert_i18n = "alert_messages.speedtest_failed", }, }, setup = check_speedtest_support, }