commit 0df00b6: rspamc: add -R option for human readable report
Amish
contact at via.aur
Sat Jan 21 12:21:03 UTC 2023
Author: Amish
Date: 2023-01-20 20:59:48 +0530
URL: https://github.com/rspamd/rspamd/commit/0df00b6af6775d67d92b15f71b9a485297deeb80
rspamc: add -R option for human readable report
---
doc/rspamc.1 | 5 +++
doc/rspamc.1.md | 3 ++
src/client/rspamc.cxx | 105 +++++++++++++++++++++++++++++++++++++++++++-------
3 files changed, 99 insertions(+), 14 deletions(-)
diff --git a/doc/rspamc.1 b/doc/rspamc.1
index 338f8053d..8989f98b2 100644
--- a/doc/rspamc.1
+++ b/doc/rspamc.1
@@ -149,6 +149,11 @@ Bind to specified ip address
.RS
.RE
.TP
+.B \-R, \-\-human
+Output human readable report
+.RS
+.RE
+.TP
.B \-j, \-\-json
Output formatted JSON
.RS
diff --git a/doc/rspamc.1.md b/doc/rspamc.1.md
index afb256792..c6baa939c 100644
--- a/doc/rspamc.1.md
+++ b/doc/rspamc.1.md
@@ -86,6 +86,9 @@ requires input.
-b *host:port*, \--bind=*host:port*
: Bind to specified ip address
+-R, \--human
+: Output human readable report
+
-j, \--json
: Output formatted JSON
diff --git a/src/client/rspamc.cxx b/src/client/rspamc.cxx
index 973bb58a4..57505cf66 100644
--- a/src/client/rspamc.cxx
+++ b/src/client/rspamc.cxx
@@ -71,6 +71,7 @@ static gboolean pass_all;
static gboolean tty = FALSE;
static gboolean verbose = FALSE;
static gboolean print_commands = FALSE;
+static gboolean humanreport = FALSE;
static gboolean json = FALSE;
static gboolean compact = FALSE;
static gboolean headers = FALSE;
@@ -134,6 +135,7 @@ static GOptionEntry entries[] =
"Bind to specified ip address", nullptr},
{"commands", 0, 0, G_OPTION_ARG_NONE, &print_commands,
"List available commands", nullptr},
+ {"human", 'R', 0, G_OPTION_ARG_NONE, &humanreport, "Output human readable report", nullptr},
{"json", 'j', 0, G_OPTION_ARG_NONE, &json, "Output json reply", nullptr},
{"compact", '\0', 0, G_OPTION_ARG_NONE, &compact, "Output compact json reply", nullptr},
{"headers", 0, 0, G_OPTION_ARG_NONE, &headers, "Output HTTP headers",
@@ -823,6 +825,59 @@ add_options(GQueue *opts)
}
}
+static void
+print_indented_line(FILE *out, std::string line, size_t maxlen, size_t indent)
+{
+ if (maxlen < 1) return;
+
+ std::string s;
+ for (size_t pos = 0; pos < line.length(); pos += s.length()) {
+ s = line.substr(pos, pos ? (maxlen-indent) : maxlen);
+ if (indent && pos) fmt::print(out, "{:>{}}", " ", indent);
+ fmt::print(out, "{}\n", s);
+ }
+}
+
+static void
+rspamc_symbol_human_output(FILE *out, const ucl_object_t *obj)
+{
+ auto first = true;
+ double score = 0;
+ const char *key = nullptr, *desc = nullptr;
+
+ const auto *val = ucl_object_lookup(obj, "score");
+ if (val != nullptr) score = ucl_object_todouble(val);
+
+ key = ucl_object_key(obj);
+ val = ucl_object_lookup(obj, "description");
+ if (val != nullptr) desc = ucl_object_tostring(val);
+
+ std::string line = fmt::format("{:>4.1f} {:<22} ", score, key);
+ if (desc != nullptr) line += desc;
+
+ val = ucl_object_lookup(obj, "options");
+ if (val != nullptr && val->type == UCL_ARRAY) {
+ ucl_object_iter_t it = nullptr;
+ const ucl_object_t *cur;
+
+ line += fmt::format("{}[", desc == nullptr ? "" : " ");
+
+ while ((cur = ucl_object_iterate (val, &it, true)) != nullptr) {
+ if (first) {
+ line += fmt::format("{}", ucl_object_tostring(cur));
+ first = false;
+ }
+ else {
+ line += fmt::format(",{}", ucl_object_tostring(cur));
+ }
+ }
+ line += ']';
+ }
+ else if (desc == nullptr) line += '\n';
+
+ print_indented_line(out, line, 78, 28);
+}
+
static void
rspamc_symbol_output(FILE *out, const ucl_object_t *obj)
{
@@ -864,12 +919,12 @@ rspamc_metric_output(FILE *out, const ucl_object_t *obj)
auto print_protocol_string = [&](const char *ucl_name, const char *output_message) {
auto *elt = ucl_object_lookup(obj, ucl_name);
if (elt) {
- fmt::print(out, "{}: {}\n", output_message,
+ fmt::print(out, fmt::runtime(humanreport ? ",{}={}" : "{}: {}\n"), output_message,
emphasis_argument(ucl_object_tostring(elt)));
}
};
- fmt::print(out, "[Metric: default]\n");
+ if (!humanreport) fmt::print(out, "[Metric: default]\n");
const auto *elt = ucl_object_lookup(obj, "required_score");
@@ -885,6 +940,13 @@ rspamc_metric_output(FILE *out, const ucl_object_t *obj)
got_scores++;
}
+ if (humanreport) {
+ fmt::print(out,
+ "{}/{}",
+ emphasis_argument(score, 2),
+ emphasis_argument(required_score, 2));
+ }
+
elt = ucl_object_lookup(obj, "action");
if (elt) {
auto act = rspamd_action_from_str_rspamc(ucl_object_tostring(elt));
@@ -915,26 +977,36 @@ rspamc_metric_output(FILE *out, const ucl_object_t *obj)
colorized_action = fmt::format(fmt::emphasis::bold, ucl_object_tostring(elt));
break;
}
- fmt::print(out, "Action: {}\n", colorized_action);
+ fmt::print(out, fmt::runtime(humanreport ? ",Action={}" : "Action: {}\n"), colorized_action);
}
- fmt::print(out, "Spam: {}\n", emphasis_argument(act.value() < METRIC_ACTION_GREYLIST ?
- "true" : "false"));
+ fmt::print(out, fmt::runtime(humanreport ? ",Spam={}" : "Spam: {}\n"),
+ emphasis_argument(act.value() < METRIC_ACTION_GREYLIST ?
+ "true" : "false"));
}
else {
print_protocol_string("action", "Action");
}
}
- print_protocol_string("subject", "Subject");
+ if (!humanreport) print_protocol_string("subject", "Subject");
- if (got_scores == 2) {
+ if (humanreport) fmt::print(out, "\n");
+ else if (got_scores == 2) {
fmt::print(out,
"Score: {} / {}\n",
emphasis_argument(score, 2),
emphasis_argument(required_score, 2));
}
+ if (humanreport) {
+ fmt::print(out, "Content analysis details: ({} points, {} required)\n\n",
+ emphasis_argument(score, 2),
+ emphasis_argument(required_score, 2));
+ fmt::print(out, " pts rule name description\n");
+ fmt::print(out, "---- ---------------------- --------------------------------------------------\n");
+ }
+
elt = ucl_object_lookup(obj, "symbols");
if (elt) {
@@ -949,9 +1021,11 @@ rspamc_metric_output(FILE *out, const ucl_object_t *obj)
sort_ucl_container_with_default(symbols, "name");
for (const auto *sym_obj : symbols) {
- rspamc_symbol_output(out, sym_obj);
+ if (humanreport) rspamc_symbol_human_output(out, sym_obj);
+ else rspamc_symbol_output(out, sym_obj);
}
}
+ if (humanreport) fmt::print(out, "\n");
}
static void
@@ -988,8 +1062,10 @@ rspamc_symbols_output(FILE *out, ucl_object_t *obj)
}
};
- print_protocol_string("message-id", "Message-ID");
- print_protocol_string("queue-id", "Queue-ID");
+ if (!humanreport) {
+ print_protocol_string("message-id", "Message-ID");
+ print_protocol_string("queue-id", "Queue-ID");
+ }
const auto *elt = ucl_object_lookup(obj, "urls");
@@ -1003,7 +1079,7 @@ rspamc_symbols_output(FILE *out, ucl_object_t *obj)
emitted = (char *)ucl_object_emit(elt, UCL_EMIT_JSON);
}
- fmt::print(out, "Urls: {}\n", emitted);
+ if (emitted && strcmp(emitted, "[]")) fmt::print(out, "Urls: {}\n", emitted);
free(emitted);
}
@@ -1018,11 +1094,12 @@ rspamc_symbols_output(FILE *out, ucl_object_t *obj)
emitted = (char *)ucl_object_emit(elt, UCL_EMIT_JSON);
}
- fmt::print(out, "Emails: {}\n", emitted);
+ if (emitted && strcmp(emitted, "[]")) fmt::print(out, "Emails: {}\n", emitted);
free(emitted);
}
print_protocol_string("error", "Scan error");
+ if (humanreport) return;
elt = ucl_object_lookup(obj, "messages");
if (elt && elt->type == UCL_OBJECT) {
@@ -1646,13 +1723,13 @@ rspamc_client_cb(struct rspamd_client_connection *conn,
}
else {
if (cmd.need_input && !json) {
- if (!compact) {
+ if (!compact && !humanreport) {
fmt::print(out, "Results for file: {} ({:.3} seconds)\n",
emphasis_argument(cbdata->filename), diff);
}
}
else {
- if (!compact && !json) {
+ if (!compact && !json && !humanreport) {
fmt::print(out, "Results for command: {} ({:.3} seconds)\n",
emphasis_argument(cmd.name), diff);
}
More information about the Commits
mailing list