aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Makefile2
-rw-r--r--check.c135
-rw-r--r--check.h10
-rw-r--r--config.c90
-rw-r--r--config.h37
-rw-r--r--events.log4
-rw-r--r--index.htm.tmpl4
-rw-r--r--main.c39
-rw-r--r--monitor.c249
-rw-r--r--monitor.cfg28
-rw-r--r--monitor.h37
11 files changed, 421 insertions, 214 deletions
diff --git a/Makefile b/Makefile
index 94b4c37..292b32a 100644
--- a/Makefile
+++ b/Makefile
@@ -3,7 +3,7 @@ CFLAGS = -g -Wall -pedantic
LDFLAGS = -lmicrohttpd -lcurl -lm
BIN = monitor
-SRC = main.c monitor.c
+SRC = main.c monitor.c config.c check.c
$(BIN): $(SRC)
$(CC) -o $@ $(CFLAGS) $^ $(LDFLAGS)
diff --git a/check.c b/check.c
new file mode 100644
index 0000000..2bd599d
--- /dev/null
+++ b/check.c
@@ -0,0 +1,135 @@
+#include "check.h"
+
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+
+#include <curl/curl.h>
+
+static int
+check_reach(const char *target)
+{
+ static char ping_cmd[256];
+
+ snprintf(ping_cmd, 256, "ping -W1 -c1 %s > /dev/null", target);
+ /* i know */
+ if (system(ping_cmd) == 0) {
+ printf("reachable\n");
+ return STATUS_UP;
+ } else {
+ printf("unreachable\n");
+ return STATUS_DOWN;
+ }
+}
+
+static int
+check_dns(const char *name)
+{
+ static char dig_cmd[512];
+ static char cmd_out[256];
+
+ snprintf(dig_cmd, 512, "dig +nocookie +short %s NS", name);
+ FILE *pf = popen(dig_cmd, "r");
+ fread(cmd_out, 256, 1, pf);
+ pclose(pf);
+
+ if (*cmd_out == '\0') {
+ printf("no ns\n");
+ return STATUS_DOWN;
+ }
+
+ *strchr(cmd_out, '\n') = '\0';
+
+ snprintf(dig_cmd, 512, "dig +nocookie +short @%s %s A", cmd_out, name);
+ pf = popen(dig_cmd, "r");
+ fread(cmd_out, 256, 1, pf);
+ pclose(pf);
+
+ if (*cmd_out == '\0' || !isdigit(*cmd_out)) {
+ printf("no a: %s\n", cmd_out);
+ return STATUS_DOWN;
+ }
+
+ *strchr(cmd_out, '\n') = '\0';
+
+ printf("%s\n", cmd_out);
+
+ return STATUS_UP;
+}
+
+static size_t
+write_data(void *ptr, size_t size, size_t nmemb, void *stream)
+{
+ return size * nmemb;
+}
+
+static int
+check_http(const char *endpoint)
+{
+ CURL *curl = curl_easy_init();
+ if (!curl) {
+ fprintf(stderr, "Error allocating cURL handle\n");
+ return -1;
+ }
+
+ //curl_easy_setopt(curl, CURLOPT_NOPROGRESS, 1L);
+ curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_data);
+ curl_easy_setopt(curl, CURLOPT_TIMEOUT, 1);
+
+ curl_easy_setopt(curl, CURLOPT_URL, endpoint);
+ CURLcode curl_code = curl_easy_perform(curl);
+ if (curl_code != CURLE_OK) {
+ printf("curl_easy_perform() failed: %s\n",
+ curl_easy_strerror(curl_code));
+ return STATUS_DOWN;
+ }
+
+ long http_code;
+ curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &http_code);
+
+ curl_easy_cleanup(curl);
+
+ printf("%ld\n", http_code);
+
+ return http_code == 200 ? STATUS_UP : STATUS_DOWN;
+}
+
+void
+check_perform(target_t *targets, size_t targets_n)
+{
+ static size_t check_num = 0;
+ static char timestr[256];
+
+ time_t time_now = time(NULL);
+ struct tm *tm_now = gmtime(&time_now);
+ strftime(timestr, 256, "%F %T", tm_now);
+
+ static const int (*check_funcs[])(const char *) = {
+ check_reach,
+ check_dns,
+ check_http
+ };
+
+ for (size_t i = 0; i < targets_n; i++) {
+ printf("[%s] [monitor] check #%ld %s: ",
+ timestr, check_num, targets[i].name);
+ targets[i].status = check_funcs[targets[i].type](targets[i].target);
+ }
+
+ check_num++;
+}
+
+int
+check_init()
+{
+ CURLcode res = curl_global_init(CURL_GLOBAL_ALL);
+ if (res) {
+ fprintf(stderr, "Error initializing cURL: %s\n",
+ curl_easy_strerror(res));
+ return -1;
+ }
+
+ return 0;
+}
+
+
diff --git a/check.h b/check.h
new file mode 100644
index 0000000..9e95c6f
--- /dev/null
+++ b/check.h
@@ -0,0 +1,10 @@
+#ifndef _CHECK_H
+#define _CHECK_H
+
+#include "monitor.h"
+
+void check_perform(target_t *targets, size_t targets_n);
+int check_init();
+
+#endif /* _CHECK_H */
+
diff --git a/config.c b/config.c
new file mode 100644
index 0000000..35fa90e
--- /dev/null
+++ b/config.c
@@ -0,0 +1,90 @@
+#include "config.h"
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+
+unsigned short port = DEFAULT_PORT;
+char *log_path = DEFAULT_LOG_PATH;
+monitor_config_t monitor_config = { .interval = DEFAULT_INTERVAL };
+alert_config_t alert_config;
+
+int
+config_load(const char *conf_path)
+{
+ FILE *cfgf = fopen(conf_path, "r");
+ if (!cfgf) {
+ fprintf(stderr, "Error opening config: %s\n", strerror(errno));
+ return -1;
+ }
+
+ fseek(cfgf , 0, SEEK_END);
+ size_t cfgsize = ftell(cfgf);
+ rewind(cfgf);
+
+ monitor_config.target_config = malloc(cfgsize);
+ alert_config.alert_config = malloc(cfgsize);
+
+ char *target_pos = monitor_config.target_config;
+ char *alert_pos = alert_config.alert_config;
+
+ printf("config:\n");
+
+ char line[256];
+ while (fgets(line, sizeof(line), cfgf)) {
+ if (*line == '#' || *line == '\n')
+ continue;
+
+ char *separator = strchr(line, '=');
+ if (!separator) {
+ fprintf(stderr, "[config] malformed line: %s\n", line);
+ continue;
+ }
+
+ *separator = '\0';
+
+ char *value = separator + 1;
+
+ if (strcmp(line, "port") == 0) {
+ port = atoi(value);
+ printf("\tport: %d\n", port);
+ if (port == 0) {
+ fprintf(stderr, "[config] invalid port: %s\n", line);
+ return -1;
+ }
+ } else if (strcmp(line, "interval") == 0) {
+ monitor_config.interval = atoi(value);
+ printf("\tinterval: %ld\n", monitor_config.interval);
+ if (monitor_config.interval == 0) {
+ fprintf(stderr, "[config] invalid interval: %s\n", line);
+ return -1;
+ }
+ } else if (strcmp(line, "log") == 0) {
+ value[strlen(value) - 1] = '\0';
+ log_path = strdup(value);
+ printf("\tlog path: %s\n", log_path);
+ } else if (strcmp(line, "from") == 0) {
+ value[strlen(value) - 1] = '\0';
+ alert_config.from = strdup(value);
+ printf("\tfrom: %s\n", log_path);
+ } else if (strcmp(line, "target") == 0) {
+ target_pos += snprintf(target_pos,
+ cfgsize - (target_pos - monitor_config.target_config),
+ "%s", value);
+ } else if (strcmp(line, "alert") == 0) {
+ target_pos += snprintf(alert_pos,
+ cfgsize - (alert_pos - alert_config.alert_config),
+ "%s", value);
+ } else {
+ fprintf(stderr, "[config] unknown key: %s\n", line);
+ continue;
+ }
+
+ }
+
+ fclose(cfgf);
+
+ return 0;
+}
+
diff --git a/config.h b/config.h
new file mode 100644
index 0000000..dbcfb97
--- /dev/null
+++ b/config.h
@@ -0,0 +1,37 @@
+#ifndef _CONFIG_H
+#define _CONFIG_H
+
+#include <time.h>
+
+
+#define BUFF_SIZE 65535
+#define INIT_VEC_CAPACITY 256
+#define CONFIG_PATH "monitor.cfg"
+
+#define DEFAULT_PORT 8888
+#define DEFAULT_INTERVAL 60
+#define DEFAULT_LOG_PATH "events.log"
+
+/* config types */
+typedef struct {
+ time_t interval;
+ char *target_config;
+} monitor_config_t;
+
+typedef struct {
+ char *from;
+ char *alert_config;
+} alert_config_t;
+
+
+/* config objects */
+extern unsigned short port;
+extern char *log_path;
+extern monitor_config_t monitor_config;
+extern alert_config_t alert_config;
+
+
+int config_load(const char *conf_path);
+
+#endif /* _CONFIG_H */
+
diff --git a/events.log b/events.log
index 85c4116..d74a182 100644
--- a/events.log
+++ b/events.log
@@ -73,4 +73,6 @@ http,2025-08-26T14:39:43Z,down
http,2025-08-26T14:44:45Z,up
http,2025-10-24T10:49:20Z,down
http,2025-10-24T12:38:19Z,up
-
+ipv4,2025-10-27T15:43:17+0000,up
+dns,2025-10-27T15:43:17+0000,up
+https,2025-10-27T15:43:17+0000,up
diff --git a/index.htm.tmpl b/index.htm.tmpl
index 1c5f13a..3278b39 100644
--- a/index.htm.tmpl
+++ b/index.htm.tmpl
@@ -44,9 +44,9 @@ td.w-last {
<main>
<h2 class="center">Status Monitor</h2>
<p>This webapp monitors the status of the main ARFNET services from outside the ARFNET network</p>
- Services
+ <span>Services</span><span style="float: right;">Current time (UTC): %s</span>
<table width="100%">
- <tr><th>Type</th><th>Service</th><th>Status</th><th>Uptime</th><th>%%up month</th><th>%%up total</th><th>Timeline</th></tr>
+ <tr><th>Type</th><th>Service</th><th>Status</th><th>Uptime</th><th>%%up month</th><th>%%up total</th><th>Timeline (week)</th></tr>
%s
</table>
<br><br>
diff --git a/main.c b/main.c
index 197d1b2..a587397 100644
--- a/main.c
+++ b/main.c
@@ -12,12 +12,13 @@
#include <microhttpd.h>
-
-
#include "monitor.h"
+#include "config.h"
+#include "check.h"
-#define PORT 8888
-#define RES_BUFF 65535
+#define CFG_FILE "monitor.cfg"
+#define TMPL_FILE "index.htm.tmpl"
+#define LOG_FILE "events.log"
static char *index_format_template = NULL;
@@ -31,7 +32,7 @@ enum MHD_Result answer_to_connection(
size_t *upload_data_size,
void **ptr
) {
- char buff[RES_BUFF];
+ char buff[BUFF_SIZE];
const struct sockaddr_in **coninfo =
(const struct sockaddr_in**)MHD_get_connection_info(
@@ -49,9 +50,11 @@ enum MHD_Result answer_to_connection(
int ret;
if (strcmp(method, "GET") == 0 && strcmp(url, "/") == 0) {
- snprintf(buff, RES_BUFF,
+ snprintf(buff, BUFF_SIZE,
index_format_template,
- monitor_generate_status_html(), monitor_generate_incidents_html());
+ timestr,
+ monitor_generate_status_html(),
+ monitor_generate_incidents_html());
response = MHD_create_response_from_buffer(strlen(buff), (void*)buff,
MHD_RESPMEM_PERSISTENT);
@@ -70,8 +73,10 @@ enum MHD_Result answer_to_connection(
}
int main() {
+ printf("ARFNET Status Monitor (C) 2025 under GPLv3\n");
+
/* read index template file */
- FILE *tf = fopen("index.htm.tmpl", "r");
+ FILE *tf = fopen(TMPL_FILE, "r");
if (!tf) {
fprintf(stderr, "error opening index template file: %s\n",
strerror(errno));
@@ -84,12 +89,21 @@ int main() {
fread(index_format_template, 1, tfs, tf);
fclose(tf);
+ if (config_load(CONFIG_PATH) < 0)
+ return 1;
+
+ if (check_init() < 0)
+ return 1;
+
+ if (monitor_init(CFG_FILE, LOG_FILE) < 0)
+ return 1;
+
/* start server */
struct MHD_Daemon *daemon;
daemon = MHD_start_daemon(
MHD_USE_INTERNAL_POLLING_THREAD | MHD_USE_EPOLL,
- PORT, NULL, NULL,
+ port, NULL, NULL,
&answer_to_connection, NULL, MHD_OPTION_END);
if (!daemon) {
@@ -97,12 +111,11 @@ int main() {
return 1;
}
- monitor_init("monitor.cfg", "events.log");
while (1) {
- monitor_check();
- monitor_update_events();
- sleep(5);
+ check_perform(targets, targets_size);
+ monitor_update_events(LOG_FILE);
+ sleep(monitor_config.interval);
}
}
diff --git a/monitor.c b/monitor.c
index d47238d..5d34824 100644
--- a/monitor.c
+++ b/monitor.c
@@ -8,41 +8,10 @@
#include <math.h>
#include <sys/param.h>
-#include <curl/curl.h>
-
#include "monitor.h"
-#define BUFF_SIZE 65535
-#define INIT_VEC_CAPACITY 256
-
-typedef enum {
- TYPE_REACH,
- TYPE_DNS,
- TYPE_WEB
-} type_t;
-
-const char *type_str[] = { "reach", "dns", "web" };
-
-typedef enum {
- STATUS_DOWN,
- STATUS_UP
-} status_t;
-
-typedef struct {
- time_t time;
- status_t status;
-} event_t;
-
-typedef struct {
- type_t type;
- char *name;
- char *target;
-
- status_t status, status_1;
+#include "config.h"
- event_t *events;
- size_t events_size, events_capacity;
-} target_t;
/* baked */
typedef struct {
@@ -55,8 +24,10 @@ typedef struct {
} incident_t;
-static target_t targets[INIT_VEC_CAPACITY];
-static size_t targets_n = 0;
+const char *type_str[] = { "reach", "dns", "web" };
+
+target_t *targets = NULL;
+size_t targets_size = 0, targets_capacity = INIT_VEC_CAPACITY;
/* ordered*/
static incident_t *incidents = NULL;
@@ -64,6 +35,8 @@ static size_t incidents_size = 0, incidents_capacity = 0;
static char timestr[256];
+static char *status_str[] = { "down", "up" };
+
static void
target_events_push_ordered(target_t *target, const event_t *event)
@@ -161,7 +134,7 @@ incidents_render()
incidents_size = 0;
- for (size_t i = 0; i < targets_n; i++) {
+ for (size_t i = 0; i < targets_size; i++) {
/* iterate through downs */
for (size_t j = 0; j < targets[i].events_size; j++) {
if (targets[i].events[j].status != STATUS_DOWN)
@@ -200,8 +173,10 @@ incidents_render()
}
int
-monitor_init(const char *cfg_path, const char *log_path)
+monitor_init()
{
+ targets = malloc(INIT_VEC_CAPACITY * sizeof(target_t));
+
/* read monitor log */
FILE *logf = fopen(log_path, "r");
if (!logf) {
@@ -220,23 +195,21 @@ monitor_init(const char *cfg_path, const char *log_path)
logbuff[logread] = '\0';
- /* read monitoring configuration */
- FILE *cfgf = fopen(cfg_path, "r");
- if (!cfgf) {
- fprintf(stderr, "Error opening config: %s\n", strerror(errno));
- return -1;
- }
-
printf("monitor targets:\n");
tzset(); /* initialize tz conversion */
char line[256];
- while (fgets(line, sizeof(line), cfgf)) {
- if (*line == '#' || *line == '\n')
- continue;
+ char *src_line = monitor_config.target_config;
+ while (src_line != (void*)1) {
+ char *next_line = strchr(src_line, '\n');
+ size_t linelen = next_line ? next_line - src_line : strlen(src_line);
+ strncpy(line, src_line, linelen);
+ line[linelen] = '\0';
+ src_line = next_line + 1;
- line[strlen(line) - 1] = '\0'; /* strip \n */
+ if (*line == '\n' || *line == '\0')
+ continue;
char *type = strtok(line, ",");
char *name = strtok(NULL, ",");
@@ -248,50 +221,41 @@ monitor_init(const char *cfg_path, const char *log_path)
}
if (strcmp(type, "reach") == 0)
- targets[targets_n].type = TYPE_REACH;
+ targets[targets_size].type = TYPE_REACH;
else if (strcmp(type, "dns") == 0)
- targets[targets_n].type = TYPE_DNS;
+ targets[targets_size].type = TYPE_DNS;
else if (strcmp(type, "web") == 0)
- targets[targets_n].type = TYPE_WEB;
+ targets[targets_size].type = TYPE_WEB;
- targets[targets_n].name = strdup(name);
- targets[targets_n].target = strdup(target);
- targets[targets_n].status = STATUS_DOWN;
+ targets[targets_size].name = strdup(name);
+ targets[targets_size].target = strdup(target);
+ targets[targets_size].status = STATUS_DOWN;
/* read monitor logs */
- targets[targets_n].events_capacity = INIT_VEC_CAPACITY;
- targets[targets_n].events_size = 0;
- targets[targets_n].events = malloc(INIT_VEC_CAPACITY * sizeof(event_t));
+ targets[targets_size].events_capacity = INIT_VEC_CAPACITY;
+ targets[targets_size].events_size = 0;
+ targets[targets_size].events = malloc(INIT_VEC_CAPACITY * sizeof(event_t));
- size_t event_n = target_events_load(&targets[targets_n], logbuff);
+ size_t event_n = target_events_load(&targets[targets_size], logbuff);
printf("\t%s: %s,%s %ld events\n",
- targets[targets_n].name,
- type_str[targets[targets_n].type],
- targets[targets_n].target,
+ targets[targets_size].name,
+ type_str[targets[targets_size].type],
+ targets[targets_size].target,
event_n
);
- targets_n++;
+ targets_size++;
}
- fclose(cfgf);
-
incidents = malloc(sizeof(incident_t) * INIT_VEC_CAPACITY);
incidents_capacity = INIT_VEC_CAPACITY;
incidents_size = 0;
- CURLcode res = curl_global_init(CURL_GLOBAL_ALL);
- if (res) {
- fprintf(stderr, "Error initializing cURL: %s\n",
- curl_easy_strerror(res));
- return -1;
- }
-
return 0;
}
-const char *
+static const char *
target_uptime(const target_t *target)
{
static char buff[256];
@@ -315,7 +279,7 @@ target_uptime(const target_t *target)
return buff;
}
-float
+static float
target_perc_uptime_since(const target_t *target, time_t since)
{
time_t downtime = 0;
@@ -340,7 +304,7 @@ target_perc_uptime_since(const target_t *target, time_t since)
return 1.0f - ((float)downtime / (float)(time(NULL) - since));
}
-float
+static float
target_perc_uptime_total(const target_t *target)
{
time_t downtime = 0, since = 0;
@@ -358,24 +322,19 @@ target_perc_uptime_total(const target_t *target)
return 1.0f - ((float)downtime / (float)(time(NULL) - since));
}
-int
+static int
color_map(float perc)
{
return 255.0f*exp2f(100.0f*perc-100.0f);
}
-const char *
+static const char *
generate_timeline(const target_t *target, time_t since, time_t span)
{
static char buff[BUFF_SIZE];
char *pos = buff;
- static char *status_str[] = {
- "down",
- "up"
- };
-
pos += snprintf(pos, BUFF_SIZE - (pos - buff),
"<table class=\"graph\" style=\"width:100%%;\"><tr>");
@@ -428,7 +387,7 @@ monitor_generate_status_html()
char *pos = buff;
- for (size_t i = 0; i < targets_n; i++) {
+ for (size_t i = 0; i < targets_size; i++) {
float perc_month = target_perc_uptime_since(&targets[i],
time(NULL) - (30*24*3600));
float perc_total = target_perc_uptime_total(&targets[i]);
@@ -480,130 +439,38 @@ monitor_generate_incidents_html()
return buff;
}
-static int
-check_reach(const char *target)
-{
- static char ping_cmd[256];
-
- snprintf(ping_cmd, 256, "ping -W1 -c1 %s > /dev/null", target);
- /* i know */
- if (system(ping_cmd) == 0) {
- printf("reachable\n");
- return STATUS_UP;
- } else {
- printf("unreachable\n");
- return STATUS_DOWN;
- }
-}
-
-static int
-check_dns(const char *name)
-{
- static char dig_cmd[512];
- static char cmd_out[256];
-
- snprintf(dig_cmd, 512, "dig +nocookie +short %s NS", name);
- FILE *pf = popen(dig_cmd, "r");
- fread(cmd_out, 256, 1, pf);
- pclose(pf);
-
- if (*cmd_out == '\0') {
- printf("no ns\n");
- return STATUS_DOWN;
- }
-
- *strchr(cmd_out, '\n') = '\0';
-
- snprintf(dig_cmd, 512, "dig +nocookie +short @%s %s A", cmd_out, name);
- pf = popen(dig_cmd, "r");
- fread(cmd_out, 256, 1, pf);
- pclose(pf);
-
- if (*cmd_out == '\0' || !isdigit(*cmd_out)) {
- printf("no a: %s\n", cmd_out);
- return STATUS_DOWN;
- }
-
- *strchr(cmd_out, '\n') = '\0';
-
- printf("%s\n", cmd_out);
-
- return STATUS_UP;
-}
-
-static size_t
-write_data(void *ptr, size_t size, size_t nmemb, void *stream)
-{
- return size * nmemb;
-}
-
-static int
-check_http(const char *endpoint)
+static void
+commit_event(const char *log_path, const target_t *target,
+ const event_t *event)
{
- CURL *curl = curl_easy_init();
- if (!curl) {
- fprintf(stderr, "Error allocating cURL handle\n");
- return -1;
- }
-
- //curl_easy_setopt(curl, CURLOPT_NOPROGRESS, 1L);
- curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_data);
- curl_easy_setopt(curl, CURLOPT_TIMEOUT, 1);
+ char buff[256];
- curl_easy_setopt(curl, CURLOPT_URL, endpoint);
- CURLcode curl_code = curl_easy_perform(curl);
- if (curl_code != CURLE_OK) {
- printf("curl_easy_perform() failed: %s\n",
- curl_easy_strerror(curl_code));
- return STATUS_DOWN;
+ FILE *logf = fopen(log_path, "a");
+ if (!logf) {
+ fprintf(stderr,
+ "Error opening log file for writing: %s\n", strerror(errno));
+ return;
}
- long http_code;
- curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &http_code);
- curl_easy_cleanup(curl);
+ struct tm *tm_event = gmtime(&event->time);
+ strftime(buff, 256, "%FT%T%z", tm_event);
- printf("%ld\n", http_code);
+ fprintf(logf, "%s,%s,%s\n",
+ target->name, buff, status_str[event->status]);
- return http_code == 200 ? STATUS_UP : STATUS_DOWN;
+ fclose(logf);
}
-void
-monitor_check()
-{
- static size_t check_num = 0;
- time_t time_now = time(NULL);
- struct tm *tm_now = gmtime(&time_now);
- strftime(timestr, 256, "%Y-%m-%d %H:%M:%S", tm_now);
-
- static const int (*check_funcs[])(const char *) = {
- check_reach,
- check_dns,
- check_http
- };
-
- for (size_t i = 0; i < targets_n; i++) {
- printf("[%s] [monitor] check #%ld %s: ",
- timestr, check_num, targets[i].name);
- targets[i].status = check_funcs[targets[i].type](targets[i].target);
- }
-
- check_num++;
-}
void
-monitor_update_events()
+monitor_update_events(const char *log_path)
{
- static char *status_str[] = {
- "down",
- "up"
- };
-
time_t time_now = time(NULL);
struct tm *tm_now = gmtime(&time_now);
- strftime(timestr, 256, "%Y-%m-%d %H:%M:%S", tm_now);
+ strftime(timestr, 256, "%F %T", tm_now);
- for (size_t i = 0; i < targets_n; i++) {
+ for (size_t i = 0; i < targets_size; i++) {
if (targets[i].events_size > 0 && (
targets[i].status ==
targets[i].events[targets[i].events_size - 1].status))
@@ -623,6 +490,8 @@ monitor_update_events()
target_events_push_ordered(&targets[i], &event);
+ commit_event(log_path, &targets[i], &event);
+
printf("[%s] [monitor] %s is now %s\n",
timestr, targets[i].name, status_str[targets[i].status]);
diff --git a/monitor.cfg b/monitor.cfg
index cc85d17..03ca7b1 100644
--- a/monitor.cfg
+++ b/monitor.cfg
@@ -1,7 +1,25 @@
# Monitor config
-# type,name,target
-reach,ipv4,2.59.235.35
-dns,dns,arf20.com
-web,http,http://arf20.com
-web,https,https://arf20.com
+# target=type,name,target
+
+# listen port
+port=8888
+
+# monitor interval in seconds (sleep)
+interval=5
+
+# monitor events log path
+log=events.log
+
+# targets to monitor
+target=reach,ipv4,2.59.235.35
+target=dns,dns,arf20.com
+target=web,http,http://arf20.com
+target=web,https,https://arf20.com
+
+# email From
+from=status@arf20.com
+
+# what to alert
+alert=api,https://arf20.com/%s
+alert=email,arf20@arf20.com
diff --git a/monitor.h b/monitor.h
index 198908e..35844cc 100644
--- a/monitor.h
+++ b/monitor.h
@@ -1,10 +1,43 @@
#ifndef _MONITOR_H
#define _MONITOR_H
-int monitor_init(const char *cfg_file, const char *log_file);
+#include <time.h>
+
+typedef enum {
+ TYPE_REACH,
+ TYPE_DNS,
+ TYPE_WEB
+} type_t;
+
+typedef enum {
+ STATUS_DOWN,
+ STATUS_UP
+} status_t;
+
+typedef struct {
+ time_t time;
+ status_t status;
+} event_t;
+
+typedef struct {
+ type_t type;
+ char *name;
+ char *target;
+
+ status_t status, status_1;
+
+ event_t *events;
+ size_t events_size, events_capacity;
+} target_t;
+
+
+extern target_t *targets;
+extern size_t targets_size;
+
+int monitor_init();
const char *monitor_generate_status_html();
const char *monitor_generate_incidents_html();
void monitor_check();
-void monitor_update_events();
+void monitor_update_events(const char *log_path);
#endif /* _MONITOR_H */