hping 0.0.4 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,21 @@
1
+ name: ci
2
+
3
+ on:
4
+ push:
5
+ pull_request:
6
+
7
+ jobs:
8
+ test:
9
+ runs-on: ubuntu-latest
10
+ strategy:
11
+ fail-fast: false
12
+ matrix:
13
+ node-version: [20.x, 22.x, 24.x]
14
+ steps:
15
+ - uses: actions/checkout@v4
16
+ - uses: actions/setup-node@v4
17
+ with:
18
+ node-version: ${{ matrix.node-version }}
19
+ cache: npm
20
+ - run: npm ci
21
+ - run: npm test
package/README.md CHANGED
@@ -1,35 +1,148 @@
1
- hPING
1
+ hPING (HTTP ping)
2
2
  =====
3
3
 
4
- Node.js CLI that sends HTTP HEAD or GET or POST requests to any web or api servers.
4
+ Node.js CLI that sends HTTP `HEAD`, `GET`, or `POST` requests to web/api servers.
5
5
 
6
- hPING is the fastest and easiest way to check or quickly monitor if http servers are alive.
6
+ <img src="http://www.anothervision.com/img/github/hping.gif" width="1126"/>
7
+ hPING is a quick way to check and monitor HTTP server availability.
8
+
9
+ ## Node.js Support
10
+
11
+ - Supported: `Node.js 20+` (validated against current major runtimes, including Node `22+`).
7
12
 
8
13
  ## Installation
9
14
 
10
- The latest hPING version is installable via NPM:
15
+ hPING is installable via npm:
11
16
 
12
17
  ```bash
13
18
  $ npm install hping -g
14
19
  ```
15
- If the above fails try this:
20
+
21
+ ## Usage
22
+
23
+ hPING single server `www.google.com`:
24
+
25
+ ```bash
26
+ $ hping www.google.com
27
+ ```
28
+
29
+ hPING server `www.google.com` with a 10-second interval:
30
+
16
31
  ```bash
17
- $ npm install git://github.com/kurdin/hping#master -g
32
+ $ hping www.google.com -i 10
18
33
  ```
19
- or
34
+
35
+ hPING single server with `GET` method:
36
+
20
37
  ```bash
21
- $ git clone https://github.com/kurdin/hping
22
- $ cd hping
23
- $ npm install
24
- $ npm link
38
+ $ hping get www.google.com
25
39
  ```
26
40
 
27
- ## Usage
41
+ hPING multiple servers:
42
+
43
+ ```bash
44
+ $ hping www.google.com www.apple.com www.microsoft.com
45
+ ```
46
+
47
+ hPING group of servers from config file (default config: `~/.hping/hping.conf.yaml`):
48
+
49
+ ```bash
50
+ $ hping "apple production"
51
+ ```
52
+
53
+ hPING can mix group of servers and separate hosts with single command:
54
+
55
+ ```bash
56
+ $ hping "apple production" www.github.com
57
+ ```
58
+
59
+ Explicit `ping` command (modern style):
60
+
61
+ ```bash
62
+ $ hping ping www.google.com
63
+ ```
64
+
65
+ ## Settings
66
+
67
+ hPING default settings (`~/.hping/hping.conf.yaml`):
68
+
69
+ ```bash
70
+ interval: 1 # (seconds) interval between hPING requests
71
+ type: HEAD # (type or requests): HEAD, GET, POST, PUT
72
+ timeout: 5000 # (milliseconds) request connection timeout
73
+ use_colors: true # (true || false), use colors for hPING output
74
+ show_stats_for_last: 100 # (number of requests) show hPING statistics for last X number of requests, set 0 to disable
75
+ max_run_time: 600 # (seconds) hPING maximum running time, set 0 to disable
76
+
77
+ log_status_change: false # (true || false) if true, hPING will log status changes to log file
78
+ log_file: logs/hping.log # (path) to hPING log file, default path in users home .hping folder
79
+ log_stats_on_exit: true # (true || false) if true, hPING will log statistics to file on exit
80
+
81
+ display_in_output: # use true || fasle to turn on/off log output sections
82
+ status: true
83
+ url: true
84
+ ip: true
85
+ type: false
86
+ status_code: true
87
+ status_info: true
88
+ server: true
89
+ content_length: false
90
+ response_time: true
91
+ ```
92
+
93
+ Show hPING server groups:
94
+
95
+ ```bash
96
+ $ hping servers
97
+ ```
98
+
99
+ Display hPING current settings:
100
+
101
+ ```bash
102
+ $ hping settings
103
+ ```
104
+
105
+ hPING server `www.google.com` with custom config:
28
106
 
29
107
  ```bash
30
- $ hping www.google.com # hPING single server (www.google.com)
108
+ $ hping www.google.com -c /etc/hping.conf.yaml
31
109
  ```
32
110
 
111
+ ## Help
112
+
113
+ hPING quick usage help:
33
114
 
115
+ ```bash
116
+ $ hping
117
+ usage: hping [ping|head|get|post] [http(s)://]www.webserver.com[:port] [another host] [server group]
118
+ ```
34
119
 
120
+ hPING full help:
121
+
122
+ ```bash
123
+ $ hping -h
124
+ ```
125
+
126
+ ## Log to file
127
+
128
+ Enable status-change logging with `log_status_change: true`.
129
+
130
+ Default log file location: `~/.hping/logs/hping.log` (override with `log_file`).
131
+
132
+ ## Development
133
+
134
+ Install deps:
135
+
136
+ ```bash
137
+ $ npm install
138
+ ```
139
+
140
+ Run tests:
141
+
142
+ ```bash
143
+ $ npm test
144
+ ```
35
145
 
146
+ ##License
147
+ The MIT License (MIT)
148
+ Copyright (c) 2014 Sergey Kurdin
package/bin/hping CHANGED
@@ -2,384 +2,9 @@
2
2
 
3
3
  'use strict';
4
4
 
5
- var program = require('commander'),
6
- util = require('util'),
7
- fs = require('fs'),
8
- log4js = require('log4js'),
9
- dns = require('dns'),
10
- path = require('path'),
11
- color = require('cli-color'),
12
- request = require('request'),
13
- status_codes = require('../lib/status'),
14
- config = require('yaml-config'),
15
- helpers = require('../lib/helpers'),
16
- info = 'hPING sends HEAD or GET or POST requests to web or api servers to check if they alive',
17
- usage = '[head|get|post] [http(s)://]www.webserver.com[:port] [another host] [server group]',
18
- hping_home_dir = getHPINGHome(),
19
- defconfile = path.resolve(__dirname, '../config/hping.yaml'),
20
- confile = path.resolve(hping_home_dir, 'hping.conf.yaml'),
21
- colors = {
22
- r: 'red',
23
- g: 'green',
24
- bb: 'blackBright',
25
- u: 'underline',
26
- m: 'magenta',
27
- y: 'yellow'
28
- },
29
- defaults = {
30
- confile: confile,
31
- interval: 1
32
- };
5
+ const { runCli } = require('../lib/cli');
33
6
 
34
- var settings, stats = {},
35
- logger_file;
36
-
37
- program
38
- .version('0.0.4')
39
- .usage(usage)
40
- .option('-c, --config [' + confile + ']', 'hping config file in YAML format', defaults.confile)
41
- .option('-i, --interval [1]', 'hping interval in seconds (set default in ' + confile + ')', defaults.interval);
42
-
43
- program
44
- .command('servers')
45
- .description('Show server groups information from config file')
46
- .action(function() {
47
- hping('servers');
48
- });
49
-
50
- program
51
- .command('settings')
52
- .description('Show hPING settings from config file')
53
- .action(function() {
54
- hping('settings');
55
- });
56
-
57
- program
58
- .command('get')
59
- .description('Sends HTTP GET requests to web or api server (set default in ' + confile + ')')
60
- .action(function() {
61
- if (program.args.length > 1) {
62
- hping(program.args, 'GET');
63
- } else {
64
- console.log(usage);
65
- }
66
- });
67
-
68
- program
69
- .command('post')
70
- .description('Sends HTTP POST requests to web or api server (set default in ' + confile + ')')
71
- .action(function() {
72
- if (program.args.length > 1) {
73
- hping(program.args, 'POST');
74
- } else {
75
- console.log(usage);
76
- }
77
- });
78
-
79
- program
80
- .command('head')
81
- .description('Sends HTTP HEAD requests to web or api server (set default in ' + confile + ')')
82
- .action(function() {
83
- if (program.args.length > 1) {
84
- hping(program.args, 'HEAD');
85
- } else {
86
- console.log(usage);
87
- }
88
- });
89
-
90
- program
91
- .on('*', function(e) {
92
- hping(e);
93
- });
94
-
95
- program.parse(process.argv);
96
-
97
- if (program.args.length < 1) {
98
- console.log('usage: hping ' + usage);
99
- }
100
-
101
- function hping(args, type) {
102
- fs.exists(confile, function(exists) {
103
- if (exists) {
104
- hping_run(args, type);
105
- } else {
106
- fs.mkdir(path.resolve(hping_home_dir), function(e) {
107
- if (!e || (e && e.code === 'EEXIST')) {
108
- fs.mkdir(path.resolve(hping_home_dir + '/logs'), function(e) {
109
- fs.createReadStream(defconfile).pipe(fs.createWriteStream(confile)).on('error', function(err) {
110
- console.log(err);
111
- }).on('close', function() {
112
- hping_run(args, type);
113
- });
114
- });
115
- } else {
116
- console.log(e);
117
- }
118
- });
119
- }
120
- });
121
- }
122
-
123
- function hping_run(args, type) {
124
- var cnf = (program.config !== defaults.confile) ? program.config : defaults.confile;
125
- settings = config.readConfig(cnf);
126
- if (!settings.interval) {
127
- console.error('Specified config file: %s could not be used, see error above. Using default config: %s', cnf, defaults.confile);
128
- settings = config.readConfig(defaults.confile);
129
- cnf = defaults.confile;
130
- }
131
- if (settings.log_status_change) logger_file = require('../lib/logger')(settings.log_file);
132
- settings.interval = (program.interval === 1) ? settings.interval : program.interval;
133
- if (args == 'servers') {
134
- showServers();
135
- return;
136
- }
137
- if (args == 'settings') {
138
- showSettings(cnf);
139
- return;
140
- }
141
- args.forEach(function(url) {
142
- if (typeof url == 'string' || url instanceof String) {
143
- if (settings.servers && settings.servers[url]) {
144
- settings.servers[url].forEach(function(url) {
145
- prerequest(url, type);
146
- });
147
- } else {
148
- prerequest(url, type);
149
- }
150
- }
151
- });
152
- }
153
-
154
- function prerequest(url, t) {
155
- if (!/^(https?):\/\//i.test(url)) url = 'http://' + url;
156
-
157
- var type = t || settings.type.toUpperCase(),
158
- run_time = 0,
159
- interval = ints(settings.interval),
160
- max_run_time = ints(settings.max_run_time),
161
- options = {
162
- url: url,
163
- timeout: ints(settings.timeout) || 5000,
164
- method: type,
165
- headers: {
166
- 'User-Agent': 'hPING [git.io/hping]'
167
- }
168
- };
169
-
170
- dns.resolve4(require('url').parse(url).hostname, function(err, ip) {
171
- if (err) ip = [''];
172
- stats[url] = [];
173
- (function dorequest() {
174
- var start = new Date();
175
- request(options, function(e, r) {
176
- var res_time = new Date() - start;
177
- var line = predisplay(e, r, url, type, ip[0], res_time);
178
- display(line);
179
- });
180
- if (max_run_time === 0 || max_run_time > (interval * run_time)) {
181
- setTimeout(dorequest, interval * 1000);
182
- run_time++;
183
- } else {
184
- console.log('hPING: Maximum running time has been reached (set in config), exiting.');
185
- gracefulExit();
186
- }
187
- })();
188
- });
189
- }
190
-
191
- function predisplay(err, res, url_org, type, ip, ms) {
192
- var hcode, hlength, hserver, hinfo, hip, htime, code, status_color, empty,
193
- sdo = settings.display_in_output,
194
- status = '[UP]',
195
- down = '[DOWN]',
196
- hstatus = status,
197
- htype = cc('type', type.toLowerCase()),
198
- hurl = url_org,
199
- line = [],
200
- url_p = require('url').parse(url_org);
201
-
202
- if (ip && hurl.indexOf(ip) == -1) hip = '(' + ip + ')';
203
- if (err && err.code) {
204
- code = 'error';
205
- status_color = colors.r;
206
- status = down;
207
- hcode = cc('error', err.code.toLowerCase(), colors.r);
208
- ms = 0;
209
- switch (err.code) {
210
- case 'ETIMEDOUT':
211
- hinfo = cc('info', 'connection_timeout', colors.r);
212
- break;
213
- case 'ENOTFOUND':
214
- hinfo = cc('info', 'server_not_found', colors.r);
215
- break;
216
- case 'ECONNRESET':
217
- hinfo = cc('info', 'connection_closed', colors.r);
218
- break;
219
- case 'ECONNREFUSED':
220
- hinfo = cc('info', 'connection_refused', colors.r);
221
- break;
222
- }
223
- } else if (res && res.headers) {
224
- htime = cc('time', ms, colors.u, 'ms');
225
- code = res.statusCode;
226
- status_color = statusColor(code);
227
- if (code >= 500) status = down;
228
- hcode = cc('code', code, (status_color !== colors.g) ? status_color : '');
229
- if (status_codes[code]) hinfo = cc('info', status_codes[code].replace(/\s+/g, '_'), (status_color !== colors.g) ? status_color : '');
230
- if (res.headers['content-length'] && res.headers['content-length'] > 0) hlength = 'content-length=' + res.headers['content-length'];
231
- if (res.headers.server) hserver = 'server=' + res.headers.server;
232
- } else {
233
- status = hstatus = 'unknown_error';
234
- }
235
-
236
- hurl = hurl.replace(url_p.hostname, colr('bold', colr(status_color, url_p.hostname))).replace(url_p.port, colr('bold', colr(status_color, url_p.port)));
237
- if (url_p.path && url_p.path != '/' && code !== 'error') hurl = hurl.replace(url_p.path, colr(status_color, url_p.path));
238
- hstatus = colr('bold', colr(status_color, status));
239
- hip = colr(colors.bb, hip);
240
-
241
- line = [
242
- 'hPING:', (sdo.status) ? hstatus : empty, (sdo.url) ? hurl : empty, (sdo.ip) ? hip : empty, (sdo.type) ? htype : empty, (sdo.status_code) ? hcode : empty, (sdo.status_info) ? hinfo : empty, (sdo.server) ? hserver : empty, (sdo.content_length) ? hlength : empty, (sdo.response_time) ? htime : empty
243
- ];
244
-
245
- if (stats[url_org].length >= ints(settings.stats_for_last)) stats[url_org].shift();
246
- if (settings.log_status_change) {
247
- if (stats[url_org][stats[url_org].length - 1] === undefined || (stats[url_org][stats[url_org].length - 1] !== undefined && stats[url_org][stats[url_org].length - 1].status !== status)) {
248
- log(line);
249
- }
250
- }
251
- stats[url_org].push({
252
- status: status,
253
- code: code,
254
- time: ms
255
- });
256
-
257
- return line;
258
- }
259
-
260
- function showServers() {
261
- console.log(info, (settings.servers) ? '\nServer groups (set in config):' + pp(settings.servers) : '', 'usage: hping ' + usage);
262
- }
263
-
264
- function showSettings(cnf) {
265
- console.log('Settings from config file: %s %s', cnf, pp(settings));
266
- }
267
-
268
- function display(line) {
269
- console.log(pline(line));
270
- }
271
-
272
- function log(line) {
273
- if (settings.log_status_change) logger_file.info(pline(line));
274
- }
275
-
276
- function gracefulExit() {
277
- if (ints(settings.show_stats_for_last) > 0) {
278
- for (var url in stats) {
279
- if (url) {
280
- display(displayStat(url));
281
- if (settings.log_stats_on_exit) log(displayStat(url));
282
- }
283
- }
284
- }
285
- log4js.shutdown(function() {
286
- process.exit(1);
287
- });
288
- }
289
-
290
- function statusColor(code) {
291
- var status_color = colors.g;
292
-
293
- if (code >= 500 || code == 'error') {
294
- status_color = colors.r;
295
- } else if (code >= 400) {
296
- status_color = colors.y;
297
- }
298
- return status_color;
299
- }
300
-
301
- function displayStat(url) {
302
- if (stats[url].length === 0) return;
303
-
304
- var codes = [],
305
- out = [],
306
- total = {
307
- requests: stats[url].length,
308
- codes: {},
309
- time: [],
310
- up: 0,
311
- down: 0
312
- },
313
- timesrange,
314
- requests = '[' + ((total.requests > settings.show_stats_for_last) ? 'last ' : '') + total.requests + ' requests] ',
315
- stat_line = '\n--- ' + url + ' hPING statistics ' + requests + '---\n';
316
-
317
- stats[url].forEach(function(stat) {
318
-
319
- if (!total.codes[stat.code]) total.codes[stat.code] = 1;
320
- else total.codes[stat.code]++;
321
-
322
- if (stat.status == '[UP]') total.up++;
323
- else total.down++;
324
-
325
- if (stat.time > 0) total.time.push(stat.time);
326
- });
327
-
328
- for (var code in total.codes) {
329
- if (code) codes.push(statProcess(code, total.codes[code], total.requests, statusColor(code), ''));
330
- }
331
-
332
- timesrange = total.time.range();
333
-
334
- out = [
335
- stat_line,
336
- statProcess('UP', total.up, total.requests, colors.g, 'bold'),
337
- statProcess('DOWN', total.down, total.requests, colors.r, 'bold'),
338
- codes.join(' '), (timesrange.min) ? 'time(min=' + timesrange.min + ' avg=' + timesrange.avg + ' max=' + timesrange.max + ')ms' : ''
339
- ];
340
-
341
- function statProcess(lb, tv, tr, tc, tb) {
342
- if (lb === 'error') lb += 's';
343
- var st = lb + '=' + Math.floor10((tv / tr) * 100) + '%';
344
- return (tv > 0) ? colr(tb, colr(tc, st)) : '';
345
- }
346
-
347
- return out;
348
- }
349
-
350
- process.on('SIGTERM', function() {
351
- gracefulExit();
352
- }).on('SIGINT', function() {
353
- gracefulExit();
7
+ runCli(process.argv.slice(2)).catch((error) => {
8
+ console.error(error.message || error);
9
+ process.exitCode = 1;
354
10
  });
355
-
356
- function cc(s1, s2, c, s3) {
357
- if (!s3) s3 = '';
358
- return (c && settings.use_colors) ? s1 + '=' + (color[c](s2)) + s3 : s1 + '=' + s2 + s3;
359
- }
360
-
361
- function colr(c, s) {
362
- return (!settings.use_colors || !c) ? s : color[c](s);
363
- }
364
-
365
- function ints(s) {
366
- return parseInt(s, 10);
367
- }
368
-
369
- function pp(s) {
370
- return JSON.stringify(s, null, ' ').replace(/[{}]|\,|[\[\]]|/g, '').replace(/\n\s*\n\s*\n/g, '\n');
371
- }
372
-
373
- function pline(l) {
374
- if (util.isArray(l)) {
375
- l = l.filter(function(e) {
376
- return e;
377
- });
378
- return l.join(' ').replace(/\n\s/g, '\n');
379
- }
380
- return '';
381
- }
382
-
383
- function getHPINGHome() {
384
- return path.resolve(process.env.HOME || process.env.HOMEPATH || process.env.USERPROFILE, '.hping/');
385
- }
package/config/hping.yaml CHANGED
@@ -1,17 +1,18 @@
1
1
  default:
2
2
 
3
3
  interval: 1 # (seconds) interval between hPING requests
4
- type: HEAD # (type or requests): HEAD, GET, POST, PUT
4
+ type: HEAD # (request type): HEAD, GET, POST
5
5
  timeout: 5000 # (milliseconds) request connection timeout
6
6
  use_colors: true # (true || false), use colors for hPING output
7
7
  show_stats_for_last: 100 # (number of requests) show hPING statistics for last X number of requests, set 0 to disable
8
+ stats_for_last: 100 # (number of requests) keep stats for last X requests per target
8
9
  max_run_time: 600 # (seconds) hPING maximum running time, set 0 to disable
9
10
 
10
11
  log_status_change: false # (true || false) if true, hPING will log status changes to log file
11
12
  log_file: logs/hping.log # (path) to hPING log file, default path in users home .hping folder
12
13
  log_stats_on_exit: true # (true || false) if true, hPING will log statistics to file on exit
13
14
 
14
- display_in_output: # use true || fasle to turn on/off log output sections
15
+ display_in_output: # use true || false to turn on/off log output sections
15
16
  status: true
16
17
  url: true
17
18
  ip: true