blob: 3db3c0d9e4a2073dd71348be7ace0a1f14ee198a [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 Tarreau2dd0d472006-06-29 17:53:05 +020029#include <common/standard.h>
Willy Tarreaufb278672006-10-15 15:38:50 +020030#include <common/time.h>
Willy Tarreaubaaee002006-06-26 02:48:02 +020031
Christopher Fauletc1b730a2017-10-24 12:00:51 +020032#include <types/cli.h>
Willy Tarreaubaaee002006-06-26 02:48:02 +020033#include <types/global.h>
William Lallemand723b73a2012-02-08 16:37:49 +010034#include <types/log.h>
Willy Tarreauec6c5df2008-07-15 00:22:45 +020035
Christopher Fauletc1b730a2017-10-24 12:00:51 +020036#include <proto/applet.h>
37#include <proto/cli.h>
William Lallemand5f232402012-04-05 18:02:55 +020038#include <proto/frontend.h>
Willy Tarreau35b51c62018-09-10 15:38:55 +020039#include <proto/h1.h>
Willy Tarreauec6c5df2008-07-15 00:22:45 +020040#include <proto/log.h>
Willy Tarreauc8368452012-12-21 00:09:23 +010041#include <proto/sample.h>
Willy Tarreaufb0afa72015-04-03 14:46:27 +020042#include <proto/stream.h>
Willy Tarreau827aee92011-03-10 16:55:02 +010043#include <proto/stream_interface.h>
Willy Tarreau773d65f2012-10-12 14:56:11 +020044#ifdef USE_OPENSSL
45#include <proto/ssl_sock.h>
46#endif
Willy Tarreaubaaee002006-06-26 02:48:02 +020047
Dragan Dosen43885c72015-10-01 13:18:13 +020048struct log_fmt {
49 char *name;
50 struct {
Willy Tarreau83061a82018-07-13 11:56:34 +020051 struct buffer sep1; /* first pid separator */
52 struct buffer sep2; /* second pid separator */
Dragan Dosen43885c72015-10-01 13:18:13 +020053 } pid;
54};
55
56static const struct log_fmt log_formats[LOG_FORMATS] = {
57 [LOG_FORMAT_RFC3164] = {
58 .name = "rfc3164",
59 .pid = {
Willy Tarreau843b7cb2018-07-13 10:54:26 +020060 .sep1 = { .area = "[", .data = 1 },
61 .sep2 = { .area = "]: ", .data = 3 }
Dragan Dosen43885c72015-10-01 13:18:13 +020062 }
63 },
64 [LOG_FORMAT_RFC5424] = {
65 .name = "rfc5424",
66 .pid = {
Willy Tarreau843b7cb2018-07-13 10:54:26 +020067 .sep1 = { .area = " ", .data = 1 },
68 .sep2 = { .area = " - ", .data = 3 }
Dragan Dosen43885c72015-10-01 13:18:13 +020069 }
Willy Tarreaue8746a02018-11-12 08:45:00 +010070 },
71 [LOG_FORMAT_SHORT] = {
72 .name = "short",
73 .pid = {
74 .sep1 = { .area = "", .data = 0 },
75 .sep2 = { .area = " ", .data = 1 },
76 }
77 },
Willy Tarreauc1b06452018-11-12 11:57:56 +010078 [LOG_FORMAT_RAW] = {
79 .name = "raw",
80 .pid = {
81 .sep1 = { .area = "", .data = 0 },
82 .sep2 = { .area = "", .data = 0 },
83 }
84 },
Dragan Dosen1322d092015-09-22 16:05:32 +020085};
86
Dragan Dosen835b9212016-02-12 13:23:03 +010087#define FD_SETS_ARE_BITFIELDS
88#ifdef FD_SETS_ARE_BITFIELDS
89/*
90 * This map is used with all the FD_* macros to check whether a particular bit
91 * is set or not. Each bit represents an ACSII code. FD_SET() sets those bytes
92 * which should be escaped. When FD_ISSET() returns non-zero, it means that the
93 * byte should be escaped. Be careful to always pass bytes from 0 to 255
94 * exclusively to the macros.
95 */
96fd_set rfc5424_escape_map[(sizeof(fd_set) > (256/8)) ? 1 : ((256/8) / sizeof(fd_set))];
Willy Tarreaue10cd482018-09-10 18:16:53 +020097fd_set hdr_encode_map[(sizeof(fd_set) > (256/8)) ? 1 : ((256/8) / sizeof(fd_set))];
98fd_set url_encode_map[(sizeof(fd_set) > (256/8)) ? 1 : ((256/8) / sizeof(fd_set))];
99fd_set http_encode_map[(sizeof(fd_set) > (256/8)) ? 1 : ((256/8) / sizeof(fd_set))];
Dragan Dosen835b9212016-02-12 13:23:03 +0100100
101#else
102#error "Check if your OS uses bitfields for fd_sets"
103#endif
104
Willy Tarreaubaaee002006-06-26 02:48:02 +0200105const char *log_facilities[NB_LOG_FACILITIES] = {
106 "kern", "user", "mail", "daemon",
107 "auth", "syslog", "lpr", "news",
108 "uucp", "cron", "auth2", "ftp",
109 "ntp", "audit", "alert", "cron2",
110 "local0", "local1", "local2", "local3",
111 "local4", "local5", "local6", "local7"
112};
113
Willy Tarreaubaaee002006-06-26 02:48:02 +0200114const char *log_levels[NB_LOG_LEVELS] = {
115 "emerg", "alert", "crit", "err",
116 "warning", "notice", "info", "debug"
117};
118
Willy Tarreau570f2212013-06-10 16:42:09 +0200119const 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 +0200120const char sess_fin_state[8] = "-RCHDLQT"; /* cliRequest, srvConnect, srvHeader, Data, Last, Queue, Tarpit */
Willy Tarreaubaaee002006-06-26 02:48:02 +0200121
William Lallemand723b73a2012-02-08 16:37:49 +0100122
123/* log_format */
124struct logformat_type {
125 char *name;
126 int type;
William Lallemandbddd4fd2012-02-27 11:23:10 +0100127 int mode;
William Lallemand5e19a282012-04-02 16:22:10 +0200128 int lw; /* logwait bitsfield */
William Lallemandb7ff6a32012-03-02 14:35:21 +0100129 int (*config_callback)(struct logformat_node *node, struct proxy *curproxy);
Willy Tarreau2beef582012-12-20 17:22:52 +0100130 const char *replace_by; /* new option to use instead of old one */
William Lallemand723b73a2012-02-08 16:37:49 +0100131};
132
William Lallemandb7ff6a32012-03-02 14:35:21 +0100133int prepare_addrsource(struct logformat_node *node, struct proxy *curproxy);
134
William Lallemand723b73a2012-02-08 16:37:49 +0100135/* log_format variable names */
136static const struct logformat_type logformat_keywords[] = {
William Lallemand5e19a282012-04-02 16:22:10 +0200137 { "o", LOG_FMT_GLOBAL, PR_MODE_TCP, 0, NULL }, /* global option */
Willy Tarreau2beef582012-12-20 17:22:52 +0100138
139 /* please keep these lines sorted ! */
140 { "B", LOG_FMT_BYTES, PR_MODE_TCP, LW_BYTES, NULL }, /* bytes from server to client */
141 { "CC", LOG_FMT_CCLIENT, PR_MODE_HTTP, LW_REQHDR, NULL }, /* client cookie */
142 { "CS", LOG_FMT_CSERVER, PR_MODE_HTTP, LW_RSPHDR, NULL }, /* server cookie */
143 { "H", LOG_FMT_HOSTNAME, PR_MODE_TCP, LW_INIT, NULL }, /* Hostname */
144 { "ID", LOG_FMT_UNIQUEID, PR_MODE_HTTP, LW_BYTES, NULL }, /* Unique ID */
Willy Tarreau4bf99632014-06-13 12:21:40 +0200145 { "ST", LOG_FMT_STATUS, PR_MODE_TCP, LW_RESP, NULL }, /* status code */
William Lallemand5e19a282012-04-02 16:22:10 +0200146 { "T", LOG_FMT_DATEGMT, PR_MODE_TCP, LW_INIT, NULL }, /* date GMT */
Thierry FOURNIER / OZON.IO4cac3592016-07-28 17:19:45 +0200147 { "Ta", LOG_FMT_Ta, PR_MODE_HTTP, LW_BYTES, NULL }, /* Time active (tr to end) */
Willy Tarreau2beef582012-12-20 17:22:52 +0100148 { "Tc", LOG_FMT_TC, PR_MODE_TCP, LW_BYTES, NULL }, /* Tc */
Thierry FOURNIER / OZON.IO4cac3592016-07-28 17:19:45 +0200149 { "Th", LOG_FMT_Th, PR_MODE_TCP, LW_BYTES, NULL }, /* Time handshake */
150 { "Ti", LOG_FMT_Ti, PR_MODE_HTTP, LW_BYTES, NULL }, /* Time idle */
151 { "Tl", LOG_FMT_DATELOCAL, PR_MODE_TCP, LW_INIT, NULL }, /* date local timezone */
152 { "Tq", LOG_FMT_TQ, PR_MODE_HTTP, LW_BYTES, NULL }, /* Tq=Th+Ti+TR */
153 { "Tr", LOG_FMT_Tr, PR_MODE_HTTP, LW_BYTES, NULL }, /* Tr */
154 { "TR", LOG_FMT_TR, PR_MODE_HTTP, LW_BYTES, NULL }, /* Time to receive a valid request */
Willy Tarreau27b639d2016-05-17 17:55:27 +0200155 { "Td", LOG_FMT_TD, PR_MODE_TCP, LW_BYTES, NULL }, /* Td = Tt - (Tq + Tw + Tc + Tr) */
Willy Tarreau2beef582012-12-20 17:22:52 +0100156 { "Ts", LOG_FMT_TS, PR_MODE_TCP, LW_INIT, NULL }, /* timestamp GMT */
William Lallemand5e19a282012-04-02 16:22:10 +0200157 { "Tt", LOG_FMT_TT, PR_MODE_TCP, LW_BYTES, NULL }, /* Tt */
Willy Tarreau2beef582012-12-20 17:22:52 +0100158 { "Tw", LOG_FMT_TW, PR_MODE_TCP, LW_BYTES, NULL }, /* Tw */
159 { "U", LOG_FMT_BYTES_UP, PR_MODE_TCP, LW_BYTES, NULL }, /* bytes from client to server */
William Lallemand5e19a282012-04-02 16:22:10 +0200160 { "ac", LOG_FMT_ACTCONN, PR_MODE_TCP, LW_BYTES, NULL }, /* actconn */
Willy Tarreau2beef582012-12-20 17:22:52 +0100161 { "b", LOG_FMT_BACKEND, PR_MODE_TCP, LW_INIT, NULL }, /* backend */
William Lallemand5e19a282012-04-02 16:22:10 +0200162 { "bc", LOG_FMT_BECONN, PR_MODE_TCP, LW_BYTES, NULL }, /* beconn */
Willy Tarreau2beef582012-12-20 17:22:52 +0100163 { "bi", LOG_FMT_BACKENDIP, PR_MODE_TCP, LW_BCKIP, prepare_addrsource }, /* backend source ip */
164 { "bp", LOG_FMT_BACKENDPORT, PR_MODE_TCP, LW_BCKIP, prepare_addrsource }, /* backend source port */
William Lallemand5e19a282012-04-02 16:22:10 +0200165 { "bq", LOG_FMT_BCKQUEUE, PR_MODE_TCP, LW_BYTES, NULL }, /* backend_queue */
Willy Tarreaud02286d2017-06-23 11:23:43 +0200166 { "ci", LOG_FMT_CLIENTIP, PR_MODE_TCP, LW_CLIP | LW_XPRT, NULL }, /* client ip */
167 { "cp", LOG_FMT_CLIENTPORT, PR_MODE_TCP, LW_CLIP | LW_XPRT, NULL }, /* client port */
Willy Tarreau2beef582012-12-20 17:22:52 +0100168 { "f", LOG_FMT_FRONTEND, PR_MODE_TCP, LW_INIT, NULL }, /* frontend */
169 { "fc", LOG_FMT_FECONN, PR_MODE_TCP, LW_BYTES, NULL }, /* feconn */
Willy Tarreaud02286d2017-06-23 11:23:43 +0200170 { "fi", LOG_FMT_FRONTENDIP, PR_MODE_TCP, LW_FRTIP | LW_XPRT, NULL }, /* frontend ip */
171 { "fp", LOG_FMT_FRONTENDPORT, PR_MODE_TCP, LW_FRTIP | LW_XPRT, NULL }, /* frontend port */
Willy Tarreau2beef582012-12-20 17:22:52 +0100172 { "ft", LOG_FMT_FRONTEND_XPRT, PR_MODE_TCP, LW_INIT, NULL }, /* frontend with transport mode */
Willy Tarreaud9ed3d22014-06-13 12:23:06 +0200173 { "hr", LOG_FMT_HDRREQUEST, PR_MODE_TCP, LW_REQHDR, NULL }, /* header request */
174 { "hrl", LOG_FMT_HDRREQUESTLIST, PR_MODE_TCP, LW_REQHDR, NULL }, /* header request list */
175 { "hs", LOG_FMT_HDRRESPONS, PR_MODE_TCP, LW_RSPHDR, NULL }, /* header response */
176 { "hsl", LOG_FMT_HDRRESPONSLIST, PR_MODE_TCP, LW_RSPHDR, NULL }, /* header response list */
Andrew Hayworth0ebc55f2015-04-27 21:37:03 +0000177 { "HM", LOG_FMT_HTTP_METHOD, PR_MODE_HTTP, LW_REQ, NULL }, /* HTTP method */
178 { "HP", LOG_FMT_HTTP_PATH, PR_MODE_HTTP, LW_REQ, NULL }, /* HTTP path */
Andrew Hayworthe63ac872015-07-31 16:14:16 +0000179 { "HQ", LOG_FMT_HTTP_QUERY, PR_MODE_HTTP, LW_REQ, NULL }, /* HTTP query */
Andrew Hayworth0ebc55f2015-04-27 21:37:03 +0000180 { "HU", LOG_FMT_HTTP_URI, PR_MODE_HTTP, LW_REQ, NULL }, /* HTTP full URI */
181 { "HV", LOG_FMT_HTTP_VERSION, PR_MODE_HTTP, LW_REQ, NULL }, /* HTTP version */
Willy Tarreau7346acb2014-08-28 15:03:15 +0200182 { "lc", LOG_FMT_LOGCNT, PR_MODE_TCP, LW_INIT, NULL }, /* log counter */
Willy Tarreau2beef582012-12-20 17:22:52 +0100183 { "ms", LOG_FMT_MS, PR_MODE_TCP, LW_INIT, NULL }, /* accept date millisecond */
William Lallemand5e19a282012-04-02 16:22:10 +0200184 { "pid", LOG_FMT_PID, PR_MODE_TCP, LW_INIT, NULL }, /* log pid */
Willy Tarreau2beef582012-12-20 17:22:52 +0100185 { "r", LOG_FMT_REQ, PR_MODE_HTTP, LW_REQ, NULL }, /* request */
186 { "rc", LOG_FMT_RETRIES, PR_MODE_TCP, LW_BYTES, NULL }, /* retries */
Willy Tarreau1f0da242014-01-25 11:01:50 +0100187 { "rt", LOG_FMT_COUNTER, PR_MODE_TCP, LW_REQ, NULL }, /* request counter (HTTP or TCP session) */
Willy Tarreau2beef582012-12-20 17:22:52 +0100188 { "s", LOG_FMT_SERVER, PR_MODE_TCP, LW_SVID, NULL }, /* server */
189 { "sc", LOG_FMT_SRVCONN, PR_MODE_TCP, LW_BYTES, NULL }, /* srv_conn */
190 { "si", LOG_FMT_SERVERIP, PR_MODE_TCP, LW_SVIP, NULL }, /* server destination ip */
191 { "sp", LOG_FMT_SERVERPORT, PR_MODE_TCP, LW_SVIP, NULL }, /* server destination port */
192 { "sq", LOG_FMT_SRVQUEUE, PR_MODE_TCP, LW_BYTES, NULL }, /* srv_queue */
Willy Tarreauffc3fcd2012-10-12 20:17:54 +0200193 { "sslc", LOG_FMT_SSL_CIPHER, PR_MODE_TCP, LW_XPRT, NULL }, /* client-side SSL ciphers */
194 { "sslv", LOG_FMT_SSL_VERSION, PR_MODE_TCP, LW_XPRT, NULL }, /* client-side SSL protocol version */
Willy Tarreau2beef582012-12-20 17:22:52 +0100195 { "t", LOG_FMT_DATE, PR_MODE_TCP, LW_INIT, NULL }, /* date */
Thierry FOURNIER / OZON.IO4cac3592016-07-28 17:19:45 +0200196 { "tr", LOG_FMT_tr, PR_MODE_HTTP, LW_INIT, NULL }, /* date of start of request */
197 { "trg",LOG_FMT_trg, PR_MODE_HTTP, LW_INIT, NULL }, /* date of start of request, GMT */
198 { "trl",LOG_FMT_trl, PR_MODE_HTTP, LW_INIT, NULL }, /* date of start of request, local */
Willy Tarreau2beef582012-12-20 17:22:52 +0100199 { "ts", LOG_FMT_TERMSTATE, PR_MODE_TCP, LW_BYTES, NULL },/* termination state */
200 { "tsc", LOG_FMT_TERMSTATE_CK, PR_MODE_TCP, LW_INIT, NULL },/* termination state */
201
202 /* The following tags are deprecated and will be removed soon */
203 { "Bi", LOG_FMT_BACKENDIP, PR_MODE_TCP, LW_BCKIP, prepare_addrsource, "bi" }, /* backend source ip */
204 { "Bp", LOG_FMT_BACKENDPORT, PR_MODE_TCP, LW_BCKIP, prepare_addrsource, "bp" }, /* backend source port */
Willy Tarreaud02286d2017-06-23 11:23:43 +0200205 { "Ci", LOG_FMT_CLIENTIP, PR_MODE_TCP, LW_CLIP | LW_XPRT, NULL, "ci" }, /* client ip */
206 { "Cp", LOG_FMT_CLIENTPORT, PR_MODE_TCP, LW_CLIP | LW_XPRT, NULL, "cp" }, /* client port */
207 { "Fi", LOG_FMT_FRONTENDIP, PR_MODE_TCP, LW_FRTIP | LW_XPRT, NULL, "fi" }, /* frontend ip */
208 { "Fp", LOG_FMT_FRONTENDPORT, PR_MODE_TCP, LW_FRTIP | LW_XPRT, NULL, "fp" }, /* frontend port */
Willy Tarreau2beef582012-12-20 17:22:52 +0100209 { "Si", LOG_FMT_SERVERIP, PR_MODE_TCP, LW_SVIP, NULL, "si" }, /* server destination ip */
210 { "Sp", LOG_FMT_SERVERPORT, PR_MODE_TCP, LW_SVIP, NULL, "sp" }, /* server destination port */
211 { "cc", LOG_FMT_CCLIENT, PR_MODE_HTTP, LW_REQHDR, NULL, "CC" }, /* client cookie */
212 { "cs", LOG_FMT_CSERVER, PR_MODE_HTTP, LW_RSPHDR, NULL, "CS" }, /* server cookie */
213 { "st", LOG_FMT_STATUS, PR_MODE_HTTP, LW_RESP, NULL, "ST" }, /* status code */
William Lallemand5e19a282012-04-02 16:22:10 +0200214 { 0, 0, 0, 0, NULL }
William Lallemand723b73a2012-02-08 16:37:49 +0100215};
216
Thierry FOURNIER / OZON.IO4cac3592016-07-28 17:19:45 +0200217char 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
218char 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 +0100219char 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 +0100220char *log_format = NULL;
221
Dragan Dosen0b85ece2015-09-25 19:17:44 +0200222/* Default string used for structured-data part in RFC5424 formatted
223 * syslog messages.
224 */
225char default_rfc5424_sd_log_format[] = "- ";
Dragan Dosen1322d092015-09-22 16:05:32 +0200226
Willy Tarreau13ef7732018-11-12 07:25:28 +0100227/* total number of dropped logs */
228unsigned int dropped_logs = 0;
229
Dragan Dosen1322d092015-09-22 16:05:32 +0200230/* This is a global syslog header, common to all outgoing messages in
231 * RFC3164 format. It begins with time-based part and is updated by
232 * update_log_hdr().
Dragan Dosen59cee972015-09-19 22:09:02 +0200233 */
Christopher Fauletf8188c62017-06-02 16:20:16 +0200234THREAD_LOCAL char *logheader = NULL;
Dragan Dosen59cee972015-09-19 22:09:02 +0200235
Dragan Dosen1322d092015-09-22 16:05:32 +0200236/* This is a global syslog header for messages in RFC5424 format. It is
237 * updated by update_log_hdr_rfc5424().
238 */
Christopher Fauletf8188c62017-06-02 16:20:16 +0200239THREAD_LOCAL char *logheader_rfc5424 = NULL;
Dragan Dosen1322d092015-09-22 16:05:32 +0200240
Dragan Dosen59cee972015-09-19 22:09:02 +0200241/* This is a global syslog message buffer, common to all outgoing
242 * messages. It contains only the data part.
Willy Tarreaub1a2faf2012-03-19 16:51:53 +0100243 */
Christopher Fauletf8188c62017-06-02 16:20:16 +0200244THREAD_LOCAL char *logline = NULL;
Willy Tarreaub1a2faf2012-03-19 16:51:53 +0100245
Dragan Dosen0b85ece2015-09-25 19:17:44 +0200246/* A global syslog message buffer, common to all RFC5424 syslog messages.
247 * Currently, it is used for generating the structured-data part.
248 */
Christopher Fauletf8188c62017-06-02 16:20:16 +0200249THREAD_LOCAL char *logline_rfc5424 = NULL;
Dragan Dosen0b85ece2015-09-25 19:17:44 +0200250
Christopher Fauletd4696382017-10-24 11:44:05 +0200251/* A global buffer used to store all startup alerts/warnings. It will then be
252 * retrieve on the CLI. */
Christopher Fauletf8188c62017-06-02 16:20:16 +0200253static THREAD_LOCAL char *startup_logs = NULL;
Christopher Fauletd4696382017-10-24 11:44:05 +0200254
William Lallemand723b73a2012-02-08 16:37:49 +0100255struct logformat_var_args {
256 char *name;
257 int mask;
258};
259
260struct logformat_var_args var_args_list[] = {
261// global
262 { "M", LOG_OPT_MANDATORY },
263 { "Q", LOG_OPT_QUOTE },
William Lallemand5f232402012-04-05 18:02:55 +0200264 { "X", LOG_OPT_HEXA },
Dragan Dosen835b9212016-02-12 13:23:03 +0100265 { "E", LOG_OPT_ESC },
William Lallemand723b73a2012-02-08 16:37:49 +0100266 { 0, 0 }
267};
268
Willy Tarreaub1f3af22013-04-12 18:30:32 +0200269/* return the name of the directive used in the current proxy for which we're
270 * currently parsing a header, when it is known.
271 */
272static inline const char *fmt_directive(const struct proxy *curproxy)
273{
Willy Tarreaubf0addb2013-12-02 12:24:54 +0100274 switch (curproxy->conf.args.ctx) {
Willy Tarreau53e1a6d2015-07-09 11:20:00 +0200275 case ARGC_ACL:
276 return "acl";
277 case ARGC_STK:
278 return "stick";
279 case ARGC_TRK:
280 return "track-sc";
281 case ARGC_LOG:
282 return "log-format";
Dragan Dosen0b85ece2015-09-25 19:17:44 +0200283 case ARGC_LOGSD:
284 return "log-format-sd";
Willy Tarreaubf0addb2013-12-02 12:24:54 +0100285 case ARGC_HRQ:
Thierry FOURNIER1c0054f2013-11-20 15:09:52 +0100286 return "http-request";
Willy Tarreaubf0addb2013-12-02 12:24:54 +0100287 case ARGC_HRS:
Thierry FOURNIER1c0054f2013-11-20 15:09:52 +0100288 return "http-response";
Willy Tarreau53e1a6d2015-07-09 11:20:00 +0200289 case ARGC_UIF:
290 return "unique-id-format";
Thierry FOURNIERd18cd0f2013-11-29 12:15:45 +0100291 case ARGC_RDR:
Willy Tarreau53e1a6d2015-07-09 11:20:00 +0200292 return "redirect";
293 case ARGC_CAP:
294 return "capture";
Willy Tarreau28d976d2015-07-09 11:39:33 +0200295 case ARGC_SRV:
296 return "server";
Christopher Fauletf7e4e7e2016-10-27 22:29:49 +0200297 case ARGC_SPOE:
298 return "spoe-message";
Thierry FOURNIER / OZON.IO4ed1c952016-11-24 23:57:54 +0100299 case ARGC_UBK:
300 return "use_backend";
Willy Tarreaubf0addb2013-12-02 12:24:54 +0100301 default:
Willy Tarreau53e1a6d2015-07-09 11:20:00 +0200302 return "undefined(please report this bug)"; /* must never happen */
Willy Tarreaubf0addb2013-12-02 12:24:54 +0100303 }
Willy Tarreaub1f3af22013-04-12 18:30:32 +0200304}
305
William Lallemand723b73a2012-02-08 16:37:49 +0100306/*
William Lallemandb7ff6a32012-03-02 14:35:21 +0100307 * callback used to configure addr source retrieval
308 */
309int prepare_addrsource(struct logformat_node *node, struct proxy *curproxy)
310{
311 curproxy->options2 |= PR_O2_SRC_ADDR;
312
313 return 0;
314}
315
316
317/*
Thierry FOURNIER / OZON.IObca46f02016-11-22 23:13:04 +0100318 * Parse args in a logformat_var. Returns 0 in error
319 * case, otherwise, it returns 1.
William Lallemand723b73a2012-02-08 16:37:49 +0100320 */
Thierry FOURNIER / OZON.IO8a4e4422016-11-23 00:41:28 +0100321int parse_logformat_var_args(char *args, struct logformat_node *node, char **err)
William Lallemand723b73a2012-02-08 16:37:49 +0100322{
323 int i = 0;
324 int end = 0;
325 int flags = 0; // 1 = + 2 = -
326 char *sp = NULL; // start pointer
327
Thierry FOURNIER / OZON.IO8a4e4422016-11-23 00:41:28 +0100328 if (args == NULL) {
329 memprintf(err, "internal error: parse_logformat_var_args() expects non null 'args'");
Thierry FOURNIER / OZON.IObca46f02016-11-22 23:13:04 +0100330 return 0;
Thierry FOURNIER / OZON.IO8a4e4422016-11-23 00:41:28 +0100331 }
William Lallemand723b73a2012-02-08 16:37:49 +0100332
333 while (1) {
334 if (*args == '\0')
335 end = 1;
336
337 if (*args == '+') {
338 // add flag
339 sp = args + 1;
340 flags = 1;
341 }
342 if (*args == '-') {
343 // delete flag
344 sp = args + 1;
345 flags = 2;
346 }
347
348 if (*args == '\0' || *args == ',') {
349 *args = '\0';
Willy Tarreau254d44c2012-12-20 18:19:26 +0100350 for (i = 0; sp && var_args_list[i].name; i++) {
William Lallemand723b73a2012-02-08 16:37:49 +0100351 if (strcmp(sp, var_args_list[i].name) == 0) {
352 if (flags == 1) {
353 node->options |= var_args_list[i].mask;
354 break;
355 } else if (flags == 2) {
356 node->options &= ~var_args_list[i].mask;
357 break;
358 }
359 }
360 }
361 sp = NULL;
362 if (end)
363 break;
364 }
Willy Tarreau254d44c2012-12-20 18:19:26 +0100365 args++;
William Lallemand723b73a2012-02-08 16:37:49 +0100366 }
Thierry FOURNIER / OZON.IObca46f02016-11-22 23:13:04 +0100367 return 1;
William Lallemand723b73a2012-02-08 16:37:49 +0100368}
369
370/*
Willy Tarreau8a3f52f2012-12-20 21:23:42 +0100371 * Parse a variable '%varname' or '%{args}varname' in log-format. The caller
372 * must pass the args part in the <arg> pointer with its length in <arg_len>,
373 * and varname with its length in <var> and <var_len> respectively. <arg> is
374 * ignored when arg_len is 0. Neither <var> nor <var_len> may be null.
Thierry FOURNIER / OZON.IOeca4d952016-11-22 22:06:04 +0100375 * Returns false in error case and err is filled, otherwise returns true.
William Lallemand723b73a2012-02-08 16:37:49 +0100376 */
Thierry FOURNIER / OZON.IO8a4e4422016-11-23 00:41:28 +0100377int 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 +0100378{
Willy Tarreau8a3f52f2012-12-20 21:23:42 +0100379 int j;
380 struct logformat_node *node;
William Lallemand723b73a2012-02-08 16:37:49 +0100381
Willy Tarreau8a3f52f2012-12-20 21:23:42 +0100382 for (j = 0; logformat_keywords[j].name; j++) { // search a log type
383 if (strlen(logformat_keywords[j].name) == var_len &&
384 strncmp(var, logformat_keywords[j].name, var_len) == 0) {
385 if (logformat_keywords[j].mode != PR_MODE_HTTP || curproxy->mode == PR_MODE_HTTP) {
Vincent Bernat02779b62016-04-03 13:48:43 +0200386 node = calloc(1, sizeof(*node));
Thierry FOURNIER / OZON.IO9cbfef22016-11-22 23:24:10 +0100387 if (!node) {
Thierry FOURNIER / OZON.IO8a4e4422016-11-23 00:41:28 +0100388 memprintf(err, "out of memory error");
Thierry FOURNIER / OZON.IO9cbfef22016-11-22 23:24:10 +0100389 return 0;
390 }
Willy Tarreau8a3f52f2012-12-20 21:23:42 +0100391 node->type = logformat_keywords[j].type;
392 node->options = *defoptions;
393 if (arg_len) {
394 node->arg = my_strndup(arg, arg_len);
Thierry FOURNIER / OZON.IO8a4e4422016-11-23 00:41:28 +0100395 if (!parse_logformat_var_args(node->arg, node, err))
Thierry FOURNIER / OZON.IOa2c38d72016-11-22 23:11:21 +0100396 return 0;
Willy Tarreau8a3f52f2012-12-20 21:23:42 +0100397 }
398 if (node->type == LOG_FMT_GLOBAL) {
399 *defoptions = node->options;
400 free(node->arg);
401 free(node);
402 } else {
403 if (logformat_keywords[j].config_callback &&
404 logformat_keywords[j].config_callback(node, curproxy) != 0) {
Thierry FOURNIER / OZON.IOeca4d952016-11-22 22:06:04 +0100405 return 0;
William Lallemand723b73a2012-02-08 16:37:49 +0100406 }
Willy Tarreau8a3f52f2012-12-20 21:23:42 +0100407 curproxy->to_log |= logformat_keywords[j].lw;
408 LIST_ADDQ(list_format, &node->list);
William Lallemand723b73a2012-02-08 16:37:49 +0100409 }
Willy Tarreau8a3f52f2012-12-20 21:23:42 +0100410 if (logformat_keywords[j].replace_by)
Christopher Faulet767a84b2017-11-24 16:50:31 +0100411 ha_warning("parsing [%s:%d] : deprecated variable '%s' in '%s', please replace it with '%s'.\n",
412 curproxy->conf.args.file, curproxy->conf.args.line,
413 logformat_keywords[j].name, fmt_directive(curproxy), logformat_keywords[j].replace_by);
Thierry FOURNIER / OZON.IOeca4d952016-11-22 22:06:04 +0100414 return 1;
Willy Tarreau8a3f52f2012-12-20 21:23:42 +0100415 } else {
Thierry FOURNIER / OZON.IO8a4e4422016-11-23 00:41:28 +0100416 memprintf(err, "format variable '%s' is reserved for HTTP mode",
417 logformat_keywords[j].name);
Thierry FOURNIER / OZON.IOeca4d952016-11-22 22:06:04 +0100418 return 0;
William Lallemand723b73a2012-02-08 16:37:49 +0100419 }
William Lallemand723b73a2012-02-08 16:37:49 +0100420 }
421 }
Willy Tarreau8a3f52f2012-12-20 21:23:42 +0100422
423 j = var[var_len];
424 var[var_len] = 0;
Thierry FOURNIER / OZON.IO8a4e4422016-11-23 00:41:28 +0100425 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 +0100426 var[var_len] = j;
Thierry FOURNIER / OZON.IOeca4d952016-11-22 22:06:04 +0100427 return 0;
William Lallemand723b73a2012-02-08 16:37:49 +0100428}
429
430/*
431 * push to the logformat linked list
432 *
433 * start: start pointer
434 * end: end text pointer
435 * type: string type
William Lallemand1d705562012-03-12 12:46:41 +0100436 * list_format: destination list
William Lallemand723b73a2012-02-08 16:37:49 +0100437 *
438 * LOG_TEXT: copy chars from start to end excluding end.
439 *
440*/
Thierry FOURNIER / OZON.IO8a4e4422016-11-23 00:41:28 +0100441int add_to_logformat_list(char *start, char *end, int type, struct list *list_format, char **err)
William Lallemand723b73a2012-02-08 16:37:49 +0100442{
443 char *str;
444
Willy Tarreaua3571662012-12-20 21:59:12 +0100445 if (type == LF_TEXT) { /* type text */
Vincent Bernat02779b62016-04-03 13:48:43 +0200446 struct logformat_node *node = calloc(1, sizeof(*node));
Thierry FOURNIER / OZON.IO9cbfef22016-11-22 23:24:10 +0100447 if (!node) {
Thierry FOURNIER / OZON.IO8a4e4422016-11-23 00:41:28 +0100448 memprintf(err, "out of memory error");
Thierry FOURNIER / OZON.IO9cbfef22016-11-22 23:24:10 +0100449 return 0;
450 }
Vincent Bernat02779b62016-04-03 13:48:43 +0200451 str = calloc(1, end - start + 1);
William Lallemand723b73a2012-02-08 16:37:49 +0100452 strncpy(str, start, end - start);
William Lallemand723b73a2012-02-08 16:37:49 +0100453 str[end - start] = '\0';
454 node->arg = str;
William Lallemand1d705562012-03-12 12:46:41 +0100455 node->type = LOG_FMT_TEXT; // type string
456 LIST_ADDQ(list_format, &node->list);
Willy Tarreaua3571662012-12-20 21:59:12 +0100457 } else if (type == LF_SEPARATOR) {
Vincent Bernat02779b62016-04-03 13:48:43 +0200458 struct logformat_node *node = calloc(1, sizeof(*node));
Thierry FOURNIER / OZON.IO9cbfef22016-11-22 23:24:10 +0100459 if (!node) {
Thierry FOURNIER / OZON.IO8a4e4422016-11-23 00:41:28 +0100460 memprintf(err, "out of memory error");
Thierry FOURNIER / OZON.IO9cbfef22016-11-22 23:24:10 +0100461 return 0;
462 }
William Lallemand1d705562012-03-12 12:46:41 +0100463 node->type = LOG_FMT_SEPARATOR;
464 LIST_ADDQ(list_format, &node->list);
William Lallemand723b73a2012-02-08 16:37:49 +0100465 }
Thierry FOURNIER / OZON.IOa2c38d72016-11-22 23:11:21 +0100466 return 1;
William Lallemand723b73a2012-02-08 16:37:49 +0100467}
468
469/*
Willy Tarreauc8368452012-12-21 00:09:23 +0100470 * Parse the sample fetch expression <text> and add a node to <list_format> upon
471 * success. At the moment, sample converters are not yet supported but fetch arguments
Willy Tarreaua4312fa2013-04-02 16:34:32 +0200472 * should work. The curpx->conf.args.ctx must be set by the caller.
Thierry FOURNIER / OZON.IOa2c38d72016-11-22 23:11:21 +0100473 *
474 * In error case, the function returns 0, otherwise it returns 1.
Willy Tarreauc8368452012-12-21 00:09:23 +0100475 */
Thierry FOURNIER / OZON.IO8a4e4422016-11-23 00:41:28 +0100476int 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 +0100477{
478 char *cmd[2];
479 struct sample_expr *expr;
480 struct logformat_node *node;
481 int cmd_arg;
482
483 cmd[0] = text;
484 cmd[1] = "";
485 cmd_arg = 0;
486
Thierry FOURNIER / OZON.IO8a4e4422016-11-23 00:41:28 +0100487 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 +0100488 if (!expr) {
Thierry FOURNIER / OZON.IO8a4e4422016-11-23 00:41:28 +0100489 memprintf(err, "failed to parse sample expression <%s> : %s", text, *err);
Thierry FOURNIER / OZON.IOa2c38d72016-11-22 23:11:21 +0100490 return 0;
Willy Tarreauc8368452012-12-21 00:09:23 +0100491 }
492
Vincent Bernat02779b62016-04-03 13:48:43 +0200493 node = calloc(1, sizeof(*node));
Thierry FOURNIER / OZON.IO9cbfef22016-11-22 23:24:10 +0100494 if (!node) {
Thierry FOURNIER / OZON.IO8a4e4422016-11-23 00:41:28 +0100495 memprintf(err, "out of memory error");
Thierry FOURNIER / OZON.IO9cbfef22016-11-22 23:24:10 +0100496 return 0;
497 }
Willy Tarreauc8368452012-12-21 00:09:23 +0100498 node->type = LOG_FMT_EXPR;
499 node->expr = expr;
500 node->options = options;
501
502 if (arg_len) {
503 node->arg = my_strndup(arg, arg_len);
Thierry FOURNIER / OZON.IO8a4e4422016-11-23 00:41:28 +0100504 if (!parse_logformat_var_args(node->arg, node, err))
Thierry FOURNIER / OZON.IOa2c38d72016-11-22 23:11:21 +0100505 return 0;
Willy Tarreauc8368452012-12-21 00:09:23 +0100506 }
Willy Tarreau434c57c2013-01-08 01:10:24 +0100507 if (expr->fetch->val & cap & SMP_VAL_REQUEST)
Willy Tarreauc8368452012-12-21 00:09:23 +0100508 node->options |= LOG_OPT_REQ_CAP; /* fetch method is request-compatible */
509
Willy Tarreau434c57c2013-01-08 01:10:24 +0100510 if (expr->fetch->val & cap & SMP_VAL_RESPONSE)
Willy Tarreauc8368452012-12-21 00:09:23 +0100511 node->options |= LOG_OPT_RES_CAP; /* fetch method is response-compatible */
512
Thierry FOURNIER / OZON.IOa2c38d72016-11-22 23:11:21 +0100513 if (!(expr->fetch->val & cap)) {
David Carlier93e8b882017-09-21 14:36:43 +0000514 free(node);
515 node = NULL;
Thierry FOURNIER / OZON.IO8a4e4422016-11-23 00:41:28 +0100516 memprintf(err, "sample fetch <%s> may not be reliably used here because it needs '%s' which is not available here",
517 text, sample_src_names(expr->fetch->use));
Thierry FOURNIER / OZON.IOa2c38d72016-11-22 23:11:21 +0100518 return 0;
519 }
Willy Tarreau434c57c2013-01-08 01:10:24 +0100520
Willy Tarreauc8368452012-12-21 00:09:23 +0100521 /* check if we need to allocate an hdr_idx struct for HTTP parsing */
522 /* Note, we may also need to set curpx->to_log with certain fetches */
Willy Tarreau25320b22013-03-24 07:22:08 +0100523 curpx->http_needed |= !!(expr->fetch->use & SMP_USE_HTTP_ANY);
Willy Tarreauc8368452012-12-21 00:09:23 +0100524
William Lallemand65ad6e12014-01-31 15:08:02 +0100525 /* FIXME: temporary workaround for missing LW_XPRT and LW_REQ flags
526 * needed with some sample fetches (eg: ssl*). We always set it for
527 * now on, but this will leave with sample capabilities soon.
Willy Tarreau1f31c732013-01-10 16:22:27 +0100528 */
529 curpx->to_log |= LW_XPRT;
William Lallemand65ad6e12014-01-31 15:08:02 +0100530 curpx->to_log |= LW_REQ;
Willy Tarreauc8368452012-12-21 00:09:23 +0100531 LIST_ADDQ(list_format, &node->list);
Thierry FOURNIER / OZON.IOa2c38d72016-11-22 23:11:21 +0100532 return 1;
Willy Tarreauc8368452012-12-21 00:09:23 +0100533}
534
535/*
William Lallemand723b73a2012-02-08 16:37:49 +0100536 * Parse the log_format string and fill a linked list.
537 * Variable name are preceded by % and composed by characters [a-zA-Z0-9]* : %varname
Willy Tarreaua4312fa2013-04-02 16:34:32 +0200538 * You can set arguments using { } : %{many arguments}varname.
539 * The curproxy->conf.args.ctx must be set by the caller.
William Lallemand1d705562012-03-12 12:46:41 +0100540 *
541 * str: the string to parse
542 * curproxy: the proxy affected
543 * list_format: the destination list
Willy Tarreau6cbbdbf2013-02-05 18:52:25 +0100544 * options: LOG_OPT_* to force on every node
Willy Tarreau434c57c2013-01-08 01:10:24 +0100545 * cap: all SMP_VAL_* flags supported by the consumer
Thierry FOURNIER / OZON.IOa2c38d72016-11-22 23:11:21 +0100546 *
Thierry FOURNIER / OZON.IO8a4e4422016-11-23 00:41:28 +0100547 * The function returns 1 in success case, otherwise, it returns 0 and err is filled.
William Lallemand723b73a2012-02-08 16:37:49 +0100548 */
Thierry FOURNIER / OZON.IO8a4e4422016-11-23 00:41:28 +0100549int 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 +0100550{
Willy Tarreaub83bc1e2012-12-24 12:36:33 +0100551 char *sp, *str, *backfmt; /* start pointer for text parts */
Willy Tarreau8a3f52f2012-12-20 21:23:42 +0100552 char *arg = NULL; /* start pointer for args */
553 char *var = NULL; /* start pointer for vars */
554 int arg_len = 0;
555 int var_len = 0;
556 int cformat; /* current token format */
557 int pformat; /* previous token format */
William Lallemand723b73a2012-02-08 16:37:49 +0100558 struct logformat_node *tmplf, *back;
559
Willy Tarreaub83bc1e2012-12-24 12:36:33 +0100560 sp = str = backfmt = strdup(fmt);
Thierry FOURNIER / OZON.IO9cbfef22016-11-22 23:24:10 +0100561 if (!str) {
Thierry FOURNIER / OZON.IO8a4e4422016-11-23 00:41:28 +0100562 memprintf(err, "out of memory error");
Thierry FOURNIER / OZON.IO9cbfef22016-11-22 23:24:10 +0100563 return 0;
564 }
William Lallemand1dc00ef2012-08-09 16:41:35 +0200565 curproxy->to_log |= LW_INIT;
William Lallemand5e19a282012-04-02 16:22:10 +0200566
William Lallemand723b73a2012-02-08 16:37:49 +0100567 /* flush the list first. */
William Lallemand1d705562012-03-12 12:46:41 +0100568 list_for_each_entry_safe(tmplf, back, list_format, list) {
William Lallemand723b73a2012-02-08 16:37:49 +0100569 LIST_DEL(&tmplf->list);
570 free(tmplf);
571 }
572
Willy Tarreau8a3f52f2012-12-20 21:23:42 +0100573 for (cformat = LF_INIT; cformat != LF_END; str++) {
William Lallemand723b73a2012-02-08 16:37:49 +0100574 pformat = cformat;
575
Willy Tarreau8a3f52f2012-12-20 21:23:42 +0100576 if (!*str)
577 cformat = LF_END; // preset it to save all states from doing this
William Lallemand723b73a2012-02-08 16:37:49 +0100578
Joseph Herlant85b40592018-11-15 12:10:04 -0800579 /* The principle of the two-step state machine below is to first detect a change, and
Willy Tarreau8a3f52f2012-12-20 21:23:42 +0100580 * second have all common paths processed at one place. The common paths are the ones
581 * encountered in text areas (LF_INIT, LF_TEXT, LF_SEPARATOR) and at the end (LF_END).
582 * We use the common LF_INIT state to dispatch to the different final states.
583 */
584 switch (pformat) {
585 case LF_STARTVAR: // text immediately following a '%'
Willy Tarreauc8368452012-12-21 00:09:23 +0100586 arg = NULL; var = NULL;
Willy Tarreau8a3f52f2012-12-20 21:23:42 +0100587 arg_len = var_len = 0;
588 if (*str == '{') { // optional argument
589 cformat = LF_STARG;
590 arg = str + 1;
William Lallemand723b73a2012-02-08 16:37:49 +0100591 }
Willy Tarreauc8368452012-12-21 00:09:23 +0100592 else if (*str == '[') {
593 cformat = LF_STEXPR;
594 var = str + 1; // store expr in variable name
595 }
Willy Tarreau0f28f822013-12-16 01:38:33 +0100596 else if (isalpha((unsigned char)*str)) { // variable name
William Lallemand723b73a2012-02-08 16:37:49 +0100597 cformat = LF_VAR;
Willy Tarreau8a3f52f2012-12-20 21:23:42 +0100598 var = str;
William Lallemand723b73a2012-02-08 16:37:49 +0100599 }
Willy Tarreau8a3f52f2012-12-20 21:23:42 +0100600 else if (*str == '%')
601 cformat = LF_TEXT; // convert this character to a litteral (useful for '%')
Willy Tarreau0f28f822013-12-16 01:38:33 +0100602 else if (isdigit((unsigned char)*str) || *str == ' ' || *str == '\t') {
Willy Tarreau06d97f92013-12-02 17:45:48 +0100603 /* single '%' followed by blank or digit, send them both */
604 cformat = LF_TEXT;
605 pformat = LF_TEXT; /* finally we include the previous char as well */
606 sp = str - 1; /* send both the '%' and the current char */
Jim Freemana2278c82017-04-15 08:01:59 -0600607 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 +0100608 *str, (int)(str - backfmt), fmt);
Thierry FOURNIER / OZON.IOa2c38d72016-11-22 23:11:21 +0100609 return 0;
Willy Tarreau06d97f92013-12-02 17:45:48 +0100610
611 }
Willy Tarreau8a3f52f2012-12-20 21:23:42 +0100612 else
613 cformat = LF_INIT; // handle other cases of litterals
614 break;
615
616 case LF_STARG: // text immediately following '%{'
617 if (*str == '}') { // end of arg
William Lallemand723b73a2012-02-08 16:37:49 +0100618 cformat = LF_EDARG;
Willy Tarreau8a3f52f2012-12-20 21:23:42 +0100619 arg_len = str - arg;
620 *str = 0; // used for reporting errors
William Lallemand723b73a2012-02-08 16:37:49 +0100621 }
Willy Tarreau8a3f52f2012-12-20 21:23:42 +0100622 break;
623
624 case LF_EDARG: // text immediately following '%{arg}'
Willy Tarreauc8368452012-12-21 00:09:23 +0100625 if (*str == '[') {
626 cformat = LF_STEXPR;
627 var = str + 1; // store expr in variable name
628 break;
629 }
Willy Tarreau0f28f822013-12-16 01:38:33 +0100630 else if (isalnum((unsigned char)*str)) { // variable name
William Lallemand723b73a2012-02-08 16:37:49 +0100631 cformat = LF_VAR;
Willy Tarreau8a3f52f2012-12-20 21:23:42 +0100632 var = str;
633 break;
634 }
Thierry FOURNIER / OZON.IO8a4e4422016-11-23 00:41:28 +0100635 memprintf(err, "parse argument modifier without variable name near '%%{%s}'", arg);
Thierry FOURNIER / OZON.IOa2c38d72016-11-22 23:11:21 +0100636 return 0;
Willy Tarreau8a3f52f2012-12-20 21:23:42 +0100637
Willy Tarreauc8368452012-12-21 00:09:23 +0100638 case LF_STEXPR: // text immediately following '%['
639 if (*str == ']') { // end of arg
640 cformat = LF_EDEXPR;
641 var_len = str - var;
642 *str = 0; // needed for parsing the expression
643 }
644 break;
645
Willy Tarreau8a3f52f2012-12-20 21:23:42 +0100646 case LF_VAR: // text part of a variable name
647 var_len = str - var;
Willy Tarreau0f28f822013-12-16 01:38:33 +0100648 if (!isalnum((unsigned char)*str))
Willy Tarreau8a3f52f2012-12-20 21:23:42 +0100649 cformat = LF_INIT; // not variable name anymore
650 break;
651
Willy Tarreauc8368452012-12-21 00:09:23 +0100652 default: // LF_INIT, LF_TEXT, LF_SEPARATOR, LF_END, LF_EDEXPR
Willy Tarreau8a3f52f2012-12-20 21:23:42 +0100653 cformat = LF_INIT;
654 }
655
656 if (cformat == LF_INIT) { /* resynchronize state to text/sep/startvar */
657 switch (*str) {
658 case '%': cformat = LF_STARTVAR; break;
659 case ' ': cformat = LF_SEPARATOR; break;
660 case 0 : cformat = LF_END; break;
661 default : cformat = LF_TEXT; break;
William Lallemand723b73a2012-02-08 16:37:49 +0100662 }
663 }
664
Willy Tarreau8a3f52f2012-12-20 21:23:42 +0100665 if (cformat != pformat || pformat == LF_SEPARATOR) {
666 switch (pformat) {
667 case LF_VAR:
Thierry FOURNIER / OZON.IO8a4e4422016-11-23 00:41:28 +0100668 if (!parse_logformat_var(arg, arg_len, var, var_len, curproxy, list_format, &options, err))
Thierry FOURNIER / OZON.IOa2c38d72016-11-22 23:11:21 +0100669 return 0;
Willy Tarreau8a3f52f2012-12-20 21:23:42 +0100670 break;
Willy Tarreauc8368452012-12-21 00:09:23 +0100671 case LF_STEXPR:
Thierry FOURNIER / OZON.IO8a4e4422016-11-23 00:41:28 +0100672 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 +0100673 return 0;
Willy Tarreauc8368452012-12-21 00:09:23 +0100674 break;
Willy Tarreau8a3f52f2012-12-20 21:23:42 +0100675 case LF_TEXT:
676 case LF_SEPARATOR:
Thierry FOURNIER / OZON.IO8a4e4422016-11-23 00:41:28 +0100677 if (!add_to_logformat_list(sp, str, pformat, list_format, err))
Thierry FOURNIER / OZON.IOa2c38d72016-11-22 23:11:21 +0100678 return 0;
Willy Tarreau8a3f52f2012-12-20 21:23:42 +0100679 break;
680 }
681 sp = str; /* new start of text at every state switch and at every separator */
William Lallemand723b73a2012-02-08 16:37:49 +0100682 }
683 }
Willy Tarreau8a3f52f2012-12-20 21:23:42 +0100684
Thierry FOURNIER / OZON.IOa2c38d72016-11-22 23:11:21 +0100685 if (pformat == LF_STARTVAR || pformat == LF_STARG || pformat == LF_STEXPR) {
Thierry FOURNIER / OZON.IO8a4e4422016-11-23 00:41:28 +0100686 memprintf(err, "truncated line after '%s'", var ? var : arg ? arg : "%");
Thierry FOURNIER / OZON.IOa2c38d72016-11-22 23:11:21 +0100687 return 0;
688 }
Willy Tarreaub83bc1e2012-12-24 12:36:33 +0100689 free(backfmt);
Thierry FOURNIER / OZON.IOa2c38d72016-11-22 23:11:21 +0100690
691 return 1;
William Lallemand723b73a2012-02-08 16:37:49 +0100692}
693
Christopher Faulet4b0b79d2018-03-26 15:54:32 +0200694/*
695 * Parse "log" keyword and update <logsrvs> list accordingly.
696 *
697 * When <do_del> is set, it means the "no log" line was parsed, so all log
698 * servers in <logsrvs> are released.
699 *
700 * Otherwise, we try to parse the "log" line. First of all, when the list is not
701 * the global one, we look for the parameter "global". If we find it,
702 * global.logsrvs is copied. Else we parse each arguments.
703 *
704 * The function returns 1 in success case, otherwise, it returns 0 and err is
705 * filled.
706 */
707int parse_logsrv(char **args, struct list *logsrvs, int do_del, char **err)
708{
709 struct sockaddr_storage *sk;
710 struct logsrv *logsrv = NULL;
711 int port1, port2;
712 int cur_arg;
713
714 /*
715 * "no log": delete previous herited or defined syslog
716 * servers.
717 */
718 if (do_del) {
719 struct logsrv *back;
720
721 if (*(args[1]) != 0) {
722 memprintf(err, "'no log' does not expect arguments");
723 goto error;
724 }
725
726 list_for_each_entry_safe(logsrv, back, logsrvs, list) {
727 LIST_DEL(&logsrv->list);
728 free(logsrv);
729 }
730 return 1;
731 }
732
733 /*
734 * "log global": copy global.logrsvs linked list to the end of logsrvs
735 * list. But first, we check (logsrvs != global.logsrvs).
736 */
737 if (*(args[1]) && *(args[2]) == 0 && !strcmp(args[1], "global")) {
738 if (logsrvs == &global.logsrvs) {
739 memprintf(err, "'global' is not supported for a global syslog server");
740 goto error;
741 }
742 list_for_each_entry(logsrv, &global.logsrvs, list) {
Christopher Faulet28ac0992018-03-26 16:09:19 +0200743 struct logsrv *node;
744
745 list_for_each_entry(node, logsrvs, list) {
746 if (node->ref == logsrv)
747 goto skip_logsrv;
748 }
749
750 node = malloc(sizeof(*node));
Christopher Faulet4b0b79d2018-03-26 15:54:32 +0200751 memcpy(node, logsrv, sizeof(struct logsrv));
Christopher Faulet28ac0992018-03-26 16:09:19 +0200752 node->ref = logsrv;
Christopher Faulet4b0b79d2018-03-26 15:54:32 +0200753 LIST_INIT(&node->list);
754 LIST_ADDQ(logsrvs, &node->list);
Christopher Faulet28ac0992018-03-26 16:09:19 +0200755
756 skip_logsrv:
757 continue;
Christopher Faulet4b0b79d2018-03-26 15:54:32 +0200758 }
759 return 1;
760 }
761
762 /*
763 * "log <address> ...: parse a syslog server line
764 */
765 if (*(args[1]) == 0 || *(args[2]) == 0) {
766 memprintf(err, "expects <address> and <facility> %s as arguments",
767 ((logsrvs == &global.logsrvs) ? "" : "or global"));
768 goto error;
769 }
770
Willy Tarreau5a32ecc2018-11-12 07:34:59 +0100771 /* take care of "stdout" and "stderr" as regular aliases for fd@1 / fd@2 */
772 if (strcmp(args[1], "stdout") == 0)
773 args[1] = "fd@1";
774 else if (strcmp(args[1], "stderr") == 0)
775 args[1] = "fd@2";
776
Christopher Faulet4b0b79d2018-03-26 15:54:32 +0200777 logsrv = calloc(1, sizeof(*logsrv));
778 if (!logsrv) {
779 memprintf(err, "out of memory");
780 goto error;
781 }
782
783 /* skip address for now, it will be parsed at the end */
784 cur_arg = 2;
785
786 /* just after the address, a length may be specified */
787 logsrv->maxlen = MAX_SYSLOG_LEN;
788 if (strcmp(args[cur_arg], "len") == 0) {
789 int len = atoi(args[cur_arg+1]);
790 if (len < 80 || len > 65535) {
791 memprintf(err, "invalid log length '%s', must be between 80 and 65535",
792 args[cur_arg+1]);
793 goto error;
794 }
795 logsrv->maxlen = len;
796 cur_arg += 2;
797 }
798 if (logsrv->maxlen > global.max_syslog_len)
799 global.max_syslog_len = logsrv->maxlen;
800
801 /* after the length, a format may be specified */
802 if (strcmp(args[cur_arg], "format") == 0) {
803 logsrv->format = get_log_format(args[cur_arg+1]);
804 if (logsrv->format < 0) {
805 memprintf(err, "unknown log format '%s'", args[cur_arg+1]);
806 goto error;
807 }
808 cur_arg += 2;
809 }
810
811 /* parse the facility */
812 logsrv->facility = get_log_facility(args[cur_arg]);
813 if (logsrv->facility < 0) {
814 memprintf(err, "unknown log facility '%s'", args[cur_arg]);
815 goto error;
816 }
817 cur_arg++;
818
819 /* parse the max syslog level (default: debug) */
820 logsrv->level = 7;
821 if (*(args[cur_arg])) {
822 logsrv->level = get_log_level(args[cur_arg]);
823 if (logsrv->level < 0) {
824 memprintf(err, "unknown optional log level '%s'", args[cur_arg]);
825 goto error;
826 }
827 cur_arg++;
828 }
829
830 /* parse the limit syslog level (default: emerg) */
831 logsrv->minlvl = 0;
832 if (*(args[cur_arg])) {
833 logsrv->minlvl = get_log_level(args[cur_arg]);
834 if (logsrv->minlvl < 0) {
835 memprintf(err, "unknown optional minimum log level '%s'", args[cur_arg]);
836 goto error;
837 }
838 cur_arg++;
839 }
840
841 /* Too many args */
842 if (*(args[cur_arg])) {
843 memprintf(err, "cannot handle unexpected argument '%s'", args[cur_arg]);
844 goto error;
845 }
846
847 /* now, back to the address */
848 sk = str2sa_range(args[1], NULL, &port1, &port2, err, NULL, NULL, 1);
849 if (!sk)
850 goto error;
851 logsrv->addr = *sk;
852
853 if (sk->ss_family == AF_INET || sk->ss_family == AF_INET6) {
854 if (port1 != port2) {
855 memprintf(err, "port ranges and offsets are not allowed in '%s'", args[1]);
856 goto error;
857 }
858 logsrv->addr = *sk;
859 if (!port1)
860 set_host_port(&logsrv->addr, SYSLOG_PORT);
861 }
862 LIST_ADDQ(logsrvs, &logsrv->list);
863 return 1;
864
865 error:
866 free(logsrv);
867 return 0;
868}
869
870
Christopher Fauletd4696382017-10-24 11:44:05 +0200871/* Generic function to display messages prefixed by a label */
872static void print_message(const char *label, const char *fmt, va_list argp)
873{
874 struct tm tm;
875 char *head, *msg;
876
877 head = msg = NULL;
878
879 get_localtime(date.tv_sec, &tm);
880 memprintf(&head, "[%s] %03d/%02d%02d%02d (%d) : ",
881 label, tm.tm_yday, tm.tm_hour, tm.tm_min, tm.tm_sec, (int)getpid());
882 memvprintf(&msg, fmt, argp);
883
884 if (global.mode & MODE_STARTING)
885 memprintf(&startup_logs, "%s%s%s", (startup_logs ? startup_logs : ""), head, msg);
886
887 fprintf(stderr, "%s%s", head, msg);
888 fflush(stderr);
889
890 free(head);
891 free(msg);
892}
893
Willy Tarreaubaaee002006-06-26 02:48:02 +0200894/*
895 * Displays the message on stderr with the date and pid. Overrides the quiet
896 * mode during startup.
897 */
Christopher Faulet767a84b2017-11-24 16:50:31 +0100898void ha_alert(const char *fmt, ...)
Willy Tarreaubaaee002006-06-26 02:48:02 +0200899{
900 va_list argp;
Willy Tarreaubaaee002006-06-26 02:48:02 +0200901
902 if (!(global.mode & MODE_QUIET) || (global.mode & (MODE_VERBOSE | MODE_STARTING))) {
903 va_start(argp, fmt);
Christopher Fauletd4696382017-10-24 11:44:05 +0200904 print_message("ALERT", fmt, argp);
Willy Tarreaubaaee002006-06-26 02:48:02 +0200905 va_end(argp);
906 }
907}
908
909
910/*
911 * Displays the message on stderr with the date and pid.
912 */
Christopher Faulet767a84b2017-11-24 16:50:31 +0100913void ha_warning(const char *fmt, ...)
Willy Tarreaubaaee002006-06-26 02:48:02 +0200914{
915 va_list argp;
Willy Tarreaubaaee002006-06-26 02:48:02 +0200916
917 if (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE)) {
918 va_start(argp, fmt);
Christopher Fauletd4696382017-10-24 11:44:05 +0200919 print_message("WARNING", fmt, argp);
Willy Tarreaubaaee002006-06-26 02:48:02 +0200920 va_end(argp);
921 }
922}
923
924/*
William Lallemand9c56a222018-11-21 18:04:52 +0100925 * Displays the message on stderr with the date and pid.
926 */
927void ha_notice(const char *fmt, ...)
928{
929 va_list argp;
930
931 if (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE)) {
932 va_start(argp, fmt);
933 print_message("NOTICE", fmt, argp);
934 va_end(argp);
935 }
936}
937
938/*
Willy Tarreaubaaee002006-06-26 02:48:02 +0200939 * Displays the message on <out> only if quiet mode is not set.
940 */
Willy Tarreaub17916e2006-10-15 15:17:57 +0200941void qfprintf(FILE *out, const char *fmt, ...)
Willy Tarreaubaaee002006-06-26 02:48:02 +0200942{
943 va_list argp;
944
945 if (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE)) {
946 va_start(argp, fmt);
947 vfprintf(out, fmt, argp);
948 fflush(out);
949 va_end(argp);
950 }
951}
952
953/*
Dragan Dosen1322d092015-09-22 16:05:32 +0200954 * returns log format for <fmt> or -1 if not found.
955 */
956int get_log_format(const char *fmt)
957{
958 int format;
959
960 format = LOG_FORMATS - 1;
Dragan Dosen43885c72015-10-01 13:18:13 +0200961 while (format >= 0 && strcmp(log_formats[format].name, fmt))
Dragan Dosen1322d092015-09-22 16:05:32 +0200962 format--;
963
964 return format;
965}
966
967/*
Willy Tarreaubaaee002006-06-26 02:48:02 +0200968 * returns log level for <lev> or -1 if not found.
969 */
970int get_log_level(const char *lev)
971{
972 int level;
973
974 level = NB_LOG_LEVELS - 1;
975 while (level >= 0 && strcmp(log_levels[level], lev))
976 level--;
977
978 return level;
979}
980
Willy Tarreaubaaee002006-06-26 02:48:02 +0200981/*
982 * returns log facility for <fac> or -1 if not found.
983 */
984int get_log_facility(const char *fac)
985{
986 int facility;
987
988 facility = NB_LOG_FACILITIES - 1;
989 while (facility >= 0 && strcmp(log_facilities[facility], fac))
990 facility--;
William Lallemand2a4a44f2012-02-06 16:00:33 +0100991
Willy Tarreaubaaee002006-06-26 02:48:02 +0200992 return facility;
993}
994
William Lallemanda1cc3812012-02-08 16:38:44 +0100995/*
Dragan Dosen835b9212016-02-12 13:23:03 +0100996 * Encode the string.
997 *
998 * When using the +E log format option, it will try to escape '"\]'
999 * characters with '\' as prefix. The same prefix should not be used as
1000 * <escape>.
1001 */
1002static char *lf_encode_string(char *start, char *stop,
1003 const char escape, const fd_set *map,
1004 const char *string,
1005 struct logformat_node *node)
1006{
1007 if (node->options & LOG_OPT_ESC) {
1008 if (start < stop) {
1009 stop--; /* reserve one byte for the final '\0' */
1010 while (start < stop && *string != '\0') {
1011 if (!FD_ISSET((unsigned char)(*string), map)) {
1012 if (!FD_ISSET((unsigned char)(*string), rfc5424_escape_map))
1013 *start++ = *string;
1014 else {
1015 if (start + 2 >= stop)
1016 break;
1017 *start++ = '\\';
1018 *start++ = *string;
1019 }
1020 }
1021 else {
1022 if (start + 3 >= stop)
1023 break;
1024 *start++ = escape;
1025 *start++ = hextab[(*string >> 4) & 15];
1026 *start++ = hextab[*string & 15];
1027 }
1028 string++;
1029 }
1030 *start = '\0';
1031 }
1032 }
1033 else {
1034 return encode_string(start, stop, escape, map, string);
1035 }
1036
1037 return start;
1038}
1039
1040/*
1041 * Encode the chunk.
1042 *
1043 * When using the +E log format option, it will try to escape '"\]'
1044 * characters with '\' as prefix. The same prefix should not be used as
1045 * <escape>.
1046 */
1047static char *lf_encode_chunk(char *start, char *stop,
1048 const char escape, const fd_set *map,
Willy Tarreau83061a82018-07-13 11:56:34 +02001049 const struct buffer *chunk,
Dragan Dosen835b9212016-02-12 13:23:03 +01001050 struct logformat_node *node)
1051{
1052 char *str, *end;
1053
1054 if (node->options & LOG_OPT_ESC) {
1055 if (start < stop) {
Willy Tarreau843b7cb2018-07-13 10:54:26 +02001056 str = chunk->area;
1057 end = chunk->area + chunk->data;
Dragan Dosen835b9212016-02-12 13:23:03 +01001058
1059 stop--; /* reserve one byte for the final '\0' */
1060 while (start < stop && str < end) {
1061 if (!FD_ISSET((unsigned char)(*str), map)) {
1062 if (!FD_ISSET((unsigned char)(*str), rfc5424_escape_map))
1063 *start++ = *str;
1064 else {
1065 if (start + 2 >= stop)
1066 break;
1067 *start++ = '\\';
1068 *start++ = *str;
1069 }
1070 }
1071 else {
1072 if (start + 3 >= stop)
1073 break;
1074 *start++ = escape;
1075 *start++ = hextab[(*str >> 4) & 15];
1076 *start++ = hextab[*str & 15];
1077 }
1078 str++;
1079 }
1080 *start = '\0';
1081 }
1082 }
1083 else {
1084 return encode_chunk(start, stop, escape, map, chunk);
1085 }
1086
1087 return start;
1088}
1089
1090/*
William Lallemanda1cc3812012-02-08 16:38:44 +01001091 * Write a string in the log string
Dragan Dosen835b9212016-02-12 13:23:03 +01001092 * Take cares of quote and escape options
William Lallemanda1cc3812012-02-08 16:38:44 +01001093 *
Joseph Herlant85b40592018-11-15 12:10:04 -08001094 * Return the address of the \0 character, or NULL on error
William Lallemanda1cc3812012-02-08 16:38:44 +01001095 */
Willy Tarreau26ffa852018-09-05 15:23:10 +02001096char *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 +01001097{
Willy Tarreau2b0108a2012-12-21 19:23:44 +01001098 if (size < 2)
1099 return NULL;
William Lallemanda1cc3812012-02-08 16:38:44 +01001100
Willy Tarreau2b0108a2012-12-21 19:23:44 +01001101 if (node->options & LOG_OPT_QUOTE) {
1102 *(dst++) = '"';
1103 size--;
William Lallemandbddd4fd2012-02-27 11:23:10 +01001104 }
Willy Tarreau2b0108a2012-12-21 19:23:44 +01001105
Willy Tarreau6cbbdbf2013-02-05 18:52:25 +01001106 if (src && len) {
Dragan Dosendb1b6f92016-07-25 11:35:02 +02001107 if (++len > size)
1108 len = size;
Dragan Dosen835b9212016-02-12 13:23:03 +01001109 if (node->options & LOG_OPT_ESC) {
Dragan Dosen835b9212016-02-12 13:23:03 +01001110 char *ret;
1111
Dragan Dosendb1b6f92016-07-25 11:35:02 +02001112 ret = escape_string(dst, dst + len, '\\', rfc5424_escape_map, src);
Dragan Dosen835b9212016-02-12 13:23:03 +01001113 if (ret == NULL || *ret != '\0')
1114 return NULL;
1115 len = ret - dst;
1116 }
1117 else {
Dragan Dosen835b9212016-02-12 13:23:03 +01001118 len = strlcpy2(dst, src, len);
1119 }
Willy Tarreau2b0108a2012-12-21 19:23:44 +01001120
1121 size -= len;
1122 dst += len;
1123 }
Willy Tarreau6cbbdbf2013-02-05 18:52:25 +01001124 else if ((node->options & (LOG_OPT_QUOTE|LOG_OPT_MANDATORY)) == LOG_OPT_MANDATORY) {
1125 if (size < 2)
1126 return NULL;
1127 *(dst++) = '-';
1128 }
Willy Tarreau2b0108a2012-12-21 19:23:44 +01001129
1130 if (node->options & LOG_OPT_QUOTE) {
1131 if (size < 2)
1132 return NULL;
1133 *(dst++) = '"';
1134 }
1135
1136 *dst = '\0';
William Lallemandbddd4fd2012-02-27 11:23:10 +01001137 return dst;
William Lallemanda1cc3812012-02-08 16:38:44 +01001138}
1139
Willy Tarreau26ffa852018-09-05 15:23:10 +02001140static inline char *lf_text(char *dst, const char *src, size_t size, const struct logformat_node *node)
Willy Tarreau2b0108a2012-12-21 19:23:44 +01001141{
1142 return lf_text_len(dst, src, size, size, node);
1143}
1144
William Lallemand5f232402012-04-05 18:02:55 +02001145/*
Joseph Herlant85b40592018-11-15 12:10:04 -08001146 * Write a IP address to the log string
William Lallemand5f232402012-04-05 18:02:55 +02001147 * +X option write in hexadecimal notation, most signifant byte on the left
1148 */
Willy Tarreau26ffa852018-09-05 15:23:10 +02001149char *lf_ip(char *dst, const struct sockaddr *sockaddr, size_t size, const struct logformat_node *node)
William Lallemand5f232402012-04-05 18:02:55 +02001150{
1151 char *ret = dst;
1152 int iret;
1153 char pn[INET6_ADDRSTRLEN];
1154
1155 if (node->options & LOG_OPT_HEXA) {
1156 const unsigned char *addr = (const unsigned char *)&((struct sockaddr_in *)sockaddr)->sin_addr.s_addr;
1157 iret = snprintf(dst, size, "%02X%02X%02X%02X", addr[0], addr[1], addr[2], addr[3]);
1158 if (iret < 0 || iret > size)
1159 return NULL;
1160 ret += iret;
1161 } else {
1162 addr_to_str((struct sockaddr_storage *)sockaddr, pn, sizeof(pn));
1163 ret = lf_text(dst, pn, size, node);
1164 if (ret == NULL)
1165 return NULL;
1166 }
1167 return ret;
1168}
1169
1170/*
1171 * Write a port to the log
1172 * +X option write in hexadecimal notation, most signifant byte on the left
1173 */
Willy Tarreau26ffa852018-09-05 15:23:10 +02001174char *lf_port(char *dst, const struct sockaddr *sockaddr, size_t size, const struct logformat_node *node)
William Lallemand5f232402012-04-05 18:02:55 +02001175{
1176 char *ret = dst;
1177 int iret;
1178
1179 if (node->options & LOG_OPT_HEXA) {
1180 const unsigned char *port = (const unsigned char *)&((struct sockaddr_in *)sockaddr)->sin_port;
1181 iret = snprintf(dst, size, "%02X%02X", port[0], port[1]);
1182 if (iret < 0 || iret > size)
1183 return NULL;
1184 ret += iret;
1185 } else {
1186 ret = ltoa_o(get_host_port((struct sockaddr_storage *)sockaddr), dst, size);
1187 if (ret == NULL)
1188 return NULL;
1189 }
1190 return ret;
1191}
1192
Dragan Dosen1322d092015-09-22 16:05:32 +02001193/* Re-generate time-based part of the syslog header in RFC3164 format at
1194 * the beginning of logheader once a second and return the pointer to the
1195 * first character after it.
Willy Tarreaub1a2faf2012-03-19 16:51:53 +01001196 */
Dragan Dosen0b85ece2015-09-25 19:17:44 +02001197static char *update_log_hdr(const time_t time)
Willy Tarreaubaaee002006-06-26 02:48:02 +02001198{
Christopher Fauletf8188c62017-06-02 16:20:16 +02001199 static THREAD_LOCAL long tvsec;
1200 static THREAD_LOCAL char *dataptr = NULL; /* backup of last end of header, NULL first time */
Willy Tarreau83061a82018-07-13 11:56:34 +02001201 static THREAD_LOCAL struct buffer host = { };
Christopher Fauletf8188c62017-06-02 16:20:16 +02001202 static THREAD_LOCAL int sep = 0;
Willy Tarreaubaaee002006-06-26 02:48:02 +02001203
Dragan Dosen0b85ece2015-09-25 19:17:44 +02001204 if (unlikely(time != tvsec || dataptr == NULL)) {
Willy Tarreaubaaee002006-06-26 02:48:02 +02001205 /* this string is rebuild only once a second */
Willy Tarreaufe944602007-10-25 10:34:16 +02001206 struct tm tm;
Willy Tarreaub1a2faf2012-03-19 16:51:53 +01001207 int hdr_len;
Willy Tarreaufe944602007-10-25 10:34:16 +02001208
Dragan Dosen0b85ece2015-09-25 19:17:44 +02001209 tvsec = time;
Willy Tarreaufe944602007-10-25 10:34:16 +02001210 get_localtime(tvsec, &tm);
Willy Tarreaubaaee002006-06-26 02:48:02 +02001211
Willy Tarreau843b7cb2018-07-13 10:54:26 +02001212 if (unlikely(global.log_send_hostname != host.area)) {
1213 host.area = global.log_send_hostname;
1214 host.data = host.area ? strlen(host.area) : 0;
1215 sep = host.data ? 1 : 0;
Dragan Dosen43885c72015-10-01 13:18:13 +02001216 }
1217
Dragan Dosen59cee972015-09-19 22:09:02 +02001218 hdr_len = snprintf(logheader, global.max_syslog_len,
Dragan Dosen43885c72015-10-01 13:18:13 +02001219 "<<<<>%s %2d %02d:%02d:%02d %.*s%*s",
Willy Tarreaufe944602007-10-25 10:34:16 +02001220 monthname[tm.tm_mon],
Dragan Dosen43885c72015-10-01 13:18:13 +02001221 tm.tm_mday, tm.tm_hour, tm.tm_min, tm.tm_sec,
Willy Tarreau843b7cb2018-07-13 10:54:26 +02001222 (int)host.data, host.area, sep, "");
Willy Tarreaubaaee002006-06-26 02:48:02 +02001223 /* WARNING: depending upon implementations, snprintf may return
1224 * either -1 or the number of bytes that would be needed to store
1225 * the total message. In both cases, we must adjust it.
1226 */
Willy Tarreau18324f52014-06-27 18:10:07 +02001227 if (hdr_len < 0 || hdr_len > global.max_syslog_len)
1228 hdr_len = global.max_syslog_len;
Willy Tarreaubaaee002006-06-26 02:48:02 +02001229
Dragan Dosen59cee972015-09-19 22:09:02 +02001230 dataptr = logheader + hdr_len;
Willy Tarreaubaaee002006-06-26 02:48:02 +02001231 }
1232
Willy Tarreau094af4e2015-01-07 15:03:42 +01001233 dataptr[0] = 0; // ensure we get rid of any previous attempt
1234
Dragan Dosen68d2e3a2015-09-19 22:35:44 +02001235 return dataptr;
William Lallemand2a4a44f2012-02-06 16:00:33 +01001236}
1237
Dragan Dosen1322d092015-09-22 16:05:32 +02001238/* Re-generate time-based part of the syslog header in RFC5424 format at
1239 * the beginning of logheader_rfc5424 once a second and return the pointer
1240 * to the first character after it.
1241 */
Dragan Dosen0b85ece2015-09-25 19:17:44 +02001242static char *update_log_hdr_rfc5424(const time_t time)
Dragan Dosen1322d092015-09-22 16:05:32 +02001243{
Christopher Fauletf8188c62017-06-02 16:20:16 +02001244 static THREAD_LOCAL long tvsec;
1245 static THREAD_LOCAL char *dataptr = NULL; /* backup of last end of header, NULL first time */
Benoit GARNIERb413c2a2016-03-27 11:08:03 +02001246 const char *gmt_offset;
Dragan Dosen1322d092015-09-22 16:05:32 +02001247
Dragan Dosen0b85ece2015-09-25 19:17:44 +02001248 if (unlikely(time != tvsec || dataptr == NULL)) {
Dragan Dosen1322d092015-09-22 16:05:32 +02001249 /* this string is rebuild only once a second */
1250 struct tm tm;
1251 int hdr_len;
1252
Dragan Dosen0b85ece2015-09-25 19:17:44 +02001253 tvsec = time;
Dragan Dosen1322d092015-09-22 16:05:32 +02001254 get_localtime(tvsec, &tm);
Benoit GARNIERe2e5bde2016-03-27 03:04:16 +02001255 gmt_offset = get_gmt_offset(time, &tm);
Dragan Dosen1322d092015-09-22 16:05:32 +02001256
1257 hdr_len = snprintf(logheader_rfc5424, global.max_syslog_len,
Dragan Dosen17def462015-10-09 21:31:43 +02001258 "<<<<>1 %4d-%02d-%02dT%02d:%02d:%02d%.3s:%.2s %s ",
Dragan Dosen1322d092015-09-22 16:05:32 +02001259 tm.tm_year+1900, tm.tm_mon+1, tm.tm_mday,
Dragan Dosen17def462015-10-09 21:31:43 +02001260 tm.tm_hour, tm.tm_min, tm.tm_sec,
Benoit GARNIERb413c2a2016-03-27 11:08:03 +02001261 gmt_offset, gmt_offset+3,
Dragan Dosen43885c72015-10-01 13:18:13 +02001262 global.log_send_hostname ? global.log_send_hostname : hostname);
Dragan Dosen1322d092015-09-22 16:05:32 +02001263 /* WARNING: depending upon implementations, snprintf may return
1264 * either -1 or the number of bytes that would be needed to store
1265 * the total message. In both cases, we must adjust it.
1266 */
1267 if (hdr_len < 0 || hdr_len > global.max_syslog_len)
1268 hdr_len = global.max_syslog_len;
1269
1270 dataptr = logheader_rfc5424 + hdr_len;
1271 }
1272
1273 dataptr[0] = 0; // ensure we get rid of any previous attempt
1274
1275 return dataptr;
1276}
1277
William Lallemand2a4a44f2012-02-06 16:00:33 +01001278/*
Dragan Dosen59cee972015-09-19 22:09:02 +02001279 * This function sends the syslog message using a printf format string. It
1280 * expects an LF-terminated message.
William Lallemand2a4a44f2012-02-06 16:00:33 +01001281 */
1282void send_log(struct proxy *p, int level, const char *format, ...)
1283{
1284 va_list argp;
Willy Tarreaub1a2faf2012-03-19 16:51:53 +01001285 int data_len;
William Lallemand2a4a44f2012-02-06 16:00:33 +01001286
Willy Tarreau8c97ab52015-01-15 16:29:53 +01001287 if (level < 0 || format == NULL || logline == NULL)
William Lallemand2a4a44f2012-02-06 16:00:33 +01001288 return;
1289
William Lallemand2a4a44f2012-02-06 16:00:33 +01001290 va_start(argp, format);
Dragan Dosen59cee972015-09-19 22:09:02 +02001291 data_len = vsnprintf(logline, global.max_syslog_len, format, argp);
Willy Tarreau18324f52014-06-27 18:10:07 +02001292 if (data_len < 0 || data_len > global.max_syslog_len)
1293 data_len = global.max_syslog_len;
Willy Tarreaubaaee002006-06-26 02:48:02 +02001294 va_end(argp);
William Lallemand2a4a44f2012-02-06 16:00:33 +01001295
Dragan Dosen0b85ece2015-09-25 19:17:44 +02001296 __send_log(p, level, logline, data_len, default_rfc5424_sd_log_format, 2);
William Lallemand2a4a44f2012-02-06 16:00:33 +01001297}
1298
1299/*
1300 * This function sends a syslog message.
1301 * It doesn't care about errors nor does it report them.
Dragan Dosen0b85ece2015-09-25 19:17:44 +02001302 * It overrides the last byte of the message vector with an LF character.
1303 * The arguments <sd> and <sd_size> are used for the structured-data part
1304 * in RFC5424 formatted syslog messages.
William Lallemand2a4a44f2012-02-06 16:00:33 +01001305 */
Dragan Dosen0b85ece2015-09-25 19:17:44 +02001306void __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 +01001307{
Christopher Fauletf8188c62017-06-02 16:20:16 +02001308 static THREAD_LOCAL struct iovec iovec[NB_MSG_IOVEC_ELEMENTS] = { };
1309 static THREAD_LOCAL struct msghdr msghdr = {
1310 //.msg_iov = iovec,
Dragan Dosen609ac2a2015-09-16 18:25:42 +02001311 .msg_iovlen = NB_MSG_IOVEC_ELEMENTS
1312 };
Christopher Fauletf8188c62017-06-02 16:20:16 +02001313 static THREAD_LOCAL int logfdunix = -1; /* syslog to AF_UNIX socket */
1314 static THREAD_LOCAL int logfdinet = -1; /* syslog to AF_INET socket */
1315 static THREAD_LOCAL char *dataptr = NULL;
William Lallemand2a4a44f2012-02-06 16:00:33 +01001316 int fac_level;
1317 struct list *logsrvs = NULL;
1318 struct logsrv *tmp = NULL;
1319 int nblogger;
Dragan Dosen1322d092015-09-22 16:05:32 +02001320 char *hdr, *hdr_ptr;
Dragan Dosen59cee972015-09-19 22:09:02 +02001321 size_t hdr_size;
Dragan Dosen0b85ece2015-09-25 19:17:44 +02001322 time_t time = date.tv_sec;
Willy Tarreau83061a82018-07-13 11:56:34 +02001323 struct buffer *tag = &global.log_tag;
Christopher Fauletf8188c62017-06-02 16:20:16 +02001324 static THREAD_LOCAL int curr_pid;
1325 static THREAD_LOCAL char pidstr[100];
Willy Tarreau83061a82018-07-13 11:56:34 +02001326 static THREAD_LOCAL struct buffer pid;
Christopher Fauletf8188c62017-06-02 16:20:16 +02001327
1328 msghdr.msg_iov = iovec;
William Lallemand2a4a44f2012-02-06 16:00:33 +01001329
1330 dataptr = message;
Willy Tarreaubaaee002006-06-26 02:48:02 +02001331
1332 if (p == NULL) {
William Lallemand0f99e342011-10-12 17:50:54 +02001333 if (!LIST_ISEMPTY(&global.logsrvs)) {
1334 logsrvs = &global.logsrvs;
Willy Tarreaubaaee002006-06-26 02:48:02 +02001335 }
1336 } else {
William Lallemand0f99e342011-10-12 17:50:54 +02001337 if (!LIST_ISEMPTY(&p->logsrvs)) {
1338 logsrvs = &p->logsrvs;
Willy Tarreaubaaee002006-06-26 02:48:02 +02001339 }
Willy Tarreau843b7cb2018-07-13 10:54:26 +02001340 if (p->log_tag.area) {
Dragan Dosen43885c72015-10-01 13:18:13 +02001341 tag = &p->log_tag;
1342 }
Robert Tsai81ae1952007-12-05 10:47:29 +01001343 }
1344
William Lallemand0f99e342011-10-12 17:50:54 +02001345 if (!logsrvs)
1346 return;
1347
Dragan Dosen43885c72015-10-01 13:18:13 +02001348 if (unlikely(curr_pid != getpid())) {
1349 curr_pid = getpid();
1350 ltoa_o(curr_pid, pidstr, sizeof(pidstr));
1351 chunk_initstr(&pid, pidstr);
1352 }
1353
Robert Tsai81ae1952007-12-05 10:47:29 +01001354 /* Send log messages to syslog server. */
William Lallemand0f99e342011-10-12 17:50:54 +02001355 nblogger = 0;
1356 list_for_each_entry(tmp, logsrvs, list) {
1357 const struct logsrv *logsrv = tmp;
David du Colombier11bcb6c2011-03-24 12:23:00 +01001358 int *plogfd = logsrv->addr.ss_family == AF_UNIX ?
Robert Tsai81ae1952007-12-05 10:47:29 +01001359 &logfdunix : &logfdinet;
Willy Tarreaue8746a02018-11-12 08:45:00 +01001360 char *pid_sep1 = "", *pid_sep2 = "";
1361 char logheader_short[3];
Robert Tsai81ae1952007-12-05 10:47:29 +01001362 int sent;
Dragan Dosen68d2e3a2015-09-19 22:35:44 +02001363 int maxlen;
Dragan Dosen59cee972015-09-19 22:09:02 +02001364 int hdr_max = 0;
Dragan Dosen43885c72015-10-01 13:18:13 +02001365 int tag_max = 0;
1366 int pid_sep1_max = 0;
1367 int pid_max = 0;
1368 int pid_sep2_max = 0;
Dragan Dosen0b85ece2015-09-25 19:17:44 +02001369 int sd_max = 0;
Dragan Dosen5b78d9b2015-09-28 16:01:03 +02001370 int max = 0;
Robert Tsai81ae1952007-12-05 10:47:29 +01001371
Willy Tarreauc7c7be22014-06-23 18:07:15 +02001372 nblogger++;
1373
Willy Tarreaubaaee002006-06-26 02:48:02 +02001374 /* we can filter the level of the messages that are sent to each logger */
William Lallemand0f99e342011-10-12 17:50:54 +02001375 if (level > logsrv->level)
Willy Tarreaubaaee002006-06-26 02:48:02 +02001376 continue;
William Lallemandbddd4fd2012-02-27 11:23:10 +01001377
Willy Tarreauc7c7be22014-06-23 18:07:15 +02001378 if (unlikely(*plogfd < 0)) {
1379 /* socket not successfully initialized yet */
Willy Tarreau5a32ecc2018-11-12 07:34:59 +01001380 if (logsrv->addr.ss_family == AF_UNSPEC) {
1381 /* the socket's address is a file descriptor */
1382 *plogfd = ((struct sockaddr_in *)&logsrv->addr)->sin_addr.s_addr;
1383 fcntl(*plogfd, F_SETFL, O_NONBLOCK);
1384 }
1385 else if ((*plogfd = socket(logsrv->addr.ss_family, SOCK_DGRAM,
1386 (logsrv->addr.ss_family == AF_UNIX) ? 0 : IPPROTO_UDP)) < 0) {
Willy Tarreauc98aebc2018-03-20 11:17:29 +01001387 static char once;
1388
1389 if (!once) {
1390 once = 1; /* note: no need for atomic ops here */
Willy Tarreau251fe342018-11-12 07:00:11 +01001391 ha_alert("socket() failed in logger #%d: %s (errno=%d)\n",
Willy Tarreauc98aebc2018-03-20 11:17:29 +01001392 nblogger, strerror(errno), errno);
1393 }
Willy Tarreauc7c7be22014-06-23 18:07:15 +02001394 continue;
William Lallemanda8b26712018-11-13 18:30:12 +01001395 } else {
1396 /* we don't want to receive anything on this socket */
1397 setsockopt(*plogfd, SOL_SOCKET, SO_RCVBUF, &zero, sizeof(zero));
1398 /* does nothing under Linux, maybe needed for others */
1399 shutdown(*plogfd, SHUT_RD);
1400 fcntl(*plogfd, F_SETFD, fcntl(*plogfd, F_GETFD, FD_CLOEXEC) | FD_CLOEXEC);
Willy Tarreauc7c7be22014-06-23 18:07:15 +02001401 }
Willy Tarreauc7c7be22014-06-23 18:07:15 +02001402 }
1403
Dragan Dosen1322d092015-09-22 16:05:32 +02001404 switch (logsrv->format) {
1405 case LOG_FORMAT_RFC3164:
1406 hdr = logheader;
Dragan Dosen0b85ece2015-09-25 19:17:44 +02001407 hdr_ptr = update_log_hdr(time);
Dragan Dosen1322d092015-09-22 16:05:32 +02001408 break;
1409
1410 case LOG_FORMAT_RFC5424:
1411 hdr = logheader_rfc5424;
Dragan Dosen0b85ece2015-09-25 19:17:44 +02001412 hdr_ptr = update_log_hdr_rfc5424(time);
Dragan Dosen0b85ece2015-09-25 19:17:44 +02001413 sd_max = sd_size; /* the SD part allowed only in RFC5424 */
Dragan Dosen1322d092015-09-22 16:05:32 +02001414 break;
1415
Willy Tarreaue8746a02018-11-12 08:45:00 +01001416 case LOG_FORMAT_SHORT:
1417 /* all fields are known, skip the header generation */
1418 hdr = logheader_short;
1419 hdr[0] = '<';
1420 hdr[1] = '0' + MAX(level, logsrv->minlvl);
1421 hdr[2] = '>';
1422 hdr_ptr = hdr;
1423 hdr_max = 3;
1424 maxlen = logsrv->maxlen - hdr_max;
1425 max = MIN(size, maxlen) - 1;
1426 goto send;
1427
Willy Tarreauc1b06452018-11-12 11:57:56 +01001428 case LOG_FORMAT_RAW:
1429 /* all fields are known, skip the header generation */
1430 hdr_ptr = hdr = "";
1431 hdr_max = 0;
1432 maxlen = logsrv->maxlen;
1433 max = MIN(size, maxlen) - 1;
1434 goto send;
1435
Dragan Dosen1322d092015-09-22 16:05:32 +02001436 default:
1437 continue; /* must never happen */
1438 }
1439
1440 hdr_size = hdr_ptr - hdr;
1441
Willy Tarreaubaaee002006-06-26 02:48:02 +02001442 /* For each target, we may have a different facility.
1443 * We can also have a different log level for each message.
1444 * This induces variations in the message header length.
1445 * Since we don't want to recompute it each time, nor copy it every
1446 * time, we only change the facility in the pre-computed header,
1447 * and we change the pointer to the header accordingly.
1448 */
William Lallemand0f99e342011-10-12 17:50:54 +02001449 fac_level = (logsrv->facility << 3) + MAX(level, logsrv->minlvl);
Dragan Dosen1322d092015-09-22 16:05:32 +02001450 hdr_ptr = hdr + 3; /* last digit of the log level */
Willy Tarreaubaaee002006-06-26 02:48:02 +02001451 do {
Dragan Dosen59cee972015-09-19 22:09:02 +02001452 *hdr_ptr = '0' + fac_level % 10;
Willy Tarreaubaaee002006-06-26 02:48:02 +02001453 fac_level /= 10;
Dragan Dosen59cee972015-09-19 22:09:02 +02001454 hdr_ptr--;
Dragan Dosen1322d092015-09-22 16:05:32 +02001455 } while (fac_level && hdr_ptr > hdr);
Dragan Dosen59cee972015-09-19 22:09:02 +02001456 *hdr_ptr = '<';
William Lallemand2a4a44f2012-02-06 16:00:33 +01001457
Dragan Dosen1322d092015-09-22 16:05:32 +02001458 hdr_max = hdr_size - (hdr_ptr - hdr);
Dragan Dosen59cee972015-09-19 22:09:02 +02001459
Dragan Dosen43885c72015-10-01 13:18:13 +02001460 /* time-based header */
Dragan Dosen59cee972015-09-19 22:09:02 +02001461 if (unlikely(hdr_size >= logsrv->maxlen)) {
1462 hdr_max = MIN(hdr_max, logsrv->maxlen) - 1;
Dragan Dosen0b85ece2015-09-25 19:17:44 +02001463 sd_max = 0;
Dragan Dosen59cee972015-09-19 22:09:02 +02001464 goto send;
1465 }
1466
Dragan Dosen68d2e3a2015-09-19 22:35:44 +02001467 maxlen = logsrv->maxlen - hdr_max;
Dragan Dosen68d2e3a2015-09-19 22:35:44 +02001468
Dragan Dosen43885c72015-10-01 13:18:13 +02001469 /* tag */
Willy Tarreau843b7cb2018-07-13 10:54:26 +02001470 tag_max = tag->data;
Dragan Dosen43885c72015-10-01 13:18:13 +02001471 if (unlikely(tag_max >= maxlen)) {
1472 tag_max = maxlen - 1;
1473 sd_max = 0;
1474 goto send;
1475 }
1476
1477 maxlen -= tag_max;
1478
1479 /* first pid separator */
Willy Tarreau843b7cb2018-07-13 10:54:26 +02001480 pid_sep1_max = log_formats[logsrv->format].pid.sep1.data;
Dragan Dosen43885c72015-10-01 13:18:13 +02001481 if (unlikely(pid_sep1_max >= maxlen)) {
1482 pid_sep1_max = maxlen - 1;
Dragan Dosen0b85ece2015-09-25 19:17:44 +02001483 sd_max = 0;
Dragan Dosen68d2e3a2015-09-19 22:35:44 +02001484 goto send;
1485 }
1486
Willy Tarreau843b7cb2018-07-13 10:54:26 +02001487 pid_sep1 = log_formats[logsrv->format].pid.sep1.area;
Dragan Dosen43885c72015-10-01 13:18:13 +02001488 maxlen -= pid_sep1_max;
Dragan Dosen59cee972015-09-19 22:09:02 +02001489
Dragan Dosen43885c72015-10-01 13:18:13 +02001490 /* pid */
Willy Tarreau843b7cb2018-07-13 10:54:26 +02001491 pid_max = pid.data;
Dragan Dosen43885c72015-10-01 13:18:13 +02001492 if (unlikely(pid_max >= maxlen)) {
1493 pid_max = maxlen - 1;
1494 sd_max = 0;
1495 goto send;
1496 }
1497
1498 maxlen -= pid_max;
1499
1500 /* second pid separator */
Willy Tarreau843b7cb2018-07-13 10:54:26 +02001501 pid_sep2_max = log_formats[logsrv->format].pid.sep2.data;
Dragan Dosen43885c72015-10-01 13:18:13 +02001502 if (unlikely(pid_sep2_max >= maxlen)) {
1503 pid_sep2_max = maxlen - 1;
1504 sd_max = 0;
1505 goto send;
1506 }
1507
Willy Tarreau843b7cb2018-07-13 10:54:26 +02001508 pid_sep2 = log_formats[logsrv->format].pid.sep2.area;
Dragan Dosen43885c72015-10-01 13:18:13 +02001509 maxlen -= pid_sep2_max;
1510
1511 /* structured-data */
Dragan Dosen0b85ece2015-09-25 19:17:44 +02001512 if (sd_max >= maxlen) {
1513 sd_max = maxlen - 1;
1514 goto send;
1515 }
Dragan Dosen59cee972015-09-19 22:09:02 +02001516
Dragan Dosen5b78d9b2015-09-28 16:01:03 +02001517 max = MIN(size, maxlen - sd_max) - 1;
Dragan Dosen59cee972015-09-19 22:09:02 +02001518send:
Dragan Dosen59cee972015-09-19 22:09:02 +02001519 iovec[0].iov_base = hdr_ptr;
Dragan Dosen43885c72015-10-01 13:18:13 +02001520 iovec[0].iov_len = hdr_max;
Willy Tarreau843b7cb2018-07-13 10:54:26 +02001521 iovec[1].iov_base = tag->area;
Dragan Dosen43885c72015-10-01 13:18:13 +02001522 iovec[1].iov_len = tag_max;
1523 iovec[2].iov_base = pid_sep1;
1524 iovec[2].iov_len = pid_sep1_max;
Willy Tarreau843b7cb2018-07-13 10:54:26 +02001525 iovec[3].iov_base = pid.area;
Dragan Dosen43885c72015-10-01 13:18:13 +02001526 iovec[3].iov_len = pid_max;
1527 iovec[4].iov_base = pid_sep2;
1528 iovec[4].iov_len = pid_sep2_max;
1529 iovec[5].iov_base = sd;
1530 iovec[5].iov_len = sd_max;
1531 iovec[6].iov_base = dataptr;
1532 iovec[6].iov_len = max;
1533 iovec[7].iov_base = "\n"; /* insert a \n at the end of the message */
1534 iovec[7].iov_len = 1;
Dragan Dosen609ac2a2015-09-16 18:25:42 +02001535
Willy Tarreau5a32ecc2018-11-12 07:34:59 +01001536 if (logsrv->addr.ss_family == AF_UNSPEC) {
1537 /* the target is a direct file descriptor */
1538 sent = writev(*plogfd, iovec, 8);
1539 }
1540 else {
1541 msghdr.msg_name = (struct sockaddr *)&logsrv->addr;
1542 msghdr.msg_namelen = get_addr_len(&logsrv->addr);
Dragan Dosen609ac2a2015-09-16 18:25:42 +02001543
Willy Tarreau5a32ecc2018-11-12 07:34:59 +01001544 sent = sendmsg(*plogfd, &msghdr, MSG_DONTWAIT | MSG_NOSIGNAL);
1545 }
Willy Tarreau18324f52014-06-27 18:10:07 +02001546
Robert Tsai81ae1952007-12-05 10:47:29 +01001547 if (sent < 0) {
Willy Tarreauc98aebc2018-03-20 11:17:29 +01001548 static char once;
1549
Willy Tarreau13ef7732018-11-12 07:25:28 +01001550 if (errno == EAGAIN)
1551 HA_ATOMIC_ADD(&dropped_logs, 1);
1552 else if (!once) {
Willy Tarreauc98aebc2018-03-20 11:17:29 +01001553 once = 1; /* note: no need for atomic ops here */
Willy Tarreau5a32ecc2018-11-12 07:34:59 +01001554 ha_alert("sendmsg()/writev() failed in logger #%d: %s (errno=%d)\n",
Willy Tarreauc98aebc2018-03-20 11:17:29 +01001555 nblogger, strerror(errno), errno);
1556 }
Robert Tsai81ae1952007-12-05 10:47:29 +01001557 }
Willy Tarreaubaaee002006-06-26 02:48:02 +02001558 }
1559}
1560
William Lallemandbddd4fd2012-02-27 11:23:10 +01001561extern fd_set hdr_encode_map[];
1562extern fd_set url_encode_map[];
Thierry FOURNIERd048d8b2014-03-13 16:46:18 +01001563extern fd_set http_encode_map[];
William Lallemandbddd4fd2012-02-27 11:23:10 +01001564
Willy Tarreaubaaee002006-06-26 02:48:02 +02001565
Willy Tarreauc89ccb62012-04-05 21:18:22 +02001566const 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 +01001567const char sess_set_cookie[8] = "NPDIRU67"; /* No set-cookie, Set-cookie found and left unchanged (passive),
1568 Set-cookie Deleted, Set-Cookie Inserted, Set-cookie Rewritten,
1569 Set-cookie Updated, unknown, unknown */
1570
William Lallemand1d705562012-03-12 12:46:41 +01001571/*
1572 * try to write a character if there is enough space, or goto out
1573 */
William Lallemandbddd4fd2012-02-27 11:23:10 +01001574#define LOGCHAR(x) do { \
William Lallemand1d705562012-03-12 12:46:41 +01001575 if (tmplog < dst + maxsize - 1) { \
William Lallemandbddd4fd2012-02-27 11:23:10 +01001576 *(tmplog++) = (x); \
1577 } else { \
1578 goto out; \
1579 } \
1580 } while(0)
1581
Dragan Dosen835b9212016-02-12 13:23:03 +01001582
1583/* Initializes some log data.
1584 */
1585void init_log()
1586{
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
Christopher Fauletcd7879a2017-10-27 13:53:47 +02001658static int init_log_buffers_per_thread()
1659{
1660 return init_log_buffers();
1661}
1662
1663static void deinit_log_buffers_per_thread()
1664{
1665 deinit_log_buffers();
1666}
1667
Christopher Faulet0132d062017-07-26 15:33:35 +02001668/* Initialize log buffers used for syslog messages */
1669int init_log_buffers()
1670{
1671 logheader = my_realloc2(logheader, global.max_syslog_len + 1);
1672 logheader_rfc5424 = my_realloc2(logheader_rfc5424, global.max_syslog_len + 1);
1673 logline = my_realloc2(logline, global.max_syslog_len + 1);
1674 logline_rfc5424 = my_realloc2(logline_rfc5424, global.max_syslog_len + 1);
1675 if (!logheader || !logline_rfc5424 || !logline || !logline_rfc5424)
1676 return 0;
1677 return 1;
1678}
1679
1680/* Deinitialize log buffers used for syslog messages */
1681void deinit_log_buffers()
1682{
1683 free(logheader);
1684 free(logheader_rfc5424);
1685 free(logline);
1686 free(logline_rfc5424);
Christopher Fauletd4696382017-10-24 11:44:05 +02001687 free(startup_logs);
Christopher Faulet0132d062017-07-26 15:33:35 +02001688 logheader = NULL;
1689 logheader_rfc5424 = NULL;
1690 logline = NULL;
1691 logline_rfc5424 = NULL;
Christopher Fauletd4696382017-10-24 11:44:05 +02001692 startup_logs = NULL;
Christopher Faulet0132d062017-07-26 15:33:35 +02001693}
1694
Willy Tarreaudf974472012-12-28 02:44:01 +01001695/* Builds a log line in <dst> based on <list_format>, and stops before reaching
1696 * <maxsize> characters. Returns the size of the output string in characters,
1697 * not counting the trailing zero which is always added if the resulting size
Willy Tarreau09bb27c2018-09-05 16:55:15 +02001698 * is not zero. It requires a valid session and optionally a stream. If the
1699 * stream is NULL, default values will be assumed for the stream part.
Willy Tarreaudf974472012-12-28 02:44:01 +01001700 */
Willy Tarreau43c538e2018-09-05 14:58:15 +02001701int 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 +02001702{
Willy Tarreaue36cbcb2015-04-03 15:40:56 +02001703 struct proxy *fe = sess->fe;
Willy Tarreau09bb27c2018-09-05 16:55:15 +02001704 struct proxy *be;
1705 struct http_txn *txn;
1706 const struct strm_logs *logs;
1707 const struct connection *be_conn;
1708 unsigned int s_flags;
1709 unsigned int uniq_id;
Willy Tarreau83061a82018-07-13 11:56:34 +02001710 struct buffer chunk;
William Lallemandbddd4fd2012-02-27 11:23:10 +01001711 char *uri;
Andrew Hayworth0ebc55f2015-04-27 21:37:03 +00001712 char *spc;
Andrew Hayworthe63ac872015-07-31 16:14:16 +00001713 char *qmark;
Andrew Hayworth0ebc55f2015-04-27 21:37:03 +00001714 char *end;
Willy Tarreaufe944602007-10-25 10:34:16 +02001715 struct tm tm;
William Lallemandbddd4fd2012-02-27 11:23:10 +01001716 int t_request;
1717 int hdr;
1718 int last_isspace = 1;
Andrew Hayworth0ebc55f2015-04-27 21:37:03 +00001719 int nspaces = 0;
Willy Tarreaub1a2faf2012-03-19 16:51:53 +01001720 char *tmplog;
William Lallemand1d705562012-03-12 12:46:41 +01001721 char *ret;
1722 int iret;
William Lallemandbddd4fd2012-02-27 11:23:10 +01001723 struct logformat_node *tmp;
Thierry FOURNIER / OZON.IO4cac3592016-07-28 17:19:45 +02001724 struct timeval tv;
Willy Tarreau09bb27c2018-09-05 16:55:15 +02001725 struct strm_logs tmp_strm_log;
Willy Tarreaubaaee002006-06-26 02:48:02 +02001726
William Lallemandbddd4fd2012-02-27 11:23:10 +01001727 /* FIXME: let's limit ourselves to frontend logging for now. */
Willy Tarreaubaaee002006-06-26 02:48:02 +02001728
Willy Tarreau09bb27c2018-09-05 16:55:15 +02001729 if (likely(s)) {
1730 be = s->be;
1731 txn = s->txn;
1732 be_conn = cs_conn(objt_cs(s->si[1].end));
1733 s_flags = s->flags;
1734 uniq_id = s->uniq_id;
1735 logs = &s->logs;
1736 } else {
1737 /* we have no stream so we first need to initialize a few
1738 * things that are needed later. We do increment the request
1739 * ID so that it's uniquely assigned to this request just as
1740 * if the request had reached the point of being processed.
1741 * A request error is reported as it's the only element we have
1742 * here and which justifies emitting such a log.
1743 */
1744 be = fe;
1745 txn = NULL;
1746 be_conn = NULL;
1747 s_flags = SF_ERR_PRXCOND | SF_FINST_R;
1748 uniq_id = HA_ATOMIC_XADD(&global.req_count, 1);
1749
1750 /* prepare a valid log structure */
1751 tmp_strm_log.tv_accept = sess->tv_accept;
1752 tmp_strm_log.accept_date = sess->accept_date;
1753 tmp_strm_log.t_handshake = sess->t_handshake;
1754 tmp_strm_log.t_idle = tv_ms_elapsed(&sess->tv_accept, &now) - sess->t_handshake;
1755 tv_zero(&tmp_strm_log.tv_request);
1756 tmp_strm_log.t_queue = -1;
1757 tmp_strm_log.t_connect = -1;
1758 tmp_strm_log.t_data = -1;
1759 tmp_strm_log.t_close = tv_ms_elapsed(&sess->tv_accept, &now);
1760 tmp_strm_log.bytes_in = 0;
1761 tmp_strm_log.bytes_out = 0;
1762 tmp_strm_log.prx_queue_pos = 0;
1763 tmp_strm_log.srv_queue_pos = 0;
1764
1765 logs = &tmp_strm_log;
1766 }
1767
William Lallemandbddd4fd2012-02-27 11:23:10 +01001768 t_request = -1;
Willy Tarreau372ac5a2018-09-05 15:16:23 +02001769 if (tv_isge(&logs->tv_request, &logs->tv_accept))
1770 t_request = tv_ms_elapsed(&logs->tv_accept, &logs->tv_request);
William Lallemandbddd4fd2012-02-27 11:23:10 +01001771
William Lallemand1d705562012-03-12 12:46:41 +01001772 tmplog = dst;
Willy Tarreauc9bd0cc2009-05-10 11:57:02 +02001773
William Lallemandbddd4fd2012-02-27 11:23:10 +01001774 /* fill logbuffer */
William Lallemand1d705562012-03-12 12:46:41 +01001775 if (LIST_ISEMPTY(list_format))
1776 return 0;
William Lallemandbddd4fd2012-02-27 11:23:10 +01001777
William Lallemand1d705562012-03-12 12:46:41 +01001778 list_for_each_entry(tmp, list_format, list) {
Willy Tarreaub363a1f2013-10-01 10:45:07 +02001779 struct connection *conn;
Willy Tarreau4f653562012-10-12 19:48:16 +02001780 const char *src = NULL;
Willy Tarreauc8368452012-12-21 00:09:23 +01001781 struct sample *key;
Willy Tarreau83061a82018-07-13 11:56:34 +02001782 const struct buffer empty = { };
William Lallemandbddd4fd2012-02-27 11:23:10 +01001783
Willy Tarreauc8368452012-12-21 00:09:23 +01001784 switch (tmp->type) {
William Lallemand1d705562012-03-12 12:46:41 +01001785 case LOG_FMT_SEPARATOR:
William Lallemandbddd4fd2012-02-27 11:23:10 +01001786 if (!last_isspace) {
1787 LOGCHAR(' ');
1788 last_isspace = 1;
William Lallemandbddd4fd2012-02-27 11:23:10 +01001789 }
1790 break;
1791
William Lallemand1d705562012-03-12 12:46:41 +01001792 case LOG_FMT_TEXT: // text
William Lallemandbddd4fd2012-02-27 11:23:10 +01001793 src = tmp->arg;
William Lallemand5f232402012-04-05 18:02:55 +02001794 iret = strlcpy2(tmplog, src, dst + maxsize - tmplog);
William Lallemand1d705562012-03-12 12:46:41 +01001795 if (iret == 0)
William Lallemandbddd4fd2012-02-27 11:23:10 +01001796 goto out;
William Lallemand1d705562012-03-12 12:46:41 +01001797 tmplog += iret;
William Lallemandbddd4fd2012-02-27 11:23:10 +01001798 last_isspace = 0;
1799 break;
1800
Willy Tarreauc8368452012-12-21 00:09:23 +01001801 case LOG_FMT_EXPR: // sample expression, may be request or response
1802 key = NULL;
1803 if (tmp->options & LOG_OPT_REQ_CAP)
Adis Nezirovic79beb242015-07-06 15:41:02 +02001804 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 +01001805 if (!key && (tmp->options & LOG_OPT_RES_CAP))
Adis Nezirovic79beb242015-07-06 15:41:02 +02001806 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 +01001807 if (tmp->options & LOG_OPT_HTTP)
Dragan Dosen835b9212016-02-12 13:23:03 +01001808 ret = lf_encode_chunk(tmplog, dst + maxsize,
1809 '%', http_encode_map, key ? &key->data.u.str : &empty, tmp);
Thierry FOURNIERd048d8b2014-03-13 16:46:18 +01001810 else
Willy Tarreau843b7cb2018-07-13 10:54:26 +02001811 ret = lf_text_len(tmplog,
1812 key ? key->data.u.str.area : NULL,
1813 key ? key->data.u.str.data : 0,
1814 dst + maxsize - tmplog,
1815 tmp);
Willy Tarreauc8368452012-12-21 00:09:23 +01001816 if (ret == 0)
1817 goto out;
1818 tmplog = ret;
1819 last_isspace = 0;
1820 break;
1821
Willy Tarreau2beef582012-12-20 17:22:52 +01001822 case LOG_FMT_CLIENTIP: // %ci
Willy Tarreau9ad7bd42015-04-03 19:19:59 +02001823 conn = objt_conn(sess->origin);
Willy Tarreaub363a1f2013-10-01 10:45:07 +02001824 if (conn)
1825 ret = lf_ip(tmplog, (struct sockaddr *)&conn->addr.from, dst + maxsize - tmplog, tmp);
1826 else
1827 ret = lf_text_len(tmplog, NULL, 0, dst + maxsize - tmplog, tmp);
William Lallemand1d705562012-03-12 12:46:41 +01001828 if (ret == NULL)
William Lallemandbddd4fd2012-02-27 11:23:10 +01001829 goto out;
William Lallemand1d705562012-03-12 12:46:41 +01001830 tmplog = ret;
William Lallemandbddd4fd2012-02-27 11:23:10 +01001831 last_isspace = 0;
1832 break;
1833
Willy Tarreau2beef582012-12-20 17:22:52 +01001834 case LOG_FMT_CLIENTPORT: // %cp
Willy Tarreau9ad7bd42015-04-03 19:19:59 +02001835 conn = objt_conn(sess->origin);
Willy Tarreaub363a1f2013-10-01 10:45:07 +02001836 if (conn) {
1837 if (conn->addr.from.ss_family == AF_UNIX) {
Willy Tarreaufb0afa72015-04-03 14:46:27 +02001838 ret = ltoa_o(sess->listener->luid, tmplog, dst + maxsize - tmplog);
Willy Tarreaub363a1f2013-10-01 10:45:07 +02001839 } else {
1840 ret = lf_port(tmplog, (struct sockaddr *)&conn->addr.from,
1841 dst + maxsize - tmplog, tmp);
1842 }
William Lallemand5f232402012-04-05 18:02:55 +02001843 }
Willy Tarreaub363a1f2013-10-01 10:45:07 +02001844 else
1845 ret = lf_text_len(tmplog, NULL, 0, dst + maxsize - tmplog, tmp);
1846
William Lallemand5f232402012-04-05 18:02:55 +02001847 if (ret == NULL)
1848 goto out;
1849 tmplog = ret;
1850 last_isspace = 0;
1851 break;
1852
Willy Tarreau2beef582012-12-20 17:22:52 +01001853 case LOG_FMT_FRONTENDIP: // %fi
Willy Tarreau9ad7bd42015-04-03 19:19:59 +02001854 conn = objt_conn(sess->origin);
Willy Tarreaub363a1f2013-10-01 10:45:07 +02001855 if (conn) {
1856 conn_get_to_addr(conn);
1857 ret = lf_ip(tmplog, (struct sockaddr *)&conn->addr.to, dst + maxsize - tmplog, tmp);
1858 }
1859 else
1860 ret = lf_text_len(tmplog, NULL, 0, dst + maxsize - tmplog, tmp);
1861
William Lallemand1d705562012-03-12 12:46:41 +01001862 if (ret == NULL)
William Lallemandbddd4fd2012-02-27 11:23:10 +01001863 goto out;
William Lallemand1d705562012-03-12 12:46:41 +01001864 tmplog = ret;
William Lallemandbddd4fd2012-02-27 11:23:10 +01001865 last_isspace = 0;
1866 break;
1867
Willy Tarreau2beef582012-12-20 17:22:52 +01001868 case LOG_FMT_FRONTENDPORT: // %fp
Willy Tarreau9ad7bd42015-04-03 19:19:59 +02001869 conn = objt_conn(sess->origin);
Willy Tarreaub363a1f2013-10-01 10:45:07 +02001870 if (conn) {
1871 conn_get_to_addr(conn);
1872 if (conn->addr.to.ss_family == AF_UNIX)
Willy Tarreaufb0afa72015-04-03 14:46:27 +02001873 ret = ltoa_o(sess->listener->luid, tmplog, dst + maxsize - tmplog);
Willy Tarreaub363a1f2013-10-01 10:45:07 +02001874 else
1875 ret = lf_port(tmplog, (struct sockaddr *)&conn->addr.to, dst + maxsize - tmplog, tmp);
William Lallemand5f232402012-04-05 18:02:55 +02001876 }
Willy Tarreaub363a1f2013-10-01 10:45:07 +02001877 else
1878 ret = lf_text_len(tmplog, NULL, 0, dst + maxsize - tmplog, tmp);
1879
William Lallemand5f232402012-04-05 18:02:55 +02001880 if (ret == NULL)
1881 goto out;
1882 tmplog = ret;
1883 last_isspace = 0;
1884 break;
1885
Willy Tarreau2beef582012-12-20 17:22:52 +01001886 case LOG_FMT_BACKENDIP: // %bi
Willy Tarreau2393c5b2018-09-05 15:24:56 +02001887 if (be_conn)
1888 ret = lf_ip(tmplog, (const struct sockaddr *)&be_conn->addr.from, dst + maxsize - tmplog, tmp);
Willy Tarreaub363a1f2013-10-01 10:45:07 +02001889 else
1890 ret = lf_text_len(tmplog, NULL, 0, dst + maxsize - tmplog, tmp);
1891
William Lallemand1d705562012-03-12 12:46:41 +01001892 if (ret == NULL)
William Lallemandb7ff6a32012-03-02 14:35:21 +01001893 goto out;
William Lallemand1d705562012-03-12 12:46:41 +01001894 tmplog = ret;
William Lallemandb7ff6a32012-03-02 14:35:21 +01001895 last_isspace = 0;
1896 break;
1897
Willy Tarreau2beef582012-12-20 17:22:52 +01001898 case LOG_FMT_BACKENDPORT: // %bp
Willy Tarreau2393c5b2018-09-05 15:24:56 +02001899 if (be_conn)
1900 ret = lf_port(tmplog, (struct sockaddr *)&be_conn->addr.from, dst + maxsize - tmplog, tmp);
Willy Tarreaub363a1f2013-10-01 10:45:07 +02001901 else
1902 ret = lf_text_len(tmplog, NULL, 0, dst + maxsize - tmplog, tmp);
1903
William Lallemand5f232402012-04-05 18:02:55 +02001904 if (ret == NULL)
1905 goto out;
1906 tmplog = ret;
1907 last_isspace = 0;
1908 break;
1909
Willy Tarreau2beef582012-12-20 17:22:52 +01001910 case LOG_FMT_SERVERIP: // %si
Willy Tarreau2393c5b2018-09-05 15:24:56 +02001911 if (be_conn)
1912 ret = lf_ip(tmplog, (struct sockaddr *)&be_conn->addr.to, dst + maxsize - tmplog, tmp);
Willy Tarreaub363a1f2013-10-01 10:45:07 +02001913 else
1914 ret = lf_text_len(tmplog, NULL, 0, dst + maxsize - tmplog, tmp);
1915
William Lallemand5f232402012-04-05 18:02:55 +02001916 if (ret == NULL)
1917 goto out;
1918 tmplog = ret;
1919 last_isspace = 0;
1920 break;
1921
Willy Tarreau2beef582012-12-20 17:22:52 +01001922 case LOG_FMT_SERVERPORT: // %sp
Willy Tarreau2393c5b2018-09-05 15:24:56 +02001923 if (be_conn)
1924 ret = lf_port(tmplog, (struct sockaddr *)&be_conn->addr.to, dst + maxsize - tmplog, tmp);
Willy Tarreaub363a1f2013-10-01 10:45:07 +02001925 else
1926 ret = lf_text_len(tmplog, NULL, 0, dst + maxsize - tmplog, tmp);
1927
William Lallemand1d705562012-03-12 12:46:41 +01001928 if (ret == NULL)
William Lallemandb7ff6a32012-03-02 14:35:21 +01001929 goto out;
William Lallemand1d705562012-03-12 12:46:41 +01001930 tmplog = ret;
William Lallemandb7ff6a32012-03-02 14:35:21 +01001931 last_isspace = 0;
1932 break;
1933
Thierry FOURNIER / OZON.IO4cac3592016-07-28 17:19:45 +02001934 case LOG_FMT_DATE: // %t = accept date
Willy Tarreau372ac5a2018-09-05 15:16:23 +02001935 get_localtime(logs->accept_date.tv_sec, &tm);
1936 ret = date2str_log(tmplog, &tm, &logs->accept_date, dst + maxsize - tmplog);
William Lallemand1d705562012-03-12 12:46:41 +01001937 if (ret == NULL)
William Lallemandbddd4fd2012-02-27 11:23:10 +01001938 goto out;
William Lallemand1d705562012-03-12 12:46:41 +01001939 tmplog = ret;
William Lallemandbddd4fd2012-02-27 11:23:10 +01001940 last_isspace = 0;
1941 break;
1942
Thierry FOURNIER / OZON.IO4cac3592016-07-28 17:19:45 +02001943 case LOG_FMT_tr: // %tr = start of request date
1944 /* Note that the timers are valid if we get here */
Willy Tarreau372ac5a2018-09-05 15:16:23 +02001945 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 +02001946 get_localtime(tv.tv_sec, &tm);
1947 ret = date2str_log(tmplog, &tm, &tv, dst + maxsize - tmplog);
1948 if (ret == NULL)
1949 goto out;
1950 tmplog = ret;
1951 last_isspace = 0;
1952 break;
1953
1954 case LOG_FMT_DATEGMT: // %T = accept date, GMT
Willy Tarreau372ac5a2018-09-05 15:16:23 +02001955 get_gmtime(logs->accept_date.tv_sec, &tm);
William Lallemand5f232402012-04-05 18:02:55 +02001956 ret = gmt2str_log(tmplog, &tm, dst + maxsize - tmplog);
William Lallemand1d705562012-03-12 12:46:41 +01001957 if (ret == NULL)
William Lallemandbddd4fd2012-02-27 11:23:10 +01001958 goto out;
William Lallemand1d705562012-03-12 12:46:41 +01001959 tmplog = ret;
William Lallemandbddd4fd2012-02-27 11:23:10 +01001960 last_isspace = 0;
1961 break;
1962
Thierry FOURNIER / OZON.IO4cac3592016-07-28 17:19:45 +02001963 case LOG_FMT_trg: // %trg = start of request date, GMT
Willy Tarreau372ac5a2018-09-05 15:16:23 +02001964 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 +02001965 get_gmtime(tv.tv_sec, &tm);
1966 ret = gmt2str_log(tmplog, &tm, dst + maxsize - tmplog);
1967 if (ret == NULL)
1968 goto out;
1969 tmplog = ret;
1970 last_isspace = 0;
1971 break;
1972
1973 case LOG_FMT_DATELOCAL: // %Tl = accept date, local
Willy Tarreau372ac5a2018-09-05 15:16:23 +02001974 get_localtime(logs->accept_date.tv_sec, &tm);
1975 ret = localdate2str_log(tmplog, logs->accept_date.tv_sec, &tm, dst + maxsize - tmplog);
Yuxans Yao4e25b012012-10-19 10:36:09 +08001976 if (ret == NULL)
1977 goto out;
1978 tmplog = ret;
1979 last_isspace = 0;
1980 break;
1981
Thierry FOURNIER / OZON.IO4cac3592016-07-28 17:19:45 +02001982 case LOG_FMT_trl: // %trl = start of request date, local
Willy Tarreau372ac5a2018-09-05 15:16:23 +02001983 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 +02001984 get_localtime(tv.tv_sec, &tm);
1985 ret = localdate2str_log(tmplog, tv.tv_sec, &tm, dst + maxsize - tmplog);
1986 if (ret == NULL)
1987 goto out;
1988 tmplog = ret;
1989 last_isspace = 0;
1990 break;
1991
William Lallemand5f232402012-04-05 18:02:55 +02001992 case LOG_FMT_TS: // %Ts
Willy Tarreau372ac5a2018-09-05 15:16:23 +02001993 get_gmtime(logs->accept_date.tv_sec, &tm);
William Lallemand5f232402012-04-05 18:02:55 +02001994 if (tmp->options & LOG_OPT_HEXA) {
Willy Tarreau372ac5a2018-09-05 15:16:23 +02001995 iret = snprintf(tmplog, dst + maxsize - tmplog, "%04X", (unsigned int)logs->accept_date.tv_sec);
William Lallemand5f232402012-04-05 18:02:55 +02001996 if (iret < 0 || iret > dst + maxsize - tmplog)
1997 goto out;
1998 last_isspace = 0;
1999 tmplog += iret;
2000 } else {
Willy Tarreau372ac5a2018-09-05 15:16:23 +02002001 ret = ltoa_o(logs->accept_date.tv_sec, tmplog, dst + maxsize - tmplog);
William Lallemand5f232402012-04-05 18:02:55 +02002002 if (ret == NULL)
2003 goto out;
2004 tmplog = ret;
2005 last_isspace = 0;
2006 }
2007 break;
2008
William Lallemand1d705562012-03-12 12:46:41 +01002009 case LOG_FMT_MS: // %ms
William Lallemand5f232402012-04-05 18:02:55 +02002010 if (tmp->options & LOG_OPT_HEXA) {
Willy Tarreau372ac5a2018-09-05 15:16:23 +02002011 iret = snprintf(tmplog, dst + maxsize - tmplog, "%02X",(unsigned int)logs->accept_date.tv_usec/1000);
William Lallemand5f232402012-04-05 18:02:55 +02002012 if (iret < 0 || iret > dst + maxsize - tmplog)
2013 goto out;
2014 last_isspace = 0;
2015 tmplog += iret;
2016 } else {
2017 if ((dst + maxsize - tmplog) < 4)
William Lallemandbddd4fd2012-02-27 11:23:10 +01002018 goto out;
Willy Tarreau372ac5a2018-09-05 15:16:23 +02002019 ret = utoa_pad((unsigned int)logs->accept_date.tv_usec/1000,
Willy Tarreau9e60cd82013-01-24 01:18:16 +01002020 tmplog, 4);
2021 if (ret == NULL)
William Lallemand51b5dca2012-03-26 17:52:55 +02002022 goto out;
Willy Tarreau9e60cd82013-01-24 01:18:16 +01002023 tmplog = ret;
William Lallemandbddd4fd2012-02-27 11:23:10 +01002024 last_isspace = 0;
William Lallemand5f232402012-04-05 18:02:55 +02002025 }
2026 break;
William Lallemandbddd4fd2012-02-27 11:23:10 +01002027
William Lallemand1d705562012-03-12 12:46:41 +01002028 case LOG_FMT_FRONTEND: // %f
William Lallemandbddd4fd2012-02-27 11:23:10 +01002029 src = fe->id;
William Lallemand5f232402012-04-05 18:02:55 +02002030 ret = lf_text(tmplog, src, dst + maxsize - tmplog, tmp);
William Lallemand1d705562012-03-12 12:46:41 +01002031 if (ret == NULL)
William Lallemandbddd4fd2012-02-27 11:23:10 +01002032 goto out;
William Lallemand1d705562012-03-12 12:46:41 +01002033 tmplog = ret;
William Lallemand51b5dca2012-03-26 17:52:55 +02002034 last_isspace = 0;
William Lallemandbddd4fd2012-02-27 11:23:10 +01002035 break;
2036
Willy Tarreau773d65f2012-10-12 14:56:11 +02002037 case LOG_FMT_FRONTEND_XPRT: // %ft
2038 src = fe->id;
2039 if (tmp->options & LOG_OPT_QUOTE)
2040 LOGCHAR('"');
2041 iret = strlcpy2(tmplog, src, dst + maxsize - tmplog);
2042 if (iret == 0)
2043 goto out;
2044 tmplog += iret;
Willy Tarreaua261e9b2016-12-22 20:44:00 +01002045 if (sess->listener->bind_conf->xprt == xprt_get(XPRT_SSL))
Willy Tarreau773d65f2012-10-12 14:56:11 +02002046 LOGCHAR('~');
Willy Tarreau773d65f2012-10-12 14:56:11 +02002047 if (tmp->options & LOG_OPT_QUOTE)
2048 LOGCHAR('"');
2049 last_isspace = 0;
2050 break;
Willy Tarreauffc3fcd2012-10-12 20:17:54 +02002051#ifdef USE_OPENSSL
2052 case LOG_FMT_SSL_CIPHER: // %sslc
2053 src = NULL;
Willy Tarreau9ad7bd42015-04-03 19:19:59 +02002054 conn = objt_conn(sess->origin);
Willy Tarreaub363a1f2013-10-01 10:45:07 +02002055 if (conn) {
Emmanuel Hocdet01da5712017-10-13 16:59:49 +02002056 src = ssl_sock_get_cipher_name(conn);
Willy Tarreaub363a1f2013-10-01 10:45:07 +02002057 }
Willy Tarreauffc3fcd2012-10-12 20:17:54 +02002058 ret = lf_text(tmplog, src, dst + maxsize - tmplog, tmp);
2059 if (ret == NULL)
2060 goto out;
2061 tmplog = ret;
2062 last_isspace = 0;
2063 break;
Willy Tarreau773d65f2012-10-12 14:56:11 +02002064
Willy Tarreauffc3fcd2012-10-12 20:17:54 +02002065 case LOG_FMT_SSL_VERSION: // %sslv
2066 src = NULL;
Willy Tarreau9ad7bd42015-04-03 19:19:59 +02002067 conn = objt_conn(sess->origin);
Willy Tarreaub363a1f2013-10-01 10:45:07 +02002068 if (conn) {
Emmanuel Hocdet01da5712017-10-13 16:59:49 +02002069 src = ssl_sock_get_proto_version(conn);
Willy Tarreaub363a1f2013-10-01 10:45:07 +02002070 }
Willy Tarreauffc3fcd2012-10-12 20:17:54 +02002071 ret = lf_text(tmplog, src, dst + maxsize - tmplog, tmp);
2072 if (ret == NULL)
2073 goto out;
2074 tmplog = ret;
2075 last_isspace = 0;
2076 break;
2077#endif
William Lallemand1d705562012-03-12 12:46:41 +01002078 case LOG_FMT_BACKEND: // %b
William Lallemandbddd4fd2012-02-27 11:23:10 +01002079 src = be->id;
William Lallemand5f232402012-04-05 18:02:55 +02002080 ret = lf_text(tmplog, src, dst + maxsize - tmplog, tmp);
William Lallemand1d705562012-03-12 12:46:41 +01002081 if (ret == NULL)
William Lallemandbddd4fd2012-02-27 11:23:10 +01002082 goto out;
William Lallemand1d705562012-03-12 12:46:41 +01002083 tmplog = ret;
William Lallemand51b5dca2012-03-26 17:52:55 +02002084 last_isspace = 0;
William Lallemandbddd4fd2012-02-27 11:23:10 +01002085 break;
2086
William Lallemand1d705562012-03-12 12:46:41 +01002087 case LOG_FMT_SERVER: // %s
Willy Tarreaue1809df2018-09-05 15:30:16 +02002088 switch (obj_type(s ? s->target : NULL)) {
Willy Tarreaud79a3b22012-12-28 09:40:16 +01002089 case OBJ_TYPE_SERVER:
Willy Tarreau1aaf3242018-09-20 11:13:58 +02002090 src = __objt_server(s->target)->id;
Willy Tarreaud79a3b22012-12-28 09:40:16 +01002091 break;
2092 case OBJ_TYPE_APPLET:
Willy Tarreau1aaf3242018-09-20 11:13:58 +02002093 src = __objt_applet(s->target)->name;
Willy Tarreaud79a3b22012-12-28 09:40:16 +01002094 break;
2095 default:
2096 src = "<NOSRV>";
2097 break;
2098 }
William Lallemand5f232402012-04-05 18:02:55 +02002099 ret = lf_text(tmplog, src, dst + maxsize - tmplog, tmp);
William Lallemand1d705562012-03-12 12:46:41 +01002100 if (ret == NULL)
William Lallemandbddd4fd2012-02-27 11:23:10 +01002101 goto out;
William Lallemand1d705562012-03-12 12:46:41 +01002102 tmplog = ret;
William Lallemandbddd4fd2012-02-27 11:23:10 +01002103 last_isspace = 0;
2104 break;
2105
Thierry FOURNIER / OZON.IO4cac3592016-07-28 17:19:45 +02002106 case LOG_FMT_Th: // %Th = handshake time
Willy Tarreau372ac5a2018-09-05 15:16:23 +02002107 ret = ltoa_o(logs->t_handshake, tmplog, dst + maxsize - tmplog);
Thierry FOURNIER / OZON.IO4cac3592016-07-28 17:19:45 +02002108 if (ret == NULL)
2109 goto out;
2110 tmplog = ret;
2111 last_isspace = 0;
2112 break;
2113
2114 case LOG_FMT_Ti: // %Ti = HTTP idle time
Willy Tarreau372ac5a2018-09-05 15:16:23 +02002115 ret = ltoa_o(logs->t_idle, tmplog, dst + maxsize - tmplog);
Thierry FOURNIER / OZON.IO4cac3592016-07-28 17:19:45 +02002116 if (ret == NULL)
2117 goto out;
2118 tmplog = ret;
2119 last_isspace = 0;
2120 break;
2121
2122 case LOG_FMT_TR: // %TR = HTTP request time
Willy Tarreau372ac5a2018-09-05 15:16:23 +02002123 ret = ltoa_o((t_request >= 0) ? t_request - logs->t_idle - logs->t_handshake : -1,
Thierry FOURNIER / OZON.IO4cac3592016-07-28 17:19:45 +02002124 tmplog, dst + maxsize - tmplog);
2125 if (ret == NULL)
2126 goto out;
2127 tmplog = ret;
2128 last_isspace = 0;
2129 break;
2130
2131 case LOG_FMT_TQ: // %Tq = Th + Ti + TR
William Lallemand5f232402012-04-05 18:02:55 +02002132 ret = ltoa_o(t_request, tmplog, dst + maxsize - tmplog);
William Lallemand1d705562012-03-12 12:46:41 +01002133 if (ret == NULL)
William Lallemandbddd4fd2012-02-27 11:23:10 +01002134 goto out;
William Lallemand1d705562012-03-12 12:46:41 +01002135 tmplog = ret;
William Lallemandbddd4fd2012-02-27 11:23:10 +01002136 last_isspace = 0;
2137 break;
2138
William Lallemand1d705562012-03-12 12:46:41 +01002139 case LOG_FMT_TW: // %Tw
Willy Tarreau372ac5a2018-09-05 15:16:23 +02002140 ret = ltoa_o((logs->t_queue >= 0) ? logs->t_queue - t_request : -1,
William Lallemand5f232402012-04-05 18:02:55 +02002141 tmplog, dst + maxsize - tmplog);
William Lallemand1d705562012-03-12 12:46:41 +01002142 if (ret == NULL)
William Lallemandbddd4fd2012-02-27 11:23:10 +01002143 goto out;
William Lallemand1d705562012-03-12 12:46:41 +01002144 tmplog = ret;
William Lallemandbddd4fd2012-02-27 11:23:10 +01002145 last_isspace = 0;
2146 break;
2147
William Lallemand1d705562012-03-12 12:46:41 +01002148 case LOG_FMT_TC: // %Tc
Willy Tarreau372ac5a2018-09-05 15:16:23 +02002149 ret = ltoa_o((logs->t_connect >= 0) ? logs->t_connect - logs->t_queue : -1,
William Lallemand5f232402012-04-05 18:02:55 +02002150 tmplog, dst + maxsize - tmplog);
William Lallemand1d705562012-03-12 12:46:41 +01002151 if (ret == NULL)
William Lallemandbddd4fd2012-02-27 11:23:10 +01002152 goto out;
William Lallemand1d705562012-03-12 12:46:41 +01002153 tmplog = ret;
William Lallemandbddd4fd2012-02-27 11:23:10 +01002154 last_isspace = 0;
2155 break;
2156
Thierry FOURNIER / OZON.IO4cac3592016-07-28 17:19:45 +02002157 case LOG_FMT_Tr: // %Tr
Willy Tarreau372ac5a2018-09-05 15:16:23 +02002158 ret = ltoa_o((logs->t_data >= 0) ? logs->t_data - logs->t_connect : -1,
William Lallemand5f232402012-04-05 18:02:55 +02002159 tmplog, dst + maxsize - tmplog);
William Lallemand1d705562012-03-12 12:46:41 +01002160 if (ret == NULL)
William Lallemandbddd4fd2012-02-27 11:23:10 +01002161 goto out;
William Lallemand1d705562012-03-12 12:46:41 +01002162 tmplog = ret;
William Lallemandbddd4fd2012-02-27 11:23:10 +01002163 last_isspace = 0;
2164 break;
2165
Willy Tarreau27b639d2016-05-17 17:55:27 +02002166 case LOG_FMT_TD: // %Td
Willy Tarreaua21c0e62018-09-05 15:07:15 +02002167 if (be->mode == PR_MODE_HTTP)
Willy Tarreau372ac5a2018-09-05 15:16:23 +02002168 ret = ltoa_o((logs->t_data >= 0) ? logs->t_close - logs->t_data : -1,
Willy Tarreau27b639d2016-05-17 17:55:27 +02002169 tmplog, dst + maxsize - tmplog);
2170 else
Willy Tarreau372ac5a2018-09-05 15:16:23 +02002171 ret = ltoa_o((logs->t_connect >= 0) ? logs->t_close - logs->t_connect : -1,
Willy Tarreau27b639d2016-05-17 17:55:27 +02002172 tmplog, dst + maxsize - tmplog);
2173 if (ret == NULL)
2174 goto out;
2175 tmplog = ret;
2176 last_isspace = 0;
2177 break;
2178
Thierry FOURNIER / OZON.IO4cac3592016-07-28 17:19:45 +02002179 case LOG_FMT_Ta: // %Ta = active time = Tt - Th - Ti
2180 if (!(fe->to_log & LW_BYTES))
2181 LOGCHAR('+');
Willy Tarreau372ac5a2018-09-05 15:16:23 +02002182 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 +02002183 tmplog, dst + maxsize - tmplog);
2184 if (ret == NULL)
2185 goto out;
2186 tmplog = ret;
2187 last_isspace = 0;
2188 break;
2189
2190 case LOG_FMT_TT: // %Tt = total time
Willy Tarreaud79a3b22012-12-28 09:40:16 +01002191 if (!(fe->to_log & LW_BYTES))
William Lallemand1d705562012-03-12 12:46:41 +01002192 LOGCHAR('+');
Willy Tarreau372ac5a2018-09-05 15:16:23 +02002193 ret = ltoa_o(logs->t_close, tmplog, dst + maxsize - tmplog);
William Lallemand1d705562012-03-12 12:46:41 +01002194 if (ret == NULL)
William Lallemandbddd4fd2012-02-27 11:23:10 +01002195 goto out;
William Lallemand1d705562012-03-12 12:46:41 +01002196 tmplog = ret;
William Lallemandbddd4fd2012-02-27 11:23:10 +01002197 last_isspace = 0;
2198 break;
2199
Willy Tarreau2beef582012-12-20 17:22:52 +01002200 case LOG_FMT_STATUS: // %ST
Willy Tarreau57bc8912016-04-25 17:09:40 +02002201 ret = ltoa_o(txn ? txn->status : 0, tmplog, dst + maxsize - tmplog);
William Lallemand1d705562012-03-12 12:46:41 +01002202 if (ret == NULL)
William Lallemandbddd4fd2012-02-27 11:23:10 +01002203 goto out;
William Lallemand1d705562012-03-12 12:46:41 +01002204 tmplog = ret;
William Lallemandbddd4fd2012-02-27 11:23:10 +01002205 last_isspace = 0;
2206 break;
2207
William Lallemand1d705562012-03-12 12:46:41 +01002208 case LOG_FMT_BYTES: // %B
Willy Tarreaud79a3b22012-12-28 09:40:16 +01002209 if (!(fe->to_log & LW_BYTES))
William Lallemand1d705562012-03-12 12:46:41 +01002210 LOGCHAR('+');
Willy Tarreau372ac5a2018-09-05 15:16:23 +02002211 ret = lltoa(logs->bytes_out, tmplog, dst + maxsize - tmplog);
William Lallemand1d705562012-03-12 12:46:41 +01002212 if (ret == NULL)
William Lallemandbddd4fd2012-02-27 11:23:10 +01002213 goto out;
William Lallemand1d705562012-03-12 12:46:41 +01002214 tmplog = ret;
William Lallemandbddd4fd2012-02-27 11:23:10 +01002215 last_isspace = 0;
2216 break;
2217
Willy Tarreauc5259fd2012-12-20 15:38:04 +01002218 case LOG_FMT_BYTES_UP: // %U
Willy Tarreau372ac5a2018-09-05 15:16:23 +02002219 ret = lltoa(logs->bytes_in, tmplog, dst + maxsize - tmplog);
Willy Tarreauc5259fd2012-12-20 15:38:04 +01002220 if (ret == NULL)
2221 goto out;
2222 tmplog = ret;
2223 last_isspace = 0;
2224 break;
2225
Willy Tarreau2beef582012-12-20 17:22:52 +01002226 case LOG_FMT_CCLIENT: // %CC
Willy Tarreau57bc8912016-04-25 17:09:40 +02002227 src = txn ? txn->cli_cookie : NULL;
William Lallemand5f232402012-04-05 18:02:55 +02002228 ret = lf_text(tmplog, src, dst + maxsize - tmplog, tmp);
William Lallemand1d705562012-03-12 12:46:41 +01002229 if (ret == NULL)
William Lallemand51b5dca2012-03-26 17:52:55 +02002230 goto out;
William Lallemand1d705562012-03-12 12:46:41 +01002231 tmplog = ret;
William Lallemandbddd4fd2012-02-27 11:23:10 +01002232 last_isspace = 0;
2233 break;
2234
Willy Tarreau2beef582012-12-20 17:22:52 +01002235 case LOG_FMT_CSERVER: // %CS
Willy Tarreau57bc8912016-04-25 17:09:40 +02002236 src = txn ? txn->srv_cookie : NULL;
William Lallemand5f232402012-04-05 18:02:55 +02002237 ret = lf_text(tmplog, src, dst + maxsize - tmplog, tmp);
William Lallemand1d705562012-03-12 12:46:41 +01002238 if (ret == NULL)
William Lallemand51b5dca2012-03-26 17:52:55 +02002239 goto out;
William Lallemand1d705562012-03-12 12:46:41 +01002240 tmplog = ret;
William Lallemandbddd4fd2012-02-27 11:23:10 +01002241 last_isspace = 0;
2242 break;
2243
William Lallemand1d705562012-03-12 12:46:41 +01002244 case LOG_FMT_TERMSTATE: // %ts
Willy Tarreaub8bc5252018-09-05 15:51:28 +02002245 LOGCHAR(sess_term_cond[(s_flags & SF_ERR_MASK) >> SF_ERR_SHIFT]);
2246 LOGCHAR(sess_fin_state[(s_flags & SF_FINST_MASK) >> SF_FINST_SHIFT]);
Willy Tarreau6580c062012-03-12 15:09:42 +01002247 *tmplog = '\0';
2248 last_isspace = 0;
2249 break;
William Lallemandbddd4fd2012-02-27 11:23:10 +01002250
William Lallemand1d705562012-03-12 12:46:41 +01002251 case LOG_FMT_TERMSTATE_CK: // %tsc, same as TS with cookie state (for mode HTTP)
Willy Tarreaub8bc5252018-09-05 15:51:28 +02002252 LOGCHAR(sess_term_cond[(s_flags & SF_ERR_MASK) >> SF_ERR_SHIFT]);
2253 LOGCHAR(sess_fin_state[(s_flags & SF_FINST_MASK) >> SF_FINST_SHIFT]);
Willy Tarreau57bc8912016-04-25 17:09:40 +02002254 LOGCHAR((txn && (be->ck_opts & PR_CK_ANY)) ? sess_cookie[(txn->flags & TX_CK_MASK) >> TX_CK_SHIFT] : '-');
2255 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 +01002256 last_isspace = 0;
2257 break;
2258
William Lallemand1d705562012-03-12 12:46:41 +01002259 case LOG_FMT_ACTCONN: // %ac
William Lallemand5f232402012-04-05 18:02:55 +02002260 ret = ltoa_o(actconn, tmplog, dst + maxsize - tmplog);
William Lallemand1d705562012-03-12 12:46:41 +01002261 if (ret == NULL)
William Lallemandbddd4fd2012-02-27 11:23:10 +01002262 goto out;
William Lallemand1d705562012-03-12 12:46:41 +01002263 tmplog = ret;
William Lallemandbddd4fd2012-02-27 11:23:10 +01002264 last_isspace = 0;
2265 break;
2266
William Lallemand1d705562012-03-12 12:46:41 +01002267 case LOG_FMT_FECONN: // %fc
William Lallemand5f232402012-04-05 18:02:55 +02002268 ret = ltoa_o(fe->feconn, tmplog, dst + maxsize - tmplog);
William Lallemand1d705562012-03-12 12:46:41 +01002269 if (ret == NULL)
William Lallemandbddd4fd2012-02-27 11:23:10 +01002270 goto out;
William Lallemand1d705562012-03-12 12:46:41 +01002271 tmplog = ret;
William Lallemandbddd4fd2012-02-27 11:23:10 +01002272 last_isspace = 0;
2273 break;
2274
William Lallemand1d705562012-03-12 12:46:41 +01002275 case LOG_FMT_BECONN: // %bc
William Lallemand5f232402012-04-05 18:02:55 +02002276 ret = ltoa_o(be->beconn, tmplog, dst + maxsize - tmplog);
William Lallemand1d705562012-03-12 12:46:41 +01002277 if (ret == NULL)
William Lallemandbddd4fd2012-02-27 11:23:10 +01002278 goto out;
William Lallemand1d705562012-03-12 12:46:41 +01002279 tmplog = ret;
William Lallemandbddd4fd2012-02-27 11:23:10 +01002280 last_isspace = 0;
2281 break;
2282
William Lallemand1d705562012-03-12 12:46:41 +01002283 case LOG_FMT_SRVCONN: // %sc
Willy Tarreaue1809df2018-09-05 15:30:16 +02002284 ret = ultoa_o(objt_server(s ? s->target : NULL) ?
Willy Tarreau3fdb3662012-11-12 00:42:33 +01002285 objt_server(s->target)->cur_sess :
William Lallemand5f232402012-04-05 18:02:55 +02002286 0, tmplog, dst + maxsize - tmplog);
William Lallemand1d705562012-03-12 12:46:41 +01002287 if (ret == NULL)
William Lallemandbddd4fd2012-02-27 11:23:10 +01002288 goto out;
William Lallemand1d705562012-03-12 12:46:41 +01002289 tmplog = ret;
William Lallemandbddd4fd2012-02-27 11:23:10 +01002290 last_isspace = 0;
2291 break;
2292
William Lallemand1d705562012-03-12 12:46:41 +01002293 case LOG_FMT_RETRIES: // %rq
Willy Tarreaub8bc5252018-09-05 15:51:28 +02002294 if (s_flags & SF_REDISP)
William Lallemand1d705562012-03-12 12:46:41 +01002295 LOGCHAR('+');
Willy Tarreauabd71a52018-09-04 19:21:44 +02002296 ret = ltoa_o((s && s->si[1].conn_retries > 0) ?
Willy Tarreau350f4872014-11-28 14:42:25 +01002297 (be->conn_retries - s->si[1].conn_retries) :
William Lallemand5f232402012-04-05 18:02:55 +02002298 be->conn_retries, tmplog, dst + maxsize - tmplog);
William Lallemand1d705562012-03-12 12:46:41 +01002299 if (ret == NULL)
William Lallemand51b5dca2012-03-26 17:52:55 +02002300 goto out;
William Lallemand1d705562012-03-12 12:46:41 +01002301 tmplog = ret;
William Lallemandbddd4fd2012-02-27 11:23:10 +01002302 last_isspace = 0;
2303 break;
2304
William Lallemand1d705562012-03-12 12:46:41 +01002305 case LOG_FMT_SRVQUEUE: // %sq
Willy Tarreau372ac5a2018-09-05 15:16:23 +02002306 ret = ltoa_o(logs->srv_queue_pos, tmplog, dst + maxsize - tmplog);
William Lallemand1d705562012-03-12 12:46:41 +01002307 if (ret == NULL)
William Lallemandbddd4fd2012-02-27 11:23:10 +01002308 goto out;
William Lallemand1d705562012-03-12 12:46:41 +01002309 tmplog = ret;
William Lallemandbddd4fd2012-02-27 11:23:10 +01002310 last_isspace = 0;
2311 break;
2312
William Lallemand1d705562012-03-12 12:46:41 +01002313 case LOG_FMT_BCKQUEUE: // %bq
Willy Tarreau372ac5a2018-09-05 15:16:23 +02002314 ret = ltoa_o(logs->prx_queue_pos, tmplog, dst + maxsize - tmplog);
William Lallemand1d705562012-03-12 12:46:41 +01002315 if (ret == NULL)
William Lallemandbddd4fd2012-02-27 11:23:10 +01002316 goto out;
William Lallemand1d705562012-03-12 12:46:41 +01002317 tmplog = ret;
William Lallemandbddd4fd2012-02-27 11:23:10 +01002318 last_isspace = 0;
2319 break;
2320
William Lallemand1d705562012-03-12 12:46:41 +01002321 case LOG_FMT_HDRREQUEST: // %hr
William Lallemandbddd4fd2012-02-27 11:23:10 +01002322 /* request header */
Willy Tarreaud4f91662018-09-05 15:28:07 +02002323 if (fe->nb_req_cap && s && s->req_cap) {
William Lallemandbddd4fd2012-02-27 11:23:10 +01002324 if (tmp->options & LOG_OPT_QUOTE)
2325 LOGCHAR('"');
2326 LOGCHAR('{');
2327 for (hdr = 0; hdr < fe->nb_req_cap; hdr++) {
2328 if (hdr)
2329 LOGCHAR('|');
Willy Tarreaucb7dd012015-04-03 22:16:32 +02002330 if (s->req_cap[hdr] != NULL) {
Dragan Dosen835b9212016-02-12 13:23:03 +01002331 ret = lf_encode_string(tmplog, dst + maxsize,
2332 '#', hdr_encode_map, s->req_cap[hdr], tmp);
William Lallemand1d705562012-03-12 12:46:41 +01002333 if (ret == NULL || *ret != '\0')
William Lallemand51b5dca2012-03-26 17:52:55 +02002334 goto out;
William Lallemand1d705562012-03-12 12:46:41 +01002335 tmplog = ret;
William Lallemand51b5dca2012-03-26 17:52:55 +02002336 }
William Lallemandbddd4fd2012-02-27 11:23:10 +01002337 }
2338 LOGCHAR('}');
William Lallemand51b5dca2012-03-26 17:52:55 +02002339 if (tmp->options & LOG_OPT_QUOTE)
2340 LOGCHAR('"');
William Lallemandbddd4fd2012-02-27 11:23:10 +01002341 last_isspace = 0;
2342 }
William Lallemandbddd4fd2012-02-27 11:23:10 +01002343 break;
2344
William Lallemand1d705562012-03-12 12:46:41 +01002345 case LOG_FMT_HDRREQUESTLIST: // %hrl
William Lallemandbddd4fd2012-02-27 11:23:10 +01002346 /* request header list */
Willy Tarreaud4f91662018-09-05 15:28:07 +02002347 if (fe->nb_req_cap && s && s->req_cap) {
William Lallemandbddd4fd2012-02-27 11:23:10 +01002348 for (hdr = 0; hdr < fe->nb_req_cap; hdr++) {
2349 if (hdr > 0)
2350 LOGCHAR(' ');
2351 if (tmp->options & LOG_OPT_QUOTE)
2352 LOGCHAR('"');
Willy Tarreaucb7dd012015-04-03 22:16:32 +02002353 if (s->req_cap[hdr] != NULL) {
Dragan Dosen835b9212016-02-12 13:23:03 +01002354 ret = lf_encode_string(tmplog, dst + maxsize,
2355 '#', hdr_encode_map, s->req_cap[hdr], tmp);
William Lallemand1d705562012-03-12 12:46:41 +01002356 if (ret == NULL || *ret != '\0')
William Lallemand51b5dca2012-03-26 17:52:55 +02002357 goto out;
William Lallemand1d705562012-03-12 12:46:41 +01002358 tmplog = ret;
William Lallemandbddd4fd2012-02-27 11:23:10 +01002359 } else if (!(tmp->options & LOG_OPT_QUOTE))
2360 LOGCHAR('-');
2361 if (tmp->options & LOG_OPT_QUOTE)
2362 LOGCHAR('"');
William Lallemandbddd4fd2012-02-27 11:23:10 +01002363 last_isspace = 0;
2364 }
2365 }
2366 break;
Willy Tarreaubaaee002006-06-26 02:48:02 +02002367
William Lallemand1d705562012-03-12 12:46:41 +01002368
2369 case LOG_FMT_HDRRESPONS: // %hs
William Lallemandbddd4fd2012-02-27 11:23:10 +01002370 /* response header */
Willy Tarreaud4f91662018-09-05 15:28:07 +02002371 if (fe->nb_rsp_cap && s && s->res_cap) {
William Lallemandbddd4fd2012-02-27 11:23:10 +01002372 if (tmp->options & LOG_OPT_QUOTE)
2373 LOGCHAR('"');
2374 LOGCHAR('{');
2375 for (hdr = 0; hdr < fe->nb_rsp_cap; hdr++) {
2376 if (hdr)
2377 LOGCHAR('|');
Willy Tarreaucb7dd012015-04-03 22:16:32 +02002378 if (s->res_cap[hdr] != NULL) {
Dragan Dosen835b9212016-02-12 13:23:03 +01002379 ret = lf_encode_string(tmplog, dst + maxsize,
2380 '#', hdr_encode_map, s->res_cap[hdr], tmp);
William Lallemand1d705562012-03-12 12:46:41 +01002381 if (ret == NULL || *ret != '\0')
William Lallemand51b5dca2012-03-26 17:52:55 +02002382 goto out;
William Lallemand1d705562012-03-12 12:46:41 +01002383 tmplog = ret;
William Lallemand51b5dca2012-03-26 17:52:55 +02002384 }
William Lallemandbddd4fd2012-02-27 11:23:10 +01002385 }
2386 LOGCHAR('}');
2387 last_isspace = 0;
2388 if (tmp->options & LOG_OPT_QUOTE)
2389 LOGCHAR('"');
2390 }
William Lallemandbddd4fd2012-02-27 11:23:10 +01002391 break;
2392
William Lallemand1d705562012-03-12 12:46:41 +01002393 case LOG_FMT_HDRRESPONSLIST: // %hsl
William Lallemandbddd4fd2012-02-27 11:23:10 +01002394 /* response header list */
Willy Tarreaud4f91662018-09-05 15:28:07 +02002395 if (fe->nb_rsp_cap && s && s->res_cap) {
William Lallemandbddd4fd2012-02-27 11:23:10 +01002396 for (hdr = 0; hdr < fe->nb_rsp_cap; hdr++) {
2397 if (hdr > 0)
2398 LOGCHAR(' ');
2399 if (tmp->options & LOG_OPT_QUOTE)
2400 LOGCHAR('"');
Willy Tarreaucb7dd012015-04-03 22:16:32 +02002401 if (s->res_cap[hdr] != NULL) {
Dragan Dosen835b9212016-02-12 13:23:03 +01002402 ret = lf_encode_string(tmplog, dst + maxsize,
2403 '#', hdr_encode_map, s->res_cap[hdr], tmp);
William Lallemand1d705562012-03-12 12:46:41 +01002404 if (ret == NULL || *ret != '\0')
William Lallemand51b5dca2012-03-26 17:52:55 +02002405 goto out;
William Lallemand1d705562012-03-12 12:46:41 +01002406 tmplog = ret;
William Lallemandbddd4fd2012-02-27 11:23:10 +01002407 } else if (!(tmp->options & LOG_OPT_QUOTE))
2408 LOGCHAR('-');
2409 if (tmp->options & LOG_OPT_QUOTE)
2410 LOGCHAR('"');
William Lallemandbddd4fd2012-02-27 11:23:10 +01002411 last_isspace = 0;
2412 }
2413 }
2414 break;
2415
William Lallemand1d705562012-03-12 12:46:41 +01002416 case LOG_FMT_REQ: // %r
William Lallemandbddd4fd2012-02-27 11:23:10 +01002417 /* Request */
2418 if (tmp->options & LOG_OPT_QUOTE)
2419 LOGCHAR('"');
Willy Tarreau57bc8912016-04-25 17:09:40 +02002420 uri = txn && txn->uri ? txn->uri : "<BADREQ>";
Dragan Dosen835b9212016-02-12 13:23:03 +01002421 ret = lf_encode_string(tmplog, dst + maxsize,
2422 '#', url_encode_map, uri, tmp);
William Lallemand1d705562012-03-12 12:46:41 +01002423 if (ret == NULL || *ret != '\0')
William Lallemand51b5dca2012-03-26 17:52:55 +02002424 goto out;
William Lallemand1d705562012-03-12 12:46:41 +01002425 tmplog = ret;
William Lallemandbddd4fd2012-02-27 11:23:10 +01002426 if (tmp->options & LOG_OPT_QUOTE)
2427 LOGCHAR('"');
William Lallemandbddd4fd2012-02-27 11:23:10 +01002428 last_isspace = 0;
2429 break;
William Lallemand5f232402012-04-05 18:02:55 +02002430
Andrew Hayworth0ebc55f2015-04-27 21:37:03 +00002431 case LOG_FMT_HTTP_PATH: // %HP
Willy Tarreau57bc8912016-04-25 17:09:40 +02002432 uri = txn && txn->uri ? txn->uri : "<BADREQ>";
Andrew Hayworth0ebc55f2015-04-27 21:37:03 +00002433
Willy Tarreaub7636d12015-06-17 19:58:02 +02002434 if (tmp->options & LOG_OPT_QUOTE)
Andrew Hayworth0ebc55f2015-04-27 21:37:03 +00002435 LOGCHAR('"');
2436
2437 end = uri + strlen(uri);
2438 // look for the first whitespace character
2439 while (uri < end && !HTTP_IS_SPHT(*uri))
2440 uri++;
2441
2442 // keep advancing past multiple spaces
2443 while (uri < end && HTTP_IS_SPHT(*uri)) {
2444 uri++; nspaces++;
2445 }
2446
2447 // look for first space or question mark after url
2448 spc = uri;
2449 while (spc < end && *spc != '?' && !HTTP_IS_SPHT(*spc))
2450 spc++;
2451
Nenad Merdanovic54e439f2016-04-26 01:39:02 +02002452 if (!txn || !txn->uri || nspaces == 0) {
Willy Tarreau843b7cb2018-07-13 10:54:26 +02002453 chunk.area = "<BADREQ>";
2454 chunk.data = strlen("<BADREQ>");
Andrew Hayworth0ebc55f2015-04-27 21:37:03 +00002455 } else {
Willy Tarreau843b7cb2018-07-13 10:54:26 +02002456 chunk.area = uri;
2457 chunk.data = spc - uri;
Andrew Hayworth0ebc55f2015-04-27 21:37:03 +00002458 }
2459
Dragan Dosen835b9212016-02-12 13:23:03 +01002460 ret = lf_encode_chunk(tmplog, dst + maxsize, '#', url_encode_map, &chunk, tmp);
Andrew Hayworth0ebc55f2015-04-27 21:37:03 +00002461 if (ret == NULL || *ret != '\0')
2462 goto out;
2463
2464 tmplog = ret;
Willy Tarreaub7636d12015-06-17 19:58:02 +02002465 if (tmp->options & LOG_OPT_QUOTE)
Andrew Hayworth0ebc55f2015-04-27 21:37:03 +00002466 LOGCHAR('"');
2467
2468 last_isspace = 0;
2469 break;
2470
Andrew Hayworthe63ac872015-07-31 16:14:16 +00002471 case LOG_FMT_HTTP_QUERY: // %HQ
2472 if (tmp->options & LOG_OPT_QUOTE)
2473 LOGCHAR('"');
2474
Willy Tarreau57bc8912016-04-25 17:09:40 +02002475 if (!txn || !txn->uri) {
Willy Tarreau843b7cb2018-07-13 10:54:26 +02002476 chunk.area = "<BADREQ>";
2477 chunk.data = strlen("<BADREQ>");
Andrew Hayworthe63ac872015-07-31 16:14:16 +00002478 } else {
2479 uri = txn->uri;
2480 end = uri + strlen(uri);
2481 // look for the first question mark
2482 while (uri < end && *uri != '?')
2483 uri++;
2484
2485 qmark = uri;
2486 // look for first space or question mark after url
2487 while (uri < end && !HTTP_IS_SPHT(*uri))
2488 uri++;
2489
Willy Tarreau843b7cb2018-07-13 10:54:26 +02002490 chunk.area = qmark;
2491 chunk.data = uri - qmark;
Andrew Hayworthe63ac872015-07-31 16:14:16 +00002492 }
2493
Dragan Dosen835b9212016-02-12 13:23:03 +01002494 ret = lf_encode_chunk(tmplog, dst + maxsize, '#', url_encode_map, &chunk, tmp);
Andrew Hayworthe63ac872015-07-31 16:14:16 +00002495 if (ret == NULL || *ret != '\0')
2496 goto out;
2497
2498 tmplog = ret;
2499 if (tmp->options & LOG_OPT_QUOTE)
2500 LOGCHAR('"');
2501
2502 last_isspace = 0;
2503 break;
2504
Andrew Hayworth0ebc55f2015-04-27 21:37:03 +00002505 case LOG_FMT_HTTP_URI: // %HU
Willy Tarreau57bc8912016-04-25 17:09:40 +02002506 uri = txn && txn->uri ? txn->uri : "<BADREQ>";
Andrew Hayworth0ebc55f2015-04-27 21:37:03 +00002507
Willy Tarreaub7636d12015-06-17 19:58:02 +02002508 if (tmp->options & LOG_OPT_QUOTE)
Andrew Hayworth0ebc55f2015-04-27 21:37:03 +00002509 LOGCHAR('"');
2510
2511 end = uri + strlen(uri);
2512 // look for the first whitespace character
2513 while (uri < end && !HTTP_IS_SPHT(*uri))
2514 uri++;
2515
2516 // keep advancing past multiple spaces
2517 while (uri < end && HTTP_IS_SPHT(*uri)) {
2518 uri++; nspaces++;
2519 }
2520
2521 // look for first space after url
2522 spc = uri;
2523 while (spc < end && !HTTP_IS_SPHT(*spc))
2524 spc++;
2525
Willy Tarreau57bc8912016-04-25 17:09:40 +02002526 if (!txn || !txn->uri || nspaces == 0) {
Willy Tarreau843b7cb2018-07-13 10:54:26 +02002527 chunk.area = "<BADREQ>";
2528 chunk.data = strlen("<BADREQ>");
Andrew Hayworth0ebc55f2015-04-27 21:37:03 +00002529 } else {
Willy Tarreau843b7cb2018-07-13 10:54:26 +02002530 chunk.area = uri;
2531 chunk.data = spc - uri;
Andrew Hayworth0ebc55f2015-04-27 21:37:03 +00002532 }
2533
Dragan Dosen835b9212016-02-12 13:23:03 +01002534 ret = lf_encode_chunk(tmplog, dst + maxsize, '#', url_encode_map, &chunk, tmp);
Andrew Hayworth0ebc55f2015-04-27 21:37:03 +00002535 if (ret == NULL || *ret != '\0')
2536 goto out;
2537
2538 tmplog = ret;
Willy Tarreaub7636d12015-06-17 19:58:02 +02002539 if (tmp->options & LOG_OPT_QUOTE)
Andrew Hayworth0ebc55f2015-04-27 21:37:03 +00002540 LOGCHAR('"');
2541
2542 last_isspace = 0;
2543 break;
2544
2545 case LOG_FMT_HTTP_METHOD: // %HM
Willy Tarreau57bc8912016-04-25 17:09:40 +02002546 uri = txn && txn->uri ? txn->uri : "<BADREQ>";
Willy Tarreaub7636d12015-06-17 19:58:02 +02002547 if (tmp->options & LOG_OPT_QUOTE)
Andrew Hayworth0ebc55f2015-04-27 21:37:03 +00002548 LOGCHAR('"');
2549
2550 end = uri + strlen(uri);
2551 // look for the first whitespace character
2552 spc = uri;
2553 while (spc < end && !HTTP_IS_SPHT(*spc))
2554 spc++;
2555
2556 if (spc == end) { // odd case, we have txn->uri, but we only got a verb
Willy Tarreau843b7cb2018-07-13 10:54:26 +02002557 chunk.area = "<BADREQ>";
2558 chunk.data = strlen("<BADREQ>");
Andrew Hayworth0ebc55f2015-04-27 21:37:03 +00002559 } else {
Willy Tarreau843b7cb2018-07-13 10:54:26 +02002560 chunk.area = uri;
2561 chunk.data = spc - uri;
Andrew Hayworth0ebc55f2015-04-27 21:37:03 +00002562 }
2563
Dragan Dosen835b9212016-02-12 13:23:03 +01002564 ret = lf_encode_chunk(tmplog, dst + maxsize, '#', url_encode_map, &chunk, tmp);
Andrew Hayworth0ebc55f2015-04-27 21:37:03 +00002565 if (ret == NULL || *ret != '\0')
2566 goto out;
2567
2568 tmplog = ret;
Willy Tarreaub7636d12015-06-17 19:58:02 +02002569 if (tmp->options & LOG_OPT_QUOTE)
Andrew Hayworth0ebc55f2015-04-27 21:37:03 +00002570 LOGCHAR('"');
2571
2572 last_isspace = 0;
2573 break;
2574
2575 case LOG_FMT_HTTP_VERSION: // %HV
Willy Tarreau57bc8912016-04-25 17:09:40 +02002576 uri = txn && txn->uri ? txn->uri : "<BADREQ>";
Willy Tarreaub7636d12015-06-17 19:58:02 +02002577 if (tmp->options & LOG_OPT_QUOTE)
Andrew Hayworth0ebc55f2015-04-27 21:37:03 +00002578 LOGCHAR('"');
2579
2580 end = uri + strlen(uri);
2581 // look for the first whitespace character
2582 while (uri < end && !HTTP_IS_SPHT(*uri))
2583 uri++;
2584
2585 // keep advancing past multiple spaces
2586 while (uri < end && HTTP_IS_SPHT(*uri)) {
2587 uri++; nspaces++;
2588 }
2589
2590 // look for the next whitespace character
2591 while (uri < end && !HTTP_IS_SPHT(*uri))
2592 uri++;
2593
2594 // keep advancing past multiple spaces
2595 while (uri < end && HTTP_IS_SPHT(*uri))
2596 uri++;
2597
Willy Tarreau57bc8912016-04-25 17:09:40 +02002598 if (!txn || !txn->uri || nspaces == 0) {
Willy Tarreau843b7cb2018-07-13 10:54:26 +02002599 chunk.area = "<BADREQ>";
2600 chunk.data = strlen("<BADREQ>");
Andrew Hayworth0ebc55f2015-04-27 21:37:03 +00002601 } else if (uri == end) {
Willy Tarreau843b7cb2018-07-13 10:54:26 +02002602 chunk.area = "HTTP/0.9";
2603 chunk.data = strlen("HTTP/0.9");
Andrew Hayworth0ebc55f2015-04-27 21:37:03 +00002604 } else {
Willy Tarreau843b7cb2018-07-13 10:54:26 +02002605 chunk.area = uri;
2606 chunk.data = end - uri;
Andrew Hayworth0ebc55f2015-04-27 21:37:03 +00002607 }
2608
Dragan Dosen835b9212016-02-12 13:23:03 +01002609 ret = lf_encode_chunk(tmplog, dst + maxsize, '#', url_encode_map, &chunk, tmp);
Andrew Hayworth0ebc55f2015-04-27 21:37:03 +00002610 if (ret == NULL || *ret != '\0')
2611 goto out;
2612
2613 tmplog = ret;
Willy Tarreaub7636d12015-06-17 19:58:02 +02002614 if (tmp->options & LOG_OPT_QUOTE)
Andrew Hayworth0ebc55f2015-04-27 21:37:03 +00002615 LOGCHAR('"');
2616
2617 last_isspace = 0;
2618 break;
2619
William Lallemand5f232402012-04-05 18:02:55 +02002620 case LOG_FMT_COUNTER: // %rt
2621 if (tmp->options & LOG_OPT_HEXA) {
Willy Tarreau5cacab62018-09-05 15:52:59 +02002622 iret = snprintf(tmplog, dst + maxsize - tmplog, "%04X", uniq_id);
William Lallemand5f232402012-04-05 18:02:55 +02002623 if (iret < 0 || iret > dst + maxsize - tmplog)
2624 goto out;
2625 last_isspace = 0;
2626 tmplog += iret;
2627 } else {
Willy Tarreau5cacab62018-09-05 15:52:59 +02002628 ret = ltoa_o(uniq_id, tmplog, dst + maxsize - tmplog);
William Lallemand5f232402012-04-05 18:02:55 +02002629 if (ret == NULL)
2630 goto out;
2631 tmplog = ret;
2632 last_isspace = 0;
2633 }
2634 break;
2635
Willy Tarreau7346acb2014-08-28 15:03:15 +02002636 case LOG_FMT_LOGCNT: // %lc
2637 if (tmp->options & LOG_OPT_HEXA) {
Willy Tarreaue36cbcb2015-04-03 15:40:56 +02002638 iret = snprintf(tmplog, dst + maxsize - tmplog, "%04X", fe->log_count);
Willy Tarreau7346acb2014-08-28 15:03:15 +02002639 if (iret < 0 || iret > dst + maxsize - tmplog)
2640 goto out;
2641 last_isspace = 0;
2642 tmplog += iret;
2643 } else {
Willy Tarreaue36cbcb2015-04-03 15:40:56 +02002644 ret = ultoa_o(fe->log_count, tmplog, dst + maxsize - tmplog);
Willy Tarreau7346acb2014-08-28 15:03:15 +02002645 if (ret == NULL)
2646 goto out;
2647 tmplog = ret;
2648 last_isspace = 0;
2649 }
2650 break;
2651
William Lallemand5f232402012-04-05 18:02:55 +02002652 case LOG_FMT_HOSTNAME: // %H
2653 src = hostname;
2654 ret = lf_text(tmplog, src, dst + maxsize - tmplog, tmp);
2655 if (ret == NULL)
2656 goto out;
2657 tmplog = ret;
2658 last_isspace = 0;
2659 break;
2660
2661 case LOG_FMT_PID: // %pid
2662 if (tmp->options & LOG_OPT_HEXA) {
2663 iret = snprintf(tmplog, dst + maxsize - tmplog, "%04X", pid);
2664 if (iret < 0 || iret > dst + maxsize - tmplog)
2665 goto out;
2666 last_isspace = 0;
2667 tmplog += iret;
2668 } else {
2669 ret = ltoa_o(pid, tmplog, dst + maxsize - tmplog);
2670 if (ret == NULL)
2671 goto out;
2672 tmplog = ret;
2673 last_isspace = 0;
2674 }
2675 break;
William Lallemanda73203e2012-03-12 12:48:57 +01002676
2677 case LOG_FMT_UNIQUEID: // %ID
William Lallemand5b7ea3a2013-08-28 15:44:19 +02002678 ret = NULL;
Willy Tarreau02fdf4f2018-09-05 15:49:01 +02002679 src = s ? s->unique_id : NULL;
Thierry FOURNIER1be69102014-04-15 01:38:48 +02002680 ret = lf_text(tmplog, src, maxsize - (tmplog - dst), tmp);
William Lallemanda73203e2012-03-12 12:48:57 +01002681 if (ret == NULL)
2682 goto out;
2683 tmplog = ret;
2684 last_isspace = 0;
2685 break;
2686
William Lallemandbddd4fd2012-02-27 11:23:10 +01002687 }
2688 }
2689
2690out:
William Lallemand1d705562012-03-12 12:46:41 +01002691 /* *tmplog is a unused character */
2692 *tmplog = '\0';
Willy Tarreaudf974472012-12-28 02:44:01 +01002693 return tmplog - dst;
William Lallemandbddd4fd2012-02-27 11:23:10 +01002694
Willy Tarreaubaaee002006-06-26 02:48:02 +02002695}
2696
William Lallemand1d705562012-03-12 12:46:41 +01002697/*
Willy Tarreau87b09662015-04-03 00:22:06 +02002698 * send a log for the stream when we have enough info about it.
William Lallemand1d705562012-03-12 12:46:41 +01002699 * Will not log if the frontend has no log defined.
2700 */
Willy Tarreau87b09662015-04-03 00:22:06 +02002701void strm_log(struct stream *s)
William Lallemand1d705562012-03-12 12:46:41 +01002702{
Willy Tarreaue36cbcb2015-04-03 15:40:56 +02002703 struct session *sess = s->sess;
William Lallemand1d705562012-03-12 12:46:41 +01002704 int size, err, level;
Dragan Dosen0b85ece2015-09-25 19:17:44 +02002705 int sd_size = 0;
William Lallemand1d705562012-03-12 12:46:41 +01002706
2707 /* if we don't want to log normal traffic, return now */
Willy Tarreaue7dff022015-04-03 01:14:29 +02002708 err = (s->flags & SF_REDISP) ||
2709 ((s->flags & SF_ERR_MASK) > SF_ERR_LOCAL) ||
2710 (((s->flags & SF_ERR_MASK) == SF_ERR_NONE) &&
Willy Tarreau350f4872014-11-28 14:42:25 +01002711 (s->si[1].conn_retries != s->be->conn_retries)) ||
Willy Tarreaueee5b512015-04-03 23:46:31 +02002712 ((sess->fe->mode == PR_MODE_HTTP) && s->txn && s->txn->status >= 500);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002713
Willy Tarreaue36cbcb2015-04-03 15:40:56 +02002714 if (!err && (sess->fe->options2 & PR_O2_NOLOGNORM))
William Lallemand1d705562012-03-12 12:46:41 +01002715 return;
William Lallemandbddd4fd2012-02-27 11:23:10 +01002716
Willy Tarreaue36cbcb2015-04-03 15:40:56 +02002717 if (LIST_ISEMPTY(&sess->fe->logsrvs))
William Lallemand1d705562012-03-12 12:46:41 +01002718 return;
William Lallemandbddd4fd2012-02-27 11:23:10 +01002719
Willy Tarreauabcd5142013-06-11 17:18:02 +02002720 if (s->logs.level) { /* loglevel was overridden */
2721 if (s->logs.level == -1) {
2722 s->logs.logwait = 0; /* logs disabled */
2723 return;
2724 }
2725 level = s->logs.level - 1;
2726 }
2727 else {
2728 level = LOG_INFO;
Willy Tarreaue36cbcb2015-04-03 15:40:56 +02002729 if (err && (sess->fe->options2 & PR_O2_LOGERRORS))
Willy Tarreauabcd5142013-06-11 17:18:02 +02002730 level = LOG_ERR;
2731 }
William Lallemand1d705562012-03-12 12:46:41 +01002732
William Lallemand5b7ea3a2013-08-28 15:44:19 +02002733 /* if unique-id was not generated */
Willy Tarreaue36cbcb2015-04-03 15:40:56 +02002734 if (!s->unique_id && !LIST_ISEMPTY(&sess->fe->format_unique_id)) {
Willy Tarreaubafbe012017-11-24 17:34:44 +01002735 if ((s->unique_id = pool_alloc(pool_head_uniqueid)) != NULL)
Willy Tarreaue36cbcb2015-04-03 15:40:56 +02002736 build_logline(s, s->unique_id, UNIQUEID_LEN, &sess->fe->format_unique_id);
William Lallemand5b7ea3a2013-08-28 15:44:19 +02002737 }
2738
Dragan Dosen0b85ece2015-09-25 19:17:44 +02002739 if (!LIST_ISEMPTY(&sess->fe->logformat_sd)) {
2740 sd_size = build_logline(s, logline_rfc5424, global.max_syslog_len,
2741 &sess->fe->logformat_sd);
2742 }
2743
Dragan Dosen59cee972015-09-19 22:09:02 +02002744 size = build_logline(s, logline, global.max_syslog_len, &sess->fe->logformat);
William Lallemand1d705562012-03-12 12:46:41 +01002745 if (size > 0) {
Christopher Fauletff8abcd2017-06-02 15:33:24 +02002746 HA_ATOMIC_ADD(&sess->fe->log_count, 1);
Dragan Dosen0b85ece2015-09-25 19:17:44 +02002747 __send_log(sess->fe, level, logline, size + 1, logline_rfc5424, sd_size);
William Lallemand1d705562012-03-12 12:46:41 +01002748 s->logs.logwait = 0;
2749 }
2750}
William Lallemandbddd4fd2012-02-27 11:23:10 +01002751
Willy Tarreau53839352018-09-05 19:51:10 +02002752/*
2753 * send a minimalist log for the session. Will not log if the frontend has no
2754 * log defined. It is assumed that this is only used to report anomalies that
2755 * cannot lead to the creation of a regular stream. Because of this the log
2756 * level is LOG_INFO or LOG_ERR depending on the "log-separate-error" setting
2757 * in the frontend. The caller must simply know that it should not call this
Willy Tarreau9fa267d2018-10-05 10:22:27 +02002758 * function to report unimportant events. It is safe to call this function with
2759 * sess==NULL (will not do anything).
Willy Tarreau53839352018-09-05 19:51:10 +02002760 */
2761void sess_log(struct session *sess)
2762{
2763 int size, level;
2764 int sd_size = 0;
2765
Willy Tarreau9fa267d2018-10-05 10:22:27 +02002766 if (!sess)
2767 return;
2768
Willy Tarreau53839352018-09-05 19:51:10 +02002769 if (LIST_ISEMPTY(&sess->fe->logsrvs))
2770 return;
2771
2772 level = LOG_INFO;
2773 if (sess->fe->options2 & PR_O2_LOGERRORS)
2774 level = LOG_ERR;
2775
2776 if (!LIST_ISEMPTY(&sess->fe->logformat_sd)) {
2777 sd_size = sess_build_logline(sess, NULL,
2778 logline_rfc5424, global.max_syslog_len,
2779 &sess->fe->logformat_sd);
2780 }
2781
2782 size = sess_build_logline(sess, NULL, logline, global.max_syslog_len, &sess->fe->logformat);
2783 if (size > 0) {
2784 HA_ATOMIC_ADD(&sess->fe->log_count, 1);
2785 __send_log(sess->fe, level, logline, size + 1, logline_rfc5424, sd_size);
2786 }
2787}
2788
Christopher Fauletc1b730a2017-10-24 12:00:51 +02002789static int cli_io_handler_show_startup_logs(struct appctx *appctx)
2790{
2791 struct stream_interface *si = appctx->owner;
2792 const char *msg = (startup_logs ? startup_logs : "No startup alerts/warnings.\n");
2793
2794 if (ci_putstr(si_ic(si), msg) == -1) {
Willy Tarreaudb398432018-11-15 11:08:52 +01002795 si_rx_room_blk(si);
Christopher Fauletc1b730a2017-10-24 12:00:51 +02002796 return 0;
2797 }
2798 return 1;
2799}
2800
2801/* register cli keywords */
2802static struct cli_kw_list cli_kws = {{ },{
2803 { { "show", "startup-logs", NULL },
2804 "show startup-logs : report logs emitted during HAProxy startup",
2805 NULL, cli_io_handler_show_startup_logs },
2806 {{},}
2807}};
2808
2809__attribute__((constructor))
2810static void __log_init(void)
2811{
Christopher Fauletcd7879a2017-10-27 13:53:47 +02002812 hap_register_per_thread_init(init_log_buffers_per_thread);
2813 hap_register_per_thread_deinit(deinit_log_buffers_per_thread);
Christopher Fauletc1b730a2017-10-24 12:00:51 +02002814 cli_register_kw(&cli_kws);
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 */