ProcfsConfigurator.cpp 7.94 KB
Newer Older
Alessio Netti's avatar
Alessio Netti committed
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
/*
 * ProcfsConfigurator.cpp
 *
 *  Created on: 18.10.2018
 *      Author: Alessio Netti
 */

#include "ProcfsConfigurator.h"

/**
 *  Class constructor.
 *
 */
ProcfsConfigurator::ProcfsConfigurator() {
    _groupName = "file";
Alessio Netti's avatar
Alessio Netti committed
16
    _baseName = "metric";
Alessio Netti's avatar
Alessio Netti committed
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
    _entityName = "INVALID";
}

/**
 *  Class destructor.
 *
 */
ProcfsConfigurator::~ProcfsConfigurator() {}

/**
 * Reads a configuration file and instantiates Procfs Sensor Groups accordingly.
 *
 * Unlike in ConfiguratorTemplate, the assignment of MQTT topics to sensor is done in the
 * sensorGroup() method.
 *
 * @param cfgPath: the path to the configuration file to be used
 * @return true if successful, false otherwise
 *
 */
bool ProcfsConfigurator::readConfig(std::string cfgPath) {
    _cfgPath = cfgPath;
Alessio Netti's avatar
Alessio Netti committed
38

Alessio Netti's avatar
Alessio Netti committed
39
40
    boost::property_tree::iptree cfg;
    boost::property_tree::read_info(cfgPath, cfg);
Alessio Netti's avatar
Alessio Netti committed
41

Alessio Netti's avatar
Alessio Netti committed
42
43
    // Read global variables (if present overwrite those from global.conf)
    readGlobal(cfg);
Alessio Netti's avatar
Alessio Netti committed
44

Alessio Netti's avatar
Alessio Netti committed
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
    // Read groups and templates for groups. Entities and single sensors are ignored as they are not supported in this plugin
    BOOST_FOREACH(boost::property_tree::iptree::value_type &val, cfg) {
        // Read template group
        if (boost::iequals(val.first, "template_" + _groupName)) {
            LOG(debug) << "Template " << _groupName << " \"" << val.second.data() << "\"";
            if (!val.second.empty()) {
                ProcfsSensorGroup* group = new ProcfsSensorGroup(val.second.data());
                if (readSensorGroup(*group, val.second)) {
                    auto ret = _templateSensorGroups.insert(std::pair<std::string, ProcfsSensorGroup*>(val.second.data(), group));
                    if(!ret.second) {
                        LOG(warning) << "Template " << _groupName << " " << val.second.data() << " already exists! Omitting...";
                    }
                } else {
                    LOG(warning) << "Template " << _groupName << " \"" << val.second.data() << "\" has bad values! Ignoring...";
                }
            }
Alessio Netti's avatar
Alessio Netti committed
61
            // Read sensor group
Alessio Netti's avatar
Alessio Netti committed
62
63
64
        } else if (boost::iequals(val.first, _groupName)) {
            LOG(debug) << _groupName << " \"" << val.second.data() << "\"";
            if (!val.second.empty()) {
65
                ProcfsSGPtr group = std::make_shared<ProcfsSensorGroup>(val.second.data());
Alessio Netti's avatar
Alessio Netti committed
66
67
68
69
70
71
                if (readSensorGroup(*group, val.second)) {
                    storeSensorGroup(group);
                } else {
                    LOG(warning) << _groupName << " \"" << val.second.data() << "\" has bad values! Ignoring...";
                }
            }
Alessio Netti's avatar
Alessio Netti committed
72
73
74
        } else if( !boost::iequals(val.first, "global") ) {
            LOG(error) << "\"" << val.first << "\": unknown construct!";
            return false;
Alessio Netti's avatar
Alessio Netti committed
75
76
        }
    }
Alessio Netti's avatar
Alessio Netti committed
77
    constructSensorNames();
Alessio Netti's avatar
Alessio Netti committed
78
79
80
    return true;
}

Alessio Netti's avatar
Alessio Netti committed
81
82
83
84
85
86
87
88
89
90
91
92
/**
 * Configures a ProcfsSensorBase object instantiated by the readSensorBase method.
 *
 * @param s: the ProcfsSensorBase object to be configured
 * @param config: the BOOST property (sub-)tree containing configuration options for the sensor
 *
 */
void ProcfsConfigurator::sensorBase(ProcfsSensorBase& s, CFG_VAL config) {
    BOOST_FOREACH(boost::property_tree::iptree::value_type &val, config) {
        if (boost::iequals(val.first, "type"))
            s.setMetric(val.second.data());
        else if (boost::iequals(val.first, "perCPU"))
Alessio Netti's avatar
Alessio Netti committed
93
            s.setPerCPU(to_bool(val.second.data()));
Alessio Netti's avatar
Alessio Netti committed
94
95
96
    }
}

Alessio Netti's avatar
Alessio Netti committed
97
98
99
100
101
102
103
104
105
106
107
/**
 * Configures a ProcfsSensorGroup object instantiated by the readSensorGroup method.
 *
 * For simplicity, the assignment of MQTT topics to sensors is done here and not in readConfig(),
 * unlike in ConfiguratorTemplate.
 *
 * @param sGroup: the ProcfsSensorGroup object to be configured
 * @param config: the BOOST property (sub-)tree containing configuration options for the sensor group
 *
 */
void ProcfsConfigurator::sensorGroup(ProcfsSensorGroup& sGroup, CFG_VAL config) {
108
    std::vector<ProcfsSBPtr> derivedSensors;
Alessio Netti's avatar
Alessio Netti committed
109
110
    ProcfsParser *parser;

Alessio Netti's avatar
Alessio Netti committed
111
112
    BOOST_FOREACH(boost::property_tree::iptree::value_type &val, config) {
        if (boost::iequals(val.first, "type")) {
113
            sGroup.setType(val.second.data());
Alessio Netti's avatar
Alessio Netti committed
114
        } else if (boost::iequals(val.first, "path")) {
115
            sGroup.setPath(val.second.data());
Alessio Netti's avatar
Alessio Netti committed
116
        } else if (boost::iequals(val.first, "mqttStart")) {
117
            sGroup.setMqttStart(val.second.data());
Alessio Netti's avatar
Alessio Netti committed
118
        } else if (boost::iequals(val.first, "cpus")) {
119
            sGroup.setCpuSet(parseCpuString(val.second.data()));
Alessio Netti's avatar
Alessio Netti committed
120
121
        }
    }
Alessio Netti's avatar
Alessio Netti committed
122

Alessio Netti's avatar
Alessio Netti committed
123
124
    // The "type" parameter must refer to either vmstat, procstat or meminfo. If not, the sensor group is not initialized
    // The only other case is when an empty string is found, which can happen for template groups
125
126
    std::string fileType = sGroup.getType();
    std::string filePath = sGroup.getPath();
Alessio Netti's avatar
Alessio Netti committed
127
128
129
130
131
132
    if(fileType == "")
        return;
    else if(fileType == "vmstat")
        parser = new VmstatParser(filePath);
    else if(fileType == "procstat")
        parser = new ProcstatParser(filePath);
Alessio Netti's avatar
Alessio Netti committed
133
134
    else if(fileType == "sar")
        parser = new SARParser(filePath);
Alessio Netti's avatar
Alessio Netti committed
135
136
137
    else if(fileType == "meminfo")
        parser = new MeminfoParser(filePath);
    else {
138
        LOG(warning) << _groupName << " " << sGroup.getGroupName() << "::" << "Unspecified or invalid type! Available types are vmstat, meminfo, procstat, sar";
Alessio Netti's avatar
Alessio Netti committed
139
        return; }
Alessio Netti's avatar
Alessio Netti committed
140

Alessio Netti's avatar
Alessio Netti committed
141
    // if any sensor objects specified by users in the configuration file are present,
Alessio Netti's avatar
Alessio Netti committed
142
    // automatic MQTT topic assignment is disabled and the topics supplied in the config are used
Alessio Netti's avatar
Alessio Netti committed
143
144
145
146
    bool autoMQTT = sGroup.getSensors().empty();
    // After getting the vector of available metrics (subset of the sensor map, if any) from the parsed file, we delete
    // all sensors not matching any parsed metrics, and arrange their order to respect the one in the file
    derivedSensors = sGroup.getDerivedSensors();
147
    parser->init(&derivedSensors, sGroup.getCpuSet());
Alessio Netti's avatar
Alessio Netti committed
148

Alessio Netti's avatar
Alessio Netti committed
149
    // If no metrics were found in the file (or the file is unreadable) the configuration aborts
Alessio Netti's avatar
Alessio Netti committed
150
    int numMetrics = parser->getNumMetrics();
Alessio Netti's avatar
Alessio Netti committed
151
    if(numMetrics == 0) {
Alessio Netti's avatar
Alessio Netti committed
152
153
        LOG(warning) << _groupName << " " << sGroup.getGroupName() << "::" << "Unable to parse file " << filePath << ", please check your configuration!";
        sGroup.getSensors().clear();
Alessio Netti's avatar
Alessio Netti committed
154
        sGroup.getDerivedSensors().clear();
Alessio Netti's avatar
Alessio Netti committed
155
        return; }
Alessio Netti's avatar
Alessio Netti committed
156
    LOG(debug) << "  Number of metrics found: " << numMetrics;
Alessio Netti's avatar
Alessio Netti committed
157

Alessio Netti's avatar
Alessio Netti committed
158
159
    // We assign the final sensor objects as parsed in the target file, and assign the parser object
    sGroup.replaceSensors(parser->getSensors());
Alessio Netti's avatar
Alessio Netti committed
160
    sGroup.setParser(parser);
Alessio Netti's avatar
Alessio Netti committed
161
    // Vector that keeps track of the current number of metrics for each CPU core for which a MQTT topic has been assigned
Alessio Netti's avatar
Alessio Netti committed
162
    // All core-independent metrics refer to position 0 in the vector. Used only on automatic MQTT assignment
Alessio Netti's avatar
Alessio Netti committed
163
    std::vector<unsigned int> *metricsCounter = new std::vector<unsigned int>(parser->getNumCPUs() + 1);
Alessio Netti's avatar
Alessio Netti committed
164
    for(unsigned int i=0;i < metricsCounter->size(); i++) metricsCounter->at(i) = 0;
Alessio Netti's avatar
Alessio Netti committed
165

Alessio Netti's avatar
Alessio Netti committed
166
    // Adding the sensors corresponding to availableMetrics
Alessio Netti's avatar
Alessio Netti committed
167
    for(int i=0;i < numMetrics; i++) {
168
        ProcfsSBPtr sensor = std::static_pointer_cast<ProcfsSBPtr::element_type>(sGroup.getSensors().at(i));
169
        if ( autoMQTT ) sensor->setMqtt(increaseMqtt(sGroup.getMqttStart(), metricsCounter->at(sensor->getCPUId() + 1)++ ));
Alessio Netti's avatar
Alessio Netti committed
170
171
        // If the metric does not refer to a specific CPU core, the topic is prefix + default mqttPart + suffix
        // The suffix is increased automatically through the metricsCounter vector
Alessio Netti's avatar
Alessio Netti committed
172
        if( sensor->getCPUId() == -1 )
Alessio Netti's avatar
Alessio Netti committed
173
            sensor->setMqtt(_mqttPrefix + sGroup.getMqttPart() + "/" + sensor->getMqtt());
Alessio Netti's avatar
Alessio Netti committed
174
175
            // If the metrics refers to a specific CPU core, the topic is prefix + CPU core ID + suffix
            // The suffix is automatically increased for each core through the metricsCounter vector
Alessio Netti's avatar
Alessio Netti committed
176
        else
Alessio Netti's avatar
Alessio Netti committed
177
            sensor->setMqtt(_mqttPrefix + formatMqttCPU(sGroup.getMqttPart(), sensor->getCPUId()) + "/" + sensor->getMqtt());
Alessio Netti's avatar
Alessio Netti committed
178
    }
Alessio Netti's avatar
Alessio Netti committed
179

Alessio Netti's avatar
Alessio Netti committed
180
    // De-allocating memory
Alessio Netti's avatar
Alessio Netti committed
181
    delete metricsCounter;
Alessio Netti's avatar
Alessio Netti committed
182
183
    //parser->close();
}