From 891e4a2cc395e9c9e638218cb25d64bfb78a6bb9 Mon Sep 17 00:00:00 2001 From: Raj Nandan Sharma Date: Mon, 4 Dec 2023 13:57:20 +0530 Subject: [PATCH] adding docs --- config/monitors.bk.yaml | 47 ++++++++++ scripts/startup.js | 3 +- src/app.html | 1 + src/lib/docs/docs.md | 174 ++++++++++++++++++++++++++++++++++- src/routes/docs/+page.svelte | 71 +++++++------- 5 files changed, 257 insertions(+), 39 deletions(-) create mode 100644 config/monitors.bk.yaml diff --git a/config/monitors.bk.yaml b/config/monitors.bk.yaml new file mode 100644 index 0000000..9e24c5c --- /dev/null +++ b/config/monitors.bk.yaml @@ -0,0 +1,47 @@ +- name: Google Search + description: Google Search + tag: "create-order" + method: POST + url: https://sandbox.cashfree.com/pg/orders + headers: + Content-Type: application/json + x-client-id: $X_CLIENT_ID + x-client-secret: $X_CLIENT_SECRET + x-api-version: '2022-09-01' + body: '{"order_amount":22222.1,"order_currency":"INR","customer_details":{"customer_id":"4091284194","customer_email":"statuspage@example.com","customer_phone":"9876543210"}}' +- name: GET Order + description: Some description + tag: "get-order" + method: POST + url: https://sandbox.cashfree.com/pg/orders/$ORDER_ID + headers: + Content-Type: application/json + x-client-id: $X_CLIENT_ID + x-client-secret: $X_CLIENT_SECRET + x-api-version: '2022-09-01' + eval: | + (function(statusCode, responseTime, responseDataBase64){ + const resp = JSON.parse(atob(responseDataBase64)); + return { + status: statusCode == 200 ? 'UP':'DOWN', + latency: latency, + } + }) +- name: GET Order Payments + description: Some description + method: POST + tag: "get-order-payments" + url: https://sandbox.cashfree.com/pg/orders/$ORDER_ID/payments + headers: + Content-Type: application/json + x-client-id: $X_CLIENT_ID + x-client-secret: $X_CLIENT_SECRET + x-api-version: '2022-09-01' + eval: | + (function(statusCode, responseTime, responseDataBase64){ + const resp = JSON.parse(atob(responseDataBase64)); + return { + status: statusCode == 200 ? 'UP':'DOWN', + latency: latency, + } + }) \ No newline at end of file diff --git a/scripts/startup.js b/scripts/startup.js index 3e2c00b..b596c04 100644 --- a/scripts/startup.js +++ b/scripts/startup.js @@ -14,8 +14,7 @@ import * as cheerio from "cheerio"; let monitors = []; let site = {}; const envSecrets = []; -const defaultEval = ` -(function (statusCode, responseTime, responseData) { +const defaultEval = `(function (statusCode, responseTime, responseData) { let statusCodeShort = Math.floor(statusCode/100); if(statusCodeShort >=2 && statusCodeShort <= 3) { return { diff --git a/src/app.html b/src/app.html index a9729f6..8063f4b 100644 --- a/src/app.html +++ b/src/app.html @@ -2,6 +2,7 @@ + %sveltekit.head% diff --git a/src/lib/docs/docs.md b/src/lib/docs/docs.md index 0718998..b73e878 100644 --- a/src/lib/docs/docs.md +++ b/src/lib/docs/docs.md @@ -14,10 +14,22 @@ npm install npm run kener ``` +## Folder structure + +``` +├── src (svelte frontend files) +├── static (things put here can be referenced directly example static/logo.png -> /logo.png) +├── scripts (nodejs server files) +├── config +│ ├── site.yaml (to personalize your kener instance) +│ ├── monitors.yaml (to add monitors) + +``` + Kener would be running at PORT 3000. Go to [http://localhost:3000](http://localhost:3000) ![alt text](ss.png "SS") - +--- # Modify Site There is a folder called `/config`. Inside which there is a `site.yaml` file. You can modify this file to have your own branding. @@ -128,17 +140,175 @@ nav: url: "/home" ``` ![alt text](ss3.png "SS") +--- # Add Monitors Inside `config/` folder there is a file called `monitors.yaml`. We will be adding our monitors here. Please note that your yaml must be valid. It is an array. -## A Simple GET Monitor +Sample ```yaml - name: Google Search description: Search the world's information, including webpages, images, videos and more. tag: "google-search" image: "/google.png" + cron: "* * * * *" + method: POST + url: https://www.google.com/webhp + headers: + Content-Type: application/json + body: '{"order_amount":1,"order_currency":"INR"}' + eval: | + (function(statusCode, responseTime, responseDataBase64){ + const resp = JSON.parse(atob(responseDataBase64)); + return { + status: statusCode == 200 ? 'UP':'DOWN', + latency: responseTime, + } + }) +``` + +| Parameter Name | Usage | Description | +| ----------- | ----------------- | --------------------------------------------------------------------------------------------------------- | +| name | Required + Unique | This will be shown in the UI to your users. Keep it short and unique | +| description | Optional | This will be show below your name | +| tag | Required + Unique | This is used to tag incidents created in Github using comments | +| image | Optional | To show a logo before the name | +| cron | Optional | Use cron expression to specify the interval to run the monitors. Defaults to `* * * * *` i.e every minute | +| method | Optional | HTTP Method | +| url | Optional | HTTP URL | +| headers | Optional | HTTP headers | +| body | Optional | HTTP Body as string | +| eval | Optional | Evaluator written in JS, to parse HTTP response and calculate uptime and latency | + +## cron + +Kener fills data every minute in UTC so if you give an expression that is not per minute, kener will backfill data using the latest status. +Example for `cron: "*/15 * * * *"` +- First run at "2023-12-02T18:00:00.000Z" - Status DOWN +- Second run at "2023-12-02T18:15:00.000Z" - Status UP + +Kener will fill data from 18:01:00 to 18:14:00 as UP + +## eval + +This is a anonymous JS function, by default it looks like this. +> **_NOTE:_** The eval function should always return a json object. The json object can have only status(UP/DOWN/DEGRADED) and lantecy(number) +`{status:"DEGRADED", latency: 200}`. +```js +(function (statusCode, responseTime, responseDataBase64) { + let statusCodeShort = Math.floor(statusCode/100); + let status = 'DOWN' + if(statusCodeShort >=2 && statusCodeShort <= 3) { + status = 'UP', + } + return { + status: 'DOWN', + latency: responseTime, + } +}) +``` +- `statusCode` **REQUIRED** is a number. It is the HTTP status code +- `responseTime` **REQUIRED**is a number. It is the latency in milliseconds +- `responseDataBase64` **REQUIRED** is a string. It is the base64 encoded response data. To use it you will have to decode it + +```js +let decodedResp = atob(responseDataBase64); +//let jsonResp = JSON.parse(decodedResp) +``` + +--- +# Monitor Examples +Here are some exhaustive examples for monitors + +## A Simple GET Monitor + +```yaml +- name: Google Search + tag: "google-search" method: GET url: https://www.google.com/webhp +``` +## A GET Monitor with image +google.png is in the static folder +```yaml +- name: Google Search + tag: "google-search" + method: GET + image: "/google.png" + url: https://www.google.com/webhp +``` + +## Get Monitor 15 Minute + +```yaml +- name: Google Search + description: Search the world's information, including webpages, images, videos and more. + tag: "google-search" + cron: "*/15 * * * *" + method: GET + url: https://www.google.com/webhp +``` + +## Post Monitor With Body +```yaml +- name: Google Search + description: Google Search + tag: "google-search-post" + method: POST + url: https://www.google.com/webhp + headers: + Content-Type: application/json + body: '{"order_amount":22222.1,"order_currency":"INR"}' +``` + +## Secrets in Header + +You can set ENV variables in your machine and use them in your monitors. Example below has `GH_TOKEN` as an environment variable. It uses process.env.GH_TOKEN. +`export GH_TOKEN=some.token.for.github` +> **_NOTE:_** DO NOT forget the `$` sign in your monitor +```yaml +- name: Github Issues + description: Github Issues Fetch + tag: "gh-search-issue" + method: GET + url: https://api.github.com/repos/rajnandan1/kener/issues + headers: + Authorization: Bearer $GH_TOKEN +``` + +## Secrets in Body + +Assuming `ORDER_ID` is present in env +```yaml +- name: Github Issues + description: Github Issues Fetch + tag: "gh-search-issue" + method: POST + url: https://api.github.com/repos/rajnandan1/kener/issues + headers: + Content-Type: application/json + body: '{"order_amount":22222.1,"order_currency":"INR", "order_id": "$ORDER_ID"}' +``` + +## Eval Body + +```yaml +- name: Github Issues + description: Github Issues Fetch + tag: "gh-search-issue" + method: GET + url: https://api.github.com/repos/rajnandan1/kener/issues + eval: | + (function(statusCode, responseTime, responseDataBase64){ + const resp = JSON.parse(atob(responseDataBase64)); + let status = 'DOWN' + if(statusCode == 200) status = 'UP'; + if(resp.length == 0) status = 'DOWN'; + if(statusCode == 200 && responseTime > 2000) status = 'DEGRADED'; + return { + status: status, + latency: responseTime, + } + }) ``` \ No newline at end of file diff --git a/src/routes/docs/+page.svelte b/src/routes/docs/+page.svelte index ab70439..ceb9a79 100644 --- a/src/routes/docs/+page.svelte +++ b/src/routes/docs/+page.svelte @@ -6,57 +6,58 @@ const content = Markdoc.transform(ast); let html = Markdoc.renderers.html(content); let sideBar = []; - onMount(() => { - - - + onMount(async () => { const headings = document.querySelectorAll("#markdown h1"); - headings.forEach((heading) => { - const id = "h1" + heading.textContent.replace(/[^a-z0-9]/gi, '-').toLowerCase(); - heading.id = id; - heading.setAttribute("sider", "sidemenu"); - heading.setAttribute("sider-t", "h1"); - }) + headings.forEach((heading) => { + const id = "h1" + heading.textContent.replace(/[^a-z0-9]/gi, "-").toLowerCase(); + heading.id = id; + heading.setAttribute("sider", "sidemenu"); + heading.setAttribute("sider-t", "h1"); + heading.style.color = "#31304D"; + }); - const headings2 = document.querySelectorAll("#markdown h2"); - headings2.forEach((heading) => { - const id = "h2" + heading.textContent.replace(/[^a-z0-9]/gi, '-').toLowerCase(); - heading.id = id; - heading.setAttribute("sider", "sidemenu"); - heading.setAttribute("sider-t", "h2"); - }) - - const sidemenuHeadings = document.querySelectorAll("#markdown [sider='sidemenu']"); - sidemenuHeadings.forEach((heading) => { - - sideBar = [...sideBar, { - id: heading.id, - text: heading.textContent, - type: heading.getAttribute("sider-t") - }]; - }) + const headings2 = document.querySelectorAll("#markdown h2"); + headings2.forEach((heading) => { + const id = "h2" + heading.textContent.replace(/[^a-z0-9]/gi, "-").toLowerCase(); + heading.id = id; + heading.setAttribute("sider", "sidemenu"); + heading.setAttribute("sider-t", "h2"); + heading.style.color = "#435585"; + }); + const sidemenuHeadings = document.querySelectorAll("#markdown [sider='sidemenu']"); + sidemenuHeadings.forEach((heading) => { + sideBar = [ + ...sideBar, + { + id: heading.id, + text: heading.textContent, + type: heading.getAttribute("sider-t"), + }, + ]; + }); });
-
    +
      {#each sideBar as item} -
    • +
    • {item.text}
    • {/each}
    • Download
    -
-
-
{@html html}
+
+
+ {@html html} +