Commit ed6633f7 authored by Alessio Netti's avatar Alessio Netti

Grafana: improvements to smoothing

- Smoothing is not hardcoded anymore and the server picks automatically
the best smoother based on the available sensor operations
- Requires a "smootherRegex" configuration parameter to identify the
smoothing operations
parent 433a196c
......@@ -54,6 +54,8 @@ void Configuration::readAdditionalBlocks(boost::property_tree::iptree& cfg) {
hierarchySettings.regex = global.second.data();
} else if (boost::iequals(global.first, "filter")) {
hierarchySettings.filter = global.second.data();
} else if (boost::iequals(global.first, "smootherRegex")) {
hierarchySettings.smootherRegex = global.second.data();
} else {
LOG(warning) << " Value \"" << global.first << "\" not recognized. Omitting";
}
......
......@@ -58,6 +58,7 @@ typedef struct {
std::string separator;
std::string regex;
std::string filter;
std::string smootherRegex;
} hierarchySettings_t;
/**
......@@ -98,6 +99,7 @@ public:
hierarchySettings.separator = "";
hierarchySettings.regex = "";
hierarchySettings.filter = "";
hierarchySettings.smootherRegex = "";
}
virtual ~Configuration() {}
......
......@@ -64,6 +64,7 @@ The configuration specifies various settings for grafanaserver in general. Pleas
| regex | Regular expression representing the full hierarchy of sensor names, where each level is separated by a provided "separator" character. If left empty, '/' are considered default separators of the different levels composing the name (e.g., /system/rack/chassis/node/sensor). If the published sensor names are different from their corresponding MQTT topics, the provided regex needs to reflect it. For example, the regex "mySystem.,rack\\d{2}.,chassis\\d{2}.,server\\d{2}" could represent a custom sensor name such as "mySystem.rack01.chassis03.server10" (see the documentation of the Sensor Navigator for more details). However, it is highly encouraged to leave the default configuration settings, whereas published sensor names exactly match their correspondant MQTT topics.
| separator | Specifies a custom separator for the different levels composing the sensor name. Default is emtpy.
| filter | Regular expression to filter the set of nodes used to build the sensor navigator. Default is none.
| smootherRegex | Regular expression to identify the sensor operations that represent smoothers. The latter need to contain the sampling interval of the smoother, in seconds, in their names. Default is empty.
| | |
| restAPI | Bundles all values related to the RestAPI. See the corresponding [section](#restApi) for more information on supported functionality.
| address | Define (IP-)address and port where the REST API server should run on. Default is 127.0.0.1:8081.
......
......@@ -64,6 +64,7 @@ void RestAPI::clear() {
_sensorDataStore = NULL;
}
_metadataStore.clear();
_smootherRegex = boost::regex();
}
//Initializes the internal sensor navigator
......@@ -90,6 +91,8 @@ bool RestAPI::initTree() {
//Build the tree navigator
LOG(info) << "Building the sensor navigator...";
_separator = _hierarchySettings.separator;
_smootherRegex = boost::regex(_hierarchySettings.smootherRegex);
_numRegex = boost::regex("[0-9]+");
_navigator = new SensorNavigator();
_navigator->setFilter(_hierarchySettings.filter);
_navigator->buildTree(_hierarchySettings.regex, &topics);
......@@ -238,28 +241,33 @@ void RestAPI::POST_query(endpointArgs) {
uint64_t sInterval = sm.getInterval() ? *sm.getInterval() : 0;
double sScale = sm.getScale() ? *sm.getScale() : 1.0;
std::string bestSmoother = "";
if(sInterval && sm.getOperations() && !sm.getOperations()->empty()) {
//Estimate the number of requested datapoints, for all sensors' data plotted in the panel. The number is calculated assuming all sensors plotted on the same panel have the same sampling period. If we exceed the maximum, then apply smoothing.
// Estimate the number of requested datapoints, for all sensors' data plotted in the panel.
// The number is calculated assuming all sensors plotted on the same panel have the same sampling period.
// If we exceed the maximum, then apply smoothing.
uint64_t grafanaInterval = end.getRaw() - start.getRaw();
int64_t bestRate = LLONG_MAX, smoothRate = LLONG_MAX;
if((int)((grafanaInterval / sInterval) * sensors.size()) > MAX_DATAPOINTS) {
//Choose a smoother
if(grafanaInterval/10000000000 < MAX_DATAPOINTS && sm.getOperations()->find("-avg10") != sm.getOperations()->end())
sensorName += "-avg10";
else if(grafanaInterval/300000000000 < MAX_DATAPOINTS && sm.getOperations()->find("-avg300") != sm.getOperations()->end())
sensorName += "-avg300";
else if(sm.getOperations()->find("-avg3600") != sm.getOperations()->end())
//Hourly averages should be fine for intervals of years.
sensorName += "-avg3600";
for(const auto &op : *sm.getOperations()) {
//Looking for the smoother identifier string and getting its sampling interval in seconds
if(boost::regex_search(op.c_str(), _match, _smootherRegex) && boost::regex_search(op.c_str(), _match, _numRegex)) {
// Calculating the number of points for this smoother and updating the best one
smoothRate = (int64_t)(grafanaInterval / (stoull(_match.str(0)) * 1000000000)) - (int64_t)MAX_DATAPOINTS;
// Getting the smoother that is the closest to MAX_DATAPOINTS, and possibly smaller
if(sign(smoothRate) < sign(bestRate) || abs(smoothRate) < abs(bestRate)) {
bestRate = smoothRate;
bestSmoother = op;
}
}
}
}
}
//We need the Sensor ID, since smoothed sensors are not published.
DCDB::SensorId sid(sensorName);
DCDB::SensorId sid(sensorName + bestSmoother);
uint16_t startWs=start.getWeekstamp(), endWs=end.getWeekstamp();
//Shoot the query for this sensor.
......
......@@ -43,6 +43,7 @@
#include "dcdb/sensor.h"
#include <boost/asio.hpp>
#include <boost/regex.hpp>
#define MAX_DATAPOINTS 100000
......@@ -127,6 +128,10 @@ private:
//Clears all internal storage
void clear();
//Quick and dirty utility methods
inline int64_t sign(int64_t val) { return val < 0 ? -1 : 1; }
inline int64_t abs(int64_t val) { return val < 0 ? -val : val; }
SensorNavigator* _navigator;
DCDB::Connection* _connection;
......@@ -135,6 +140,9 @@ private:
MetadataStore _metadataStore;
std::string _separator;
hierarchySettings_t _hierarchySettings;
boost::regex _smootherRegex;
boost::regex _numRegex;
boost::cmatch _match;
};
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment