Skip to content

Commit b03ca2e

Browse files
committed
init commit config based is done REST endpoints to come
1 parent b7535a3 commit b03ca2e

14 files changed

+894
-0
lines changed

.gitignore

+2
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
package-lock.json
2+
node_modules

README.nbs

+41
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
# Fasquest
2+
A fast node request model, works very similar to `request` module but way faster and no dependencies + it works in the browser!
3+
4+
### Install
5+
```
6+
npm install fasquest
7+
```
8+
9+
### Basic Node Example
10+
```js
11+
const Fasquest = require('fasquest');
12+
13+
var options = {
14+
uri: 'http://127.0.0.1/',
15+
resolveWithFullResponse: true
16+
}
17+
18+
Fasquest.request(options).then(res=>{
19+
console.log('hey look I got a response')
20+
})
21+
22+
23+
```
24+
25+
### Basic Web Example
26+
```js
27+
import Fasquest from "fasquest";
28+
var options = {
29+
uri: 'http://127.0.0.1/',
30+
resolveWithFullResponse: true
31+
}
32+
33+
await Fasquest.request(options);
34+
35+
36+
```
37+
38+
39+
## Changelog
40+
41+
{{doc1}}

changelog-template.hbs

+30
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
### Changelog
2+
3+
All notable changes to this project will be documented in this file. Dates are displayed in UTC.
4+
5+
{{#each releases}}
6+
{{#if href}}
7+
###{{#unless major}}#{{/unless}} [{{title}}]({{href}})
8+
{{else}}
9+
#### {{title}}
10+
{{/if}}
11+
12+
{{#if tag}}
13+
> {{niceDate}}
14+
{{/if}}
15+
16+
{{#if summary}}
17+
{{summary}}
18+
{{/if}}
19+
20+
{{#each merges}}
21+
- {{{message}}}{{#if href}} [`#{{id}}`]({{href}}){{/if}}
22+
{{/each}}
23+
{{#each fixes}}
24+
- {{{commit.subject}}}{{#each fixes}}{{#if href}} [`#{{id}}`]({{href}}){{/if}}{{/each}}
25+
{{/each}}
26+
{{#each commits}}
27+
- {{#if breaking}}**Breaking change:** {{/if}}{{{subject}}}{{#if href}} [`{{shorthash}}`]({{href}}){{/if}}
28+
{{/each}}
29+
30+
{{/each}}

package.json

+39
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
{
2+
"name": "sky-puppy",
3+
"version": "0.1.0",
4+
"description": "A easy to use reliable health checking service with Prometheus export",
5+
"main": "./src/index.js",
6+
"scripts": {
7+
"start": "node src/index.js",
8+
"test": "SKY_PUPPY_CONFIG_PATH=./test node src/index.js",
9+
"version": "auto-changelog -l false --sort-commits date-desc --package --hide-credit --template changelog-template.hbs -p && mdsquash -i CHANGELOG.md && git add -A CHANGELOG.md && git add -A README.md",
10+
"postversion": "git push && git push --tags && npm publish"
11+
},
12+
"repository": {
13+
"type": "git",
14+
"url": "git+https://github.com/Phara0h/sky-puppy.git"
15+
},
16+
"keywords": [
17+
"prometheus",
18+
"health",
19+
"check",
20+
"request",
21+
"service"
22+
],
23+
"author": "Phara0h",
24+
"license": "GPL-3.0-or-later",
25+
"bugs": {
26+
"url": "https://github.com/Phara0h/sky-puppy/issues"
27+
},
28+
"homepage": "https://github.com/Phara0h/sky-puppy#readme",
29+
"dependencies": {
30+
"auto-changelog": "^2.2.0",
31+
"fasquest": "^2.4.0",
32+
"fastify": "^2.15.3",
33+
"jsdoc-to-markdown": "^6.0.1",
34+
"mdsquash": "^1.0.5",
35+
"nbars": "^1.0.1",
36+
"nstats": "^2.1.5",
37+
"postgen": "^4.1.5"
38+
}
39+
}

src/alerts.js

+141
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,141 @@
1+
const fs = require('fs');
2+
var fasquest = require('fasquest');
3+
const client = {
4+
https: require('https'),
5+
http: require('http'),
6+
};
7+
fasquest.agent = {
8+
http: new client.http.Agent({
9+
keepAlive: false
10+
}),
11+
https: new client.https.Agent({
12+
keepAlive: false
13+
})
14+
};
15+
class Alerts {
16+
constructor(stats,config,nbars) {
17+
18+
this.nbars = nbars;
19+
this.alerters = {}
20+
this.alerts_status = {}
21+
this.alerts = {
22+
down: {},
23+
healthy: {},
24+
unhealthy: {},
25+
unhealthy_status: {},
26+
unhealthy_response_time: {}
27+
}
28+
this.stats = stats;
29+
this.config = config;
30+
31+
var alertersKeys = Object.keys(this.config.alerters);
32+
33+
for (var i = 0; i < alertersKeys.length; i++) {
34+
this.addAlerter(alertersKeys[i],{...this.config.getAlerter(alertersKeys[i])});
35+
}
36+
37+
}
38+
39+
addAlerter(name,alerter) {
40+
if(!this.config.getAlerter(name)) {
41+
this.config.addAlerter(name,alerter);
42+
}
43+
44+
var nAlerter = {
45+
name,
46+
request: {
47+
...alerter
48+
}
49+
}
50+
51+
nAlerter.request.method = nAlerter.request.method || 'GET';
52+
nAlerter.request.timeout = Math.round((nAlerter.request.timeout || 60)*1000);
53+
nAlerter.request.resolveWithFullResponse = true;
54+
nAlerter.request.simple = false;
55+
56+
57+
if(!nAlerter.request.headers) {
58+
nAlerter.request.headers = {};
59+
}
60+
nAlerter.request.headers['User-Agent'] = `Sky-Puppy / ${this.config.skypuppy.version} (Health Check Service)`
61+
62+
this.alerters[name] = nAlerter;
63+
}
64+
65+
async _checkStatus(alert,service,type) {
66+
if(service.status.up === type) {
67+
68+
if(this.alerts_status[service.name] != null && this.alerts_status[service.name] === type) {
69+
return;
70+
}
71+
// check if status has changed
72+
if(!this.alerts[alert.type][service.name]) {
73+
this.alerts[alert.type][service.name] = {status:{...service.status,count: {...service.status.count}}}
74+
this.alerts[alert.type][service.name].status.count[alert.type]--;
75+
}
76+
77+
if((service.status.count[alert.type] - this.alerts[alert.type][service.name].status.count[alert.type]) >= (alert.for || 1) && !this.alerts[alert.type][service.name].alerted) {
78+
this.alerts[alert.type][service.name].alerted = true;
79+
await this._send_alert(alert,service);
80+
return;
81+
}
82+
83+
} else {
84+
this.alerts[alert.type][service.name] = null;
85+
}
86+
}
87+
88+
89+
90+
async alert(service) {
91+
if(service.config.alerts) {
92+
for (var i = 0; i < service.config.alerts.length; i++) {
93+
switch(service.config.alerts[i].type) {
94+
case "down":
95+
await this._checkStatus(service.config.alerts[i],service,-1);
96+
break;
97+
case "unhealthy":
98+
case "unhealthy_status":
99+
case "unhealthy_response_time":
100+
await this._checkStatus(service.config.alerts[i],service,0);
101+
break;
102+
case "healthy":
103+
await this._checkStatus(service.config.alerts[i],service,1);
104+
break;
105+
}
106+
}
107+
}
108+
}
109+
110+
async _send_alert(alert,service) {
111+
var overrides = alert.overrides || {};
112+
var request = {...this.alerters[alert.alerter].request, ...overrides}
113+
if(request.body) {
114+
request.body = this.nbars.transform(
115+
request.json ? JSON.stringify(request.body) : request.body,
116+
{
117+
alert_type: alert.type,
118+
service_name: service.name,
119+
timestamp: new Date().toISOString() ,
120+
last_unhealthy_total_duration: service.status.last_unhealthy_total_duration || 'Unknown',
121+
last_healthy_total_duration: service.status.last_healthy ? (Number(process.hrtime.bigint() - service.status.last_healthy) / 1000000000).toFixed(2) : 'Unknown'
122+
}
123+
)
124+
125+
if(request.json) {
126+
request.body = JSON.parse(request.body)
127+
}
128+
}
129+
//console.log(request.body)
130+
this.alerts_status[service.name] = service.status.up
131+
132+
try {
133+
await fasquest.request(JSON.parse(JSON.stringify(request)));
134+
} catch (e) {
135+
console.log(e)
136+
}
137+
138+
}
139+
140+
}
141+
module.exports = Alerts;

src/config.js

+74
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
const fs = require('fs');
2+
var path = require('path');
3+
class Config {
4+
constructor(config) {
5+
this.version = require(path.dirname(require.main.filename)+'/../package.json').version;
6+
try {
7+
this.path = path.resolve(process.env.SKY_PUPPY_CONFIG_PATH || './') + '/sky-puppy-config.json';
8+
this.settings = JSON.parse(fs.readFileSync(this.path));
9+
} catch (e) {
10+
this.path = path.dirname('./') + '/sky-puppy-config.json';
11+
this.settings = {};
12+
console.log('Error loading config. Creating and using default one at ' + this.path);
13+
this.saveConfig();
14+
}
15+
if(!this.alerters) {
16+
this.settings.alerters = {};
17+
}
18+
19+
if(!this.services) {
20+
this.settings.services = {};
21+
}
22+
23+
this.settings.skypuppy = this.settings.skypuppy || {
24+
version: this.version
25+
}
26+
}
27+
28+
addService(name,service) {
29+
try {
30+
this.services[name] = service;
31+
this.saveConfig();
32+
return this.services[name];
33+
} catch (e) {
34+
return null;
35+
}
36+
}
37+
38+
addAlerter(name,service) {
39+
try {
40+
this.alerters[name] = service;
41+
this.saveConfig();
42+
return this.alerters[name];
43+
} catch (e) {
44+
return null;
45+
}
46+
}
47+
48+
getService(name) {
49+
return this.services[name];
50+
}
51+
getAlerter(name) {
52+
return this.alerters[name];
53+
}
54+
55+
get services() {
56+
return this.settings.services;
57+
}
58+
59+
get alerters() {
60+
return this.settings.alerters;
61+
}
62+
63+
get skypuppy() {
64+
return this.settings.skypuppy;
65+
}
66+
67+
68+
69+
saveConfig() {
70+
console.log('Saving Config');
71+
fs.writeFileSync(this.path, JSON.stringify(this.settings, null, 4));
72+
}
73+
}
74+
module.exports = Config;

0 commit comments

Comments
 (0)