/* HTTP server */
struct rspamd_http_context *http_ctx;
struct rspamd_http_connection_router *http;
- /* Server's start time */
- ev_tstamp start_time;
/* Main server */
struct rspamd_main *srv;
/* SSL cert */
data[4] = st.actions_stat[METRIC_ACTION_SOFT_REJECT];
/* Get uptime */
- uptime = ev_time() - session->ctx->start_time;
+ uptime = ev_time() - session->ctx->srv->start_time;
ucl_object_insert_key(obj, ucl_object_fromstring(RVERSION), "version", 0, false);
ucl_object_insert_key(obj, ucl_object_fromstring("ok"), "auth", 0, false);
ucl_object_insert_key(top, ucl_object_fromstring(RVERSION), "version", 0, false);
ucl_object_insert_key(top, ucl_object_fromstring(session->ctx->cfg->checksum), "config_id", 0, false);
- uptime = ev_time() - session->ctx->start_time;
+ uptime = ev_time() - session->ctx->srv->start_time;
ucl_object_insert_key(top, ucl_object_fromint(uptime), "uptime", 0, false);
ucl_object_insert_key(top, ucl_object_frombool(session->is_read_only),
"read_only", 0, false);
struct rspamd_task *task;
struct rspamd_stat_cbdata *cbdata;
- uptime = ev_time() - session->ctx->start_time;
+ uptime = ev_time() - session->ctx->srv->start_time;
ctx = session->ctx;
memcpy(&stat_copy, session->ctx->worker->srv->stat, sizeof(stat_copy));
top = rspamd_worker_metrics_object(session->ctx->cfg, &stat_copy, uptime);
- ucl_object_insert_key(top, ucl_object_fromint(session->ctx->start_time), "start_time", 0, false);
+ ucl_object_insert_key(top, ucl_object_fromint(session->ctx->srv->start_time), "start_time", 0, false);
ucl_object_insert_key(top, ucl_object_frombool(session->is_read_only),
"read_only", 0, false);
task = rspamd_task_new(session->ctx->worker, session->cfg, session->pool,
"controller",
rspamd_controller_accept_socket);
- ctx->start_time = ev_time();
ctx->worker = worker;
ctx->cfg = worker->srv->cfg;
ctx->srv = worker->srv;
#include "unix-std.h"
#include "protocol_internal.h"
#include "libserver/mempool_vars_internal.h"
+#include "libserver/worker_util.h"
#include "contrib/fastutf8/fastutf8.h"
#include "task.h"
#include "lua/lua_classnames.h"
goto err;
}
break;
+ case 'M':
+ case 'm':
+ /* metrics, process */
+ if (COMPARE_CMD(p, MSG_CMD_METRICS, pathlen)) {
+ msg_debug_protocol("got metrics command");
+ task->cmd = CMD_METRICS;
+ task->flags |= RSPAMD_TASK_FLAG_SKIP;
+ task->processed_stages |= RSPAMD_TASK_STAGE_DONE; /* Skip all */
+ }
+ else {
+ goto err;
+ }
+ break;
default:
goto err;
}
g_array_free(extra, TRUE);
}
-void rspamd_protocol_write_reply(struct rspamd_task *task, ev_tstamp timeout)
+void rspamd_protocol_write_reply(struct rspamd_task *task, ev_tstamp timeout, struct rspamd_main *srv)
{
struct rspamd_http_message *msg;
const char *ctype = "application/json";
rspamd_fstring_t *reply;
+ ev_tstamp now = ev_time();
msg = rspamd_http_new_message(HTTP_RESPONSE);
}
}
else {
+ rspamd_fstring_t *output;
+ struct rspamd_stat stat_copy;
msg->status = rspamd_fstring_new_init("OK", 2);
switch (task->cmd) {
rspamd_http_message_set_body(msg, "pong" CRLF, 6);
ctype = "text/plain";
break;
+ case CMD_METRICS:
+ msg_debug_protocol("writing metrics to client");
+
+ memcpy(&stat_copy, srv->stat, sizeof(stat_copy));
+ output = rspamd_metrics_to_prometheus_string(
+ rspamd_worker_metrics_object(srv->cfg, &stat_copy, now - srv->start_time));
+ rspamd_http_message_set_body_from_fstring_steal(msg, output);
+ ctype = "application/openmetrics-text; version=1.0.0; charset=utf-8";
+ break;
default:
msg_err_protocol("BROKEN");
break;
}
ev_now_update(task->event_loop);
- msg->date = ev_time();
+ msg->date = now;
rspamd_http_connection_reset(task->http_conn);
rspamd_http_connection_write_message(task->http_conn, msg, NULL,
struct rspamd_protocol_log_symbol_result results[];
};
-struct rspamd_metric;
+struct rspamd_main;
/**
* Process headers into HTTP message and set appropriate task fields
* @param task task object
* @return 0 if we wrote reply and -1 if there was some error
*/
-void rspamd_protocol_write_reply(struct rspamd_task *task, ev_tstamp timeout);
+void rspamd_protocol_write_reply(struct rspamd_task *task, ev_tstamp timeout, struct rspamd_main *srv);
/**
* Convert rspamd output to legacy protocol reply
-/*-
- * Copyright 2017 Vsevolod Stakhov
+/*
+ * Copyright 2024 Vsevolod Stakhov
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
- * http://www.apache.org/licenses/LICENSE-2.0
+ * http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* Return a confirmation that spamd is alive
*/
#define MSG_CMD_PING "ping"
+
+#define MSG_CMD_METRICS "metrics"
/*
* Process this message as described above and return modified message
*/
}
else {
if (!(task->processed_stages & RSPAMD_TASK_STAGE_REPLIED)) {
- rspamd_protocol_write_reply(task, write_timeout);
+ rspamd_protocol_write_reply(task, write_timeout, task->worker->srv);
}
}
}
-/*-
- * Copyright 2016 Vsevolod Stakhov
+/*
+ * Copyright 2024 Vsevolod Stakhov
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
- * http://www.apache.org/licenses/LICENSE-2.0
+ * http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
CMD_CHECK_RSPAMC, /* Legacy rspamc format (like SA one) */
CMD_CHECK, /* Legacy check - metric json reply */
CMD_CHECK_V2, /* Modern check - symbols in json reply */
+ CMD_METRICS,
};
enum rspamd_task_stage {
exit(EXIT_FAILURE);
}
+ rspamd_main->start_time = ev_time();
/* Unblock signals */
sigemptyset(&signals.sa_mask);
sigprocmask(SIG_SETMASK, &signals.sa_mask, NULL);
struct roll_history *history; /**< rolling history */
struct ev_loop *event_loop;
ev_signal term_ev, int_ev, hup_ev, usr1_ev; /**< signals */
+ ev_tstamp start_time;
struct rspamd_http_context *http_ctx;
};
/* Language detector */
struct rspamd_lang_detector *lang_det;
double task_timeout;
+ struct rspamd_main *srv;
};
enum rspamd_backend_flags {
int out_type = UCL_EMIT_JSON_COMPACT;
const char *ctype = "application/json";
const rspamd_ftok_t *accept_hdr = rspamd_task_get_request_header(task, "Accept");
+ rspamd_fstring_t *output;
+ struct rspamd_stat stat_copy;
if (accept_hdr && rspamd_substring_search(accept_hdr->begin, accept_hdr->len,
"application/msgpack", sizeof("application/msgpack") - 1) != -1) {
rspamd_http_message_set_body(msg, "pong" CRLF, 6);
ctype = "text/plain";
break;
+ case CMD_METRICS:
+ memcpy(&stat_copy, session->ctx->srv->stat, sizeof(stat_copy));
+ output = rspamd_metrics_to_prometheus_string(
+ rspamd_worker_metrics_object(task->cfg, &stat_copy, ev_time() - session->ctx->srv->start_time));
+ rspamd_http_message_set_body_from_fstring_steal(msg, output);
+ ctype = "application/openmetrics-text; version=1.0.0; charset=utf-8";
+ break;
default:
msg_err_task("BROKEN");
break;
task->flags |= RSPAMD_TASK_FLAG_SKIP;
}
else {
- if (task->cmd == CMD_PING) {
+ if (task->cmd == CMD_PING || task->cmd == CMD_METRICS) {
task->flags |= RSPAMD_TASK_FLAG_SKIP;
}
else {
g_assert(rspamd_worker_check_context(worker->ctx, rspamd_rspamd_proxy_magic));
ctx->cfg = worker->srv->cfg;
+ ctx->srv = worker->srv;
ctx->event_loop = rspamd_prepare_worker(worker, "rspamd_proxy",
proxy_accept_socket);
task->flags |= RSPAMD_TASK_FLAG_SKIP;
}
else {
- if (task->cmd == CMD_PING) {
+ if (task->cmd == CMD_PING || task->cmd == CMD_METRICS) {
task->flags |= RSPAMD_TASK_FLAG_SKIP;
}
else {
-/*-
- * Copyright 2016 Vsevolod Stakhov
+/*
+ * Copyright 2024 Vsevolod Stakhov
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
- * http://www.apache.org/licenses/LICENSE-2.0
+ * http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,