Skip to content

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 '.log' entry.

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 finished
  • analyze -> (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 message
  • list - list of tests with all details
  • group - 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 output
  • html - 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 recursion
  • result: 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.

HTML output

Or with verbose mode:

HTML output

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 successful
  • WARN - the test shows a warning state for this case
  • ERROR - 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 done
  • IRRELEVANT - ignore this fix
  • MANUAL - this has to be further investigated
  • OK - the fix was correctly applied
  • WARN - it could not completely be checked
  • ERROR - applying the fix made problems