Commit fa4e87ff authored by Alessio Netti's avatar Alessio Netti

Documentation and secondary features

- Update config files to reflect new topic structure
- Updated READMEs accordingly
- Added support for "relaxed" analyzers, whose units can be built
even if some sensors cannot be found in the system
- Added support for sub-units, so as to build hierarchical unit structures
parent 95a0fe1d
......@@ -158,6 +158,7 @@ file. The following is instead a list of configuration parameters that are avail
|:----- |:----------- |
| default | Name of the template that must be used to configure this analyzer.
| interval | Specifies how often the analyzer will be invoked to perform computations, and thus the sampling interval of its output sensors. Only used for analyzers in _streaming_ mode.
| relaxed | If set to _true_, the units of this analyzer will be instantiated even if some of the respective input sensors do not exist.
| delay | Delay in milliseconds to be applied to the start of the analyzer. This parameter only applies to streaming analyzers. It can be used to allow for input sensor caches to be populated before the analyzer is started.
| minValues | Minimum number of readings that need to be stored in output sensors before these are pushed as MQTT messages. Only used for analyzers in _streaming_ mode.
| mqttPart | Part of the MQTT topic associated to this analyzer. Only used when the Unit system is not employed (see this [section](#mqttTopics)).
......@@ -182,7 +183,7 @@ streaming true
average avg1 {
default def1
mqttPart FF0
mqttPart /avg1
input {
sensor col_user
......@@ -191,15 +192,15 @@ mqttPart FF0
output {
sensor sum {
mqttsuffix 76
mqttsuffix /sum
}
sensor max {
mqttsuffix 77
mqttsuffix /max
}
sensor avg {
mqttsuffix 78
mqttsuffix /avg
}
}
}
......@@ -224,7 +225,7 @@ streaming true
average avg1 {
default def1
mqttPart FF0
mqttPart /avg1
input {
sensor "<bottomup>col_user"
......@@ -233,15 +234,15 @@ mqttPart FF0
output {
sensor "<bottomup, filter cpu01>sum" {
mqttsuffix 76
mqttsuffix /sum
}
sensor "<bottomup, filter cpu01>max" {
mqttsuffix 77
mqttsuffix /max
}
sensor "<bottomup, filter cpu01>avg" {
mqttsuffix 78
mqttsuffix /avg
}
}
}
......@@ -315,6 +316,14 @@ the MQTT prefix, analyzer part and sensor suffix that are defined;
by concatenating the MQTT prefix associated to the unit (which is defined as _the portion of the MQTT topic shared by all sensors
belonging to such unit_) and the sensor suffix. The middle part of the topic is padded accordingly to ensure a fixed length.
#### Pipelining Analyzers <a name="pipelining"></a>
The inputs and outputs of streaming analyzers can be chained so as to form a processing pipeline. To enable this, users
need to configure analyzers by enabling the _relaxed_ configuration parameter, and by selecting as input the output sensors
of other analyzers. This is necessary as the analyzers are instantiated sequentially at startup, and
the framework cannot infer the correct order of initialization so as to resolve all dependencies transparently.
> NOTE &ensp;&ensp;&ensp;&ensp;&ensp; This feature is not supported when using analyzers in _on demand_ mode.
## Rest API <a name="restApi"></a>
DCDBAnalytics provides a REST API that can be used to perform various management operations on the framework. The
......
global {
mqttPrefix /FF112233445566778899AAB
mqttPrefix /test
}
template_aggregator def1 {
interval 1000
minValues 3
mqttPart FF0
duplicate false
streaming true
}
aggregator avg1 {
default def1
mqttPart FF0
window 2000
operation sum
......@@ -27,7 +25,7 @@ operation sum
output {
sensor "<bottomup, filter cpu250>sum" {
mqttsuffix 76
mqttsuffix /sum
}
}
......@@ -37,7 +35,6 @@ operation sum
aggregator avg2 {
default def1
interval 1500
mqttPart FF1
operation average
input {
......@@ -51,7 +48,7 @@ operation average
output {
sensor "<bottomup 1>avg" {
mqttsuffix 78
mqttsuffix /avg
}
}
......@@ -61,7 +58,7 @@ operation average
aggregator avg3 {
default def1
interval 1500
mqttPart FF2
mqttPart /mypart
operation maximum
input {
......@@ -73,7 +70,7 @@ operation maximum
output {
sensor "<bottomup 1>maxall" {
mqttsuffix 81
mqttsuffix /maxall
}
}
......
......@@ -362,6 +362,8 @@ protected:
an.setDelayInterval(stoull(val.second.data()) / 1000);
} else if (boost::iequals(val.first, "duplicate")) {
an.setDuplicate(to_bool(val.second.data()));
} else if (boost::iequals(val.first, "relaxed")) {
an.setRelaxed(to_bool(val.second.data()));
} else if (boost::iequals(val.first, "streaming")) {
an.setStreaming(to_bool(val.second.data()));
} else if (boost::iequals(val.first, INPUT_BLOCK) || boost::iequals(val.first, OUTPUT_BLOCK)) {
......@@ -398,7 +400,7 @@ protected:
try {
units = _unitGen.generateUnits(protoInputs, protoOutputs, inputMode,
MQTTChecker::formatTopic(_mqttPrefix) + MQTTChecker::formatTopic(an.getMqttPart()),
!an.getStreaming());
!an.getStreaming(), an.getRelaxed());
}
catch (const std::exception &e) {
LOG(error) << _analyzerName << " " << an.getName() << ": Error when creating units: " << e.what();
......
......@@ -44,6 +44,7 @@ public:
_name(name),
_mqttPart(""),
_isTemplate(false),
_relaxed(false),
_duplicate(false),
_streaming(true),
_sync(true),
......@@ -65,6 +66,7 @@ public:
_name(other._name),
_mqttPart(other._mqttPart),
_isTemplate(other._isTemplate),
_relaxed(other._relaxed),
_duplicate(other._duplicate),
_streaming(other._streaming),
_sync(other._sync),
......@@ -91,6 +93,7 @@ public:
_name = other._name;
_mqttPart = other._mqttPart;
_isTemplate = other._isTemplate;
_relaxed = other._relaxed;
_unitID = other._unitID;
_duplicate = other._duplicate;
_streaming = other._streaming;
......@@ -204,6 +207,7 @@ public:
const string& getName() const { return _name; }
const string& getMqttPart() const { return _mqttPart; }
bool getTemplate() const { return _isTemplate; }
bool getRelaxed() const { return _relaxed; }
bool getSync() const { return _sync; }
bool getDuplicate() const { return _duplicate; }
bool getStreaming() const { return _streaming; }
......@@ -217,6 +221,7 @@ public:
void setName(const string& name) { _name = name; }
void setMqttPart(const string& mqttPart) { _mqttPart = mqttPart; }
void setTemplate(bool t) { _isTemplate = t; }
void setRelaxed(bool r) { _relaxed = r; }
void setSync(bool sync) { _sync = sync; }
void setUnitID(int u) { _unitID = u; }
void setStreaming(bool streaming) { _streaming = streaming; }
......@@ -257,6 +262,8 @@ protected:
// To distinguish between templates and actual analyzers
bool _isTemplate;
// If the analyzer's units must be built in relaxed mode
bool _relaxed;
// If true, the analyzer is a duplicate of another
bool _duplicate;
// If true, the analyzer performs computation in streaming
......
......@@ -261,7 +261,7 @@ public:
throw std::runtime_error("No template unit in analyzer " + _name + "!");
LOG(debug) << "Analyzer " << _name << ": cache miss for unit " << node << ".";
U_Ptr uTemplate = _ondemandCache->at(SensorNavigator::templateKey);
tempUnit = unitGen.generateUnit(node, uTemplate->getInputs(), uTemplate->getOutputs(), uTemplate->getInputMode(), "");
tempUnit = unitGen.generateUnit(node, uTemplate->getInputs(), uTemplate->getOutputs(), uTemplate->getInputMode(), "", false);
addToOndemandCache(tempUnit);
}
......
......@@ -151,9 +151,12 @@ public:
* @param inputMode Defines the method with which input sensors are instantiated for each unit
* @param mqttPrefix MQTT prefix to use for output sensors if only the "root" unit is defined
* @param ondemand If True, no unit resolution is performed and a raw unit template is stored
* @param relaxed If True, checks on the existence of input sensors are ignored
* @return A vector of shared pointers to the generated unit objects
*/
vector<shared_ptr<UnitTemplate<SBase>>> *generateUnits(vector<shared_ptr<SBase>>& inputs, vector<shared_ptr<SBase>>& outputs, inputMode_t inputMode, string mqttPrefix="", bool ondemand=false) {
vector<shared_ptr<UnitTemplate<SBase>>> *generateUnits(vector<shared_ptr<SBase>>& inputs, vector<shared_ptr<SBase>>& outputs,
inputMode_t inputMode, string mqttPrefix="", bool ondemand=false, bool relaxed=false) {
// If no outputs are defined, no units can be instantiated
if((inputs.empty() && inputMode==SELECTIVE) || outputs.empty())
throw invalid_argument("UnitGenerator: Invalid inputs or outputs!");
......@@ -183,7 +186,7 @@ public:
if(!ondemand || unitLevel==-1)
for(const auto& u : *units) {
try {
unitObjects->push_back(_generateUnit(u, inputs, outputs, inputMode, mqttPrefix));
unitObjects->push_back(_generateUnit(u, inputs, outputs, inputMode, mqttPrefix, relaxed));
} catch( const exception& e) {
delete units;
delete unitObjects;
......@@ -215,9 +218,12 @@ public:
* @param outputs The vector of "prototype" sensor objects for outputs
* @param inputMode Defines the method with which input sensors are instantiated for each unit
* @param mqttPrefix MQTT prefix to use for output sensors if only the "root" unit is defined
* @param relaxed If True, checks on the existence of input sensors are ignored
* @return A vector of shared pointers to the generated unit objects
*/
shared_ptr<UnitTemplate<SBase>> generateUnit(const string& u, vector<shared_ptr<SBase>>& inputs, vector<shared_ptr<SBase>>& outputs, inputMode_t inputMode, string mqttPrefix="") {
shared_ptr<UnitTemplate<SBase>> generateUnit(const string& u, vector<shared_ptr<SBase>>& inputs, vector<shared_ptr<SBase>>& outputs,
inputMode_t inputMode, string mqttPrefix="", bool relaxed=false) {
// If no outputs are defined, no units can be instantiated
if((inputs.size()==0 && inputMode==SELECTIVE) || outputs.size() == 0)
throw invalid_argument("UnitGenerator: Invalid inputs or outputs!");
......@@ -230,7 +236,7 @@ public:
if(!nodeBelongsToPattern(u, outputs[0]->getName()))
throw domain_error("UnitGenerator: Node " + u + " does not belong to this unit domain!");
return _generateUnit(u, inputs, outputs, inputMode, mqttPrefix);
return _generateUnit(u, inputs, outputs, inputMode, mqttPrefix, relaxed);
}
/**
......@@ -287,7 +293,9 @@ protected:
}
// Private method for building units, that does not perform redundant checks
shared_ptr<UnitTemplate<SBase>> _generateUnit(const string& u, vector<shared_ptr<SBase>>& inputs, vector<shared_ptr<SBase>>& outputs, inputMode_t inputMode, string mqttPrefix="") {
shared_ptr<UnitTemplate<SBase>> _generateUnit(const string& u, vector<shared_ptr<SBase>>& inputs, vector<shared_ptr<SBase>>& outputs,
inputMode_t inputMode, string mqttPrefix, bool relaxed) {
vector<shared_ptr<SBase>> unitInputs, unitOutputs;
// AddedSensors keeps track of which sensor names were added already to the input set, to prevent duplicates
set<string> addedSensors, *sensors;
......@@ -307,7 +315,7 @@ protected:
if (!addedSensors.count(s)) {
SBase uIn(*in);
uIn.setName(s);
if (!_navi->sensorExists(uIn.getName())) {
if (!(_navi->sensorExists(uIn.getName()) || relaxed)) {
delete sensors;
throw invalid_argument("UnitGenerator: Sensor " + uIn.getName() + " does not exist!");
}
......
......@@ -61,6 +61,10 @@ public:
_outputs.push_back(s);
_baseOutputs.push_back(s);
}
for(auto u : other._subUnits) {
_subUnits.push_back(u);
}
}
/**
......@@ -83,6 +87,11 @@ public:
_outputs.push_back(s);
_baseOutputs.push_back(s);
}
_subUnits.clear();
for(auto u : other._subUnits) {
_subUnits.push_back(u);
}
return *this;
}
......@@ -173,6 +182,17 @@ public:
_baseOutputs = std::vector<SBasePtr>(_outputs.begin(), _outputs.end());
}
/**
* @brief Set the outputs of this unit
*
* The same considerations done for setInputs apply here as well.
*
* @param outputs A vector of pointers to objects derived from SensorBase that will be this unit's output
*/
void setSubUnits(const std::vector<std::shared_ptr<UnitTemplate<S>>>& sUnits) {
_subUnits = sUnits;
}
/**
* @brief Add a single input sensor to this unit
*
......@@ -188,6 +208,13 @@ public:
void addOutput(const S_Ptr output) { _outputs.push_back(output); _baseOutputs.push_back(output); }
/**
* @brief Adds a sub-unit to this unit
*
* @param sUnit A shared pointer to a UnitTemplate object
*/
void addSubUnit(const std::shared_ptr<UnitTemplate<S>> sUnit) { _subUnits.push_back(sUnit); }
/**
* @brief Prints the current unit configuration
*
......@@ -202,6 +229,11 @@ public:
LOG_VAR(ll) << " Outputs: ";
for (const auto &o : _outputs)
o->printConfig(ll, lg, 20);
if(_subUnits.size()>0) {
LOG_VAR(ll) << " Sub-units: ";
for (const auto &u : _subUnits)
LOG_VAR(ll) << " " << u->getName();
}
}
protected:
......@@ -216,6 +248,8 @@ protected:
std::vector<SBasePtr> _baseInputs;
// Vector of Sensor objects that make up outputs
std::vector<S_Ptr> _outputs;
// Vector of sub-units that are associated to this unit
std::vector<std::shared_ptr<UnitTemplate<S>>> _subUnits;
// Same as baseInputs
std::vector<SBasePtr> _baseOutputs;
};
......
global {
mqttListenAddress 127.0.0.1:1883
cleaningInterval 86400
mqttprefix /00112233445566778899AABB
mqttprefix /test
threads 24
messageThreads 128
messageSlots 16
......
......@@ -139,38 +139,12 @@ PUT https://localhost:8000/bacnet/stop?authkey=myToken
## MQTT topic <a name="mqttTopic"></a>
For communication between the different DCDB-components (database, dcdbpusher) the [MQTT protocol](https://mqtt.org/) is used. In order to identify each sensor, everyone has to have a unique MQTT topic assigned. A MQTT topic for DCDB consists of exactly 112 bits (= 28 hex characters), not including '/' separators. The topic for a sensor is built by appending up to 4 parts:
1. mqttprefix (e.g. /00112233445566778899AA)
2. mqttpart of entity (if supported by plugin, e.g. /BB)
3. mqttpart of group (e.g. /1122)
4. mqttsuffix (e.g. /3344)
1. mqttprefix (e.g. /mysystem)
2. mqttpart of entity (if supported by plugin, e.g. /host0)
3. mqttpart of group (e.g. /eth0)
4. mqttsuffix (e.g. /xmitdata)
Then the topic for the sensor is /00112233445566778899AA/BB/1122/3344.
### Automatic sensor name publishing <a name="autopublish"></a>
In order to perform queries through the *dcdbquery* tool for a certain sensor, a mapping from its MQTT topic to the desired displayed name must be supplied through the *dcdbconfig* tool, which stores this information in the underlying Cassandra datastore.
However, dcdbpusher can also handle this task automatically, and perform the publishing of all configured sensors. To enable this feature, users must use the *sensorpattern* global configuration parameter, which can also be supplied through the -a command line option.
Such sensor pattern is a string defining the naming scheme to be used by dcdbpusher: it is composed of a fixed part, which will be present in the names of all sensors, and of several wildcards, which are automatically replaced by dcdbpusher with the information of the specific sensor. Current supported wildcards are:
* \<sensor\>: the sensor's name as set in the configuration file of the corresponding plugin;
* \<group\>: the name of the sensor group to which the single sensor belongs;
* \<plugin\>: the name of the plugin managing the sensor group.
Note that the \<sensor\> wildcard *must* be supplied in order for the sensor pattern to be considered valid. If not, the sensor pattern will be discarded and automatic sensor name publishing will not be performed. An example of a valid sensor pattern is the following:
```
myHostname.<group>.<sensor>
```
This sensor pattern will include the hostname (in this case, *myHostname*) to distinguish between the sensors of different hosts, plus the sensor group and name. For the *MemFree* and *nr_alloc_batch* sensors defined in the default [ProcFS config file](config/procfs.conf), this pattern will produce the following names:
```
myHostname.meminfo.MemFree
myHostname.vmstat.nr_alloc_batch
```
It is advised to always include the group name together with the sensor name in the pattern, as dcdbpusher does not perform any checks on the uniqueness of sensor names.
Then the topic for the sensor is /mysystem/host0/eth0/xmitdata.
# Plugins <a name ="plugins"></a>
......@@ -205,7 +179,7 @@ In the following two abstract config files are shown to visualize the structure,
------------------------------------------------
global {
mqttprefix /00112233445566778899AABB0000
mqttprefix /myprefix
cacheInterval 120
...
}
......@@ -213,32 +187,32 @@ global {
template_group temp1 { ;template group named temp1 (is not used in live operation)
interval 1000 ;While it is possible define entities/groups/sensors without
minValues 3 ;name it is strictly disregarded. Naming entities/groups/sensors
mqttPart AA ;simplifies debugging and especially enables one to reference
mqttPart /aa ;simplifies debugging and especially enables one to reference
;templates later on. Also names should be always unique.
sensor s1 {
mqttsuffix 01
mqttsuffix /s1
... ;usually the sensor would require additional attributes
}
sensor s2 {
mqttsuffix 02
mqttsuffix /s2
...
}
}
group g1 {
default temp1 ;use temp1 as template group
mqttPart BB ;overwrite the mqttPart from temp1, to avoid identical
mqttPart /bb ;overwrite the mqttPart from temp1, to avoid identical
;mqtt-topics if another group uses the same template
sensor s3 { ;g1 has now 3 sensors: s1, s2 (both taken over from temp1)
mqttsuffix 03 ;and s3
mqttsuffix /s3 ;and s3
...
}
}
group g2 { ;g2 consists of only one sensor (s21) and uses
sensor s21 { ;for every attribute the default value
mqttsuffix 0000 ;by using a longer mqttsuffix we do not need a
mqttsuffix /s21 ;by using a longer mqttsuffix we do not need a
... ;group mqtt-part
}
}
......@@ -260,15 +234,15 @@ template_entity temp1 { ;template entity which is not used in live operation
group g1 {
interval 1000
minValues 3
mqttPart AA
mqttPart /aa
sensor s1 {
mqttsuffix 01
mqttsuffix /s1
... ;usually the sensor would require additional attributes
}
sensor s2 {
mqttsuffix 02
mqttsuffix /s2
...
}
}
......@@ -279,7 +253,7 @@ entity ent1 {
group g2 { ;ent1 has now two groups (g1 and g2) with a total of
sensor s21 { ;3 sensors (s1, s2, s21)
mqttsuffix 0000
mqttsuffix /s21
...
}
}
......@@ -324,7 +298,7 @@ Explanation of the values specific for the perfevent plugin:
| config | Together with the type-field config determines which performance counter should be read. Possible values and what they measure are listed below.
| cpus | One can define a comma-separated list of cpu numbers (also value ranges can be specified, e.g. 2-4 equals 2,3,4). The hardware counter will then be only opened on the specified cpus.
| htVal | Specify multiplier for CPU aggregation. All CPUs where (CPU-number % htVal) has the same result are aggregated together. Only CPUs which are included in the "cpus" field (or all CPUs if the "cpus" field is not present) are aggregated. Background: To reduce the amount of pushed sensor data, it is possible to aggregate cpu readings. This feature is specifically aimed at processors which are hyper-threading enabled but can also come in handy for other use cases. Only the values pushed via the MQTT-Pusher are aggregated. There still exist sensors for each CPU and they store unaggregated readings in their local caches.
| mqttsufffix | In the context of the perfevent plugin the mqttpart requires a place holder ('x') for the CPU id. Sensors will be duplicated in order to open hardware counter for each CPU. Therefore the mqttsuffix should contain a placeholder consisting of 'x' to be replaced by the CPU id and make the suffix unique.
| mqttsufffix | In the context of the perfevent plugin the CPU id is integrated in the suffix. Sensors will be duplicated in order to open hardware counter for each CPU. Therefore an identifier in the style of "/cpuxx" will be pre-prended to the mqttSuffix when building the topics.
> NOTE &ensp;&ensp;&ensp; As perfevent counters are usually always monotonic, the delta attribute is by default set to true for all sensors. One has to explicitly set delta to "off" for a sensor to overwrite this behaviour.
......@@ -532,9 +506,8 @@ Explanation of the values specific for the ProcFS plugin:
|:----- |:----------- |
| type | The type of the file parsed by the sensor group. Can be either "vmstat", "meminfo", "procstat" or "sar"
| path | Path of the file, if different from the default path in the /proc filesystem
| mqttPart | The mqttPart can be used a placeholder. For sensors associated to metrics that are core-specific (e.g. some of those in /proc/stat) the mqttPart is replaced with the CPU id. For all other metrics that are system-wide, the mqttPart is used as it is.
| mqttStart | Base MQTT suffix that is automatically incremented to generate topics for sensors associated to metrics in the same file. Note that this parameter is used only if automatic MQTT topic generation is enabled, when no sensors are explicitly defined.
| cpus | Defines the set of CPU cores for which metrics must be collected. Only affects extraction of core-specific metrics (e.g. those in /proc/stat), whereas system-level metrics are acquired regardless of this setting. If no CPU cores set is defined, metrics for all available CPU cores will be collected. This parameter follows the same syntax as in the Perf-event plugin.
| mqttSuffix | the mqttSuffix field in the ProcFS plugin, for sensors that are CPU-related such as the ones in procstat files, behaves as described for the perf-event plugin.
Additionally, sensors in the ProcFS plugin (defined with the "metric" keyword) support the following additional values:
......
global {
mqttPrefix /FF112233445566778899
mqttPrefix /test
address_cache ./test.cache
interface eth0
port 22222
......@@ -12,7 +12,6 @@ global {
template_group def0 {
interval 1000
minValues 3
mqttPart FFFF
property test1 {
factor 10
......@@ -20,7 +19,7 @@ template_group def0 {
deviceInstance 1234
objectInstance 1234
objectType 8
mqttsuffix 0000
mqttsuffix /mysensor
}
}
......@@ -32,18 +31,17 @@ group g1 {
deviceInstance 1234
objectInstance 1234
objectType 8
mqttsuffix 0001
mqttsuffix /mysensor2
}
}
group g2 {
mqttPart FFFF
property prop {
deviceInstance 2222
objectInstance 1234
objectType 8
id 75
mqttsuffix 0004
mqttsuffix /mysensor3
}
}
global {
mqttBroker localhost:1883
mqttprefix /00112233445566778899AABB
mqttprefix /test
threads 24
maxMsgNum 100
verbosity 5
......
;comments in config files are indicated by a semicolon
global {
mqttPrefix /FF112233445566778899AABBFFFF
mqttPrefix /test
;add here other global attributes for your plugin
}
......@@ -11,17 +11,17 @@ group template_a1 {
minValues 10
sensor IOBYTESREAD {
metric IOBYTESREAD
mqttsuffix 0000
mqttsuffix /iobytesread
}
sensor IOBYTESWRITE {
metric IOBYTESWRITE
mqttsuffix 0001
mqttsuffix /iobyteswrite
}
sensor IOREADS {
metric IOREADS
mqttsuffix 0002
mqttsuffix /ioreads
}
}
......@@ -30,7 +30,7 @@ group io01 {
sensor IOWRITES {
metric IOWRITES
mqttsuffix 0003
mqttsuffix /iowrites
}
}
......
......@@ -14,14 +14,14 @@ template_group energy {
cmd "0x00 0x2e 0x81 0x4d 0x4f 0x00 0x00 0x01 0x82 0x00 0x08"
start 5
stop 12
mqttsuffix 99887766
mqttsuffix /energy
}
}
host localhost {
username "USERID"
password "PASSW0RD"
mqttPart "/00/11/2233445566/778899"
mqttPart "/my/ipmi/host/"
group g1 {
default energy
......@@ -31,7 +31,7 @@ host localhost {
sensor recordSens {
recordId 4321
factor 1000
mqttsuffix 11223345
mqttsuffix /recordSens
}
}
}
......
;comments in config files are indicated by a semicolon
global {
mqttPrefix /FF112233445566778899AABBFFFF
mqttPrefix /test
;add here other global attributes for your plugin
}
group g1 {
interval 1000
mqttprefix 01
; mqttprefix 01
cpus 0-95
sensor Instructions {
mqttsuffix 00
mqttsuffix /instructions
metric 0x309
}
sensor Cycles {
mqttsuffix 01
mqttsuffix /cycles
metric 0x30A
}
sensor RefCycles {
mqttsuffix 02
mqttsuffix /refcycles
metric 0x30B
}
}
......
global {
mqttPrefix /FF112233445566778899AABB
mqttPrefix /test
}
template_group temp1 {
......@@ -8,7 +8,7 @@ template_group temp1 {