]> git.ipfire.org Git - thirdparty/haproxy.git/commitdiff
REORG: cli: move "show errors" out of cli.c
authorWilly Tarreau <w@1wt.eu>
Tue, 22 Nov 2016 18:48:51 +0000 (19:48 +0100)
committerWilly Tarreau <w@1wt.eu>
Thu, 24 Nov 2016 15:59:28 +0000 (16:59 +0100)
It really belongs to proto_http.c since it's a dump for HTTP request
and response errors. Note that it's possible that some parts do not
need to be exported anymore since it really is the only place where
errors are manipulated.

include/types/cli.h
src/cli.c
src/proto_http.c

index ebe4adb6224cacc767f36e2aeee3b185be8bf092..0ebfc69b4a27bdb5ccc0e24fdc3da35b803177ed 100644 (file)
@@ -47,7 +47,6 @@ enum {
        STAT_CLI_PROMPT,     /* display the prompt (first output, same code) */
        STAT_CLI_PRINT,      /* display message in cli->msg */
        STAT_CLI_PRINT_FREE, /* display message in cli->msg. After the display, free the pointer */
-       STAT_CLI_O_ERR,      /* dump errors */
        STAT_CLI_O_ENV,      /* dump environment */
        STAT_CLI_O_CUSTOM,   /* custom callback pointer */
 };
index 39fe01fdea5c44e9b7ebf40cfd315ab5b09b066b..b1d2e54df724502044d8b671c31d735ac6ddc02e 100644 (file)
--- a/src/cli.c
+++ b/src/cli.c
@@ -56,7 +56,6 @@
 #include <proto/pipe.h>
 #include <proto/listener.h>
 #include <proto/map.h>
-#include <proto/proto_http.h>
 #include <proto/proto_uxst.h>
 #include <proto/proxy.h>
 #include <proto/sample.h>
@@ -68,7 +67,6 @@
 #include <proto/task.h>
 
 static int stats_dump_env_to_buffer(struct stream_interface *si);
-static int stats_dump_errors_to_buffer(struct stream_interface *si);
 
 static struct applet cli_applet;
 
@@ -79,7 +77,6 @@ static const char stats_sock_usage_msg[] =
        "  prompt         : toggle interactive mode with prompt\n"
        "  quit           : disconnect\n"
        "  show env [var] : dump environment variables known to the process\n"
-       "  show errors    : report last request and response errors for each proxy\n"
        "  set timeout    : change a timeout setting\n"
        "  set maxconn    : change a maxconn setting\n"
        "  set rate-limit : change a rate limiting value\n"
@@ -577,20 +574,6 @@ static int stats_sock_parse_request(struct stream_interface *si, char *line)
                                appctx->st2 = STAT_ST_END;
                        }
                }
-               else if (strcmp(args[1], "errors") == 0) {
-                       if (strm_li(s)->bind_conf->level < ACCESS_LVL_OPER) {
-                               appctx->ctx.cli.msg = stats_permission_denied_msg;
-                               appctx->st0 = STAT_CLI_PRINT;
-                               return 1;
-                       }
-                       if (*args[2])
-                               appctx->ctx.errors.iid  = atoi(args[2]);
-                       else
-                               appctx->ctx.errors.iid  = -1;
-                       appctx->ctx.errors.px = NULL;
-                       appctx->st2 = STAT_ST_INIT;
-                       appctx->st0 = STAT_CLI_O_ERR; // stats_dump_errors_to_buffer
-               }
                else { /* neither "stat" nor "info" nor "sess" nor "errors" nor "table" */
                        return 0;
                }
@@ -1291,10 +1274,6 @@ static void cli_io_handler(struct appctx *appctx)
                                else
                                        si_applet_cant_put(si);
                                break;
-                       case STAT_CLI_O_ERR:    /* errors dump */
-                               if (stats_dump_errors_to_buffer(si))
-                                       appctx->st0 = STAT_CLI_PROMPT;
-                               break;
                        case STAT_CLI_O_ENV:    /* environment dump */
                                if (stats_dump_env_to_buffer(si))
                                        appctx->st0 = STAT_CLI_PROMPT;
@@ -1385,169 +1364,6 @@ static void cli_release_handler(struct appctx *appctx)
        }
 }
 
-/* This function dumps all captured errors onto the stream interface's
- * read buffer. It returns 0 if the output buffer is full and it needs
- * to be called again, otherwise non-zero.
- */
-static int stats_dump_errors_to_buffer(struct stream_interface *si)
-{
-       struct appctx *appctx = __objt_appctx(si->end);
-       extern const char *monthname[12];
-
-       if (unlikely(si_ic(si)->flags & (CF_WRITE_ERROR|CF_SHUTW)))
-               return 1;
-
-       chunk_reset(&trash);
-
-       if (!appctx->ctx.errors.px) {
-               /* the function had not been called yet, let's prepare the
-                * buffer for a response.
-                */
-               struct tm tm;
-
-               get_localtime(date.tv_sec, &tm);
-               chunk_appendf(&trash, "Total events captured on [%02d/%s/%04d:%02d:%02d:%02d.%03d] : %u\n",
-                            tm.tm_mday, monthname[tm.tm_mon], tm.tm_year+1900,
-                            tm.tm_hour, tm.tm_min, tm.tm_sec, (int)(date.tv_usec/1000),
-                            error_snapshot_id);
-
-               if (bi_putchk(si_ic(si), &trash) == -1) {
-                       /* Socket buffer full. Let's try again later from the same point */
-                       si_applet_cant_put(si);
-                       return 0;
-               }
-
-               appctx->ctx.errors.px = proxy;
-               appctx->ctx.errors.buf = 0;
-               appctx->ctx.errors.bol = 0;
-               appctx->ctx.errors.ptr = -1;
-       }
-
-       /* we have two inner loops here, one for the proxy, the other one for
-        * the buffer.
-        */
-       while (appctx->ctx.errors.px) {
-               struct error_snapshot *es;
-
-               if (appctx->ctx.errors.buf == 0)
-                       es = &appctx->ctx.errors.px->invalid_req;
-               else
-                       es = &appctx->ctx.errors.px->invalid_rep;
-
-               if (!es->when.tv_sec)
-                       goto next;
-
-               if (appctx->ctx.errors.iid >= 0 &&
-                   appctx->ctx.errors.px->uuid != appctx->ctx.errors.iid &&
-                   es->oe->uuid != appctx->ctx.errors.iid)
-                       goto next;
-
-               if (appctx->ctx.errors.ptr < 0) {
-                       /* just print headers now */
-
-                       char pn[INET6_ADDRSTRLEN];
-                       struct tm tm;
-                       int port;
-
-                       get_localtime(es->when.tv_sec, &tm);
-                       chunk_appendf(&trash, " \n[%02d/%s/%04d:%02d:%02d:%02d.%03d]",
-                                    tm.tm_mday, monthname[tm.tm_mon], tm.tm_year+1900,
-                                    tm.tm_hour, tm.tm_min, tm.tm_sec, (int)(es->when.tv_usec/1000));
-
-                       switch (addr_to_str(&es->src, pn, sizeof(pn))) {
-                       case AF_INET:
-                       case AF_INET6:
-                               port = get_host_port(&es->src);
-                               break;
-                       default:
-                               port = 0;
-                       }
-
-                       switch (appctx->ctx.errors.buf) {
-                       case 0:
-                               chunk_appendf(&trash,
-                                            " frontend %s (#%d): invalid request\n"
-                                            "  backend %s (#%d)",
-                                            appctx->ctx.errors.px->id, appctx->ctx.errors.px->uuid,
-                                            (es->oe->cap & PR_CAP_BE) ? es->oe->id : "<NONE>",
-                                            (es->oe->cap & PR_CAP_BE) ? es->oe->uuid : -1);
-                               break;
-                       case 1:
-                               chunk_appendf(&trash,
-                                            " backend %s (#%d): invalid response\n"
-                                            "  frontend %s (#%d)",
-                                            appctx->ctx.errors.px->id, appctx->ctx.errors.px->uuid,
-                                            es->oe->id, es->oe->uuid);
-                               break;
-                       }
-
-                       chunk_appendf(&trash,
-                                    ", server %s (#%d), event #%u\n"
-                                    "  src %s:%d, session #%d, session flags 0x%08x\n"
-                                    "  HTTP msg state %d, msg flags 0x%08x, tx flags 0x%08x\n"
-                                    "  HTTP chunk len %lld bytes, HTTP body len %lld bytes\n"
-                                    "  buffer flags 0x%08x, out %d bytes, total %lld bytes\n"
-                                    "  pending %d bytes, wrapping at %d, error at position %d:\n \n",
-                                    es->srv ? es->srv->id : "<NONE>", es->srv ? es->srv->puid : -1,
-                                    es->ev_id,
-                                    pn, port, es->sid, es->s_flags,
-                                    es->state, es->m_flags, es->t_flags,
-                                    es->m_clen, es->m_blen,
-                                    es->b_flags, es->b_out, es->b_tot,
-                                    es->len, es->b_wrap, es->pos);
-
-                       if (bi_putchk(si_ic(si), &trash) == -1) {
-                               /* Socket buffer full. Let's try again later from the same point */
-                               si_applet_cant_put(si);
-                               return 0;
-                       }
-                       appctx->ctx.errors.ptr = 0;
-                       appctx->ctx.errors.sid = es->sid;
-               }
-
-               if (appctx->ctx.errors.sid != es->sid) {
-                       /* the snapshot changed while we were dumping it */
-                       chunk_appendf(&trash,
-                                    "  WARNING! update detected on this snapshot, dump interrupted. Please re-check!\n");
-                       if (bi_putchk(si_ic(si), &trash) == -1) {
-                               si_applet_cant_put(si);
-                               return 0;
-                       }
-                       goto next;
-               }
-
-               /* OK, ptr >= 0, so we have to dump the current line */
-               while (es->buf && appctx->ctx.errors.ptr < es->len && appctx->ctx.errors.ptr < global.tune.bufsize) {
-                       int newptr;
-                       int newline;
-
-                       newline = appctx->ctx.errors.bol;
-                       newptr = dump_text_line(&trash, es->buf, global.tune.bufsize, es->len, &newline, appctx->ctx.errors.ptr);
-                       if (newptr == appctx->ctx.errors.ptr)
-                               return 0;
-
-                       if (bi_putchk(si_ic(si), &trash) == -1) {
-                               /* Socket buffer full. Let's try again later from the same point */
-                               si_applet_cant_put(si);
-                               return 0;
-                       }
-                       appctx->ctx.errors.ptr = newptr;
-                       appctx->ctx.errors.bol = newline;
-               };
-       next:
-               appctx->ctx.errors.bol = 0;
-               appctx->ctx.errors.ptr = -1;
-               appctx->ctx.errors.buf++;
-               if (appctx->ctx.errors.buf > 1) {
-                       appctx->ctx.errors.buf = 0;
-                       appctx->ctx.errors.px = appctx->ctx.errors.px->next;
-               }
-       }
-
-       /* dump complete */
-       return 1;
-}
-
 /* This function dumps all environmnent variables to the buffer. It returns 0
  * if the output buffer is full and it needs to be called again, otherwise
  * non-zero. Dumps only one entry if st2 == STAT_ST_END.
index 181dfc2bf30ef12f5735f9ab09bb770d021353ea..a792fcf411fe324b8a88e8cf22587a1badf9d78e 100644 (file)
@@ -39,6 +39,7 @@
 #include <common/version.h>
 
 #include <types/capture.h>
+#include <types/cli.h>
 #include <types/filters.h>
 #include <types/global.h>
 #include <types/stats.h>
@@ -50,6 +51,7 @@
 #include <proto/backend.h>
 #include <proto/channel.h>
 #include <proto/checks.h>
+#include <proto/cli.h>
 #include <proto/compression.h>
 #include <proto/stats.h>
 #include <proto/fd.h>
@@ -12823,6 +12825,196 @@ struct action_kw *action_http_res_custom(const char *kw)
        return action_lookup(&http_res_keywords.list, kw);
 }
 
+
+/* "show errors" handler for the CLI. Returns 0 if wants to continue, 1 to stop
+ * now.
+ */
+static int cli_parse_show_errors(char **args, struct appctx *appctx, void *private)
+{
+       if (!cli_has_level(appctx, ACCESS_LVL_OPER))
+               return 1;
+
+       if (*args[2])
+               appctx->ctx.errors.iid  = atoi(args[2]);
+       else
+               appctx->ctx.errors.iid  = -1;
+       appctx->ctx.errors.px = NULL;
+       appctx->st2 = STAT_ST_INIT;
+       return 0;
+}
+
+/* This function dumps all captured errors onto the stream interface's
+ * read buffer. It returns 0 if the output buffer is full and it needs
+ * to be called again, otherwise non-zero.
+ */
+static int cli_io_handler_show_errors(struct appctx *appctx)
+{
+       struct stream_interface *si = appctx->owner;
+       extern const char *monthname[12];
+
+       if (unlikely(si_ic(si)->flags & (CF_WRITE_ERROR|CF_SHUTW)))
+               return 1;
+
+       chunk_reset(&trash);
+
+       if (!appctx->ctx.errors.px) {
+               /* the function had not been called yet, let's prepare the
+                * buffer for a response.
+                */
+               struct tm tm;
+
+               get_localtime(date.tv_sec, &tm);
+               chunk_appendf(&trash, "Total events captured on [%02d/%s/%04d:%02d:%02d:%02d.%03d] : %u\n",
+                            tm.tm_mday, monthname[tm.tm_mon], tm.tm_year+1900,
+                            tm.tm_hour, tm.tm_min, tm.tm_sec, (int)(date.tv_usec/1000),
+                            error_snapshot_id);
+
+               if (bi_putchk(si_ic(si), &trash) == -1) {
+                       /* Socket buffer full. Let's try again later from the same point */
+                       si_applet_cant_put(si);
+                       return 0;
+               }
+
+               appctx->ctx.errors.px = proxy;
+               appctx->ctx.errors.buf = 0;
+               appctx->ctx.errors.bol = 0;
+               appctx->ctx.errors.ptr = -1;
+       }
+
+       /* we have two inner loops here, one for the proxy, the other one for
+        * the buffer.
+        */
+       while (appctx->ctx.errors.px) {
+               struct error_snapshot *es;
+
+               if (appctx->ctx.errors.buf == 0)
+                       es = &appctx->ctx.errors.px->invalid_req;
+               else
+                       es = &appctx->ctx.errors.px->invalid_rep;
+
+               if (!es->when.tv_sec)
+                       goto next;
+
+               if (appctx->ctx.errors.iid >= 0 &&
+                   appctx->ctx.errors.px->uuid != appctx->ctx.errors.iid &&
+                   es->oe->uuid != appctx->ctx.errors.iid)
+                       goto next;
+
+               if (appctx->ctx.errors.ptr < 0) {
+                       /* just print headers now */
+
+                       char pn[INET6_ADDRSTRLEN];
+                       struct tm tm;
+                       int port;
+
+                       get_localtime(es->when.tv_sec, &tm);
+                       chunk_appendf(&trash, " \n[%02d/%s/%04d:%02d:%02d:%02d.%03d]",
+                                    tm.tm_mday, monthname[tm.tm_mon], tm.tm_year+1900,
+                                    tm.tm_hour, tm.tm_min, tm.tm_sec, (int)(es->when.tv_usec/1000));
+
+                       switch (addr_to_str(&es->src, pn, sizeof(pn))) {
+                       case AF_INET:
+                       case AF_INET6:
+                               port = get_host_port(&es->src);
+                               break;
+                       default:
+                               port = 0;
+                       }
+
+                       switch (appctx->ctx.errors.buf) {
+                       case 0:
+                               chunk_appendf(&trash,
+                                            " frontend %s (#%d): invalid request\n"
+                                            "  backend %s (#%d)",
+                                            appctx->ctx.errors.px->id, appctx->ctx.errors.px->uuid,
+                                            (es->oe->cap & PR_CAP_BE) ? es->oe->id : "<NONE>",
+                                            (es->oe->cap & PR_CAP_BE) ? es->oe->uuid : -1);
+                               break;
+                       case 1:
+                               chunk_appendf(&trash,
+                                            " backend %s (#%d): invalid response\n"
+                                            "  frontend %s (#%d)",
+                                            appctx->ctx.errors.px->id, appctx->ctx.errors.px->uuid,
+                                            es->oe->id, es->oe->uuid);
+                               break;
+                       }
+
+                       chunk_appendf(&trash,
+                                    ", server %s (#%d), event #%u\n"
+                                    "  src %s:%d, session #%d, session flags 0x%08x\n"
+                                    "  HTTP msg state %d, msg flags 0x%08x, tx flags 0x%08x\n"
+                                    "  HTTP chunk len %lld bytes, HTTP body len %lld bytes\n"
+                                    "  buffer flags 0x%08x, out %d bytes, total %lld bytes\n"
+                                    "  pending %d bytes, wrapping at %d, error at position %d:\n \n",
+                                    es->srv ? es->srv->id : "<NONE>", es->srv ? es->srv->puid : -1,
+                                    es->ev_id,
+                                    pn, port, es->sid, es->s_flags,
+                                    es->state, es->m_flags, es->t_flags,
+                                    es->m_clen, es->m_blen,
+                                    es->b_flags, es->b_out, es->b_tot,
+                                    es->len, es->b_wrap, es->pos);
+
+                       if (bi_putchk(si_ic(si), &trash) == -1) {
+                               /* Socket buffer full. Let's try again later from the same point */
+                               si_applet_cant_put(si);
+                               return 0;
+                       }
+                       appctx->ctx.errors.ptr = 0;
+                       appctx->ctx.errors.sid = es->sid;
+               }
+
+               if (appctx->ctx.errors.sid != es->sid) {
+                       /* the snapshot changed while we were dumping it */
+                       chunk_appendf(&trash,
+                                    "  WARNING! update detected on this snapshot, dump interrupted. Please re-check!\n");
+                       if (bi_putchk(si_ic(si), &trash) == -1) {
+                               si_applet_cant_put(si);
+                               return 0;
+                       }
+                       goto next;
+               }
+
+               /* OK, ptr >= 0, so we have to dump the current line */
+               while (es->buf && appctx->ctx.errors.ptr < es->len && appctx->ctx.errors.ptr < global.tune.bufsize) {
+                       int newptr;
+                       int newline;
+
+                       newline = appctx->ctx.errors.bol;
+                       newptr = dump_text_line(&trash, es->buf, global.tune.bufsize, es->len, &newline, appctx->ctx.errors.ptr);
+                       if (newptr == appctx->ctx.errors.ptr)
+                               return 0;
+
+                       if (bi_putchk(si_ic(si), &trash) == -1) {
+                               /* Socket buffer full. Let's try again later from the same point */
+                               si_applet_cant_put(si);
+                               return 0;
+                       }
+                       appctx->ctx.errors.ptr = newptr;
+                       appctx->ctx.errors.bol = newline;
+               };
+       next:
+               appctx->ctx.errors.bol = 0;
+               appctx->ctx.errors.ptr = -1;
+               appctx->ctx.errors.buf++;
+               if (appctx->ctx.errors.buf > 1) {
+                       appctx->ctx.errors.buf = 0;
+                       appctx->ctx.errors.px = appctx->ctx.errors.px->next;
+               }
+       }
+
+       /* dump complete */
+       return 1;
+}
+
+/* register cli keywords */
+static struct cli_kw_list cli_kws = {{ },{
+       { { "show", "errors", NULL },
+         "show errors    : report last request and response errors for each proxy",
+         cli_parse_show_errors, cli_io_handler_show_errors, NULL,
+       },
+       {{},}
+}};
+
 /************************************************************************/
 /*          All supported ACL keywords must be declared here.           */
 /************************************************************************/
@@ -13076,6 +13268,7 @@ static void __http_protocol_init(void)
        sample_register_convs(&sample_conv_kws);
        http_req_keywords_register(&http_req_actions);
        http_res_keywords_register(&http_res_actions);
+       cli_register_kw(&cli_kws);
 }