blob: c77528dcc038e40f47cd4fec227d984bc9feaf60 [file] [log] [blame]
Willy Tarreau91861262007-10-17 17:06:05 +02001/*
2 * Functions dedicated to statistics output
3 *
4 * Copyright 2000-2007 Willy Tarreau <w@1wt.eu>
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License
8 * as published by the Free Software Foundation; either version
9 * 2 of the License, or (at your option) any later version.
10 *
11 */
12
13#include <ctype.h>
14#include <errno.h>
15#include <fcntl.h>
16#include <stdio.h>
17#include <stdlib.h>
18#include <string.h>
19#include <time.h>
20
21#include <sys/socket.h>
22#include <sys/stat.h>
23#include <sys/types.h>
24
25#include <common/compat.h>
26#include <common/config.h>
27#include <common/debug.h>
28#include <common/memory.h>
29#include <common/mini-clist.h>
30#include <common/standard.h>
31#include <common/time.h>
32#include <common/uri_auth.h>
33#include <common/version.h>
34
35#include <types/client.h>
36#include <types/global.h>
37#include <types/polling.h>
38#include <types/proxy.h>
39#include <types/server.h>
40
41#include <proto/backend.h>
42#include <proto/buffers.h>
43#include <proto/dumpstats.h>
44#include <proto/fd.h>
45#include <proto/senddata.h>
46#include <proto/session.h>
47
48/*
49 * Produces statistics data for the session <s>. Expects to be called with
50 * s->cli_state == CL_STSHUTR. It stops by itself by unsetting the SN_SELF_GEN
51 * flag from the session, which it uses to keep on being called when there is
52 * free space in the buffer, of simply by letting an empty buffer upon return.
53 * It returns 0 if it had to stop writing data and an I/O is needed, 1 if the
54 * dump is finished and the session must be closed, or -1 in case of any error.
55 */
56int stats_dump_http(struct session *s, struct uri_auth *uri, int flags)
57{
58 struct buffer *rep = s->rep;
59 struct proxy *px;
60 struct chunk msg;
61 unsigned int up;
62
63 msg.len = 0;
64 msg.str = trash;
65
66 switch (s->data_state) {
67 case DATA_ST_INIT:
68 /* the function had not been called yet */
69 s->flags |= SN_SELF_GEN; // more data will follow
70
71 chunk_printf(&msg, sizeof(trash),
72 "HTTP/1.0 200 OK\r\n"
73 "Cache-Control: no-cache\r\n"
74 "Connection: close\r\n"
Willy Tarreau55bb8452007-10-17 18:44:57 +020075 "Content-Type: %s\r\n",
76 (flags & STAT_FMT_HTML) ? "text/html" : "text/plain");
Willy Tarreau91861262007-10-17 17:06:05 +020077
78 if (uri->refresh > 0 && !(s->flags & SN_STAT_NORFRSH))
79 chunk_printf(&msg, sizeof(trash), "Refresh: %d\r\n",
80 uri->refresh);
81
82 chunk_printf(&msg, sizeof(trash), "\r\n");
83
84 s->txn.status = 200;
85 client_retnclose(s, &msg); // send the start of the response.
86 msg.len = 0;
87
88 if (!(s->flags & SN_ERR_MASK)) // this is not really an error but it is
89 s->flags |= SN_ERR_PRXCOND; // to mark that it comes from the proxy
90 if (!(s->flags & SN_FINST_MASK))
91 s->flags |= SN_FINST_R;
92
93 if (s->txn.meth == HTTP_METH_HEAD) {
94 /* that's all we return in case of HEAD request */
95 s->data_state = DATA_ST_FIN;
96 s->flags &= ~SN_SELF_GEN;
97 return 1;
98 }
99
100 s->data_state = DATA_ST_HEAD; /* let's start producing data */
101 /* fall through */
102
103 case DATA_ST_HEAD:
Willy Tarreau55bb8452007-10-17 18:44:57 +0200104 if (flags & STAT_FMT_HTML) {
105 /* WARNING! This must fit in the first buffer !!! */
106 chunk_printf(&msg, sizeof(trash),
Willy Tarreau91861262007-10-17 17:06:05 +0200107 "<html><head><title>Statistics Report for " PRODUCT_NAME "</title>\n"
108 "<meta http-equiv=\"content-type\" content=\"text/html; charset=iso-8859-1\">\n"
109 "<style type=\"text/css\"><!--\n"
110 "body {"
111 " font-family: helvetica, arial;"
112 " font-size: 12px;"
113 " font-weight: normal;"
114 " color: black;"
115 " background: white;"
116 "}\n"
117 "th,td {"
118 " font-size: 0.8em;"
119 " align: center;"
120 "}\n"
121 "h1 {"
122 " font-size: xx-large;"
123 " margin-bottom: 0.5em;"
124 "}\n"
125 "h2 {"
126 " font-family: helvetica, arial;"
127 " font-size: x-large;"
128 " font-weight: bold;"
129 " font-style: italic;"
130 " color: #6020a0;"
131 " margin-top: 0em;"
132 " margin-bottom: 0em;"
133 "}\n"
134 "h3 {"
135 " font-family: helvetica, arial;"
136 " font-size: 16px;"
137 " font-weight: bold;"
138 " color: #b00040;"
139 " background: #e8e8d0;"
140 " margin-top: 0em;"
141 " margin-bottom: 0em;"
142 "}\n"
143 "li {"
144 " margin-top: 0.25em;"
145 " margin-right: 2em;"
146 "}\n"
147 ".hr {margin-top: 0.25em;"
148 " border-color: black;"
149 " border-bottom-style: solid;"
150 "}\n"
151 ".pxname {background: #b00040;color: #ffff40;font-weight: bold;}\n"
152 ".titre {background: #20D0D0;color: #000000;font-weight: bold;}\n"
153 ".total {background: #20D0D0;color: #ffff80;}\n"
154 ".frontend {background: #e8e8d0;}\n"
155 ".backend {background: #e8e8d0;}\n"
156 ".active0 {background: #ff9090;}\n"
157 ".active1 {background: #ffd020;}\n"
158 ".active2 {background: #ffffa0;}\n"
159 ".active3 {background: #c0ffc0;}\n"
160 ".active4 {background: #e0e0e0;}\n"
161 ".backup0 {background: #ff9090;}\n"
162 ".backup1 {background: #ff80ff;}\n"
163 ".backup2 {background: #c060ff;}\n"
164 ".backup3 {background: #b0d0ff;}\n"
165 ".backup4 {background: #e0e0e0;}\n"
166 "table.tbl { border-collapse: collapse; border-style: none;}\n"
167 "table.tbl td { border-width: 1px 1px 1px 1px; border-style: solid solid solid solid; padding: 2px 3px; border-color: gray;}\n"
168 "table.tbl th { border-width: 1px; border-style: solid solid solid solid; border-color: gray;}\n"
169 "table.tbl th.empty { border-style: none; empty-cells: hide;}\n"
170 "table.lgd { border-collapse: collapse; border-width: 1px; border-style: none none none solid; border-color: black;}\n"
171 "table.lgd td { border-width: 1px; border-style: solid solid solid solid; border-color: gray; padding: 2px;}\n"
172 "table.lgd td.noborder { border-style: none; padding: 2px; white-space: nowrap;}\n"
173 "-->\n"
174 "</style></head>\n");
Willy Tarreau55bb8452007-10-17 18:44:57 +0200175 } else {
176 chunk_printf(&msg, sizeof(trash),
177 "# pxname,svname,"
178 "qcur,qmax,"
179 "scur,smax,slim,stot,"
180 "bin,bout,"
181 "dreq,dresp,"
182 "ereq,econ,eresp,"
183 "weight,act,bck,"
184 "chkfail,chkdown"
185 "\n");
186 }
Willy Tarreau91861262007-10-17 17:06:05 +0200187 if (buffer_write_chunk(rep, &msg) != 0)
188 return 0;
189
190 s->data_state = DATA_ST_INFO;
191 /* fall through */
192
193 case DATA_ST_INFO:
194 up = (now.tv_sec - start_date.tv_sec);
195
196 /* WARNING! this has to fit the first packet too.
197 * We are around 3.5 kB, add adding entries will
198 * become tricky if we want to support 4kB buffers !
199 */
Willy Tarreau55bb8452007-10-17 18:44:57 +0200200 if (flags & STAT_FMT_HTML) {
201 chunk_printf(&msg, sizeof(trash),
Willy Tarreau91861262007-10-17 17:06:05 +0200202 "<body><h1><a href=\"" PRODUCT_URL "\" style=\"text-decoration: none;\">"
203 PRODUCT_NAME "%s</a></h1>\n"
204 "<h2>Statistics Report for pid %d</h2>\n"
205 "<hr width=\"100%%\" class=\"hr\">\n"
206 "<h3>&gt; General process information</h3>\n"
207 "<table border=0 cols=4><tr><td align=\"left\" nowrap width=\"1%%\">\n"
208 "<p><b>pid = </b> %d (nbproc = %d)<br>\n"
209 "<b>uptime = </b> %dd %dh%02dm%02ds<br>\n"
210 "<b>system limits :</b> memmax = %s%s ; ulimit-n = %d<br>\n"
211 "<b>maxsock = </b> %d<br>\n"
212 "<b>maxconn = </b> %d (current conns = %d)<br>\n"
213 "</td><td align=\"center\" nowrap>\n"
214 "<table class=\"lgd\"><tr>\n"
215 "<td class=\"active3\">&nbsp;</td><td class=\"noborder\">active UP </td>"
216 "<td class=\"backup3\">&nbsp;</td><td class=\"noborder\">backup UP </td>"
217 "</tr><tr>\n"
218 "<td class=\"active2\"></td><td class=\"noborder\">active UP, going down </td>"
219 "<td class=\"backup2\"></td><td class=\"noborder\">backup UP, going down </td>"
220 "</tr><tr>\n"
221 "<td class=\"active1\"></td><td class=\"noborder\">active DOWN, going up </td>"
222 "<td class=\"backup1\"></td><td class=\"noborder\">backup DOWN, going up </td>"
223 "</tr><tr>\n"
224 "<td class=\"active0\"></td><td class=\"noborder\">active or backup DOWN &nbsp;</td>"
225 "<td class=\"active4\"></td><td class=\"noborder\">not checked </td>"
226 "</tr></table>\n"
227 "</td>"
228 "<td align=\"left\" valign=\"top\" nowrap width=\"1%%\">"
229 "<b>Display option:</b><ul style=\"margin-top: 0.25em;\">"
230 "",
231 (uri->flags&ST_HIDEVER)?"":(STATS_VERSION_STRING),
232 pid, pid, global.nbproc,
233 up / 86400, (up % 86400) / 3600,
234 (up % 3600) / 60, (up % 60),
235 global.rlimit_memmax ? ultoa(global.rlimit_memmax) : "unlimited",
236 global.rlimit_memmax ? " MB" : "",
237 global.rlimit_nofile,
238 global.maxsock,
239 global.maxconn,
240 actconn
241 );
242
Willy Tarreau55bb8452007-10-17 18:44:57 +0200243 if (s->flags & SN_STAT_HIDEDWN)
244 chunk_printf(&msg, sizeof(trash),
Willy Tarreau91861262007-10-17 17:06:05 +0200245 "<li><a href=\"%s%s%s\">Show all servers</a><br>\n",
246 uri->uri_prefix,
247 "",
248 (s->flags & SN_STAT_NORFRSH) ? ";norefresh" : "");
Willy Tarreau55bb8452007-10-17 18:44:57 +0200249 else
250 chunk_printf(&msg, sizeof(trash),
Willy Tarreau91861262007-10-17 17:06:05 +0200251 "<li><a href=\"%s%s%s\">Hide 'DOWN' servers</a><br>\n",
252 uri->uri_prefix,
253 ";up",
254 (s->flags & SN_STAT_NORFRSH) ? ";norefresh" : "");
255
Willy Tarreau55bb8452007-10-17 18:44:57 +0200256 if (uri->refresh > 0) {
257 if (s->flags & SN_STAT_NORFRSH)
258 chunk_printf(&msg, sizeof(trash),
Willy Tarreau91861262007-10-17 17:06:05 +0200259 "<li><a href=\"%s%s%s\">Enable refresh</a><br>\n",
260 uri->uri_prefix,
261 (s->flags & SN_STAT_HIDEDWN) ? ";up" : "",
262 "");
Willy Tarreau55bb8452007-10-17 18:44:57 +0200263 else
264 chunk_printf(&msg, sizeof(trash),
Willy Tarreau91861262007-10-17 17:06:05 +0200265 "<li><a href=\"%s%s%s\">Disable refresh</a><br>\n",
266 uri->uri_prefix,
267 (s->flags & SN_STAT_HIDEDWN) ? ";up" : "",
268 ";norefresh");
Willy Tarreau55bb8452007-10-17 18:44:57 +0200269 }
Willy Tarreau91861262007-10-17 17:06:05 +0200270
Willy Tarreau55bb8452007-10-17 18:44:57 +0200271 chunk_printf(&msg, sizeof(trash),
Willy Tarreau91861262007-10-17 17:06:05 +0200272 "<li><a href=\"%s%s%s\">Refresh now</a><br>\n",
273 uri->uri_prefix,
274 (s->flags & SN_STAT_HIDEDWN) ? ";up" : "",
275 (s->flags & SN_STAT_NORFRSH) ? ";norefresh" : "");
276
Willy Tarreau55bb8452007-10-17 18:44:57 +0200277 chunk_printf(&msg, sizeof(trash),
Willy Tarreau91861262007-10-17 17:06:05 +0200278 "</td>"
279 "<td align=\"left\" valign=\"top\" nowrap width=\"1%%\">"
280 "<b>External ressources:</b><ul style=\"margin-top: 0.25em;\">\n"
281 "<li><a href=\"" PRODUCT_URL "\">Primary site</a><br>\n"
282 "<li><a href=\"" PRODUCT_URL_UPD "\">Updates (v" PRODUCT_BRANCH ")</a><br>\n"
283 "<li><a href=\"" PRODUCT_URL_DOC "\">Online manual</a><br>\n"
284 "</ul>"
285 "</td>"
286 "</tr></table>\n"
287 ""
288 );
289
Willy Tarreau55bb8452007-10-17 18:44:57 +0200290 if (buffer_write_chunk(rep, &msg) != 0)
291 return 0;
292 }
Willy Tarreau91861262007-10-17 17:06:05 +0200293
294 memset(&s->data_ctx, 0, sizeof(s->data_ctx));
295
296 s->data_ctx.stats.px = proxy;
297 s->data_ctx.stats.px_st = DATA_ST_PX_INIT;
298 s->data_state = DATA_ST_LIST;
299 /* fall through */
300
301 case DATA_ST_LIST:
302 /* dump proxies */
303 while (s->data_ctx.stats.px) {
304 px = s->data_ctx.stats.px;
305 /* skip the disabled proxies and non-networked ones */
306 if (px->state != PR_STSTOPPED && (px->cap & (PR_CAP_FE | PR_CAP_BE)))
307 if (stats_dump_proxy(s, px, uri, flags) == 0)
308 return 0;
309
310 s->data_ctx.stats.px = px->next;
311 s->data_ctx.stats.px_st = DATA_ST_PX_INIT;
312 }
313 /* here, we just have reached the last proxy */
314
315 s->data_state = DATA_ST_END;
316 /* fall through */
317
318 case DATA_ST_END:
Willy Tarreau55bb8452007-10-17 18:44:57 +0200319 if (flags & STAT_FMT_HTML) {
320 chunk_printf(&msg, sizeof(trash), "</body></html>\n");
321 if (buffer_write_chunk(rep, &msg) != 0)
322 return 0;
323 }
Willy Tarreau91861262007-10-17 17:06:05 +0200324
325 s->data_state = DATA_ST_FIN;
326 /* fall through */
327
328 case DATA_ST_FIN:
329 s->flags &= ~SN_SELF_GEN;
330 return 1;
331
332 default:
333 /* unknown state ! */
334 s->flags &= ~SN_SELF_GEN;
335 return -1;
336 }
337}
338
339
340/*
341 * Dumps statistics for a proxy.
342 * Returns 0 if it had to stop dumping data because of lack of buffer space,
343 * ot non-zero if everything completed.
344 */
345int stats_dump_proxy(struct session *s, struct proxy *px, struct uri_auth *uri, int flags)
346{
347 struct buffer *rep = s->rep;
348 struct server *sv;
349 struct chunk msg;
350
351 msg.len = 0;
352 msg.str = trash;
353
354 switch (s->data_ctx.stats.px_st) {
355 case DATA_ST_PX_INIT:
356 /* we are on a new proxy */
357
358 if (uri && uri->scope) {
359 /* we have a limited scope, we have to check the proxy name */
360 struct stat_scope *scope;
361 int len;
362
363 len = strlen(px->id);
364 scope = uri->scope;
365
366 while (scope) {
367 /* match exact proxy name */
368 if (scope->px_len == len && !memcmp(px->id, scope->px_id, len))
369 break;
370
371 /* match '.' which means 'self' proxy */
372 if (!strcmp(scope->px_id, ".") && px == s->fe)
373 break;
374 scope = scope->next;
375 }
376
377 /* proxy name not found : don't dump anything */
378 if (scope == NULL)
379 return 1;
380 }
381
382 s->data_ctx.stats.px_st = DATA_ST_PX_TH;
383 /* fall through */
384
385 case DATA_ST_PX_TH:
Willy Tarreau55bb8452007-10-17 18:44:57 +0200386 if (flags & STAT_FMT_HTML) {
387 /* print a new table */
388 chunk_printf(&msg, sizeof(trash),
389 "<table cols=\"20\" class=\"tbl\" width=\"100%%\">\n"
390 "<tr align=\"center\" class=\"titre\">"
391 "<th colspan=2 class=\"pxname\">%s</th>"
392 "<th colspan=18 class=\"empty\"></th>"
393 "</tr>\n"
394 "<tr align=\"center\" class=\"titre\">"
395 "<th rowspan=2></th>"
396 "<th colspan=2>Queue</th><th colspan=4>Sessions</th>"
397 "<th colspan=2>Bytes</th><th colspan=2>Denied</th>"
398 "<th colspan=3>Errors</th><th colspan=6>Server</th>"
399 "</tr>\n"
400 "<tr align=\"center\" class=\"titre\">"
401 "<th>Cur</th><th>Max</th><th>Cur</th><th>Max</th>"
402 "<th>Limit</th><th>Cumul</th><th>In</th><th>Out</th>"
403 "<th>Req</th><th>Resp</th><th>Req</th><th>Conn</th>"
404 "<th>Resp</th><th>Status</th><th>Weight</th><th>Act</th>"
405 "<th>Bck</th><th>Check</th><th>Down</th></tr>\n"
406 "",
407 px->id);
408
409 if (buffer_write_chunk(rep, &msg) != 0)
410 return 0;
411 }
Willy Tarreau91861262007-10-17 17:06:05 +0200412
413 s->data_ctx.stats.px_st = DATA_ST_PX_FE;
414 /* fall through */
415
416 case DATA_ST_PX_FE:
417 /* print the frontend */
418 if (px->cap & PR_CAP_FE) {
Willy Tarreau55bb8452007-10-17 18:44:57 +0200419 if (flags & STAT_FMT_HTML) {
420 chunk_printf(&msg, sizeof(trash),
Willy Tarreau91861262007-10-17 17:06:05 +0200421 /* name, queue */
422 "<tr align=center class=\"frontend\"><td>Frontend</td><td colspan=2></td>"
Willy Tarreau55bb8452007-10-17 18:44:57 +0200423 /* sessions : current, max, limit, cumul */
424 "<td align=right>%d</td><td align=right>%d</td>"
425 "<td align=right>%d</td><td align=right>%d</td>"
Willy Tarreau91861262007-10-17 17:06:05 +0200426 /* bytes : in, out */
427 "<td align=right>%lld</td><td align=right>%lld</td>"
428 /* denied: req, resp */
429 "<td align=right>%d</td><td align=right>%d</td>"
430 /* errors : request, connect, response */
431 "<td align=right>%d</td><td align=right></td><td align=right></td>"
Willy Tarreau55bb8452007-10-17 18:44:57 +0200432 /* server status : reflect frontend status */
Willy Tarreau91861262007-10-17 17:06:05 +0200433 "<td align=center>%s</td>"
434 /* rest of server: nothing */
435 "<td align=center colspan=5></td></tr>"
436 "",
437 px->feconn, px->feconn_max, px->maxconn, px->cum_feconn,
438 px->bytes_in, px->bytes_out,
439 px->denied_req, px->denied_resp,
440 px->failed_req,
441 px->state == PR_STRUN ? "OPEN" :
442 px->state == PR_STIDLE ? "FULL" : "STOP");
Willy Tarreau55bb8452007-10-17 18:44:57 +0200443 } else {
444 chunk_printf(&msg, sizeof(trash),
445 /* pxid, name, queue cur, queue max, */
446 "%s,FRONTEND,,,"
447 /* sessions : current, max, limit, cumul */
448 "%d,%d,%d,%d,"
449 /* bytes : in, out */
450 "%lld,%lld,"
451 /* denied: req, resp */
452 "%d,%d,"
453 /* errors : request, connect, response */
454 "%d,,,"
455 /* server status : reflect frontend status */
456 "%s,"
457 /* rest of server: nothing */
458 ",,,,,"
459 "\n",
460 px->id,
461 px->feconn, px->feconn_max, px->maxconn, px->cum_feconn,
462 px->bytes_in, px->bytes_out,
463 px->denied_req, px->denied_resp,
464 px->failed_req,
465 px->state == PR_STRUN ? "OPEN" :
466 px->state == PR_STIDLE ? "FULL" : "STOP");
467 }
Willy Tarreau91861262007-10-17 17:06:05 +0200468
469 if (buffer_write_chunk(rep, &msg) != 0)
470 return 0;
471 }
472
473 s->data_ctx.stats.sv = px->srv; /* may be NULL */
474 s->data_ctx.stats.px_st = DATA_ST_PX_SV;
475 /* fall through */
476
477 case DATA_ST_PX_SV:
478 /* stats.sv has been initialized above */
479 while (s->data_ctx.stats.sv != NULL) {
Willy Tarreau91861262007-10-17 17:06:05 +0200480 int sv_state; /* 0=DOWN, 1=going up, 2=going down, 3=UP, 4=unchecked */
481
482 sv = s->data_ctx.stats.sv;
483
484 /* FIXME: produce some small strings for "UP/DOWN x/y &#xxxx;" */
485 if (!(sv->state & SRV_CHECKED))
486 sv_state = 4;
487 else if (sv->state & SRV_RUNNING)
488 if (sv->health == sv->rise + sv->fall - 1)
489 sv_state = 3; /* UP */
490 else
491 sv_state = 2; /* going down */
492 else
493 if (sv->health)
494 sv_state = 1; /* going up */
495 else
496 sv_state = 0; /* DOWN */
497
498 if ((sv_state == 0) && (s->flags & SN_STAT_HIDEDWN)) {
499 /* do not report servers which are DOWN */
500 s->data_ctx.stats.sv = sv->next;
501 continue;
502 }
503
Willy Tarreau55bb8452007-10-17 18:44:57 +0200504 if (flags & STAT_FMT_HTML) {
505 static char *srv_hlt_st[5] = { "DOWN", "DN %d/%d &uarr;", "UP %d/%d &darr;",
506 "UP", "<i>no check</i>" };
507 chunk_printf(&msg, sizeof(trash),
Willy Tarreau91861262007-10-17 17:06:05 +0200508 /* name */
509 "<tr align=\"center\" class=\"%s%d\"><td>%s</td>"
510 /* queue : current, max */
511 "<td align=right>%d</td><td align=right>%d</td>"
512 /* sessions : current, max, limit, cumul */
Willy Tarreau55bb8452007-10-17 18:44:57 +0200513 "<td align=right>%d</td><td align=right>%d</td>"
514 "<td align=right>%s</td><td align=right>%d</td>"
Willy Tarreau91861262007-10-17 17:06:05 +0200515 /* bytes : in, out */
516 "<td align=right>%lld</td><td align=right>%lld</td>"
517 /* denied: req, resp */
518 "<td align=right></td><td align=right>%d</td>"
519 /* errors : request, connect, response */
520 "<td align=right></td><td align=right>%d</td><td align=right>%d</td>\n"
521 "",
522 (sv->state & SRV_BACKUP) ? "backup" : "active",
523 sv_state, sv->id,
524 sv->nbpend, sv->nbpend_max,
525 sv->cur_sess, sv->cur_sess_max, sv->maxconn ? ultoa(sv->maxconn) : "-", sv->cum_sess,
526 sv->bytes_in, sv->bytes_out,
527 sv->failed_secu,
528 sv->failed_conns, sv->failed_resp);
529
Willy Tarreau55bb8452007-10-17 18:44:57 +0200530 /* status */
531 chunk_printf(&msg, sizeof(trash), "<td nowrap>");
532 chunk_printf(&msg, sizeof(trash),
Willy Tarreau91861262007-10-17 17:06:05 +0200533 srv_hlt_st[sv_state],
534 (sv->state & SRV_RUNNING) ? (sv->health - sv->rise + 1) : (sv->health),
535 (sv->state & SRV_RUNNING) ? (sv->fall) : (sv->rise));
536
Willy Tarreau55bb8452007-10-17 18:44:57 +0200537 chunk_printf(&msg, sizeof(trash),
Willy Tarreau91861262007-10-17 17:06:05 +0200538 /* weight */
539 "</td><td>%d</td>"
540 /* act, bck */
541 "<td>%s</td><td>%s</td>"
542 "",
543 sv->uweight,
544 (sv->state & SRV_BACKUP) ? "-" : "Y",
545 (sv->state & SRV_BACKUP) ? "Y" : "-");
546
Willy Tarreau55bb8452007-10-17 18:44:57 +0200547 /* check failures : unique, fatal */
548 if (sv->state & SRV_CHECKED)
549 chunk_printf(&msg, sizeof(trash),
Willy Tarreau91861262007-10-17 17:06:05 +0200550 "<td align=right>%d</td><td align=right>%d</td></tr>\n",
551 sv->failed_checks, sv->down_trans);
Willy Tarreau55bb8452007-10-17 18:44:57 +0200552 else
553 chunk_printf(&msg, sizeof(trash),
Willy Tarreau91861262007-10-17 17:06:05 +0200554 "<td colspan=2></td></tr>\n");
Willy Tarreau55bb8452007-10-17 18:44:57 +0200555 } else {
556 static char *srv_hlt_st[5] = { "DOWN,", "DOWN %d/%d,", "UP %d/%d,",
557 "UP,", "no check," };
558 chunk_printf(&msg, sizeof(trash),
559 /* pxid, name */
560 "%s,%s,"
561 /* queue : current, max */
562 "%d,%d,"
563 /* sessions : current, max, limit, cumul */
564 "%d,%d,%s,%d,"
565 /* bytes : in, out */
566 "%lld,%lld,"
567 /* denied: req, resp */
568 ",%d,"
569 /* errors : request, connect, response */
570 ",%d,%d,"
571 "",
572 px->id, sv->id,
573 sv->nbpend, sv->nbpend_max,
574 sv->cur_sess, sv->cur_sess_max, sv->maxconn ? ultoa(sv->maxconn) : "-", sv->cum_sess,
575 sv->bytes_in, sv->bytes_out,
576 sv->failed_secu,
577 sv->failed_conns, sv->failed_resp);
578
579 /* status */
580 chunk_printf(&msg, sizeof(trash),
581 srv_hlt_st[sv_state],
582 (sv->state & SRV_RUNNING) ? (sv->health - sv->rise + 1) : (sv->health),
583 (sv->state & SRV_RUNNING) ? (sv->fall) : (sv->rise));
Willy Tarreau91861262007-10-17 17:06:05 +0200584
Willy Tarreau55bb8452007-10-17 18:44:57 +0200585 chunk_printf(&msg, sizeof(trash),
586 /* weight, active, backup */
587 "%d,%d,%d,"
588 "",
589 sv->uweight,
590 (sv->state & SRV_BACKUP) ? 0 : 1,
591 (sv->state & SRV_BACKUP) ? 1 : 0);
592
593 /* check failures : unique, fatal */
594 if (sv->state & SRV_CHECKED)
595 chunk_printf(&msg, sizeof(trash),
596 "%d,%d,\n",
597 sv->failed_checks, sv->down_trans);
598 else
599 chunk_printf(&msg, sizeof(trash),
600 ",,\n");
601 }
Willy Tarreau91861262007-10-17 17:06:05 +0200602 if (buffer_write_chunk(rep, &msg) != 0)
603 return 0;
604
605 s->data_ctx.stats.sv = sv->next;
606 } /* while sv */
607
608 s->data_ctx.stats.px_st = DATA_ST_PX_BE;
609 /* fall through */
610
611 case DATA_ST_PX_BE:
612 /* print the backend */
613 if (px->cap & PR_CAP_BE) {
614 int gcd = 1;
615
616 if (px->map_state & PR_MAP_RECALC)
617 recalc_server_map(px);
618
619 /* The GCD which was computed causes the total effective
620 * weight to appear lower than all weights. Let's
621 * recompute it.
622 */
623 if (px->srv && px->srv->eweight)
624 gcd = px->srv->uweight / px->srv->eweight;
625
Willy Tarreau55bb8452007-10-17 18:44:57 +0200626 if (flags & STAT_FMT_HTML) {
627 chunk_printf(&msg, sizeof(trash),
Willy Tarreau91861262007-10-17 17:06:05 +0200628 /* name */
629 "<tr align=center class=\"backend\"><td>Backend</td>"
630 /* queue : current, max */
631 "<td align=right>%d</td><td align=right>%d</td>"
632 /* sessions : current, max, limit, cumul. */
633 "<td align=right>%d</td><td align=right>%d</td><td align=right>%d</td><td align=right>%d</td>"
634 /* bytes : in, out */
635 "<td align=right>%lld</td><td align=right>%lld</td>"
636 /* denied: req, resp */
637 "<td align=right>%d</td><td align=right>%d</td>"
638 /* errors : request, connect, response */
639 "<td align=right></td><td align=right>%d</td><td align=right>%d</td>\n"
640 /* server status : reflect backend status (up/down) : we display UP
641 * if the backend has known working servers or if it has no server at
642 * all (eg: for stats). Tthen we display the total weight, number of
643 * active and backups. */
644 "<td align=center>%s</td><td align=center>%d</td>"
645 "<td align=center>%d</td><td align=center>%d</td>"
646 /* rest of server: nothing */
647 "<td align=center colspan=2></td></tr>"
648 "",
649 px->nbpend /* or px->totpend ? */, px->nbpend_max,
650 px->beconn, px->beconn_max, px->fullconn, px->cum_beconn,
651 px->bytes_in, px->bytes_out,
652 px->denied_req, px->denied_resp,
653 px->failed_conns, px->failed_resp,
654 (px->srv_map_sz > 0 || !px->srv) ? "UP" : "DOWN",
655 px->srv_map_sz * gcd, px->srv_act, px->srv_bck);
Willy Tarreau55bb8452007-10-17 18:44:57 +0200656 } else {
657 chunk_printf(&msg, sizeof(trash),
658 /* pxid, name */
659 "%s,BACKEND,"
660 /* queue : current, max */
661 "%d,%d,"
662 /* sessions : current, max, limit, cumul */
663 "%d,%d,%d,%d,"
664 /* bytes : in, out */
665 "%lld,%lld,"
666 /* denied: req, resp */
667 "%d,%d,"
668 /* errors : request, connect, response */
669 ",%d,%d,"
670 /* server status : reflect backend status (up/down) : we display UP
671 * if the backend has known working servers or if it has no server at
672 * all (eg: for stats). Tthen we display the total weight, number of
673 * active and backups. */
674 "%s,"
675 "%d,%d,%d,"
676 /* rest of server: nothing */
677 ",,"
678 "\n",
679 px->id,
680 px->nbpend /* or px->totpend ? */, px->nbpend_max,
681 px->beconn, px->beconn_max, px->fullconn, px->cum_beconn,
682 px->bytes_in, px->bytes_out,
683 px->denied_req, px->denied_resp,
684 px->failed_conns, px->failed_resp,
685 (px->srv_map_sz > 0 || !px->srv) ? "UP" : "DOWN",
686 px->srv_map_sz * gcd, px->srv_act, px->srv_bck);
687 }
Willy Tarreau91861262007-10-17 17:06:05 +0200688 if (buffer_write_chunk(rep, &msg) != 0)
689 return 0;
690 }
691
692 s->data_ctx.stats.px_st = DATA_ST_PX_END;
693 /* fall through */
694
695 case DATA_ST_PX_END:
Willy Tarreau55bb8452007-10-17 18:44:57 +0200696 if (flags & STAT_FMT_HTML) {
697 chunk_printf(&msg, sizeof(trash), "</table><p>\n");
Willy Tarreau91861262007-10-17 17:06:05 +0200698
Willy Tarreau55bb8452007-10-17 18:44:57 +0200699 if (buffer_write_chunk(rep, &msg) != 0)
700 return 0;
701 }
Willy Tarreau91861262007-10-17 17:06:05 +0200702
703 s->data_ctx.stats.px_st = DATA_ST_PX_FIN;
704 /* fall through */
705
706 case DATA_ST_PX_FIN:
707 return 1;
708
709 default:
710 /* unknown state, we should put an abort() here ! */
711 return 1;
712 }
713}
714
715/*
716 * Local variables:
717 * c-indent-level: 8
718 * c-basic-offset: 8
719 * End:
720 */