--- /dev/null
+#!/usr/bin/perl -w
+
+use Test::Command tests => 48;
+use Test::More;
+
+# fping -J -c 2 127.0.0.1
+{
+my $cmd = Test::Command->new(cmd => "fping -J -c 2 127.0.0.1");
+$cmd->exit_is_num(0);
+$cmd->stdout_like(qr/^\{"resp":\s\{"host":\s"127\.0\.0\.1",\s"seq":\s0,\s"size":\s\d+,\s"rtt":\s\d+\.\d+,\s"rttAvg":\s\d+\.\d+,\s"loss":\s\d+\}\}
+\{"resp":\s\{"host":\s"127\.0\.0\.1",\s"seq":\s1,\s"size":\s\d+,\s"rtt":\s\d+\.\d+,\s"rttAvg":\s\d+\.\d+,\s"loss":\s\d+\}\}
+\{"summary":\s\{"host":\s"127\.0\.0\.1",\s"xmt":\s\d+,\s"rcv":\s\d+,\s"loss":\s\d+,\s"rttMin":\s\d+\.\d+,\s"rttAvg":\s\d+\.\d+,\s"rttMax":\s\d+\.\d+\}\}\n?$/);
+$cmd->stderr_is_eq("");
+}
+
+# fping -J -c 1 --icmp-timestamp 127.0.0.1
+SKIP: {
+if($^O eq 'darwin') {
+ skip 'On macOS, this test is unreliable', 3;
+}
+my $cmd = Test::Command->new(cmd => "fping -J -c 1 --icmp-timestamp 127.0.0.1");
+$cmd->exit_is_num(0);
+$cmd->stdout_like(qr/^\{"resp":\s\{"host":\s"127\.0\.0\.1",\s"seq":\s0,\s"size":\s\d+,\s"rtt":\s\d+\.\d+,\s"rttAvg":\s\d+\.\d+,\s"loss":\s\d+,\s"timestamps":\s\{"originate":\s\d+,\s"receive":\s\d+,\s"transmit":\s\d+,\s"localreceive":\s\d+\}\}\}
+\{"summary":\s\{"host":\s"127\.0\.0\.1",\s"xmt":\s\d+,\s"rcv":\s\d+,\s"loss":\s\d+,\s"rttMin":\s\d+\.\d+,\s"rttAvg":\s\d+\.\d+,\s"rttMax":\s\d+\.\d+\}\}\n?$/);
+$cmd->stderr_is_eq("");
+}
+
+# fping -J -c 1 --print-ttl 127.0.0.1
+{
+my $cmd = Test::Command->new(cmd => "fping -J -c 1 --print-ttl 127.0.0.1");
+$cmd->exit_is_num(0);
+$cmd->stdout_like(qr/^\{"resp":\s\{"host":\s"127\.0\.0\.1",\s"seq":\s0,\s"size":\s\d+,\s"rtt":\s\d+\.\d+,\s"rttAvg":\s\d+\.\d+,\s"loss":\s\d+,\s"ttl":\s\d+\}\}
+\{"summary":\s\{"host":\s"127\.0\.0\.1",\s"xmt":\s\d+,\s"rcv":\s\d+,\s"loss":\s\d+,\s"rttMin":\s\d+\.\d+,\s"rttAvg":\s\d+\.\d+,\s"rttMax":\s\d+\.\d+\}\}\n?$/);
+$cmd->stderr_is_eq("");
+}
+
+# fping -J -c 1 --print-tos 127.0.0.1
+{
+my $cmd = Test::Command->new(cmd => "fping -J -c 1 --print-tos 127.0.0.1");
+$cmd->exit_is_num(0);
+$cmd->stdout_like(qr/^\{"resp":\s\{"host":\s"127\.0\.0\.1",\s"seq":\s0,\s"size":\s\d+,\s"rtt":\s\d+\.\d+,\s"rttAvg":\s\d+\.\d+,\s"loss":\s\d+,\s"tos":\s\d+\}\}
+\{"summary":\s\{"host":\s"127\.0\.0\.1",\s"xmt":\s\d+,\s"rcv":\s\d+,\s"loss":\s\d+,\s"rttMin":\s\d+\.\d+,\s"rttAvg":\s\d+\.\d+,\s"rttMax":\s\d+\.\d+\}\}\n?$/);
+$cmd->stderr_is_eq("");
+}
+
+# fping -J -c 1 --print-ttl --print-tos 127.0.0.1
+{
+my $cmd = Test::Command->new(cmd => "fping -J -c 1 --print-ttl --print-tos 127.0.0.1");
+$cmd->exit_is_num(0);
+$cmd->stdout_like(qr/^\{"resp":\s\{"host":\s"127\.0\.0\.1",\s"seq":\s0,\s"size":\s\d+,\s"rtt":\s\d+\.\d+,\s"rttAvg":\s\d+\.\d+,\s"loss":\s\d+,\s"tos":\s\d+,\s"ttl":\s\d+\}\}
+\{"summary":\s\{"host":\s"127\.0\.0\.1",\s"xmt":\s\d+,\s"rcv":\s\d+,\s"loss":\s\d+,\s"rttMin":\s\d+\.\d+,\s"rttAvg":\s\d+\.\d+,\s"rttMax":\s\d+\.\d+\}\}\n?$/);
+$cmd->stderr_is_eq("");
+}
+
+# fping -J -c 1 192.0.2.47
+{
+my $cmd = Test::Command->new(cmd => "fping -J -c 1 192.0.2.47");
+$cmd->exit_is_num(1);
+$cmd->stdout_like(qr/^\{"resp":\s\{"host":\s"192\.0\.2\.47",\s"seq":\s\d+,\s"rttAvg":\s"NaN",\s"loss":\s\d+\}\}
+\{"summary":\s\{"host":\s"192\.0\.2\.47",\s"xmt":\s\d+,\s"rcv":\s\d+,\s"loss":\s\d+\}\}\n?$/);
+$cmd->stderr_is_eq("");
+}
+
+# fping -J -c 2 -D 127.0.0.1
+{
+my $cmd = Test::Command->new(cmd => "fping -J -c 2 -D 127.0.0.1");
+$cmd->exit_is_num(0);
+$cmd->stdout_like(qr/^\{"resp":\s\{"timestamp":\s\d+.\d+,\s"host":\s"127\.0\.0\.1",\s"seq":\s0,\s"size":\s\d+,\s"rtt":\s\d+\.\d+,\s"rttAvg":\s\d+\.\d+,\s"loss":\s\d+\}\}
+\{"resp":\s\{"timestamp":\s\d+.\d+,\s"host":\s"127\.0\.0\.1",\s"seq":\s1,\s"size":\s\d+,\s"rtt":\s\d+\.\d+,\s"rttAvg":\s\d+\.\d+,\s"loss":\s\d+\}\}
+\{"summary":\s\{"host":\s"127\.0\.0\.1",\s"xmt":\s\d+,\s"rcv":\s\d+,\s"loss":\s\d+,\s"rttMin":\s\d+\.\d+,\s"rttAvg":\s\d+\.\d+,\s"rttMax":\s\d+\.\d+\}\}\n?$/);
+$cmd->stderr_is_eq("");
+}
+
+# fping -J -c 1 -q 127.0.0.1
+{
+my $cmd = Test::Command->new(cmd => "fping -J -c 1 -q 127.0.0.1");
+$cmd->exit_is_num(0);
+$cmd->stdout_like(qr/^\{"summary":\s\{"host":\s"127\.0\.0\.1",\s"xmt":\s\d+,\s"rcv":\s\d+,\s"loss":\s\d+,\s"rttMin":\s\d+\.\d+,\s"rttAvg":\s\d+\.\d+,\s"rttMax":\s\d+\.\d+\}\}\n?$/);
+$cmd->stderr_is_eq("");
+}
+
+# fping -J -C 1 -q 127.0.0.1
+{
+my $cmd = Test::Command->new(cmd => "fping -J -C 1 -q 127.0.0.1");
+$cmd->exit_is_num(0);
+$cmd->stdout_like(qr/^\{"vSum":\s\{"host":\s"\d+\.\d+\.\d+\.\d+",\s"values":\s\[\d+\.\d+\]\}\}\n?$/);
+$cmd->stderr_is_eq("");
+}
+
+# fping -J -C 1 -q 127.0.0.1 127.0.0.2
+{
+my $cmd = Test::Command->new(cmd => "fping -J -C 1 -q 127.0.0.1 127.0.0.2");
+$cmd->exit_is_num(0); # Both hosts are reachable in this test
+$cmd->stdout_like(qr/^\{"vSum":\s\{"host":\s"\d+\.\d+\.\d+\.\d+",\s"values":\s\[\d+\.\d+\]}}
+\{"vSum":\s\{"host":\s"\d+\.\d+\.\d+\.\d+",\s"values":\s\[\d+\.\d+\]\}\}\n?$/);
+$cmd->stderr_is_eq("");
+}
+
+# fping -J -C3 -p 100 -q 127.0.0.1
+{
+my $cmd = Test::Command->new(cmd => "fping -J -C3 -p 100 -q 127.0.0.1");
+$cmd->exit_is_num(0);
+$cmd->stdout_like(qr/^\{"vSum":\s\{"host":\s"\d+\.\d+\.\d+\.\d+",\s"values":\s\[\d+\.\d+\,\s\d+\.\d+,\s\d+\.\d+\]\}\}\n?$/);
+$cmd->stderr_is_eq("");
+}
+
+# fping -J -c 1 -q host.invalid
+{
+my $cmd = Test::Command->new(cmd => "fping -J -c 1 -q host.invalid");
+$cmd->exit_is_num(2); # Exit code 2 indicates name resolution error
+$cmd->stdout_is_eq("");
+$cmd->stderr_like(qr/^\{"host":\s"host\.invalid", "error":\s"(?:Name or service not known|Temporary failure in name resolution|nodename nor servname provided, or not known)"\}$/);
+}
+
+# fping -J -c 1 -q -g 127.0.0.1/30
+{
+my $cmd = Test::Command->new(cmd => "fping -J -c 1 -q -g 127.0.0.1/30");
+$cmd->exit_is_num(0);
+$cmd->stdout_like(qr/^\{"summary":\s\{"host":\s"127\.0\.0\.1",\s"xmt":\s\d+,\s"rcv":\s\d+,\s"loss":\s\d+,\s"rttMin":\s\d+\.\d+,\s"rttAvg":\s\d+\.\d+,\s"rttMax":\s\d+\.\d+\}\}
+\{"summary":\s\{"host":\s"127\.0\.0\.2",\s"xmt":\s\d+,\s"rcv":\s\d+,\s"loss":\s\d+,\s"rttMin":\s\d+\.\d+,\s"rttAvg":\s\d+\.\d+,\s"rttMax":\s\d+\.\d+\}\}?$/);
+$cmd->stderr_is_eq("");
+}
+
+# fping -J -c 2 -Q 1 127.0.0.1
+{
+my $cmd = Test::Command->new(cmd => "fping -J -c 2 -Q 1 127.0.0.1");
+$cmd->exit_is_num(0);
+$cmd->stdout_like(qr/^\{"intSum":\s\{"time":\s\d+,"host":\s"127\.0\.0\.1",\s"xmt":\s\d+,\s"rcv":\s\d+,\s"loss":\s\d+,\s"rttMin":\s\d+\.\d+,\s"rttAvg":\s\d+\.\d+,\s"rttMax":\s\d+\.\d+\}\}
+\{"summary":\s\{"host":\s"127\.0\.0\.1",\s"xmt":\s\d+,\s"rcv":\s\d+,\s"loss":\s\d+,\s"rttMin":\s\d+\.\d+,\s"rttAvg":\s\d+\.\d+,\s"rttMax":\s\d+\.\d+\}\}?$/);
+$cmd->stderr_is_eq("");
+}
+
+# fping -J -s -q -c 2 127.0.0.1
+{
+my $cmd = Test::Command->new(cmd => "fping -J -s -q -c 2 127.0.0.1");
+$cmd->exit_is_num(0);
+$cmd->stdout_like(qr/^\{"summary":\s\{"host":\s"127\.0\.0\.1",\s"xmt":\s\d+,\s"rcv":\s\d+,\s"loss":\s\d+,\s"rttMin":\s\d+\.\d+,\s"rttAvg":\s\d+\.\d+,\s"rttMax":\s\d+\.\d+\}\}
+\{"globalSum":\s\{"targets":\s\d+,\s"alive":\s\d+,\s"unreachable":\s\d+,\s"unknown\saddresses":\s\d+,\s"timeouts\s\(waiting\sfor\sresponse\)":\s\d+,\s"ICMP\sEchos\ssent":\s\d+,\s"ICMP\sEcho\sReplies\sreceived":\s\d+,\s"other\sICMP\sreceived":\s0,\s"ms\s\(min\sround\strip\stime\)":\s\d+\.\d+,\s"ms\s\(avg\sround\strip\stime\)":\s\d+\.\d+,\s"ms\s\(max\sround\strip\stime\)":\s\d+\.\d+,\s"sec\s\(elapsed\sreal\stime\)":\s\d+\.\d+\}\}?$/);
+$cmd->stderr_is_eq("");
+}
+
+# fping -J 127.0.0.1
+{
+my $cmd = Test::Command->new(cmd => "fping -J 127.0.0.1");
+$cmd->exit_is_num(1);
+$cmd->stdout_is_eq("");
+$cmd->stderr_is_eq("fping: with -J or --json required -c or -C\n");
+}
/* switches */
int generate_flag = 0; /* flag for IP list generation */
int verbose_flag, quiet_flag, stats_flag, unreachable_flag, alive_flag;
-int elapsed_flag, version_flag, count_flag, loop_flag, netdata_flag;
+int elapsed_flag, version_flag, count_flag, loop_flag, netdata_flag, json_flag;
int per_recv_flag, report_all_rtts_flag, name_flag, addr_flag, backoff_flag, rdns_flag;
int multif_flag, timeout_flag, fast_reachable;
int outage_flag = 0;
void usage(int);
int wait_for_reply(int64_t);
void print_per_system_stats(void);
+void print_per_system_stats_json(void);
void print_per_system_splits(void);
+void print_per_system_splits_json(void);
void stats_reset_interval(HOST_ENTRY *h);
void print_netdata(void);
void print_global_stats(void);
+void print_global_stats_json(void);
void main_loop();
void signal_handler(int);
void finish();
{ "ttl", 'H', OPTPARSE_REQUIRED },
{ "interval", 'i', OPTPARSE_REQUIRED },
{ "iface", 'I', OPTPARSE_REQUIRED },
+ { "json", 'J', OPTPARSE_OPTIONAL },
{ "icmp-timestamp", '0', OPTPARSE_NONE },
#ifdef SO_MARK
{ "fwmark", 'k', OPTPARSE_REQUIRED },
#endif
break;
+ case 'J':
+ json_flag = 1;
+ break;
+
case 'T':
/* This option is ignored for compatibility reasons ("select timeout" is not meaningful anymore) */
break;
exit(1);
}
+ if (json_flag && !count_flag) {
+ fprintf(stderr, "%s: with -J or --json required -c or -C\n", prog);
+ exit(1);
+ }
+
#ifdef FPING_SAFE_LIMITS
if ((interval < (int64_t)MIN_INTERVAL * 1000000 || perhost_interval < (int64_t)MIN_PERHOST_INTERVAL * 1000000)
&& getuid()) {
fprintf(stderr, " outage_flag set\n");
if (netdata_flag)
fprintf(stderr, " netdata_flag set\n");
+ if (json_flag)
+ fprintf(stderr, " json_flag set\n");
}
#endif /* DEBUG || _DEBUG */
stats_add(h, event->ping_index, 0, -1);
if (per_recv_flag) {
+ if (json_flag)
+ printf("{\"resp\": {");
+
if (timestamp_flag) {
- print_timestamp_format(current_time_ns, timestamp_format_flag);
+ if (json_flag)
+ printf("\"timestamp\": %.5f, ", (double)current_time_ns / 1e9);
+ else
+ print_timestamp_format(current_time_ns, timestamp_format_flag);
+ }
+ if (json_flag)
+ {
+ printf("\"host\": \"%s\", ", h->host);
+ printf("\"seq\": %d", event->ping_index);
+ }
+ else {
+ printf("%-*s : [%d], timed out",
+ max_hostname_len, h->host, event->ping_index);
}
- printf("%-*s : [%d], timed out",
- max_hostname_len, h->host, event->ping_index);
if (h->num_recv > 0) {
- printf(" (%s avg, ", sprint_tm(h->total_time / h->num_recv));
+ if (json_flag)
+ printf(", \"rttAvg\": %s", sprint_tm(h->total_time / h->num_recv));
+ else
+ printf(" (%s avg, ", sprint_tm(h->total_time / h->num_recv));
}
else {
- printf(" (NaN avg, ");
+ if (json_flag)
+ printf(", \"rttAvg\": \"NaN\"");
+ else
+ printf(" (NaN avg, ");
}
if (h->num_recv <= h->num_sent) {
- printf("%d%% loss)",
- ((h->num_sent - h->num_recv) * 100) / h->num_sent);
+ if (json_flag) {
+ printf(", \"loss\": %d", ((h->num_sent - h->num_recv) * 100) / h->num_sent);
+ }
+ else {
+ printf("%d%% loss)",
+ ((h->num_sent - h->num_recv) * 100) / h->num_sent);
+ }
}
else {
- printf("%d%% return)",
- (h->num_recv_total * 100) / h->num_sent);
+ if (json_flag) {
+ printf(", \"return\": %d", (h->num_recv_total * 100) / h->num_sent);
+ }
+ else {
+ printf("%d%% return)",
+ (h->num_recv_total * 100) / h->num_sent);
+ }
}
+
+ if (json_flag)
+ printf("}}");
+
printf("\n");
}
if (status_snapshot) {
status_snapshot = 0;
- print_per_system_splits();
+ if (json_flag)
+ print_per_system_splits_json();
+ else
+ print_per_system_splits();
}
/* Print report */
if (report_interval && (loop_flag || count_flag) && (current_time_ns >= next_report_time)) {
- if (netdata_flag)
+ if (netdata_flag) {
print_netdata();
- else
+ }
+ else if (json_flag) {
+ print_per_system_splits_json();
+ }
+ else {
print_per_system_splits();
+ }
while (current_time_ns >= next_report_time) {
next_report_time += report_interval;
}
}
- if (count_flag || loop_flag)
- print_per_system_stats();
+ if (count_flag || loop_flag) {
+ if (json_flag)
+ print_per_system_stats_json();
+ else
+ print_per_system_stats();
+ }
#if defined(DEBUG) || defined(_DEBUG)
- else if (print_per_system_flag)
- print_per_system_stats();
+ else if (print_per_system_flag) {
+ if (json_flag)
+ print_per_system_stats_json();
+ else
+ print_per_system_stats();
+ }
#endif /* DEBUG || _DEBUG */
- if (stats_flag)
- print_global_stats();
+ if (stats_flag) {
+ if (json_flag)
+ print_global_stats_json();
+ else
+ print_global_stats();
+ }
if (min_reachable) {
if ((num_hosts - num_unreachable) >= min_reachable) {
}
}
+/************************************************************
+
+ Function: print_per_system_stats_json
+
+*************************************************************
+
+ Inputs: void (none)
+
+ Description:
+
+
+************************************************************/
+
+void print_per_system_stats_json(void)
+{
+ int i, j, avg, outage_ms;
+ HOST_ENTRY *h;
+ int64_t resp;
+
+ for (i = 0; i < num_hosts; i++) {
+ h = table[i];
+
+ if (report_all_rtts_flag)
+ fprintf(stdout, "{\"vSum\": {");
+ else
+ fprintf(stdout, "{\"summary\": {");
+
+ fprintf(stdout, "\"host\": \"%s\", ", h->host);
+
+ if (report_all_rtts_flag) {
+ fprintf(stdout, "\"values\": [");
+ for (j = 0; j < h->num_sent; j++) {
+ if (j > 0)
+ fprintf(stdout, ", ");
+
+ if ((resp = h->resp_times[j]) >= 0)
+ fprintf(stdout, "%s", sprint_tm(resp));
+ else
+ fprintf(stdout, "-");
+ }
+
+ fprintf(stdout, "]}");
+ }
+ else {
+ if (h->num_recv <= h->num_sent) {
+ fprintf(stdout, "\"xmt\": %d, ", h->num_sent);
+ fprintf(stdout, "\"rcv\": %d, ", h->num_recv);
+ fprintf(stdout, "\"loss\": %d", h->num_sent > 0 ? ((h->num_sent - h->num_recv) * 100) / h->num_sent : 0);
+
+ if (outage_flag) {
+ /* Time outage total */
+ outage_ms = (h->num_sent - h->num_recv) * perhost_interval / 1e6;
+ fprintf(stdout, ", \"outage(ms)\": %d", outage_ms);
+ }
+ }
+ else {
+ fprintf(stdout, "\"xmt\": %d, ", h->num_sent);
+ fprintf(stdout, "\"rcv\": %d, ", h->num_recv);
+ fprintf(stdout, "\"return\": %d", h->num_sent > 0 ? ((h->num_recv * 100) / h->num_sent) : 0);
+ }
+
+ if (h->num_recv) {
+ avg = h->total_time / h->num_recv;
+ fprintf(stdout, ", \"rttMin\": %s", sprint_tm(h->min_reply));
+ fprintf(stdout, ", \"rttAvg\": %s", sprint_tm(avg));
+ fprintf(stdout, ", \"rttMax\": %s", sprint_tm(h->max_reply));
+ }
+
+ fprintf(stdout, "}");
+ }
+ fprintf(stdout, "}\n");
+ }
+}
+
/************************************************************
Function: print_netdata
}
}
+/************************************************************
+
+ Function: print_per_system_splits_json
+
+*************************************************************
+
+ Inputs: void (none)
+
+ Description:
+
+
+************************************************************/
+
+void print_per_system_splits_json(void)
+{
+ int i, avg, outage_ms_i;
+ HOST_ENTRY *h;
+
+ update_current_time();
+
+ for (i = 0; i < num_hosts; i++) {
+ h = table[i];
+ fprintf(stdout, "{\"intSum\": {");
+ fprintf(stdout, "\"time\": %" PRId64 ",", current_time.tv_sec);
+ fprintf(stdout, "\"host\": \"%s\", ", h->host);
+
+ if (h->num_recv_i <= h->num_sent_i) {
+ fprintf(stdout, "\"xmt\": %d, ", h->num_sent_i);
+ fprintf(stdout, "\"rcv\": %d, ", h->num_recv_i);
+ fprintf(stdout, "\"loss\": %d", h->num_sent_i > 0 ? ((h->num_sent_i - h->num_recv_i) * 100) / h->num_sent_i : 0);
+
+ if (outage_flag) {
+ /* Time outage */
+ outage_ms_i = (h->num_sent_i - h->num_recv_i) * perhost_interval / 1e6;
+ fprintf(stdout, ", \"outage(ms)\": %d", outage_ms_i);
+ }
+ }
+ else {
+ fprintf(stdout, "\"xmt\": %d, ", h->num_sent_i);
+ fprintf(stdout, "\"rcv\": %d, ", h->num_recv_i);
+ fprintf(stdout, "\"loss\": %d", h->num_sent_i > 0 ? ((h->num_recv_i * 100) / h->num_sent_i) : 0);
+ }
+
+ if (h->num_recv_i) {
+ avg = h->total_time_i / h->num_recv_i;
+ fprintf(stdout, ", \"rttMin\": %s, ", sprint_tm(h->min_reply_i));
+ fprintf(stdout, "\"rttAvg\": %s, ", sprint_tm(avg));
+ fprintf(stdout, "\"rttMax\": %s", sprint_tm(h->max_reply_i));
+ }
+
+ fprintf(stdout, "}}\n");
+ if (!cumulative_stats_flag) {
+ stats_reset_interval(h);
+ }
+ }
+}
+
/************************************************************
Function: print_global_stats
fprintf(stderr, "\n");
}
+/************************************************************
+
+ Function: print_global_stats_json
+
+*************************************************************
+
+ Inputs: void (none)
+
+ Description:
+
+
+************************************************************/
+
+void print_global_stats_json(void)
+{
+ fprintf(stdout, "{\"globalSum\": {");
+ fprintf(stdout, "\"targets\": %d, ", num_hosts);
+ fprintf(stdout, "\"alive\": %d, ", num_alive);
+ fprintf(stdout, "\"unreachable\": %d, ", num_unreachable);
+ fprintf(stdout, "\"unknown addresses\": %d, ", num_noaddress);
+ fprintf(stdout, "\"timeouts (waiting for response)\": %d, ", num_timeout);
+ fprintf(stdout, "\"ICMP Echos sent\": %d, ", num_pingsent);
+ fprintf(stdout, "\"ICMP Echo Replies received\": %d, ", num_pingreceived);
+ fprintf(stdout, "\"other ICMP received\": %d, ", num_othericmprcvd);
+
+ if (total_replies == 0) {
+ min_reply = 0;
+ max_reply = 0;
+ total_replies = 1;
+ sum_replies = 0;
+ }
+
+ fprintf(stdout, "\"ms (min round trip time)\": %s, ", sprint_tm(min_reply));
+ fprintf(stdout, "\"ms (avg round trip time)\": %s, ", sprint_tm(sum_replies / total_replies));
+ fprintf(stdout, "\"ms (max round trip time)\": %s, ", sprint_tm(max_reply));
+ fprintf(stdout, "\"sec (elapsed real time)\": %.3f", (end_time - start_time) / 1e9);
+ fprintf(stdout, "}}\n");
+}
+
/************************************************************
Function: send_ping
/* print received ping (unless --quiet) */
if (per_recv_flag) {
+ if (json_flag)
+ printf("{\"resp\": {");
+
if (timestamp_flag) {
- print_timestamp_format(recv_time, timestamp_format_flag);
+ if (json_flag)
+ printf("\"timestamp\": %.5f, ", (double)recv_time / 1e9);
+ else
+ print_timestamp_format(recv_time, timestamp_format_flag);
}
avg = h->total_time / h->num_recv;
- printf("%-*s : [%d], %d bytes, %s ms",
- max_hostname_len, h->host, this_count, result, sprint_tm(this_reply));
- printf(" (%s avg, ", sprint_tm(avg));
+ if (json_flag) {
+ printf("\"host\": \"%s\", ", h->host);
+ printf("\"seq\": %d, ", this_count);
+ printf("\"size\": %d, ", result);
+ printf("\"rtt\": %s, ", sprint_tm(this_reply));
+ printf("\"rttAvg\": %s", sprint_tm(avg));
+ }
+ else {
+ printf("%-*s : [%d], %d bytes, %s ms", max_hostname_len, h->host, this_count, result, sprint_tm(this_reply));
+ printf(" (%s avg, ", sprint_tm(avg));
+ }
if (h->num_recv <= h->num_sent) {
- printf("%d%% loss)",
- ((h->num_sent - h->num_recv) * 100) / h->num_sent);
+ if (json_flag)
+ printf(", \"loss\": %d", ((h->num_sent - h->num_recv) * 100) / h->num_sent);
+ else
+ printf("%d%% loss)", ((h->num_sent - h->num_recv) * 100) / h->num_sent);
}
else {
- printf("%d%% return)",
- (h->num_recv_total * 100) / h->num_sent);
+ if (json_flag)
+ printf(", \"return\": %d", (h->num_recv_total * 100) / h->num_sent);
+ else
+ printf("%d%% return)", (h->num_recv_total * 100) / h->num_sent);
}
}
}
if (icmp_request_typ == 13) {
- printf("%s timestamps: Originate=%u Receive=%u Transmit=%u Localreceive=%u",
- alive_flag ? "" : ",",
- ip_header_otime_ms, ip_header_rtime_ms, ip_header_ttime_ms,
- ms_since_midnight_utc(recv_time));
+ if (json_flag) {
+ printf(", \"timestamps\": {");
+ printf("\"originate\": %u, ", ip_header_otime_ms);
+ printf("\"receive\": %u, ", ip_header_rtime_ms);
+ printf("\"transmit\": %u, ", ip_header_ttime_ms);
+ printf("\"localreceive\": %u}", ms_since_midnight_utc(recv_time));
+ }
+ else {
+ printf("%s timestamps: Originate=%u Receive=%u Transmit=%u Localreceive=%u",
+ alive_flag ? "" : ",",
+ ip_header_otime_ms, ip_header_rtime_ms, ip_header_ttime_ms,
+ ms_since_midnight_utc(recv_time));
+ }
}
if(print_tos_flag) {
if(ip_header_tos != -1) {
- printf(" (TOS %d)", ip_header_tos);
+ if (json_flag)
+ printf(", \"tos\": %d", ip_header_tos);
+ else
+ printf(" (TOS %d)", ip_header_tos);
}
else {
- printf(" (TOS unknown)");
+ if (json_flag)
+ printf(", \"tos\": -1");
+ else
+ printf(" (TOS unknown)");
}
}
if (print_ttl_flag) {
if(ip_header_ttl != -1) {
- printf(" (TTL %d)", ip_header_ttl);
+ if (json_flag)
+ printf(", \"ttl\": %d", ip_header_ttl);
+ else
+ printf(" (TTL %d)", ip_header_ttl);
}
else {
- printf(" (TTL unknown)");
+ if (json_flag)
+ printf(", \"ttl\": -1");
+ else
+ printf(" (TTL unknown)");
}
}
if (elapsed_flag && !per_recv_flag)
printf(" (%s ms)", sprint_tm(this_reply));
+ if (json_flag)
+ printf("}}");
+
printf("\n");
}
if (!quiet_flag)
print_warning("%s: %s\n", name, gai_strerror(ret_ga));
num_noaddress++;
+
+ // Handle JSON output for invalid hosts
+ if (json_flag) {
+ fprintf(stderr, "{\"host\": \"%s\", \"error\": \"%s\"}", name, gai_strerror(ret_ga));
+ return;
+ }
+
return;
}
fprintf(out, " -D, --timestamp print timestamp before each output line\n");
fprintf(out, " --timestamp-format=FORMAT show timestamp in the given format (-D required): ctime|iso|rfc3339\n");
fprintf(out, " -e, --elapsed show elapsed time on return packets\n");
+ fprintf(out, " -J, --json output in JSON format (-c or -C required)\n");
fprintf(out, " -n, --name show targets by name (reverse-DNS lookup for target IPs)\n");
fprintf(out, " -N, --netdata output compatible for netdata (-l -Q are required)\n");
fprintf(out, " -o, --outage show the accumulated outage time (lost packets * packet interval)\n");