jupp0r / prometheus-cpp

Prometheus Client Library for Modern C++
Other
929 stars 327 forks source link

metrics are not displayed on localhost:9091 #642

Open paffosx opened 1 year ago

paffosx commented 1 year ago

Hello everyone. I am writing code to remove metrics from a remote server and output them to localhost:9091. My problem is that I can't understand why the metrics are not displayed on localhost:9091 despite the fact that there is a connection to the server and the removed metrics are selected in the console. Who is not difficult to help or tell me how to solve my problem. my code:

include <libssh/libssh.h>

include <prometheus/registry.h>

include <prometheus/exposer.h>

include <prometheus/counter.h>

include <prometheus/gauge.h>

include

include

include

include

include

include "string.h"

// Function to execute a command on an SSH channel and return the output std::string execute_ssh_command(ssh_session session, const std::string& command) { ssh_channel channel = ssh_channel_new(session); if (channel == NULL) { throw std::runtime_error("Error creating SSH channel"); } if (ssh_channel_open_session(channel) != SSH_OK) { throw std::runtime_error("Error opening SSH channel"); } if (ssh_channel_request_exec(channel, command.c_str()) != SSH_OK) { throw std::runtime_error("Error executing SSH command"); } char buffer[256]; std::stringstream output; while (ssh_channel_read(channel, buffer, sizeof(buffer), 0) > 0) { output << buffer; } ssh_channel_send_eof(channel); ssh_channel_close(channel); ssh_channel_free(channel); return output.str(); }

int verify_knownhost(ssh_session session) { enum ssh_known_hosts_e state; unsigned char hash = NULL; ssh_key srv_pubkey = NULL; size_t hlen; char buf[10]; char hexa; char *p; int cmp; int rc;

rc = ssh_get_server_publickey(session, &srv_pubkey);
if (rc < 0) {
    return -1;
}

rc = ssh_get_publickey_hash(srv_pubkey,
                            SSH_PUBLICKEY_HASH_SHA1,
                            &hash,
                            &hlen);
ssh_key_free(srv_pubkey);
if (rc < 0) {
    return -1;
}

state = ssh_session_is_known_server(session);
switch (state) {
    case SSH_KNOWN_HOSTS_OK:
        /* OK */

        break;
    case SSH_KNOWN_HOSTS_CHANGED:
        fprintf(stderr, "Host key for server changed: it is now:\n");
        ssh_print_hexa("Public key hash", hash, hlen);
        fprintf(stderr, "For security reasons, connection will be stopped\n");
        ssh_clean_pubkey_hash(&hash);

        return -1;
    case SSH_KNOWN_HOSTS_OTHER:
        fprintf(stderr, "The host key for this server was not found but an other"
                "type of key exists.\n");
        fprintf(stderr, "An attacker might change the default server key to"
                "confuse your client into thinking the key does not exist\n");
        ssh_clean_pubkey_hash(&hash);

        return -1;
    case SSH_KNOWN_HOSTS_NOT_FOUND:
        fprintf(stderr, "Could not find known host file.\n");
        fprintf(stderr, "If you accept the host key here, the file will be"
                "automatically created.\n");

        /* FALL THROUGH to SSH_SERVER_NOT_KNOWN behavior */

    case SSH_KNOWN_HOSTS_UNKNOWN:
        hexa = ssh_get_hexa(hash, hlen);
        fprintf(stderr,"The server is unknown. Do you trust the host key?\n");
        fprintf(stderr, "Public key hash: %s\n", hexa);
        ssh_string_free_char(hexa);
        ssh_clean_pubkey_hash(&hash);
        p = fgets(buf, sizeof(buf), stdin);
        if (p == NULL) {
            return -1;
        }

        cmp = strncasecmp(buf, "yes", 3);
        if (cmp != 0) {
            return -1;
        }

        rc = ssh_session_update_known_hosts(session);
        if (rc < 0) {
            fprintf(stderr, "Error %s\n", strerror(errno));
            return -1;
        }

        break;
    case SSH_KNOWN_HOSTS_ERROR:
        fprintf(stderr, "Error %s", ssh_get_error(session));
        ssh_clean_pubkey_hash(&hash);
        return -1;
}

ssh_clean_pubkey_hash(&hash);
return 0;

}

int main() {

int port[]={22};
char *password;
char pswrd[]={"password"};
char ip[]={"id"};
char login[]={"name"};
int rc;
ssh_session session;
session = ssh_new();
if(session == NULL) 
    {
        std::cout << "Session cannot be created. Exiting.." << std::endl;
        exit(EXIT_FAILURE);
    }

ssh_options_set(session, SSH_OPTIONS_HOST, ip);
ssh_options_set(session, SSH_OPTIONS_USER, login);

rc = ssh_connect(session);

if (rc != SSH_OK)
    {
        fprintf(stderr, "Error connecting to localhost: %s\n",
        ssh_get_error(session));
        ssh_free(session);
        exit(-1);
    }

if (verify_knownhost(session) < 0) { ssh_disconnect(session); ssh_free(session); exit(-1); }

password=pswrd;
rc = ssh_userauth_password(session, NULL, password);
if (rc != SSH_AUTH_SUCCESS)
    {
        fprintf(stderr, "Error authenticating with password: %s\n",
        ssh_get_error(session));
        ssh_disconnect(session);
        ssh_free(session);
        exit(-1);
    }

//creating the prometheus registry

auto registry = std::make_shared<prometheus::Registry>();

auto& ram_usage_gauge = prometheus::BuildGauge()
                           .Name("node_memory_usage_bytes")
                           .Help("RAM usage")
                           .Register(*registry);

prometheus::Exposer exposer{"localhost:9091"};
// collecting indicators every 1 seconds
while (true) {
try {
    // getting data about RAM on the server
    std::string output = execute_ssh_command(session, "free | grep Mem | awk '{print $3}'");
    int node_memory_usage_bytes = std::stoi(output);
    std::cout<< node_memory_usage_bytes<< std::endl;
    ram_usage_gauge.Add({{"name","id"}})
        .Set(node_memory_usage_bytes);
} catch (std::exception& e) {
    std::cerr << "Error getting RAM usage: " << e.what() << std::endl;
}
// transferring metrics to port 9091

exposer.RegisterCollectable(registry);

std::this_thread::sleep_for(std::chrono::seconds(1));

}

// completion of work
ssh_disconnect(session);
ssh_free(session);

}

gjasny commented 1 year ago

You should register the registry in the exposer only once and prior to your while-loop. For debugging I'd suggest that you set some breakpoints in the exposer code like here: https://github.com/jupp0r/prometheus-cpp/blob/99e4d5085e4557fc9f3bea8db0c69bb1727c3d56/pull/src/exposer.cc#L54

But if I look at the complexity with an SSH access to a remote machine, I wonder if installing something like Telegraf on the remote machine would be the easier option. Telegraf is a statically linked Go binary with no dependencies and easy to handle.