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

[PATCH 08/23] wip uptime


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

From: arf20 <aruizfernandez05@xxxxxxxxx>

---
 events.log     |   2 +
 index.htm.tmpl |   2 +-
 main.c         |   4 +-
 monitor.c      | 185 +++++++++++++++++++++++++++++++++++++++----------
 monitor.cfg    |   8 +--
 monitor.h      |   1 +
 6 files changed, 160 insertions(+), 42 deletions(-)

diff --git a/events.log b/events.log
index 3c3ddf5..1affe2b 100644
--- a/events.log
+++ b/events.log
@@ -71,4 +71,6 @@ http,2025-08-26 11:46:20,down
 http,2025-08-26 11:51:24,up
 http,2025-08-26 14:39:43,down
 http,2025-08-26 14:44:45,up
+http,2025-10-24 10:49:20,down
+http,2025-10-24 12:38:19,up
 
diff --git a/index.htm.tmpl b/index.htm.tmpl
index cf90884..6637f05 100644
--- a/index.htm.tmpl
+++ b/index.htm.tmpl
@@ -36,7 +36,7 @@ table, th, td {
             <br><br>
             Incidents
             <table>
-                <tr><th>Resolved</th><th>Started</th><th>Duration</th></tr>
+                <tr><th>Service</th><th>Resolved</th><th>Started</th><th>Duration</th></tr>
                 %s
             </table>
         </main>
diff --git a/main.c b/main.c
index fdfc5cd..8c0405f 100644
--- a/main.c
+++ b/main.c
@@ -40,7 +40,7 @@ enum MHD_Result answer_to_connection(
     time_t time_now = time(NULL);
     struct tm *tm_now = gmtime(&time_now);
     static char timestr[256];
-    strftime(timestr, 256, "%Y-%m-%d %H-%M-%S", tm_now);
+    strftime(timestr, 256, "%Y-%m-%d %H:%M:%S", tm_now);
 
     printf("[%s] [webserver] %s %s %s: ",
         timestr, inet_ntoa((*coninfo)->sin_addr), method, url);
@@ -51,7 +51,7 @@ enum MHD_Result answer_to_connection(
     if (strcmp(method, "GET") == 0 && strcmp(url, "/") == 0) {
         snprintf(buff, RES_BUFF,
             index_format_template,
-            monitor_generate_status_html(), "(incidents)");
+            monitor_generate_status_html(), monitor_generate_incidents_html());
 
         response = MHD_create_response_from_buffer(strlen(buff), (void*)buff,
             MHD_RESPMEM_PERSISTENT);
diff --git a/monitor.c b/monitor.c
index 41bcc61..e6165a3 100644
--- a/monitor.c
+++ b/monitor.c
@@ -38,25 +38,58 @@ typedef struct {
     status_t status;
 
     event_t *events;
-    size_t event_size, event_capacity;
+    size_t events_size, events_capacity;
 } target_t;
 
+/* baked */
+typedef struct {
+    time_t started_time;
+    time_t duration_time;
+    int resolved;
+    char *service;
+    char *started;
+    char *duration;
+} incident_t;
+
 
 static target_t targets[INIT_VEC_CAPACITY];
-static size_t target_n = 0;
+static size_t targets_n = 0;
 
+/* ordered*/
+static incident_t *incidents = NULL;
+static size_t incidents_size = 0, incidents_capacity = 0;
 
 static char timestr[256];
 
 
-
 static void
 target_events_push(target_t *target, event_t event)
 {
-    if (target->event_size + 1 > target->event_capacity)
-        target->events = realloc(target->events, 2 * target->event_capacity);
+    if (target->events_size + 1 > target->events_capacity)
+        target->events = realloc(target->events,
+            2 * sizeof(event_t) * target->events_capacity);
+
+    target->events[target->events_size++] = event;
+}
+
+static void
+incidents_push_ordered(const incident_t *incident)
+{
+    if (incidents_size + 1 > incidents_capacity)
+        incidents = realloc(incidents,
+            2 * sizeof(incident_t) * incidents_capacity);
+
+    size_t i = 0;
+    while (incidents[i].started_time < incident->started_time
+            && i < incidents_size)
+        i++;
+    /* incidents[i].started_time >= incident.started_time */
+    memmove(&incidents[i + 1], &incidents[i],
+        (incidents_size - i) * sizeof(incident_t));
 
-    target->events[target->event_size++] = event;
+    incidents[i] = *incident;
+
+    incidents_size++;
 }
 
 static size_t
@@ -91,7 +124,7 @@ target_events_load(target_t *target, const char *logbuff) {
             continue;
 
         struct tm event_time;
-        strptime(time, "%Y-%m-%d %H-%M-%S", &event_time);
+        strptime(time, "%Y-%m-%d %H:%M:%S", &event_time);
 
         event_t event = {
             mktime(&event_time),
@@ -106,6 +139,48 @@ target_events_load(target_t *target, const char *logbuff) {
     return n;
 }
 
+/* assume events start with down */
+void
+incidents_render()
+{
+    char buff[256];
+
+    for (size_t i = 0; i < targets_n; i++) {
+        /* iterate through downs */
+        for (size_t j = 0; j < targets[i].events_size; j++) {
+            if (targets[i].events[j].status != STATUS_DOWN)
+                continue;
+            /* next must be up */
+            int resolved = 1;
+            if (targets[i].events_size == j + 1 ||
+                    targets[i].events[j + 1].status != STATUS_UP)
+                resolved = 0;
+
+            time_t start = targets[i].events[j].time;
+            time_t duration = targets[i].events[j + 1].time - start;
+
+            snprintf(buff, 256, "%ldh %ldm %lds", duration / 3600,
+                (duration / 60) % 60, duration % 60);
+            char *durationstr = strdup(buff);
+
+            struct tm *tm_start = gmtime(&start);
+            strftime(buff, 256, "%Y-%m-%d %H:%M:%S", tm_start);
+            char *startstr = strdup(buff);
+
+            incident_t incident = {
+                targets[i].events[j].time,
+                duration,
+                resolved,
+                targets[i].name,
+                startstr,
+                durationstr
+            };
+
+            incidents_push_ordered(&incident);
+        }
+    }
+}
+
 int
 monitor_init(const char *cfg_path, const char *log_path) {
     /* read monitor log */
@@ -152,35 +227,41 @@ monitor_init(const char *cfg_path, const char *log_path) {
         }
 
         if (strcmp(type, "reach") == 0)
-            targets[target_n].type = TYPE_REACH;
+            targets[targets_n].type = TYPE_REACH;
         else if (strcmp(type, "dns") == 0)
-            targets[target_n].type = TYPE_DNS;
+            targets[targets_n].type = TYPE_DNS;
         else if (strcmp(type, "web") == 0)
-            targets[target_n].type = TYPE_WEB;
+            targets[targets_n].type = TYPE_WEB;
 
-        targets[target_n].name = strdup(name);
-        targets[target_n].target = strdup(target);
-        targets[target_n].status = STATUS_DOWN;
+        targets[targets_n].name = strdup(name);
+        targets[targets_n].target = strdup(target);
+        targets[targets_n].status = STATUS_DOWN;
 
         /* read monitor logs */
-        targets[target_n].event_capacity = INIT_VEC_CAPACITY;
-        targets[target_n].event_size = 0;
-        targets[target_n].events = malloc(INIT_VEC_CAPACITY * sizeof(event_t));
+        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));
 
-        size_t event_n = target_events_load(&targets[target_n], logbuff);
+        size_t event_n = target_events_load(&targets[targets_n], logbuff);
 
         printf("\t%s: %s,%s %ld events\n",
-            targets[target_n].name,
-            type_str[targets[target_n].type],
-            targets[target_n].target,
+            targets[targets_n].name,
+            type_str[targets[targets_n].type],
+            targets[targets_n].target,
             event_n
         );
         
-        target_n++;
+        targets_n++;
     } 
 
     fclose(cfgf);
 
+    incidents = malloc(sizeof(incident_t) * INIT_VEC_CAPACITY);
+    incidents_capacity = INIT_VEC_CAPACITY;
+    incidents_size = 0;
+
+    incidents_render();
+
     CURLcode res = curl_global_init(CURL_GLOBAL_ALL);
     if (res) {
         fprintf(stderr, "Error initializing cURL: %s\n",
@@ -188,7 +269,26 @@ monitor_init(const char *cfg_path, const char *log_path) {
         return -1;
     }
 
-        return 0;
+    return 0;
+}
+
+const char *
+target_uptime(const target_t *target)
+{
+    static char buff[256];
+
+    event_t last_event = target->events[target->events_size - 1];
+
+    if (last_event.status == STATUS_DOWN) {
+        snprintf(buff, 256, "-");
+        return buff;
+    }
+
+    time_t uptime = time(NULL) - last_event.time;
+    snprintf(buff, 256, "%ldd %ldh %ldm %lds",
+        uptime / (3600*24), (uptime / 3600) % 24, (uptime / 60) % 60, uptime % 60);
+
+    return buff;
 }
 
 const char *
@@ -203,15 +303,15 @@ monitor_generate_status_html()
    
     char *pos = buff;
 
-    for (size_t i = 0; i < target_n; i++) {
-        pos += snprintf(pos, BUFF_SIZE,
-            "<tr><td>%s</td><td>%s</td>%s<td></td><td>%s</td><td>%s</td>%s</tr>\n",
-            type_str[targets[i].type],
-            targets[i].target,
-            status_html[targets[i].status],
-            "",
-            "",
-            ""
+    for (size_t i = 0; i < targets_n; i++) {
+        pos += snprintf(pos, BUFF_SIZE - (pos - buff),
+            "<tr><td>%s</td><td>%s</td>%s<td>%s</td><td>%s</td><td>%s</td></tr>\n",
+            type_str[targets[i].type],          /* type */
+            targets[i].target,                  /* target */
+            status_html[targets[i].status],     /* status */
+            target_uptime(&targets[i]),         /* uptime */
+            "",                                 /* %up month */
+            ""                                  /* %up total */
         );
     }
 
@@ -223,8 +323,23 @@ const char *
 monitor_generate_incidents_html()
 {
     static char buff[BUFF_SIZE];
-   
-    snprintf(buff, BUFF_SIZE, "<tr><td></td><td></td><td></td></tr>");
+
+    static const char *resolvedstr[] = {
+        "unresolved",
+        "resolved"
+    };
+    
+    char *pos = buff;
+  
+    for (int i = incidents_size - 1; i >= 0; i--) {
+        pos += snprintf(pos, BUFF_SIZE - (pos - buff),
+            "<tr><td>%s</td><td>%s</td><td>%s</td><td>%s</td></tr>\n",
+            incidents[i].service,
+            resolvedstr[incidents[i].resolved],
+            incidents[i].started,
+            incidents[i].duration
+        );
+    }
 
     return buff;
 }
@@ -323,7 +438,7 @@ 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);
+    strftime(timestr, 256, "%Y-%m-%d %H:%M:%S", tm_now);
 
     static const int (*check_funcs[])(const char *) = {
         check_reach,
@@ -331,7 +446,7 @@ monitor_check()
         check_http
     };
 
-    for (size_t i = 0; i < target_n; i++) {
+    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);
diff --git a/monitor.cfg b/monitor.cfg
index ee4c4a1..cc85d17 100644
--- a/monitor.cfg
+++ b/monitor.cfg
@@ -1,7 +1,7 @@
 # Monitor config
 # type,name,target
-reach,ipv4,10.0.0.0
-dns,dns,arf20.co
-web,http,http://arf20.com:4321
-web,https,https://arf20.co
+reach,ipv4,2.59.235.35
+dns,dns,arf20.com
+web,http,http://arf20.com
+web,https,https://arf20.com
 
diff --git a/monitor.h b/monitor.h
index b9ab3c9..8c2529e 100644
--- a/monitor.h
+++ b/monitor.h
@@ -3,6 +3,7 @@
 
 int monitor_init(const char *cfg_file, const char *log_file);
 const char *monitor_generate_status_html();
+const char *monitor_generate_incidents_html();
 void monitor_check();
 
 #endif /* _MONITOR_H */
-- 
2.47.3


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