AnalyticsManager.cpp 6.96 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
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
//
// Created by Netti, Alessio on 10.12.18.
//

#include "AnalyticsManager.h"

void AnalyticsManager::clear() {
    for(const auto& p : _plugins)
        p.destroy(p.configurator);
    _plugins.clear();
}

bool AnalyticsManager::load(const string& path, const string& globalFile, const pluginSettings_t& pluginSettings) {
    //The load code is pretty much the same as in Configuration.cpp to load pusher plugins
    _configPath = path;
    _pluginSettings = pluginSettings;
    boost::property_tree::iptree cfg;
    try {
        boost::property_tree::read_info(path + globalFile, cfg);
    } catch (boost::property_tree::info_parser_error& e) {
        LOG(error) << "Error when reading analyzer plugins from global.conf: " << e.what();
        return false;
    }

    BOOST_FOREACH(boost::property_tree::iptree::value_type &plugin, cfg.get_child("analyzerPlugins")) {
        if (boost::iequals(plugin.first, "analyzerPlugin")) {
            if (!plugin.second.empty()) {
                LOG(info) << "Loading analyzer plugin \"" << plugin.second.data() << "\"...";
                std::string pluginConfig; //path to config file for plugin
                std::string pluginLib = "libdcdbanalyzer_" + plugin.second.data();
#if __APPLE__
                pluginLib+= ".dylib";
#else
                pluginLib+= ".so";
#endif
                BOOST_FOREACH(boost::property_tree::iptree::value_type &val, plugin.second) {
                    if (boost::iequals(val.first, "path")) {
                        std::string path = val.second.data();
                        // If path not specified we will look up in the default lib-directories (usr/lib and friends)
                        if (path != "") {
                            if (path[path.length()-1] != '/')
                                path.append("/");
                            pluginLib = path + pluginLib;
                        }
                    } else if (boost::iequals(val.first, "config")) {
                        pluginConfig = val.second.data();
                        // If config-path not specified we will look for pluginName.conf in the global.conf directory
                        if (pluginConfig == "")
                            pluginConfig = _configPath + plugin.second.data() + ".conf";
                    } else {
                        LOG(warning) << "  Value \"" << val.first << "\" not recognized. Omitting";
                    }
                }
                // Open dl-code based on http://tldp.org/HOWTO/C++-dlopen/thesolution.html
                if (FILE *file = fopen(pluginConfig.c_str(), "r")) {
                    fclose(file);
                    an_dl_t dynLib;
                    dynLib.id = plugin.second.data();
                    dynLib.DL = NULL;
                    dynLib.configurator = NULL;

                    // If plugin.conf exists, open libdcdbanalyzer_pluginName.so and read config
                    LOG(info) << pluginConfig << " found";
                    dynLib.DL = dlopen(pluginLib.c_str(), RTLD_NOW);
                    if(!dynLib.DL) {
                        LOG(error) << "Cannot load " << dynLib.id << "-library: " << dlerror();
                        return false;
                    }
                    dlerror();

                    // Set dynLib an_dl_t struct, load create and destroy symbols
                    dynLib.create = (an_create_t*) dlsym(dynLib.DL, "create");
                    const char* dlsym_error = dlerror();
                    if (dlsym_error) {
                        LOG(error) << "Cannot load symbol create for " << dynLib.id << ": " << dlsym_error;
                        return false;
                    }

                    dynLib.destroy = (an_destroy_t*) dlsym(dynLib.DL, "destroy");
                    dlsym_error = dlerror();
                    if (dlsym_error) {
                        LOG(error) << "Cannot load symbol destroy for " << dynLib.id << ": " << dlsym_error;
                        return false;
                    }

                    dynLib.configurator = dynLib.create();
                    dynLib.configurator->setGlobalSettings(_pluginSettings);
                    // Read the analyzer plugin configuration
                    if (!(dynLib.configurator->readConfig(pluginConfig))) {
                        LOG(error) << "Plugin \"" << dynLib.id << "\" could not read configuration!";
                        return false;
                    }

                    // Returning an empty vector may indicate problems with the config file
                    if(dynLib.configurator->getAnalyzers().size() == 0) {
                        LOG(warning) << "Plugin \"" << dynLib.id << "\" created no analyzers!";
                    }

                    //check if an MQTT-suffix was assigned twice
                    for(const auto& a : dynLib.configurator->getAnalyzers()) {
                        for(const auto& u : a->getUnits())
                            for(const auto& o: u->getBaseOutputs()) {
                                //TODO: make MQTT topic check generic
                                bool ok = true; //checkMqtt(o->getMqtt());
                                if(!ok) {
                                    LOG(error) << "Problematic MQTT-Topics! Please check your config files";
                                    return false;
                                }
                            }
                    }

                    //save dl-struct
                    _plugins.push_back(dynLib);
                    LOG(info) << "Plugin \"" << dynLib.id << "\" loaded!";
                } else {
                    LOG(info) << pluginConfig << " not found. Omitting";
                }
            }
        }
    }
    return true;
}

bool AnalyticsManager::init(boost::asio::io_service& io, const string& plugin) {
    for (const auto &p : _plugins)
        //Actions always affect either one or all plugins, and always all analyzers within said plugin
        if(plugin=="" || plugin==p.id)
            for (const auto &a : p.configurator->getAnalyzers())
                a->init(io);
    return true;
}

bool AnalyticsManager::reload(boost::asio::io_service& io, const string& plugin) {
    for (const auto &p : _plugins)
        if(plugin=="" || plugin==p.id) {
            if( !p.configurator->reReadConfig() )
                return false;
            for (const auto &a : p.configurator->getAnalyzers())
                a->init(io);
        }
    return true;
}

bool AnalyticsManager::start(const string& plugin) {
    for (const auto &p : _plugins)
        if(plugin=="" || plugin==p.id)
            for (const auto &a : p.configurator->getAnalyzers())
                a->start();
    return true;
}

bool AnalyticsManager::stop(const string& plugin) {
    for (const auto &p : _plugins)
        if(plugin=="" || plugin==p.id)
            for (const auto &a : p.configurator->getAnalyzers())
                a->stop();
    return true;
}

string AnalyticsManager::forwardREST(const string& command) {
    //TODO: implement REST interface integration
    return "";
}