Application Programming Interface¶
First install it as module:
npm install @alinex/checkup --save
Now you can use it within a server or process environment.
Setup¶
First a new checkup has to be instantiated:
import Checkup from '@ainex/checkup'
const checkup = new Checkup({
config: <URI>,
verbose: <number>,
extend: <boolean>,
analyze: <boolean>,
autofix: <boolean>,
concurrency: <number>,
store: {...},
})
If one of the three logging types are set they will be written into defined filename (by string) or the '
Verbosity¶
The logs can be enhanced using higher verbosity. The following levels are defined.
Test: (Level 1-4)
Level | Type | Content |
---|---|---|
2 | REQUEST | Web Request |
3 | DATA | Send with request |
2 | STATUS | Response code |
3 | RESPONSE | Meta data |
3 | RETURN | Returning data from request |
2 | PROCESS | Command to be executed on CLI |
2 | EXITCODE | Response from CLI call |
3 | STDERR | Error output from CLI call |
3 | STDOUT | Standard output from CLI call |
4 | VALIDATE | Rules for validation |
1 | RESULT | Resulting data structure |
Analyze: (Level 5-8)
Level | Type | Content |
---|---|---|
5 | ANALYZE | Heading for analyzation step |
5 | PROCESS | Command to be executed on CLI |
5 | EXITCODE | Response from CLI call |
6 | STDERR | Error output from CLI call |
7 | STDOUT | Standard output from CLI call |
Repair: (Level 1-4)
Level | Type | Content |
---|---|---|
1 | REPAIR | Heading for repair step |
2 | PROCESS | Command to be executed on CLI |
2 | EXITCODE | Response from CLI call |
3 | STDERR | Error output from CLI call |
3 | STDOUT | Standard output from CLI call |
If extend
is set the verbosity level will be upgraded to level 4 in case of an error in test and up to 6 in case of problems in fix analyzation.
Store¶
Data stores can be used to collect the results over a longer time to analyze them later. Each data store is different with different possibilities. See the configuration details for each store.
Use Scheduler¶
Note
This makes the process a long running one which will not end till the scheduler is stopped or the process is terminated. Typically this feature is used within a server.
The scheduler works using the cron
settings in the cases. It will make a separate Runner for each possible cron-pattern which will be called depending on the resulting times. To start you simply call the scheduler()
method and if needed you may also stop it with the stop()
method of the returning object.
// start the scheduler asynchronously
checkup.scheduler()
// alternative; to be able to stop scheduler
const scheduler = checkup.scheduler()
...
scheduler.stop()
Run Suite¶
This is the default call.
Each run of the suite may select all or only some cases. To execute you have to instantiate a Runner and call it's start
method.
Path selection¶
A runner may contain only some of the suite's cases. You make a sub selection of the defined cases by defining the filter with path and tag selection. Both attributes are arrays and can contain multiple values.
Sub paths can also be specified partly ending at any character. All cases which match (from start) ANY of the given paths are included. But multiple tags are resolved as AND combination, so only cases are included, which include all defined tags. The group and name of the test case will automatically be added to tags.
There are multiple ways to run the suite. This depends on how you want it's response.
Examples¶
See the description of events and result formats, used in the examples, below.
Run all and get report afterwards
const runner = await checkup.create({ paths, tags })
runner.start()
// output complete report to console
.then(() => checkup.console(runner.console()))
// uncatched error
.catch((e: any) => {
console.error(chalk.bold.red(e))
console.error(e.stack.replace(/^.*?\n/, ''))
if (e.describe) console.error(e.describe())
})
Immediate response if block is finished
const runner = await checkup.create({ paths, tags })
// get the result as console output by event
runner.on('test', (name) => console.log(runner.console(name)))
runner.on('analyze', (name) => console.log(runner.console(name)))
runner.on('repair', (name) => console.log(runner.console(name)))
runner.start()
.then(() => console.log(runner.console('', { recursive: false })))
// uncatched error
.catch((e: any) => {
console.error(chalk.bold.red(e))
console.error(e.stack.replace(/^.*?\n/, ''))
if (e.describe) console.error(e.describe())
})
Get progress while running
const runner = await checkup.create({ paths, tags })
// use the step event to get done and max values
runner.on('step', (pos, max) => {
process.stderr.cursorTo(0)
process.stderr.write(`Test and analysis running... ${pos}/${max} checks (${Math.round(100 / max * pos)}% done)`)
})
runner.start()
.then(() => {
process.stderr.clearLine(-1)
process.stderr.cursorTo(0)
})
// output complete report to console
.then(() => checkup.console(runner.console()))
// uncatched error
.catch((e: any) => {
console.error(chalk.bold.red(e))
console.error(e.stack.replace(/^.*?\n/, ''))
if (e.describe) console.error(e.describe())
})
Events¶
The following events can be used to get informed while the whole process is further running:
test -> (test_name)
- informs that a test has finishedanalyze -> (fix_name)
- fix has been analyzed (fixname is<test_name>:<fix>-<class>
)repair -> (fix_name)
- repair process has finished (fixname is<test_name>:<fix>-<class>
)step -> (pos, max)
- informs about progress (in analyzation or repair run)
The step numbers are only used as percentage, don't use them for any interpretation their measurement is dynamically and the rules may change in the future. To know directly how many tests are done and with which result show into the runners num
Object.
If a repair is done this is a complete new run after the analyzation is completely finished and will take place as new progress using the step events again.
Result¶
After or while the runner is working you may always call the current information using it's properties and methods (mostly after triggered by event or after finishing).
The result can be retrieved in different formats and from different objects. The following data elements can be retrieved by giving the name of one of the following:
- complete report if nothing selected
- group - a group entry
- test - only the test result itself
- fix - the analysis and if done the repair information
The data structure of the result can further be customized using different formatters:
status
- only the status with maybe the error messagelist
- list of tests with all detailsgroup
- grouped structure with test results within the groups
If you work through the REST server the data structure may be presented in different formats like JSON, XML...
But there are also some formatters with fixed output.
console
- output optimal for colorful console outputhtml
- output for human reading web display
For each formatter there may be additional properties which further specifies the output. One general setting is recursion which is on by default and can be switched off with recursive: false
in the properties. For all other options see the description ob each Formatter below.
To retrieve the result call:
runner.report(format: string, name?: string, prop?: { recursive: boolean })
The name is the same as returned by the events.
Status Format¶
This is a puristic and simple format containing only two elements: status and error message if available.
runner.report('status', 'host.uptime')
{
"status": "OK",
"error": ""
}
List Format¶
The result format is a direct JavaScript Object best used to pass the structured data on to any other logic:
runner.result('list', 'host.uptime')
{
"host.uptime": {
"name": "host.uptime",
"title": "Host Startup Time",
"description": "This test will check if the localhost server is started within the last minutes, maybe there was a crash or some changes made.",
"test": "./linux/uptime",
"data": {
"warn": {
"age": "5 min"
}
},
"parent": [
"",
"host",
"host.uptime"
],
"tags": [
"linux",
"uptime",
"linux",
"uptime",
"linux",
"uptime",
"linux",
"uptime",
"linux",
"uptime",
"linux",
"uptime",
"linux",
"uptime",
"linux",
"uptime"
],
"cache": 50,
"fix": {},
"autofix": false,
"status": "OK",
"result": {
"boot": "2020-10-27T18:35:58.000Z",
"age": 10384
},
"start": "2020-10-27T21:29:02.131Z",
"log": "",
"fixes": []
},
"_status": "OK",
"_summary": {
"total": 1,
"OK": 1
}
}
Group Format¶
The result format is a direct JavaScript Object best used to pass the structured data on to any other logic:
runner.result('group', 'host.uptime')
{
"tests": {},
"sub": {
"host": {
"name": "host",
"title": "Local machine",
"parent": [
"",
"host"
],
"tags": [],
"data": {},
"cache": 50,
"fix": {},
"autofix": false,
"tests": {
"host.uptime": {
"name": "host.uptime",
"title": "Host Startup Time",
"description": "This test will check if the localhost server is started within the last minutes, maybe there was a crash or some changes made.",
"test": "./linux/uptime",
"data": {
"warn": {
"age": "5 min"
}
},
"parent": [
"",
"host",
"host.uptime"
],
"tags": [
"linux",
"uptime"
],
"cache": 50,
"fix": {},
"autofix": false,
"status": "OK",
"result": {
"boot": "2020-10-27T18:35:58.000Z",
"age": 10943
},
"start": "2020-10-27T21:38:21.768Z",
"log": "",
"fixes": []
},
"host.load": {
"name": "host.load",
"title": "System Load",
"description": "This test will check the current localhost server CPU load values.",
"test": "./linux/load",
"parent": [
"",
"host",
"host.load"
],
"tags": [
"linux",
"load"
],
"data": {},
"cache": 50,
"fix": {},
"autofix": false,
"status": "OK",
"result": {
"load1mTotal": 2.15,
"load5mTotal": 2.18,
"load15mTotal": 2.28,
"cpus": 4,
"user": 0.138,
"system": 0.05,
"nice": 0,
"idle": 0.81,
"iowait": 0,
"hwirq": 0,
"swirq": 0.003,
"steal": 0,
"load1m": 0.5375,
"load5m": 0.545,
"load15m": 0.57
},
"start": "2020-10-27T21:38:21.769Z",
"log": "",
"fixes": []
},
"host.memory": {
"name": "host.memory",
"title": "System Memory",
"description": "This test will read the current localhost server memory values and show how much is available or free.",
"test": "./linux/memory",
"parent": [
"",
"host",
"host.memory"
],
"tags": [
"linux",
"memory"
],
"data": {},
"cache": 50,
"fix": {},
"autofix": false,
"status": "OK",
"result": {
"MemTotal": 16302136,
"MemFree": 933812,
"MemAvailable": 5575772,
"SwapTotal": 16653308,
"SwapFree": 16546812,
"PercentAvailable": 0.34,
"PercentSwapFree": 0.99
},
"start": "2020-10-27T21:38:21.825Z",
"log": "",
"fixes": []
},
"host.disk": {
"name": "host.disk",
"title": "Disks",
"description": "This test will check all the mounted devices on localhost for their free space.",
"test": "./linux/disk",
"parent": [
"",
"host",
"host.disk"
],
"tags": [
"linux",
"disk"
],
"data": {},
"cache": 50,
"fix": {},
"autofix": false,
"status": "OK",
"result": [
{
"device": "/dev/nvme0n1p2",
"itotal": 30187520,
"ifree": 27618796,
"ipercent": 0.9149077499575984,
"total": 475219048,
"free": 282336704,
"percent": 0.594119080849638,
"mount": "/"
},
{
"device": "/dev/nvme0n1p1",
"itotal": 0,
"ifree": 0,
"ipercent": null,
"total": 523248,
"free": 517052,
"percent": 0.9881585787236645,
"mount": "/boot/efi"
}
],
"start": "2020-10-27T21:38:21.839Z",
"log": "",
"fixes": []
},
"host.logs": {
"name": "host.logs",
"title": "Space for Logs",
"description": "This test will check the current localhost server CPU load values.",
"test": "./linux/file",
"data": {
"path": "/var/log",
"warn": {
"minFree": "100 MiB"
}
},
"parent": [
"",
"host",
"host.logs"
],
"tags": [
"linux",
"file"
],
"cache": 50,
"fix": {},
"autofix": false,
"status": "OK",
"result": {
"mount": "/",
"size": 992693166,
"free": 282336704,
"mode": "40775",
"read": [
"user",
"group",
"other"
],
"write": [
"user",
"group",
false
],
"execute": [
"user",
"group",
"other"
],
"sticky": false,
"setgid": false,
"setuid": false,
"type": "directory",
"uid": 0,
"owner": "root",
"gid": 108,
"group": "syslog",
"access": "2020-10-27T18:38:50.000Z",
"change": "2020-10-27T18:36:14.000Z",
"metadata": "2020-10-27T18:36:14.000Z",
"mimetype": "inode/directory",
"charset": "binary"
},
"start": "2020-10-27T21:38:21.852Z",
"log": "",
"fixes": []
}
},
"sub": {},
"status": "OK",
"summary": {
"total": 5,
"OK": 5
}
},
"services": {
"name": "services",
"title": "External Services",
"parent": [
"",
"services"
],
"tags": [],
"data": {},
"cache": 50,
"fix": {},
"autofix": false,
"tests": {
"services.mongodb": {
"name": "services.mongodb",
"title": "MongoDB Daemon",
"description": "This test will check if the mongodb daemon on localhost is started and time and ip/port may be checked.",
"test": "./linux/daemon",
"data": {
"service": "mongodb",
"warn": {
"age": "5 min"
}
},
"parent": [
"",
"services",
"services.mongodb"
],
"tags": [
"linux",
"daemon"
],
"cache": 50,
"fix": {},
"autofix": false,
"status": "OK",
"result": {
"title": "An object/document-oriented database",
"script": "/lib/systemd/system/mongodb.service",
"active": true,
"status": "running",
"date": 1603823774000,
"age": 10927,
"pid": "1094"
},
"start": "2020-10-27T21:38:21.876Z",
"log": "",
"fixes": []
}
},
"sub": {},
"status": "OK",
"summary": {
"total": 1,
"OK": 1
}
}
},
"status": "OK",
"summary": {
"total": 6,
"OK": 6
}
}
Console Format¶
The console format should be used for output to the linux console:
runner.report('console', 'host')
Possible properties are:
recursive: false
to switch off recursionresult: true
will include result output also if verbosity is not >= 3
✔ OK Just Booted Up (local.uptime)
✔ OK System Memory (local.memory)
✔ OK MongoDB Daemon (local.daemon)
⚡ WARN Disks (local.disk)
Error at 0.percent (preset:result): Der Wert muss größer als 0.9 sein, aber 0.6473954806626354 wurde angegeben.
Check space on all disks.
REQUEST LANG=C df -x tmpfs -x devtmpfs -x squashfs --output=source,itotal,iavail,size,avail,target -k | sed 's/Mounted on/Mounted/;s/ \+/,/g'
RESPONSE code: 0
RETURN [
{
Filesystem: '/dev/nvme0n1p2',
Inodes: 30187520,
IFree: 27790757,
'1K-blocks': 475219048,
Avail: 307654664,
Mounted: '/'
},
{
Filesystem: '/dev/nvme0n1p1',
Inodes: 0,
IFree: 0,
'1K-blocks': 523248,
Avail: 517084,
Mounted: '/boot/efi'
}
]
VALIDATE Prüfen der abgerufenen Daten
Eine Liste mit Werten. Alle Elemente werden entfernt, die nicht den folgenden Bedingungen entsprechen:
- Nur spezifische Speichermedien werden geprüft.
Ein Datenobjekt mit Wertepaaren. Die Werte haben das folgende Format:
- Mounted: Der Speicher muss unter / eingebunden sein.
Ein Text Element. Der Wert sollte sein:
- gleich '/'
Die Werte haben das folgende Format:
- *: Aktuelle Auslastung
Ein Datenobjekt mit Wertepaaren. Die Werte haben das folgende Format:
- Filesystem: StringSchema
Ein Text Element.
- Inodes: NumberSchema
Ein nummerischer Wert.
- IFree: NumberSchema
Ein nummerischer Wert.
- 1K-blocks: NumberSchema
Ein nummerischer Wert.
- Avail: NumberSchema
Ein nummerischer Wert.
- Mounted: StringSchema
Ein Text Element.
Alle definierten Schlüssel sind notwendig.
RESULT [
{
device: '/dev/nvme0n1p2',
itotal: 30187520,
ifree: 27790757,
ipercent: 0.9206041768253901,
total: 475219048,
free: 307654664,
percent: 0.6473954806626354,
mount: '/'
}
]
VALIDATE Prüfung der Werte auf Fehler
Eine Liste mit Werten. Die Werte haben das folgende Format:
- *: Prüfung jedes Speichermediums
Ein Datenobjekt mit Wertepaaren. Die Werte haben das folgende Format:
- percent: Das Sepeichermedium muss mehr als 10% freien Platz haben.
Ein nummerischer Wert. Der Wert muss größer als 0.1 sein.
- ipercent: Das Sepeichermedium muss mehr als 10% freie Einträge haben.
Ein nummerischer Wert. Der Wert muss größer als 0.1 sein.
VALIDATE Prüfung der Werte auf Warnungen
Eine Liste mit Werten. Die Werte haben das folgende Format:
- *: Prüfung jedes Speichermediums
Ein Datenobjekt mit Wertepaaren. Die Werte haben das folgende Format:
- percent: Das Sepeichermedium muss mehr als 90% freien Platz haben.
Ein nummerischer Wert. Der Wert muss größer als 0.9 sein.
- ipercent: Das Sepeichermedium muss mehr als 20% freie Einträge haben.
Ein nummerischer Wert. Der Wert muss größer als 0.2 sein.
✔ OK System Load (local.load)
🛠 MANUAL Repariere volles Speichermedium (local.disk)
Dies kann möglicherweise automatisch repariert werden, wenn dies in der Konfiguration und im Aufruf erlaubt wird.
Der freie Platz auf /dev/nvme0n1p2, welches unter / eingebunden ist, ist bei nur noch 64,74%.
Die größten Dateien und Verzeichnisse auf / sind:
16G /home/alex/Downloads
6,9G /home/alex/Videos/test
6,0G /home/alex/.thunderbird/so8mthku.default/ImapMail/mail.xxxx-2.com/INBOX.sbd
5,9G /home/alex/.local/share/torbrowser/tbb/x86_64/tor-browser_de/Browser/Downloads
Im Verzeichnis /var/log sind 6 Dateien älter als 30 Tage (Änderungsdatum). Diese reichen vom 20.08.2020 bis 24.08.2020 und haben eine gesamte Größe von 27,1 MiB.
Nachdem hier 27,1 MiB in alten Dateien gefunden wurden, könnten diese auch automatisch gelöscht werden um Speicher frei zu geben.
Im Verzeichnis /var/log sind 11 unkomprimierte Dateien älter als 7 Tage (Änderungsdatum). Diese reichen vom 11.09.2020 bis 16.09.2020 und haben eine gesamte Größe von 168,51 MiB. Nachdem hier 168,51 MiB
unkomprimierte Daten gefunden wurden, könnten diese auch automatisch gepackt werden um einen Teil des Speicherplatzes frei zu bekommen.
5 Testfälle in allen Pfaden
4 Testfälle waren erfolgreich
1 Testfall im Warnzustand
The output is colored using escape sequences. If the terminal won't support colors they are not used.
Warning
To further use the result and filter it, better don't use the console formatter, other ones are better for this.
HTML Format¶
If it is manually called from the browser the HTML format will be used automatically. This is aimed to human interpretation, not for automatic aprocesses.
Or with verbose mode:
Status¶
Each test may have one of the following status codes:
NODATA
- the test could not be completed (problem in network/middleware)OK
- the test was successfulWARN
- the test shows a warning state for this caseERROR
- the test shows an error state for this case
Info
A monitoring system should work on the three main status but ignore the NODATA
status.
The fix will also have a status:
NODATA
- the analyzation/repair could not be doneIRRELEVANT
- ignore this fixMANUAL
- this has to be further investigatedOK
- the fix was correctly appliedWARN
- it could not completely be checkedERROR
- applying the fix made problems