int srv_postinit(struct server *srv);
int srv_init_addr(void);
struct server *cli_find_server(struct appctx *appctx, char *arg);
+int cli_clear_counters_server(struct appctx *appctx, char *arg, int force);
struct server *new_server(struct proxy *proxy);
void srv_take(struct server *srv);
void srv_drop(struct server *srv);
struct stconn;
struct uri_auth;
struct proxy;
+struct server;
int stats_dump_proxies(struct stconn *sc, struct buffer *buf, struct htx *htx);
void proxy_stats_clear_counters(int clrall, struct list *stat_modules);
int stats_proxy_in_scope(const struct proxy *px, const struct uri_auth *uri,
const struct proxy *http_px);
+void srv_stats_clear_extra_counters(struct server *sv);
#endif /* _HAPROXY_STATS_PROXY_H */
#include <haproxy/sample.h>
#include <haproxy/sc_strm.h>
#include <haproxy/server.h>
+#include <haproxy/stats-proxy.h>
#include <haproxy/stats.h>
#include <haproxy/ssl_sock.h>
#include <haproxy/stconn.h>
return 1;
}
+/* Reset the statistics counters of a single server, invoked from the
+ * "clear counters server <backend>/<server> [force]" CLI command (dispatched
+ * by cli_parse_clear_counters() in stats.c, since "clear counters" is a
+ * two-word keyword that would otherwise shadow a three-word variant).
+ *
+ * The command is not gated by the server's administrative state: like
+ * "clear counters" / "clear counters all", it only zeroes counter values
+ * and does not touch the server object or its runtime state, so it is safe
+ * to issue on a live server (a concurrent counter increment races on a
+ * value exactly as it already does for "clear counters all"). This is
+ * useful when a server slot is being reused to represent a different
+ * logical entity (e.g. a different Kubernetes pod occupying the same slot
+ * after a rename) and per-entity counter attribution is required.
+ *
+ * When the server's counters are registered in a shared-memory stats file
+ * object (COUNTERS_SHARED_F_LOCAL not set), clearing them breaks the
+ * monotonicity that monitoring tools consuming the shared stats rely on,
+ * and affects every process attached to the object. Such a clear is
+ * therefore refused unless <force> is set.
+ *
+ * <arg> is the "<backend>/<server>" argument. Always returns 1 (the CLI
+ * parser convention for "message emitted, stop"); success or error is
+ * reported to <appctx>.
+ */
+int cli_clear_counters_server(struct appctx *appctx, char *arg, int force)
+{
+ struct server *sv;
+
+ sv = cli_find_server(appctx, arg);
+ if (!sv)
+ return 1;
+
+ if (!force && !(sv->counters.shared.flags & COUNTERS_SHARED_F_LOCAL)) {
+ cli_err(appctx,
+ "Server counters are stored in a shared-memory stats "
+ "file; clearing them breaks monotonicity for monitoring "
+ "tools and affects all attached processes. Append 'force' "
+ "to clear anyway.\n");
+ return 1;
+ }
+
+ HA_SPIN_LOCK(SERVER_LOCK, &sv->lock);
+
+ counters_be_reset(&sv->counters);
+ srv_stats_clear_extra_counters(sv);
+
+ HA_SPIN_UNLOCK(SERVER_LOCK, &sv->lock);
+
+ cli_msg(appctx, LOG_NOTICE, "Server counters cleared.\n");
+ return 1;
+}
+
/* register cli keywords */
static struct cli_kw_list cli_kws = {{ },{
{ { "disable", "agent", NULL }, "disable agent : disable agent checks", cli_parse_disable_agent, NULL },
}
}
}
+
+/* Reset the module-registered extra counters of a single server <sv>, as done
+ * by "clear counters" for every server. Only modules flagged clearable are
+ * reset, matching the OPER-level "clear counters" semantics (the ADMIN-only
+ * "clear counters all" resets non-clearable modules too, but there is no
+ * per-server equivalent of "all"). The native counters are handled separately
+ * by the caller via counters_be_reset().
+ */
+void srv_stats_clear_extra_counters(struct server *sv)
+{
+ struct list *stat_modules = &stats_module_list[STATS_DOMAIN_PROXY];
+ struct stats_module *mod;
+
+ list_for_each_entry(mod, stat_modules, list) {
+ enum stats_domain_px_cap mod_cap = stats_px_get_cap(mod->domain_flags);
+
+ if (!mod->clearable)
+ continue;
+ if (!(mod_cap & STATS_PX_CAP_SRV))
+ continue;
+ if (!sv->extra_counters)
+ continue;
+
+ EXTRA_COUNTERS_INIT(sv->extra_counters,
+ mod,
+ mod->counters,
+ mod->counters_size);
+ }
+}
{
int clrall = 0;
+ /* "clear counters server <b>/<s> [force]" resets the counters of a
+ * single server. Handled here rather than via a dedicated three-word
+ * CLI keyword because "clear counters" is a two-word keyword that would
+ * shadow any three-word variant during keyword lookup. Requires ADMIN
+ * level like "clear counters all": it clears cumulative counters, and
+ * an OPER-only user must not be able to wipe those to hide activity.
+ */
+ if (strcmp(args[2], "server") == 0) {
+ int force = (strcmp(args[4], "force") == 0);
+
+ if (!cli_has_level(appctx, ACCESS_LVL_ADMIN))
+ return 1;
+ return cli_clear_counters_server(appctx, args[3], force);
+ }
+
if (strcmp(args[2], "all") == 0)
clrall = 1;
/* register cli keywords */
static struct cli_kw_list cli_kws = {{ },{
- { { "clear", "counters", NULL }, "clear counters [all] : clear max statistics counters (or all counters)", cli_parse_clear_counters, NULL, NULL },
+ { { "clear", "counters", NULL }, "clear counters [all|server <bk>/<srv> [force]] : clear max statistics counters (or all, or one server's)", cli_parse_clear_counters, NULL, NULL },
{ { "show", "info", NULL }, "show info [desc|json|typed|float]* : report information about the running process", cli_parse_show_info, cli_io_handler_dump_info, NULL },
{ { "show", "stat", NULL }, "show stat [desc|json|no-maint|typed|up]*: report counters for each proxy and server", cli_parse_show_stat, cli_io_handler_dump_stat, cli_io_handler_release_stat },
{ { "show", "schema", "json", NULL }, "show schema json : report schema used for stats", cli_parse_show_schema_json, cli_io_handler_dump_json_schema, NULL },