blob: 3093ccea3b7e8a631a801c56095491a280d6b2c3 [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 Tarreau8a3f52f2012-12-20 21:23:42 +010013#include <ctype.h>
Willy Tarreauc8f24f82007-11-30 18:38:35 +010014#include <fcntl.h>
Willy Tarreaubaaee002006-06-26 02:48:02 +020015#include <stdarg.h>
16#include <stdio.h>
17#include <stdlib.h>
18#include <string.h>
19#include <syslog.h>
20#include <time.h>
21#include <unistd.h>
Robert Tsai81ae1952007-12-05 10:47:29 +010022#include <errno.h>
Willy Tarreaubaaee002006-06-26 02:48:02 +020023
24#include <sys/time.h>
Willy Tarreau077edcb2016-08-10 18:30:56 +020025#include <sys/uio.h>
Willy Tarreaubaaee002006-06-26 02:48:02 +020026
Willy Tarreaue3ba5f02006-06-29 18:54:54 +020027#include <common/config.h>
Willy Tarreaud6d06902009-08-19 11:22:33 +020028#include <common/compat.h>
Willy Tarreau0108d902018-11-25 19:14:37 +010029#include <common/initcall.h>
Willy Tarreau2dd0d472006-06-29 17:53:05 +020030#include <common/standard.h>
Willy Tarreaufb278672006-10-15 15:38:50 +020031#include <common/time.h>
Willy Tarreaubaaee002006-06-26 02:48:02 +020032
Christopher Fauletc1b730a2017-10-24 12:00:51 +020033#include <types/cli.h>
Willy Tarreaubaaee002006-06-26 02:48:02 +020034#include <types/global.h>
William Lallemand723b73a2012-02-08 16:37:49 +010035#include <types/log.h>
Willy Tarreauec6c5df2008-07-15 00:22:45 +020036
Christopher Fauletc1b730a2017-10-24 12:00:51 +020037#include <proto/applet.h>
38#include <proto/cli.h>
William Lallemand5f232402012-04-05 18:02:55 +020039#include <proto/frontend.h>
Willy Tarreau35b51c62018-09-10 15:38:55 +020040#include <proto/h1.h>
Willy Tarreauec6c5df2008-07-15 00:22:45 +020041#include <proto/log.h>
Willy Tarreauc8368452012-12-21 00:09:23 +010042#include <proto/sample.h>
Willy Tarreaufb0afa72015-04-03 14:46:27 +020043#include <proto/stream.h>
Willy Tarreau827aee92011-03-10 16:55:02 +010044#include <proto/stream_interface.h>
Willy Tarreau773d65f2012-10-12 14:56:11 +020045#ifdef USE_OPENSSL
46#include <proto/ssl_sock.h>
47#endif
Willy Tarreaubaaee002006-06-26 02:48:02 +020048
Dragan Dosen43885c72015-10-01 13:18:13 +020049struct log_fmt {
50 char *name;
51 struct {
Willy Tarreau83061a82018-07-13 11:56:34 +020052 struct buffer sep1; /* first pid separator */
53 struct buffer sep2; /* second pid separator */
Dragan Dosen43885c72015-10-01 13:18:13 +020054 } pid;
55};
56
57static const struct log_fmt log_formats[LOG_FORMATS] = {
58 [LOG_FORMAT_RFC3164] = {
59 .name = "rfc3164",
60 .pid = {
Willy Tarreau843b7cb2018-07-13 10:54:26 +020061 .sep1 = { .area = "[", .data = 1 },
62 .sep2 = { .area = "]: ", .data = 3 }
Dragan Dosen43885c72015-10-01 13:18:13 +020063 }
64 },
65 [LOG_FORMAT_RFC5424] = {
66 .name = "rfc5424",
67 .pid = {
Willy Tarreau843b7cb2018-07-13 10:54:26 +020068 .sep1 = { .area = " ", .data = 1 },
69 .sep2 = { .area = " - ", .data = 3 }
Dragan Dosen43885c72015-10-01 13:18:13 +020070 }
Willy Tarreaue8746a02018-11-12 08:45:00 +010071 },
72 [LOG_FORMAT_SHORT] = {
73 .name = "short",
74 .pid = {
75 .sep1 = { .area = "", .data = 0 },
76 .sep2 = { .area = " ", .data = 1 },
77 }
78 },
Willy Tarreauc1b06452018-11-12 11:57:56 +010079 [LOG_FORMAT_RAW] = {
80 .name = "raw",
81 .pid = {
82 .sep1 = { .area = "", .data = 0 },
83 .sep2 = { .area = "", .data = 0 },
84 }
85 },
Dragan Dosen1322d092015-09-22 16:05:32 +020086};
87
Dragan Dosen835b9212016-02-12 13:23:03 +010088#define FD_SETS_ARE_BITFIELDS
89#ifdef FD_SETS_ARE_BITFIELDS
90/*
91 * This map is used with all the FD_* macros to check whether a particular bit
92 * is set or not. Each bit represents an ACSII code. FD_SET() sets those bytes
93 * which should be escaped. When FD_ISSET() returns non-zero, it means that the
94 * byte should be escaped. Be careful to always pass bytes from 0 to 255
95 * exclusively to the macros.
96 */
97fd_set rfc5424_escape_map[(sizeof(fd_set) > (256/8)) ? 1 : ((256/8) / sizeof(fd_set))];
Willy Tarreaue10cd482018-09-10 18:16:53 +020098fd_set hdr_encode_map[(sizeof(fd_set) > (256/8)) ? 1 : ((256/8) / sizeof(fd_set))];
99fd_set url_encode_map[(sizeof(fd_set) > (256/8)) ? 1 : ((256/8) / sizeof(fd_set))];
100fd_set http_encode_map[(sizeof(fd_set) > (256/8)) ? 1 : ((256/8) / sizeof(fd_set))];
Dragan Dosen835b9212016-02-12 13:23:03 +0100101
102#else
103#error "Check if your OS uses bitfields for fd_sets"
104#endif
105
Willy Tarreaubaaee002006-06-26 02:48:02 +0200106const char *log_facilities[NB_LOG_FACILITIES] = {
107 "kern", "user", "mail", "daemon",
108 "auth", "syslog", "lpr", "news",
109 "uucp", "cron", "auth2", "ftp",
110 "ntp", "audit", "alert", "cron2",
111 "local0", "local1", "local2", "local3",
112 "local4", "local5", "local6", "local7"
113};
114
Willy Tarreaubaaee002006-06-26 02:48:02 +0200115const char *log_levels[NB_LOG_LEVELS] = {
116 "emerg", "alert", "crit", "err",
117 "warning", "notice", "info", "debug"
118};
119
Willy Tarreau570f2212013-06-10 16:42:09 +0200120const char sess_term_cond[16] = "-LcCsSPRIDKUIIII"; /* normal, Local, CliTo, CliErr, SrvTo, SrvErr, PxErr, Resource, Internal, Down, Killed, Up, -- */
Willy Tarreaub8750a82006-09-03 09:56:00 +0200121const char sess_fin_state[8] = "-RCHDLQT"; /* cliRequest, srvConnect, srvHeader, Data, Last, Queue, Tarpit */
Willy Tarreaubaaee002006-06-26 02:48:02 +0200122
William Lallemand723b73a2012-02-08 16:37:49 +0100123
124/* log_format */
125struct logformat_type {
126 char *name;
127 int type;
William Lallemandbddd4fd2012-02-27 11:23:10 +0100128 int mode;
William Lallemand5e19a282012-04-02 16:22:10 +0200129 int lw; /* logwait bitsfield */
William Lallemandb7ff6a32012-03-02 14:35:21 +0100130 int (*config_callback)(struct logformat_node *node, struct proxy *curproxy);
Willy Tarreau2beef582012-12-20 17:22:52 +0100131 const char *replace_by; /* new option to use instead of old one */
William Lallemand723b73a2012-02-08 16:37:49 +0100132};
133
William Lallemandb7ff6a32012-03-02 14:35:21 +0100134int prepare_addrsource(struct logformat_node *node, struct proxy *curproxy);
135
William Lallemand723b73a2012-02-08 16:37:49 +0100136/* log_format variable names */
137static const struct logformat_type logformat_keywords[] = {
William Lallemand5e19a282012-04-02 16:22:10 +0200138 { "o", LOG_FMT_GLOBAL, PR_MODE_TCP, 0, NULL }, /* global option */
Willy Tarreau2beef582012-12-20 17:22:52 +0100139
140 /* please keep these lines sorted ! */
141 { "B", LOG_FMT_BYTES, PR_MODE_TCP, LW_BYTES, NULL }, /* bytes from server to client */
142 { "CC", LOG_FMT_CCLIENT, PR_MODE_HTTP, LW_REQHDR, NULL }, /* client cookie */
143 { "CS", LOG_FMT_CSERVER, PR_MODE_HTTP, LW_RSPHDR, NULL }, /* server cookie */
144 { "H", LOG_FMT_HOSTNAME, PR_MODE_TCP, LW_INIT, NULL }, /* Hostname */
145 { "ID", LOG_FMT_UNIQUEID, PR_MODE_HTTP, LW_BYTES, NULL }, /* Unique ID */
Willy Tarreau4bf99632014-06-13 12:21:40 +0200146 { "ST", LOG_FMT_STATUS, PR_MODE_TCP, LW_RESP, NULL }, /* status code */
William Lallemand5e19a282012-04-02 16:22:10 +0200147 { "T", LOG_FMT_DATEGMT, PR_MODE_TCP, LW_INIT, NULL }, /* date GMT */
Thierry FOURNIER / OZON.IO4cac3592016-07-28 17:19:45 +0200148 { "Ta", LOG_FMT_Ta, PR_MODE_HTTP, LW_BYTES, NULL }, /* Time active (tr to end) */
Willy Tarreau2beef582012-12-20 17:22:52 +0100149 { "Tc", LOG_FMT_TC, PR_MODE_TCP, LW_BYTES, NULL }, /* Tc */
Thierry FOURNIER / OZON.IO4cac3592016-07-28 17:19:45 +0200150 { "Th", LOG_FMT_Th, PR_MODE_TCP, LW_BYTES, NULL }, /* Time handshake */
151 { "Ti", LOG_FMT_Ti, PR_MODE_HTTP, LW_BYTES, NULL }, /* Time idle */
152 { "Tl", LOG_FMT_DATELOCAL, PR_MODE_TCP, LW_INIT, NULL }, /* date local timezone */
153 { "Tq", LOG_FMT_TQ, PR_MODE_HTTP, LW_BYTES, NULL }, /* Tq=Th+Ti+TR */
154 { "Tr", LOG_FMT_Tr, PR_MODE_HTTP, LW_BYTES, NULL }, /* Tr */
155 { "TR", LOG_FMT_TR, PR_MODE_HTTP, LW_BYTES, NULL }, /* Time to receive a valid request */
Willy Tarreau27b639d2016-05-17 17:55:27 +0200156 { "Td", LOG_FMT_TD, PR_MODE_TCP, LW_BYTES, NULL }, /* Td = Tt - (Tq + Tw + Tc + Tr) */
Willy Tarreau2beef582012-12-20 17:22:52 +0100157 { "Ts", LOG_FMT_TS, PR_MODE_TCP, LW_INIT, NULL }, /* timestamp GMT */
William Lallemand5e19a282012-04-02 16:22:10 +0200158 { "Tt", LOG_FMT_TT, PR_MODE_TCP, LW_BYTES, NULL }, /* Tt */
Willy Tarreau2beef582012-12-20 17:22:52 +0100159 { "Tw", LOG_FMT_TW, PR_MODE_TCP, LW_BYTES, NULL }, /* Tw */
160 { "U", LOG_FMT_BYTES_UP, PR_MODE_TCP, LW_BYTES, NULL }, /* bytes from client to server */
William Lallemand5e19a282012-04-02 16:22:10 +0200161 { "ac", LOG_FMT_ACTCONN, PR_MODE_TCP, LW_BYTES, NULL }, /* actconn */
Willy Tarreau2beef582012-12-20 17:22:52 +0100162 { "b", LOG_FMT_BACKEND, PR_MODE_TCP, LW_INIT, NULL }, /* backend */
William Lallemand5e19a282012-04-02 16:22:10 +0200163 { "bc", LOG_FMT_BECONN, PR_MODE_TCP, LW_BYTES, NULL }, /* beconn */
Willy Tarreau2beef582012-12-20 17:22:52 +0100164 { "bi", LOG_FMT_BACKENDIP, PR_MODE_TCP, LW_BCKIP, prepare_addrsource }, /* backend source ip */
165 { "bp", LOG_FMT_BACKENDPORT, PR_MODE_TCP, LW_BCKIP, prepare_addrsource }, /* backend source port */
William Lallemand5e19a282012-04-02 16:22:10 +0200166 { "bq", LOG_FMT_BCKQUEUE, PR_MODE_TCP, LW_BYTES, NULL }, /* backend_queue */
Willy Tarreaud02286d2017-06-23 11:23:43 +0200167 { "ci", LOG_FMT_CLIENTIP, PR_MODE_TCP, LW_CLIP | LW_XPRT, NULL }, /* client ip */
168 { "cp", LOG_FMT_CLIENTPORT, PR_MODE_TCP, LW_CLIP | LW_XPRT, NULL }, /* client port */
Willy Tarreau2beef582012-12-20 17:22:52 +0100169 { "f", LOG_FMT_FRONTEND, PR_MODE_TCP, LW_INIT, NULL }, /* frontend */
170 { "fc", LOG_FMT_FECONN, PR_MODE_TCP, LW_BYTES, NULL }, /* feconn */
Willy Tarreaud02286d2017-06-23 11:23:43 +0200171 { "fi", LOG_FMT_FRONTENDIP, PR_MODE_TCP, LW_FRTIP | LW_XPRT, NULL }, /* frontend ip */
172 { "fp", LOG_FMT_FRONTENDPORT, PR_MODE_TCP, LW_FRTIP | LW_XPRT, NULL }, /* frontend port */
Willy Tarreau2beef582012-12-20 17:22:52 +0100173 { "ft", LOG_FMT_FRONTEND_XPRT, PR_MODE_TCP, LW_INIT, NULL }, /* frontend with transport mode */
Willy Tarreaud9ed3d22014-06-13 12:23:06 +0200174 { "hr", LOG_FMT_HDRREQUEST, PR_MODE_TCP, LW_REQHDR, NULL }, /* header request */
175 { "hrl", LOG_FMT_HDRREQUESTLIST, PR_MODE_TCP, LW_REQHDR, NULL }, /* header request list */
176 { "hs", LOG_FMT_HDRRESPONS, PR_MODE_TCP, LW_RSPHDR, NULL }, /* header response */
177 { "hsl", LOG_FMT_HDRRESPONSLIST, PR_MODE_TCP, LW_RSPHDR, NULL }, /* header response list */
Andrew Hayworth0ebc55f2015-04-27 21:37:03 +0000178 { "HM", LOG_FMT_HTTP_METHOD, PR_MODE_HTTP, LW_REQ, NULL }, /* HTTP method */
179 { "HP", LOG_FMT_HTTP_PATH, PR_MODE_HTTP, LW_REQ, NULL }, /* HTTP path */
Andrew Hayworthe63ac872015-07-31 16:14:16 +0000180 { "HQ", LOG_FMT_HTTP_QUERY, PR_MODE_HTTP, LW_REQ, NULL }, /* HTTP query */
Andrew Hayworth0ebc55f2015-04-27 21:37:03 +0000181 { "HU", LOG_FMT_HTTP_URI, PR_MODE_HTTP, LW_REQ, NULL }, /* HTTP full URI */
182 { "HV", LOG_FMT_HTTP_VERSION, PR_MODE_HTTP, LW_REQ, NULL }, /* HTTP version */
Willy Tarreau7346acb2014-08-28 15:03:15 +0200183 { "lc", LOG_FMT_LOGCNT, PR_MODE_TCP, LW_INIT, NULL }, /* log counter */
Willy Tarreau2beef582012-12-20 17:22:52 +0100184 { "ms", LOG_FMT_MS, PR_MODE_TCP, LW_INIT, NULL }, /* accept date millisecond */
William Lallemand5e19a282012-04-02 16:22:10 +0200185 { "pid", LOG_FMT_PID, PR_MODE_TCP, LW_INIT, NULL }, /* log pid */
Willy Tarreau2beef582012-12-20 17:22:52 +0100186 { "r", LOG_FMT_REQ, PR_MODE_HTTP, LW_REQ, NULL }, /* request */
187 { "rc", LOG_FMT_RETRIES, PR_MODE_TCP, LW_BYTES, NULL }, /* retries */
Willy Tarreau1f0da242014-01-25 11:01:50 +0100188 { "rt", LOG_FMT_COUNTER, PR_MODE_TCP, LW_REQ, NULL }, /* request counter (HTTP or TCP session) */
Willy Tarreau2beef582012-12-20 17:22:52 +0100189 { "s", LOG_FMT_SERVER, PR_MODE_TCP, LW_SVID, NULL }, /* server */
190 { "sc", LOG_FMT_SRVCONN, PR_MODE_TCP, LW_BYTES, NULL }, /* srv_conn */
191 { "si", LOG_FMT_SERVERIP, PR_MODE_TCP, LW_SVIP, NULL }, /* server destination ip */
192 { "sp", LOG_FMT_SERVERPORT, PR_MODE_TCP, LW_SVIP, NULL }, /* server destination port */
193 { "sq", LOG_FMT_SRVQUEUE, PR_MODE_TCP, LW_BYTES, NULL }, /* srv_queue */
Willy Tarreauffc3fcd2012-10-12 20:17:54 +0200194 { "sslc", LOG_FMT_SSL_CIPHER, PR_MODE_TCP, LW_XPRT, NULL }, /* client-side SSL ciphers */
195 { "sslv", LOG_FMT_SSL_VERSION, PR_MODE_TCP, LW_XPRT, NULL }, /* client-side SSL protocol version */
Willy Tarreau2beef582012-12-20 17:22:52 +0100196 { "t", LOG_FMT_DATE, PR_MODE_TCP, LW_INIT, NULL }, /* date */
Thierry FOURNIER / OZON.IO4cac3592016-07-28 17:19:45 +0200197 { "tr", LOG_FMT_tr, PR_MODE_HTTP, LW_INIT, NULL }, /* date of start of request */
198 { "trg",LOG_FMT_trg, PR_MODE_HTTP, LW_INIT, NULL }, /* date of start of request, GMT */
199 { "trl",LOG_FMT_trl, PR_MODE_HTTP, LW_INIT, NULL }, /* date of start of request, local */
Willy Tarreau2beef582012-12-20 17:22:52 +0100200 { "ts", LOG_FMT_TERMSTATE, PR_MODE_TCP, LW_BYTES, NULL },/* termination state */
201 { "tsc", LOG_FMT_TERMSTATE_CK, PR_MODE_TCP, LW_INIT, NULL },/* termination state */
202
203 /* The following tags are deprecated and will be removed soon */
204 { "Bi", LOG_FMT_BACKENDIP, PR_MODE_TCP, LW_BCKIP, prepare_addrsource, "bi" }, /* backend source ip */
205 { "Bp", LOG_FMT_BACKENDPORT, PR_MODE_TCP, LW_BCKIP, prepare_addrsource, "bp" }, /* backend source port */
Willy Tarreaud02286d2017-06-23 11:23:43 +0200206 { "Ci", LOG_FMT_CLIENTIP, PR_MODE_TCP, LW_CLIP | LW_XPRT, NULL, "ci" }, /* client ip */
207 { "Cp", LOG_FMT_CLIENTPORT, PR_MODE_TCP, LW_CLIP | LW_XPRT, NULL, "cp" }, /* client port */
208 { "Fi", LOG_FMT_FRONTENDIP, PR_MODE_TCP, LW_FRTIP | LW_XPRT, NULL, "fi" }, /* frontend ip */
209 { "Fp", LOG_FMT_FRONTENDPORT, PR_MODE_TCP, LW_FRTIP | LW_XPRT, NULL, "fp" }, /* frontend port */
Willy Tarreau2beef582012-12-20 17:22:52 +0100210 { "Si", LOG_FMT_SERVERIP, PR_MODE_TCP, LW_SVIP, NULL, "si" }, /* server destination ip */
211 { "Sp", LOG_FMT_SERVERPORT, PR_MODE_TCP, LW_SVIP, NULL, "sp" }, /* server destination port */
212 { "cc", LOG_FMT_CCLIENT, PR_MODE_HTTP, LW_REQHDR, NULL, "CC" }, /* client cookie */
213 { "cs", LOG_FMT_CSERVER, PR_MODE_HTTP, LW_RSPHDR, NULL, "CS" }, /* server cookie */
214 { "st", LOG_FMT_STATUS, PR_MODE_HTTP, LW_RESP, NULL, "ST" }, /* status code */
William Lallemand5e19a282012-04-02 16:22:10 +0200215 { 0, 0, 0, 0, NULL }
William Lallemand723b73a2012-02-08 16:37:49 +0100216};
217
Thierry FOURNIER / OZON.IO4cac3592016-07-28 17:19:45 +0200218char default_http_log_format[] = "%ci:%cp [%tr] %ft %b/%s %TR/%Tw/%Tc/%Tr/%Ta %ST %B %CC %CS %tsc %ac/%fc/%bc/%sc/%rc %sq/%bq %hr %hs %{+Q}r"; // default format
219char clf_http_log_format[] = "%{+Q}o %{-Q}ci - - [%trg] %r %ST %B \"\" \"\" %cp %ms %ft %b %s %TR %Tw %Tc %Tr %Ta %tsc %ac %fc %bc %sc %rc %sq %bq %CC %CS %hrl %hsl";
Willy Tarreau2beef582012-12-20 17:22:52 +0100220char default_tcp_log_format[] = "%ci:%cp [%t] %ft %b/%s %Tw/%Tc/%Tt %B %ts %ac/%fc/%bc/%sc/%rc %sq/%bq";
William Lallemand723b73a2012-02-08 16:37:49 +0100221char *log_format = NULL;
222
Dragan Dosen0b85ece2015-09-25 19:17:44 +0200223/* Default string used for structured-data part in RFC5424 formatted
224 * syslog messages.
225 */
226char default_rfc5424_sd_log_format[] = "- ";
Dragan Dosen1322d092015-09-22 16:05:32 +0200227
Willy Tarreau13ef7732018-11-12 07:25:28 +0100228/* total number of dropped logs */
229unsigned int dropped_logs = 0;
230
Dragan Dosen1322d092015-09-22 16:05:32 +0200231/* This is a global syslog header, common to all outgoing messages in
232 * RFC3164 format. It begins with time-based part and is updated by
233 * update_log_hdr().
Dragan Dosen59cee972015-09-19 22:09:02 +0200234 */
Christopher Fauletf8188c62017-06-02 16:20:16 +0200235THREAD_LOCAL char *logheader = NULL;
Dragan Dosen59cee972015-09-19 22:09:02 +0200236
Dragan Dosen1322d092015-09-22 16:05:32 +0200237/* This is a global syslog header for messages in RFC5424 format. It is
238 * updated by update_log_hdr_rfc5424().
239 */
Christopher Fauletf8188c62017-06-02 16:20:16 +0200240THREAD_LOCAL char *logheader_rfc5424 = NULL;
Dragan Dosen1322d092015-09-22 16:05:32 +0200241
Dragan Dosen59cee972015-09-19 22:09:02 +0200242/* This is a global syslog message buffer, common to all outgoing
243 * messages. It contains only the data part.
Willy Tarreaub1a2faf2012-03-19 16:51:53 +0100244 */
Christopher Fauletf8188c62017-06-02 16:20:16 +0200245THREAD_LOCAL char *logline = NULL;
Willy Tarreaub1a2faf2012-03-19 16:51:53 +0100246
Dragan Dosen0b85ece2015-09-25 19:17:44 +0200247/* A global syslog message buffer, common to all RFC5424 syslog messages.
248 * Currently, it is used for generating the structured-data part.
249 */
Christopher Fauletf8188c62017-06-02 16:20:16 +0200250THREAD_LOCAL char *logline_rfc5424 = NULL;
Dragan Dosen0b85ece2015-09-25 19:17:44 +0200251
Christopher Fauletd4696382017-10-24 11:44:05 +0200252/* A global buffer used to store all startup alerts/warnings. It will then be
253 * retrieve on the CLI. */
Christopher Fauletf8188c62017-06-02 16:20:16 +0200254static THREAD_LOCAL char *startup_logs = NULL;
Christopher Fauletd4696382017-10-24 11:44:05 +0200255
William Lallemand723b73a2012-02-08 16:37:49 +0100256struct logformat_var_args {
257 char *name;
258 int mask;
259};
260
261struct logformat_var_args var_args_list[] = {
262// global
263 { "M", LOG_OPT_MANDATORY },
264 { "Q", LOG_OPT_QUOTE },
William Lallemand5f232402012-04-05 18:02:55 +0200265 { "X", LOG_OPT_HEXA },
Dragan Dosen835b9212016-02-12 13:23:03 +0100266 { "E", LOG_OPT_ESC },
William Lallemand723b73a2012-02-08 16:37:49 +0100267 { 0, 0 }
268};
269
Willy Tarreaub1f3af22013-04-12 18:30:32 +0200270/* return the name of the directive used in the current proxy for which we're
271 * currently parsing a header, when it is known.
272 */
273static inline const char *fmt_directive(const struct proxy *curproxy)
274{
Willy Tarreaubf0addb2013-12-02 12:24:54 +0100275 switch (curproxy->conf.args.ctx) {
Willy Tarreau53e1a6d2015-07-09 11:20:00 +0200276 case ARGC_ACL:
277 return "acl";
278 case ARGC_STK:
279 return "stick";
280 case ARGC_TRK:
281 return "track-sc";
282 case ARGC_LOG:
283 return "log-format";
Dragan Dosen0b85ece2015-09-25 19:17:44 +0200284 case ARGC_LOGSD:
285 return "log-format-sd";
Willy Tarreaubf0addb2013-12-02 12:24:54 +0100286 case ARGC_HRQ:
Thierry FOURNIER1c0054f2013-11-20 15:09:52 +0100287 return "http-request";
Willy Tarreaubf0addb2013-12-02 12:24:54 +0100288 case ARGC_HRS:
Thierry FOURNIER1c0054f2013-11-20 15:09:52 +0100289 return "http-response";
Willy Tarreau53e1a6d2015-07-09 11:20:00 +0200290 case ARGC_UIF:
291 return "unique-id-format";
Thierry FOURNIERd18cd0f2013-11-29 12:15:45 +0100292 case ARGC_RDR:
Willy Tarreau53e1a6d2015-07-09 11:20:00 +0200293 return "redirect";
294 case ARGC_CAP:
295 return "capture";
Willy Tarreau28d976d2015-07-09 11:39:33 +0200296 case ARGC_SRV:
297 return "server";
Christopher Fauletf7e4e7e2016-10-27 22:29:49 +0200298 case ARGC_SPOE:
299 return "spoe-message";
Thierry FOURNIER / OZON.IO4ed1c952016-11-24 23:57:54 +0100300 case ARGC_UBK:
301 return "use_backend";
Willy Tarreaubf0addb2013-12-02 12:24:54 +0100302 default:
Willy Tarreau53e1a6d2015-07-09 11:20:00 +0200303 return "undefined(please report this bug)"; /* must never happen */
Willy Tarreaubf0addb2013-12-02 12:24:54 +0100304 }
Willy Tarreaub1f3af22013-04-12 18:30:32 +0200305}
306
William Lallemand723b73a2012-02-08 16:37:49 +0100307/*
William Lallemandb7ff6a32012-03-02 14:35:21 +0100308 * callback used to configure addr source retrieval
309 */
310int prepare_addrsource(struct logformat_node *node, struct proxy *curproxy)
311{
312 curproxy->options2 |= PR_O2_SRC_ADDR;
313
314 return 0;
315}
316
317
318/*
Thierry FOURNIER / OZON.IObca46f02016-11-22 23:13:04 +0100319 * Parse args in a logformat_var. Returns 0 in error
320 * case, otherwise, it returns 1.
William Lallemand723b73a2012-02-08 16:37:49 +0100321 */
Thierry FOURNIER / OZON.IO8a4e4422016-11-23 00:41:28 +0100322int parse_logformat_var_args(char *args, struct logformat_node *node, char **err)
William Lallemand723b73a2012-02-08 16:37:49 +0100323{
324 int i = 0;
325 int end = 0;
326 int flags = 0; // 1 = + 2 = -
327 char *sp = NULL; // start pointer
328
Thierry FOURNIER / OZON.IO8a4e4422016-11-23 00:41:28 +0100329 if (args == NULL) {
330 memprintf(err, "internal error: parse_logformat_var_args() expects non null 'args'");
Thierry FOURNIER / OZON.IObca46f02016-11-22 23:13:04 +0100331 return 0;
Thierry FOURNIER / OZON.IO8a4e4422016-11-23 00:41:28 +0100332 }
William Lallemand723b73a2012-02-08 16:37:49 +0100333
334 while (1) {
335 if (*args == '\0')
336 end = 1;
337
338 if (*args == '+') {
339 // add flag
340 sp = args + 1;
341 flags = 1;
342 }
343 if (*args == '-') {
344 // delete flag
345 sp = args + 1;
346 flags = 2;
347 }
348
349 if (*args == '\0' || *args == ',') {
350 *args = '\0';
Willy Tarreau254d44c2012-12-20 18:19:26 +0100351 for (i = 0; sp && var_args_list[i].name; i++) {
William Lallemand723b73a2012-02-08 16:37:49 +0100352 if (strcmp(sp, var_args_list[i].name) == 0) {
353 if (flags == 1) {
354 node->options |= var_args_list[i].mask;
355 break;
356 } else if (flags == 2) {
357 node->options &= ~var_args_list[i].mask;
358 break;
359 }
360 }
361 }
362 sp = NULL;
363 if (end)
364 break;
365 }
Willy Tarreau254d44c2012-12-20 18:19:26 +0100366 args++;
William Lallemand723b73a2012-02-08 16:37:49 +0100367 }
Thierry FOURNIER / OZON.IObca46f02016-11-22 23:13:04 +0100368 return 1;
William Lallemand723b73a2012-02-08 16:37:49 +0100369}
370
371/*
Willy Tarreau8a3f52f2012-12-20 21:23:42 +0100372 * Parse a variable '%varname' or '%{args}varname' in log-format. The caller
373 * must pass the args part in the <arg> pointer with its length in <arg_len>,
374 * and varname with its length in <var> and <var_len> respectively. <arg> is
375 * ignored when arg_len is 0. Neither <var> nor <var_len> may be null.
Thierry FOURNIER / OZON.IOeca4d952016-11-22 22:06:04 +0100376 * Returns false in error case and err is filled, otherwise returns true.
William Lallemand723b73a2012-02-08 16:37:49 +0100377 */
Thierry FOURNIER / OZON.IO8a4e4422016-11-23 00:41:28 +0100378int parse_logformat_var(char *arg, int arg_len, char *var, int var_len, struct proxy *curproxy, struct list *list_format, int *defoptions, char **err)
William Lallemand723b73a2012-02-08 16:37:49 +0100379{
Willy Tarreau8a3f52f2012-12-20 21:23:42 +0100380 int j;
381 struct logformat_node *node;
William Lallemand723b73a2012-02-08 16:37:49 +0100382
Willy Tarreau8a3f52f2012-12-20 21:23:42 +0100383 for (j = 0; logformat_keywords[j].name; j++) { // search a log type
384 if (strlen(logformat_keywords[j].name) == var_len &&
385 strncmp(var, logformat_keywords[j].name, var_len) == 0) {
386 if (logformat_keywords[j].mode != PR_MODE_HTTP || curproxy->mode == PR_MODE_HTTP) {
Vincent Bernat02779b62016-04-03 13:48:43 +0200387 node = calloc(1, sizeof(*node));
Thierry FOURNIER / OZON.IO9cbfef22016-11-22 23:24:10 +0100388 if (!node) {
Thierry FOURNIER / OZON.IO8a4e4422016-11-23 00:41:28 +0100389 memprintf(err, "out of memory error");
Thierry FOURNIER / OZON.IO9cbfef22016-11-22 23:24:10 +0100390 return 0;
391 }
Willy Tarreau8a3f52f2012-12-20 21:23:42 +0100392 node->type = logformat_keywords[j].type;
393 node->options = *defoptions;
394 if (arg_len) {
395 node->arg = my_strndup(arg, arg_len);
Thierry FOURNIER / OZON.IO8a4e4422016-11-23 00:41:28 +0100396 if (!parse_logformat_var_args(node->arg, node, err))
Thierry FOURNIER / OZON.IOa2c38d72016-11-22 23:11:21 +0100397 return 0;
Willy Tarreau8a3f52f2012-12-20 21:23:42 +0100398 }
399 if (node->type == LOG_FMT_GLOBAL) {
400 *defoptions = node->options;
401 free(node->arg);
402 free(node);
403 } else {
404 if (logformat_keywords[j].config_callback &&
405 logformat_keywords[j].config_callback(node, curproxy) != 0) {
Thierry FOURNIER / OZON.IOeca4d952016-11-22 22:06:04 +0100406 return 0;
William Lallemand723b73a2012-02-08 16:37:49 +0100407 }
Willy Tarreau8a3f52f2012-12-20 21:23:42 +0100408 curproxy->to_log |= logformat_keywords[j].lw;
409 LIST_ADDQ(list_format, &node->list);
William Lallemand723b73a2012-02-08 16:37:49 +0100410 }
Willy Tarreau8a3f52f2012-12-20 21:23:42 +0100411 if (logformat_keywords[j].replace_by)
Christopher Faulet767a84b2017-11-24 16:50:31 +0100412 ha_warning("parsing [%s:%d] : deprecated variable '%s' in '%s', please replace it with '%s'.\n",
413 curproxy->conf.args.file, curproxy->conf.args.line,
414 logformat_keywords[j].name, fmt_directive(curproxy), logformat_keywords[j].replace_by);
Thierry FOURNIER / OZON.IOeca4d952016-11-22 22:06:04 +0100415 return 1;
Willy Tarreau8a3f52f2012-12-20 21:23:42 +0100416 } else {
Thierry FOURNIER / OZON.IO8a4e4422016-11-23 00:41:28 +0100417 memprintf(err, "format variable '%s' is reserved for HTTP mode",
418 logformat_keywords[j].name);
Thierry FOURNIER / OZON.IOeca4d952016-11-22 22:06:04 +0100419 return 0;
William Lallemand723b73a2012-02-08 16:37:49 +0100420 }
William Lallemand723b73a2012-02-08 16:37:49 +0100421 }
422 }
Willy Tarreau8a3f52f2012-12-20 21:23:42 +0100423
424 j = var[var_len];
425 var[var_len] = 0;
Thierry FOURNIER / OZON.IO8a4e4422016-11-23 00:41:28 +0100426 memprintf(err, "no such format variable '%s'. If you wanted to emit the '%%' character verbatim, you need to use '%%%%'", var);
Willy Tarreau8a3f52f2012-12-20 21:23:42 +0100427 var[var_len] = j;
Thierry FOURNIER / OZON.IOeca4d952016-11-22 22:06:04 +0100428 return 0;
William Lallemand723b73a2012-02-08 16:37:49 +0100429}
430
431/*
432 * push to the logformat linked list
433 *
434 * start: start pointer
435 * end: end text pointer
436 * type: string type
William Lallemand1d705562012-03-12 12:46:41 +0100437 * list_format: destination list
William Lallemand723b73a2012-02-08 16:37:49 +0100438 *
439 * LOG_TEXT: copy chars from start to end excluding end.
440 *
441*/
Thierry FOURNIER / OZON.IO8a4e4422016-11-23 00:41:28 +0100442int add_to_logformat_list(char *start, char *end, int type, struct list *list_format, char **err)
William Lallemand723b73a2012-02-08 16:37:49 +0100443{
444 char *str;
445
Willy Tarreaua3571662012-12-20 21:59:12 +0100446 if (type == LF_TEXT) { /* type text */
Vincent Bernat02779b62016-04-03 13:48:43 +0200447 struct logformat_node *node = calloc(1, sizeof(*node));
Thierry FOURNIER / OZON.IO9cbfef22016-11-22 23:24:10 +0100448 if (!node) {
Thierry FOURNIER / OZON.IO8a4e4422016-11-23 00:41:28 +0100449 memprintf(err, "out of memory error");
Thierry FOURNIER / OZON.IO9cbfef22016-11-22 23:24:10 +0100450 return 0;
451 }
Vincent Bernat02779b62016-04-03 13:48:43 +0200452 str = calloc(1, end - start + 1);
William Lallemand723b73a2012-02-08 16:37:49 +0100453 strncpy(str, start, end - start);
William Lallemand723b73a2012-02-08 16:37:49 +0100454 str[end - start] = '\0';
455 node->arg = str;
William Lallemand1d705562012-03-12 12:46:41 +0100456 node->type = LOG_FMT_TEXT; // type string
457 LIST_ADDQ(list_format, &node->list);
Willy Tarreaua3571662012-12-20 21:59:12 +0100458 } else if (type == LF_SEPARATOR) {
Vincent Bernat02779b62016-04-03 13:48:43 +0200459 struct logformat_node *node = calloc(1, sizeof(*node));
Thierry FOURNIER / OZON.IO9cbfef22016-11-22 23:24:10 +0100460 if (!node) {
Thierry FOURNIER / OZON.IO8a4e4422016-11-23 00:41:28 +0100461 memprintf(err, "out of memory error");
Thierry FOURNIER / OZON.IO9cbfef22016-11-22 23:24:10 +0100462 return 0;
463 }
William Lallemand1d705562012-03-12 12:46:41 +0100464 node->type = LOG_FMT_SEPARATOR;
465 LIST_ADDQ(list_format, &node->list);
William Lallemand723b73a2012-02-08 16:37:49 +0100466 }
Thierry FOURNIER / OZON.IOa2c38d72016-11-22 23:11:21 +0100467 return 1;
William Lallemand723b73a2012-02-08 16:37:49 +0100468}
469
470/*
Willy Tarreauc8368452012-12-21 00:09:23 +0100471 * Parse the sample fetch expression <text> and add a node to <list_format> upon
472 * success. At the moment, sample converters are not yet supported but fetch arguments
Willy Tarreaua4312fa2013-04-02 16:34:32 +0200473 * should work. The curpx->conf.args.ctx must be set by the caller.
Thierry FOURNIER / OZON.IOa2c38d72016-11-22 23:11:21 +0100474 *
475 * In error case, the function returns 0, otherwise it returns 1.
Willy Tarreauc8368452012-12-21 00:09:23 +0100476 */
Thierry FOURNIER / OZON.IO8a4e4422016-11-23 00:41:28 +0100477int add_sample_to_logformat_list(char *text, char *arg, int arg_len, struct proxy *curpx, struct list *list_format, int options, int cap, char **err)
Willy Tarreauc8368452012-12-21 00:09:23 +0100478{
479 char *cmd[2];
480 struct sample_expr *expr;
481 struct logformat_node *node;
482 int cmd_arg;
483
484 cmd[0] = text;
485 cmd[1] = "";
486 cmd_arg = 0;
487
Thierry FOURNIER / OZON.IO8a4e4422016-11-23 00:41:28 +0100488 expr = sample_parse_expr(cmd, &cmd_arg, curpx->conf.args.file, curpx->conf.args.line, err, &curpx->conf.args);
Willy Tarreauc8368452012-12-21 00:09:23 +0100489 if (!expr) {
Thierry FOURNIER / OZON.IO8a4e4422016-11-23 00:41:28 +0100490 memprintf(err, "failed to parse sample expression <%s> : %s", text, *err);
Thierry FOURNIER / OZON.IOa2c38d72016-11-22 23:11:21 +0100491 return 0;
Willy Tarreauc8368452012-12-21 00:09:23 +0100492 }
493
Vincent Bernat02779b62016-04-03 13:48:43 +0200494 node = calloc(1, sizeof(*node));
Thierry FOURNIER / OZON.IO9cbfef22016-11-22 23:24:10 +0100495 if (!node) {
Thierry FOURNIER / OZON.IO8a4e4422016-11-23 00:41:28 +0100496 memprintf(err, "out of memory error");
Thierry FOURNIER / OZON.IO9cbfef22016-11-22 23:24:10 +0100497 return 0;
498 }
Willy Tarreauc8368452012-12-21 00:09:23 +0100499 node->type = LOG_FMT_EXPR;
500 node->expr = expr;
501 node->options = options;
502
503 if (arg_len) {
504 node->arg = my_strndup(arg, arg_len);
Thierry FOURNIER / OZON.IO8a4e4422016-11-23 00:41:28 +0100505 if (!parse_logformat_var_args(node->arg, node, err))
Thierry FOURNIER / OZON.IOa2c38d72016-11-22 23:11:21 +0100506 return 0;
Willy Tarreauc8368452012-12-21 00:09:23 +0100507 }
Willy Tarreau434c57c2013-01-08 01:10:24 +0100508 if (expr->fetch->val & cap & SMP_VAL_REQUEST)
Willy Tarreauc8368452012-12-21 00:09:23 +0100509 node->options |= LOG_OPT_REQ_CAP; /* fetch method is request-compatible */
510
Willy Tarreau434c57c2013-01-08 01:10:24 +0100511 if (expr->fetch->val & cap & SMP_VAL_RESPONSE)
Willy Tarreauc8368452012-12-21 00:09:23 +0100512 node->options |= LOG_OPT_RES_CAP; /* fetch method is response-compatible */
513
Thierry FOURNIER / OZON.IOa2c38d72016-11-22 23:11:21 +0100514 if (!(expr->fetch->val & cap)) {
David Carlier93e8b882017-09-21 14:36:43 +0000515 free(node);
516 node = NULL;
Thierry FOURNIER / OZON.IO8a4e4422016-11-23 00:41:28 +0100517 memprintf(err, "sample fetch <%s> may not be reliably used here because it needs '%s' which is not available here",
518 text, sample_src_names(expr->fetch->use));
Thierry FOURNIER / OZON.IOa2c38d72016-11-22 23:11:21 +0100519 return 0;
520 }
Willy Tarreau434c57c2013-01-08 01:10:24 +0100521
Willy Tarreauc8368452012-12-21 00:09:23 +0100522 /* check if we need to allocate an hdr_idx struct for HTTP parsing */
523 /* Note, we may also need to set curpx->to_log with certain fetches */
Willy Tarreau25320b22013-03-24 07:22:08 +0100524 curpx->http_needed |= !!(expr->fetch->use & SMP_USE_HTTP_ANY);
Willy Tarreauc8368452012-12-21 00:09:23 +0100525
William Lallemand65ad6e12014-01-31 15:08:02 +0100526 /* FIXME: temporary workaround for missing LW_XPRT and LW_REQ flags
527 * needed with some sample fetches (eg: ssl*). We always set it for
528 * now on, but this will leave with sample capabilities soon.
Willy Tarreau1f31c732013-01-10 16:22:27 +0100529 */
530 curpx->to_log |= LW_XPRT;
William Lallemand65ad6e12014-01-31 15:08:02 +0100531 curpx->to_log |= LW_REQ;
Willy Tarreauc8368452012-12-21 00:09:23 +0100532 LIST_ADDQ(list_format, &node->list);
Thierry FOURNIER / OZON.IOa2c38d72016-11-22 23:11:21 +0100533 return 1;
Willy Tarreauc8368452012-12-21 00:09:23 +0100534}
535
536/*
William Lallemand723b73a2012-02-08 16:37:49 +0100537 * Parse the log_format string and fill a linked list.
538 * Variable name are preceded by % and composed by characters [a-zA-Z0-9]* : %varname
Willy Tarreaua4312fa2013-04-02 16:34:32 +0200539 * You can set arguments using { } : %{many arguments}varname.
540 * The curproxy->conf.args.ctx must be set by the caller.
William Lallemand1d705562012-03-12 12:46:41 +0100541 *
542 * str: the string to parse
543 * curproxy: the proxy affected
544 * list_format: the destination list
Willy Tarreau6cbbdbf2013-02-05 18:52:25 +0100545 * options: LOG_OPT_* to force on every node
Willy Tarreau434c57c2013-01-08 01:10:24 +0100546 * cap: all SMP_VAL_* flags supported by the consumer
Thierry FOURNIER / OZON.IOa2c38d72016-11-22 23:11:21 +0100547 *
Thierry FOURNIER / OZON.IO8a4e4422016-11-23 00:41:28 +0100548 * The function returns 1 in success case, otherwise, it returns 0 and err is filled.
William Lallemand723b73a2012-02-08 16:37:49 +0100549 */
Thierry FOURNIER / OZON.IO8a4e4422016-11-23 00:41:28 +0100550int parse_logformat_string(const char *fmt, struct proxy *curproxy, struct list *list_format, int options, int cap, char **err)
William Lallemand723b73a2012-02-08 16:37:49 +0100551{
Willy Tarreaub83bc1e2012-12-24 12:36:33 +0100552 char *sp, *str, *backfmt; /* start pointer for text parts */
Willy Tarreau8a3f52f2012-12-20 21:23:42 +0100553 char *arg = NULL; /* start pointer for args */
554 char *var = NULL; /* start pointer for vars */
555 int arg_len = 0;
556 int var_len = 0;
557 int cformat; /* current token format */
558 int pformat; /* previous token format */
William Lallemand723b73a2012-02-08 16:37:49 +0100559 struct logformat_node *tmplf, *back;
560
Willy Tarreaub83bc1e2012-12-24 12:36:33 +0100561 sp = str = backfmt = strdup(fmt);
Thierry FOURNIER / OZON.IO9cbfef22016-11-22 23:24:10 +0100562 if (!str) {
Thierry FOURNIER / OZON.IO8a4e4422016-11-23 00:41:28 +0100563 memprintf(err, "out of memory error");
Thierry FOURNIER / OZON.IO9cbfef22016-11-22 23:24:10 +0100564 return 0;
565 }
William Lallemand1dc00ef2012-08-09 16:41:35 +0200566 curproxy->to_log |= LW_INIT;
William Lallemand5e19a282012-04-02 16:22:10 +0200567
William Lallemand723b73a2012-02-08 16:37:49 +0100568 /* flush the list first. */
William Lallemand1d705562012-03-12 12:46:41 +0100569 list_for_each_entry_safe(tmplf, back, list_format, list) {
William Lallemand723b73a2012-02-08 16:37:49 +0100570 LIST_DEL(&tmplf->list);
571 free(tmplf);
572 }
573
Willy Tarreau8a3f52f2012-12-20 21:23:42 +0100574 for (cformat = LF_INIT; cformat != LF_END; str++) {
William Lallemand723b73a2012-02-08 16:37:49 +0100575 pformat = cformat;
576
Willy Tarreau8a3f52f2012-12-20 21:23:42 +0100577 if (!*str)
578 cformat = LF_END; // preset it to save all states from doing this
William Lallemand723b73a2012-02-08 16:37:49 +0100579
Joseph Herlant85b40592018-11-15 12:10:04 -0800580 /* The principle of the two-step state machine below is to first detect a change, and
Willy Tarreau8a3f52f2012-12-20 21:23:42 +0100581 * second have all common paths processed at one place. The common paths are the ones
582 * encountered in text areas (LF_INIT, LF_TEXT, LF_SEPARATOR) and at the end (LF_END).
583 * We use the common LF_INIT state to dispatch to the different final states.
584 */
585 switch (pformat) {
586 case LF_STARTVAR: // text immediately following a '%'
Willy Tarreauc8368452012-12-21 00:09:23 +0100587 arg = NULL; var = NULL;
Willy Tarreau8a3f52f2012-12-20 21:23:42 +0100588 arg_len = var_len = 0;
589 if (*str == '{') { // optional argument
590 cformat = LF_STARG;
591 arg = str + 1;
William Lallemand723b73a2012-02-08 16:37:49 +0100592 }
Willy Tarreauc8368452012-12-21 00:09:23 +0100593 else if (*str == '[') {
594 cformat = LF_STEXPR;
595 var = str + 1; // store expr in variable name
596 }
Willy Tarreau0f28f822013-12-16 01:38:33 +0100597 else if (isalpha((unsigned char)*str)) { // variable name
William Lallemand723b73a2012-02-08 16:37:49 +0100598 cformat = LF_VAR;
Willy Tarreau8a3f52f2012-12-20 21:23:42 +0100599 var = str;
William Lallemand723b73a2012-02-08 16:37:49 +0100600 }
Willy Tarreau8a3f52f2012-12-20 21:23:42 +0100601 else if (*str == '%')
602 cformat = LF_TEXT; // convert this character to a litteral (useful for '%')
Willy Tarreau0f28f822013-12-16 01:38:33 +0100603 else if (isdigit((unsigned char)*str) || *str == ' ' || *str == '\t') {
Willy Tarreau06d97f92013-12-02 17:45:48 +0100604 /* single '%' followed by blank or digit, send them both */
605 cformat = LF_TEXT;
606 pformat = LF_TEXT; /* finally we include the previous char as well */
607 sp = str - 1; /* send both the '%' and the current char */
Jim Freemana2278c82017-04-15 08:01:59 -0600608 memprintf(err, "unexpected variable name near '%c' at position %d line : '%s'. Maybe you want to write a single '%%', use the syntax '%%%%'",
Thierry FOURNIER / OZON.IO8a4e4422016-11-23 00:41:28 +0100609 *str, (int)(str - backfmt), fmt);
Thierry FOURNIER / OZON.IOa2c38d72016-11-22 23:11:21 +0100610 return 0;
Willy Tarreau06d97f92013-12-02 17:45:48 +0100611
612 }
Willy Tarreau8a3f52f2012-12-20 21:23:42 +0100613 else
614 cformat = LF_INIT; // handle other cases of litterals
615 break;
616
617 case LF_STARG: // text immediately following '%{'
618 if (*str == '}') { // end of arg
William Lallemand723b73a2012-02-08 16:37:49 +0100619 cformat = LF_EDARG;
Willy Tarreau8a3f52f2012-12-20 21:23:42 +0100620 arg_len = str - arg;
621 *str = 0; // used for reporting errors
William Lallemand723b73a2012-02-08 16:37:49 +0100622 }
Willy Tarreau8a3f52f2012-12-20 21:23:42 +0100623 break;
624
625 case LF_EDARG: // text immediately following '%{arg}'
Willy Tarreauc8368452012-12-21 00:09:23 +0100626 if (*str == '[') {
627 cformat = LF_STEXPR;
628 var = str + 1; // store expr in variable name
629 break;
630 }
Willy Tarreau0f28f822013-12-16 01:38:33 +0100631 else if (isalnum((unsigned char)*str)) { // variable name
William Lallemand723b73a2012-02-08 16:37:49 +0100632 cformat = LF_VAR;
Willy Tarreau8a3f52f2012-12-20 21:23:42 +0100633 var = str;
634 break;
635 }
Thierry FOURNIER / OZON.IO8a4e4422016-11-23 00:41:28 +0100636 memprintf(err, "parse argument modifier without variable name near '%%{%s}'", arg);
Thierry FOURNIER / OZON.IOa2c38d72016-11-22 23:11:21 +0100637 return 0;
Willy Tarreau8a3f52f2012-12-20 21:23:42 +0100638
Willy Tarreauc8368452012-12-21 00:09:23 +0100639 case LF_STEXPR: // text immediately following '%['
640 if (*str == ']') { // end of arg
641 cformat = LF_EDEXPR;
642 var_len = str - var;
643 *str = 0; // needed for parsing the expression
644 }
645 break;
646
Willy Tarreau8a3f52f2012-12-20 21:23:42 +0100647 case LF_VAR: // text part of a variable name
648 var_len = str - var;
Willy Tarreau0f28f822013-12-16 01:38:33 +0100649 if (!isalnum((unsigned char)*str))
Willy Tarreau8a3f52f2012-12-20 21:23:42 +0100650 cformat = LF_INIT; // not variable name anymore
651 break;
652
Willy Tarreauc8368452012-12-21 00:09:23 +0100653 default: // LF_INIT, LF_TEXT, LF_SEPARATOR, LF_END, LF_EDEXPR
Willy Tarreau8a3f52f2012-12-20 21:23:42 +0100654 cformat = LF_INIT;
655 }
656
657 if (cformat == LF_INIT) { /* resynchronize state to text/sep/startvar */
658 switch (*str) {
659 case '%': cformat = LF_STARTVAR; break;
660 case ' ': cformat = LF_SEPARATOR; break;
661 case 0 : cformat = LF_END; break;
662 default : cformat = LF_TEXT; break;
William Lallemand723b73a2012-02-08 16:37:49 +0100663 }
664 }
665
Willy Tarreau8a3f52f2012-12-20 21:23:42 +0100666 if (cformat != pformat || pformat == LF_SEPARATOR) {
667 switch (pformat) {
668 case LF_VAR:
Thierry FOURNIER / OZON.IO8a4e4422016-11-23 00:41:28 +0100669 if (!parse_logformat_var(arg, arg_len, var, var_len, curproxy, list_format, &options, err))
Thierry FOURNIER / OZON.IOa2c38d72016-11-22 23:11:21 +0100670 return 0;
Willy Tarreau8a3f52f2012-12-20 21:23:42 +0100671 break;
Willy Tarreauc8368452012-12-21 00:09:23 +0100672 case LF_STEXPR:
Thierry FOURNIER / OZON.IO8a4e4422016-11-23 00:41:28 +0100673 if (!add_sample_to_logformat_list(var, arg, arg_len, curproxy, list_format, options, cap, err))
Thierry FOURNIER / OZON.IOa2c38d72016-11-22 23:11:21 +0100674 return 0;
Willy Tarreauc8368452012-12-21 00:09:23 +0100675 break;
Willy Tarreau8a3f52f2012-12-20 21:23:42 +0100676 case LF_TEXT:
677 case LF_SEPARATOR:
Thierry FOURNIER / OZON.IO8a4e4422016-11-23 00:41:28 +0100678 if (!add_to_logformat_list(sp, str, pformat, list_format, err))
Thierry FOURNIER / OZON.IOa2c38d72016-11-22 23:11:21 +0100679 return 0;
Willy Tarreau8a3f52f2012-12-20 21:23:42 +0100680 break;
681 }
682 sp = str; /* new start of text at every state switch and at every separator */
William Lallemand723b73a2012-02-08 16:37:49 +0100683 }
684 }
Willy Tarreau8a3f52f2012-12-20 21:23:42 +0100685
Thierry FOURNIER / OZON.IOa2c38d72016-11-22 23:11:21 +0100686 if (pformat == LF_STARTVAR || pformat == LF_STARG || pformat == LF_STEXPR) {
Thierry FOURNIER / OZON.IO8a4e4422016-11-23 00:41:28 +0100687 memprintf(err, "truncated line after '%s'", var ? var : arg ? arg : "%");
Thierry FOURNIER / OZON.IOa2c38d72016-11-22 23:11:21 +0100688 return 0;
689 }
Willy Tarreaub83bc1e2012-12-24 12:36:33 +0100690 free(backfmt);
Thierry FOURNIER / OZON.IOa2c38d72016-11-22 23:11:21 +0100691
692 return 1;
William Lallemand723b73a2012-02-08 16:37:49 +0100693}
694
Christopher Faulet4b0b79d2018-03-26 15:54:32 +0200695/*
696 * Parse "log" keyword and update <logsrvs> list accordingly.
697 *
698 * When <do_del> is set, it means the "no log" line was parsed, so all log
699 * servers in <logsrvs> are released.
700 *
701 * Otherwise, we try to parse the "log" line. First of all, when the list is not
702 * the global one, we look for the parameter "global". If we find it,
703 * global.logsrvs is copied. Else we parse each arguments.
704 *
705 * The function returns 1 in success case, otherwise, it returns 0 and err is
706 * filled.
707 */
708int parse_logsrv(char **args, struct list *logsrvs, int do_del, char **err)
709{
710 struct sockaddr_storage *sk;
711 struct logsrv *logsrv = NULL;
712 int port1, port2;
713 int cur_arg;
714
715 /*
716 * "no log": delete previous herited or defined syslog
717 * servers.
718 */
719 if (do_del) {
720 struct logsrv *back;
721
722 if (*(args[1]) != 0) {
723 memprintf(err, "'no log' does not expect arguments");
724 goto error;
725 }
726
727 list_for_each_entry_safe(logsrv, back, logsrvs, list) {
728 LIST_DEL(&logsrv->list);
729 free(logsrv);
730 }
731 return 1;
732 }
733
734 /*
735 * "log global": copy global.logrsvs linked list to the end of logsrvs
736 * list. But first, we check (logsrvs != global.logsrvs).
737 */
738 if (*(args[1]) && *(args[2]) == 0 && !strcmp(args[1], "global")) {
739 if (logsrvs == &global.logsrvs) {
740 memprintf(err, "'global' is not supported for a global syslog server");
741 goto error;
742 }
743 list_for_each_entry(logsrv, &global.logsrvs, list) {
Christopher Faulet28ac0992018-03-26 16:09:19 +0200744 struct logsrv *node;
745
746 list_for_each_entry(node, logsrvs, list) {
747 if (node->ref == logsrv)
748 goto skip_logsrv;
749 }
750
751 node = malloc(sizeof(*node));
Christopher Faulet4b0b79d2018-03-26 15:54:32 +0200752 memcpy(node, logsrv, sizeof(struct logsrv));
Christopher Faulet28ac0992018-03-26 16:09:19 +0200753 node->ref = logsrv;
Christopher Faulet4b0b79d2018-03-26 15:54:32 +0200754 LIST_INIT(&node->list);
755 LIST_ADDQ(logsrvs, &node->list);
Christopher Faulet28ac0992018-03-26 16:09:19 +0200756
757 skip_logsrv:
758 continue;
Christopher Faulet4b0b79d2018-03-26 15:54:32 +0200759 }
760 return 1;
761 }
762
763 /*
764 * "log <address> ...: parse a syslog server line
765 */
766 if (*(args[1]) == 0 || *(args[2]) == 0) {
767 memprintf(err, "expects <address> and <facility> %s as arguments",
768 ((logsrvs == &global.logsrvs) ? "" : "or global"));
769 goto error;
770 }
771
Willy Tarreau5a32ecc2018-11-12 07:34:59 +0100772 /* take care of "stdout" and "stderr" as regular aliases for fd@1 / fd@2 */
773 if (strcmp(args[1], "stdout") == 0)
774 args[1] = "fd@1";
775 else if (strcmp(args[1], "stderr") == 0)
776 args[1] = "fd@2";
777
Christopher Faulet4b0b79d2018-03-26 15:54:32 +0200778 logsrv = calloc(1, sizeof(*logsrv));
779 if (!logsrv) {
780 memprintf(err, "out of memory");
781 goto error;
782 }
783
784 /* skip address for now, it will be parsed at the end */
785 cur_arg = 2;
786
787 /* just after the address, a length may be specified */
788 logsrv->maxlen = MAX_SYSLOG_LEN;
789 if (strcmp(args[cur_arg], "len") == 0) {
790 int len = atoi(args[cur_arg+1]);
791 if (len < 80 || len > 65535) {
792 memprintf(err, "invalid log length '%s', must be between 80 and 65535",
793 args[cur_arg+1]);
794 goto error;
795 }
796 logsrv->maxlen = len;
797 cur_arg += 2;
798 }
799 if (logsrv->maxlen > global.max_syslog_len)
800 global.max_syslog_len = logsrv->maxlen;
801
802 /* after the length, a format may be specified */
803 if (strcmp(args[cur_arg], "format") == 0) {
804 logsrv->format = get_log_format(args[cur_arg+1]);
805 if (logsrv->format < 0) {
806 memprintf(err, "unknown log format '%s'", args[cur_arg+1]);
807 goto error;
808 }
809 cur_arg += 2;
810 }
811
812 /* parse the facility */
813 logsrv->facility = get_log_facility(args[cur_arg]);
814 if (logsrv->facility < 0) {
815 memprintf(err, "unknown log facility '%s'", args[cur_arg]);
816 goto error;
817 }
818 cur_arg++;
819
820 /* parse the max syslog level (default: debug) */
821 logsrv->level = 7;
822 if (*(args[cur_arg])) {
823 logsrv->level = get_log_level(args[cur_arg]);
824 if (logsrv->level < 0) {
825 memprintf(err, "unknown optional log level '%s'", args[cur_arg]);
826 goto error;
827 }
828 cur_arg++;
829 }
830
831 /* parse the limit syslog level (default: emerg) */
832 logsrv->minlvl = 0;
833 if (*(args[cur_arg])) {
834 logsrv->minlvl = get_log_level(args[cur_arg]);
835 if (logsrv->minlvl < 0) {
836 memprintf(err, "unknown optional minimum log level '%s'", args[cur_arg]);
837 goto error;
838 }
839 cur_arg++;
840 }
841
842 /* Too many args */
843 if (*(args[cur_arg])) {
844 memprintf(err, "cannot handle unexpected argument '%s'", args[cur_arg]);
845 goto error;
846 }
847
848 /* now, back to the address */
849 sk = str2sa_range(args[1], NULL, &port1, &port2, err, NULL, NULL, 1);
850 if (!sk)
851 goto error;
852 logsrv->addr = *sk;
853
854 if (sk->ss_family == AF_INET || sk->ss_family == AF_INET6) {
855 if (port1 != port2) {
856 memprintf(err, "port ranges and offsets are not allowed in '%s'", args[1]);
857 goto error;
858 }
859 logsrv->addr = *sk;
860 if (!port1)
861 set_host_port(&logsrv->addr, SYSLOG_PORT);
862 }
863 LIST_ADDQ(logsrvs, &logsrv->list);
864 return 1;
865
866 error:
867 free(logsrv);
868 return 0;
869}
870
871
Christopher Fauletd4696382017-10-24 11:44:05 +0200872/* Generic function to display messages prefixed by a label */
873static void print_message(const char *label, const char *fmt, va_list argp)
874{
875 struct tm tm;
876 char *head, *msg;
877
878 head = msg = NULL;
879
880 get_localtime(date.tv_sec, &tm);
881 memprintf(&head, "[%s] %03d/%02d%02d%02d (%d) : ",
882 label, tm.tm_yday, tm.tm_hour, tm.tm_min, tm.tm_sec, (int)getpid());
883 memvprintf(&msg, fmt, argp);
884
885 if (global.mode & MODE_STARTING)
886 memprintf(&startup_logs, "%s%s%s", (startup_logs ? startup_logs : ""), head, msg);
887
888 fprintf(stderr, "%s%s", head, msg);
889 fflush(stderr);
890
891 free(head);
892 free(msg);
893}
894
Willy Tarreaubaaee002006-06-26 02:48:02 +0200895/*
896 * Displays the message on stderr with the date and pid. Overrides the quiet
897 * mode during startup.
898 */
Christopher Faulet767a84b2017-11-24 16:50:31 +0100899void ha_alert(const char *fmt, ...)
Willy Tarreaubaaee002006-06-26 02:48:02 +0200900{
901 va_list argp;
Willy Tarreaubaaee002006-06-26 02:48:02 +0200902
903 if (!(global.mode & MODE_QUIET) || (global.mode & (MODE_VERBOSE | MODE_STARTING))) {
904 va_start(argp, fmt);
Christopher Fauletd4696382017-10-24 11:44:05 +0200905 print_message("ALERT", fmt, argp);
Willy Tarreaubaaee002006-06-26 02:48:02 +0200906 va_end(argp);
907 }
908}
909
910
911/*
912 * Displays the message on stderr with the date and pid.
913 */
Christopher Faulet767a84b2017-11-24 16:50:31 +0100914void ha_warning(const char *fmt, ...)
Willy Tarreaubaaee002006-06-26 02:48:02 +0200915{
916 va_list argp;
Willy Tarreaubaaee002006-06-26 02:48:02 +0200917
918 if (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE)) {
919 va_start(argp, fmt);
Christopher Fauletd4696382017-10-24 11:44:05 +0200920 print_message("WARNING", fmt, argp);
Willy Tarreaubaaee002006-06-26 02:48:02 +0200921 va_end(argp);
922 }
923}
924
925/*
William Lallemand9c56a222018-11-21 18:04:52 +0100926 * Displays the message on stderr with the date and pid.
927 */
928void ha_notice(const char *fmt, ...)
929{
930 va_list argp;
931
932 if (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE)) {
933 va_start(argp, fmt);
934 print_message("NOTICE", fmt, argp);
935 va_end(argp);
936 }
937}
938
939/*
Willy Tarreaubaaee002006-06-26 02:48:02 +0200940 * Displays the message on <out> only if quiet mode is not set.
941 */
Willy Tarreaub17916e2006-10-15 15:17:57 +0200942void qfprintf(FILE *out, const char *fmt, ...)
Willy Tarreaubaaee002006-06-26 02:48:02 +0200943{
944 va_list argp;
945
946 if (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE)) {
947 va_start(argp, fmt);
948 vfprintf(out, fmt, argp);
949 fflush(out);
950 va_end(argp);
951 }
952}
953
954/*
Dragan Dosen1322d092015-09-22 16:05:32 +0200955 * returns log format for <fmt> or -1 if not found.
956 */
957int get_log_format(const char *fmt)
958{
959 int format;
960
961 format = LOG_FORMATS - 1;
Dragan Dosen43885c72015-10-01 13:18:13 +0200962 while (format >= 0 && strcmp(log_formats[format].name, fmt))
Dragan Dosen1322d092015-09-22 16:05:32 +0200963 format--;
964
965 return format;
966}
967
968/*
Willy Tarreaubaaee002006-06-26 02:48:02 +0200969 * returns log level for <lev> or -1 if not found.
970 */
971int get_log_level(const char *lev)
972{
973 int level;
974
975 level = NB_LOG_LEVELS - 1;
976 while (level >= 0 && strcmp(log_levels[level], lev))
977 level--;
978
979 return level;
980}
981
Willy Tarreaubaaee002006-06-26 02:48:02 +0200982/*
983 * returns log facility for <fac> or -1 if not found.
984 */
985int get_log_facility(const char *fac)
986{
987 int facility;
988
989 facility = NB_LOG_FACILITIES - 1;
990 while (facility >= 0 && strcmp(log_facilities[facility], fac))
991 facility--;
William Lallemand2a4a44f2012-02-06 16:00:33 +0100992
Willy Tarreaubaaee002006-06-26 02:48:02 +0200993 return facility;
994}
995
William Lallemanda1cc3812012-02-08 16:38:44 +0100996/*
Dragan Dosen835b9212016-02-12 13:23:03 +0100997 * Encode the string.
998 *
999 * When using the +E log format option, it will try to escape '"\]'
1000 * characters with '\' as prefix. The same prefix should not be used as
1001 * <escape>.
1002 */
1003static char *lf_encode_string(char *start, char *stop,
1004 const char escape, const fd_set *map,
1005 const char *string,
1006 struct logformat_node *node)
1007{
1008 if (node->options & LOG_OPT_ESC) {
1009 if (start < stop) {
1010 stop--; /* reserve one byte for the final '\0' */
1011 while (start < stop && *string != '\0') {
1012 if (!FD_ISSET((unsigned char)(*string), map)) {
1013 if (!FD_ISSET((unsigned char)(*string), rfc5424_escape_map))
1014 *start++ = *string;
1015 else {
1016 if (start + 2 >= stop)
1017 break;
1018 *start++ = '\\';
1019 *start++ = *string;
1020 }
1021 }
1022 else {
1023 if (start + 3 >= stop)
1024 break;
1025 *start++ = escape;
1026 *start++ = hextab[(*string >> 4) & 15];
1027 *start++ = hextab[*string & 15];
1028 }
1029 string++;
1030 }
1031 *start = '\0';
1032 }
1033 }
1034 else {
1035 return encode_string(start, stop, escape, map, string);
1036 }
1037
1038 return start;
1039}
1040
1041/*
1042 * Encode the chunk.
1043 *
1044 * When using the +E log format option, it will try to escape '"\]'
1045 * characters with '\' as prefix. The same prefix should not be used as
1046 * <escape>.
1047 */
1048static char *lf_encode_chunk(char *start, char *stop,
1049 const char escape, const fd_set *map,
Willy Tarreau83061a82018-07-13 11:56:34 +02001050 const struct buffer *chunk,
Dragan Dosen835b9212016-02-12 13:23:03 +01001051 struct logformat_node *node)
1052{
1053 char *str, *end;
1054
1055 if (node->options & LOG_OPT_ESC) {
1056 if (start < stop) {
Willy Tarreau843b7cb2018-07-13 10:54:26 +02001057 str = chunk->area;
1058 end = chunk->area + chunk->data;
Dragan Dosen835b9212016-02-12 13:23:03 +01001059
1060 stop--; /* reserve one byte for the final '\0' */
1061 while (start < stop && str < end) {
1062 if (!FD_ISSET((unsigned char)(*str), map)) {
1063 if (!FD_ISSET((unsigned char)(*str), rfc5424_escape_map))
1064 *start++ = *str;
1065 else {
1066 if (start + 2 >= stop)
1067 break;
1068 *start++ = '\\';
1069 *start++ = *str;
1070 }
1071 }
1072 else {
1073 if (start + 3 >= stop)
1074 break;
1075 *start++ = escape;
1076 *start++ = hextab[(*str >> 4) & 15];
1077 *start++ = hextab[*str & 15];
1078 }
1079 str++;
1080 }
1081 *start = '\0';
1082 }
1083 }
1084 else {
1085 return encode_chunk(start, stop, escape, map, chunk);
1086 }
1087
1088 return start;
1089}
1090
1091/*
William Lallemanda1cc3812012-02-08 16:38:44 +01001092 * Write a string in the log string
Dragan Dosen835b9212016-02-12 13:23:03 +01001093 * Take cares of quote and escape options
William Lallemanda1cc3812012-02-08 16:38:44 +01001094 *
Joseph Herlant85b40592018-11-15 12:10:04 -08001095 * Return the address of the \0 character, or NULL on error
William Lallemanda1cc3812012-02-08 16:38:44 +01001096 */
Willy Tarreau26ffa852018-09-05 15:23:10 +02001097char *lf_text_len(char *dst, const char *src, size_t len, size_t size, const struct logformat_node *node)
William Lallemanda1cc3812012-02-08 16:38:44 +01001098{
Willy Tarreau2b0108a2012-12-21 19:23:44 +01001099 if (size < 2)
1100 return NULL;
William Lallemanda1cc3812012-02-08 16:38:44 +01001101
Willy Tarreau2b0108a2012-12-21 19:23:44 +01001102 if (node->options & LOG_OPT_QUOTE) {
1103 *(dst++) = '"';
1104 size--;
William Lallemandbddd4fd2012-02-27 11:23:10 +01001105 }
Willy Tarreau2b0108a2012-12-21 19:23:44 +01001106
Willy Tarreau6cbbdbf2013-02-05 18:52:25 +01001107 if (src && len) {
Dragan Dosendb1b6f92016-07-25 11:35:02 +02001108 if (++len > size)
1109 len = size;
Dragan Dosen835b9212016-02-12 13:23:03 +01001110 if (node->options & LOG_OPT_ESC) {
Dragan Dosen835b9212016-02-12 13:23:03 +01001111 char *ret;
1112
Dragan Dosendb1b6f92016-07-25 11:35:02 +02001113 ret = escape_string(dst, dst + len, '\\', rfc5424_escape_map, src);
Dragan Dosen835b9212016-02-12 13:23:03 +01001114 if (ret == NULL || *ret != '\0')
1115 return NULL;
1116 len = ret - dst;
1117 }
1118 else {
Dragan Dosen835b9212016-02-12 13:23:03 +01001119 len = strlcpy2(dst, src, len);
1120 }
Willy Tarreau2b0108a2012-12-21 19:23:44 +01001121
1122 size -= len;
1123 dst += len;
1124 }
Willy Tarreau6cbbdbf2013-02-05 18:52:25 +01001125 else if ((node->options & (LOG_OPT_QUOTE|LOG_OPT_MANDATORY)) == LOG_OPT_MANDATORY) {
1126 if (size < 2)
1127 return NULL;
1128 *(dst++) = '-';
1129 }
Willy Tarreau2b0108a2012-12-21 19:23:44 +01001130
1131 if (node->options & LOG_OPT_QUOTE) {
1132 if (size < 2)
1133 return NULL;
1134 *(dst++) = '"';
1135 }
1136
1137 *dst = '\0';
William Lallemandbddd4fd2012-02-27 11:23:10 +01001138 return dst;
William Lallemanda1cc3812012-02-08 16:38:44 +01001139}
1140
Willy Tarreau26ffa852018-09-05 15:23:10 +02001141static inline char *lf_text(char *dst, const char *src, size_t size, const struct logformat_node *node)
Willy Tarreau2b0108a2012-12-21 19:23:44 +01001142{
1143 return lf_text_len(dst, src, size, size, node);
1144}
1145
William Lallemand5f232402012-04-05 18:02:55 +02001146/*
Joseph Herlant85b40592018-11-15 12:10:04 -08001147 * Write a IP address to the log string
William Lallemand5f232402012-04-05 18:02:55 +02001148 * +X option write in hexadecimal notation, most signifant byte on the left
1149 */
Willy Tarreau26ffa852018-09-05 15:23:10 +02001150char *lf_ip(char *dst, const struct sockaddr *sockaddr, size_t size, const struct logformat_node *node)
William Lallemand5f232402012-04-05 18:02:55 +02001151{
1152 char *ret = dst;
1153 int iret;
1154 char pn[INET6_ADDRSTRLEN];
1155
1156 if (node->options & LOG_OPT_HEXA) {
1157 const unsigned char *addr = (const unsigned char *)&((struct sockaddr_in *)sockaddr)->sin_addr.s_addr;
1158 iret = snprintf(dst, size, "%02X%02X%02X%02X", addr[0], addr[1], addr[2], addr[3]);
1159 if (iret < 0 || iret > size)
1160 return NULL;
1161 ret += iret;
1162 } else {
1163 addr_to_str((struct sockaddr_storage *)sockaddr, pn, sizeof(pn));
1164 ret = lf_text(dst, pn, size, node);
1165 if (ret == NULL)
1166 return NULL;
1167 }
1168 return ret;
1169}
1170
1171/*
1172 * Write a port to the log
1173 * +X option write in hexadecimal notation, most signifant byte on the left
1174 */
Willy Tarreau26ffa852018-09-05 15:23:10 +02001175char *lf_port(char *dst, const struct sockaddr *sockaddr, size_t size, const struct logformat_node *node)
William Lallemand5f232402012-04-05 18:02:55 +02001176{
1177 char *ret = dst;
1178 int iret;
1179
1180 if (node->options & LOG_OPT_HEXA) {
1181 const unsigned char *port = (const unsigned char *)&((struct sockaddr_in *)sockaddr)->sin_port;
1182 iret = snprintf(dst, size, "%02X%02X", port[0], port[1]);
1183 if (iret < 0 || iret > size)
1184 return NULL;
1185 ret += iret;
1186 } else {
1187 ret = ltoa_o(get_host_port((struct sockaddr_storage *)sockaddr), dst, size);
1188 if (ret == NULL)
1189 return NULL;
1190 }
1191 return ret;
1192}
1193
Dragan Dosen1322d092015-09-22 16:05:32 +02001194/* Re-generate time-based part of the syslog header in RFC3164 format at
1195 * the beginning of logheader once a second and return the pointer to the
1196 * first character after it.
Willy Tarreaub1a2faf2012-03-19 16:51:53 +01001197 */
Dragan Dosen0b85ece2015-09-25 19:17:44 +02001198static char *update_log_hdr(const time_t time)
Willy Tarreaubaaee002006-06-26 02:48:02 +02001199{
Christopher Fauletf8188c62017-06-02 16:20:16 +02001200 static THREAD_LOCAL long tvsec;
1201 static THREAD_LOCAL char *dataptr = NULL; /* backup of last end of header, NULL first time */
Willy Tarreau83061a82018-07-13 11:56:34 +02001202 static THREAD_LOCAL struct buffer host = { };
Christopher Fauletf8188c62017-06-02 16:20:16 +02001203 static THREAD_LOCAL int sep = 0;
Willy Tarreaubaaee002006-06-26 02:48:02 +02001204
Dragan Dosen0b85ece2015-09-25 19:17:44 +02001205 if (unlikely(time != tvsec || dataptr == NULL)) {
Willy Tarreaubaaee002006-06-26 02:48:02 +02001206 /* this string is rebuild only once a second */
Willy Tarreaufe944602007-10-25 10:34:16 +02001207 struct tm tm;
Willy Tarreaub1a2faf2012-03-19 16:51:53 +01001208 int hdr_len;
Willy Tarreaufe944602007-10-25 10:34:16 +02001209
Dragan Dosen0b85ece2015-09-25 19:17:44 +02001210 tvsec = time;
Willy Tarreaufe944602007-10-25 10:34:16 +02001211 get_localtime(tvsec, &tm);
Willy Tarreaubaaee002006-06-26 02:48:02 +02001212
Willy Tarreau843b7cb2018-07-13 10:54:26 +02001213 if (unlikely(global.log_send_hostname != host.area)) {
1214 host.area = global.log_send_hostname;
1215 host.data = host.area ? strlen(host.area) : 0;
1216 sep = host.data ? 1 : 0;
Dragan Dosen43885c72015-10-01 13:18:13 +02001217 }
1218
Dragan Dosen59cee972015-09-19 22:09:02 +02001219 hdr_len = snprintf(logheader, global.max_syslog_len,
Dragan Dosen43885c72015-10-01 13:18:13 +02001220 "<<<<>%s %2d %02d:%02d:%02d %.*s%*s",
Willy Tarreaufe944602007-10-25 10:34:16 +02001221 monthname[tm.tm_mon],
Dragan Dosen43885c72015-10-01 13:18:13 +02001222 tm.tm_mday, tm.tm_hour, tm.tm_min, tm.tm_sec,
Willy Tarreau843b7cb2018-07-13 10:54:26 +02001223 (int)host.data, host.area, sep, "");
Willy Tarreaubaaee002006-06-26 02:48:02 +02001224 /* WARNING: depending upon implementations, snprintf may return
1225 * either -1 or the number of bytes that would be needed to store
1226 * the total message. In both cases, we must adjust it.
1227 */
Willy Tarreau18324f52014-06-27 18:10:07 +02001228 if (hdr_len < 0 || hdr_len > global.max_syslog_len)
1229 hdr_len = global.max_syslog_len;
Willy Tarreaubaaee002006-06-26 02:48:02 +02001230
Dragan Dosen59cee972015-09-19 22:09:02 +02001231 dataptr = logheader + hdr_len;
Willy Tarreaubaaee002006-06-26 02:48:02 +02001232 }
1233
Willy Tarreau094af4e2015-01-07 15:03:42 +01001234 dataptr[0] = 0; // ensure we get rid of any previous attempt
1235
Dragan Dosen68d2e3a2015-09-19 22:35:44 +02001236 return dataptr;
William Lallemand2a4a44f2012-02-06 16:00:33 +01001237}
1238
Dragan Dosen1322d092015-09-22 16:05:32 +02001239/* Re-generate time-based part of the syslog header in RFC5424 format at
1240 * the beginning of logheader_rfc5424 once a second and return the pointer
1241 * to the first character after it.
1242 */
Dragan Dosen0b85ece2015-09-25 19:17:44 +02001243static char *update_log_hdr_rfc5424(const time_t time)
Dragan Dosen1322d092015-09-22 16:05:32 +02001244{
Christopher Fauletf8188c62017-06-02 16:20:16 +02001245 static THREAD_LOCAL long tvsec;
1246 static THREAD_LOCAL char *dataptr = NULL; /* backup of last end of header, NULL first time */
Benoit GARNIERb413c2a2016-03-27 11:08:03 +02001247 const char *gmt_offset;
Dragan Dosen1322d092015-09-22 16:05:32 +02001248
Dragan Dosen0b85ece2015-09-25 19:17:44 +02001249 if (unlikely(time != tvsec || dataptr == NULL)) {
Dragan Dosen1322d092015-09-22 16:05:32 +02001250 /* this string is rebuild only once a second */
1251 struct tm tm;
1252 int hdr_len;
1253
Dragan Dosen0b85ece2015-09-25 19:17:44 +02001254 tvsec = time;
Dragan Dosen1322d092015-09-22 16:05:32 +02001255 get_localtime(tvsec, &tm);
Benoit GARNIERe2e5bde2016-03-27 03:04:16 +02001256 gmt_offset = get_gmt_offset(time, &tm);
Dragan Dosen1322d092015-09-22 16:05:32 +02001257
1258 hdr_len = snprintf(logheader_rfc5424, global.max_syslog_len,
Dragan Dosen17def462015-10-09 21:31:43 +02001259 "<<<<>1 %4d-%02d-%02dT%02d:%02d:%02d%.3s:%.2s %s ",
Dragan Dosen1322d092015-09-22 16:05:32 +02001260 tm.tm_year+1900, tm.tm_mon+1, tm.tm_mday,
Dragan Dosen17def462015-10-09 21:31:43 +02001261 tm.tm_hour, tm.tm_min, tm.tm_sec,
Benoit GARNIERb413c2a2016-03-27 11:08:03 +02001262 gmt_offset, gmt_offset+3,
Dragan Dosen43885c72015-10-01 13:18:13 +02001263 global.log_send_hostname ? global.log_send_hostname : hostname);
Dragan Dosen1322d092015-09-22 16:05:32 +02001264 /* WARNING: depending upon implementations, snprintf may return
1265 * either -1 or the number of bytes that would be needed to store
1266 * the total message. In both cases, we must adjust it.
1267 */
1268 if (hdr_len < 0 || hdr_len > global.max_syslog_len)
1269 hdr_len = global.max_syslog_len;
1270
1271 dataptr = logheader_rfc5424 + hdr_len;
1272 }
1273
1274 dataptr[0] = 0; // ensure we get rid of any previous attempt
1275
1276 return dataptr;
1277}
1278
William Lallemand2a4a44f2012-02-06 16:00:33 +01001279/*
Dragan Dosen59cee972015-09-19 22:09:02 +02001280 * This function sends the syslog message using a printf format string. It
1281 * expects an LF-terminated message.
William Lallemand2a4a44f2012-02-06 16:00:33 +01001282 */
1283void send_log(struct proxy *p, int level, const char *format, ...)
1284{
1285 va_list argp;
Willy Tarreaub1a2faf2012-03-19 16:51:53 +01001286 int data_len;
William Lallemand2a4a44f2012-02-06 16:00:33 +01001287
Willy Tarreau8c97ab52015-01-15 16:29:53 +01001288 if (level < 0 || format == NULL || logline == NULL)
William Lallemand2a4a44f2012-02-06 16:00:33 +01001289 return;
1290
William Lallemand2a4a44f2012-02-06 16:00:33 +01001291 va_start(argp, format);
Dragan Dosen59cee972015-09-19 22:09:02 +02001292 data_len = vsnprintf(logline, global.max_syslog_len, format, argp);
Willy Tarreau18324f52014-06-27 18:10:07 +02001293 if (data_len < 0 || data_len > global.max_syslog_len)
1294 data_len = global.max_syslog_len;
Willy Tarreaubaaee002006-06-26 02:48:02 +02001295 va_end(argp);
William Lallemand2a4a44f2012-02-06 16:00:33 +01001296
Dragan Dosen0b85ece2015-09-25 19:17:44 +02001297 __send_log(p, level, logline, data_len, default_rfc5424_sd_log_format, 2);
William Lallemand2a4a44f2012-02-06 16:00:33 +01001298}
1299
1300/*
1301 * This function sends a syslog message.
1302 * It doesn't care about errors nor does it report them.
Dragan Dosen0b85ece2015-09-25 19:17:44 +02001303 * It overrides the last byte of the message vector with an LF character.
1304 * The arguments <sd> and <sd_size> are used for the structured-data part
1305 * in RFC5424 formatted syslog messages.
William Lallemand2a4a44f2012-02-06 16:00:33 +01001306 */
Dragan Dosen0b85ece2015-09-25 19:17:44 +02001307void __send_log(struct proxy *p, int level, char *message, size_t size, char *sd, size_t sd_size)
William Lallemand2a4a44f2012-02-06 16:00:33 +01001308{
Christopher Fauletf8188c62017-06-02 16:20:16 +02001309 static THREAD_LOCAL struct iovec iovec[NB_MSG_IOVEC_ELEMENTS] = { };
1310 static THREAD_LOCAL struct msghdr msghdr = {
1311 //.msg_iov = iovec,
Dragan Dosen609ac2a2015-09-16 18:25:42 +02001312 .msg_iovlen = NB_MSG_IOVEC_ELEMENTS
1313 };
Christopher Fauletf8188c62017-06-02 16:20:16 +02001314 static THREAD_LOCAL int logfdunix = -1; /* syslog to AF_UNIX socket */
1315 static THREAD_LOCAL int logfdinet = -1; /* syslog to AF_INET socket */
1316 static THREAD_LOCAL char *dataptr = NULL;
William Lallemand2a4a44f2012-02-06 16:00:33 +01001317 int fac_level;
1318 struct list *logsrvs = NULL;
1319 struct logsrv *tmp = NULL;
1320 int nblogger;
Dragan Dosen1322d092015-09-22 16:05:32 +02001321 char *hdr, *hdr_ptr;
Dragan Dosen59cee972015-09-19 22:09:02 +02001322 size_t hdr_size;
Dragan Dosen0b85ece2015-09-25 19:17:44 +02001323 time_t time = date.tv_sec;
Willy Tarreau83061a82018-07-13 11:56:34 +02001324 struct buffer *tag = &global.log_tag;
Christopher Fauletf8188c62017-06-02 16:20:16 +02001325 static THREAD_LOCAL int curr_pid;
1326 static THREAD_LOCAL char pidstr[100];
Willy Tarreau83061a82018-07-13 11:56:34 +02001327 static THREAD_LOCAL struct buffer pid;
Christopher Fauletf8188c62017-06-02 16:20:16 +02001328
1329 msghdr.msg_iov = iovec;
William Lallemand2a4a44f2012-02-06 16:00:33 +01001330
1331 dataptr = message;
Willy Tarreaubaaee002006-06-26 02:48:02 +02001332
1333 if (p == NULL) {
William Lallemand0f99e342011-10-12 17:50:54 +02001334 if (!LIST_ISEMPTY(&global.logsrvs)) {
1335 logsrvs = &global.logsrvs;
Willy Tarreaubaaee002006-06-26 02:48:02 +02001336 }
1337 } else {
William Lallemand0f99e342011-10-12 17:50:54 +02001338 if (!LIST_ISEMPTY(&p->logsrvs)) {
1339 logsrvs = &p->logsrvs;
Willy Tarreaubaaee002006-06-26 02:48:02 +02001340 }
Willy Tarreau843b7cb2018-07-13 10:54:26 +02001341 if (p->log_tag.area) {
Dragan Dosen43885c72015-10-01 13:18:13 +02001342 tag = &p->log_tag;
1343 }
Robert Tsai81ae1952007-12-05 10:47:29 +01001344 }
1345
William Lallemand0f99e342011-10-12 17:50:54 +02001346 if (!logsrvs)
1347 return;
1348
Dragan Dosen43885c72015-10-01 13:18:13 +02001349 if (unlikely(curr_pid != getpid())) {
1350 curr_pid = getpid();
1351 ltoa_o(curr_pid, pidstr, sizeof(pidstr));
1352 chunk_initstr(&pid, pidstr);
1353 }
1354
Robert Tsai81ae1952007-12-05 10:47:29 +01001355 /* Send log messages to syslog server. */
William Lallemand0f99e342011-10-12 17:50:54 +02001356 nblogger = 0;
1357 list_for_each_entry(tmp, logsrvs, list) {
1358 const struct logsrv *logsrv = tmp;
David du Colombier11bcb6c2011-03-24 12:23:00 +01001359 int *plogfd = logsrv->addr.ss_family == AF_UNIX ?
Robert Tsai81ae1952007-12-05 10:47:29 +01001360 &logfdunix : &logfdinet;
Willy Tarreaue8746a02018-11-12 08:45:00 +01001361 char *pid_sep1 = "", *pid_sep2 = "";
1362 char logheader_short[3];
Robert Tsai81ae1952007-12-05 10:47:29 +01001363 int sent;
Dragan Dosen68d2e3a2015-09-19 22:35:44 +02001364 int maxlen;
Dragan Dosen59cee972015-09-19 22:09:02 +02001365 int hdr_max = 0;
Dragan Dosen43885c72015-10-01 13:18:13 +02001366 int tag_max = 0;
1367 int pid_sep1_max = 0;
1368 int pid_max = 0;
1369 int pid_sep2_max = 0;
Dragan Dosen0b85ece2015-09-25 19:17:44 +02001370 int sd_max = 0;
Dragan Dosen5b78d9b2015-09-28 16:01:03 +02001371 int max = 0;
Robert Tsai81ae1952007-12-05 10:47:29 +01001372
Willy Tarreauc7c7be22014-06-23 18:07:15 +02001373 nblogger++;
1374
Willy Tarreaubaaee002006-06-26 02:48:02 +02001375 /* we can filter the level of the messages that are sent to each logger */
William Lallemand0f99e342011-10-12 17:50:54 +02001376 if (level > logsrv->level)
Willy Tarreaubaaee002006-06-26 02:48:02 +02001377 continue;
William Lallemandbddd4fd2012-02-27 11:23:10 +01001378
Willy Tarreauc7c7be22014-06-23 18:07:15 +02001379 if (unlikely(*plogfd < 0)) {
1380 /* socket not successfully initialized yet */
Willy Tarreau5a32ecc2018-11-12 07:34:59 +01001381 if (logsrv->addr.ss_family == AF_UNSPEC) {
1382 /* the socket's address is a file descriptor */
1383 *plogfd = ((struct sockaddr_in *)&logsrv->addr)->sin_addr.s_addr;
1384 fcntl(*plogfd, F_SETFL, O_NONBLOCK);
1385 }
1386 else if ((*plogfd = socket(logsrv->addr.ss_family, SOCK_DGRAM,
1387 (logsrv->addr.ss_family == AF_UNIX) ? 0 : IPPROTO_UDP)) < 0) {
Willy Tarreauc98aebc2018-03-20 11:17:29 +01001388 static char once;
1389
1390 if (!once) {
1391 once = 1; /* note: no need for atomic ops here */
Willy Tarreau251fe342018-11-12 07:00:11 +01001392 ha_alert("socket() failed in logger #%d: %s (errno=%d)\n",
Willy Tarreauc98aebc2018-03-20 11:17:29 +01001393 nblogger, strerror(errno), errno);
1394 }
Willy Tarreauc7c7be22014-06-23 18:07:15 +02001395 continue;
William Lallemanda8b26712018-11-13 18:30:12 +01001396 } else {
1397 /* we don't want to receive anything on this socket */
1398 setsockopt(*plogfd, SOL_SOCKET, SO_RCVBUF, &zero, sizeof(zero));
1399 /* does nothing under Linux, maybe needed for others */
1400 shutdown(*plogfd, SHUT_RD);
1401 fcntl(*plogfd, F_SETFD, fcntl(*plogfd, F_GETFD, FD_CLOEXEC) | FD_CLOEXEC);
Willy Tarreauc7c7be22014-06-23 18:07:15 +02001402 }
Willy Tarreauc7c7be22014-06-23 18:07:15 +02001403 }
1404
Dragan Dosen1322d092015-09-22 16:05:32 +02001405 switch (logsrv->format) {
1406 case LOG_FORMAT_RFC3164:
1407 hdr = logheader;
Dragan Dosen0b85ece2015-09-25 19:17:44 +02001408 hdr_ptr = update_log_hdr(time);
Dragan Dosen1322d092015-09-22 16:05:32 +02001409 break;
1410
1411 case LOG_FORMAT_RFC5424:
1412 hdr = logheader_rfc5424;
Dragan Dosen0b85ece2015-09-25 19:17:44 +02001413 hdr_ptr = update_log_hdr_rfc5424(time);
Dragan Dosen0b85ece2015-09-25 19:17:44 +02001414 sd_max = sd_size; /* the SD part allowed only in RFC5424 */
Dragan Dosen1322d092015-09-22 16:05:32 +02001415 break;
1416
Willy Tarreaue8746a02018-11-12 08:45:00 +01001417 case LOG_FORMAT_SHORT:
1418 /* all fields are known, skip the header generation */
1419 hdr = logheader_short;
1420 hdr[0] = '<';
1421 hdr[1] = '0' + MAX(level, logsrv->minlvl);
1422 hdr[2] = '>';
1423 hdr_ptr = hdr;
1424 hdr_max = 3;
1425 maxlen = logsrv->maxlen - hdr_max;
1426 max = MIN(size, maxlen) - 1;
1427 goto send;
1428
Willy Tarreauc1b06452018-11-12 11:57:56 +01001429 case LOG_FORMAT_RAW:
1430 /* all fields are known, skip the header generation */
1431 hdr_ptr = hdr = "";
1432 hdr_max = 0;
1433 maxlen = logsrv->maxlen;
1434 max = MIN(size, maxlen) - 1;
1435 goto send;
1436
Dragan Dosen1322d092015-09-22 16:05:32 +02001437 default:
1438 continue; /* must never happen */
1439 }
1440
1441 hdr_size = hdr_ptr - hdr;
1442
Willy Tarreaubaaee002006-06-26 02:48:02 +02001443 /* For each target, we may have a different facility.
1444 * We can also have a different log level for each message.
1445 * This induces variations in the message header length.
1446 * Since we don't want to recompute it each time, nor copy it every
1447 * time, we only change the facility in the pre-computed header,
1448 * and we change the pointer to the header accordingly.
1449 */
William Lallemand0f99e342011-10-12 17:50:54 +02001450 fac_level = (logsrv->facility << 3) + MAX(level, logsrv->minlvl);
Dragan Dosen1322d092015-09-22 16:05:32 +02001451 hdr_ptr = hdr + 3; /* last digit of the log level */
Willy Tarreaubaaee002006-06-26 02:48:02 +02001452 do {
Dragan Dosen59cee972015-09-19 22:09:02 +02001453 *hdr_ptr = '0' + fac_level % 10;
Willy Tarreaubaaee002006-06-26 02:48:02 +02001454 fac_level /= 10;
Dragan Dosen59cee972015-09-19 22:09:02 +02001455 hdr_ptr--;
Dragan Dosen1322d092015-09-22 16:05:32 +02001456 } while (fac_level && hdr_ptr > hdr);
Dragan Dosen59cee972015-09-19 22:09:02 +02001457 *hdr_ptr = '<';
William Lallemand2a4a44f2012-02-06 16:00:33 +01001458
Dragan Dosen1322d092015-09-22 16:05:32 +02001459 hdr_max = hdr_size - (hdr_ptr - hdr);
Dragan Dosen59cee972015-09-19 22:09:02 +02001460
Dragan Dosen43885c72015-10-01 13:18:13 +02001461 /* time-based header */
Dragan Dosen59cee972015-09-19 22:09:02 +02001462 if (unlikely(hdr_size >= logsrv->maxlen)) {
1463 hdr_max = MIN(hdr_max, logsrv->maxlen) - 1;
Dragan Dosen0b85ece2015-09-25 19:17:44 +02001464 sd_max = 0;
Dragan Dosen59cee972015-09-19 22:09:02 +02001465 goto send;
1466 }
1467
Dragan Dosen68d2e3a2015-09-19 22:35:44 +02001468 maxlen = logsrv->maxlen - hdr_max;
Dragan Dosen68d2e3a2015-09-19 22:35:44 +02001469
Dragan Dosen43885c72015-10-01 13:18:13 +02001470 /* tag */
Willy Tarreau843b7cb2018-07-13 10:54:26 +02001471 tag_max = tag->data;
Dragan Dosen43885c72015-10-01 13:18:13 +02001472 if (unlikely(tag_max >= maxlen)) {
1473 tag_max = maxlen - 1;
1474 sd_max = 0;
1475 goto send;
1476 }
1477
1478 maxlen -= tag_max;
1479
1480 /* first pid separator */
Willy Tarreau843b7cb2018-07-13 10:54:26 +02001481 pid_sep1_max = log_formats[logsrv->format].pid.sep1.data;
Dragan Dosen43885c72015-10-01 13:18:13 +02001482 if (unlikely(pid_sep1_max >= maxlen)) {
1483 pid_sep1_max = maxlen - 1;
Dragan Dosen0b85ece2015-09-25 19:17:44 +02001484 sd_max = 0;
Dragan Dosen68d2e3a2015-09-19 22:35:44 +02001485 goto send;
1486 }
1487
Willy Tarreau843b7cb2018-07-13 10:54:26 +02001488 pid_sep1 = log_formats[logsrv->format].pid.sep1.area;
Dragan Dosen43885c72015-10-01 13:18:13 +02001489 maxlen -= pid_sep1_max;
Dragan Dosen59cee972015-09-19 22:09:02 +02001490
Dragan Dosen43885c72015-10-01 13:18:13 +02001491 /* pid */
Willy Tarreau843b7cb2018-07-13 10:54:26 +02001492 pid_max = pid.data;
Dragan Dosen43885c72015-10-01 13:18:13 +02001493 if (unlikely(pid_max >= maxlen)) {
1494 pid_max = maxlen - 1;
1495 sd_max = 0;
1496 goto send;
1497 }
1498
1499 maxlen -= pid_max;
1500
1501 /* second pid separator */
Willy Tarreau843b7cb2018-07-13 10:54:26 +02001502 pid_sep2_max = log_formats[logsrv->format].pid.sep2.data;
Dragan Dosen43885c72015-10-01 13:18:13 +02001503 if (unlikely(pid_sep2_max >= maxlen)) {
1504 pid_sep2_max = maxlen - 1;
1505 sd_max = 0;
1506 goto send;
1507 }
1508
Willy Tarreau843b7cb2018-07-13 10:54:26 +02001509 pid_sep2 = log_formats[logsrv->format].pid.sep2.area;
Dragan Dosen43885c72015-10-01 13:18:13 +02001510 maxlen -= pid_sep2_max;
1511
1512 /* structured-data */
Dragan Dosen0b85ece2015-09-25 19:17:44 +02001513 if (sd_max >= maxlen) {
1514 sd_max = maxlen - 1;
1515 goto send;
1516 }
Dragan Dosen59cee972015-09-19 22:09:02 +02001517
Dragan Dosen5b78d9b2015-09-28 16:01:03 +02001518 max = MIN(size, maxlen - sd_max) - 1;
Dragan Dosen59cee972015-09-19 22:09:02 +02001519send:
Dragan Dosen59cee972015-09-19 22:09:02 +02001520 iovec[0].iov_base = hdr_ptr;
Dragan Dosen43885c72015-10-01 13:18:13 +02001521 iovec[0].iov_len = hdr_max;
Willy Tarreau843b7cb2018-07-13 10:54:26 +02001522 iovec[1].iov_base = tag->area;
Dragan Dosen43885c72015-10-01 13:18:13 +02001523 iovec[1].iov_len = tag_max;
1524 iovec[2].iov_base = pid_sep1;
1525 iovec[2].iov_len = pid_sep1_max;
Willy Tarreau843b7cb2018-07-13 10:54:26 +02001526 iovec[3].iov_base = pid.area;
Dragan Dosen43885c72015-10-01 13:18:13 +02001527 iovec[3].iov_len = pid_max;
1528 iovec[4].iov_base = pid_sep2;
1529 iovec[4].iov_len = pid_sep2_max;
1530 iovec[5].iov_base = sd;
1531 iovec[5].iov_len = sd_max;
1532 iovec[6].iov_base = dataptr;
1533 iovec[6].iov_len = max;
1534 iovec[7].iov_base = "\n"; /* insert a \n at the end of the message */
1535 iovec[7].iov_len = 1;
Dragan Dosen609ac2a2015-09-16 18:25:42 +02001536
Willy Tarreau5a32ecc2018-11-12 07:34:59 +01001537 if (logsrv->addr.ss_family == AF_UNSPEC) {
1538 /* the target is a direct file descriptor */
1539 sent = writev(*plogfd, iovec, 8);
1540 }
1541 else {
1542 msghdr.msg_name = (struct sockaddr *)&logsrv->addr;
1543 msghdr.msg_namelen = get_addr_len(&logsrv->addr);
Dragan Dosen609ac2a2015-09-16 18:25:42 +02001544
Willy Tarreau5a32ecc2018-11-12 07:34:59 +01001545 sent = sendmsg(*plogfd, &msghdr, MSG_DONTWAIT | MSG_NOSIGNAL);
1546 }
Willy Tarreau18324f52014-06-27 18:10:07 +02001547
Robert Tsai81ae1952007-12-05 10:47:29 +01001548 if (sent < 0) {
Willy Tarreauc98aebc2018-03-20 11:17:29 +01001549 static char once;
1550
Willy Tarreau13ef7732018-11-12 07:25:28 +01001551 if (errno == EAGAIN)
1552 HA_ATOMIC_ADD(&dropped_logs, 1);
1553 else if (!once) {
Willy Tarreauc98aebc2018-03-20 11:17:29 +01001554 once = 1; /* note: no need for atomic ops here */
Willy Tarreau5a32ecc2018-11-12 07:34:59 +01001555 ha_alert("sendmsg()/writev() failed in logger #%d: %s (errno=%d)\n",
Willy Tarreauc98aebc2018-03-20 11:17:29 +01001556 nblogger, strerror(errno), errno);
1557 }
Robert Tsai81ae1952007-12-05 10:47:29 +01001558 }
Willy Tarreaubaaee002006-06-26 02:48:02 +02001559 }
1560}
1561
William Lallemandbddd4fd2012-02-27 11:23:10 +01001562extern fd_set hdr_encode_map[];
1563extern fd_set url_encode_map[];
Thierry FOURNIERd048d8b2014-03-13 16:46:18 +01001564extern fd_set http_encode_map[];
William Lallemandbddd4fd2012-02-27 11:23:10 +01001565
Willy Tarreaubaaee002006-06-26 02:48:02 +02001566
Willy Tarreauc89ccb62012-04-05 21:18:22 +02001567const 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 +01001568const char sess_set_cookie[8] = "NPDIRU67"; /* No set-cookie, Set-cookie found and left unchanged (passive),
1569 Set-cookie Deleted, Set-Cookie Inserted, Set-cookie Rewritten,
1570 Set-cookie Updated, unknown, unknown */
1571
William Lallemand1d705562012-03-12 12:46:41 +01001572/*
1573 * try to write a character if there is enough space, or goto out
1574 */
William Lallemandbddd4fd2012-02-27 11:23:10 +01001575#define LOGCHAR(x) do { \
William Lallemand1d705562012-03-12 12:46:41 +01001576 if (tmplog < dst + maxsize - 1) { \
William Lallemandbddd4fd2012-02-27 11:23:10 +01001577 *(tmplog++) = (x); \
1578 } else { \
1579 goto out; \
1580 } \
1581 } while(0)
1582
Dragan Dosen835b9212016-02-12 13:23:03 +01001583
Willy Tarreaub6b3df32018-11-26 16:31:20 +01001584/* Initializes some log data at boot */
1585static void init_log()
Dragan Dosen835b9212016-02-12 13:23:03 +01001586{
1587 char *tmp;
Willy Tarreaue10cd482018-09-10 18:16:53 +02001588 int i;
Dragan Dosen835b9212016-02-12 13:23:03 +01001589
1590 /* Initialize the escape map for the RFC5424 structured-data : '"\]'
1591 * inside PARAM-VALUE should be escaped with '\' as prefix.
1592 * See https://tools.ietf.org/html/rfc5424#section-6.3.3 for more
1593 * details.
1594 */
1595 memset(rfc5424_escape_map, 0, sizeof(rfc5424_escape_map));
1596
1597 tmp = "\"\\]";
1598 while (*tmp) {
1599 FD_SET(*tmp, rfc5424_escape_map);
1600 tmp++;
1601 }
Willy Tarreaue10cd482018-09-10 18:16:53 +02001602
1603 /* initialize the log header encoding map : '{|}"#' should be encoded with
1604 * '#' as prefix, as well as non-printable characters ( <32 or >= 127 ).
1605 * URL encoding only requires '"', '#' to be encoded as well as non-
1606 * printable characters above.
1607 */
1608 memset(hdr_encode_map, 0, sizeof(hdr_encode_map));
1609 memset(url_encode_map, 0, sizeof(url_encode_map));
1610 for (i = 0; i < 32; i++) {
1611 FD_SET(i, hdr_encode_map);
1612 FD_SET(i, url_encode_map);
1613 }
1614 for (i = 127; i < 256; i++) {
1615 FD_SET(i, hdr_encode_map);
1616 FD_SET(i, url_encode_map);
1617 }
1618
1619 tmp = "\"#{|}";
1620 while (*tmp) {
1621 FD_SET(*tmp, hdr_encode_map);
1622 tmp++;
1623 }
1624
1625 tmp = "\"#";
1626 while (*tmp) {
1627 FD_SET(*tmp, url_encode_map);
1628 tmp++;
1629 }
1630
1631 /* initialize the http header encoding map. The draft httpbis define the
1632 * header content as:
1633 *
1634 * HTTP-message = start-line
1635 * *( header-field CRLF )
1636 * CRLF
1637 * [ message-body ]
1638 * header-field = field-name ":" OWS field-value OWS
1639 * field-value = *( field-content / obs-fold )
1640 * field-content = field-vchar [ 1*( SP / HTAB ) field-vchar ]
1641 * obs-fold = CRLF 1*( SP / HTAB )
1642 * field-vchar = VCHAR / obs-text
1643 * VCHAR = %x21-7E
1644 * obs-text = %x80-FF
1645 *
1646 * All the chars are encoded except "VCHAR", "obs-text", SP and HTAB.
1647 * The encoded chars are form 0x00 to 0x08, 0x0a to 0x1f and 0x7f. The
Joseph Herlant85b40592018-11-15 12:10:04 -08001648 * "obs-fold" is voluntarily forgotten because haproxy remove this.
Willy Tarreaue10cd482018-09-10 18:16:53 +02001649 */
1650 memset(http_encode_map, 0, sizeof(http_encode_map));
1651 for (i = 0x00; i <= 0x08; i++)
1652 FD_SET(i, http_encode_map);
1653 for (i = 0x0a; i <= 0x1f; i++)
1654 FD_SET(i, http_encode_map);
1655 FD_SET(0x7f, http_encode_map);
Dragan Dosen835b9212016-02-12 13:23:03 +01001656}
William Lallemand1d705562012-03-12 12:46:41 +01001657
Willy Tarreaub6b3df32018-11-26 16:31:20 +01001658INITCALL0(STG_PREPARE, init_log);
1659
Christopher Fauletcd7879a2017-10-27 13:53:47 +02001660static int init_log_buffers_per_thread()
1661{
1662 return init_log_buffers();
1663}
1664
1665static void deinit_log_buffers_per_thread()
1666{
1667 deinit_log_buffers();
1668}
1669
Christopher Faulet0132d062017-07-26 15:33:35 +02001670/* Initialize log buffers used for syslog messages */
1671int init_log_buffers()
1672{
1673 logheader = my_realloc2(logheader, global.max_syslog_len + 1);
1674 logheader_rfc5424 = my_realloc2(logheader_rfc5424, global.max_syslog_len + 1);
1675 logline = my_realloc2(logline, global.max_syslog_len + 1);
1676 logline_rfc5424 = my_realloc2(logline_rfc5424, global.max_syslog_len + 1);
1677 if (!logheader || !logline_rfc5424 || !logline || !logline_rfc5424)
1678 return 0;
1679 return 1;
1680}
1681
1682/* Deinitialize log buffers used for syslog messages */
1683void deinit_log_buffers()
1684{
1685 free(logheader);
1686 free(logheader_rfc5424);
1687 free(logline);
1688 free(logline_rfc5424);
Christopher Fauletd4696382017-10-24 11:44:05 +02001689 free(startup_logs);
Christopher Faulet0132d062017-07-26 15:33:35 +02001690 logheader = NULL;
1691 logheader_rfc5424 = NULL;
1692 logline = NULL;
1693 logline_rfc5424 = NULL;
Christopher Fauletd4696382017-10-24 11:44:05 +02001694 startup_logs = NULL;
Christopher Faulet0132d062017-07-26 15:33:35 +02001695}
1696
Willy Tarreaudf974472012-12-28 02:44:01 +01001697/* Builds a log line in <dst> based on <list_format>, and stops before reaching
1698 * <maxsize> characters. Returns the size of the output string in characters,
1699 * not counting the trailing zero which is always added if the resulting size
Willy Tarreau09bb27c2018-09-05 16:55:15 +02001700 * is not zero. It requires a valid session and optionally a stream. If the
1701 * stream is NULL, default values will be assumed for the stream part.
Willy Tarreaudf974472012-12-28 02:44:01 +01001702 */
Willy Tarreau43c538e2018-09-05 14:58:15 +02001703int sess_build_logline(struct session *sess, struct stream *s, char *dst, size_t maxsize, struct list *list_format)
Willy Tarreaubaaee002006-06-26 02:48:02 +02001704{
Willy Tarreaue36cbcb2015-04-03 15:40:56 +02001705 struct proxy *fe = sess->fe;
Willy Tarreau09bb27c2018-09-05 16:55:15 +02001706 struct proxy *be;
1707 struct http_txn *txn;
1708 const struct strm_logs *logs;
1709 const struct connection *be_conn;
1710 unsigned int s_flags;
1711 unsigned int uniq_id;
Willy Tarreau83061a82018-07-13 11:56:34 +02001712 struct buffer chunk;
William Lallemandbddd4fd2012-02-27 11:23:10 +01001713 char *uri;
Andrew Hayworth0ebc55f2015-04-27 21:37:03 +00001714 char *spc;
Andrew Hayworthe63ac872015-07-31 16:14:16 +00001715 char *qmark;
Andrew Hayworth0ebc55f2015-04-27 21:37:03 +00001716 char *end;
Willy Tarreaufe944602007-10-25 10:34:16 +02001717 struct tm tm;
William Lallemandbddd4fd2012-02-27 11:23:10 +01001718 int t_request;
1719 int hdr;
1720 int last_isspace = 1;
Andrew Hayworth0ebc55f2015-04-27 21:37:03 +00001721 int nspaces = 0;
Willy Tarreaub1a2faf2012-03-19 16:51:53 +01001722 char *tmplog;
William Lallemand1d705562012-03-12 12:46:41 +01001723 char *ret;
1724 int iret;
William Lallemandbddd4fd2012-02-27 11:23:10 +01001725 struct logformat_node *tmp;
Thierry FOURNIER / OZON.IO4cac3592016-07-28 17:19:45 +02001726 struct timeval tv;
Willy Tarreau09bb27c2018-09-05 16:55:15 +02001727 struct strm_logs tmp_strm_log;
Willy Tarreaubaaee002006-06-26 02:48:02 +02001728
William Lallemandbddd4fd2012-02-27 11:23:10 +01001729 /* FIXME: let's limit ourselves to frontend logging for now. */
Willy Tarreaubaaee002006-06-26 02:48:02 +02001730
Willy Tarreau09bb27c2018-09-05 16:55:15 +02001731 if (likely(s)) {
1732 be = s->be;
1733 txn = s->txn;
1734 be_conn = cs_conn(objt_cs(s->si[1].end));
1735 s_flags = s->flags;
1736 uniq_id = s->uniq_id;
1737 logs = &s->logs;
1738 } else {
1739 /* we have no stream so we first need to initialize a few
1740 * things that are needed later. We do increment the request
1741 * ID so that it's uniquely assigned to this request just as
1742 * if the request had reached the point of being processed.
1743 * A request error is reported as it's the only element we have
1744 * here and which justifies emitting such a log.
1745 */
1746 be = fe;
1747 txn = NULL;
1748 be_conn = NULL;
1749 s_flags = SF_ERR_PRXCOND | SF_FINST_R;
1750 uniq_id = HA_ATOMIC_XADD(&global.req_count, 1);
1751
1752 /* prepare a valid log structure */
1753 tmp_strm_log.tv_accept = sess->tv_accept;
1754 tmp_strm_log.accept_date = sess->accept_date;
1755 tmp_strm_log.t_handshake = sess->t_handshake;
1756 tmp_strm_log.t_idle = tv_ms_elapsed(&sess->tv_accept, &now) - sess->t_handshake;
1757 tv_zero(&tmp_strm_log.tv_request);
1758 tmp_strm_log.t_queue = -1;
1759 tmp_strm_log.t_connect = -1;
1760 tmp_strm_log.t_data = -1;
1761 tmp_strm_log.t_close = tv_ms_elapsed(&sess->tv_accept, &now);
1762 tmp_strm_log.bytes_in = 0;
1763 tmp_strm_log.bytes_out = 0;
1764 tmp_strm_log.prx_queue_pos = 0;
1765 tmp_strm_log.srv_queue_pos = 0;
1766
1767 logs = &tmp_strm_log;
1768 }
1769
William Lallemandbddd4fd2012-02-27 11:23:10 +01001770 t_request = -1;
Willy Tarreau372ac5a2018-09-05 15:16:23 +02001771 if (tv_isge(&logs->tv_request, &logs->tv_accept))
1772 t_request = tv_ms_elapsed(&logs->tv_accept, &logs->tv_request);
William Lallemandbddd4fd2012-02-27 11:23:10 +01001773
William Lallemand1d705562012-03-12 12:46:41 +01001774 tmplog = dst;
Willy Tarreauc9bd0cc2009-05-10 11:57:02 +02001775
William Lallemandbddd4fd2012-02-27 11:23:10 +01001776 /* fill logbuffer */
William Lallemand1d705562012-03-12 12:46:41 +01001777 if (LIST_ISEMPTY(list_format))
1778 return 0;
William Lallemandbddd4fd2012-02-27 11:23:10 +01001779
William Lallemand1d705562012-03-12 12:46:41 +01001780 list_for_each_entry(tmp, list_format, list) {
Willy Tarreaub363a1f2013-10-01 10:45:07 +02001781 struct connection *conn;
Willy Tarreau4f653562012-10-12 19:48:16 +02001782 const char *src = NULL;
Willy Tarreauc8368452012-12-21 00:09:23 +01001783 struct sample *key;
Willy Tarreau83061a82018-07-13 11:56:34 +02001784 const struct buffer empty = { };
William Lallemandbddd4fd2012-02-27 11:23:10 +01001785
Willy Tarreauc8368452012-12-21 00:09:23 +01001786 switch (tmp->type) {
William Lallemand1d705562012-03-12 12:46:41 +01001787 case LOG_FMT_SEPARATOR:
William Lallemandbddd4fd2012-02-27 11:23:10 +01001788 if (!last_isspace) {
1789 LOGCHAR(' ');
1790 last_isspace = 1;
William Lallemandbddd4fd2012-02-27 11:23:10 +01001791 }
1792 break;
1793
William Lallemand1d705562012-03-12 12:46:41 +01001794 case LOG_FMT_TEXT: // text
William Lallemandbddd4fd2012-02-27 11:23:10 +01001795 src = tmp->arg;
William Lallemand5f232402012-04-05 18:02:55 +02001796 iret = strlcpy2(tmplog, src, dst + maxsize - tmplog);
William Lallemand1d705562012-03-12 12:46:41 +01001797 if (iret == 0)
William Lallemandbddd4fd2012-02-27 11:23:10 +01001798 goto out;
William Lallemand1d705562012-03-12 12:46:41 +01001799 tmplog += iret;
William Lallemandbddd4fd2012-02-27 11:23:10 +01001800 last_isspace = 0;
1801 break;
1802
Willy Tarreauc8368452012-12-21 00:09:23 +01001803 case LOG_FMT_EXPR: // sample expression, may be request or response
1804 key = NULL;
1805 if (tmp->options & LOG_OPT_REQ_CAP)
Adis Nezirovic79beb242015-07-06 15:41:02 +02001806 key = sample_fetch_as_type(be, sess, s, SMP_OPT_DIR_REQ|SMP_OPT_FINAL, tmp->expr, SMP_T_STR);
Willy Tarreauc8368452012-12-21 00:09:23 +01001807 if (!key && (tmp->options & LOG_OPT_RES_CAP))
Adis Nezirovic79beb242015-07-06 15:41:02 +02001808 key = sample_fetch_as_type(be, sess, s, SMP_OPT_DIR_RES|SMP_OPT_FINAL, tmp->expr, SMP_T_STR);
Thierry FOURNIERd048d8b2014-03-13 16:46:18 +01001809 if (tmp->options & LOG_OPT_HTTP)
Dragan Dosen835b9212016-02-12 13:23:03 +01001810 ret = lf_encode_chunk(tmplog, dst + maxsize,
1811 '%', http_encode_map, key ? &key->data.u.str : &empty, tmp);
Thierry FOURNIERd048d8b2014-03-13 16:46:18 +01001812 else
Willy Tarreau843b7cb2018-07-13 10:54:26 +02001813 ret = lf_text_len(tmplog,
1814 key ? key->data.u.str.area : NULL,
1815 key ? key->data.u.str.data : 0,
1816 dst + maxsize - tmplog,
1817 tmp);
Willy Tarreauc8368452012-12-21 00:09:23 +01001818 if (ret == 0)
1819 goto out;
1820 tmplog = ret;
1821 last_isspace = 0;
1822 break;
1823
Willy Tarreau2beef582012-12-20 17:22:52 +01001824 case LOG_FMT_CLIENTIP: // %ci
Willy Tarreau9ad7bd42015-04-03 19:19:59 +02001825 conn = objt_conn(sess->origin);
Willy Tarreaub363a1f2013-10-01 10:45:07 +02001826 if (conn)
1827 ret = lf_ip(tmplog, (struct sockaddr *)&conn->addr.from, dst + maxsize - tmplog, tmp);
1828 else
1829 ret = lf_text_len(tmplog, NULL, 0, dst + maxsize - tmplog, tmp);
William Lallemand1d705562012-03-12 12:46:41 +01001830 if (ret == NULL)
William Lallemandbddd4fd2012-02-27 11:23:10 +01001831 goto out;
William Lallemand1d705562012-03-12 12:46:41 +01001832 tmplog = ret;
William Lallemandbddd4fd2012-02-27 11:23:10 +01001833 last_isspace = 0;
1834 break;
1835
Willy Tarreau2beef582012-12-20 17:22:52 +01001836 case LOG_FMT_CLIENTPORT: // %cp
Willy Tarreau9ad7bd42015-04-03 19:19:59 +02001837 conn = objt_conn(sess->origin);
Willy Tarreaub363a1f2013-10-01 10:45:07 +02001838 if (conn) {
1839 if (conn->addr.from.ss_family == AF_UNIX) {
Willy Tarreaufb0afa72015-04-03 14:46:27 +02001840 ret = ltoa_o(sess->listener->luid, tmplog, dst + maxsize - tmplog);
Willy Tarreaub363a1f2013-10-01 10:45:07 +02001841 } else {
1842 ret = lf_port(tmplog, (struct sockaddr *)&conn->addr.from,
1843 dst + maxsize - tmplog, tmp);
1844 }
William Lallemand5f232402012-04-05 18:02:55 +02001845 }
Willy Tarreaub363a1f2013-10-01 10:45:07 +02001846 else
1847 ret = lf_text_len(tmplog, NULL, 0, dst + maxsize - tmplog, tmp);
1848
William Lallemand5f232402012-04-05 18:02:55 +02001849 if (ret == NULL)
1850 goto out;
1851 tmplog = ret;
1852 last_isspace = 0;
1853 break;
1854
Willy Tarreau2beef582012-12-20 17:22:52 +01001855 case LOG_FMT_FRONTENDIP: // %fi
Willy Tarreau9ad7bd42015-04-03 19:19:59 +02001856 conn = objt_conn(sess->origin);
Willy Tarreaub363a1f2013-10-01 10:45:07 +02001857 if (conn) {
1858 conn_get_to_addr(conn);
1859 ret = lf_ip(tmplog, (struct sockaddr *)&conn->addr.to, dst + maxsize - tmplog, tmp);
1860 }
1861 else
1862 ret = lf_text_len(tmplog, NULL, 0, dst + maxsize - tmplog, tmp);
1863
William Lallemand1d705562012-03-12 12:46:41 +01001864 if (ret == NULL)
William Lallemandbddd4fd2012-02-27 11:23:10 +01001865 goto out;
William Lallemand1d705562012-03-12 12:46:41 +01001866 tmplog = ret;
William Lallemandbddd4fd2012-02-27 11:23:10 +01001867 last_isspace = 0;
1868 break;
1869
Willy Tarreau2beef582012-12-20 17:22:52 +01001870 case LOG_FMT_FRONTENDPORT: // %fp
Willy Tarreau9ad7bd42015-04-03 19:19:59 +02001871 conn = objt_conn(sess->origin);
Willy Tarreaub363a1f2013-10-01 10:45:07 +02001872 if (conn) {
1873 conn_get_to_addr(conn);
1874 if (conn->addr.to.ss_family == AF_UNIX)
Willy Tarreaufb0afa72015-04-03 14:46:27 +02001875 ret = ltoa_o(sess->listener->luid, tmplog, dst + maxsize - tmplog);
Willy Tarreaub363a1f2013-10-01 10:45:07 +02001876 else
1877 ret = lf_port(tmplog, (struct sockaddr *)&conn->addr.to, dst + maxsize - tmplog, tmp);
William Lallemand5f232402012-04-05 18:02:55 +02001878 }
Willy Tarreaub363a1f2013-10-01 10:45:07 +02001879 else
1880 ret = lf_text_len(tmplog, NULL, 0, dst + maxsize - tmplog, tmp);
1881
William Lallemand5f232402012-04-05 18:02:55 +02001882 if (ret == NULL)
1883 goto out;
1884 tmplog = ret;
1885 last_isspace = 0;
1886 break;
1887
Willy Tarreau2beef582012-12-20 17:22:52 +01001888 case LOG_FMT_BACKENDIP: // %bi
Willy Tarreau2393c5b2018-09-05 15:24:56 +02001889 if (be_conn)
1890 ret = lf_ip(tmplog, (const struct sockaddr *)&be_conn->addr.from, dst + maxsize - tmplog, tmp);
Willy Tarreaub363a1f2013-10-01 10:45:07 +02001891 else
1892 ret = lf_text_len(tmplog, NULL, 0, dst + maxsize - tmplog, tmp);
1893
William Lallemand1d705562012-03-12 12:46:41 +01001894 if (ret == NULL)
William Lallemandb7ff6a32012-03-02 14:35:21 +01001895 goto out;
William Lallemand1d705562012-03-12 12:46:41 +01001896 tmplog = ret;
William Lallemandb7ff6a32012-03-02 14:35:21 +01001897 last_isspace = 0;
1898 break;
1899
Willy Tarreau2beef582012-12-20 17:22:52 +01001900 case LOG_FMT_BACKENDPORT: // %bp
Willy Tarreau2393c5b2018-09-05 15:24:56 +02001901 if (be_conn)
1902 ret = lf_port(tmplog, (struct sockaddr *)&be_conn->addr.from, dst + maxsize - tmplog, tmp);
Willy Tarreaub363a1f2013-10-01 10:45:07 +02001903 else
1904 ret = lf_text_len(tmplog, NULL, 0, dst + maxsize - tmplog, tmp);
1905
William Lallemand5f232402012-04-05 18:02:55 +02001906 if (ret == NULL)
1907 goto out;
1908 tmplog = ret;
1909 last_isspace = 0;
1910 break;
1911
Willy Tarreau2beef582012-12-20 17:22:52 +01001912 case LOG_FMT_SERVERIP: // %si
Willy Tarreau2393c5b2018-09-05 15:24:56 +02001913 if (be_conn)
1914 ret = lf_ip(tmplog, (struct sockaddr *)&be_conn->addr.to, dst + maxsize - tmplog, tmp);
Willy Tarreaub363a1f2013-10-01 10:45:07 +02001915 else
1916 ret = lf_text_len(tmplog, NULL, 0, dst + maxsize - tmplog, tmp);
1917
William Lallemand5f232402012-04-05 18:02:55 +02001918 if (ret == NULL)
1919 goto out;
1920 tmplog = ret;
1921 last_isspace = 0;
1922 break;
1923
Willy Tarreau2beef582012-12-20 17:22:52 +01001924 case LOG_FMT_SERVERPORT: // %sp
Willy Tarreau2393c5b2018-09-05 15:24:56 +02001925 if (be_conn)
1926 ret = lf_port(tmplog, (struct sockaddr *)&be_conn->addr.to, dst + maxsize - tmplog, tmp);
Willy Tarreaub363a1f2013-10-01 10:45:07 +02001927 else
1928 ret = lf_text_len(tmplog, NULL, 0, dst + maxsize - tmplog, tmp);
1929
William Lallemand1d705562012-03-12 12:46:41 +01001930 if (ret == NULL)
William Lallemandb7ff6a32012-03-02 14:35:21 +01001931 goto out;
William Lallemand1d705562012-03-12 12:46:41 +01001932 tmplog = ret;
William Lallemandb7ff6a32012-03-02 14:35:21 +01001933 last_isspace = 0;
1934 break;
1935
Thierry FOURNIER / OZON.IO4cac3592016-07-28 17:19:45 +02001936 case LOG_FMT_DATE: // %t = accept date
Willy Tarreau372ac5a2018-09-05 15:16:23 +02001937 get_localtime(logs->accept_date.tv_sec, &tm);
1938 ret = date2str_log(tmplog, &tm, &logs->accept_date, dst + maxsize - tmplog);
William Lallemand1d705562012-03-12 12:46:41 +01001939 if (ret == NULL)
William Lallemandbddd4fd2012-02-27 11:23:10 +01001940 goto out;
William Lallemand1d705562012-03-12 12:46:41 +01001941 tmplog = ret;
William Lallemandbddd4fd2012-02-27 11:23:10 +01001942 last_isspace = 0;
1943 break;
1944
Thierry FOURNIER / OZON.IO4cac3592016-07-28 17:19:45 +02001945 case LOG_FMT_tr: // %tr = start of request date
1946 /* Note that the timers are valid if we get here */
Willy Tarreau372ac5a2018-09-05 15:16:23 +02001947 tv_ms_add(&tv, &logs->accept_date, logs->t_idle >= 0 ? logs->t_idle + logs->t_handshake : 0);
Thierry FOURNIER / OZON.IO4cac3592016-07-28 17:19:45 +02001948 get_localtime(tv.tv_sec, &tm);
1949 ret = date2str_log(tmplog, &tm, &tv, dst + maxsize - tmplog);
1950 if (ret == NULL)
1951 goto out;
1952 tmplog = ret;
1953 last_isspace = 0;
1954 break;
1955
1956 case LOG_FMT_DATEGMT: // %T = accept date, GMT
Willy Tarreau372ac5a2018-09-05 15:16:23 +02001957 get_gmtime(logs->accept_date.tv_sec, &tm);
William Lallemand5f232402012-04-05 18:02:55 +02001958 ret = gmt2str_log(tmplog, &tm, dst + maxsize - tmplog);
William Lallemand1d705562012-03-12 12:46:41 +01001959 if (ret == NULL)
William Lallemandbddd4fd2012-02-27 11:23:10 +01001960 goto out;
William Lallemand1d705562012-03-12 12:46:41 +01001961 tmplog = ret;
William Lallemandbddd4fd2012-02-27 11:23:10 +01001962 last_isspace = 0;
1963 break;
1964
Thierry FOURNIER / OZON.IO4cac3592016-07-28 17:19:45 +02001965 case LOG_FMT_trg: // %trg = start of request date, GMT
Willy Tarreau372ac5a2018-09-05 15:16:23 +02001966 tv_ms_add(&tv, &logs->accept_date, logs->t_idle >= 0 ? logs->t_idle + logs->t_handshake : 0);
Thierry FOURNIER / OZON.IO4cac3592016-07-28 17:19:45 +02001967 get_gmtime(tv.tv_sec, &tm);
1968 ret = gmt2str_log(tmplog, &tm, dst + maxsize - tmplog);
1969 if (ret == NULL)
1970 goto out;
1971 tmplog = ret;
1972 last_isspace = 0;
1973 break;
1974
1975 case LOG_FMT_DATELOCAL: // %Tl = accept date, local
Willy Tarreau372ac5a2018-09-05 15:16:23 +02001976 get_localtime(logs->accept_date.tv_sec, &tm);
1977 ret = localdate2str_log(tmplog, logs->accept_date.tv_sec, &tm, dst + maxsize - tmplog);
Yuxans Yao4e25b012012-10-19 10:36:09 +08001978 if (ret == NULL)
1979 goto out;
1980 tmplog = ret;
1981 last_isspace = 0;
1982 break;
1983
Thierry FOURNIER / OZON.IO4cac3592016-07-28 17:19:45 +02001984 case LOG_FMT_trl: // %trl = start of request date, local
Willy Tarreau372ac5a2018-09-05 15:16:23 +02001985 tv_ms_add(&tv, &logs->accept_date, logs->t_idle >= 0 ? logs->t_idle + logs->t_handshake : 0);
Thierry FOURNIER / OZON.IO4cac3592016-07-28 17:19:45 +02001986 get_localtime(tv.tv_sec, &tm);
1987 ret = localdate2str_log(tmplog, tv.tv_sec, &tm, dst + maxsize - tmplog);
1988 if (ret == NULL)
1989 goto out;
1990 tmplog = ret;
1991 last_isspace = 0;
1992 break;
1993
William Lallemand5f232402012-04-05 18:02:55 +02001994 case LOG_FMT_TS: // %Ts
Willy Tarreau372ac5a2018-09-05 15:16:23 +02001995 get_gmtime(logs->accept_date.tv_sec, &tm);
William Lallemand5f232402012-04-05 18:02:55 +02001996 if (tmp->options & LOG_OPT_HEXA) {
Willy Tarreau372ac5a2018-09-05 15:16:23 +02001997 iret = snprintf(tmplog, dst + maxsize - tmplog, "%04X", (unsigned int)logs->accept_date.tv_sec);
William Lallemand5f232402012-04-05 18:02:55 +02001998 if (iret < 0 || iret > dst + maxsize - tmplog)
1999 goto out;
2000 last_isspace = 0;
2001 tmplog += iret;
2002 } else {
Willy Tarreau372ac5a2018-09-05 15:16:23 +02002003 ret = ltoa_o(logs->accept_date.tv_sec, tmplog, dst + maxsize - tmplog);
William Lallemand5f232402012-04-05 18:02:55 +02002004 if (ret == NULL)
2005 goto out;
2006 tmplog = ret;
2007 last_isspace = 0;
2008 }
2009 break;
2010
William Lallemand1d705562012-03-12 12:46:41 +01002011 case LOG_FMT_MS: // %ms
William Lallemand5f232402012-04-05 18:02:55 +02002012 if (tmp->options & LOG_OPT_HEXA) {
Willy Tarreau372ac5a2018-09-05 15:16:23 +02002013 iret = snprintf(tmplog, dst + maxsize - tmplog, "%02X",(unsigned int)logs->accept_date.tv_usec/1000);
William Lallemand5f232402012-04-05 18:02:55 +02002014 if (iret < 0 || iret > dst + maxsize - tmplog)
2015 goto out;
2016 last_isspace = 0;
2017 tmplog += iret;
2018 } else {
2019 if ((dst + maxsize - tmplog) < 4)
William Lallemandbddd4fd2012-02-27 11:23:10 +01002020 goto out;
Willy Tarreau372ac5a2018-09-05 15:16:23 +02002021 ret = utoa_pad((unsigned int)logs->accept_date.tv_usec/1000,
Willy Tarreau9e60cd82013-01-24 01:18:16 +01002022 tmplog, 4);
2023 if (ret == NULL)
William Lallemand51b5dca2012-03-26 17:52:55 +02002024 goto out;
Willy Tarreau9e60cd82013-01-24 01:18:16 +01002025 tmplog = ret;
William Lallemandbddd4fd2012-02-27 11:23:10 +01002026 last_isspace = 0;
William Lallemand5f232402012-04-05 18:02:55 +02002027 }
2028 break;
William Lallemandbddd4fd2012-02-27 11:23:10 +01002029
William Lallemand1d705562012-03-12 12:46:41 +01002030 case LOG_FMT_FRONTEND: // %f
William Lallemandbddd4fd2012-02-27 11:23:10 +01002031 src = fe->id;
William Lallemand5f232402012-04-05 18:02:55 +02002032 ret = lf_text(tmplog, src, dst + maxsize - tmplog, tmp);
William Lallemand1d705562012-03-12 12:46:41 +01002033 if (ret == NULL)
William Lallemandbddd4fd2012-02-27 11:23:10 +01002034 goto out;
William Lallemand1d705562012-03-12 12:46:41 +01002035 tmplog = ret;
William Lallemand51b5dca2012-03-26 17:52:55 +02002036 last_isspace = 0;
William Lallemandbddd4fd2012-02-27 11:23:10 +01002037 break;
2038
Willy Tarreau773d65f2012-10-12 14:56:11 +02002039 case LOG_FMT_FRONTEND_XPRT: // %ft
2040 src = fe->id;
2041 if (tmp->options & LOG_OPT_QUOTE)
2042 LOGCHAR('"');
2043 iret = strlcpy2(tmplog, src, dst + maxsize - tmplog);
2044 if (iret == 0)
2045 goto out;
2046 tmplog += iret;
Willy Tarreaua261e9b2016-12-22 20:44:00 +01002047 if (sess->listener->bind_conf->xprt == xprt_get(XPRT_SSL))
Willy Tarreau773d65f2012-10-12 14:56:11 +02002048 LOGCHAR('~');
Willy Tarreau773d65f2012-10-12 14:56:11 +02002049 if (tmp->options & LOG_OPT_QUOTE)
2050 LOGCHAR('"');
2051 last_isspace = 0;
2052 break;
Willy Tarreauffc3fcd2012-10-12 20:17:54 +02002053#ifdef USE_OPENSSL
2054 case LOG_FMT_SSL_CIPHER: // %sslc
2055 src = NULL;
Willy Tarreau9ad7bd42015-04-03 19:19:59 +02002056 conn = objt_conn(sess->origin);
Willy Tarreaub363a1f2013-10-01 10:45:07 +02002057 if (conn) {
Emmanuel Hocdet01da5712017-10-13 16:59:49 +02002058 src = ssl_sock_get_cipher_name(conn);
Willy Tarreaub363a1f2013-10-01 10:45:07 +02002059 }
Willy Tarreauffc3fcd2012-10-12 20:17:54 +02002060 ret = lf_text(tmplog, src, dst + maxsize - tmplog, tmp);
2061 if (ret == NULL)
2062 goto out;
2063 tmplog = ret;
2064 last_isspace = 0;
2065 break;
Willy Tarreau773d65f2012-10-12 14:56:11 +02002066
Willy Tarreauffc3fcd2012-10-12 20:17:54 +02002067 case LOG_FMT_SSL_VERSION: // %sslv
2068 src = NULL;
Willy Tarreau9ad7bd42015-04-03 19:19:59 +02002069 conn = objt_conn(sess->origin);
Willy Tarreaub363a1f2013-10-01 10:45:07 +02002070 if (conn) {
Emmanuel Hocdet01da5712017-10-13 16:59:49 +02002071 src = ssl_sock_get_proto_version(conn);
Willy Tarreaub363a1f2013-10-01 10:45:07 +02002072 }
Willy Tarreauffc3fcd2012-10-12 20:17:54 +02002073 ret = lf_text(tmplog, src, dst + maxsize - tmplog, tmp);
2074 if (ret == NULL)
2075 goto out;
2076 tmplog = ret;
2077 last_isspace = 0;
2078 break;
2079#endif
William Lallemand1d705562012-03-12 12:46:41 +01002080 case LOG_FMT_BACKEND: // %b
William Lallemandbddd4fd2012-02-27 11:23:10 +01002081 src = be->id;
William Lallemand5f232402012-04-05 18:02:55 +02002082 ret = lf_text(tmplog, src, dst + maxsize - tmplog, tmp);
William Lallemand1d705562012-03-12 12:46:41 +01002083 if (ret == NULL)
William Lallemandbddd4fd2012-02-27 11:23:10 +01002084 goto out;
William Lallemand1d705562012-03-12 12:46:41 +01002085 tmplog = ret;
William Lallemand51b5dca2012-03-26 17:52:55 +02002086 last_isspace = 0;
William Lallemandbddd4fd2012-02-27 11:23:10 +01002087 break;
2088
William Lallemand1d705562012-03-12 12:46:41 +01002089 case LOG_FMT_SERVER: // %s
Willy Tarreaue1809df2018-09-05 15:30:16 +02002090 switch (obj_type(s ? s->target : NULL)) {
Willy Tarreaud79a3b22012-12-28 09:40:16 +01002091 case OBJ_TYPE_SERVER:
Willy Tarreau1aaf3242018-09-20 11:13:58 +02002092 src = __objt_server(s->target)->id;
Willy Tarreaud79a3b22012-12-28 09:40:16 +01002093 break;
2094 case OBJ_TYPE_APPLET:
Willy Tarreau1aaf3242018-09-20 11:13:58 +02002095 src = __objt_applet(s->target)->name;
Willy Tarreaud79a3b22012-12-28 09:40:16 +01002096 break;
2097 default:
2098 src = "<NOSRV>";
2099 break;
2100 }
William Lallemand5f232402012-04-05 18:02:55 +02002101 ret = lf_text(tmplog, src, dst + maxsize - tmplog, tmp);
William Lallemand1d705562012-03-12 12:46:41 +01002102 if (ret == NULL)
William Lallemandbddd4fd2012-02-27 11:23:10 +01002103 goto out;
William Lallemand1d705562012-03-12 12:46:41 +01002104 tmplog = ret;
William Lallemandbddd4fd2012-02-27 11:23:10 +01002105 last_isspace = 0;
2106 break;
2107
Thierry FOURNIER / OZON.IO4cac3592016-07-28 17:19:45 +02002108 case LOG_FMT_Th: // %Th = handshake time
Willy Tarreau372ac5a2018-09-05 15:16:23 +02002109 ret = ltoa_o(logs->t_handshake, tmplog, dst + maxsize - tmplog);
Thierry FOURNIER / OZON.IO4cac3592016-07-28 17:19:45 +02002110 if (ret == NULL)
2111 goto out;
2112 tmplog = ret;
2113 last_isspace = 0;
2114 break;
2115
2116 case LOG_FMT_Ti: // %Ti = HTTP idle time
Willy Tarreau372ac5a2018-09-05 15:16:23 +02002117 ret = ltoa_o(logs->t_idle, tmplog, dst + maxsize - tmplog);
Thierry FOURNIER / OZON.IO4cac3592016-07-28 17:19:45 +02002118 if (ret == NULL)
2119 goto out;
2120 tmplog = ret;
2121 last_isspace = 0;
2122 break;
2123
2124 case LOG_FMT_TR: // %TR = HTTP request time
Willy Tarreau372ac5a2018-09-05 15:16:23 +02002125 ret = ltoa_o((t_request >= 0) ? t_request - logs->t_idle - logs->t_handshake : -1,
Thierry FOURNIER / OZON.IO4cac3592016-07-28 17:19:45 +02002126 tmplog, dst + maxsize - tmplog);
2127 if (ret == NULL)
2128 goto out;
2129 tmplog = ret;
2130 last_isspace = 0;
2131 break;
2132
2133 case LOG_FMT_TQ: // %Tq = Th + Ti + TR
William Lallemand5f232402012-04-05 18:02:55 +02002134 ret = ltoa_o(t_request, tmplog, dst + maxsize - tmplog);
William Lallemand1d705562012-03-12 12:46:41 +01002135 if (ret == NULL)
William Lallemandbddd4fd2012-02-27 11:23:10 +01002136 goto out;
William Lallemand1d705562012-03-12 12:46:41 +01002137 tmplog = ret;
William Lallemandbddd4fd2012-02-27 11:23:10 +01002138 last_isspace = 0;
2139 break;
2140
William Lallemand1d705562012-03-12 12:46:41 +01002141 case LOG_FMT_TW: // %Tw
Willy Tarreau372ac5a2018-09-05 15:16:23 +02002142 ret = ltoa_o((logs->t_queue >= 0) ? logs->t_queue - t_request : -1,
William Lallemand5f232402012-04-05 18:02:55 +02002143 tmplog, dst + maxsize - tmplog);
William Lallemand1d705562012-03-12 12:46:41 +01002144 if (ret == NULL)
William Lallemandbddd4fd2012-02-27 11:23:10 +01002145 goto out;
William Lallemand1d705562012-03-12 12:46:41 +01002146 tmplog = ret;
William Lallemandbddd4fd2012-02-27 11:23:10 +01002147 last_isspace = 0;
2148 break;
2149
William Lallemand1d705562012-03-12 12:46:41 +01002150 case LOG_FMT_TC: // %Tc
Willy Tarreau372ac5a2018-09-05 15:16:23 +02002151 ret = ltoa_o((logs->t_connect >= 0) ? logs->t_connect - logs->t_queue : -1,
William Lallemand5f232402012-04-05 18:02:55 +02002152 tmplog, dst + maxsize - tmplog);
William Lallemand1d705562012-03-12 12:46:41 +01002153 if (ret == NULL)
William Lallemandbddd4fd2012-02-27 11:23:10 +01002154 goto out;
William Lallemand1d705562012-03-12 12:46:41 +01002155 tmplog = ret;
William Lallemandbddd4fd2012-02-27 11:23:10 +01002156 last_isspace = 0;
2157 break;
2158
Thierry FOURNIER / OZON.IO4cac3592016-07-28 17:19:45 +02002159 case LOG_FMT_Tr: // %Tr
Willy Tarreau372ac5a2018-09-05 15:16:23 +02002160 ret = ltoa_o((logs->t_data >= 0) ? logs->t_data - logs->t_connect : -1,
William Lallemand5f232402012-04-05 18:02:55 +02002161 tmplog, dst + maxsize - tmplog);
William Lallemand1d705562012-03-12 12:46:41 +01002162 if (ret == NULL)
William Lallemandbddd4fd2012-02-27 11:23:10 +01002163 goto out;
William Lallemand1d705562012-03-12 12:46:41 +01002164 tmplog = ret;
William Lallemandbddd4fd2012-02-27 11:23:10 +01002165 last_isspace = 0;
2166 break;
2167
Willy Tarreau27b639d2016-05-17 17:55:27 +02002168 case LOG_FMT_TD: // %Td
Willy Tarreaua21c0e62018-09-05 15:07:15 +02002169 if (be->mode == PR_MODE_HTTP)
Willy Tarreau372ac5a2018-09-05 15:16:23 +02002170 ret = ltoa_o((logs->t_data >= 0) ? logs->t_close - logs->t_data : -1,
Willy Tarreau27b639d2016-05-17 17:55:27 +02002171 tmplog, dst + maxsize - tmplog);
2172 else
Willy Tarreau372ac5a2018-09-05 15:16:23 +02002173 ret = ltoa_o((logs->t_connect >= 0) ? logs->t_close - logs->t_connect : -1,
Willy Tarreau27b639d2016-05-17 17:55:27 +02002174 tmplog, dst + maxsize - tmplog);
2175 if (ret == NULL)
2176 goto out;
2177 tmplog = ret;
2178 last_isspace = 0;
2179 break;
2180
Thierry FOURNIER / OZON.IO4cac3592016-07-28 17:19:45 +02002181 case LOG_FMT_Ta: // %Ta = active time = Tt - Th - Ti
2182 if (!(fe->to_log & LW_BYTES))
2183 LOGCHAR('+');
Willy Tarreau372ac5a2018-09-05 15:16:23 +02002184 ret = ltoa_o(logs->t_close - (logs->t_idle >= 0 ? logs->t_idle + logs->t_handshake : 0),
Thierry FOURNIER / OZON.IO4cac3592016-07-28 17:19:45 +02002185 tmplog, dst + maxsize - tmplog);
2186 if (ret == NULL)
2187 goto out;
2188 tmplog = ret;
2189 last_isspace = 0;
2190 break;
2191
2192 case LOG_FMT_TT: // %Tt = total time
Willy Tarreaud79a3b22012-12-28 09:40:16 +01002193 if (!(fe->to_log & LW_BYTES))
William Lallemand1d705562012-03-12 12:46:41 +01002194 LOGCHAR('+');
Willy Tarreau372ac5a2018-09-05 15:16:23 +02002195 ret = ltoa_o(logs->t_close, tmplog, dst + maxsize - tmplog);
William Lallemand1d705562012-03-12 12:46:41 +01002196 if (ret == NULL)
William Lallemandbddd4fd2012-02-27 11:23:10 +01002197 goto out;
William Lallemand1d705562012-03-12 12:46:41 +01002198 tmplog = ret;
William Lallemandbddd4fd2012-02-27 11:23:10 +01002199 last_isspace = 0;
2200 break;
2201
Willy Tarreau2beef582012-12-20 17:22:52 +01002202 case LOG_FMT_STATUS: // %ST
Willy Tarreau57bc8912016-04-25 17:09:40 +02002203 ret = ltoa_o(txn ? txn->status : 0, tmplog, dst + maxsize - tmplog);
William Lallemand1d705562012-03-12 12:46:41 +01002204 if (ret == NULL)
William Lallemandbddd4fd2012-02-27 11:23:10 +01002205 goto out;
William Lallemand1d705562012-03-12 12:46:41 +01002206 tmplog = ret;
William Lallemandbddd4fd2012-02-27 11:23:10 +01002207 last_isspace = 0;
2208 break;
2209
William Lallemand1d705562012-03-12 12:46:41 +01002210 case LOG_FMT_BYTES: // %B
Willy Tarreaud79a3b22012-12-28 09:40:16 +01002211 if (!(fe->to_log & LW_BYTES))
William Lallemand1d705562012-03-12 12:46:41 +01002212 LOGCHAR('+');
Willy Tarreau372ac5a2018-09-05 15:16:23 +02002213 ret = lltoa(logs->bytes_out, tmplog, dst + maxsize - tmplog);
William Lallemand1d705562012-03-12 12:46:41 +01002214 if (ret == NULL)
William Lallemandbddd4fd2012-02-27 11:23:10 +01002215 goto out;
William Lallemand1d705562012-03-12 12:46:41 +01002216 tmplog = ret;
William Lallemandbddd4fd2012-02-27 11:23:10 +01002217 last_isspace = 0;
2218 break;
2219
Willy Tarreauc5259fd2012-12-20 15:38:04 +01002220 case LOG_FMT_BYTES_UP: // %U
Willy Tarreau372ac5a2018-09-05 15:16:23 +02002221 ret = lltoa(logs->bytes_in, tmplog, dst + maxsize - tmplog);
Willy Tarreauc5259fd2012-12-20 15:38:04 +01002222 if (ret == NULL)
2223 goto out;
2224 tmplog = ret;
2225 last_isspace = 0;
2226 break;
2227
Willy Tarreau2beef582012-12-20 17:22:52 +01002228 case LOG_FMT_CCLIENT: // %CC
Willy Tarreau57bc8912016-04-25 17:09:40 +02002229 src = txn ? txn->cli_cookie : NULL;
William Lallemand5f232402012-04-05 18:02:55 +02002230 ret = lf_text(tmplog, src, dst + maxsize - tmplog, tmp);
William Lallemand1d705562012-03-12 12:46:41 +01002231 if (ret == NULL)
William Lallemand51b5dca2012-03-26 17:52:55 +02002232 goto out;
William Lallemand1d705562012-03-12 12:46:41 +01002233 tmplog = ret;
William Lallemandbddd4fd2012-02-27 11:23:10 +01002234 last_isspace = 0;
2235 break;
2236
Willy Tarreau2beef582012-12-20 17:22:52 +01002237 case LOG_FMT_CSERVER: // %CS
Willy Tarreau57bc8912016-04-25 17:09:40 +02002238 src = txn ? txn->srv_cookie : NULL;
William Lallemand5f232402012-04-05 18:02:55 +02002239 ret = lf_text(tmplog, src, dst + maxsize - tmplog, tmp);
William Lallemand1d705562012-03-12 12:46:41 +01002240 if (ret == NULL)
William Lallemand51b5dca2012-03-26 17:52:55 +02002241 goto out;
William Lallemand1d705562012-03-12 12:46:41 +01002242 tmplog = ret;
William Lallemandbddd4fd2012-02-27 11:23:10 +01002243 last_isspace = 0;
2244 break;
2245
William Lallemand1d705562012-03-12 12:46:41 +01002246 case LOG_FMT_TERMSTATE: // %ts
Willy Tarreaub8bc5252018-09-05 15:51:28 +02002247 LOGCHAR(sess_term_cond[(s_flags & SF_ERR_MASK) >> SF_ERR_SHIFT]);
2248 LOGCHAR(sess_fin_state[(s_flags & SF_FINST_MASK) >> SF_FINST_SHIFT]);
Willy Tarreau6580c062012-03-12 15:09:42 +01002249 *tmplog = '\0';
2250 last_isspace = 0;
2251 break;
William Lallemandbddd4fd2012-02-27 11:23:10 +01002252
William Lallemand1d705562012-03-12 12:46:41 +01002253 case LOG_FMT_TERMSTATE_CK: // %tsc, same as TS with cookie state (for mode HTTP)
Willy Tarreaub8bc5252018-09-05 15:51:28 +02002254 LOGCHAR(sess_term_cond[(s_flags & SF_ERR_MASK) >> SF_ERR_SHIFT]);
2255 LOGCHAR(sess_fin_state[(s_flags & SF_FINST_MASK) >> SF_FINST_SHIFT]);
Willy Tarreau57bc8912016-04-25 17:09:40 +02002256 LOGCHAR((txn && (be->ck_opts & PR_CK_ANY)) ? sess_cookie[(txn->flags & TX_CK_MASK) >> TX_CK_SHIFT] : '-');
2257 LOGCHAR((txn && (be->ck_opts & PR_CK_ANY)) ? sess_set_cookie[(txn->flags & TX_SCK_MASK) >> TX_SCK_SHIFT] : '-');
William Lallemandbddd4fd2012-02-27 11:23:10 +01002258 last_isspace = 0;
2259 break;
2260
William Lallemand1d705562012-03-12 12:46:41 +01002261 case LOG_FMT_ACTCONN: // %ac
William Lallemand5f232402012-04-05 18:02:55 +02002262 ret = ltoa_o(actconn, tmplog, dst + maxsize - tmplog);
William Lallemand1d705562012-03-12 12:46:41 +01002263 if (ret == NULL)
William Lallemandbddd4fd2012-02-27 11:23:10 +01002264 goto out;
William Lallemand1d705562012-03-12 12:46:41 +01002265 tmplog = ret;
William Lallemandbddd4fd2012-02-27 11:23:10 +01002266 last_isspace = 0;
2267 break;
2268
William Lallemand1d705562012-03-12 12:46:41 +01002269 case LOG_FMT_FECONN: // %fc
William Lallemand5f232402012-04-05 18:02:55 +02002270 ret = ltoa_o(fe->feconn, tmplog, dst + maxsize - tmplog);
William Lallemand1d705562012-03-12 12:46:41 +01002271 if (ret == NULL)
William Lallemandbddd4fd2012-02-27 11:23:10 +01002272 goto out;
William Lallemand1d705562012-03-12 12:46:41 +01002273 tmplog = ret;
William Lallemandbddd4fd2012-02-27 11:23:10 +01002274 last_isspace = 0;
2275 break;
2276
William Lallemand1d705562012-03-12 12:46:41 +01002277 case LOG_FMT_BECONN: // %bc
William Lallemand5f232402012-04-05 18:02:55 +02002278 ret = ltoa_o(be->beconn, tmplog, dst + maxsize - tmplog);
William Lallemand1d705562012-03-12 12:46:41 +01002279 if (ret == NULL)
William Lallemandbddd4fd2012-02-27 11:23:10 +01002280 goto out;
William Lallemand1d705562012-03-12 12:46:41 +01002281 tmplog = ret;
William Lallemandbddd4fd2012-02-27 11:23:10 +01002282 last_isspace = 0;
2283 break;
2284
William Lallemand1d705562012-03-12 12:46:41 +01002285 case LOG_FMT_SRVCONN: // %sc
Willy Tarreaue1809df2018-09-05 15:30:16 +02002286 ret = ultoa_o(objt_server(s ? s->target : NULL) ?
Willy Tarreau3fdb3662012-11-12 00:42:33 +01002287 objt_server(s->target)->cur_sess :
William Lallemand5f232402012-04-05 18:02:55 +02002288 0, tmplog, dst + maxsize - tmplog);
William Lallemand1d705562012-03-12 12:46:41 +01002289 if (ret == NULL)
William Lallemandbddd4fd2012-02-27 11:23:10 +01002290 goto out;
William Lallemand1d705562012-03-12 12:46:41 +01002291 tmplog = ret;
William Lallemandbddd4fd2012-02-27 11:23:10 +01002292 last_isspace = 0;
2293 break;
2294
William Lallemand1d705562012-03-12 12:46:41 +01002295 case LOG_FMT_RETRIES: // %rq
Willy Tarreaub8bc5252018-09-05 15:51:28 +02002296 if (s_flags & SF_REDISP)
William Lallemand1d705562012-03-12 12:46:41 +01002297 LOGCHAR('+');
Willy Tarreauabd71a52018-09-04 19:21:44 +02002298 ret = ltoa_o((s && s->si[1].conn_retries > 0) ?
Willy Tarreau350f4872014-11-28 14:42:25 +01002299 (be->conn_retries - s->si[1].conn_retries) :
William Lallemand5f232402012-04-05 18:02:55 +02002300 be->conn_retries, tmplog, dst + maxsize - tmplog);
William Lallemand1d705562012-03-12 12:46:41 +01002301 if (ret == NULL)
William Lallemand51b5dca2012-03-26 17:52:55 +02002302 goto out;
William Lallemand1d705562012-03-12 12:46:41 +01002303 tmplog = ret;
William Lallemandbddd4fd2012-02-27 11:23:10 +01002304 last_isspace = 0;
2305 break;
2306
William Lallemand1d705562012-03-12 12:46:41 +01002307 case LOG_FMT_SRVQUEUE: // %sq
Willy Tarreau372ac5a2018-09-05 15:16:23 +02002308 ret = ltoa_o(logs->srv_queue_pos, tmplog, dst + maxsize - tmplog);
William Lallemand1d705562012-03-12 12:46:41 +01002309 if (ret == NULL)
William Lallemandbddd4fd2012-02-27 11:23:10 +01002310 goto out;
William Lallemand1d705562012-03-12 12:46:41 +01002311 tmplog = ret;
William Lallemandbddd4fd2012-02-27 11:23:10 +01002312 last_isspace = 0;
2313 break;
2314
William Lallemand1d705562012-03-12 12:46:41 +01002315 case LOG_FMT_BCKQUEUE: // %bq
Willy Tarreau372ac5a2018-09-05 15:16:23 +02002316 ret = ltoa_o(logs->prx_queue_pos, tmplog, dst + maxsize - tmplog);
William Lallemand1d705562012-03-12 12:46:41 +01002317 if (ret == NULL)
William Lallemandbddd4fd2012-02-27 11:23:10 +01002318 goto out;
William Lallemand1d705562012-03-12 12:46:41 +01002319 tmplog = ret;
William Lallemandbddd4fd2012-02-27 11:23:10 +01002320 last_isspace = 0;
2321 break;
2322
William Lallemand1d705562012-03-12 12:46:41 +01002323 case LOG_FMT_HDRREQUEST: // %hr
William Lallemandbddd4fd2012-02-27 11:23:10 +01002324 /* request header */
Willy Tarreaud4f91662018-09-05 15:28:07 +02002325 if (fe->nb_req_cap && s && s->req_cap) {
William Lallemandbddd4fd2012-02-27 11:23:10 +01002326 if (tmp->options & LOG_OPT_QUOTE)
2327 LOGCHAR('"');
2328 LOGCHAR('{');
2329 for (hdr = 0; hdr < fe->nb_req_cap; hdr++) {
2330 if (hdr)
2331 LOGCHAR('|');
Willy Tarreaucb7dd012015-04-03 22:16:32 +02002332 if (s->req_cap[hdr] != NULL) {
Dragan Dosen835b9212016-02-12 13:23:03 +01002333 ret = lf_encode_string(tmplog, dst + maxsize,
2334 '#', hdr_encode_map, s->req_cap[hdr], tmp);
William Lallemand1d705562012-03-12 12:46:41 +01002335 if (ret == NULL || *ret != '\0')
William Lallemand51b5dca2012-03-26 17:52:55 +02002336 goto out;
William Lallemand1d705562012-03-12 12:46:41 +01002337 tmplog = ret;
William Lallemand51b5dca2012-03-26 17:52:55 +02002338 }
William Lallemandbddd4fd2012-02-27 11:23:10 +01002339 }
2340 LOGCHAR('}');
William Lallemand51b5dca2012-03-26 17:52:55 +02002341 if (tmp->options & LOG_OPT_QUOTE)
2342 LOGCHAR('"');
William Lallemandbddd4fd2012-02-27 11:23:10 +01002343 last_isspace = 0;
2344 }
William Lallemandbddd4fd2012-02-27 11:23:10 +01002345 break;
2346
William Lallemand1d705562012-03-12 12:46:41 +01002347 case LOG_FMT_HDRREQUESTLIST: // %hrl
William Lallemandbddd4fd2012-02-27 11:23:10 +01002348 /* request header list */
Willy Tarreaud4f91662018-09-05 15:28:07 +02002349 if (fe->nb_req_cap && s && s->req_cap) {
William Lallemandbddd4fd2012-02-27 11:23:10 +01002350 for (hdr = 0; hdr < fe->nb_req_cap; hdr++) {
2351 if (hdr > 0)
2352 LOGCHAR(' ');
2353 if (tmp->options & LOG_OPT_QUOTE)
2354 LOGCHAR('"');
Willy Tarreaucb7dd012015-04-03 22:16:32 +02002355 if (s->req_cap[hdr] != NULL) {
Dragan Dosen835b9212016-02-12 13:23:03 +01002356 ret = lf_encode_string(tmplog, dst + maxsize,
2357 '#', hdr_encode_map, s->req_cap[hdr], tmp);
William Lallemand1d705562012-03-12 12:46:41 +01002358 if (ret == NULL || *ret != '\0')
William Lallemand51b5dca2012-03-26 17:52:55 +02002359 goto out;
William Lallemand1d705562012-03-12 12:46:41 +01002360 tmplog = ret;
William Lallemandbddd4fd2012-02-27 11:23:10 +01002361 } else if (!(tmp->options & LOG_OPT_QUOTE))
2362 LOGCHAR('-');
2363 if (tmp->options & LOG_OPT_QUOTE)
2364 LOGCHAR('"');
William Lallemandbddd4fd2012-02-27 11:23:10 +01002365 last_isspace = 0;
2366 }
2367 }
2368 break;
Willy Tarreaubaaee002006-06-26 02:48:02 +02002369
William Lallemand1d705562012-03-12 12:46:41 +01002370
2371 case LOG_FMT_HDRRESPONS: // %hs
William Lallemandbddd4fd2012-02-27 11:23:10 +01002372 /* response header */
Willy Tarreaud4f91662018-09-05 15:28:07 +02002373 if (fe->nb_rsp_cap && s && s->res_cap) {
William Lallemandbddd4fd2012-02-27 11:23:10 +01002374 if (tmp->options & LOG_OPT_QUOTE)
2375 LOGCHAR('"');
2376 LOGCHAR('{');
2377 for (hdr = 0; hdr < fe->nb_rsp_cap; hdr++) {
2378 if (hdr)
2379 LOGCHAR('|');
Willy Tarreaucb7dd012015-04-03 22:16:32 +02002380 if (s->res_cap[hdr] != NULL) {
Dragan Dosen835b9212016-02-12 13:23:03 +01002381 ret = lf_encode_string(tmplog, dst + maxsize,
2382 '#', hdr_encode_map, s->res_cap[hdr], tmp);
William Lallemand1d705562012-03-12 12:46:41 +01002383 if (ret == NULL || *ret != '\0')
William Lallemand51b5dca2012-03-26 17:52:55 +02002384 goto out;
William Lallemand1d705562012-03-12 12:46:41 +01002385 tmplog = ret;
William Lallemand51b5dca2012-03-26 17:52:55 +02002386 }
William Lallemandbddd4fd2012-02-27 11:23:10 +01002387 }
2388 LOGCHAR('}');
2389 last_isspace = 0;
2390 if (tmp->options & LOG_OPT_QUOTE)
2391 LOGCHAR('"');
2392 }
William Lallemandbddd4fd2012-02-27 11:23:10 +01002393 break;
2394
William Lallemand1d705562012-03-12 12:46:41 +01002395 case LOG_FMT_HDRRESPONSLIST: // %hsl
William Lallemandbddd4fd2012-02-27 11:23:10 +01002396 /* response header list */
Willy Tarreaud4f91662018-09-05 15:28:07 +02002397 if (fe->nb_rsp_cap && s && s->res_cap) {
William Lallemandbddd4fd2012-02-27 11:23:10 +01002398 for (hdr = 0; hdr < fe->nb_rsp_cap; hdr++) {
2399 if (hdr > 0)
2400 LOGCHAR(' ');
2401 if (tmp->options & LOG_OPT_QUOTE)
2402 LOGCHAR('"');
Willy Tarreaucb7dd012015-04-03 22:16:32 +02002403 if (s->res_cap[hdr] != NULL) {
Dragan Dosen835b9212016-02-12 13:23:03 +01002404 ret = lf_encode_string(tmplog, dst + maxsize,
2405 '#', hdr_encode_map, s->res_cap[hdr], tmp);
William Lallemand1d705562012-03-12 12:46:41 +01002406 if (ret == NULL || *ret != '\0')
William Lallemand51b5dca2012-03-26 17:52:55 +02002407 goto out;
William Lallemand1d705562012-03-12 12:46:41 +01002408 tmplog = ret;
William Lallemandbddd4fd2012-02-27 11:23:10 +01002409 } else if (!(tmp->options & LOG_OPT_QUOTE))
2410 LOGCHAR('-');
2411 if (tmp->options & LOG_OPT_QUOTE)
2412 LOGCHAR('"');
William Lallemandbddd4fd2012-02-27 11:23:10 +01002413 last_isspace = 0;
2414 }
2415 }
2416 break;
2417
William Lallemand1d705562012-03-12 12:46:41 +01002418 case LOG_FMT_REQ: // %r
William Lallemandbddd4fd2012-02-27 11:23:10 +01002419 /* Request */
2420 if (tmp->options & LOG_OPT_QUOTE)
2421 LOGCHAR('"');
Willy Tarreau57bc8912016-04-25 17:09:40 +02002422 uri = txn && txn->uri ? txn->uri : "<BADREQ>";
Dragan Dosen835b9212016-02-12 13:23:03 +01002423 ret = lf_encode_string(tmplog, dst + maxsize,
2424 '#', url_encode_map, uri, tmp);
William Lallemand1d705562012-03-12 12:46:41 +01002425 if (ret == NULL || *ret != '\0')
William Lallemand51b5dca2012-03-26 17:52:55 +02002426 goto out;
William Lallemand1d705562012-03-12 12:46:41 +01002427 tmplog = ret;
William Lallemandbddd4fd2012-02-27 11:23:10 +01002428 if (tmp->options & LOG_OPT_QUOTE)
2429 LOGCHAR('"');
William Lallemandbddd4fd2012-02-27 11:23:10 +01002430 last_isspace = 0;
2431 break;
William Lallemand5f232402012-04-05 18:02:55 +02002432
Andrew Hayworth0ebc55f2015-04-27 21:37:03 +00002433 case LOG_FMT_HTTP_PATH: // %HP
Willy Tarreau57bc8912016-04-25 17:09:40 +02002434 uri = txn && txn->uri ? txn->uri : "<BADREQ>";
Andrew Hayworth0ebc55f2015-04-27 21:37:03 +00002435
Willy Tarreaub7636d12015-06-17 19:58:02 +02002436 if (tmp->options & LOG_OPT_QUOTE)
Andrew Hayworth0ebc55f2015-04-27 21:37:03 +00002437 LOGCHAR('"');
2438
2439 end = uri + strlen(uri);
2440 // look for the first whitespace character
2441 while (uri < end && !HTTP_IS_SPHT(*uri))
2442 uri++;
2443
2444 // keep advancing past multiple spaces
2445 while (uri < end && HTTP_IS_SPHT(*uri)) {
2446 uri++; nspaces++;
2447 }
2448
2449 // look for first space or question mark after url
2450 spc = uri;
2451 while (spc < end && *spc != '?' && !HTTP_IS_SPHT(*spc))
2452 spc++;
2453
Nenad Merdanovic54e439f2016-04-26 01:39:02 +02002454 if (!txn || !txn->uri || nspaces == 0) {
Willy Tarreau843b7cb2018-07-13 10:54:26 +02002455 chunk.area = "<BADREQ>";
2456 chunk.data = strlen("<BADREQ>");
Andrew Hayworth0ebc55f2015-04-27 21:37:03 +00002457 } else {
Willy Tarreau843b7cb2018-07-13 10:54:26 +02002458 chunk.area = uri;
2459 chunk.data = spc - uri;
Andrew Hayworth0ebc55f2015-04-27 21:37:03 +00002460 }
2461
Dragan Dosen835b9212016-02-12 13:23:03 +01002462 ret = lf_encode_chunk(tmplog, dst + maxsize, '#', url_encode_map, &chunk, tmp);
Andrew Hayworth0ebc55f2015-04-27 21:37:03 +00002463 if (ret == NULL || *ret != '\0')
2464 goto out;
2465
2466 tmplog = ret;
Willy Tarreaub7636d12015-06-17 19:58:02 +02002467 if (tmp->options & LOG_OPT_QUOTE)
Andrew Hayworth0ebc55f2015-04-27 21:37:03 +00002468 LOGCHAR('"');
2469
2470 last_isspace = 0;
2471 break;
2472
Andrew Hayworthe63ac872015-07-31 16:14:16 +00002473 case LOG_FMT_HTTP_QUERY: // %HQ
2474 if (tmp->options & LOG_OPT_QUOTE)
2475 LOGCHAR('"');
2476
Willy Tarreau57bc8912016-04-25 17:09:40 +02002477 if (!txn || !txn->uri) {
Willy Tarreau843b7cb2018-07-13 10:54:26 +02002478 chunk.area = "<BADREQ>";
2479 chunk.data = strlen("<BADREQ>");
Andrew Hayworthe63ac872015-07-31 16:14:16 +00002480 } else {
2481 uri = txn->uri;
2482 end = uri + strlen(uri);
2483 // look for the first question mark
2484 while (uri < end && *uri != '?')
2485 uri++;
2486
2487 qmark = uri;
2488 // look for first space or question mark after url
2489 while (uri < end && !HTTP_IS_SPHT(*uri))
2490 uri++;
2491
Willy Tarreau843b7cb2018-07-13 10:54:26 +02002492 chunk.area = qmark;
2493 chunk.data = uri - qmark;
Andrew Hayworthe63ac872015-07-31 16:14:16 +00002494 }
2495
Dragan Dosen835b9212016-02-12 13:23:03 +01002496 ret = lf_encode_chunk(tmplog, dst + maxsize, '#', url_encode_map, &chunk, tmp);
Andrew Hayworthe63ac872015-07-31 16:14:16 +00002497 if (ret == NULL || *ret != '\0')
2498 goto out;
2499
2500 tmplog = ret;
2501 if (tmp->options & LOG_OPT_QUOTE)
2502 LOGCHAR('"');
2503
2504 last_isspace = 0;
2505 break;
2506
Andrew Hayworth0ebc55f2015-04-27 21:37:03 +00002507 case LOG_FMT_HTTP_URI: // %HU
Willy Tarreau57bc8912016-04-25 17:09:40 +02002508 uri = txn && txn->uri ? txn->uri : "<BADREQ>";
Andrew Hayworth0ebc55f2015-04-27 21:37:03 +00002509
Willy Tarreaub7636d12015-06-17 19:58:02 +02002510 if (tmp->options & LOG_OPT_QUOTE)
Andrew Hayworth0ebc55f2015-04-27 21:37:03 +00002511 LOGCHAR('"');
2512
2513 end = uri + strlen(uri);
2514 // look for the first whitespace character
2515 while (uri < end && !HTTP_IS_SPHT(*uri))
2516 uri++;
2517
2518 // keep advancing past multiple spaces
2519 while (uri < end && HTTP_IS_SPHT(*uri)) {
2520 uri++; nspaces++;
2521 }
2522
2523 // look for first space after url
2524 spc = uri;
2525 while (spc < end && !HTTP_IS_SPHT(*spc))
2526 spc++;
2527
Willy Tarreau57bc8912016-04-25 17:09:40 +02002528 if (!txn || !txn->uri || nspaces == 0) {
Willy Tarreau843b7cb2018-07-13 10:54:26 +02002529 chunk.area = "<BADREQ>";
2530 chunk.data = strlen("<BADREQ>");
Andrew Hayworth0ebc55f2015-04-27 21:37:03 +00002531 } else {
Willy Tarreau843b7cb2018-07-13 10:54:26 +02002532 chunk.area = uri;
2533 chunk.data = spc - uri;
Andrew Hayworth0ebc55f2015-04-27 21:37:03 +00002534 }
2535
Dragan Dosen835b9212016-02-12 13:23:03 +01002536 ret = lf_encode_chunk(tmplog, dst + maxsize, '#', url_encode_map, &chunk, tmp);
Andrew Hayworth0ebc55f2015-04-27 21:37:03 +00002537 if (ret == NULL || *ret != '\0')
2538 goto out;
2539
2540 tmplog = ret;
Willy Tarreaub7636d12015-06-17 19:58:02 +02002541 if (tmp->options & LOG_OPT_QUOTE)
Andrew Hayworth0ebc55f2015-04-27 21:37:03 +00002542 LOGCHAR('"');
2543
2544 last_isspace = 0;
2545 break;
2546
2547 case LOG_FMT_HTTP_METHOD: // %HM
Willy Tarreau57bc8912016-04-25 17:09:40 +02002548 uri = txn && txn->uri ? txn->uri : "<BADREQ>";
Willy Tarreaub7636d12015-06-17 19:58:02 +02002549 if (tmp->options & LOG_OPT_QUOTE)
Andrew Hayworth0ebc55f2015-04-27 21:37:03 +00002550 LOGCHAR('"');
2551
2552 end = uri + strlen(uri);
2553 // look for the first whitespace character
2554 spc = uri;
2555 while (spc < end && !HTTP_IS_SPHT(*spc))
2556 spc++;
2557
2558 if (spc == end) { // odd case, we have txn->uri, but we only got a verb
Willy Tarreau843b7cb2018-07-13 10:54:26 +02002559 chunk.area = "<BADREQ>";
2560 chunk.data = strlen("<BADREQ>");
Andrew Hayworth0ebc55f2015-04-27 21:37:03 +00002561 } else {
Willy Tarreau843b7cb2018-07-13 10:54:26 +02002562 chunk.area = uri;
2563 chunk.data = spc - uri;
Andrew Hayworth0ebc55f2015-04-27 21:37:03 +00002564 }
2565
Dragan Dosen835b9212016-02-12 13:23:03 +01002566 ret = lf_encode_chunk(tmplog, dst + maxsize, '#', url_encode_map, &chunk, tmp);
Andrew Hayworth0ebc55f2015-04-27 21:37:03 +00002567 if (ret == NULL || *ret != '\0')
2568 goto out;
2569
2570 tmplog = ret;
Willy Tarreaub7636d12015-06-17 19:58:02 +02002571 if (tmp->options & LOG_OPT_QUOTE)
Andrew Hayworth0ebc55f2015-04-27 21:37:03 +00002572 LOGCHAR('"');
2573
2574 last_isspace = 0;
2575 break;
2576
2577 case LOG_FMT_HTTP_VERSION: // %HV
Willy Tarreau57bc8912016-04-25 17:09:40 +02002578 uri = txn && txn->uri ? txn->uri : "<BADREQ>";
Willy Tarreaub7636d12015-06-17 19:58:02 +02002579 if (tmp->options & LOG_OPT_QUOTE)
Andrew Hayworth0ebc55f2015-04-27 21:37:03 +00002580 LOGCHAR('"');
2581
2582 end = uri + strlen(uri);
2583 // look for the first whitespace character
2584 while (uri < end && !HTTP_IS_SPHT(*uri))
2585 uri++;
2586
2587 // keep advancing past multiple spaces
2588 while (uri < end && HTTP_IS_SPHT(*uri)) {
2589 uri++; nspaces++;
2590 }
2591
2592 // look for the next whitespace character
2593 while (uri < end && !HTTP_IS_SPHT(*uri))
2594 uri++;
2595
2596 // keep advancing past multiple spaces
2597 while (uri < end && HTTP_IS_SPHT(*uri))
2598 uri++;
2599
Willy Tarreau57bc8912016-04-25 17:09:40 +02002600 if (!txn || !txn->uri || nspaces == 0) {
Willy Tarreau843b7cb2018-07-13 10:54:26 +02002601 chunk.area = "<BADREQ>";
2602 chunk.data = strlen("<BADREQ>");
Andrew Hayworth0ebc55f2015-04-27 21:37:03 +00002603 } else if (uri == end) {
Willy Tarreau843b7cb2018-07-13 10:54:26 +02002604 chunk.area = "HTTP/0.9";
2605 chunk.data = strlen("HTTP/0.9");
Andrew Hayworth0ebc55f2015-04-27 21:37:03 +00002606 } else {
Willy Tarreau843b7cb2018-07-13 10:54:26 +02002607 chunk.area = uri;
2608 chunk.data = end - uri;
Andrew Hayworth0ebc55f2015-04-27 21:37:03 +00002609 }
2610
Dragan Dosen835b9212016-02-12 13:23:03 +01002611 ret = lf_encode_chunk(tmplog, dst + maxsize, '#', url_encode_map, &chunk, tmp);
Andrew Hayworth0ebc55f2015-04-27 21:37:03 +00002612 if (ret == NULL || *ret != '\0')
2613 goto out;
2614
2615 tmplog = ret;
Willy Tarreaub7636d12015-06-17 19:58:02 +02002616 if (tmp->options & LOG_OPT_QUOTE)
Andrew Hayworth0ebc55f2015-04-27 21:37:03 +00002617 LOGCHAR('"');
2618
2619 last_isspace = 0;
2620 break;
2621
William Lallemand5f232402012-04-05 18:02:55 +02002622 case LOG_FMT_COUNTER: // %rt
2623 if (tmp->options & LOG_OPT_HEXA) {
Willy Tarreau5cacab62018-09-05 15:52:59 +02002624 iret = snprintf(tmplog, dst + maxsize - tmplog, "%04X", uniq_id);
William Lallemand5f232402012-04-05 18:02:55 +02002625 if (iret < 0 || iret > dst + maxsize - tmplog)
2626 goto out;
2627 last_isspace = 0;
2628 tmplog += iret;
2629 } else {
Willy Tarreau5cacab62018-09-05 15:52:59 +02002630 ret = ltoa_o(uniq_id, tmplog, dst + maxsize - tmplog);
William Lallemand5f232402012-04-05 18:02:55 +02002631 if (ret == NULL)
2632 goto out;
2633 tmplog = ret;
2634 last_isspace = 0;
2635 }
2636 break;
2637
Willy Tarreau7346acb2014-08-28 15:03:15 +02002638 case LOG_FMT_LOGCNT: // %lc
2639 if (tmp->options & LOG_OPT_HEXA) {
Willy Tarreaue36cbcb2015-04-03 15:40:56 +02002640 iret = snprintf(tmplog, dst + maxsize - tmplog, "%04X", fe->log_count);
Willy Tarreau7346acb2014-08-28 15:03:15 +02002641 if (iret < 0 || iret > dst + maxsize - tmplog)
2642 goto out;
2643 last_isspace = 0;
2644 tmplog += iret;
2645 } else {
Willy Tarreaue36cbcb2015-04-03 15:40:56 +02002646 ret = ultoa_o(fe->log_count, tmplog, dst + maxsize - tmplog);
Willy Tarreau7346acb2014-08-28 15:03:15 +02002647 if (ret == NULL)
2648 goto out;
2649 tmplog = ret;
2650 last_isspace = 0;
2651 }
2652 break;
2653
William Lallemand5f232402012-04-05 18:02:55 +02002654 case LOG_FMT_HOSTNAME: // %H
2655 src = hostname;
2656 ret = lf_text(tmplog, src, dst + maxsize - tmplog, tmp);
2657 if (ret == NULL)
2658 goto out;
2659 tmplog = ret;
2660 last_isspace = 0;
2661 break;
2662
2663 case LOG_FMT_PID: // %pid
2664 if (tmp->options & LOG_OPT_HEXA) {
2665 iret = snprintf(tmplog, dst + maxsize - tmplog, "%04X", pid);
2666 if (iret < 0 || iret > dst + maxsize - tmplog)
2667 goto out;
2668 last_isspace = 0;
2669 tmplog += iret;
2670 } else {
2671 ret = ltoa_o(pid, tmplog, dst + maxsize - tmplog);
2672 if (ret == NULL)
2673 goto out;
2674 tmplog = ret;
2675 last_isspace = 0;
2676 }
2677 break;
William Lallemanda73203e2012-03-12 12:48:57 +01002678
2679 case LOG_FMT_UNIQUEID: // %ID
William Lallemand5b7ea3a2013-08-28 15:44:19 +02002680 ret = NULL;
Willy Tarreau02fdf4f2018-09-05 15:49:01 +02002681 src = s ? s->unique_id : NULL;
Thierry FOURNIER1be69102014-04-15 01:38:48 +02002682 ret = lf_text(tmplog, src, maxsize - (tmplog - dst), tmp);
William Lallemanda73203e2012-03-12 12:48:57 +01002683 if (ret == NULL)
2684 goto out;
2685 tmplog = ret;
2686 last_isspace = 0;
2687 break;
2688
William Lallemandbddd4fd2012-02-27 11:23:10 +01002689 }
2690 }
2691
2692out:
William Lallemand1d705562012-03-12 12:46:41 +01002693 /* *tmplog is a unused character */
2694 *tmplog = '\0';
Willy Tarreaudf974472012-12-28 02:44:01 +01002695 return tmplog - dst;
William Lallemandbddd4fd2012-02-27 11:23:10 +01002696
Willy Tarreaubaaee002006-06-26 02:48:02 +02002697}
2698
William Lallemand1d705562012-03-12 12:46:41 +01002699/*
Willy Tarreau87b09662015-04-03 00:22:06 +02002700 * send a log for the stream when we have enough info about it.
William Lallemand1d705562012-03-12 12:46:41 +01002701 * Will not log if the frontend has no log defined.
2702 */
Willy Tarreau87b09662015-04-03 00:22:06 +02002703void strm_log(struct stream *s)
William Lallemand1d705562012-03-12 12:46:41 +01002704{
Willy Tarreaue36cbcb2015-04-03 15:40:56 +02002705 struct session *sess = s->sess;
William Lallemand1d705562012-03-12 12:46:41 +01002706 int size, err, level;
Dragan Dosen0b85ece2015-09-25 19:17:44 +02002707 int sd_size = 0;
William Lallemand1d705562012-03-12 12:46:41 +01002708
2709 /* if we don't want to log normal traffic, return now */
Willy Tarreaue7dff022015-04-03 01:14:29 +02002710 err = (s->flags & SF_REDISP) ||
2711 ((s->flags & SF_ERR_MASK) > SF_ERR_LOCAL) ||
2712 (((s->flags & SF_ERR_MASK) == SF_ERR_NONE) &&
Willy Tarreau350f4872014-11-28 14:42:25 +01002713 (s->si[1].conn_retries != s->be->conn_retries)) ||
Willy Tarreaueee5b512015-04-03 23:46:31 +02002714 ((sess->fe->mode == PR_MODE_HTTP) && s->txn && s->txn->status >= 500);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002715
Willy Tarreaue36cbcb2015-04-03 15:40:56 +02002716 if (!err && (sess->fe->options2 & PR_O2_NOLOGNORM))
William Lallemand1d705562012-03-12 12:46:41 +01002717 return;
William Lallemandbddd4fd2012-02-27 11:23:10 +01002718
Willy Tarreaue36cbcb2015-04-03 15:40:56 +02002719 if (LIST_ISEMPTY(&sess->fe->logsrvs))
William Lallemand1d705562012-03-12 12:46:41 +01002720 return;
William Lallemandbddd4fd2012-02-27 11:23:10 +01002721
Willy Tarreauabcd5142013-06-11 17:18:02 +02002722 if (s->logs.level) { /* loglevel was overridden */
2723 if (s->logs.level == -1) {
2724 s->logs.logwait = 0; /* logs disabled */
2725 return;
2726 }
2727 level = s->logs.level - 1;
2728 }
2729 else {
2730 level = LOG_INFO;
Willy Tarreaue36cbcb2015-04-03 15:40:56 +02002731 if (err && (sess->fe->options2 & PR_O2_LOGERRORS))
Willy Tarreauabcd5142013-06-11 17:18:02 +02002732 level = LOG_ERR;
2733 }
William Lallemand1d705562012-03-12 12:46:41 +01002734
William Lallemand5b7ea3a2013-08-28 15:44:19 +02002735 /* if unique-id was not generated */
Willy Tarreaue36cbcb2015-04-03 15:40:56 +02002736 if (!s->unique_id && !LIST_ISEMPTY(&sess->fe->format_unique_id)) {
Willy Tarreaubafbe012017-11-24 17:34:44 +01002737 if ((s->unique_id = pool_alloc(pool_head_uniqueid)) != NULL)
Willy Tarreaue36cbcb2015-04-03 15:40:56 +02002738 build_logline(s, s->unique_id, UNIQUEID_LEN, &sess->fe->format_unique_id);
William Lallemand5b7ea3a2013-08-28 15:44:19 +02002739 }
2740
Dragan Dosen0b85ece2015-09-25 19:17:44 +02002741 if (!LIST_ISEMPTY(&sess->fe->logformat_sd)) {
2742 sd_size = build_logline(s, logline_rfc5424, global.max_syslog_len,
2743 &sess->fe->logformat_sd);
2744 }
2745
Dragan Dosen59cee972015-09-19 22:09:02 +02002746 size = build_logline(s, logline, global.max_syslog_len, &sess->fe->logformat);
William Lallemand1d705562012-03-12 12:46:41 +01002747 if (size > 0) {
Christopher Fauletff8abcd2017-06-02 15:33:24 +02002748 HA_ATOMIC_ADD(&sess->fe->log_count, 1);
Dragan Dosen0b85ece2015-09-25 19:17:44 +02002749 __send_log(sess->fe, level, logline, size + 1, logline_rfc5424, sd_size);
William Lallemand1d705562012-03-12 12:46:41 +01002750 s->logs.logwait = 0;
2751 }
2752}
William Lallemandbddd4fd2012-02-27 11:23:10 +01002753
Willy Tarreau53839352018-09-05 19:51:10 +02002754/*
2755 * send a minimalist log for the session. Will not log if the frontend has no
2756 * log defined. It is assumed that this is only used to report anomalies that
2757 * cannot lead to the creation of a regular stream. Because of this the log
2758 * level is LOG_INFO or LOG_ERR depending on the "log-separate-error" setting
2759 * in the frontend. The caller must simply know that it should not call this
Willy Tarreau9fa267d2018-10-05 10:22:27 +02002760 * function to report unimportant events. It is safe to call this function with
2761 * sess==NULL (will not do anything).
Willy Tarreau53839352018-09-05 19:51:10 +02002762 */
2763void sess_log(struct session *sess)
2764{
2765 int size, level;
2766 int sd_size = 0;
2767
Willy Tarreau9fa267d2018-10-05 10:22:27 +02002768 if (!sess)
2769 return;
2770
Willy Tarreau53839352018-09-05 19:51:10 +02002771 if (LIST_ISEMPTY(&sess->fe->logsrvs))
2772 return;
2773
2774 level = LOG_INFO;
2775 if (sess->fe->options2 & PR_O2_LOGERRORS)
2776 level = LOG_ERR;
2777
2778 if (!LIST_ISEMPTY(&sess->fe->logformat_sd)) {
2779 sd_size = sess_build_logline(sess, NULL,
2780 logline_rfc5424, global.max_syslog_len,
2781 &sess->fe->logformat_sd);
2782 }
2783
2784 size = sess_build_logline(sess, NULL, logline, global.max_syslog_len, &sess->fe->logformat);
2785 if (size > 0) {
2786 HA_ATOMIC_ADD(&sess->fe->log_count, 1);
2787 __send_log(sess->fe, level, logline, size + 1, logline_rfc5424, sd_size);
2788 }
2789}
2790
Christopher Fauletc1b730a2017-10-24 12:00:51 +02002791static int cli_io_handler_show_startup_logs(struct appctx *appctx)
2792{
2793 struct stream_interface *si = appctx->owner;
2794 const char *msg = (startup_logs ? startup_logs : "No startup alerts/warnings.\n");
2795
2796 if (ci_putstr(si_ic(si), msg) == -1) {
Willy Tarreaudb398432018-11-15 11:08:52 +01002797 si_rx_room_blk(si);
Christopher Fauletc1b730a2017-10-24 12:00:51 +02002798 return 0;
2799 }
2800 return 1;
2801}
2802
2803/* register cli keywords */
2804static struct cli_kw_list cli_kws = {{ },{
2805 { { "show", "startup-logs", NULL },
2806 "show startup-logs : report logs emitted during HAProxy startup",
2807 NULL, cli_io_handler_show_startup_logs },
2808 {{},}
2809}};
2810
Willy Tarreau0108d902018-11-25 19:14:37 +01002811INITCALL1(STG_REGISTER, cli_register_kw, &cli_kws);
2812
Willy Tarreau172f5ce2018-11-26 11:21:50 +01002813REGISTER_PER_THREAD_INIT(init_log_buffers_per_thread);
2814REGISTER_PER_THREAD_DEINIT(deinit_log_buffers_per_thread);
2815
Willy Tarreaubaaee002006-06-26 02:48:02 +02002816/*
2817 * Local variables:
2818 * c-indent-level: 8
2819 * c-basic-offset: 8
2820 * End:
2821 */