JSON output

This commit is contained in:
2025-08-05 05:30:13 +02:00
parent 08daf76d81
commit 8b6c7c7bc8
4 changed files with 83 additions and 6 deletions

View File

@@ -75,6 +75,9 @@ garbage collection period in number of refresh. default is 50.
\fB-P\fP \fB-P\fP
Show only processes with the specified pid(s). Show only processes with the specified pid(s).
.TP .TP
\fB-j\fP
Output in JSON format.
.TP
\fB-f\fP \fB-f\fP
EXPERIMENTAL: specify string pcap filter (like tcpdump). This may be removed or changed in a future version. EXPERIMENTAL: specify string pcap filter (like tcpdump). This may be removed or changed in a future version.
.TP .TP

View File

@@ -49,6 +49,8 @@ extern int viewMode;
extern bool showcommandline; extern bool showcommandline;
extern bool showBasename; extern bool showBasename;
extern bool output_json;
extern unsigned refreshlimit; extern unsigned refreshlimit;
extern unsigned refreshcount; extern unsigned refreshcount;
@@ -90,6 +92,7 @@ public:
void show(int row, unsigned int proglen, unsigned int devlen); void show(int row, unsigned int proglen, unsigned int devlen);
void log(); void log();
void json();
double sent_value; double sent_value;
double recv_value; double recv_value;
@@ -232,6 +235,48 @@ void Line::log() {
<< recv_value << std::endl; << recv_value << std::endl;
} }
#include <iomanip>
std::string escape_json(const std::string &s) {
std::ostringstream o;
for (auto c = s.cbegin(); c != s.cend(); c++) {
switch (*c) {
case '"': o << "\\\""; break;
case '\\': o << "\\\\"; break;
case '\b': o << "\\b"; break;
case '\f': o << "\\f"; break;
case '\n': o << "\\n"; break;
case '\r': o << "\\r"; break;
case '\t': o << "\\t"; break;
default:
if ('\x00' <= *c && *c <= '\x1f') {
o << "\\u"
<< std::hex << std::setw(4) << std::setfill('0') << static_cast<int>(*c);
} else {
o << *c;
}
}
}
return o.str();
}
void Line::json() {
std::cout << "{";
std::cout << "\"name\": \"" << escape_json(m_name) << "\"";
std::cout << ", ";
std::cout << "\"pid\": \"" << m_pid << "\"";
std::cout << ", ";
std::cout << "\"uid\": \"" << m_uid << "\"";
std::cout << ", ";
std::cout << "\"devicename\": \"" << devicename << "\"";
std::cout << ", ";
std::cout << "\"sent\": " << sent_value;
std::cout << ", ";
std::cout << "\"recv\": " << recv_value;
std::cout << "}";
}
int get_devlen(Line *lines[], int nproc, int rows) { int get_devlen(Line *lines[], int nproc, int rows) {
int devlen = MIN_COLUMN_WIDTH_DEV; int devlen = MIN_COLUMN_WIDTH_DEV;
int curlen; int curlen;
@@ -343,6 +388,28 @@ void show_trace(Line *lines[], int nproc) {
} }
} }
char* get_iso8601_timestamp() {
static char buffer[32];
time_t now = time(NULL);
struct tm *utc = gmtime(&now);
strftime(buffer, sizeof(buffer), "%Y-%m-%dT%H:%M:%SZ", utc);
return buffer;
}
void show_json(Line *lines[], int nproc) {
/* print them */
std::cout << "{\"timestamp\": \""<< get_iso8601_timestamp() << "\", \"processes\": [";
for (int i = 0; i < nproc; i++) {
if(i>0){
std::cout << ",";
}
lines[i]->json();
delete lines[i];
}
std::cout << "]}"<< std::endl;
}
void show_ncurses(Line *lines[], int nproc) { void show_ncurses(Line *lines[], int nproc) {
int rows; // number of terminal rows int rows; // number of terminal rows
int cols; // number of terminal columns int cols; // number of terminal columns
@@ -453,7 +520,9 @@ void do_refresh() {
/* sort the accumulated lines */ /* sort the accumulated lines */
qsort(lines, nproc, sizeof(Line *), GreatestFirst); qsort(lines, nproc, sizeof(Line *), GreatestFirst);
if (tracemode || DEBUG) if (output_json)
show_json(lines, nproc);
else if (tracemode || DEBUG)
show_trace(lines, nproc); show_trace(lines, nproc);
else else
show_ncurses(lines, nproc); show_ncurses(lines, nproc);

View File

@@ -69,6 +69,7 @@ static void help(bool iserror) {
output << " b: display the program basename instead of the fullpath\n"; output << " b: display the program basename instead of the fullpath\n";
output << " m: switch between total (kB, bytes, MB) and throughput (kB/s, " output << " m: switch between total (kB, bytes, MB) and throughput (kB/s, "
" MB/s, GB/s) mode\n"; " MB/s, GB/s) mode\n";
output << " j: json output\n";
} }
void quit_cb(int /* i */) { void quit_cb(int /* i */) {
@@ -80,7 +81,7 @@ void quit_cb(int /* i */) {
} }
void forceExit(bool success, const char *msg, ...) { void forceExit(bool success, const char *msg, ...) {
if ((!tracemode) && (!DEBUG)) { if ((!tracemode) && (!DEBUG) && (!output_json)) {
exit_ui(); exit_ui();
} }
@@ -141,7 +142,7 @@ void clean_up() {
} }
procclean(); procclean();
if ((!tracemode) && (!DEBUG)) if ((!tracemode) && (!DEBUG) && (!output_json))
exit_ui(); exit_ui();
} }
@@ -153,7 +154,7 @@ int main(int argc, char **argv) {
int garbage_collection_period = 50; int garbage_collection_period = 50;
int opt; int opt;
while ((opt = getopt(argc, argv, "Vhxtpsd:v:c:laf:Cbg:P:")) != -1) { while ((opt = getopt(argc, argv, "Vhxtpsd:v:c:laf:Cbg:P:j")) != -1) {
switch (opt) { switch (opt) {
case 'V': case 'V':
versiondisplay(); versiondisplay();
@@ -204,6 +205,9 @@ int main(int argc, char **argv) {
case 'P': case 'P':
pidsToWatch.insert((pid_t)atoi(optarg)); pidsToWatch.insert((pid_t)atoi(optarg));
break; break;
case 'j':
output_json = true;
break;
default: default:
help(true); help(true);
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
@@ -300,7 +304,7 @@ int main(int argc, char **argv) {
struct dpargs *userdata = (dpargs *)malloc(sizeof(struct dpargs)); struct dpargs *userdata = (dpargs *)malloc(sizeof(struct dpargs));
if ((!tracemode) && (!DEBUG)) { if ((!tracemode) && (!DEBUG) && (!output_json)) {
init_ui(); init_ui();
} }
@@ -328,7 +332,7 @@ int main(int argc, char **argv) {
time_t const now = ::time(NULL); time_t const now = ::time(NULL);
if (last_refresh_time + refreshdelay <= now) { if (last_refresh_time + refreshdelay <= now) {
last_refresh_time = now; last_refresh_time = now;
if ((!DEBUG) && (!tracemode)) { if ((!DEBUG) && (!tracemode) && (!output_json)) {
// handle user input // handle user input
ui_tick(); ui_tick();
} }

View File

@@ -63,6 +63,7 @@ bool showcommandline = false;
bool showBasename = false; bool showBasename = false;
// viewMode: kb/s or total // viewMode: kb/s or total
int viewMode = VIEWMODE_KBPS; int viewMode = VIEWMODE_KBPS;
bool output_json = false;
const char version[] = " version " VERSION; const char version[] = " version " VERSION;
timeval curtime; timeval curtime;