blob: 9065a5b38c3fa4c92ccf534e731903f8921dc89a [file] [log] [blame]
Willy Tarreaubaaee002006-06-26 02:48:02 +02001/*
2 * General logging functions.
3 *
Willy Tarreaub7f694f2008-06-22 17:18:02 +02004 * Copyright 2000-2008 Willy Tarreau <w@1wt.eu>
Willy Tarreaubaaee002006-06-26 02:48:02 +02005 *
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
Willy Tarreauc8f24f82007-11-30 18:38:35 +010013#include <fcntl.h>
Willy Tarreaubaaee002006-06-26 02:48:02 +020014#include <stdarg.h>
15#include <stdio.h>
16#include <stdlib.h>
17#include <string.h>
18#include <syslog.h>
19#include <time.h>
20#include <unistd.h>
Robert Tsai81ae1952007-12-05 10:47:29 +010021#include <errno.h>
Willy Tarreaubaaee002006-06-26 02:48:02 +020022
23#include <sys/time.h>
24
Willy Tarreaue3ba5f02006-06-29 18:54:54 +020025#include <common/config.h>
Willy Tarreaud6d06902009-08-19 11:22:33 +020026#include <common/compat.h>
Willy Tarreau2dd0d472006-06-29 17:53:05 +020027#include <common/standard.h>
Willy Tarreaufb278672006-10-15 15:38:50 +020028#include <common/time.h>
Willy Tarreaubaaee002006-06-26 02:48:02 +020029
Willy Tarreaubaaee002006-06-26 02:48:02 +020030#include <types/global.h>
William Lallemand723b73a2012-02-08 16:37:49 +010031#include <types/log.h>
Willy Tarreauec6c5df2008-07-15 00:22:45 +020032
33#include <proto/log.h>
Willy Tarreau827aee92011-03-10 16:55:02 +010034#include <proto/stream_interface.h>
Willy Tarreaubaaee002006-06-26 02:48:02 +020035
Willy Tarreaubaaee002006-06-26 02:48:02 +020036const char *log_facilities[NB_LOG_FACILITIES] = {
37 "kern", "user", "mail", "daemon",
38 "auth", "syslog", "lpr", "news",
39 "uucp", "cron", "auth2", "ftp",
40 "ntp", "audit", "alert", "cron2",
41 "local0", "local1", "local2", "local3",
42 "local4", "local5", "local6", "local7"
43};
44
45
46const char *log_levels[NB_LOG_LEVELS] = {
47 "emerg", "alert", "crit", "err",
48 "warning", "notice", "info", "debug"
49};
50
Willy Tarreaua2a64e92011-09-07 23:01:56 +020051const char sess_term_cond[10] = "-cCsSPRIDK"; /* normal, CliTo, CliErr, SrvTo, SrvErr, PxErr, Resource, Internal, Down, Killed */
Willy Tarreaub8750a82006-09-03 09:56:00 +020052const char sess_fin_state[8] = "-RCHDLQT"; /* cliRequest, srvConnect, srvHeader, Data, Last, Queue, Tarpit */
Willy Tarreaubaaee002006-06-26 02:48:02 +020053
William Lallemand723b73a2012-02-08 16:37:49 +010054
55/* log_format */
56struct logformat_type {
57 char *name;
58 int type;
William Lallemandbddd4fd2012-02-27 11:23:10 +010059 int mode;
William Lallemandb7ff6a32012-03-02 14:35:21 +010060 int (*config_callback)(struct logformat_node *node, struct proxy *curproxy);
William Lallemand723b73a2012-02-08 16:37:49 +010061};
62
William Lallemandb7ff6a32012-03-02 14:35:21 +010063int prepare_addrsource(struct logformat_node *node, struct proxy *curproxy);
64
William Lallemand723b73a2012-02-08 16:37:49 +010065/* log_format variable names */
66static const struct logformat_type logformat_keywords[] = {
William Lallemandb7ff6a32012-03-02 14:35:21 +010067 { "o", LOG_GLOBAL, PR_MODE_TCP, NULL }, /* global option */
68 { "Ci", LOG_CLIENTIP, PR_MODE_TCP, NULL }, /* client ip */
69 { "Cp", LOG_CLIENTPORT, PR_MODE_TCP, NULL }, /* client port */
70 { "Bp", LOG_SOURCEPORT, PR_MODE_TCP, prepare_addrsource }, /* backend source port */
71 { "Bi", LOG_SOURCEIP, PR_MODE_TCP, prepare_addrsource }, /* backend source ip */
72 { "t", LOG_DATE, PR_MODE_TCP, NULL }, /* date */
73 { "T", LOG_DATEGMT, PR_MODE_TCP, NULL }, /* date GMT */
74 { "ms", LOG_MS, PR_MODE_TCP, NULL }, /* accept date millisecond */
75 { "f", LOG_FRONTEND, PR_MODE_TCP, NULL }, /* frontend */
76 { "b", LOG_BACKEND, PR_MODE_TCP, NULL }, /* backend */
77 { "s", LOG_SERVER, PR_MODE_TCP, NULL }, /* server */
78 { "B", LOG_BYTES, PR_MODE_TCP, NULL }, /* bytes read */
79 { "Tq", LOG_TQ, PR_MODE_HTTP, NULL }, /* Tq */
80 { "Tw", LOG_TW, PR_MODE_TCP, NULL }, /* Tw */
81 { "Tc", LOG_TC, PR_MODE_TCP, NULL }, /* Tc */
82 { "Tr", LOG_TR, PR_MODE_HTTP, NULL }, /* Tr */
83 { "Tt", LOG_TT, PR_MODE_TCP, NULL }, /* Tt */
84 { "st", LOG_STATUS, PR_MODE_HTTP, NULL }, /* status code */
85 { "cc", LOG_CCLIENT, PR_MODE_HTTP, NULL }, /* client cookie */
86 { "cs", LOG_CSERVER, PR_MODE_HTTP, NULL }, /* server cookie */
87 { "ts", LOG_TERMSTATE, PR_MODE_TCP, NULL },/* terminaison state */
Willy Tarreau6580c062012-03-12 15:09:42 +010088 { "tsc", LOG_TERMSTATE_CK, PR_MODE_HTTP, NULL },/* terminaison state with cookie status */
William Lallemandb7ff6a32012-03-02 14:35:21 +010089 { "ac", LOG_ACTCONN, PR_MODE_TCP, NULL }, /* actconn */
90 { "fc", LOG_FECONN, PR_MODE_TCP, NULL }, /* feconn */
91 { "bc", LOG_BECONN, PR_MODE_TCP, NULL }, /* beconn */
92 { "sc", LOG_SRVCONN, PR_MODE_TCP, NULL }, /* srv_conn */
93 { "rc", LOG_RETRIES, PR_MODE_TCP, NULL }, /* retries */
94 { "sq", LOG_SRVQUEUE, PR_MODE_TCP, NULL }, /* srv_queue */
95 { "bq", LOG_BCKQUEUE, PR_MODE_TCP, NULL }, /* backend_queue */
96 { "hr", LOG_HDRREQUEST, PR_MODE_HTTP, NULL }, /* header request */
97 { "hs", LOG_HDRRESPONS, PR_MODE_HTTP, NULL }, /* header response */
98 { "hrl", LOG_HDRREQUESTLIST, PR_MODE_HTTP, NULL }, /* header request list */
99 { "hsl", LOG_HDRRESPONSLIST, PR_MODE_HTTP, NULL }, /* header response list */
100 { "r", LOG_REQ, PR_MODE_HTTP, NULL }, /* request */
101 { 0, 0, 0, NULL }
William Lallemand723b73a2012-02-08 16:37:49 +0100102};
103
Willy Tarreau6580c062012-03-12 15:09:42 +0100104char default_http_log_format[] = "%Ci:%Cp [%t] %f %b/%s %Tq/%Tw/%Tc/%Tr/%Tt %st %B %cc %cs %tsc %ac/%fc/%bc/%sc/%rc %sq/%bq %hr %hs %{+Q}r"; // default format
105char clf_http_log_format[] = "%{+Q}o %{-Q}Ci - - [%T] %r %st %B \"\" \"\" %Cp %ms %f %b %s %Tq %Tw %Tc %Tr %Tt %tsc %ac %fc %bc %sc %rc %sq %bq %cc %cs %hrl %hsl";
William Lallemandbddd4fd2012-02-27 11:23:10 +0100106char default_tcp_log_format[] = "%Ci:%Cp [%t] %f %b/%s %Tw/%Tc/%Tt %B %ts %ac/%fc/%bc/%sc/%rc %sq/%bq";
William Lallemand723b73a2012-02-08 16:37:49 +0100107char *log_format = NULL;
108
Willy Tarreaub1a2faf2012-03-19 16:51:53 +0100109/* This is a global syslog line, common to all outgoing messages. It begins
110 * with the syslog tag and the date that are updated by update_log_hdr().
111 */
112static char logline[MAX_SYSLOG_LEN];
113
William Lallemand723b73a2012-02-08 16:37:49 +0100114struct logformat_var_args {
115 char *name;
116 int mask;
117};
118
119struct logformat_var_args var_args_list[] = {
120// global
121 { "M", LOG_OPT_MANDATORY },
122 { "Q", LOG_OPT_QUOTE },
123 { 0, 0 }
124};
125
126/*
William Lallemandb7ff6a32012-03-02 14:35:21 +0100127 * callback used to configure addr source retrieval
128 */
129int prepare_addrsource(struct logformat_node *node, struct proxy *curproxy)
130{
131 curproxy->options2 |= PR_O2_SRC_ADDR;
132
133 return 0;
134}
135
136
137/*
William Lallemand723b73a2012-02-08 16:37:49 +0100138 * Parse args in a logformat_var
139 */
140int parse_logformat_var_args(char *args, struct logformat_node *node)
141{
142 int i = 0;
143 int end = 0;
144 int flags = 0; // 1 = + 2 = -
145 char *sp = NULL; // start pointer
146
147 if (args == NULL)
148 return 1;
149
150 while (1) {
151 if (*args == '\0')
152 end = 1;
153
154 if (*args == '+') {
155 // add flag
156 sp = args + 1;
157 flags = 1;
158 }
159 if (*args == '-') {
160 // delete flag
161 sp = args + 1;
162 flags = 2;
163 }
164
165 if (*args == '\0' || *args == ',') {
166 *args = '\0';
167 for (i = 0; var_args_list[i].name; i++) {
168 if (strcmp(sp, var_args_list[i].name) == 0) {
169 if (flags == 1) {
170 node->options |= var_args_list[i].mask;
171 break;
172 } else if (flags == 2) {
173 node->options &= ~var_args_list[i].mask;
174 break;
175 }
176 }
177 }
178 sp = NULL;
179 if (end)
180 break;
181 }
182 args++;
183 }
184 return 0;
185}
186
187/*
188 * Parse a variable '%varname' or '%{args}varname' in logformat
189 *
190 */
William Lallemand81f51172012-03-12 11:03:47 +0100191int parse_logformat_var(char *str, size_t len, struct proxy *curproxy, int *defoptions)
William Lallemand723b73a2012-02-08 16:37:49 +0100192{
193 int i, j;
194 char *arg = NULL; // arguments
195 int fparam = 0;
196 char *name = NULL;
197 struct logformat_node *node = NULL;
198 char varname[255] = { 0 }; // variable name
William Lallemand723b73a2012-02-08 16:37:49 +0100199
William Lallemand723b73a2012-02-08 16:37:49 +0100200 for (i = 1; i < len; i++) { // escape first char %
201 if (!arg && str[i] == '{') {
202 arg = str + i;
203 fparam = 1;
204 } else if (arg && str[i] == '}') {
205 char *tmp = arg;
206 arg = calloc(str + i - tmp, 1); // without {}
207 strncpy(arg, tmp + 1, str + i - tmp - 1); // copy without { and }
208 arg[str + i - tmp - 1] = '\0';
209 fparam = 0;
210 } else if (!name && !fparam) {
211 strncpy(varname, str + i, len - i + 1);
212 varname[len - i] = '\0';
213 for (j = 0; logformat_keywords[j].name; j++) { // search a log type
214 if (strcmp(varname, logformat_keywords[j].name) == 0) {
William Lallemandbddd4fd2012-02-27 11:23:10 +0100215 if (!((logformat_keywords[j].mode == PR_MODE_HTTP) && (curproxy->mode == PR_MODE_TCP))) {
216 node = calloc(1, sizeof(struct logformat_node));
217 node->type = logformat_keywords[j].type;
William Lallemand81f51172012-03-12 11:03:47 +0100218 node->options = *defoptions;
William Lallemandbddd4fd2012-02-27 11:23:10 +0100219 node->arg = arg;
220 parse_logformat_var_args(node->arg, node);
221 if (node->type == LOG_GLOBAL) {
William Lallemand81f51172012-03-12 11:03:47 +0100222 *defoptions = node->options;
William Lallemandbddd4fd2012-02-27 11:23:10 +0100223 free(node);
224 } else {
William Lallemandb7ff6a32012-03-02 14:35:21 +0100225 if (logformat_keywords[j].config_callback != NULL) {
226 if (logformat_keywords[j].config_callback(node, curproxy) != 0) {
227 return -1;
228 }
229 }
William Lallemandbddd4fd2012-02-27 11:23:10 +0100230 LIST_ADDQ(&curproxy->logformat, &node->list);
231 }
232 return 0;
William Lallemand723b73a2012-02-08 16:37:49 +0100233 } else {
William Lallemandbddd4fd2012-02-27 11:23:10 +0100234 Warning("Warning: No such variable name '%s' in this log mode\n", varname);
235 if (arg)
236 free(arg);
237 return -1;
William Lallemand723b73a2012-02-08 16:37:49 +0100238 }
William Lallemand723b73a2012-02-08 16:37:49 +0100239 }
240 }
241 Warning("Warning: No such variable name '%s' in logformat\n", varname);
242 if (arg)
243 free(arg);
244 return -1;
245 }
246 }
247 return -1;
248}
249
250/*
251 * push to the logformat linked list
252 *
253 * start: start pointer
254 * end: end text pointer
255 * type: string type
256 *
257 * LOG_TEXT: copy chars from start to end excluding end.
258 *
259*/
260void add_to_logformat_list(char *start, char *end, int type, struct proxy *curproxy)
261{
262 char *str;
263
264 if (type == LOG_TEXT) { /* type text */
265 struct logformat_node *node = calloc(1, sizeof(struct logformat_node));
266
267 str = calloc(end - start + 1, 1);
268 strncpy(str, start, end - start);
269
270 str[end - start] = '\0';
271 node->arg = str;
272 node->type = LOG_TEXT; // type string
273 LIST_ADDQ(&curproxy->logformat, &node->list);
William Lallemand723b73a2012-02-08 16:37:49 +0100274 } else if (type == LOG_SEPARATOR) {
275 struct logformat_node *node = calloc(1, sizeof(struct logformat_node));
276 node->type = LOG_SEPARATOR;
277 LIST_ADDQ(&curproxy->logformat, &node->list);
278 }
279}
280
281/*
282 * Parse the log_format string and fill a linked list.
283 * Variable name are preceded by % and composed by characters [a-zA-Z0-9]* : %varname
284 * You can set arguments using { } : %{many arguments}varname
285 */
286void parse_logformat_string(char *str, struct proxy *curproxy)
287{
288 char *sp = str; /* start pointer */
289 int cformat = -1; /* current token format : LOG_TEXT, LOG_SEPARATOR, LOG_VARIABLE */
290 int pformat = -1; /* previous token format */
291 struct logformat_node *tmplf, *back;
William Lallemand81f51172012-03-12 11:03:47 +0100292 int options = 0;
William Lallemand723b73a2012-02-08 16:37:49 +0100293
294 /* flush the list first. */
295 list_for_each_entry_safe(tmplf, back, &curproxy->logformat, list) {
296 LIST_DEL(&tmplf->list);
297 free(tmplf);
298 }
299
300 while (1) {
301
302 // push the variable only if formats are different, not
303 // within a variable, and not the first iteration
304 if ((cformat != pformat && cformat != -1 && pformat != -1) || *str == '\0') {
305 if (((pformat != LF_STARTVAR && cformat != LF_VAR) &&
306 (pformat != LF_STARTVAR && cformat != LF_STARG) &&
307 (pformat != LF_STARG && cformat != LF_VAR)) || *str == '\0') {
308 if (pformat > LF_VAR) // unfinished string
309 pformat = LF_TEXT;
William Lallemand81f51172012-03-12 11:03:47 +0100310 if (pformat == LF_VAR)
311 parse_logformat_var(sp, str - sp, curproxy, &options);
312 else
313 add_to_logformat_list(sp, str, pformat, curproxy);
William Lallemand723b73a2012-02-08 16:37:49 +0100314 sp = str;
315 if (*str == '\0')
316 break;
317 }
318 }
319
320 if (cformat != -1)
321 str++; // consume the string, except on the first tour
322
323 pformat = cformat;
324
325 if (*str == '\0') {
326 cformat = LF_STARTVAR; // for breaking in all cases
327 continue;
328 }
329
330 if (pformat == LF_STARTVAR) { // after a %
331 if ( (*str >= 'a' && *str <= 'z') || // parse varname
332 (*str >= 'A' && *str <= 'Z') ||
333 (*str >= '0' && *str <= '9')) {
334 cformat = LF_VAR; // varname
335 continue;
336 } else if (*str == '{') {
337 cformat = LF_STARG; // variable arguments
338 continue;
339 } else { // another unexpected token
340 pformat = LF_TEXT; // redefine the format of the previous token to TEXT
341 cformat = LF_TEXT;
342 continue;
343 }
344
345 } else if (pformat == LF_VAR) { // after a varname
346 if ( (*str >= 'a' && *str <= 'z') || // parse varname
347 (*str >= 'A' && *str <= 'Z') ||
348 (*str >= '0' && *str <= '9')) {
349 cformat = LF_VAR;
350 continue;
351 }
352 } else if (pformat == LF_STARG) { // inside variable arguments
353 if (*str == '}') { // end of varname
354 cformat = LF_EDARG;
355 continue;
356 } else { // all tokens are acceptable within { }
357 cformat = LF_STARG;
358 continue;
359 }
360 } else if (pformat == LF_EDARG) { // after arguments
361 if ( (*str >= 'a' && *str <= 'z') || // parse a varname
362 (*str >= 'A' && *str <= 'Z') ||
363 (*str >= '0' && *str <= '9')) {
364 cformat = LF_VAR;
365 continue;
366 } else { // if no varname after arguments, transform in TEXT
367 pformat = LF_TEXT;
368 cformat = LF_TEXT;
369 }
370 }
371
372 // others tokens that don't match previous conditions
373 if (*str == '%') {
374 cformat = LF_STARTVAR;
375 } else if (*str == ' ') {
376 cformat = LF_SEPARATOR;
377 } else {
378 cformat = LF_TEXT;
379 }
380 }
381}
382
Willy Tarreaubaaee002006-06-26 02:48:02 +0200383/*
384 * Displays the message on stderr with the date and pid. Overrides the quiet
385 * mode during startup.
386 */
Willy Tarreaub17916e2006-10-15 15:17:57 +0200387void Alert(const char *fmt, ...)
Willy Tarreaubaaee002006-06-26 02:48:02 +0200388{
389 va_list argp;
Willy Tarreaufe944602007-10-25 10:34:16 +0200390 struct tm tm;
Willy Tarreaubaaee002006-06-26 02:48:02 +0200391
392 if (!(global.mode & MODE_QUIET) || (global.mode & (MODE_VERBOSE | MODE_STARTING))) {
393 va_start(argp, fmt);
394
Willy Tarreaub7f694f2008-06-22 17:18:02 +0200395 get_localtime(date.tv_sec, &tm);
Willy Tarreaubaaee002006-06-26 02:48:02 +0200396 fprintf(stderr, "[ALERT] %03d/%02d%02d%02d (%d) : ",
Willy Tarreaufe944602007-10-25 10:34:16 +0200397 tm.tm_yday, tm.tm_hour, tm.tm_min, tm.tm_sec, (int)getpid());
Willy Tarreaubaaee002006-06-26 02:48:02 +0200398 vfprintf(stderr, fmt, argp);
399 fflush(stderr);
400 va_end(argp);
401 }
402}
403
404
405/*
406 * Displays the message on stderr with the date and pid.
407 */
Willy Tarreaub17916e2006-10-15 15:17:57 +0200408void Warning(const char *fmt, ...)
Willy Tarreaubaaee002006-06-26 02:48:02 +0200409{
410 va_list argp;
Willy Tarreaufe944602007-10-25 10:34:16 +0200411 struct tm tm;
Willy Tarreaubaaee002006-06-26 02:48:02 +0200412
413 if (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE)) {
414 va_start(argp, fmt);
415
Willy Tarreaub7f694f2008-06-22 17:18:02 +0200416 get_localtime(date.tv_sec, &tm);
Willy Tarreaubaaee002006-06-26 02:48:02 +0200417 fprintf(stderr, "[WARNING] %03d/%02d%02d%02d (%d) : ",
Willy Tarreaufe944602007-10-25 10:34:16 +0200418 tm.tm_yday, tm.tm_hour, tm.tm_min, tm.tm_sec, (int)getpid());
Willy Tarreaubaaee002006-06-26 02:48:02 +0200419 vfprintf(stderr, fmt, argp);
420 fflush(stderr);
421 va_end(argp);
422 }
423}
424
425/*
426 * Displays the message on <out> only if quiet mode is not set.
427 */
Willy Tarreaub17916e2006-10-15 15:17:57 +0200428void qfprintf(FILE *out, const char *fmt, ...)
Willy Tarreaubaaee002006-06-26 02:48:02 +0200429{
430 va_list argp;
431
432 if (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE)) {
433 va_start(argp, fmt);
434 vfprintf(out, fmt, argp);
435 fflush(out);
436 va_end(argp);
437 }
438}
439
440/*
441 * returns log level for <lev> or -1 if not found.
442 */
443int get_log_level(const char *lev)
444{
445 int level;
446
447 level = NB_LOG_LEVELS - 1;
448 while (level >= 0 && strcmp(log_levels[level], lev))
449 level--;
450
451 return level;
452}
453
454
455/*
456 * returns log facility for <fac> or -1 if not found.
457 */
458int get_log_facility(const char *fac)
459{
460 int facility;
461
462 facility = NB_LOG_FACILITIES - 1;
463 while (facility >= 0 && strcmp(log_facilities[facility], fac))
464 facility--;
William Lallemand2a4a44f2012-02-06 16:00:33 +0100465
Willy Tarreaubaaee002006-06-26 02:48:02 +0200466 return facility;
467}
468
William Lallemanda1cc3812012-02-08 16:38:44 +0100469/*
470 * Write a string in the log string
471 * Take cares of mandatory and quote options
472 *
473 * Return the adress of the \0 character, or NULL on error
474 */
475char *logformat_write_string(char *dst, char *src, size_t size, struct logformat_node *node)
476{
William Lallemand51b5dca2012-03-26 17:52:55 +0200477 int n;
William Lallemanda1cc3812012-02-08 16:38:44 +0100478
William Lallemandbddd4fd2012-02-27 11:23:10 +0100479 if (src == NULL || *src == '\0') {
480 if (node->options & LOG_OPT_QUOTE) {
481 if (size > 2) {
482 *(dst++) = '"';
483 *(dst++) = '"';
484 *dst = '\0';
485 node->options |= LOG_OPT_WRITTEN;
486 } else {
487 dst = NULL;
488 return dst;
489 }
490 } else {
491 if (size > 1) {
492 *(dst++) = '-';
493 *dst = '\0';
494 node->options |= LOG_OPT_WRITTEN;
495 } else { // error no space available
496 dst = NULL;
497 return dst;
498 }
499 }
500 } else {
501 if (node->options & LOG_OPT_QUOTE) {
502 if (size-- > 1 ) {
503 *(dst++) = '"';
504 } else {
505 dst = NULL;
506 return NULL;
507 }
William Lallemand51b5dca2012-03-26 17:52:55 +0200508 n = strlcpy2(dst, src, size);
509 size -= n;
510 dst += n;
William Lallemandbddd4fd2012-02-27 11:23:10 +0100511 if (size > 1) {
512 *(dst++) = '"';
513 *dst = '\0';
514 } else {
515 dst = NULL;
516 }
517 } else {
518 dst += strlcpy2(dst, src, size);
519 }
520 }
521 return dst;
William Lallemanda1cc3812012-02-08 16:38:44 +0100522}
523
Willy Tarreaub1a2faf2012-03-19 16:51:53 +0100524/* Re-generate the syslog header at the beginning of logline once a second and
525 * return the pointer to the first character after the header.
526 */
527static char *update_log_hdr()
Willy Tarreaubaaee002006-06-26 02:48:02 +0200528{
Willy Tarreaub1a2faf2012-03-19 16:51:53 +0100529 static long tvsec;
530 static char *dataptr = NULL; /* backup of last end of header, NULL first time */
Willy Tarreaubaaee002006-06-26 02:48:02 +0200531
Willy Tarreaub7f694f2008-06-22 17:18:02 +0200532 if (unlikely(date.tv_sec != tvsec || dataptr == NULL)) {
Willy Tarreaubaaee002006-06-26 02:48:02 +0200533 /* this string is rebuild only once a second */
Willy Tarreaufe944602007-10-25 10:34:16 +0200534 struct tm tm;
Willy Tarreaub1a2faf2012-03-19 16:51:53 +0100535 int hdr_len;
Willy Tarreaufe944602007-10-25 10:34:16 +0200536
Willy Tarreaub7f694f2008-06-22 17:18:02 +0200537 tvsec = date.tv_sec;
Willy Tarreaufe944602007-10-25 10:34:16 +0200538 get_localtime(tvsec, &tm);
Willy Tarreaubaaee002006-06-26 02:48:02 +0200539
Willy Tarreaub1a2faf2012-03-19 16:51:53 +0100540 hdr_len = snprintf(logline, MAX_SYSLOG_LEN,
Joe Williamsdf5b38f2010-12-29 17:05:48 +0100541 "<<<<>%s %2d %02d:%02d:%02d %s%s[%d]: ",
Willy Tarreaufe944602007-10-25 10:34:16 +0200542 monthname[tm.tm_mon],
543 tm.tm_mday, tm.tm_hour, tm.tm_min, tm.tm_sec,
Joe Williamsdf5b38f2010-12-29 17:05:48 +0100544 global.log_send_hostname ? global.log_send_hostname : "",
Kevinm48936af2010-12-22 16:08:21 +0000545 global.log_tag, pid);
Willy Tarreaubaaee002006-06-26 02:48:02 +0200546 /* WARNING: depending upon implementations, snprintf may return
547 * either -1 or the number of bytes that would be needed to store
548 * the total message. In both cases, we must adjust it.
549 */
William Lallemand2a4a44f2012-02-06 16:00:33 +0100550 if (hdr_len < 0 || hdr_len > MAX_SYSLOG_LEN)
551 hdr_len = MAX_SYSLOG_LEN;
Willy Tarreaubaaee002006-06-26 02:48:02 +0200552
Willy Tarreaub1a2faf2012-03-19 16:51:53 +0100553 dataptr = logline + hdr_len;
Willy Tarreaubaaee002006-06-26 02:48:02 +0200554 }
555
William Lallemand2a4a44f2012-02-06 16:00:33 +0100556 return dataptr;
557}
558
559/*
560 * This function adds a header to the message and sends the syslog message
Willy Tarreau53bf6af2012-02-24 11:46:54 +0100561 * using a printf format string. It expects an LF-terminated message.
William Lallemand2a4a44f2012-02-06 16:00:33 +0100562 */
563void send_log(struct proxy *p, int level, const char *format, ...)
564{
565 va_list argp;
Willy Tarreaub1a2faf2012-03-19 16:51:53 +0100566 char *dataptr;
567 int data_len;
William Lallemand2a4a44f2012-02-06 16:00:33 +0100568
569 if (level < 0 || format == NULL)
570 return;
571
Willy Tarreaub1a2faf2012-03-19 16:51:53 +0100572 dataptr = update_log_hdr(); /* update log header and skip it */
573 data_len = dataptr - logline;
William Lallemand2a4a44f2012-02-06 16:00:33 +0100574
575 va_start(argp, format);
Willy Tarreaub1a2faf2012-03-19 16:51:53 +0100576 data_len += vsnprintf(dataptr, logline + sizeof(logline) - dataptr, format, argp);
William Lallemand2a4a44f2012-02-06 16:00:33 +0100577 if (data_len < 0 || data_len > MAX_SYSLOG_LEN)
578 data_len = MAX_SYSLOG_LEN;
Willy Tarreaubaaee002006-06-26 02:48:02 +0200579 va_end(argp);
William Lallemand2a4a44f2012-02-06 16:00:33 +0100580
Willy Tarreaub1a2faf2012-03-19 16:51:53 +0100581 __send_log(p, level, logline, data_len);
William Lallemand2a4a44f2012-02-06 16:00:33 +0100582}
583
584/*
585 * This function sends a syslog message.
586 * It doesn't care about errors nor does it report them.
Willy Tarreau53bf6af2012-02-24 11:46:54 +0100587 * It overrides the last byte (message[size-1]) with an LF character.
William Lallemand2a4a44f2012-02-06 16:00:33 +0100588 */
589void __send_log(struct proxy *p, int level, char *message, size_t size)
590{
591 static int logfdunix = -1; /* syslog to AF_UNIX socket */
592 static int logfdinet = -1; /* syslog to AF_INET socket */
593 static char *dataptr = NULL;
594 int fac_level;
595 struct list *logsrvs = NULL;
596 struct logsrv *tmp = NULL;
597 int nblogger;
598 char *log_ptr;
599
600 dataptr = message;
Willy Tarreaubaaee002006-06-26 02:48:02 +0200601
602 if (p == NULL) {
William Lallemand0f99e342011-10-12 17:50:54 +0200603 if (!LIST_ISEMPTY(&global.logsrvs)) {
604 logsrvs = &global.logsrvs;
Willy Tarreaubaaee002006-06-26 02:48:02 +0200605 }
606 } else {
William Lallemand0f99e342011-10-12 17:50:54 +0200607 if (!LIST_ISEMPTY(&p->logsrvs)) {
608 logsrvs = &p->logsrvs;
Willy Tarreaubaaee002006-06-26 02:48:02 +0200609 }
Robert Tsai81ae1952007-12-05 10:47:29 +0100610 }
611
William Lallemand0f99e342011-10-12 17:50:54 +0200612 if (!logsrvs)
613 return;
614
William Lallemand2a4a44f2012-02-06 16:00:33 +0100615 message[size - 1] = '\n';
616
Robert Tsai81ae1952007-12-05 10:47:29 +0100617 /* Lazily set up syslog sockets for protocol families of configured
618 * syslog servers. */
William Lallemand0f99e342011-10-12 17:50:54 +0200619 nblogger = 0;
620 list_for_each_entry(tmp, logsrvs, list) {
621 const struct logsrv *logsrv = tmp;
Robert Tsai81ae1952007-12-05 10:47:29 +0100622 int proto, *plogfd;
William Lallemand0f99e342011-10-12 17:50:54 +0200623
David du Colombier11bcb6c2011-03-24 12:23:00 +0100624 if (logsrv->addr.ss_family == AF_UNIX) {
Robert Tsai81ae1952007-12-05 10:47:29 +0100625 proto = 0;
626 plogfd = &logfdunix;
627 } else {
Robert Tsai81ae1952007-12-05 10:47:29 +0100628 proto = IPPROTO_UDP;
629 plogfd = &logfdinet;
630 }
631 if (*plogfd >= 0) {
632 /* socket already created. */
633 continue;
634 }
David du Colombier11bcb6c2011-03-24 12:23:00 +0100635 if ((*plogfd = socket(logsrv->addr.ss_family, SOCK_DGRAM,
Robert Tsai81ae1952007-12-05 10:47:29 +0100636 proto)) < 0) {
637 Alert("socket for logger #%d failed: %s (errno=%d)\n",
638 nblogger + 1, strerror(errno), errno);
639 return;
640 }
641 /* we don't want to receive anything on this socket */
642 setsockopt(*plogfd, SOL_SOCKET, SO_RCVBUF, &zero, sizeof(zero));
643 /* does nothing under Linux, maybe needed for others */
644 shutdown(*plogfd, SHUT_RD);
William Lallemand0f99e342011-10-12 17:50:54 +0200645 nblogger++;
Willy Tarreaubaaee002006-06-26 02:48:02 +0200646 }
647
Robert Tsai81ae1952007-12-05 10:47:29 +0100648 /* Send log messages to syslog server. */
William Lallemand0f99e342011-10-12 17:50:54 +0200649 nblogger = 0;
650 list_for_each_entry(tmp, logsrvs, list) {
651 const struct logsrv *logsrv = tmp;
David du Colombier11bcb6c2011-03-24 12:23:00 +0100652 int *plogfd = logsrv->addr.ss_family == AF_UNIX ?
Robert Tsai81ae1952007-12-05 10:47:29 +0100653 &logfdunix : &logfdinet;
654 int sent;
655
Willy Tarreaubaaee002006-06-26 02:48:02 +0200656 /* we can filter the level of the messages that are sent to each logger */
William Lallemand0f99e342011-10-12 17:50:54 +0200657 if (level > logsrv->level)
Willy Tarreaubaaee002006-06-26 02:48:02 +0200658 continue;
William Lallemandbddd4fd2012-02-27 11:23:10 +0100659
Willy Tarreaubaaee002006-06-26 02:48:02 +0200660 /* For each target, we may have a different facility.
661 * We can also have a different log level for each message.
662 * This induces variations in the message header length.
663 * Since we don't want to recompute it each time, nor copy it every
664 * time, we only change the facility in the pre-computed header,
665 * and we change the pointer to the header accordingly.
666 */
William Lallemand0f99e342011-10-12 17:50:54 +0200667 fac_level = (logsrv->facility << 3) + MAX(level, logsrv->minlvl);
William Lallemand2a4a44f2012-02-06 16:00:33 +0100668 log_ptr = dataptr + 3; /* last digit of the log level */
Willy Tarreaubaaee002006-06-26 02:48:02 +0200669 do {
670 *log_ptr = '0' + fac_level % 10;
671 fac_level /= 10;
672 log_ptr--;
William Lallemand2a4a44f2012-02-06 16:00:33 +0100673 } while (fac_level && log_ptr > dataptr);
Willy Tarreaubaaee002006-06-26 02:48:02 +0200674 *log_ptr = '<';
William Lallemand2a4a44f2012-02-06 16:00:33 +0100675
William Lallemandbfb099c2012-03-19 16:15:12 +0100676 sent = sendto(*plogfd, log_ptr, size + log_ptr - dataptr,
Willy Tarreau1b4b7ce2011-04-05 16:56:50 +0200677 MSG_DONTWAIT | MSG_NOSIGNAL,
678 (struct sockaddr *)&logsrv->addr, get_addr_len(&logsrv->addr));
Robert Tsai81ae1952007-12-05 10:47:29 +0100679 if (sent < 0) {
680 Alert("sendto logger #%d failed: %s (errno=%d)\n",
681 nblogger, strerror(errno), errno);
682 }
William Lallemand0f99e342011-10-12 17:50:54 +0200683 nblogger++;
Willy Tarreaubaaee002006-06-26 02:48:02 +0200684 }
685}
686
William Lallemandbddd4fd2012-02-27 11:23:10 +0100687extern fd_set hdr_encode_map[];
688extern fd_set url_encode_map[];
689
Willy Tarreaubaaee002006-06-26 02:48:02 +0200690
Willy Tarreauc89ccb62012-04-05 21:18:22 +0200691const char sess_cookie[8] = "NIDVEOU7"; /* No cookie, Invalid cookie, cookie for a Down server, Valid cookie, Expired cookie, Old cookie, Unused, unknown */
William Lallemandbddd4fd2012-02-27 11:23:10 +0100692const char sess_set_cookie[8] = "NPDIRU67"; /* No set-cookie, Set-cookie found and left unchanged (passive),
693 Set-cookie Deleted, Set-Cookie Inserted, Set-cookie Rewritten,
694 Set-cookie Updated, unknown, unknown */
695
696#define LOGCHAR(x) do { \
William Lallemand51b5dca2012-03-26 17:52:55 +0200697 if (tmplog < logline + MAX_SYSLOG_LEN - 1) { \
William Lallemandbddd4fd2012-02-27 11:23:10 +0100698 *(tmplog++) = (x); \
699 } else { \
700 goto out; \
701 } \
702 } while(0)
703
Willy Tarreaubaaee002006-06-26 02:48:02 +0200704/*
William Lallemandbddd4fd2012-02-27 11:23:10 +0100705 * send a log for the session when we have enough info about it.
706 * Will not log if the frontend has no log defined.
Willy Tarreaubaaee002006-06-26 02:48:02 +0200707 */
William Lallemandbddd4fd2012-02-27 11:23:10 +0100708void sess_log(struct session *s)
Willy Tarreaubaaee002006-06-26 02:48:02 +0200709{
Cyril Bontéacd7d632010-11-01 19:26:02 +0100710 char pn[INET6_ADDRSTRLEN];
William Lallemandb7ff6a32012-03-02 14:35:21 +0100711 char sn[INET6_ADDRSTRLEN];
Willy Tarreau73de9892006-11-30 11:40:23 +0100712 struct proxy *fe = s->fe;
Willy Tarreauddb358d2006-12-17 22:55:52 +0100713 struct proxy *be = s->be;
714 struct proxy *prx_log;
William Lallemandbddd4fd2012-02-27 11:23:10 +0100715 struct http_txn *txn = &s->txn;
Willy Tarreauc9bd0cc2009-05-10 11:57:02 +0200716 int tolog, level, err;
William Lallemandbddd4fd2012-02-27 11:23:10 +0100717 char *uri;
718 const char *svid;
Willy Tarreaufe944602007-10-25 10:34:16 +0200719 struct tm tm;
William Lallemandbddd4fd2012-02-27 11:23:10 +0100720 int t_request;
721 int hdr;
722 int last_isspace = 1;
Willy Tarreaub1a2faf2012-03-19 16:51:53 +0100723 char *tmplog;
William Lallemandbddd4fd2012-02-27 11:23:10 +0100724 struct logformat_node *tmp;
Willy Tarreaubaaee002006-06-26 02:48:02 +0200725
Willy Tarreauc9bd0cc2009-05-10 11:57:02 +0200726 /* if we don't want to log normal traffic, return now */
William Lallemandbddd4fd2012-02-27 11:23:10 +0100727 err = (s->flags & (SN_ERR_MASK | SN_REDISP)) ||
728 (s->req->cons->conn_retries != be->conn_retries) ||
729 ((s->fe->mode == PR_MODE_HTTP) && txn->status >= 500);
Willy Tarreauc9bd0cc2009-05-10 11:57:02 +0200730 if (!err && (fe->options2 & PR_O2_NOLOGNORM))
731 return;
732
William Lallemandbddd4fd2012-02-27 11:23:10 +0100733 if (LIST_ISEMPTY(&fe->logsrvs))
Willy Tarreaue7ded1f2009-08-09 10:11:45 +0200734 return;
Willy Tarreaue7ded1f2009-08-09 10:11:45 +0200735 prx_log = fe;
William Lallemandbddd4fd2012-02-27 11:23:10 +0100736
737 if (addr_to_str(&s->req->prod->addr.from, pn, sizeof(pn)) == AF_UNIX)
738 snprintf(pn, sizeof(pn), "unix:%d", s->listener->luid);
739
William Lallemandb7ff6a32012-03-02 14:35:21 +0100740 if (be->options2 & PR_O2_SRC_ADDR) {
741 if (addr_to_str(&s->req->cons->addr.from, sn, sizeof(sn)) == AF_UNIX)
742 snprintf(sn, sizeof(sn), "unix:%d", s->listener->luid);
743 }
744
William Lallemandbddd4fd2012-02-27 11:23:10 +0100745 /* FIXME: let's limit ourselves to frontend logging for now. */
Willy Tarreau42250582007-04-01 01:30:43 +0200746 tolog = fe->to_log;
Willy Tarreau71904a42011-02-13 14:30:26 +0100747
748 if (!(tolog & LW_SVID))
749 svid = "-";
Willy Tarreau7b7a8e92011-03-27 19:53:06 +0200750 else switch (s->target.type) {
Willy Tarreau71904a42011-02-13 14:30:26 +0100751 case TARG_TYPE_SERVER:
Willy Tarreau7b7a8e92011-03-27 19:53:06 +0200752 svid = s->target.ptr.s->id;
Willy Tarreau71904a42011-02-13 14:30:26 +0100753 break;
754 case TARG_TYPE_APPLET:
Willy Tarreau7b7a8e92011-03-27 19:53:06 +0200755 svid = s->target.ptr.a->name;
Willy Tarreau71904a42011-02-13 14:30:26 +0100756 break;
757 default:
758 svid = "<NOSRV>";
759 break;
760 }
Willy Tarreaubaaee002006-06-26 02:48:02 +0200761
William Lallemandbddd4fd2012-02-27 11:23:10 +0100762 t_request = -1;
763 if (tv_isge(&s->logs.tv_request, &s->logs.tv_accept))
764 t_request = tv_ms_elapsed(&s->logs.tv_accept, &s->logs.tv_request);
765
Willy Tarreauc9bd0cc2009-05-10 11:57:02 +0200766 level = LOG_INFO;
767 if (err && (fe->options2 & PR_O2_LOGERRORS))
768 level = LOG_ERR;
769
William Lallemandbddd4fd2012-02-27 11:23:10 +0100770 /* fill logbuffer */
771
Willy Tarreaub1a2faf2012-03-19 16:51:53 +0100772 tmplog = update_log_hdr(); /* update log header and skip it */
William Lallemandbddd4fd2012-02-27 11:23:10 +0100773
774 list_for_each_entry(tmp, &fe->logformat, list) {
775 char *src = NULL;
776 switch (tmp->type) {
777
778 case LOG_SEPARATOR:
779 if (!last_isspace) {
780 LOGCHAR(' ');
781 last_isspace = 1;
782 *tmplog = '\0';
783 }
784 break;
785
786 case LOG_TEXT: // text
787 src = tmp->arg;
788 tmplog += strlcpy2(tmplog, src, MAX_SYSLOG_LEN - (tmplog - logline));
William Lallemand51b5dca2012-03-26 17:52:55 +0200789 if (tmplog > logline + MAX_SYSLOG_LEN - 2)
William Lallemandbddd4fd2012-02-27 11:23:10 +0100790 goto out;
791 last_isspace = 0;
792 break;
793
794 case LOG_CLIENTIP: // %Ci
795 src = (s->req->prod->addr.from.ss_family == AF_UNIX) ? "unix" : pn;
796 tmplog = logformat_write_string(tmplog, src, MAX_SYSLOG_LEN - (tmplog - logline), tmp);
William Lallemandbddd4fd2012-02-27 11:23:10 +0100797 if (!tmplog)
798 goto out;
799 last_isspace = 0;
800 break;
801
802 case LOG_CLIENTPORT: // %Cp
803 tmplog = ltoa_o((s->req->prod->addr.from.ss_family == AF_UNIX) ? s->listener->luid : get_host_port(&s->req->prod->addr.from),
804 tmplog, MAX_SYSLOG_LEN - (tmplog - logline));
805 if (!tmplog)
806 goto out;
807 last_isspace = 0;
808 break;
809
William Lallemandb7ff6a32012-03-02 14:35:21 +0100810 case LOG_SOURCEIP: // Bi
811 src = (s->req->cons->addr.from.ss_family == AF_UNIX) ? "unix" : sn;
812 tmplog = logformat_write_string(tmplog, src, MAX_SYSLOG_LEN - (tmplog - logline), tmp);
William Lallemandb7ff6a32012-03-02 14:35:21 +0100813 if (!tmplog)
814 goto out;
815 last_isspace = 0;
816 break;
817
818 case LOG_SOURCEPORT: // %Bp
819 tmplog = ltoa_o((s->req->cons->addr.from.ss_family == AF_UNIX) ? s->listener->luid : get_host_port(&s->req->cons->addr.from),
820 tmplog, MAX_SYSLOG_LEN - (tmplog - logline));
821 if (!tmplog)
822 goto out;
823 last_isspace = 0;
824 break;
825
William Lallemandbddd4fd2012-02-27 11:23:10 +0100826 case LOG_DATE: // %t
827 get_localtime(s->logs.accept_date.tv_sec, &tm);
828 tmplog = date2str_log(tmplog, &tm, &(s->logs.accept_date), MAX_SYSLOG_LEN - (tmplog - logline));
829 if (!tmplog)
830 goto out;
831 last_isspace = 0;
832 break;
833
834 case LOG_DATEGMT: // %T
835 get_gmtime(s->logs.accept_date.tv_sec, &tm);
836 tmplog = gmt2str_log(tmplog, &tm, MAX_SYSLOG_LEN - (tmplog - logline));
837 if (!tmplog)
838 goto out;
839 last_isspace = 0;
840 break;
841
842 case LOG_MS: // %ms
843 if ((MAX_SYSLOG_LEN - (tmplog - logline)) < 4) {
844 tmplog = NULL;
845 goto out;
846 }
847 tmplog = utoa_pad((unsigned int)s->logs.accept_date.tv_usec/1000,
848 tmplog, 4);
William Lallemand51b5dca2012-03-26 17:52:55 +0200849 if (!tmplog)
850 goto out;
William Lallemandbddd4fd2012-02-27 11:23:10 +0100851 last_isspace = 0;
William Lallemandbddd4fd2012-02-27 11:23:10 +0100852 break;
853
854 case LOG_FRONTEND: // %f
855 src = fe->id;
856 tmplog = logformat_write_string(tmplog, src, MAX_SYSLOG_LEN - (tmplog - logline), tmp);
857 if (!tmplog)
858 goto out;
William Lallemand51b5dca2012-03-26 17:52:55 +0200859 last_isspace = 0;
William Lallemandbddd4fd2012-02-27 11:23:10 +0100860 break;
861
862 case LOG_BACKEND: // %b
863 src = be->id;
864 tmplog = logformat_write_string(tmplog, src, MAX_SYSLOG_LEN - (tmplog - logline), tmp);
865 if (!tmplog)
866 goto out;
William Lallemand51b5dca2012-03-26 17:52:55 +0200867 last_isspace = 0;
William Lallemandbddd4fd2012-02-27 11:23:10 +0100868 break;
869
870 case LOG_SERVER: // %s
871 src = (char *)svid;
872 tmplog = logformat_write_string(tmplog, src, MAX_SYSLOG_LEN - (tmplog - logline), tmp);
873 if (!tmplog)
874 goto out;
875 last_isspace = 0;
876 break;
877
878 case LOG_TQ: // %Tq
879 tmplog = ltoa_o(t_request, tmplog, MAX_SYSLOG_LEN - (tmplog - logline));
880 if (!tmplog)
881 goto out;
882 last_isspace = 0;
883 break;
884
885 case LOG_TW: // %Tw
886 tmplog = ltoa_o((s->logs.t_queue >= 0) ? s->logs.t_queue - t_request : -1, tmplog, MAX_SYSLOG_LEN - (tmplog - logline));
887 if (!tmplog)
888 goto out;
889 last_isspace = 0;
890 break;
891
892 case LOG_TC: // %Tc
893 tmplog = ltoa_o((s->logs.t_connect >= 0) ? s->logs.t_connect - s->logs.t_queue : -1, tmplog, MAX_SYSLOG_LEN - (tmplog - logline));
894 if (!tmplog)
895 goto out;
896 last_isspace = 0;
897 break;
898
899 case LOG_TR: // %Tr
900 tmplog = ltoa_o((s->logs.t_data >= 0) ? s->logs.t_data - s->logs.t_connect : -1, tmplog, MAX_SYSLOG_LEN - (tmplog - logline));
901 if (!tmplog)
902 goto out;
903 last_isspace = 0;
904 break;
905
906 case LOG_TT: // %Tt
907 if (!(tolog & LW_BYTES))
908 *(tmplog++) = '+';
909 tmplog = ltoa_o(s->logs.t_close, tmplog, MAX_SYSLOG_LEN - (tmplog - logline));
910 if (!tmplog)
911 goto out;
912 last_isspace = 0;
913 break;
914
915 case LOG_STATUS: // %st
William Lallemand7f25deb2012-03-22 11:32:29 +0100916 tmplog = ltoa_o(txn->status, tmplog, MAX_SYSLOG_LEN - (tmplog - logline));
William Lallemandbddd4fd2012-02-27 11:23:10 +0100917 if (!tmplog)
918 goto out;
919 last_isspace = 0;
920 break;
921
922 case LOG_BYTES: // %B
923 if (!(tolog & LW_BYTES))
924 *(tmplog++) = '+';
925 tmplog = lltoa(s->logs.bytes_out, tmplog, MAX_SYSLOG_LEN - (tmplog - logline));
926 if (!tmplog)
927 goto out;
928 last_isspace = 0;
929 break;
930
931 case LOG_CCLIENT: // %cc
932 src = txn->cli_cookie;
933 tmplog = logformat_write_string(tmplog, src, MAX_SYSLOG_LEN - (tmplog - logline), tmp);
William Lallemand51b5dca2012-03-26 17:52:55 +0200934 if (!tmplog)
935 goto out;
William Lallemandbddd4fd2012-02-27 11:23:10 +0100936 last_isspace = 0;
937 break;
938
939 case LOG_CSERVER: // %cs
940 src = txn->srv_cookie;
941 tmplog = logformat_write_string(tmplog, src, MAX_SYSLOG_LEN - (tmplog - logline), tmp);
William Lallemand51b5dca2012-03-26 17:52:55 +0200942 if (!tmplog)
943 goto out;
William Lallemandbddd4fd2012-02-27 11:23:10 +0100944 last_isspace = 0;
945 break;
946
947 case LOG_TERMSTATE: // %ts
Willy Tarreau6580c062012-03-12 15:09:42 +0100948 LOGCHAR(sess_term_cond[(s->flags & SN_ERR_MASK) >> SN_ERR_SHIFT]);
949 LOGCHAR(sess_fin_state[(s->flags & SN_FINST_MASK) >> SN_FINST_SHIFT]);
950 *tmplog = '\0';
951 last_isspace = 0;
952 break;
William Lallemandbddd4fd2012-02-27 11:23:10 +0100953
Willy Tarreau6580c062012-03-12 15:09:42 +0100954 case LOG_TERMSTATE_CK: // %tsc, same as TS with cookie state (for mode HTTP)
William Lallemandbddd4fd2012-02-27 11:23:10 +0100955 LOGCHAR(sess_term_cond[(s->flags & SN_ERR_MASK) >> SN_ERR_SHIFT]);
956 LOGCHAR(sess_fin_state[(s->flags & SN_FINST_MASK) >> SN_FINST_SHIFT]);
Willy Tarreau6580c062012-03-12 15:09:42 +0100957 LOGCHAR((be->options & PR_O_COOK_ANY) ? sess_cookie[(txn->flags & TX_CK_MASK) >> TX_CK_SHIFT] : '-');
958 LOGCHAR((be->options & PR_O_COOK_ANY) ? sess_set_cookie[(txn->flags & TX_SCK_MASK) >> TX_SCK_SHIFT] : '-');
William Lallemandbddd4fd2012-02-27 11:23:10 +0100959 *tmplog = '\0';
960 last_isspace = 0;
961 break;
962
963 case LOG_ACTCONN: // %ac
964 tmplog = ltoa_o(actconn, tmplog, MAX_SYSLOG_LEN - (tmplog - logline));
965 if (!tmplog)
966 goto out;
967 last_isspace = 0;
968 break;
969
970 case LOG_FECONN: // %fc
971 tmplog = ltoa_o(fe->feconn, tmplog, MAX_SYSLOG_LEN - (tmplog - logline));
972 if (!tmplog)
973 goto out;
974 last_isspace = 0;
975 break;
976
977 case LOG_BECONN: // %bc
978 tmplog = ltoa_o(be->beconn, tmplog, MAX_SYSLOG_LEN - (tmplog - logline));
979 if (!tmplog)
980 goto out;
981 last_isspace = 0;
982 break;
983
984 case LOG_SRVCONN: // %sc
985 tmplog = ultoa_o(target_srv(&s->target) ? target_srv(&s->target)->cur_sess : 0, tmplog, MAX_SYSLOG_LEN - (tmplog - logline));
986 if (!tmplog)
987 goto out;
988 last_isspace = 0;
989 break;
990
991 case LOG_RETRIES: // %rq
992 if (s->flags & SN_REDISP)
993 *(tmplog++) = '+';
994 tmplog = ltoa_o((s->req->cons->conn_retries>0)?(be->conn_retries - s->req->cons->conn_retries):be->conn_retries, tmplog, MAX_SYSLOG_LEN - (tmplog - logline));
William Lallemand51b5dca2012-03-26 17:52:55 +0200995 if (!tmplog)
996 goto out;
William Lallemandbddd4fd2012-02-27 11:23:10 +0100997 last_isspace = 0;
998 break;
999
1000 case LOG_SRVQUEUE: // %sq
1001 tmplog = ltoa_o(s->logs.srv_queue_size, tmplog, MAX_SYSLOG_LEN - (tmplog - logline));
1002 if (!tmplog)
1003 goto out;
1004 last_isspace = 0;
1005 break;
1006
1007 case LOG_BCKQUEUE: // %bq
1008 tmplog = ltoa_o(s->logs.prx_queue_size, tmplog, MAX_SYSLOG_LEN - (tmplog - logline));
1009 if (!tmplog)
1010 goto out;
1011 last_isspace = 0;
1012 break;
1013
1014 case LOG_HDRREQUEST: // %hr
1015 /* request header */
1016 if (fe->to_log & LW_REQHDR && txn->req.cap) {
1017 if (tmp->options & LOG_OPT_QUOTE)
1018 LOGCHAR('"');
1019 LOGCHAR('{');
1020 for (hdr = 0; hdr < fe->nb_req_cap; hdr++) {
1021 if (hdr)
1022 LOGCHAR('|');
William Lallemand51b5dca2012-03-26 17:52:55 +02001023 if (txn->req.cap[hdr] != NULL) {
William Lallemandbddd4fd2012-02-27 11:23:10 +01001024 tmplog = encode_string(tmplog, logline + MAX_SYSLOG_LEN,
1025 '#', hdr_encode_map, txn->req.cap[hdr]);
William Lallemand51b5dca2012-03-26 17:52:55 +02001026 if (*tmplog != '\0')
1027 goto out;
1028 }
William Lallemandbddd4fd2012-02-27 11:23:10 +01001029 }
1030 LOGCHAR('}');
William Lallemand51b5dca2012-03-26 17:52:55 +02001031 if (tmp->options & LOG_OPT_QUOTE)
1032 LOGCHAR('"');
William Lallemandbddd4fd2012-02-27 11:23:10 +01001033 last_isspace = 0;
1034 }
1035 *tmplog = '\0';
1036 break;
1037
1038 case LOG_HDRREQUESTLIST: // %hrl
1039 /* request header list */
1040 if (fe->to_log & LW_REQHDR && txn->req.cap) {
1041 for (hdr = 0; hdr < fe->nb_req_cap; hdr++) {
1042 if (hdr > 0)
1043 LOGCHAR(' ');
1044 if (tmp->options & LOG_OPT_QUOTE)
1045 LOGCHAR('"');
1046 if (txn->req.cap[hdr] != NULL) {
1047 tmplog = encode_string(tmplog, logline + MAX_SYSLOG_LEN,
1048 '#', hdr_encode_map, txn->req.cap[hdr]);
William Lallemand51b5dca2012-03-26 17:52:55 +02001049 if (*tmplog != '\0')
1050 goto out;
1051
William Lallemandbddd4fd2012-02-27 11:23:10 +01001052 } else if (!(tmp->options & LOG_OPT_QUOTE))
1053 LOGCHAR('-');
1054 if (tmp->options & LOG_OPT_QUOTE)
1055 LOGCHAR('"');
1056 *tmplog = '\0';
1057 last_isspace = 0;
1058 }
1059 }
1060 break;
Willy Tarreaubaaee002006-06-26 02:48:02 +02001061
William Lallemandbddd4fd2012-02-27 11:23:10 +01001062 case LOG_HDRRESPONS: // %hs
1063 /* response header */
1064 if (fe->to_log & LW_RSPHDR &&
1065 txn->rsp.cap) {
1066 if (tmp->options & LOG_OPT_QUOTE)
1067 LOGCHAR('"');
1068 LOGCHAR('{');
1069 for (hdr = 0; hdr < fe->nb_rsp_cap; hdr++) {
1070 if (hdr)
1071 LOGCHAR('|');
William Lallemand51b5dca2012-03-26 17:52:55 +02001072 if (txn->rsp.cap[hdr] != NULL) {
William Lallemandbddd4fd2012-02-27 11:23:10 +01001073 tmplog = encode_string(tmplog, logline + MAX_SYSLOG_LEN,
1074 '#', hdr_encode_map, txn->rsp.cap[hdr]);
William Lallemand51b5dca2012-03-26 17:52:55 +02001075 if (*tmplog != '\0')
1076 goto out;
1077 }
William Lallemandbddd4fd2012-02-27 11:23:10 +01001078 }
1079 LOGCHAR('}');
1080 last_isspace = 0;
1081 if (tmp->options & LOG_OPT_QUOTE)
1082 LOGCHAR('"');
1083 }
1084 *tmplog = '\0';
1085 break;
1086
1087 case LOG_HDRRESPONSLIST: // %hsl
1088 /* response header list */
1089 if (fe->to_log & LW_RSPHDR && txn->rsp.cap) {
1090 for (hdr = 0; hdr < fe->nb_rsp_cap; hdr++) {
1091 if (hdr > 0)
1092 LOGCHAR(' ');
1093 if (tmp->options & LOG_OPT_QUOTE)
1094 LOGCHAR('"');
1095 if (txn->rsp.cap[hdr] != NULL) {
1096 tmplog = encode_string(tmplog, logline + MAX_SYSLOG_LEN,
1097 '#', hdr_encode_map, txn->rsp.cap[hdr]);
William Lallemand51b5dca2012-03-26 17:52:55 +02001098 if (*tmplog != '\0')
1099 goto out;
William Lallemandbddd4fd2012-02-27 11:23:10 +01001100 } else if (!(tmp->options & LOG_OPT_QUOTE))
1101 LOGCHAR('-');
1102 if (tmp->options & LOG_OPT_QUOTE)
1103 LOGCHAR('"');
1104 *tmplog = '\0';
1105 last_isspace = 0;
1106 }
1107 }
1108 break;
1109
1110 case LOG_REQ: // %r
1111 /* Request */
1112 if (tmp->options & LOG_OPT_QUOTE)
1113 LOGCHAR('"');
1114 uri = txn->uri ? txn->uri : "<BADREQ>";
1115 tmplog = encode_string(tmplog, logline + MAX_SYSLOG_LEN,
1116 '#', url_encode_map, uri);
William Lallemand51b5dca2012-03-26 17:52:55 +02001117 if (*tmplog != '\0')
1118 goto out;
William Lallemandbddd4fd2012-02-27 11:23:10 +01001119 if (tmp->options & LOG_OPT_QUOTE)
1120 LOGCHAR('"');
1121 *tmplog = '\0';
1122 last_isspace = 0;
1123 break;
1124 }
1125 }
1126
1127out:
1128
1129 if (tmplog == NULL) // if previous error
1130 tmplog = logline + MAX_SYSLOG_LEN - 1;
1131
1132 __send_log(prx_log, level, logline, tmplog - logline + 1);
Willy Tarreaubaaee002006-06-26 02:48:02 +02001133 s->logs.logwait = 0;
William Lallemandbddd4fd2012-02-27 11:23:10 +01001134
Willy Tarreaubaaee002006-06-26 02:48:02 +02001135}
1136
Willy Tarreaubaaee002006-06-26 02:48:02 +02001137
William Lallemandbddd4fd2012-02-27 11:23:10 +01001138
1139
1140
Willy Tarreaubaaee002006-06-26 02:48:02 +02001141/*
1142 * Local variables:
1143 * c-indent-level: 8
1144 * c-basic-offset: 8
1145 * End:
1146 */