mirror of
https://github.com/rajnandan1/kener.git
synced 2026-01-06 01:20:15 -06:00
adding docs
This commit is contained in:
47
config/monitors.bk.yaml
Normal file
47
config/monitors.bk.yaml
Normal file
@@ -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,
|
||||
}
|
||||
})
|
||||
@@ -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 {
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
<meta charset="utf-8">
|
||||
<link rel="icon" id="kener-app-favicon" href="/kener.png">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
|
||||
</head><body data-sveltekit-preload-data="hover">%sveltekit.head%
|
||||
|
||||
|
||||
|
||||
@@ -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)
|
||||
|
||||

|
||||
|
||||
---
|
||||
# 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"
|
||||
```
|
||||

|
||||
---
|
||||
# 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,
|
||||
}
|
||||
})
|
||||
```
|
||||
@@ -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"),
|
||||
},
|
||||
];
|
||||
});
|
||||
});
|
||||
</script>
|
||||
<section class="mx-auto container rounded-3xl bg-white mt-32">
|
||||
<div class="grid grid-cols-5 gap-4">
|
||||
<div class="col-span-1">
|
||||
<ul class="w-full mt-1 sticky top-0 text-sm font-medium text-gray-900 bg-white mt-8 rounded-lg ">
|
||||
<ul class="w-full mt-1 sticky top-0 text-sm font-medium text-gray-900 bg-white mt-8 rounded-lg">
|
||||
{#each sideBar as item}
|
||||
<li class="w-full px-4 py-2 ">
|
||||
<li class="w-full px-4 py-2">
|
||||
<a href="#{item.id}" class="{item.type == 'h2'?'pl-5':''}">{item.text}</a>
|
||||
</li>
|
||||
{/each}
|
||||
<li class="w-full px-4 py-2 rounded-b-lg">Download</li>
|
||||
</ul>
|
||||
|
||||
</div>
|
||||
<div class="col-span-4">
|
||||
<div class="bg-white p-10 md">
|
||||
<article id="markdown" class="prose prose-stone max-w-none prose-code:bg-gray-200
|
||||
|
||||
prose-code:px-[0.3rem] prose-code:py-[0.2rem] prose-code:font-mono prose-code:text-sm prose-code:rounded prose-code:font-mono
|
||||
">{@html html}</article>
|
||||
<div class="bg-white p-10 md">
|
||||
<article
|
||||
id="markdown"
|
||||
class="prose prose-stone max-w-none prose-code:bg-gray-200 prose-code:px-[0.3rem] prose-code:py-[0.2rem] prose-code:font-mono prose-code:text-sm prose-code:rounded prose-code:font-mono"
|
||||
>
|
||||
{@html html}
|
||||
</article>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user