]> git.ipfire.org Git - thirdparty/haproxy.git/commitdiff
MINOR: stconn: add a new pair of sf functions {bs,fs}.debug_str
authorWilly Tarreau <w@1wt.eu>
Tue, 30 Jul 2024 15:57:37 +0000 (17:57 +0200)
committerWilly Tarreau <w@1wt.eu>
Wed, 7 Aug 2024 12:07:41 +0000 (14:07 +0200)
These are passed to the underlying mux to retrieve debug information
at the mux level (stream/connection) as a string that's meant to be
added to logs.

The API is quite complex just because we can't pass any info to the
bottom function. So we construct a union and pass the argument as an
int, and expect the callee to fill that with its buffer in return.

Most likely the mux->ctl and ->sctl API should be reworked before
the release to simplify this.

The functions take an optional argument that is a bit mask of the
layers to dump:
  muxs=1
  muxc=2
  xprt=4
  conn=8
  sock=16

The default (0) logs everything available.

doc/configuration.txt
include/haproxy/connection-t.h
src/stconn.c

index d5c6a0e86f3d41989faa80bb428f8c4b3b995650..6d975df77d90ed336dab30d134a26f04dfcce40a 100644 (file)
@@ -23966,11 +23966,13 @@ Summary of sample fetch methods in this section and their respective types:
   keyword                                             output type
 ----------------------------------------------------+-------------
 bs.aborted                                            boolean
+bs.debug_str([<bitmap>])                              string
 bs.id                                                 integer
 bs.rst_code                                           integer
 distcc_body(<token>[,<occ>])                          binary
 distcc_param(<token>[,<occ>])                         integer
 fs.aborted                                            boolean
+fs.debug_str([<bitmap>])                              string
 fs.id                                                 integer
 fs.rst_code                                           integer
 payload(<offset>,<length>)                            binary
@@ -24008,6 +24010,28 @@ bs.aborted: boolean
   Returns true is an abort was received from the server for the current
   stream. Otherwise false is returned.
 
+bs.debug_str([<bitmap>]) : string
+  This function is meant to be used by developers during certain complex
+  troubleshooting sessions. It extracts some internal states from the lower
+  layers of the backend stream and connection, and arranges them as a string,
+  generally in the form of a series of "name=value" delimited with spaces. The
+  <bitmap> optional argument indicates what layer(s) to extract information
+  from, and is an arithmetic OR (or a sum) of the following values:
+     - socket layer: 16
+     - connection layer: 8
+     - transport layer (e.g. SSL): 4
+     - mux connection: 2
+     - mux stream: 1
+
+  These values might change across versions. The default value of zero is
+  special and enables all layers. Please do not rely on the output of this
+  function for long-term production monitoring. It is meant to evolve even
+  within a stable branch, as the needs for increased details arise. One use
+  typical use case is to concatenate these information at the very end of a
+  log-format, along with fs.debug_str(). Example:
+
+     log-format "$HAPROXY_HTTP_LOG_FMT fs=<%[fs.debug_str]> bs=<%[bs.debug_str]>"
+
 bs.id : integer
   Returns the multiplexer's stream ID on the server side. It is the
   multiplexer's responsibility to return the appropriate information.
@@ -24048,6 +24072,28 @@ fs.aborted: boolean
   Returns true is an abort was received from the client for the current
   stream. Otherwise false is returned.
 
+fs.debug_str([<bitmap>]) : string
+  This function is meant to be used by developers during certain complex
+  troubleshooting sessions. It extracts some internal states from the lower
+  layers of the frontend stream and connection, and arranges them as a string,
+  generally in the form of a series of "name=value" delimited with spaces. The
+  <bitmap> optional argument indicates what layer(s) to extract information
+  from, and is an arithmetic OR (or a sum) of the following values:
+     - socket layer: 16
+     - connection layer: 8
+     - transport layer (e.g. SSL): 4
+     - mux connection: 2
+     - mux stream: 1
+
+  These values might change across versions. The default value of zero is
+  special and enables all layers. Please do not rely on the output of this
+  function for long-term production monitoring. It is meant to evolve even
+  within a stable branch, as the needs for increased details arise. One use
+  typical use case is to concatenate these information at the very end of a
+  log-format, along with bs.debug_str(). Example:
+
+     log-format "$HAPROXY_HTTP_LOG_FMT fs=<%[fs.debug_str]> bs=<%[bs.debug_str]>"
+
 fs.id : integer
   Returns the multiplexer's stream ID on the client side. It is the
   multiplexer's responsibility to return the appropriate information. For
index 41c937c8c82758d851ebec119e81a21d1377f195..7119c0c20de18570b22c565c827a64e45a880720 100644 (file)
@@ -331,8 +331,16 @@ enum mux_ctl_type {
 /* sctl command used by mux->sctl() */
 enum mux_sctl_type {
        MUX_SCTL_SID, /* Return the mux stream ID as output, as a signed 64bits integer */
+       MUX_SCTL_DBG_STR,    /* takes a mux_sctl_dbg_str_ctx argument, reads flags and returns debug info */
 };
 
+#define MUX_SCTL_DBG_STR_L_MUXS  0x00000001  // info from mux stream
+#define MUX_SCTL_DBG_STR_L_MUXC  0x00000002  // info from mux connection
+#define MUX_SCTL_DBG_STR_L_XPRT  0x00000004  // info from xprt layer
+#define MUX_SCTL_DBG_STR_L_CONN  0x00000008  // info from struct connection layer
+#define MUX_SCTL_DBG_STR_L_SOCK  0x00000010  // info from socket layer (quic_conn as well)
+
+
 /* response for ctl MUX_STATUS */
 #define MUX_STATUS_READY (1 << 0)
 
@@ -688,6 +696,15 @@ struct tlv_ssl {
        uint8_t sub_tlv[VAR_ARRAY];
 }__attribute__((packed));
 
+/* context for a MUX_SCTL_DBG_STR call */
+union mux_sctl_dbg_str_ctx {
+       struct {
+               uint debug_flags; // union of MUX_SCTL_DBG_STR_L_*
+       } arg; // sctl argument for the call
+       struct {
+               struct buffer buf;
+       } ret; // sctl return contents
+};
 
 /* This structure is used to manage idle connections, their locking, and the
  * list of such idle connections to be removed. It is per-thread and must be
index cabc23a7ad3078bf297231e59a4509c5691f26db..eacbb5c6be51a427fa1aa309fcf4a1c76de0e24e 100644 (file)
@@ -12,6 +12,7 @@
 
 #include <haproxy/api.h>
 #include <haproxy/applet.h>
+#include <haproxy/arg.h>
 #include <haproxy/connection.h>
 #include <haproxy/check.h>
 #include <haproxy/filters.h>
@@ -2364,6 +2365,45 @@ void sc_conn_commit_endp_upgrade(struct stconn *sc)
        BUG_ON(!sc->sedesc);
 }
 
+/* Return a debug string exposing the internals of the front or back
+ * stream/connection when supported. It will be protocol-dependent and will
+ * change over time like the output of "show fd" or "show sess all".
+ */
+static int smp_fetch_debug_str(const struct arg *args, struct sample *smp, const char *kw, void *private)
+{
+       struct connection *conn;
+       struct stconn *sc;
+       union mux_sctl_dbg_str_ctx sctl_ctx = { };
+
+       if (!smp->strm)
+               return 0;
+
+       sc = (kw[0] == 'f' ? smp->strm->scf : smp->strm->scb);
+       conn = sc_conn(sc);
+
+       if (!conn)
+               return 0;
+
+       /* a missing mux is necessarily on the backend, and may arrive later */
+       if (!conn->mux) {
+               smp->flags |= SMP_F_MAY_CHANGE;
+               return 0;
+       }
+
+       /* Not implemented, return nothing */
+       if (!conn->mux->sctl)
+               return 0;
+
+       sctl_ctx.arg.debug_flags = args->data.sint ? args->data.sint : ~0U;
+       if (conn->mux->sctl(sc, MUX_SCTL_DBG_STR, &sctl_ctx) == -1)
+               return 0;
+
+       smp->data.type = SMP_T_STR;
+       smp->flags = SMP_F_VOL_TEST | SMP_F_MAY_CHANGE;
+       smp->data.u.str = sctl_ctx.ret.buf;
+       return 1;
+}
+
 /* return the frontend or backend mux stream ID.
  */
 static int
@@ -2459,9 +2499,11 @@ smp_fetch_strm_rst_code(const struct arg *args, struct sample *smp, const char *
  * common denominator, the type that can be casted into all other ones.
  */
 static struct sample_fetch_kw_list sample_fetch_keywords = {ILH, {
+       { "bs.debug_str", smp_fetch_debug_str, ARG1(0,SINT), NULL, SMP_T_STR, SMP_USE_L5SRV },
        { "bs.id", smp_fetch_sid, 0, NULL, SMP_T_SINT, SMP_USE_L5SRV },
        { "bs.aborted", smp_fetch_strm_aborted, 0, NULL, SMP_T_SINT, SMP_USE_L5SRV },
        { "bs.rst_code", smp_fetch_strm_rst_code, 0, NULL, SMP_T_SINT, SMP_USE_L5SRV },
+       { "fs.debug_str", smp_fetch_debug_str, ARG1(0,SINT), NULL, SMP_T_STR, SMP_USE_L5CLI },
        { "fs.id", smp_fetch_sid, 0, NULL, SMP_T_STR, SMP_USE_L5CLI },
        { "fs.aborted", smp_fetch_strm_aborted, 0, NULL, SMP_T_SINT, SMP_USE_L5CLI },
        { "fs.rst_code", smp_fetch_strm_rst_code, 0, NULL, SMP_T_SINT, SMP_USE_L5CLI },