ntopng/http_src/utilities/metrics-manager.js
2025-07-21 13:05:03 +02:00

406 lines
16 KiB
JavaScript

/**
(C) 2022 - ntop.org
*/
import { ntopng_utility, ntopng_url_manager } from "../services/context/ntopng_globals_services.js";
import metricsConsts from "../constants/metrics-consts.js"
import NtopUtils from "./ntop-utils.js";
const set_timeseries_groups_in_url = (timeseries_groups) => {
let params_timeseries_groups = [];
timeseries_groups.forEach((ts_group) => {
let param = get_ts_group_url_param(ts_group);
params_timeseries_groups.push(param);
});
let url_timeseries_groups = params_timeseries_groups.join(";;");
ntopng_url_manager.set_key_to_url("timeseries_groups", url_timeseries_groups);
};
function get_ts_group_url_param(ts_group) {
let timeseries = [];
ts_group.timeseries.forEach((ts) => {
timeseries.push(`${ts.id}=${ts.raw}:${ts.past}:${ts.avg}:${ts.perc_95}`);
});
let metric_schema_query = ts_group.metric.schema;
if (ts_group.metric.query != null) {
metric_schema_query = `${metric_schema_query}+${ts_group.metric.query}`;
}
let timeseries_param = timeseries.join("|");
let source_value_array_query = ts_group.source_array.map((source) => source.value).join("+");
let param = `${ts_group.source_type.id};${source_value_array_query};${metric_schema_query};${timeseries_param}`;
return param;
}
const get_timeseries_groups_from_url = async (http_prefix, url_timeseries_groups) => {
if (url_timeseries_groups == null) {
url_timeseries_groups = ntopng_url_manager.get_url_entry("timeseries_groups");
}
if (url_timeseries_groups == null || url_timeseries_groups == "") {
return null;
}
let groups = url_timeseries_groups.split(";;");
groups.map(async (g) => {
let ts_group = await get_url_param_from_ts_group(g);
return ts_group;
});
let timeseries_groups = Promise.all(groups.map(async (g) => {
let ts_group = await get_url_param_from_ts_group(g);
return ts_group;
}));
return timeseries_groups;
};
const get_ts_group = (source_type, source_array, metric, customized_ts) => {
let ts_config = {
raw: true,
past: true, /* By default enable the past serie */
avg: false,
perc_95: false,
}
if (customized_ts && customized_ts.raw != null) ts_config.raw = customized_ts.raw;
if (customized_ts && customized_ts.past != null) ts_config.past = customized_ts.past;
if (customized_ts && customized_ts.avg != null) ts_config.avg = customized_ts.avg;
if (customized_ts && customized_ts.perc_95 != null) ts_config.perc_95 = customized_ts.perc_95;
let id = get_ts_group_id(source_type, source_array, metric);
let timeseries = [];
for (let key in metric.timeseries) {
let ts = metric.timeseries[key];
ts_config.id = key;
ts_config.label = ts.label;
timeseries.push(ts_config);
}
return {
id, source_type, source_array, metric, timeseries,
};
};
const get_default_timeseries_groups = async (http_prefix, metric_ts_schema, metric_query) => {
let source_type = get_current_page_source_type();
let source_array = await get_default_source_array(http_prefix, source_type);
let metrics = await get_metrics(http_prefix, source_type, source_array);
let metric = get_default_metric(metrics, metric_ts_schema, metric_query);
let ts_group = get_ts_group(source_type, source_array, metric);
return [ts_group];
};
async function get_url_param_from_ts_group(ts_group_url_param) {
let g = ts_group_url_param;
let info = g.split(";");
let source_type_id = info[0];
let source_value_query = info[1];
let source_value_array = source_value_query.split("+");
let metric_schema_query = info[2];
let metric_schema_query_array = metric_schema_query.split("+");
if (metric_schema_query_array.length < 2) {
metric_schema_query_array.push(null);
}
let timeseries_url = info[3];
let source_type = get_source_type_from_id(source_type_id);
let source_array = await get_source_array_from_value_array(http_prefix, source_type, source_value_array);
let metric = await get_metric_from_schema(http_prefix, source_type, source_array, metric_schema_query_array[0], metric_schema_query_array[1]);
let timeseries = get_timeseries(timeseries_url, metric);
return {
id: get_ts_group_id(source_type, source_array, metric),
source_type,
source_array,
metric,
timeseries,
};
}
const get_ts_group_id = (source_type, source_array, metric, enable_source_def_value_dict, set_source_type_id_group) => {
let metric_id = "";
if (metric != null) {
metric_id = metric.schema;
if (metric.query != null) {
metric_id = `${metric_id} - ${metric.query}`;
}
}
let source_def_array = source_type.source_def_array;
let source_value_array = source_array.map((source, i) => {
let source_def_value = source_def_array[i].value;
if (enable_source_def_value_dict != null && !enable_source_def_value_dict[source_def_value]) { return null; }
return source.value;
}).filter((s) => s != null).join("_");
let source_type_id = source_type.id;
if (set_source_type_id_group && source_type.id_group != null) {
source_type_id = source_type.id_group;
}
return `${source_type_id} - ${source_value_array} - ${metric_id}`;
};
function get_timeseries(timeseries_url, metric) {
let ts_url_array = timeseries_url.split("|");
let r = /(.+)=(.+):(.+):(.+):(.+)/;
let timeseries = [];
ts_url_array.forEach((ts_url) => {
let values = r.exec(ts_url);
if (values.length > 0) {
let id = values[1];
let label = metric.timeseries[id].label;
let raw = JSON.parse(values[2]);
let past = JSON.parse(values[3]);
let avg = JSON.parse(values[4]);
let perc_95 = JSON.parse(values[5]);
timeseries.push({
id, label, raw, past, avg, perc_95,
});
}
});
return timeseries;
}
const ui_types = metricsConsts.ui_types;
// dictionary of functions to convert an element of source_url rest result to a source ({label, value })
const sources_url_el_to_source = metricsConsts.sources_url_el_to_source;
const sources_types = metricsConsts.sources_types;
const sources_types_tables = metricsConsts.sources_types_tables;
const get_source_type_from_id = (source_type_id) => {
return sources_types.find((st) => st.id == source_type_id);
};
const get_default_source_array = async (http_prefix, source_type) => {
let source_value_array = get_default_source_value_array(source_type);
let source_array = await get_source_array_from_value_array(http_prefix, source_type, source_value_array);
return source_array;
};
async function get_source_array_from_value_dict(http_prefix, source_type, source_value_dict) {
let source_value_array = source_type.source_def_array.map((source_def) => source_value_dict[source_def.value]);
let source_array = await get_source_array_from_value_array(http_prefix, source_type, source_value_array);
return source_array;
}
const get_source_array_from_value_array = async (http_prefix, source_type, source_value_array) => {
if (source_type == null) {
source_type = get_current_page_source_type();
}
let source_array = [];
let source;
for (let i = 0; i < source_value_array.length; i++) {
let source_value = source_value_array[i];
let source_def = source_type.source_def_array[i];
if (source_def.sources_url || source_def.sources_function) {
let sources = [];
sources = await get_sources(http_prefix, source_type.id, source_def, source_value_array);
source = sources.find((s) => s.value == source_value);
if (source == null) {
source = sources[0];
}
} else {
source = { label: source_value, value: source_value };
}
source_array.push(source);
}
return source_array;
};
let cache_sources = {};
function get_source_def_key(id, source_def, selected_source_value_array) {
let key = `${id}_${source_def.value}`;
if (!source_def.refresh_on_sources_change) {
return key;
}
const value_array = selected_source_value_array.join("_");
key = `${key}_${value_array}`;
return key;
}
const get_sources = async (http_prefix, id, source_def, selected_source_value_array) => {
let key = get_source_def_key(id, source_def, selected_source_value_array);
if (cache_sources[key] == null) {
if (source_def.sources_url) {
let url = `${http_prefix}/${source_def.sources_url}`;
cache_sources[key] = ntopng_utility.http_request(url);
} else if (source_def.sources_function) {
cache_sources[key] = source_def.sources_function(selected_source_value_array);
} else {
return [];
}
}
let sources = await cache_sources[key];
if (source_def.sources_url) {
let f_map_source_element = sources_url_el_to_source[source_def.value_map_sources_res];
if (f_map_source_element == null) {
f_map_source_element = sources_url_el_to_source[source_def.value];
}
if (f_map_source_element == null) {
throw `:Error: metrics-manager.js, missing sources_url_to_source ${source_def.value} key`;
}
sources = sources.map((s) => f_map_source_element(s));
}
return sources.sort(NtopUtils.sortAlphabetically);
};
function set_source_value_object_in_url(source_type, source_value_object) {
source_type.source_def_array.forEach((source_def) => {
let source_value = source_value_object[source_def.value];
if (source_value == null) { return; }
if (source_def.f_set_value_url != null) {
source_def.f_set_value_url();
} else if (source_def.value_url != null) {
ntopng_url_manager.set_key_to_url(source_def.value_url, source_value);
} else {
ntopng_url_manager.set_key_to_url(source_def.value, source_value);
}
});
}
const get_default_source_value_array = (source_type) => {
if (source_type == null) {
source_type = get_current_page_source_type();
}
let source_value_array = source_type.source_def_array.map((source_def) => {
if (source_def.f_get_value_url != null) {
return source_def.f_get_value_url();
}
let source_def_value = source_def.value_url;
if (source_def_value == null) {
source_def_value = source_def.value;
}
let source_value = ntopng_url_manager.get_url_entry(source_def_value);
return source_value;
});
return source_value_array;
};
function get_metrics_url(http_prefix, source_type, source_array, epoch) {
let params = source_type.source_def_array.map((source_def, i) => {
return `${source_def.value}=${source_array[i].value}`;
}).join("&");
let epoch_string = ``;
if (epoch != null) {
epoch_string = `epoch_end=${epoch.epoch_end}&epoch_begin=${epoch.epoch_begin}`
}
let url = `${http_prefix}/lua/rest/v2/get/timeseries/type/consts.lua?query=${source_type.query}&${params}&${epoch_string}`;
return url;
}
function get_metric_key(source_type, source_array) {
let source_array_key = source_array.map((source) => source.value).join("_");
let key = `${source_type.id}_${source_array_key}`;
return key;
}
let cache_metrics = {};
let last_metrics_time_interval = null;
const get_metrics = async (http_prefix, source_type, source_array, status) => {
let epoch_begin = status?.epoch_begin || ntopng_url_manager.get_url_entry("epoch_begin");
let epoch_end = status?.epoch_end || ntopng_url_manager.get_url_entry("epoch_end");
let current_last_metrics_time_interval = `${epoch_begin}_${epoch_end}`;
if (source_type == null) {
source_type = get_current_page_source_type();
}
if (source_array == null) {
source_array = await get_default_source_array(http_prefix, source_type);
}
// let url = `${http_prefix}/lua/rest/v2/get/timeseries/type/consts.lua?query=${source_type.value}`;
let url = get_metrics_url(http_prefix, source_type, source_array, { epoch_begin: epoch_begin, epoch_end: epoch_end });
let key = get_metric_key(source_type, source_array);
if (current_last_metrics_time_interval != last_metrics_time_interval) {
cache_metrics[key] = null;
last_metrics_time_interval = current_last_metrics_time_interval;
}
if (cache_metrics[key] == null) {
cache_metrics[key] = ntopng_utility.http_request(url);
}
let metrics = await cache_metrics[key];
if (metrics == null || metrics.length == 0) { return [{}]; }
if (metrics.some((m) => m.default_visible == true) == false) {
metrics[0].default_visible = true;
}
return ntopng_utility.clone(metrics);
};
const get_current_page_source_type = () => {
let pathname = window.location.pathname;
for (let i = 0; i < sources_types.length; i += 1) {
let regExp = new RegExp(sources_types[i].regex_page_url);
if (regExp.test(pathname) == true) {
return sources_types[i];
}
}
throw `source_type not found for ${pathname}`;
};
const get_metric_from_schema = async (http_prefix, source_type, source_array, metric_schema, metric_query, status) => {
let metrics = await get_metrics(http_prefix, source_type, source_array, status);
if (metric_schema === 'top:iface:ndpi') {
return metrics.find((m) => m.schema == metric_schema && m.query == metric_query) ||
metrics.find((m) => m.schema == 'top:iface:ndpi_full' && m.query == metric_query)
}
const metric = metrics.find((m) => m.schema == metric_schema && m.query == metric_query);
return metric
};
const get_metric_query_from_ts_query = (ts_query, source_type) => {
if (source_type == null) {
source_type = get_current_page_source_type();
}
let source_def_dict = {};
source_type.source_def_array.forEach((s_def) => source_def_dict[s_def.value] = true);
let metric_query = null
let ts_query_array = ts_query.split(",");
for (let i = 0; i < ts_query_array.length; i += 1) {
let ts_val_key = ts_query_array[i].split(":")[0];
if (source_def_dict[ts_val_key] == null) {
if (!metric_query) { metric_query = `${ts_query_array[i]}` }
else { metric_query = `${metric_query},${ts_query_array[i]}` }
}
}
return metric_query;
};
const get_default_metric = (metrics, metric_ts_schema, metric_query) => {
let default_metric;
if (metric_ts_schema != null) {
default_metric = metrics.find((m) => m.schema == metric_ts_schema && (metric_query == null || m.query == metric_query));
}
if (default_metric == null) {
default_metric = metrics.find((m) => m.default_visible == true);
}
if (default_metric != null) {
return default_metric;
}
return metrics[0];
};
const metricsManager = function () {
return {
set_timeseries_groups_in_url,
get_timeseries_groups_from_url,
get_default_timeseries_groups,
get_ts_group,
get_ts_group_id,
sources_types,
sources_types_tables,
get_source_type_from_id,
get_current_page_source_type,
get_sources,
get_default_source_array,
get_source_array_from_value_dict,
get_source_array_from_value_array,
get_default_source_value_array,
get_metrics,
get_metric_from_schema,
get_metric_query_from_ts_query,
get_default_metric,
set_source_value_object_in_url,
ui_types,
};
}();
export default metricsManager;