Commit b2f28aae authored by Micha Mueller's avatar Micha Mueller
Browse files

Merge branch 'master' of gitlab.lrz.de:dcdb/dcdb

parents 40c685ee 64ed2657
......@@ -41,7 +41,7 @@ Additional parameters specific to this framework are the following:
| Value | Explanation |
|:----- |:----------- |
| global | Wrapper structure for the global values.
| analytics | Wrapper structure for the data analytics-specific values.
| hierarchy | Space-separated sequence of regular expressions used to infer the local (DCDBPusher) or global (DCDBCollectAgent) sensor hierarchy. This parameter should be wrapped in quotes to ensure proper parsing. See the Sensor Tree [section](#sensorTree) for more details.
| analyzerPlugins | Block containing the specification of all data analytics plugin to be instantiated.
| plugin _name_ | The plugin name is used to build the corresponding lib-name (e.g. average --> libdcdbanalyzer_average.1.0)
......
......@@ -10,7 +10,7 @@
#include "QueryEngine.h"
#include "AnalyzerInterface.h"
#include "pluginsettings.h"
#include "globalconfiguration.h"
/**
* Interface to configurators for data analyzer plugins
......
......@@ -85,7 +85,11 @@ public:
virtual ~AnalyzerConfiguratorTemplate() {
for (auto ta : _templateAnalyzers)
delete ta.second;
for (auto ts : _templateSensors)
delete ts.second;
_templateAnalyzers.clear();
_templateSensors.clear();
_templateProtoInputs.clear();
_analyzerInterfaces.clear();
_analyzers.clear();
}
......@@ -154,18 +158,22 @@ public:
if (!val.second.empty()) {
Analyzer* an = new Analyzer(val.second.data());
an->setTemplate(true);
if (readAnalyzer(*an, val.second)) {
auto ret = _templateAnalyzers.insert(std::pair<std::string, Analyzer*>(val.second.data(), an));
if(!ret.second) {
LOG(warning) << "Template " << _analyzerName << " " << val.second.data() << " already exists! Omitting...";
delete an;
}
} else {
if (!readAnalyzer(*an, val.second)) {
LOG(warning) << "Template " << _analyzerName << " \"" << val.second.data() << "\" has bad values! Ignoring...";
delete an;
}
}
// Here we read and instantiate analyzers
// Sensor templates are read
} else if (boost::iequals(val.first, "template_" + _baseName)) {
LOG(debug) << "Template " << _baseName << " \"" << val.second.data() << "\"";
if (!val.second.empty()) {
SBase* base = new SBase(val.second.data());
if (!readSensorBase(*base, val.second, true)) {
LOG(warning) << "Template " << _baseName << " \"" << val.second.data() << "\" has bad values! Ignoring...";
delete base;
}
}
// Here we read and instantiate analyzers
} else if (boost::iequals(val.first, _analyzerName)) {
LOG(debug) << _analyzerName << " \"" << val.second.data() << "\"";
if (!val.second.empty()) {
......@@ -211,14 +219,18 @@ public:
for(auto a : _analyzers)
a->wait();
// First of all, delete all template analyzers
// First of all, delete all template analyzers and sensors
for (auto ta : _templateAnalyzers)
delete ta.second;
for (auto ts : _templateSensors)
delete ts.second;
// Clear all analyzers
_analyzerInterfaces.clear();
_analyzers.clear();
_templateAnalyzers.clear();
_templateSensors.clear();
_templateProtoInputs.clear();
}
/**
......@@ -294,7 +306,7 @@ protected:
* @param ll Severity level to log with
*/
virtual void printConfiguratorConfig(LOG_LEVEL ll) {
LOG_VAR(ll) << " No other plugin-specific general parameters defined";
LOG_VAR(ll) << " No other plugin-specific general parameters defined";
}
/**
......@@ -331,9 +343,12 @@ protected:
an = *(it->second);
an.setName(config.data());
an.setTemplate(false);
// Analyzers instantiated from templates DO NOT share the same units and sensors. This would lead to
// too much naming ambiguity and is generally just not needed
// Analyzers instantiated from templates DO NOT share the same units and output sensors.
// This would lead to too much naming ambiguity and is generally just not needed
an.clearUnits();
// The input sensors defined in the template are on the other hand preserved; this is meant as a
// workaround to shorten certain configurations
protoInputs = _templateProtoInputs[def.get().data()];
} else {
LOG(warning) << "Template " << _analyzerName << "\"" << def.get().data() << "\" not found! Using standard values.";
}
......@@ -362,7 +377,7 @@ protected:
if (boost::iequals(valInner.first, _baseName)) {
LOG(debug) << " I/O " << _baseName << " " << valInner.second.data();
SBase sensor = SBase(valInner.second.data());
if (readSensorBase(sensor, valInner.second)) {
if (readSensorBase(sensor, valInner.second, false)) {
shared_ptr<SBase> sensorPtr = make_shared<SBase>(sensor);
val.first==INPUT_BLOCK ? protoInputs.push_back(sensorPtr) : protoOutputs.push_back(sensorPtr);
} else {
......@@ -424,6 +439,14 @@ protected:
}
}
delete units;
} else {
// If the analyzer is a template, we add it to the related map
auto ret = _templateAnalyzers.insert(std::pair<std::string, Analyzer*>(an.getName(), &an));
if(!ret.second) {
LOG(warning) << "Template " << _analyzerName << " " << an.getName() << " already exists! Omitting...";
return false;
}
_templateProtoInputs.insert(std::pair<std::string, std::vector<shared_ptr<SBase>>>(an.getName(), protoInputs));
}
return true;
}
......@@ -439,9 +462,23 @@ protected:
* @param config A boost property (sub-)tree containing the sensor values
* @return True if successful, false otherwise
*/
bool readSensorBase(SBase& sBase, CFG_VAL config) {
bool readSensorBase(SBase& sBase, CFG_VAL config, bool isTemplate=false) {
sBase.setCacheInterval(_cacheInterval);
if (!isTemplate) {
// Copying parameters from the template (if defined)
boost::optional<boost::property_tree::iptree&> def = config.get_child_optional("default");
if(def) {
LOG(debug) << " Using \"" << def.get().data() << "\" as default.";
auto it = _templateSensors.find(def.get().data());
if(it != _templateSensors.end()) {
sBase = *(it->second);
sBase.setName(config.data());
} else {
LOG(warning) << "Template " << _baseName << "\" " << def.get().data() << "\" not found! Using standard values.";
}
}
}
// Reading other sensor parameters
BOOST_FOREACH(boost::property_tree::iptree::value_type &val, config) {
if (boost::iequals(val.first, "mqttsuffix")) {
sBase.setMqtt(val.second.data());
......@@ -450,12 +487,21 @@ protected:
} else if (boost::iequals(val.first, "delta")) {
sBase.setDelta(to_bool(val.second.data()));
} else if (boost::iequals(val.first, "sink")) {
sBase.setSinkPath( val.second.data() );
sBase.setSinkPath(val.second.data());
} else if (boost::iequals(val.first, "subSampling")) {
sBase.setSubsampling( std::stoul(val.second.data()) );
sBase.setSubsampling(std::stoul(val.second.data()));
}
}
sensorBase(sBase, config);
if(isTemplate) {
auto ret = _templateSensors.insert(std::pair<std::string, SBase*>(sBase.getName(), &sBase));
if(!ret.second) {
LOG(warning) << "Template " << _baseName << " " << sBase.getName() << " already exists! Omitting...";
return false;
}
}
return true;
}
......@@ -553,6 +599,10 @@ protected:
std::vector<A_Ptr> _analyzers;
// Map of the template analyzers that were defined in the config file - used for easy retrieval and instantiation
std::map<std::string, Analyzer*> _templateAnalyzers;
// Map of the template sensors that were defined
std::map<std::string, SBase*> _templateSensors;
// Map of the protoinputs belonging to template analyzers
std::map<std::string, std::vector<shared_ptr<SBase>>> _templateProtoInputs;
};
#endif //PROJECT_ANALYZERCONFIGURATORTEMPLATE_H
......@@ -91,6 +91,14 @@ public:
* "buffer" vector allows to re-use memory over successive readings. Note that in order to use
* this method, a callback must have been set through the setQueryCallback method. If not, this
* method will throw an exception.
*
* The "rel" argument governs how the search is performed in local sensor caches: if set to true,
* startTs and endTs indicate relative offsets against the most recent reading, and the returned
* vector is a view of the cache whose range is computed statically in O(1), and therefore the
* underlying data may be slightly unaligned depending on the sampling rate. If rel is set to
* false, startTs and endTs are interpreted as absolute timestamps, and the cache view is
* determined by performing binary search with O(log(n)) complexity, thus resulting in a accurate
* time range. This parameter does not affect the query method when using the Cassandra datastore.
*
* @param name Name of the sensor to be queried
* @param startTs Start timestamp (in nanoseconds) of the time range for the query
......
......@@ -5,6 +5,7 @@ CXXFLAGS = -O2 -g --std=c++11 -Wall -Wno-unused-function -Wno-unused-local-typed
OBJS = ../common/src/logging.o \
../analytics/AnalyticsManager.o \
../common/src/sensornavigator.o \
../common/src/globalconfiguration.o \
analyticscontroller.o \
sensorcache.o \
collectagent.o \
......
......@@ -14,19 +14,22 @@ void AnalyticsController::stop() {
_keepRunning = false;
LOG(info) << "Stopping sensors...";
_manager->stop();
_manager->clear();
LOG(info) << "Stopping data analytics management thread...";
_mainThread.join();
LOG(info) << "Stopping worker threads...";
_keepAliveWork.reset();
_threads.join_all();
_initialized = false;
}
//TODO: error checking on _io
restResponse_t AnalyticsController::REST(const vector<string>& pathStrs, const vector<pair<string,string>>& queries, const string& method) {
if(_initialized)
throw runtime_error("Cannot forward REST command, AnalyticsController is not initialized!");
return _manager->REST(pathStrs, queries, method, _io);
}
bool AnalyticsController::initialize(globalCA_t& settings, const string& configPath) {
bool AnalyticsController::initialize(Configuration& settings, const string& configPath) {
_settings = settings;
_configPath = configPath;
_navigator = make_shared<SensorNavigator>();
......@@ -47,7 +50,7 @@ bool AnalyticsController::initialize(globalCA_t& settings, const string& configP
// Building the sensor navigator
try {
_navigator->buildTree(_settings.hierarchy, &names, &topics);
_navigator->buildTree(_settings.analyticsSettings.hierarchy, &names, &topics);
} catch (const std::invalid_argument &e) {
LOG(error) << e.what();
LOG(error) << "Failed to build sensor hierarchy tree!";
......
......@@ -75,11 +75,11 @@ public:
* and then create an AnalyticsManager object, which will take care of instantiating and
* preparing plugins.
*
* @param settings Settings structure containing user-specified configuration parameters
* @param settings Settings class containing user-specified configuration parameters
* @param configPath Path to the configuration files for the data analytics framework
* @return True if successful, false otherwise
*/
bool initialize(globalCA_t& settings, const string& configPath);
bool initialize(Configuration& settings, const string& configPath);
/**
* @brief Sets the cache to be used for sensors
......@@ -178,7 +178,7 @@ private:
// Internal data analytics manager object
shared_ptr<AnalyticsManager> _manager;
// Misc configuration attributes
globalCA_t _settings;
Configuration _settings;
string _configPath;
// Readings counter
uint64_t _readingCtr;
......
......@@ -84,8 +84,7 @@ std::vector<reading_t>* sensorQueryCallback(const string& name, const uint64_t s
sid.mqttTopicConvert(topic);
if(mySensorCache.getSensorMap().count(sid) > 0) {
CacheEntry &entry = mySensorCache.getSensorMap()[sid];
// getView is called with live=false to drop strict staleness checks
output = entry.getView(startTs, endTs, buffer, rel, false);
output = entry.getView(startTs, endTs, buffer, rel);
if (output->size() > 0)
return output;
}
......@@ -157,7 +156,6 @@ struct httpHandler_t {
std::string response = "";
std::ostringstream data;
std::string auth_value = "";
bool json = false;
std::vector<std::string> pathStrs;
std::vector<std::pair<std::string, std::string>> queries;
......@@ -196,15 +194,17 @@ struct httpHandler_t {
}
}
//finished string processing
for (auto& p : queries) {
//authkey is required in every case
//if (p.first == "authkey") {
// auth_value = p.second;
//} else
if (p.first == "json")
if (stoi(p.second) > 0)
json = true;
}
//bool json = false;
//for (auto& p : queries) {
// authkey is required in every case
//if (p.first == "authkey") {
// auth_value = p.second;
//} else
//if (p.first == "json")
// if (stoi(p.second) > 0)
// json = true;
//}
if (pathStrs.size() < 1) {
LOGH(warning) << "Received malformed request: No first path part";
......@@ -431,26 +431,24 @@ int mqttCallback(SimpleMQTTMessage *msg)
* Print usage information
*/
void usage() {
Configuration config("");
globalCA_t& defaults = config.getGlobal();
Configuration config("", "collectagent.conf");
/*
1 2 3 4 5 6 7 8
012345678901234567890123456789012345678901234567890123456789012345678901234567890
*/
cout << "Usage:" << endl;
cout << " collectagent [-d] [-s] [-x] [-a<string>] [-m<host>] [-r<host>] [-c<host>] [-u<username>] [-p<password>] [-t<ttl>] [-v<verbosity>] <path/to/configfiles/>" << endl;
cout << " collectagent [-d] [-s] [-x] [-a<string>] [-m<host>] [-c<host>] [-u<username>] [-p<password>] [-t<ttl>] [-v<verbosity>] <path/to/configfiles/>" << endl;
cout << " collectagent -h" << endl;
cout << endl;
cout << "Options:" << endl;
cout << " -a <string> Auto-publish pattern [default: none]" << endl;
cout << " -m<host> MQTT listen address [default: " << defaults.mqttListenAddress << "]" << endl;
cout << " -r<host> REST API listen address [default: " << defaults.restListenAddress << "]" << endl;
cout << " -c<host> Cassandra host [default: " << defaults.cassandraSettings.address << "]" << endl;
cout << " -m<host> MQTT listen address [default: " << config.mqttListenHost << ":" << config.mqttListenPort << "]" << endl;
cout << " -c<host> Cassandra host [default: " << config.cassandraSettings.host << ":" << config.cassandraSettings.port << "]" << endl;
cout << " -u<username> Cassandra username [default: none]" << endl;
cout << " -p<password> Cassandra password [default: none]" << endl;
cout << " -t<ttl> Cassandra insert TTL [default: " << defaults.cassandraSettings.ttl << "]" << endl;
cout << " -v<level> Set verbosity of output [default: " << defaults.logLevelCmd << "]" << endl
cout << " -t<ttl> Cassandra insert TTL [default: " << config.cassandraSettings.ttl << "]" << endl;
cout << " -v<level> Set verbosity of output [default: " << config.logLevelCmd << "]" << endl
<< " Can be a number between 5 (all) and 0 (fatal)." << endl;
cout << endl;
cout << " -d Daemonize" << endl;
......@@ -462,7 +460,6 @@ void usage() {
int main(int argc, char* const argv[]) {
cout << "CollectAgent " << VERSION << " (libdcdb " << DCDB::Version::getVersion() << ")" << endl << endl;
bool validateConfig = false;
try{
......@@ -494,38 +491,40 @@ int main(int argc, char* const argv[]) {
initLogging();
auto cmdSink = setupCmdLogger();
Configuration config(argv[argc - 1]);
if( !config.readGlobal() ) {
Configuration config(argv[argc - 1], "collectagent.conf");
if( !config.readConfig() ) {
LOG(fatal) << "Failed to read global configuration!";
exit(EXIT_FAILURE);
}
globalCA_t& settings = config.getGlobal();
/* Parse command line */
std::string listenHost, cassandraHost, restApiHost;
std::string listenPort, cassandraPort, restApiPort;
// References to shorten access to config parameters
Configuration& settings = config;
cassandra_t& cassandraSettings = config.cassandraSettings;
pluginSettings_t& pluginSettings = config.pluginSettings;
restAPISettings_t& restAPISettings = config.restAPISettings;
analyticsSettings_t& analyticsSettings = config.analyticsSettings;
optind = 1;
while ((ret=getopt(argc, argv, opts))!=-1) {
switch(ret) {
case 'a':
settings.pluginSettings.sensorPattern = optarg;
pluginSettings.sensorPattern = optarg;
break;
case 'm':
settings.mqttListenAddress = optarg;
break;
case 'r':
settings.restListenAddress = optarg;
settings.mqttListenHost = parseNetworkHost(optarg);
settings.mqttListenPort = parseNetworkPort(optarg);
if(settings.mqttListenPort=="") settings.mqttListenPort = string(LISTENPORT);
break;
case 'c':
settings.cassandraSettings.address = optarg;
cassandraSettings.host = parseNetworkHost(optarg);
cassandraSettings.port = parseNetworkPort(optarg);
if(cassandraSettings.port=="") cassandraSettings.port = string(CASSANDRAPORT);
break;
case 'u':
settings.cassandraSettings.username = optarg;
cassandraSettings.username = optarg;
break;
case 'p': {
settings.cassandraSettings.password = optarg;
cassandraSettings.password = optarg;
// What does this do? Mask the password?
size_t pwdLen = strlen(optarg);
memset(optarg, 'x', (pwdLen >= 3) ? 3 : pwdLen);
......@@ -535,7 +534,7 @@ int main(int argc, char* const argv[]) {
break;
}
case 't':
settings.cassandraSettings.ttl = stoul(optarg);
cassandraSettings.ttl = stoul(optarg);
break;
case 'v':
settings.logLevelCmd = translateLogLevel(stoi(optarg));
......@@ -548,7 +547,7 @@ int main(int argc, char* const argv[]) {
settings.statistics = 1;
break;
case 'x':
validateConfig = true;
settings.validateConfig = true;
break;
case 'h':
default:
......@@ -557,7 +556,7 @@ int main(int argc, char* const argv[]) {
}
}
auto fileSink = setupFileLogger(settings.pluginSettings.tempdir, std::string("collectagent"));
auto fileSink = setupFileLogger(pluginSettings.tempdir, std::string("collectagent"));
//severity level may be overwritten (per option or config-file) --> set it according to globalSettings
fileSink->set_filter(boost::log::trivial::severity >= settings.logLevelFile);
cmdSink->set_filter(boost::log::trivial::severity >= settings.logLevelCmd);
......@@ -577,49 +576,19 @@ int main(int argc, char* const argv[]) {
// Daemonizing the collectagent
if(settings.daemonize)
dcdbdaemon();
/*
* Parse hostnames for port specifications
*/
listenHost = string(settings.mqttListenAddress);
size_t pos = listenHost.find(":");
if (pos != string::npos) {
listenPort = listenHost.substr(pos+1);
listenHost.erase(pos);
} else {
listenPort = LISTENPORT;
}
cassandraHost = string(settings.cassandraSettings.address);
pos = cassandraHost.find(":");
if (pos != string::npos) {
cassandraPort = cassandraHost.substr(pos+1);
cassandraHost.erase(pos);
} else {
cassandraPort = CASSANDRAPORT;
}
restApiHost = string(settings.restListenAddress);
pos = restApiHost.find(":");
if (pos != string::npos) {
restApiPort = restApiHost.substr(pos+1);
restApiHost.erase(pos);
} else {
restApiPort = RESTAPIPORT;
}
// Setting the size of the sensor cache
// Conversion from milliseconds to nanoseconds
mySensorCache.setMaxHistory(uint64_t(settings.pluginSettings.cacheInterval) * 1000000);
mySensorCache.setMaxHistory(uint64_t(pluginSettings.cacheInterval) * 1000000);
//Allocate and initialize connection to Cassandra.
dcdbConn = new DCDB::Connection(cassandraHost, atoi(cassandraPort.c_str()), settings.cassandraSettings.username, settings.cassandraSettings.password);
dcdbConn->setNumThreadsIo(settings.cassandraSettings.numThreadsIo);
dcdbConn->setQueueSizeIo(settings.cassandraSettings.queueSizeIo);
uint32_t params[3] = {settings.cassandraSettings.coreConnPerHost, settings.cassandraSettings.maxConnPerHost, settings.cassandraSettings.maxConcRequests};
dcdbConn = new DCDB::Connection(cassandraSettings.host, atoi(cassandraSettings.port.c_str()),
cassandraSettings.username, cassandraSettings.password);
dcdbConn->setNumThreadsIo(cassandraSettings.numThreadsIo);
dcdbConn->setQueueSizeIo(cassandraSettings.queueSizeIo);
uint32_t params[3] = {cassandraSettings.coreConnPerHost, cassandraSettings.maxConnPerHost, cassandraSettings.maxConcRequests};
dcdbConn->setBackendParams(params);
if (!dcdbConn->connect()) {
LOG(fatal) << "Cannot connect to Cassandra!";
exit(EXIT_FAILURE);
......@@ -629,8 +598,7 @@ int main(int argc, char* const argv[]) {
* Legacy behavior: Initialize the DCDB schema in Cassandra.
*/
dcdbConn->initSchema();
/*
* Allocate the SensorDataStore.
*/
......@@ -640,9 +608,9 @@ int main(int argc, char* const argv[]) {
/*
* Set TTL for data store inserts if TTL > 0.
*/
if (settings.cassandraSettings.ttl > 0)
mySensorDataStore->setTTL(settings.cassandraSettings.ttl);
mySensorDataStore->setDebugLog(settings.cassandraSettings.debugLog);
if (cassandraSettings.ttl > 0)
mySensorDataStore->setTTL(cassandraSettings.ttl);
mySensorDataStore->setDebugLog(cassandraSettings.debugLog);
analyticsController = new AnalyticsController(mySensorConfig, mySensorDataStore);
analyticsController->setCache(&mySensorCache);
......@@ -650,40 +618,50 @@ int main(int argc, char* const argv[]) {
return EXIT_FAILURE;
queryEngine.setQueryCallback(sensorQueryCallback);
LOG_LEVEL vLogLevel = validateConfig ? LOG_LEVEL::info : LOG_LEVEL::debug;
LOG_LEVEL vLogLevel = settings.validateConfig ? LOG_LEVEL::info : LOG_LEVEL::debug;
LOG_VAR(vLogLevel) << "----- Configuration -----";
//print global settings in either case
LOG(info) << "Global Settings:";
LOG(info) << " MQTT-listenAddress: " << settings.mqttListenAddress;
LOG(info) << " CacheInterval: " << int(settings.pluginSettings.cacheInterval/1000) << " [s]";
LOG(info) << " MQTT-listenAddress: " << settings.mqttListenHost << ":" << settings.mqttListenPort;
LOG(info) << " CacheInterval: " << int(pluginSettings.cacheInterval/1000) << " [s]";
LOG(info) << " CleaningInterval: " << settings.cleaningInterval << " [s]";
LOG(info) << " MessageThreads: " << settings.messageThreads;
LOG(info) << " MessageSlots: " << settings.messageSlots;
LOG(info) << " Daemonize: " << (settings.daemonize ? "Enabled" : "Disabled");
LOG(info) << " Statistics: " << (settings.statistics ? "Enabled" : "Disabled");
LOG(info) << " Write-Dir: " << settings.pluginSettings.tempdir;
LOG(info) << " Hierarchy: " << (settings.hierarchy!="" ? settings.hierarchy : "none");
LOG(info) << (validateConfig ? " Only validating config files." : " ValidateConfig: Disabled");
LOG(info) << " MQTT-prefix: " << pluginSettings.mqttPrefix;
LOG(info) << " Write-Dir: " << pluginSettings.tempdir;
LOG(info) << (settings.validateConfig ? " Only validating config files." : " ValidateConfig: Disabled");
LOG(info) << "Analytics Settings:";
LOG(info) << " Hierarchy: " << (analyticsSettings.hierarchy!="" ? analyticsSettings.hierarchy : "none");
LOG(info) << "Cassandra Driver Settings:";
LOG(info) << " Address: " << settings.cassandraSettings.address;
LOG(info) << " TTL: " << settings.cassandraSettings.ttl;
LOG(info) << " NumThreadsIO: " << settings.cassandraSettings.numThreadsIo;
LOG(info) << " QueueSizeIO: " << settings.cassandraSettings.queueSizeIo;
LOG(info) << " CoreConnPerHost: " << settings.cassandraSettings.coreConnPerHost;
LOG(info) << " MaxConnPerHost: " << settings.cassandraSettings.maxConnPerHost;
LOG(info) << " MaxConcRequests: " << settings.cassandraSettings.maxConcRequests;
LOG(info) << " DebugLog: " << (settings.cassandraSettings.debugLog ? "Enabled" : "Disabled");
LOG(info) << " Address: " << cassandraSettings.host << ":" << cassandraSettings.port;
LOG(info) << " TTL: " << cassandraSettings.ttl;
LOG(info) << " NumThreadsIO: " << cassandraSettings.numThreadsIo;
LOG(info) << " QueueSizeIO: " << cassandraSettings.queueSizeIo;
LOG(info) << " CoreConnPerHost: " << cassandraSettings.coreConnPerHost;
LOG(info) << " MaxConnPerHost: " << cassandraSettings.maxConnPerHost;
LOG(info) << " MaxConcRequests: " << cassandraSettings.maxConcRequests;
LOG(info) << " DebugLog: " << (cassandraSettings.debugLog ? "Enabled" : "Disabled");
#ifdef SimpleMQTTVerbose
LOG(info) << " Username: " << settings.cassandraSettings.username;
LOG(info) << " Password: " << settings.cassandraSettings.password;
LOG(info) << " Username: " << cassandraSettings.username;
LOG(info) << " Password: " << cassandraSettings.password;
#else
LOG(info) << " Username and password not printed.";
#endif
LOG(info) << "RestAPI Settings:";
LOG(info) << " REST Server: " << settings.restListenAddress;
LOG(info) << " REST Server: " << restAPISettings.restHost << ":" << restAPISettings.restPort;
#ifdef SimpleMQTTVerbose
LOG(info) << " Certificate: " << restAPISettings.certificate;
LOG(info) << " Private key file: " << restAPISettings.privateKey;
LOG(info) << " DH params from: " << restAPISettings.dhFile;
#else
LOG(info) << " Certificate, private key and DH-param file not printed.";
#endif
LOG_VAR(vLogLevel) << "----- Analytics Configuration -----";
for(auto& p : analyticsController->getManager()->getPlugins()) {
......@@ -692,7 +670,7 @@ int main(int argc, char* const argv[]) {
}
LOG_VAR(vLogLevel) << "----- End Configuration -----";
if (validateConfig)
if (settings.<