You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
proxysql/lib/ProxySQL_HTTP_Server.cpp

933 lines
33 KiB

#include <iostream> // std::cout
#include <algorithm> // std::sort
#include <vector> // std::vector
#include "re2/re2.h"
#include "re2/regexp.h"
#include "proxysql.h"
#include "cpp.h"
#include "ProxySQL_HTTP_Server.hpp" // HTTP server
#include "ProxySQL_Statistics.hpp"
#include "SQLite3_Server.h"
#include "MySQL_Authentication.hpp"
#include <search.h>
#include <stdlib.h>
#include <stdio.h>
#include <sys/time.h>
#include <time.h>
#include <string.h>
#include <assert.h>
#include <unistd.h>
#include <sys/socket.h>
#include <resolv.h>
#include <arpa/inet.h>
#include <pthread.h>
#include "SpookyV2.h"
#include <fcntl.h>
#include <sys/utsname.h>
#include "platform.h"
#include "microhttpd.h"
#include "curl/curl.h"
#ifdef DEBUG
#define DEB "_DEBUG"
#else
#define DEB ""
#endif /* DEBUG */
#define PROXYSQL_HTTP_SERVER_VERSION "1.4.1031" DEB
extern ProxySQL_Statistics *GloProxyStats;
extern MySQL_Threads_Handler *GloMTH;
extern ProxySQL_Admin *GloAdmin;
extern MySQL_Authentication *GloMyAuth;
extern SQLite3_Server *GloSQLite3Server;
#ifdef PROXYSQLCLICKHOUSE
extern ClickHouse_Server *GloClickHouseServer;
#endif
extern char * Chart_bundle_js_c;
extern char * font_awesome;
extern char * main_bundle_min_css_c;
#define RATE_LIMIT_PAGE "<html><head><title>Rate Limit Page</title></head><body>Rate Limit Reached</body></html>"
#define DENIED "<html><head><title>ProxySQL status page</title></head><body>Access denied</body></html>"
#define OPAQUE "733b20011778ce330631c9afof70a870baddd964"
struct MemoryStruct {
char *memory;
size_t size;
};
static size_t WriteMemoryCallback(void *contents, size_t size, size_t nmemb, void *userp) {
size_t realsize = size * nmemb;
struct MemoryStruct *mem = (struct MemoryStruct *)userp;
mem->memory = (char *)realloc(mem->memory, mem->size + realsize + 1);
assert(mem->memory);
memcpy(&(mem->memory[mem->size]), contents, realsize);
mem->size += realsize;
mem->memory[mem->size] = 0;
return realsize;
}
static char * check_latest_version() {
CURL *curl_handle;
CURLcode res;
struct MemoryStruct chunk;
chunk.memory = (char *)malloc(1);
chunk.size = 0;
curl_global_init(CURL_GLOBAL_ALL);
curl_handle = curl_easy_init();
curl_easy_setopt(curl_handle, CURLOPT_URL, "https://www.proxysql.com/latest");
curl_easy_setopt(curl_handle, CURLOPT_WRITEFUNCTION, WriteMemoryCallback);
curl_easy_setopt(curl_handle, CURLOPT_WRITEDATA, (void *)&chunk);
curl_easy_setopt(curl_handle, CURLOPT_SSL_VERIFYPEER, 0);
string s = "proxysql-agent/";
s += PROXYSQL_VERSION;
curl_easy_setopt(curl_handle, CURLOPT_USERAGENT, s.c_str());
curl_easy_setopt(curl_handle, CURLOPT_TIMEOUT, 10);
curl_easy_setopt(curl_handle, CURLOPT_CONNECTTIMEOUT, 10);
res = curl_easy_perform(curl_handle);
if (res != CURLE_OK) {
proxy_error("curl_easy_perform() failed: %s\n", curl_easy_strerror(res));
free(chunk.memory);
chunk.memory = NULL;
}
curl_easy_cleanup(curl_handle);
curl_global_cleanup();
return chunk.memory;
}
static char *div1= (char *)"<div style=\"margin-bottom: 1px;\"><a href=stats?metric=";
static char *style1 = (char *)" style=\"color: #2969a5 ; background-color: white; font-weight: bold; font-size: 13px; font-family: Verdana, sans-serif; border: 0px; text-decoration: none; padding-left: 5px; padding-right: 5px;\">";
static char *style2 = (char *)" style=\"color: #2969a5 ; background-color: white; font-size: 12px; font-family: Verdana, sans-serif; border: 0px; text-decoration: none; padding-left: 5px; padding-right: 5px;\">";
static char *generate_home() {
char *s = NULL;
string html = "";
html.append("<div class=\"menu\" style=\"height: auto;\">\n");
html.append("<span style=\"float: left; width: 50%;\">\n");
html.append("<div style=\"margin-top: 15px;\"><a href=\"/\""); html.append(style2); html.append("Home</a>\n");
html.append("<a href=stats?metric=system"); html.append(style2); html.append("System</a>\n");
html.append("<a href=stats?metric=mysql"); html.append(style2); html.append("MySQL</a>\n");
html.append("<a href=stats?metric=cache"); html.append(style2); html.append("Query Cache</a></div>\n");
html.append("</span>\n</div>\n");
html.append("<span style=\"float: left; width: 100%;\">\n");
html.append("<div style=\"height: auto;\">\n");
html.append("<p></p>\n");
html.append("<p></p>\n");
html.append("<h2 style=\"font-size: 25px; margin-top: 0em; margin-bottom: 0em;\">General information</h2>\n<hr style=\"align: centre\" width=\"100%\">\n");
html.append("<table style=\"font-size: 15px;\" border=0 width=\"100%\">\n");
html.append("<tr width=\"100%\">\n");
html.append("<td width=\"33%\">\n");
html.append("<b>Uptime = </b>");
{
unsigned long long t1=monotonic_time();
char buf1[50];
unsigned long long uptime = (t1-GloVars.global.start_time)/1000/1000;
unsigned long long days = uptime / 86400;
unsigned long long hours = (uptime - days*86400)/3600;
unsigned long long mins = (uptime % 3600)/60;
unsigned long long secs = uptime % 60;
sprintf(buf1,"%llud %02lluh%02llum%02llus", days, hours, mins, secs);
html.append(buf1);
}
html.append("<br>\n");
html.append("<b>OS version = </b>");
{
struct utsname unameData;
int rc;
rc=uname(&unameData);
if (rc==0) {
html.append(unameData.sysname); html.append(" ");
html.append(unameData.nodename); html.append(" ");
html.append(unameData.release); html.append(" ");
html.append(unameData.machine);
} else {
html.append("UNKNOWN");
}
}
html.append("<br>\n");
html.append("<b>Worker threads = </b>");
{
char buf[16];
sprintf(buf,"%u",GloMTH->num_threads);
html.append(buf);
}
html.append("<br>\n");
html.append("<b>Idle threads = </b>");
if (glovars.idle_threads) {
html.append("<span style=\"color: green;\">enabled</span>");
} else {
html.append("<span style=\"background-color: red;\"> disabled </span>");
}
html.append("<br>\n");
html.append("<b>Monitor = </b>");
{
char *en = GloMTH->get_variable((char *)"monitor_enabled");
if (en && strcmp(en,"true")==0) {
html.append("<span style=\"color: green;\">enabled</span>");
} else {
html.append("<span style=\"background-color: red;\"> disabled </span>");
}
if (en) {
free(en);
}
}
html.append("<br>\n");
html.append("</td>\n");
html.append("<td width=\"33%\">\n");
{
char *en = GloAdmin->get_variable((char *)"mysql_ifaces");
if (en) {
html.append("<b>Admin interface(s)</b> = ");
html.append(en);
html.append("<br>\n");
free(en);
}
}
#ifdef PROXYSQLCLICKHOUSE
if (GloVars.global.clickhouse_server==false) {
html.append("<b>ClickHouse = </b><span style=\"background-color: yellow;\"> Disabled </span><br>\n");
} else {
char *en = GloClickHouseServer->get_variable((char *)"mysql_ifaces");
if (en) {
html.append("<b>ClickHouse interface</b> = ");
html.append(en);
html.append("<br>\n");
free(en);
}
}
#else
html.append("<b>ClickHouse = </b><span style=\"background-color: red;\"> support not compiled </span><br>\n");
#endif
if (GloMTH) {
char *en = GloMTH->get_variable((char *)"interfaces");
if (en) {
html.append("<b>MySQL interface(s)</b> = ");
html.append(en);
html.append("<br>\n");
free(en);
}
} else {
html.append("<b>MySQL interface(s)</b> = <span style=\"background-color: red;\"> Not started </span><br>");
}
if (GloVars.global.sqlite3_server==false) {
html.append("<b>SQLite3 = </b><span style=\"background-color: yellow;\"> Disabled </span><br>\n");
} else {
char *en = GloSQLite3Server->get_variable((char *)"mysql_ifaces");
if (en) {
html.append("<b>SQLite3 interface(s)</b> = ");
html.append(en);
html.append("<br>\n");
free(en);
}
}
html.append("</td>\n");
html.append("<td width=\"33%\">\n");
html.append("<b>ProxySQL version = </b>"); html.append(PROXYSQL_VERSION); html.append("<br>\n");
html.append("<b>ProxySQL latest = </b>");
{
GloAdmin->AdminHTTPServer->check_latest_version_http();
if (GloAdmin->AdminHTTPServer->variables.proxysql_latest_version == NULL) {
html.append("unknown");
} else {
html.append(GloAdmin->AdminHTTPServer->variables.proxysql_latest_version);
}
}
html.append("<br>\n");
html.append("</td>\n");
html.append("</tr>\n");
html.append("</table>\n");
html.append("</div></span>\n");
s = strdup(html.c_str());
return s;
}
static char *generate_buttons(char *base) {
char *s = NULL;
string html = "<div class=\"menu\" style=\"height: auto;\"><span style=\"float: left; width: 100%;\">\n";
html.append("<div style=\"margin-top: 15px;\">");
html.append("<a href=\"/\""); html.append(style2); html.append("Home</a>\n");
html.append("<a href=stats?metric=system"); html.append(style2); html.append("System</a>\n");
html.append("<a href=stats?metric=mysql"); html.append(style2); html.append("MySQL</a>\n");
html.append("<a href=stats?metric=cache"); html.append(style2); html.append("Query Cache</a>\n");
html.append("</div></span>");
html.append("<div class=\"menu\" style=\"height: auto;\">\n<span style=\"float: left;\">\n");
html.append("<p></p>\n");
html.append("<p></p>\n");
html.append("<h2 style=\"font-size: 25px; margin-top: 0em; margin-bottom: 0em;\">Statistics:</h2>\n<hr style=\"align: centre\" width=\"100%\">\n");
html.append("<div class=\"menu\" style=\"height: auto;\">\n<span style=\"float: left;\">\n<div style=\"border-bottom-style: solid; border-bottom-color: #2969a5; border-bottom-width: 0px; margin-bottom: 1px; color: #2969a5 ; background-color: white; font-size: 15px; font-family: Verdana, sans-serif; font-weight: bold; text-decoration: none; padding-left: 5px; padding-right: 5px;\"></div>\n");
html.append(div1); html.append(base); html.append("&interval=1800"); html.append(style1); html.append("Last 1/2 hour</a></div>\n");
html.append(div1); html.append(base); html.append("&interval=3600"); html.append(style1); html.append("Last 1 hour</a></div>\n");
html.append(div1); html.append(base); html.append("&interval=7200"); html.append(style1); html.append("Last 2 hours</a></div>\n");
html.append("</span>\n</div>\n");
html.append("<div class=\"menu\" style=\"height: auto;\">\n<span style=\"float: left;\">\n<div style=\"border-bottom-style: solid; border-bottom-color: #2969a5; border-bottom-width: 0px; margin-bottom: 1px; color: #2969a5 ; background-color: white; font-size: 15px; font-family: Verdana, sans-serif; font-weight: bold; text-decoration: none; padding-left: 5px; padding-right: 5px;\"></div>\n");
html.append(div1); html.append(base); html.append("&interval=28800"); html.append(style1); html.append("Last 8 hours</a></div>\n");
html.append(div1); html.append(base); html.append("&interval=86400"); html.append(style1); html.append("Last 1 day</a></div>\n");
html.append(div1); html.append(base); html.append("&interval=259200"); html.append(style1); html.append("Last 3 days</a></div>\n");
html.append("</span>\n</div>\n");
html.append("<div class=\"menu\" style=\"height: auto;\">\n<span style=\"float: left;\">\n<div style=\"border-bottom-style: solid; border-bottom-color: #2969a5; border-bottom-width: 0px; margin-bottom: 1px; color: #2969a5 ; background-color: white; font-size: 15px; font-family: Verdana, sans-serif; font-weight: bold; text-decoration: none; padding-left: 5px; padding-right: 5px;\"></div>\n");
html.append(div1); html.append(base); html.append("&interval=604800"); html.append(style1); html.append("Last 7 days</a></div>\n");
html.append(div1); html.append(base); html.append("&interval=2592000"); html.append(style1); html.append("Last 1 month</a></div>\n");
html.append(div1); html.append(base); html.append("&interval=7776000"); html.append(style1); html.append("Last 3 months</a></div>\n");
html.append("</span>\n</div>\n");
s = strdup(html.c_str());
return s;
}
void ProxySQL_HTTP_Server::check_latest_version_http() {
pthread_mutex_lock(&check_version_mutex);
time_t now = time(NULL);
if (now > last_check_version + 300) {
if (variables.proxysql_latest_version) {
if (now > last_check_version + 3600) {
free(variables.proxysql_latest_version);
variables.proxysql_latest_version = NULL;
}
}
if (variables.proxysql_latest_version == NULL) {
variables.proxysql_latest_version = check_latest_version();
last_check_version = now;
}
}
pthread_mutex_unlock(&check_version_mutex);
}
char * ProxySQL_HTTP_Server::extract_values(SQLite3_result *result, int idx, bool relative, double mult) {
string s = "[";
int i;
for ( i= (relative ? 1 : 0) ; i < result->rows_count ; i++) {
SQLite3_row *r1 = ( relative ? result->rows[i-1] : NULL );
SQLite3_row *r2 = result->rows[i];
double v;
if (relative) {
double d2 = atol(r2->fields[idx]);
double d1 = atol(r1->fields[idx]);
double diff = (atol(r2->fields[1])-atol(r1->fields[1]));
v = (d2-d1)/diff;
} else {
v = atol(r2->fields[idx]);
}
v *= mult;
if (v<0) v=0;
s.append(std::to_string(v));
if (i != result->rows_count-1) {
s.append(", ");
}
}
s.append("];");
char *ret=strdup(s.c_str());
return ret;
}
char * ProxySQL_HTTP_Server::extract_ts(SQLite3_result *result, bool relative) {
string s = "[";
int i;
for ( i= (relative ? 1 : 0) ; i < result->rows_count ; i++) {
SQLite3_row *r2 = result->rows[i];
s.append("\"");
s.append(r2->fields[0]);
s.append("\"");
if (i != result->rows_count-1) {
s.append(", ");
}
}
s.append("];");
char *ret=strdup(s.c_str());
return ret;
}
void ProxySQL_HTTP_Server::init() {
}
void ProxySQL_HTTP_Server::print_version() {
fprintf(stderr,"Standard ProxySQL HTTP Server Handler rev. %s -- %s -- %s\n", PROXYSQL_HTTP_SERVER_VERSION, __FILE__, __TIMESTAMP__);
}
#define EMPTY_PAGE "<html><head><title>File not found</title></head><body>File not found<br/><a href=\"/\">Go back home</a></body></html>"
int ProxySQL_HTTP_Server::handler(void *cls, struct MHD_Connection *connection, const char *url, const char *method, const char *version, const char *upload_data, size_t *upload_data_size, void **ptr) {
struct MHD_Response *response;
int ret;
char *username;
char *password = NULL;
const char *realm = "Access to ProxySQL status page";
username = MHD_digest_auth_get_username(connection);
if (username == NULL) {
response = MHD_create_response_from_buffer(strlen(DENIED), (void *)DENIED, MHD_RESPMEM_PERSISTENT);
ret = MHD_queue_auth_fail_response(connection, realm, OPAQUE, response, MHD_NO);
MHD_destroy_response(response);
return ret;
}
{
int default_hostgroup = -1;
char *default_schema = NULL;
bool schema_locked;
bool transaction_persistent;
bool fast_forward;
bool _ret_use_ssl = false;
int max_connections;
void *sha1_pass = NULL;
password=GloMyAuth->lookup(username, USERNAME_FRONTEND, &_ret_use_ssl, &default_hostgroup, &default_schema, &schema_locked, &transaction_persistent, &fast_forward, &max_connections, &sha1_pass);
if (default_schema) { // unused
free(default_schema);
}
if (sha1_pass) { // unused
free(sha1_pass);
}
if (
(default_hostgroup != STATS_HOSTGROUP)
||
(password == NULL)
) {
if (password) {
free(password); // cleanup
}
free(username); // cleanup
response = MHD_create_response_from_buffer(strlen(DENIED), (void *)DENIED, MHD_RESPMEM_PERSISTENT);
ret = MHD_queue_auth_fail_response(connection, realm, OPAQUE, response, MHD_NO);
MHD_destroy_response(response);
return ret;
}
}
ret = MHD_digest_auth_check(connection, realm, username, password, 300);
free(username);
free(password);
if ( (ret == MHD_INVALID_NONCE) || (ret == MHD_NO) ) {
response = MHD_create_response_from_buffer(strlen(DENIED), (void *)DENIED, MHD_RESPMEM_PERSISTENT);
if (NULL == response)
return MHD_NO;
ret = MHD_queue_auth_fail_response(connection, realm, OPAQUE, response, (ret == MHD_INVALID_NONCE) ? MHD_YES : MHD_NO);
MHD_destroy_response(response);
return ret;
}
char *valmetric = NULL;
char *interval_s = NULL;
int interval_i = 1800;
time_t now = time(NULL);
if (now != cur_time) {
page_sec = 0;
cur_time = now;
}
page_sec++;
if (page_sec > ProxySQL_HTTP_Server_Rate_Limit) {
response = MHD_create_response_from_buffer(strlen(RATE_LIMIT_PAGE), (void *) RATE_LIMIT_PAGE, MHD_RESPMEM_PERSISTENT);
ret = MHD_queue_response (connection, MHD_HTTP_OK, response);
MHD_destroy_response (response);
return ret;
}
if (0 != strcmp (method, "GET"))
return MHD_NO; /* unexpected method */
if (strcmp(url,"/stats")==0) {
valmetric = (char *)MHD_lookup_connection_value (connection, MHD_GET_ARGUMENT_KIND, (char *)"metric");
interval_s = (char *)MHD_lookup_connection_value (connection, MHD_GET_ARGUMENT_KIND, (char *)"interval");
if (valmetric == NULL) {
response = MHD_create_response_from_buffer (strlen (EMPTY_PAGE), (void *) EMPTY_PAGE, MHD_RESPMEM_PERSISTENT);
ret = MHD_queue_response (connection, MHD_HTTP_NOT_FOUND, response);
MHD_destroy_response (response);
return ret;
}
int tmp_ = 0;
if (interval_s) {
tmp_ = atoi(interval_s);
}
switch (tmp_) {
case 1800:
case 3600:
case 7200:
case 28800:
case 86400:
case 259200:
case 604800:
case 2592000:
case 7776000:
interval_i = tmp_;
break;
default:
break;
}
/*
if (valunit == NULL) {
valunit = (char *)"second";
}
if ( (strcmp(valunit,"second")) && (strcmp(valunit,"hour")) && (strcmp(valunit,"day")) ) {
response = MHD_create_response_from_buffer (strlen (EMPTY_PAGE), (void *) EMPTY_PAGE, MHD_RESPMEM_PERSISTENT);
ret = MHD_queue_response (connection, MHD_HTTP_NOT_FOUND, response);
MHD_destroy_response (response);
return ret;
}
if (valinterval == NULL) {
if ((strcmp(valunit,(char *)"second") == 0)) {
valinterval = (char *)"14400";
}
if ((strcmp(valunit,(char *)"hour") == 0)) {
valinterval = (char *)"720";
}
if ((strcmp(valunit,"day") == 0)) {
valinterval = (char *)"365";
}
}
*/
if (strcmp(valmetric,"system")==0) {
string *s = generate_header((char *)"ProxySQL Graphs");
char *buttons = generate_buttons((char *)"system");
s->append(buttons);
free(buttons);
s->append("<div class=\"graphs\" style=\"clear: both; height: auto;\">\n");
string *s1 = generate_canvas((char *)"myChart1");
s->append(s1->c_str());
s->append("<p></p>\n");
s1 = generate_canvas((char *)"myChart2");
s->append(s1->c_str());
s->append("<p></p>\n");
s1 = generate_canvas((char *)"myChart3");
s->append(s1->c_str());
s->append("<p></p>\n");
s1 = generate_canvas((char *)"myChart4");
s->append(s1->c_str());
s->append("</div>\n");
SQLite3_result *cpu_sqlite = GloProxyStats->get_system_cpu_metrics(interval_i);
#ifndef NOJEM
SQLite3_result *memory_sqlite = GloProxyStats->get_system_memory_metrics(interval_i);
#endif
char **nm = NULL;
char **nl = NULL;
char **nv = NULL;
char *ts = NULL;
nm = (char **)malloc(sizeof(char *)*2);
nm[0] = (char *)"utime";
nm[1] = (char *)"stime";
nl = (char **)malloc(sizeof(char *)*2);
nl[0] = (char *)"User Time";
nl[1] = (char *)"System Time";
nv = (char **)malloc(sizeof(char *)*2);
nv[0] = extract_values(cpu_sqlite,2,true,(double)1/sysconf(_SC_CLK_TCK));
nv[1] = extract_values(cpu_sqlite,3,true,(double)1/sysconf(_SC_CLK_TCK));
ts = extract_ts(cpu_sqlite,true);
s1 = generate_chart((char *)"myChart1",ts,2,nm,nl,nv);
s->append(s1->c_str());
free(nm);
free(nl);
free(nv[0]);
free(nv[1]);
free(nv);
free(ts);
#ifndef NOJEM
nm = (char **)malloc(sizeof(char *)*5);
nm[0] = (char *)"allocated";
nm[1] = (char *)"resident";
nm[2] = (char *)"active";
nm[3] = (char *)"mapped";
nm[4] = (char *)"metadata";
nl = (char **)malloc(sizeof(char *)*5);
nl[0] = (char *)"Allocated";
nl[1] = (char *)"Resident";
nl[2] = (char *)"Active";
nl[3] = (char *)"Mapped";
nl[4] = (char *)"Metadata";
nv = (char **)malloc(sizeof(char *)*5);
nv[0] = extract_values(memory_sqlite,2,false);
nv[1] = extract_values(memory_sqlite,3,false);
nv[2] = extract_values(memory_sqlite,4,false);
nv[3] = extract_values(memory_sqlite,5,false);
nv[4] = extract_values(memory_sqlite,6,false);
ts = extract_ts(cpu_sqlite,true);
s1 = generate_chart((char *)"myChart2",ts,5,nm,nl,nv);
s->append(s1->c_str());
free(nm);
free(nl);
free(nv[0]);
free(nv[1]);
free(nv[2]);
free(nv[3]);
free(nv[4]);
free(nv);
free(ts);
#endif
s->append("</body></html>");
response = MHD_create_response_from_buffer(s->length(), (void *) s->c_str(), MHD_RESPMEM_PERSISTENT);
ret = MHD_queue_response (connection, MHD_HTTP_OK, response);
MHD_destroy_response (response);
return ret;
}
if (strcmp(valmetric,"mysql")==0) {
string *s = generate_header((char *)"ProxySQL Graphs");
char *buttons = generate_buttons((char *)"mysql");
s->append(buttons);
free(buttons);
s->append("<div class=\"graphs\" style=\"clear: both; height: auto;\">\n");
string *s1 = generate_canvas((char *)"myChart1");
s->append(s1->c_str());
s->append("<p></p>\n");
s1 = generate_canvas((char *)"myChart2");
s->append(s1->c_str());
s->append("<p></p>\n");
s1 = generate_canvas((char *)"myChart3");
s->append(s1->c_str());
s->append("<p></p>\n");
s1 = generate_canvas((char *)"myChart4");
s->append(s1->c_str());
s->append("</div>\n");
char **nm = NULL;
char **nl = NULL;
char **nv = NULL;
char *ts = NULL;
SQLite3_result *mysql_metrics_sqlite = GloProxyStats->get_mysql_metrics(interval_i);
nm = (char **)malloc(sizeof(char *)*6);
nm[0] = (char *)"Client_Connections_aborted";
nm[1] = (char *)"Client_Connections_connected";
nm[2] = (char *)"Client_Connections_created";
nm[3] = (char *)"Server_Connections_aborted";
nm[4] = (char *)"Server_Connections_connected";
nm[5] = (char *)"Server_Connections_created";
nl = (char **)malloc(sizeof(char *)*6);
nl[0] = (char *)"Client Connections aborted";
nl[1] = (char *)"Client Connections connected";
nl[2] = (char *)"Client Connections created";
nl[3] = (char *)"Server Connections aborted";
nl[4] = (char *)"Server Connections connected";
nl[5] = (char *)"Server Connections created";
nv = (char **)malloc(sizeof(char *)*6);
nv[0] = extract_values(mysql_metrics_sqlite,2,true,(double)1);
nv[1] = extract_values(mysql_metrics_sqlite,3,false,(double)1);
nv[2] = extract_values(mysql_metrics_sqlite,4,true,(double)1);
nv[3] = extract_values(mysql_metrics_sqlite,5,true,(double)1);
nv[4] = extract_values(mysql_metrics_sqlite,6,false,(double)1);
nv[5] = extract_values(mysql_metrics_sqlite,7,true,(double)1);
ts = extract_ts(mysql_metrics_sqlite,true);
s1 = generate_chart((char *)"myChart1",ts,6,nm,nl,nv);
s->append(s1->c_str());
free(nm);
free(nl);
for (int aa=0 ; aa<6 ; aa++) {
free(nv[aa]);
}
free(nv);
free(ts);
nm = (char **)malloc(sizeof(char *)*6);
nm[0] = (char *)"ConnPool_get_conn_failure";
nm[1] = (char *)"ConnPool_get_conn_immediate";
nm[2] = (char *)"ConnPool_get_conn_success";
nm[3] = (char *)"Questions";
nm[4] = (char *)"Slow_queries";
nm[5] = (char *)"GTID_consistent_queries";
nl = (char **)malloc(sizeof(char *)*6);
nl[0] = (char *)"ConnPool failure";
nl[1] = (char *)"ConnPool immediate";
nl[2] = (char *)"ConnPool success";
nl[3] = (char *)"Questions";
nl[4] = (char *)"Slow Queries";
nl[5] = (char *)"GTID Consistent Queries";
nv = (char **)malloc(sizeof(char *)*6);
nv[0] = extract_values(mysql_metrics_sqlite,8,true);
nv[1] = extract_values(mysql_metrics_sqlite,9,true);
nv[2] = extract_values(mysql_metrics_sqlite,10,true);
nv[3] = extract_values(mysql_metrics_sqlite,11,true);
nv[4] = extract_values(mysql_metrics_sqlite,12,true);
nv[5] = extract_values(mysql_metrics_sqlite,13,true);
ts = extract_ts(mysql_metrics_sqlite,true);
s1 = generate_chart((char *)"myChart2",ts,6,nm,nl,nv);
s->append(s1->c_str());
free(nm);
free(nl);
for (int aa=0 ; aa<6 ; aa++) {
free(nv[aa]);
}
free(nv);
free(ts);
SQLite3_result *myhgm_metrics_sqlite = GloProxyStats->get_myhgm_metrics(interval_i);
nm = (char **)malloc(sizeof(char *)*5);
nm[0] = (char *)"MyHGM_myconnpoll_destroy";
nm[1] = (char *)"MyHGM_myconnpoll_get";
nm[2] = (char *)"MyHGM_myconnpoll_get_ok";
nm[3] = (char *)"MyHGM_myconnpoll_push";
nm[4] = (char *)"MyHGM_myconnpoll_reset";
nl = (char **)malloc(sizeof(char *)*5);
nl[0] = (char *)"MyHGM ConnPoll Destroy";
nl[1] = (char *)"MyHGM ConnPoll Get";
nl[2] = (char *)"MyHGM ConnPoll Get OK";
nl[3] = (char *)"MyHGM ConnPoll Push";
nl[4] = (char *)"MyHGM ConnPoll Reset";
nv = (char **)malloc(sizeof(char *)*5);
nv[0] = extract_values(myhgm_metrics_sqlite,2,true);
nv[1] = extract_values(myhgm_metrics_sqlite,3,true);
nv[2] = extract_values(myhgm_metrics_sqlite,4,true);
nv[3] = extract_values(myhgm_metrics_sqlite,5,true);
nv[4] = extract_values(myhgm_metrics_sqlite,6,true);
ts = extract_ts(myhgm_metrics_sqlite,true);
s1 = generate_chart((char *)"myChart3",ts,5,nm,nl,nv);
s->append(s1->c_str());
free(nm);
free(nl);
for (int aa=0 ; aa<5 ; aa++) {
free(nv[aa]);
}
free(nv);
free(ts);
s->append("</body></html>");
response = MHD_create_response_from_buffer(s->length(), (void *) s->c_str(), MHD_RESPMEM_MUST_COPY);
ret = MHD_queue_response (connection, MHD_HTTP_OK, response);
MHD_destroy_response (response);
delete s;
return ret;
}
if (strcmp(valmetric,"cache")==0) {
string *s = generate_header((char *)"ProxySQL Graphs");
char *buttons = generate_buttons((char *)"cache");
s->append(buttons);
free(buttons);
s->append("<div class=\"graphs\" style=\"clear: both; height: auto;\">\n");
string *s1 = generate_canvas((char *)"myChart1");
s->append(s1->c_str());
s->append("<p></p>\n");
s1 = generate_canvas((char *)"myChart2");
s->append(s1->c_str());
s->append("<p></p>\n");
s1 = generate_canvas((char *)"myChart3");
s->append(s1->c_str());
s->append("<p></p>\n");
s1 = generate_canvas((char *)"myChart4");
s->append(s1->c_str());
s->append("</div>\n");
SQLite3_result *mysql_metrics_sqlite = GloProxyStats->get_MySQL_Query_Cache_metrics(interval_i);
char **nm = NULL;
char **nl = NULL;
char **nv = NULL;
char *ts = NULL;
nm = (char **)malloc(sizeof(char *)*5);
nm[0] = (char *)"count_GET";
nm[1] = (char *)"count_GET_OK";
nm[2] = (char *)"count_SET";
nm[3] = (char *)"Entries_Purged";
nm[4] = (char *)"Entries_In_Cache";
nl = (char **)malloc(sizeof(char *)*5);
nl[0] = (char *)"Count GET";
nl[1] = (char *)"Count GET OK";
nl[2] = (char *)"Count SET";
nl[3] = (char *)"Entries Purged";
nl[4] = (char *)"Entries In Cache";
nv = (char **)malloc(sizeof(char *)*6);
nv[0] = extract_values(mysql_metrics_sqlite,2,true,(double)1);
nv[1] = extract_values(mysql_metrics_sqlite,3,true,(double)1);
nv[2] = extract_values(mysql_metrics_sqlite,4,true,(double)1);
nv[3] = extract_values(mysql_metrics_sqlite,7,true,(double)1);
nv[4] = extract_values(mysql_metrics_sqlite,8,false,(double)1);
ts = extract_ts(mysql_metrics_sqlite,true);
s1 = generate_chart((char *)"myChart1",ts,5,nm,nl,nv);
s->append(s1->c_str());
free(nm);
free(nl);
for (int aa=0 ; aa<5 ; aa++) {
free(nv[aa]);
}
free(nv);
free(ts);
nm = (char **)malloc(sizeof(char *)*3);
nm[0] = (char *)"bytes_IN";
nm[1] = (char *)"bytes_OUT";
nm[2] = (char *)"Memory_Bytes";
nl = (char **)malloc(sizeof(char *)*3);
nl[0] = (char *)"KB IN";
nl[1] = (char *)"KB OUT";
nl[2] = (char *)"QC size MB";
nv = (char **)malloc(sizeof(char *)*3);
nv[0] = extract_values(mysql_metrics_sqlite,5,true,(double)1/1024);
nv[1] = extract_values(mysql_metrics_sqlite,6,true,(double)1/1024);
nv[2] = extract_values(mysql_metrics_sqlite,9,false,(double)1/1024/1024);
ts = extract_ts(mysql_metrics_sqlite,true);
s1 = generate_chart((char *)"myChart2",ts,3,nm,nl,nv);
s->append(s1->c_str());
free(nm);
free(nl);
for (int aa=0 ; aa<3 ; aa++) {
free(nv[aa]);
}
free(nv);
free(ts);
s->append("</body></html>");
response = MHD_create_response_from_buffer(s->length(), (void *) s->c_str(), MHD_RESPMEM_MUST_COPY);
ret = MHD_queue_response (connection, MHD_HTTP_OK, response);
MHD_destroy_response (response);
delete s;
return ret;
}
}
if (strcmp(url,"/Chart.bundle.js")==0) {
response = MHD_create_response_from_buffer(strlen(Chart_bundle_js_c), Chart_bundle_js_c, MHD_RESPMEM_PERSISTENT);
ret = MHD_queue_response (connection, MHD_HTTP_OK, response);
MHD_destroy_response (response);
return ret;
}
if (strcmp(url,"/font-awesome.min.css")==0) {
response = MHD_create_response_from_buffer(strlen(font_awesome), font_awesome, MHD_RESPMEM_PERSISTENT);
ret = MHD_queue_response (connection, MHD_HTTP_OK, response);
MHD_destroy_response (response);
return ret;
}
if (strcmp(url,"/main-bundle.min.css")==0) {
response = MHD_create_response_from_buffer(strlen(main_bundle_min_css_c), main_bundle_min_css_c, MHD_RESPMEM_PERSISTENT);
ret = MHD_queue_response (connection, MHD_HTTP_OK, response);
MHD_destroy_response (response);
return ret;
}
if (strcmp(url,"/")==0) {
string *s = generate_header((char *)"ProxySQL Home");
char *home = generate_home();
s->append(home);
free(home);
s->append("</body></html>");
response = MHD_create_response_from_buffer(s->length(), (void *) s->c_str(), MHD_RESPMEM_MUST_COPY);
ret = MHD_queue_response (connection, MHD_HTTP_OK, response);
MHD_destroy_response (response);
delete s;
return ret;
}
response = MHD_create_response_from_buffer (strlen (EMPTY_PAGE), (void *) EMPTY_PAGE, MHD_RESPMEM_PERSISTENT);
ret = MHD_queue_response (connection, MHD_HTTP_NOT_FOUND, response);
MHD_destroy_response (response);
return ret;
}
string * ProxySQL_HTTP_Server::generate_header(char *s) {
string *a = new string();
a->append("<!DOCTYPE html><head>\n<title>");
a->append(s);
a->append("</title>\n");
a->append("<link rel=\"stylesheet\" href=\"https://fonts.googleapis.com/css?family=Source+Sans+Pro:300,400,400i,600,900|Fira+Mono\"/>\n");
a->append("<link rel=\"stylesheet\" href=\"/main-bundle.min.css\"/>\n");
a->append("<link rel=\"stylesheet\" href=\"/font-awesome.min.css\"/>\n");
a->append("<script src=\"/Chart.bundle.js\"></script>\n</head>\n<body style=\"background-color: white;\">\n");
a->append("<header class=\"header cf \" role=\"banner\">\n<a class=\"brand\" href=\"http://www.proxysql.com\"><span><strong>Proxy</strong>SQL</span>\n</a>");
return a;
}
string * ProxySQL_HTTP_Server::generate_canvas(char *s) {
string *a = new string();
a->append("<div class=\"wrapper\" style=\"width: 750px; height: 350px\"><canvas id=\"");
a->append(s);
a->append("\" width=\"700\" height=\"330\"></canvas></div>\n");
return a;
}
ProxySQL_HTTP_Server::ProxySQL_HTTP_Server() {
page_sec = 0;
cur_time = time(NULL);
last_check_version = 0;
pthread_mutex_init(&check_version_mutex,NULL);
variables.proxysql_latest_version = NULL;
}
ProxySQL_HTTP_Server::~ProxySQL_HTTP_Server() {
if (variables.proxysql_latest_version) {
free(variables.proxysql_latest_version);
variables.proxysql_latest_version = NULL;
}
}
string * ProxySQL_HTTP_Server::generate_chart(char *chart_name, char *ts, int nsets, char **dname, char **llabel, char **values) {
char *h=(char *)"0123456789abcdef";
string *ret= new string();
int i;
ret->append("<script>\n");
ret->append("var ts = ");
ret->append(ts);
ret->append("\n");
for (i=0;i<nsets;i++) {
ret->append("var ");
ret->append(dname[i]);
ret->append(" = ");
ret->append(values[i]);
ret->append("\n");
}
ret->append("var ctx = document.getElementById(\"");
ret->append(chart_name);
ret->append("\");\nvar ");
ret->append(chart_name);
ret->append(" = new Chart(ctx, { \n");
ret->append("type: 'line', \n");
ret->append(" data: { \n");
ret->append(" labels: ts,\n");
ret->append(" datasets: [ \n");
for (i=0;i<nsets;i++) {
ret->append(" {\n");
ret->append(" data: "); ret->append(dname[i]); ret->append(",\n");
ret->append(" label: \""); ret->append(llabel[i]); ret->append("\",\n");
int j;
char pal[7];
for (j=0; j<6; j++) { pal[j]=h[rand()%16]; }
pal[6]='\0';
ret->append(" borderColor: \"#"); ret->append(pal); ret->append("\",\n");
ret->append(" fill: false\n");
ret->append(" }");
if (i<nsets-1) {
ret->append(",");
}
ret->append("\n");
}
ret->append(" ]\n");
ret->append(" },\n");
ret->append("options: {\n");
ret->append(" scales: {\n");
ret->append(" xAxes: [{\n");
ret->append(" ticks: {\n");
// ret->append(" autoSkip: true,\n");
// ret->append(" maxRotation: 0,\n");
// ret->append(" minRotation: 0\n");
ret->append(" }\n");
ret->append(" }]\n");
ret->append(" }\n");
ret->append(" }\n");
ret->append("});\n");
ret->append("</script>\n");
return ret;
}