[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[PATCH 14/23] unified config, refactor, for alerts


MIME-Version: 1.0
Content-Transfer-Encoding: 8bit

From: arf20 <aruizfernandez05@xxxxxxxxx>

---
 Makefile       |   2 +-
 check.c        | 135 ++++++++++++++++++++++++++++
 check.h        |  10 +++
 config.c       |  90 +++++++++++++++++++
 config.h       |  37 ++++++++
 index.htm.tmpl |   4 +-
 main.c         |  35 +++++---
 monitor.c      | 235 ++++++++-----------------------------------------
 monitor.cfg    |  28 ++++--
 monitor.h      |  35 +++++++-
 10 files changed, 390 insertions(+), 221 deletions(-)
 create mode 100644 check.c
 create mode 100644 check.h
 create mode 100644 config.c
 create mode 100644 config.h

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/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 d262ac0..a587397 100644
--- a/main.c
+++ b/main.c
@@ -12,14 +12,9 @@
 
 #include <microhttpd.h>
 
-
-
 #include "monitor.h"
-
-#define RES_BUFF    65535
-
-
-#define PORT        8888
+#include "config.h"
+#include "check.h"
 
 #define CFG_FILE    "monitor.cfg"
 #define TMPL_FILE   "index.htm.tmpl"
@@ -37,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(
@@ -55,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);
@@ -76,6 +73,8 @@ enum MHD_Result answer_to_connection(
 }
 
 int main() {
+    printf("ARFNET Status Monitor (C) 2025 under GPLv3\n");
+
     /* read index template file */
     FILE *tf = fopen(TMPL_FILE, "r");
     if (!tf) {
@@ -90,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) {
@@ -103,12 +111,11 @@ int main() {
         return 1;
     }
 
-    monitor_init(CFG_FILE, LOG_FILE);
 
     while (1) {
-        monitor_check();
+        check_perform(targets, targets_size);
         monitor_update_events(LOG_FILE);
-        sleep(5);
+        sleep(monitor_config.interval);
     }
 }
 
diff --git a/monitor.c b/monitor.c
index c277752..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,46 +221,37 @@ 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;
 }
 
@@ -371,11 +335,6 @@ generate_timeline(const target_t *target, time_t since, time_t span)
 
     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,126 +439,10 @@ 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)
-{
-    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
-monitor_check()
-{
-    static size_t check_num = 0;
-    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++;
-}
-
 static void
 commit_event(const char *log_path, const target_t *target,
     const event_t *event)
 {
-    static char *status_str[] = {
-        "down",
-        "up"
-    };
-
     char buff[256];
 
     FILE *logf = fopen(log_path, "a");
@@ -619,19 +462,15 @@ commit_event(const char *log_path, const target_t *target,
     fclose(logf);
 }
 
+
 void
 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, "%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))
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@xxxxxxxxx
+
+# what to alert
+alert=api,https://arf20.com/%s
+alert=email,arf20@xxxxxxxxx
 
diff --git a/monitor.h b/monitor.h
index f9b1af3..35844cc 100644
--- a/monitor.h
+++ b/monitor.h
@@ -1,7 +1,40 @@
 #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();
-- 
2.47.3


References:
[arfnet2-status PATCH 00/23] First releasearf20 <arf20@xxxxxxxxx>