diff options
| author | arf20 <aruizfernandez05@gmail.com> | 2025-11-10 00:28:43 +0100 |
|---|---|---|
| committer | arf20 <aruizfernandez05@gmail.com> | 2025-11-10 00:28:43 +0100 |
| commit | 2ad586295dcd5dcef3d29af32998d55bb5c09843 (patch) | |
| tree | 8b4128ad080bfa063f36ffb2ccc28642a87f19fc | |
| parent | c766bf7134b8179401b7e05f00d5a3693e2b56f4 (diff) | |
| download | arfnet2-status-2ad586295dcd5dcef3d29af32998d55bb5c09843.tar.gz arfnet2-status-2ad586295dcd5dcef3d29af32998d55bb5c09843.zip | |
WIP api alert
| -rw-r--r-- | .gitignore | 1 | ||||
| -rw-r--r-- | Makefile | 2 | ||||
| -rw-r--r-- | alert.c | 166 | ||||
| -rw-r--r-- | alert.h | 10 | ||||
| -rw-r--r-- | config.c | 2 | ||||
| -rw-r--r-- | events.log | 2 | ||||
| -rw-r--r-- | main.c | 6 | ||||
| -rw-r--r-- | monitor.c | 12 | ||||
| -rw-r--r-- | monitor.cfg | 6 | ||||
| -rw-r--r-- | monitor.cfg.example | 27 |
10 files changed, 225 insertions, 9 deletions
@@ -1 +1,2 @@ monitor +monitor.cfg @@ -3,7 +3,7 @@ CFLAGS = -g -Wall -pedantic LDFLAGS = -lmicrohttpd -lcurl -lm BIN = monitor -SRC = main.c monitor.c config.c check.c +SRC = main.c monitor.c config.c check.c alert.c $(BIN): $(SRC) $(CC) -o $@ $(CFLAGS) $^ $(LDFLAGS) @@ -0,0 +1,166 @@ +#include "alert.h" + +#include "config.h" + +#include <curl/curl.h> + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +typedef enum { + TYPE_API, + TYPE_EMAIL +} alert_type_t; + +typedef struct { + alert_type_t type; + char *target; /* in api: endpoint, in email: address */ + char *extra; /* in api: Content-Type, in email: subject template */ + char *body_tmpl; +} alert_t; + +alert_t *alerts = NULL; +size_t alerts_size = 0, alerts_capacity = INIT_VEC_CAPACITY; + +static const char *type_str[] = { "api", "email" }; +static const char *status_str[] = { "down", "up" }; +static const char *from = NULL; + + +static size_t +write_data(void *ptr, size_t size, size_t nmemb, void *stream) +{ + return size * nmemb; +} + +static int +send_api(const target_t *target, const char *endpoint, const char *content_type, + const char *body_tmpl) +{ + static char buff[4096]; + + CURL *curl = curl_easy_init(); + if (!curl) { + fprintf(stderr, "Error allocating cURL handle\n"); + return -1; + } + + curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_data); + curl_easy_setopt(curl, CURLOPT_TIMEOUT, 1); + + curl_easy_setopt(curl, CURLOPT_URL, endpoint); + + struct curl_slist *list = NULL; + snprintf(buff, 256, "Content-Type: %s", content_type); + list = curl_slist_append(list, buff); /* copies */ + curl_easy_setopt(curl, CURLOPT_HTTPHEADER, list); + + snprintf(buff, 4096, body_tmpl, target->name, status_str[target->status]); + curl_easy_setopt(curl, CURLOPT_POSTFIELDS, buff); + + 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; +} + + +static int +send_email(const target_t *target, const char *address, const char *subject_tmpl, + const char *body_tmpl) +{ + +} + + +int +alert_init() +{ + alerts = malloc(INIT_VEC_CAPACITY * sizeof(alert_t)); + + from = alert_config.from; + + printf("alerts:\n"); + + char line[256]; + char *src_line = alert_config.alert_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; + + if (*line == '\n' || *line == '\0') + continue; + + char *type = strtok(line, ","); + char *target = strtok(NULL, ","); + char *extra = strtok(NULL, ","); + char *body_tmpl = strtok(NULL, ","); + + if (!type || !target) { + fprintf(stderr, "malformed config line: %s\n", line); + continue; + } + + if (strcmp(type, "api") == 0) + alerts[alerts_size].type = TYPE_API; + else if (strcmp(type, "email") == 0) + alerts[alerts_size].type = TYPE_EMAIL; + else { + fprintf(stderr, "unknown alert type: %s\n", line); + continue; + } + + alerts[alerts_size].target = strdup(target); + alerts[alerts_size].extra = strdup(extra); + alerts[alerts_size].body_tmpl = strdup(body_tmpl); + + printf("\t%s: %s\n", + alerts[alerts_size].target, + type_str[alerts[alerts_size].type] + ); + + alerts_size++; + } + + return alerts_size; +} + +void +alert_trigger(const target_t *target) +{ + static const int (*send_funcs[])(const target_t *, const char *, + const char *, const char *) = + { + send_api, + send_email + }; + + static char timestr[256]; + + time_t time_now = time(NULL); + struct tm *tm_now = gmtime(&time_now); + strftime(timestr, 256, "%F %T", tm_now); + + for (int i = 0; i < alerts_size; i++) { + printf("[%s] [monitor] alerted %s about %s\n", + timestr, alerts[i].target, target->name); + send_funcs[target->type](target, alerts[i].target, alerts[i].extra, + alerts[i].body_tmpl); + } +} + @@ -0,0 +1,10 @@ +#ifndef _ALERT_H +#define _ALERT_H + +#include "monitor.h" + +int alert_init(); +void alert_trigger(const target_t *target); + +#endif /* _ALERT_H */ + @@ -73,7 +73,7 @@ config_load(const char *conf_path) cfgsize - (target_pos - monitor_config.target_config), "%s", value); } else if (strcmp(line, "alert") == 0) { - target_pos += snprintf(alert_pos, + alert_pos += snprintf(alert_pos, cfgsize - (alert_pos - alert_config.alert_config), "%s", value); } else { @@ -76,3 +76,5 @@ 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 +http,2025-11-04T18:39:12Z,down +http,2025-11-04T18:40:12Z,up @@ -15,6 +15,7 @@ #include "monitor.h" #include "config.h" #include "check.h" +#include "alert.h" #define CFG_FILE "monitor.cfg" #define TMPL_FILE "index.htm.tmpl" @@ -95,7 +96,10 @@ int main() { if (check_init() < 0) return 1; - if (monitor_init(CFG_FILE, LOG_FILE) < 0) + if (monitor_init() < 0) + return 1; + + if (alert_init() < 0) return 1; /* start server */ @@ -24,7 +24,8 @@ typedef struct { } incident_t; -const char *type_str[] = { "reach", "dns", "web" }; +static const char *status_str[] = { "down", "up" }; +static const char *type_str[] = { "reach", "dns", "web" }; target_t *targets = NULL; size_t targets_size = 0, targets_capacity = INIT_VEC_CAPACITY; @@ -35,7 +36,6 @@ static size_t incidents_size = 0, incidents_capacity = 0; static char timestr[256]; -static char *status_str[] = { "down", "up" }; static void @@ -215,7 +215,7 @@ monitor_init() char *name = strtok(NULL, ","); char *target = strtok(NULL, ","); - if (!target || !name || !target) { + if (!type || !name || !target) { fprintf(stderr, "malformed config line: %s\n", line); continue; } @@ -226,6 +226,10 @@ monitor_init() targets[targets_size].type = TYPE_DNS; else if (strcmp(type, "web") == 0) targets[targets_size].type = TYPE_WEB; + else { + fprintf(stderr, "unknown target type: %s\n", line); + continue; + } targets[targets_size].name = strdup(name); targets[targets_size].target = strdup(target); @@ -246,7 +250,7 @@ monitor_init() ); targets_size++; - } + } incidents = malloc(sizeof(incident_t) * INIT_VEC_CAPACITY); incidents_capacity = INIT_VEC_CAPACITY; diff --git a/monitor.cfg b/monitor.cfg index 03ca7b1..226a88e 100644 --- a/monitor.cfg +++ b/monitor.cfg @@ -20,6 +20,8 @@ target=web,https,https://arf20.com from=status@arf20.com # what to alert -alert=api,https://arf20.com/%s -alert=email,arf20@arf20.com +# alert=api,<url>,<content-type>,<body template> +alert=api,https://arf20.com/%s,application/json,{"content":"%s is %s"} +# alert=email,<address>,<subject template>,<body template> +alert=email,arf20@arf20.com,%s is %s,%s is %s diff --git a/monitor.cfg.example b/monitor.cfg.example new file mode 100644 index 0000000..226a88e --- /dev/null +++ b/monitor.cfg.example @@ -0,0 +1,27 @@ +# Monitor config +# 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,<url>,<content-type>,<body template> +alert=api,https://arf20.com/%s,application/json,{"content":"%s is %s"} +# alert=email,<address>,<subject template>,<body template> +alert=email,arf20@arf20.com,%s is %s,%s is %s + |
