blob: ae4121db8aa295fe9fe02563522947643558c5d8 [file] [log] [blame]
Willy Tarreaubaaee002006-06-26 02:48:02 +02001/*
2 * General logging functions.
3 *
Willy Tarreaub7f694f2008-06-22 17:18:02 +02004 * Copyright 2000-2008 Willy Tarreau <w@1wt.eu>
Willy Tarreaubaaee002006-06-26 02:48:02 +02005 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License
8 * as published by the Free Software Foundation; either version
9 * 2 of the License, or (at your option) any later version.
10 *
11 */
12
Willy Tarreau8a3f52f2012-12-20 21:23:42 +010013#include <ctype.h>
Willy Tarreauc8f24f82007-11-30 18:38:35 +010014#include <fcntl.h>
Willy Tarreaubaaee002006-06-26 02:48:02 +020015#include <stdarg.h>
16#include <stdio.h>
17#include <stdlib.h>
18#include <string.h>
19#include <syslog.h>
20#include <time.h>
21#include <unistd.h>
Robert Tsai81ae1952007-12-05 10:47:29 +010022#include <errno.h>
Willy Tarreaubaaee002006-06-26 02:48:02 +020023
24#include <sys/time.h>
Willy Tarreau077edcb2016-08-10 18:30:56 +020025#include <sys/uio.h>
Willy Tarreaubaaee002006-06-26 02:48:02 +020026
Willy Tarreaue3ba5f02006-06-29 18:54:54 +020027#include <common/config.h>
Willy Tarreaud6d06902009-08-19 11:22:33 +020028#include <common/compat.h>
Willy Tarreau0108d902018-11-25 19:14:37 +010029#include <common/initcall.h>
Willy Tarreau2dd0d472006-06-29 17:53:05 +020030#include <common/standard.h>
Willy Tarreaufb278672006-10-15 15:38:50 +020031#include <common/time.h>
Willy Tarreaubaaee002006-06-26 02:48:02 +020032
Christopher Fauletc1b730a2017-10-24 12:00:51 +020033#include <types/cli.h>
Willy Tarreaubaaee002006-06-26 02:48:02 +020034#include <types/global.h>
William Lallemand723b73a2012-02-08 16:37:49 +010035#include <types/log.h>
Willy Tarreauec6c5df2008-07-15 00:22:45 +020036
Christopher Fauletc1b730a2017-10-24 12:00:51 +020037#include <proto/applet.h>
38#include <proto/cli.h>
Willy Tarreaud52a7f82019-08-30 14:05:35 +020039#include <proto/fd.h>
William Lallemand5f232402012-04-05 18:02:55 +020040#include <proto/frontend.h>
Willy Tarreauec6c5df2008-07-15 00:22:45 +020041#include <proto/log.h>
Willy Tarreauc046d162019-08-30 15:24:59 +020042#include <proto/ring.h>
Willy Tarreauc8368452012-12-21 00:09:23 +010043#include <proto/sample.h>
Willy Tarreauc046d162019-08-30 15:24:59 +020044#include <proto/sink.h>
Willy Tarreauc125cef2019-05-10 09:58:43 +020045#include <proto/ssl_sock.h>
Willy Tarreaufb0afa72015-04-03 14:46:27 +020046#include <proto/stream.h>
Willy Tarreau827aee92011-03-10 16:55:02 +010047#include <proto/stream_interface.h>
Willy Tarreaubaaee002006-06-26 02:48:02 +020048
Dragan Dosen43885c72015-10-01 13:18:13 +020049struct log_fmt {
50 char *name;
51 struct {
Willy Tarreau83061a82018-07-13 11:56:34 +020052 struct buffer sep1; /* first pid separator */
53 struct buffer sep2; /* second pid separator */
Dragan Dosen43885c72015-10-01 13:18:13 +020054 } pid;
55};
56
57static const struct log_fmt log_formats[LOG_FORMATS] = {
58 [LOG_FORMAT_RFC3164] = {
59 .name = "rfc3164",
60 .pid = {
Willy Tarreau843b7cb2018-07-13 10:54:26 +020061 .sep1 = { .area = "[", .data = 1 },
62 .sep2 = { .area = "]: ", .data = 3 }
Dragan Dosen43885c72015-10-01 13:18:13 +020063 }
64 },
65 [LOG_FORMAT_RFC5424] = {
66 .name = "rfc5424",
67 .pid = {
Willy Tarreau843b7cb2018-07-13 10:54:26 +020068 .sep1 = { .area = " ", .data = 1 },
69 .sep2 = { .area = " - ", .data = 3 }
Dragan Dosen43885c72015-10-01 13:18:13 +020070 }
Willy Tarreaue8746a02018-11-12 08:45:00 +010071 },
72 [LOG_FORMAT_SHORT] = {
73 .name = "short",
74 .pid = {
75 .sep1 = { .area = "", .data = 0 },
76 .sep2 = { .area = " ", .data = 1 },
77 }
78 },
Willy Tarreauc1b06452018-11-12 11:57:56 +010079 [LOG_FORMAT_RAW] = {
80 .name = "raw",
81 .pid = {
82 .sep1 = { .area = "", .data = 0 },
83 .sep2 = { .area = "", .data = 0 },
84 }
85 },
Dragan Dosen1322d092015-09-22 16:05:32 +020086};
87
Dragan Dosen835b9212016-02-12 13:23:03 +010088/*
89 * This map is used with all the FD_* macros to check whether a particular bit
Willy Tarreau1bfd6022019-06-07 11:10:07 +020090 * is set or not. Each bit represents an ACSII code. ha_bit_set() sets those
91 * bytes which should be escaped. When ha_bit_test() returns non-zero, it means
92 * that the byte should be escaped. Be careful to always pass bytes from 0 to
93 * 255 exclusively to the macros.
Dragan Dosen835b9212016-02-12 13:23:03 +010094 */
Willy Tarreau1bfd6022019-06-07 11:10:07 +020095long rfc5424_escape_map[(256/8) / sizeof(long)];
96long hdr_encode_map[(256/8) / sizeof(long)];
97long url_encode_map[(256/8) / sizeof(long)];
98long http_encode_map[(256/8) / sizeof(long)];
Dragan Dosen835b9212016-02-12 13:23:03 +010099
Dragan Dosen835b9212016-02-12 13:23:03 +0100100
Willy Tarreaubaaee002006-06-26 02:48:02 +0200101const char *log_facilities[NB_LOG_FACILITIES] = {
102 "kern", "user", "mail", "daemon",
103 "auth", "syslog", "lpr", "news",
104 "uucp", "cron", "auth2", "ftp",
105 "ntp", "audit", "alert", "cron2",
106 "local0", "local1", "local2", "local3",
107 "local4", "local5", "local6", "local7"
108};
109
Willy Tarreaubaaee002006-06-26 02:48:02 +0200110const char *log_levels[NB_LOG_LEVELS] = {
111 "emerg", "alert", "crit", "err",
112 "warning", "notice", "info", "debug"
113};
114
Willy Tarreau570f2212013-06-10 16:42:09 +0200115const 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 +0200116const char sess_fin_state[8] = "-RCHDLQT"; /* cliRequest, srvConnect, srvHeader, Data, Last, Queue, Tarpit */
Willy Tarreaubaaee002006-06-26 02:48:02 +0200117
William Lallemand723b73a2012-02-08 16:37:49 +0100118
119/* log_format */
120struct logformat_type {
121 char *name;
122 int type;
William Lallemandbddd4fd2012-02-27 11:23:10 +0100123 int mode;
William Lallemand5e19a282012-04-02 16:22:10 +0200124 int lw; /* logwait bitsfield */
William Lallemandb7ff6a32012-03-02 14:35:21 +0100125 int (*config_callback)(struct logformat_node *node, struct proxy *curproxy);
Willy Tarreau2beef582012-12-20 17:22:52 +0100126 const char *replace_by; /* new option to use instead of old one */
William Lallemand723b73a2012-02-08 16:37:49 +0100127};
128
William Lallemandb7ff6a32012-03-02 14:35:21 +0100129int prepare_addrsource(struct logformat_node *node, struct proxy *curproxy);
130
William Lallemand723b73a2012-02-08 16:37:49 +0100131/* log_format variable names */
132static const struct logformat_type logformat_keywords[] = {
William Lallemand5e19a282012-04-02 16:22:10 +0200133 { "o", LOG_FMT_GLOBAL, PR_MODE_TCP, 0, NULL }, /* global option */
Willy Tarreau2beef582012-12-20 17:22:52 +0100134
135 /* please keep these lines sorted ! */
136 { "B", LOG_FMT_BYTES, PR_MODE_TCP, LW_BYTES, NULL }, /* bytes from server to client */
137 { "CC", LOG_FMT_CCLIENT, PR_MODE_HTTP, LW_REQHDR, NULL }, /* client cookie */
138 { "CS", LOG_FMT_CSERVER, PR_MODE_HTTP, LW_RSPHDR, NULL }, /* server cookie */
139 { "H", LOG_FMT_HOSTNAME, PR_MODE_TCP, LW_INIT, NULL }, /* Hostname */
140 { "ID", LOG_FMT_UNIQUEID, PR_MODE_HTTP, LW_BYTES, NULL }, /* Unique ID */
Willy Tarreau4bf99632014-06-13 12:21:40 +0200141 { "ST", LOG_FMT_STATUS, PR_MODE_TCP, LW_RESP, NULL }, /* status code */
William Lallemand5e19a282012-04-02 16:22:10 +0200142 { "T", LOG_FMT_DATEGMT, PR_MODE_TCP, LW_INIT, NULL }, /* date GMT */
Thierry FOURNIER / OZON.IO4cac3592016-07-28 17:19:45 +0200143 { "Ta", LOG_FMT_Ta, PR_MODE_HTTP, LW_BYTES, NULL }, /* Time active (tr to end) */
Willy Tarreau2beef582012-12-20 17:22:52 +0100144 { "Tc", LOG_FMT_TC, PR_MODE_TCP, LW_BYTES, NULL }, /* Tc */
Thierry FOURNIER / OZON.IO4cac3592016-07-28 17:19:45 +0200145 { "Th", LOG_FMT_Th, PR_MODE_TCP, LW_BYTES, NULL }, /* Time handshake */
146 { "Ti", LOG_FMT_Ti, PR_MODE_HTTP, LW_BYTES, NULL }, /* Time idle */
147 { "Tl", LOG_FMT_DATELOCAL, PR_MODE_TCP, LW_INIT, NULL }, /* date local timezone */
148 { "Tq", LOG_FMT_TQ, PR_MODE_HTTP, LW_BYTES, NULL }, /* Tq=Th+Ti+TR */
149 { "Tr", LOG_FMT_Tr, PR_MODE_HTTP, LW_BYTES, NULL }, /* Tr */
150 { "TR", LOG_FMT_TR, PR_MODE_HTTP, LW_BYTES, NULL }, /* Time to receive a valid request */
Willy Tarreau27b639d2016-05-17 17:55:27 +0200151 { "Td", LOG_FMT_TD, PR_MODE_TCP, LW_BYTES, NULL }, /* Td = Tt - (Tq + Tw + Tc + Tr) */
Willy Tarreau2beef582012-12-20 17:22:52 +0100152 { "Ts", LOG_FMT_TS, PR_MODE_TCP, LW_INIT, NULL }, /* timestamp GMT */
William Lallemand5e19a282012-04-02 16:22:10 +0200153 { "Tt", LOG_FMT_TT, PR_MODE_TCP, LW_BYTES, NULL }, /* Tt */
Willy Tarreau2beef582012-12-20 17:22:52 +0100154 { "Tw", LOG_FMT_TW, PR_MODE_TCP, LW_BYTES, NULL }, /* Tw */
155 { "U", LOG_FMT_BYTES_UP, PR_MODE_TCP, LW_BYTES, NULL }, /* bytes from client to server */
William Lallemand5e19a282012-04-02 16:22:10 +0200156 { "ac", LOG_FMT_ACTCONN, PR_MODE_TCP, LW_BYTES, NULL }, /* actconn */
Willy Tarreau2beef582012-12-20 17:22:52 +0100157 { "b", LOG_FMT_BACKEND, PR_MODE_TCP, LW_INIT, NULL }, /* backend */
William Lallemand5e19a282012-04-02 16:22:10 +0200158 { "bc", LOG_FMT_BECONN, PR_MODE_TCP, LW_BYTES, NULL }, /* beconn */
Willy Tarreau2beef582012-12-20 17:22:52 +0100159 { "bi", LOG_FMT_BACKENDIP, PR_MODE_TCP, LW_BCKIP, prepare_addrsource }, /* backend source ip */
160 { "bp", LOG_FMT_BACKENDPORT, PR_MODE_TCP, LW_BCKIP, prepare_addrsource }, /* backend source port */
William Lallemand5e19a282012-04-02 16:22:10 +0200161 { "bq", LOG_FMT_BCKQUEUE, PR_MODE_TCP, LW_BYTES, NULL }, /* backend_queue */
Willy Tarreaud02286d2017-06-23 11:23:43 +0200162 { "ci", LOG_FMT_CLIENTIP, PR_MODE_TCP, LW_CLIP | LW_XPRT, NULL }, /* client ip */
163 { "cp", LOG_FMT_CLIENTPORT, PR_MODE_TCP, LW_CLIP | LW_XPRT, NULL }, /* client port */
Willy Tarreau2beef582012-12-20 17:22:52 +0100164 { "f", LOG_FMT_FRONTEND, PR_MODE_TCP, LW_INIT, NULL }, /* frontend */
165 { "fc", LOG_FMT_FECONN, PR_MODE_TCP, LW_BYTES, NULL }, /* feconn */
Willy Tarreaud02286d2017-06-23 11:23:43 +0200166 { "fi", LOG_FMT_FRONTENDIP, PR_MODE_TCP, LW_FRTIP | LW_XPRT, NULL }, /* frontend ip */
167 { "fp", LOG_FMT_FRONTENDPORT, PR_MODE_TCP, LW_FRTIP | LW_XPRT, NULL }, /* frontend port */
Willy Tarreau2beef582012-12-20 17:22:52 +0100168 { "ft", LOG_FMT_FRONTEND_XPRT, PR_MODE_TCP, LW_INIT, NULL }, /* frontend with transport mode */
Willy Tarreaud9ed3d22014-06-13 12:23:06 +0200169 { "hr", LOG_FMT_HDRREQUEST, PR_MODE_TCP, LW_REQHDR, NULL }, /* header request */
170 { "hrl", LOG_FMT_HDRREQUESTLIST, PR_MODE_TCP, LW_REQHDR, NULL }, /* header request list */
171 { "hs", LOG_FMT_HDRRESPONS, PR_MODE_TCP, LW_RSPHDR, NULL }, /* header response */
172 { "hsl", LOG_FMT_HDRRESPONSLIST, PR_MODE_TCP, LW_RSPHDR, NULL }, /* header response list */
Andrew Hayworth0ebc55f2015-04-27 21:37:03 +0000173 { "HM", LOG_FMT_HTTP_METHOD, PR_MODE_HTTP, LW_REQ, NULL }, /* HTTP method */
174 { "HP", LOG_FMT_HTTP_PATH, PR_MODE_HTTP, LW_REQ, NULL }, /* HTTP path */
Andrew Hayworthe63ac872015-07-31 16:14:16 +0000175 { "HQ", LOG_FMT_HTTP_QUERY, PR_MODE_HTTP, LW_REQ, NULL }, /* HTTP query */
Andrew Hayworth0ebc55f2015-04-27 21:37:03 +0000176 { "HU", LOG_FMT_HTTP_URI, PR_MODE_HTTP, LW_REQ, NULL }, /* HTTP full URI */
177 { "HV", LOG_FMT_HTTP_VERSION, PR_MODE_HTTP, LW_REQ, NULL }, /* HTTP version */
Willy Tarreau7346acb2014-08-28 15:03:15 +0200178 { "lc", LOG_FMT_LOGCNT, PR_MODE_TCP, LW_INIT, NULL }, /* log counter */
Willy Tarreau2beef582012-12-20 17:22:52 +0100179 { "ms", LOG_FMT_MS, PR_MODE_TCP, LW_INIT, NULL }, /* accept date millisecond */
William Lallemand5e19a282012-04-02 16:22:10 +0200180 { "pid", LOG_FMT_PID, PR_MODE_TCP, LW_INIT, NULL }, /* log pid */
Willy Tarreau2beef582012-12-20 17:22:52 +0100181 { "r", LOG_FMT_REQ, PR_MODE_HTTP, LW_REQ, NULL }, /* request */
182 { "rc", LOG_FMT_RETRIES, PR_MODE_TCP, LW_BYTES, NULL }, /* retries */
Willy Tarreau1f0da242014-01-25 11:01:50 +0100183 { "rt", LOG_FMT_COUNTER, PR_MODE_TCP, LW_REQ, NULL }, /* request counter (HTTP or TCP session) */
Willy Tarreau2beef582012-12-20 17:22:52 +0100184 { "s", LOG_FMT_SERVER, PR_MODE_TCP, LW_SVID, NULL }, /* server */
185 { "sc", LOG_FMT_SRVCONN, PR_MODE_TCP, LW_BYTES, NULL }, /* srv_conn */
186 { "si", LOG_FMT_SERVERIP, PR_MODE_TCP, LW_SVIP, NULL }, /* server destination ip */
187 { "sp", LOG_FMT_SERVERPORT, PR_MODE_TCP, LW_SVIP, NULL }, /* server destination port */
188 { "sq", LOG_FMT_SRVQUEUE, PR_MODE_TCP, LW_BYTES, NULL }, /* srv_queue */
Willy Tarreauffc3fcd2012-10-12 20:17:54 +0200189 { "sslc", LOG_FMT_SSL_CIPHER, PR_MODE_TCP, LW_XPRT, NULL }, /* client-side SSL ciphers */
190 { "sslv", LOG_FMT_SSL_VERSION, PR_MODE_TCP, LW_XPRT, NULL }, /* client-side SSL protocol version */
Willy Tarreau2beef582012-12-20 17:22:52 +0100191 { "t", LOG_FMT_DATE, PR_MODE_TCP, LW_INIT, NULL }, /* date */
Thierry FOURNIER / OZON.IO4cac3592016-07-28 17:19:45 +0200192 { "tr", LOG_FMT_tr, PR_MODE_HTTP, LW_INIT, NULL }, /* date of start of request */
193 { "trg",LOG_FMT_trg, PR_MODE_HTTP, LW_INIT, NULL }, /* date of start of request, GMT */
194 { "trl",LOG_FMT_trl, PR_MODE_HTTP, LW_INIT, NULL }, /* date of start of request, local */
Willy Tarreau2beef582012-12-20 17:22:52 +0100195 { "ts", LOG_FMT_TERMSTATE, PR_MODE_TCP, LW_BYTES, NULL },/* termination state */
196 { "tsc", LOG_FMT_TERMSTATE_CK, PR_MODE_TCP, LW_INIT, NULL },/* termination state */
197
198 /* The following tags are deprecated and will be removed soon */
199 { "Bi", LOG_FMT_BACKENDIP, PR_MODE_TCP, LW_BCKIP, prepare_addrsource, "bi" }, /* backend source ip */
200 { "Bp", LOG_FMT_BACKENDPORT, PR_MODE_TCP, LW_BCKIP, prepare_addrsource, "bp" }, /* backend source port */
Willy Tarreaud02286d2017-06-23 11:23:43 +0200201 { "Ci", LOG_FMT_CLIENTIP, PR_MODE_TCP, LW_CLIP | LW_XPRT, NULL, "ci" }, /* client ip */
202 { "Cp", LOG_FMT_CLIENTPORT, PR_MODE_TCP, LW_CLIP | LW_XPRT, NULL, "cp" }, /* client port */
203 { "Fi", LOG_FMT_FRONTENDIP, PR_MODE_TCP, LW_FRTIP | LW_XPRT, NULL, "fi" }, /* frontend ip */
204 { "Fp", LOG_FMT_FRONTENDPORT, PR_MODE_TCP, LW_FRTIP | LW_XPRT, NULL, "fp" }, /* frontend port */
Willy Tarreau2beef582012-12-20 17:22:52 +0100205 { "Si", LOG_FMT_SERVERIP, PR_MODE_TCP, LW_SVIP, NULL, "si" }, /* server destination ip */
206 { "Sp", LOG_FMT_SERVERPORT, PR_MODE_TCP, LW_SVIP, NULL, "sp" }, /* server destination port */
207 { "cc", LOG_FMT_CCLIENT, PR_MODE_HTTP, LW_REQHDR, NULL, "CC" }, /* client cookie */
208 { "cs", LOG_FMT_CSERVER, PR_MODE_HTTP, LW_RSPHDR, NULL, "CS" }, /* server cookie */
209 { "st", LOG_FMT_STATUS, PR_MODE_HTTP, LW_RESP, NULL, "ST" }, /* status code */
William Lallemand5e19a282012-04-02 16:22:10 +0200210 { 0, 0, 0, 0, NULL }
William Lallemand723b73a2012-02-08 16:37:49 +0100211};
212
Thierry FOURNIER / OZON.IO4cac3592016-07-28 17:19:45 +0200213char 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
214char 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 +0100215char 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 +0100216char *log_format = NULL;
217
Dragan Dosen0b85ece2015-09-25 19:17:44 +0200218/* Default string used for structured-data part in RFC5424 formatted
219 * syslog messages.
220 */
221char default_rfc5424_sd_log_format[] = "- ";
Dragan Dosen1322d092015-09-22 16:05:32 +0200222
Willy Tarreau13ef7732018-11-12 07:25:28 +0100223/* total number of dropped logs */
224unsigned int dropped_logs = 0;
225
Dragan Dosen1322d092015-09-22 16:05:32 +0200226/* This is a global syslog header, common to all outgoing messages in
227 * RFC3164 format. It begins with time-based part and is updated by
228 * update_log_hdr().
Dragan Dosen59cee972015-09-19 22:09:02 +0200229 */
Christopher Fauletf8188c62017-06-02 16:20:16 +0200230THREAD_LOCAL char *logheader = NULL;
Willy Tarreau55e2f5a2019-05-05 10:11:39 +0200231THREAD_LOCAL char *logheader_end = NULL;
Dragan Dosen59cee972015-09-19 22:09:02 +0200232
Dragan Dosen1322d092015-09-22 16:05:32 +0200233/* This is a global syslog header for messages in RFC5424 format. It is
234 * updated by update_log_hdr_rfc5424().
235 */
Christopher Fauletf8188c62017-06-02 16:20:16 +0200236THREAD_LOCAL char *logheader_rfc5424 = NULL;
Willy Tarreau55e2f5a2019-05-05 10:11:39 +0200237THREAD_LOCAL char *logheader_rfc5424_end = NULL;
Dragan Dosen1322d092015-09-22 16:05:32 +0200238
Dragan Dosen59cee972015-09-19 22:09:02 +0200239/* This is a global syslog message buffer, common to all outgoing
240 * messages. It contains only the data part.
Willy Tarreaub1a2faf2012-03-19 16:51:53 +0100241 */
Christopher Fauletf8188c62017-06-02 16:20:16 +0200242THREAD_LOCAL char *logline = NULL;
Willy Tarreaub1a2faf2012-03-19 16:51:53 +0100243
Dragan Dosen0b85ece2015-09-25 19:17:44 +0200244/* A global syslog message buffer, common to all RFC5424 syslog messages.
245 * Currently, it is used for generating the structured-data part.
246 */
Christopher Fauletf8188c62017-06-02 16:20:16 +0200247THREAD_LOCAL char *logline_rfc5424 = NULL;
Dragan Dosen0b85ece2015-09-25 19:17:44 +0200248
Christopher Fauletd4696382017-10-24 11:44:05 +0200249/* A global buffer used to store all startup alerts/warnings. It will then be
250 * retrieve on the CLI. */
Willy Tarreaua6483992018-12-15 16:55:36 +0100251static char *startup_logs = NULL;
Christopher Fauletd4696382017-10-24 11:44:05 +0200252
William Lallemand723b73a2012-02-08 16:37:49 +0100253struct logformat_var_args {
254 char *name;
255 int mask;
256};
257
258struct logformat_var_args var_args_list[] = {
259// global
260 { "M", LOG_OPT_MANDATORY },
261 { "Q", LOG_OPT_QUOTE },
William Lallemand5f232402012-04-05 18:02:55 +0200262 { "X", LOG_OPT_HEXA },
Dragan Dosen835b9212016-02-12 13:23:03 +0100263 { "E", LOG_OPT_ESC },
William Lallemand723b73a2012-02-08 16:37:49 +0100264 { 0, 0 }
265};
266
Willy Tarreaub1f3af22013-04-12 18:30:32 +0200267/* return the name of the directive used in the current proxy for which we're
268 * currently parsing a header, when it is known.
269 */
270static inline const char *fmt_directive(const struct proxy *curproxy)
271{
Willy Tarreaubf0addb2013-12-02 12:24:54 +0100272 switch (curproxy->conf.args.ctx) {
Willy Tarreau53e1a6d2015-07-09 11:20:00 +0200273 case ARGC_ACL:
274 return "acl";
275 case ARGC_STK:
276 return "stick";
277 case ARGC_TRK:
278 return "track-sc";
279 case ARGC_LOG:
280 return "log-format";
Dragan Dosen0b85ece2015-09-25 19:17:44 +0200281 case ARGC_LOGSD:
282 return "log-format-sd";
Willy Tarreaubf0addb2013-12-02 12:24:54 +0100283 case ARGC_HRQ:
Thierry FOURNIER1c0054f2013-11-20 15:09:52 +0100284 return "http-request";
Willy Tarreaubf0addb2013-12-02 12:24:54 +0100285 case ARGC_HRS:
Thierry FOURNIER1c0054f2013-11-20 15:09:52 +0100286 return "http-response";
Willy Tarreau53e1a6d2015-07-09 11:20:00 +0200287 case ARGC_UIF:
288 return "unique-id-format";
Thierry FOURNIERd18cd0f2013-11-29 12:15:45 +0100289 case ARGC_RDR:
Willy Tarreau53e1a6d2015-07-09 11:20:00 +0200290 return "redirect";
291 case ARGC_CAP:
292 return "capture";
Willy Tarreau28d976d2015-07-09 11:39:33 +0200293 case ARGC_SRV:
294 return "server";
Christopher Fauletf7e4e7e2016-10-27 22:29:49 +0200295 case ARGC_SPOE:
296 return "spoe-message";
Thierry FOURNIER / OZON.IO4ed1c952016-11-24 23:57:54 +0100297 case ARGC_UBK:
298 return "use_backend";
Willy Tarreaubf0addb2013-12-02 12:24:54 +0100299 default:
Willy Tarreau53e1a6d2015-07-09 11:20:00 +0200300 return "undefined(please report this bug)"; /* must never happen */
Willy Tarreaubf0addb2013-12-02 12:24:54 +0100301 }
Willy Tarreaub1f3af22013-04-12 18:30:32 +0200302}
303
William Lallemand723b73a2012-02-08 16:37:49 +0100304/*
William Lallemandb7ff6a32012-03-02 14:35:21 +0100305 * callback used to configure addr source retrieval
306 */
307int prepare_addrsource(struct logformat_node *node, struct proxy *curproxy)
308{
309 curproxy->options2 |= PR_O2_SRC_ADDR;
310
311 return 0;
312}
313
314
315/*
Thierry FOURNIER / OZON.IObca46f02016-11-22 23:13:04 +0100316 * Parse args in a logformat_var. Returns 0 in error
317 * case, otherwise, it returns 1.
William Lallemand723b73a2012-02-08 16:37:49 +0100318 */
Thierry FOURNIER / OZON.IO8a4e4422016-11-23 00:41:28 +0100319int parse_logformat_var_args(char *args, struct logformat_node *node, char **err)
William Lallemand723b73a2012-02-08 16:37:49 +0100320{
321 int i = 0;
322 int end = 0;
323 int flags = 0; // 1 = + 2 = -
324 char *sp = NULL; // start pointer
325
Thierry FOURNIER / OZON.IO8a4e4422016-11-23 00:41:28 +0100326 if (args == NULL) {
327 memprintf(err, "internal error: parse_logformat_var_args() expects non null 'args'");
Thierry FOURNIER / OZON.IObca46f02016-11-22 23:13:04 +0100328 return 0;
Thierry FOURNIER / OZON.IO8a4e4422016-11-23 00:41:28 +0100329 }
William Lallemand723b73a2012-02-08 16:37:49 +0100330
331 while (1) {
332 if (*args == '\0')
333 end = 1;
334
335 if (*args == '+') {
336 // add flag
337 sp = args + 1;
338 flags = 1;
339 }
340 if (*args == '-') {
341 // delete flag
342 sp = args + 1;
343 flags = 2;
344 }
345
346 if (*args == '\0' || *args == ',') {
347 *args = '\0';
Willy Tarreau254d44c2012-12-20 18:19:26 +0100348 for (i = 0; sp && var_args_list[i].name; i++) {
William Lallemand723b73a2012-02-08 16:37:49 +0100349 if (strcmp(sp, var_args_list[i].name) == 0) {
350 if (flags == 1) {
351 node->options |= var_args_list[i].mask;
352 break;
353 } else if (flags == 2) {
354 node->options &= ~var_args_list[i].mask;
355 break;
356 }
357 }
358 }
359 sp = NULL;
360 if (end)
361 break;
362 }
Willy Tarreau254d44c2012-12-20 18:19:26 +0100363 args++;
William Lallemand723b73a2012-02-08 16:37:49 +0100364 }
Thierry FOURNIER / OZON.IObca46f02016-11-22 23:13:04 +0100365 return 1;
William Lallemand723b73a2012-02-08 16:37:49 +0100366}
367
368/*
Willy Tarreau8a3f52f2012-12-20 21:23:42 +0100369 * Parse a variable '%varname' or '%{args}varname' in log-format. The caller
370 * must pass the args part in the <arg> pointer with its length in <arg_len>,
371 * and varname with its length in <var> and <var_len> respectively. <arg> is
372 * ignored when arg_len is 0. Neither <var> nor <var_len> may be null.
Thierry FOURNIER / OZON.IOeca4d952016-11-22 22:06:04 +0100373 * Returns false in error case and err is filled, otherwise returns true.
William Lallemand723b73a2012-02-08 16:37:49 +0100374 */
Thierry FOURNIER / OZON.IO8a4e4422016-11-23 00:41:28 +0100375int 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 +0100376{
Willy Tarreau8a3f52f2012-12-20 21:23:42 +0100377 int j;
Dragan Dosen61302da2019-04-30 00:40:02 +0200378 struct logformat_node *node = NULL;
William Lallemand723b73a2012-02-08 16:37:49 +0100379
Willy Tarreau8a3f52f2012-12-20 21:23:42 +0100380 for (j = 0; logformat_keywords[j].name; j++) { // search a log type
381 if (strlen(logformat_keywords[j].name) == var_len &&
382 strncmp(var, logformat_keywords[j].name, var_len) == 0) {
383 if (logformat_keywords[j].mode != PR_MODE_HTTP || curproxy->mode == PR_MODE_HTTP) {
Vincent Bernat02779b62016-04-03 13:48:43 +0200384 node = calloc(1, sizeof(*node));
Thierry FOURNIER / OZON.IO9cbfef22016-11-22 23:24:10 +0100385 if (!node) {
Thierry FOURNIER / OZON.IO8a4e4422016-11-23 00:41:28 +0100386 memprintf(err, "out of memory error");
Dragan Dosen61302da2019-04-30 00:40:02 +0200387 goto error_free;
Thierry FOURNIER / OZON.IO9cbfef22016-11-22 23:24:10 +0100388 }
Willy Tarreau8a3f52f2012-12-20 21:23:42 +0100389 node->type = logformat_keywords[j].type;
390 node->options = *defoptions;
391 if (arg_len) {
392 node->arg = my_strndup(arg, arg_len);
Thierry FOURNIER / OZON.IO8a4e4422016-11-23 00:41:28 +0100393 if (!parse_logformat_var_args(node->arg, node, err))
Dragan Dosen61302da2019-04-30 00:40:02 +0200394 goto error_free;
Willy Tarreau8a3f52f2012-12-20 21:23:42 +0100395 }
396 if (node->type == LOG_FMT_GLOBAL) {
397 *defoptions = node->options;
398 free(node->arg);
399 free(node);
400 } else {
401 if (logformat_keywords[j].config_callback &&
402 logformat_keywords[j].config_callback(node, curproxy) != 0) {
Dragan Dosen61302da2019-04-30 00:40:02 +0200403 goto error_free;
William Lallemand723b73a2012-02-08 16:37:49 +0100404 }
Willy Tarreau8a3f52f2012-12-20 21:23:42 +0100405 curproxy->to_log |= logformat_keywords[j].lw;
406 LIST_ADDQ(list_format, &node->list);
William Lallemand723b73a2012-02-08 16:37:49 +0100407 }
Willy Tarreau8a3f52f2012-12-20 21:23:42 +0100408 if (logformat_keywords[j].replace_by)
Christopher Faulet767a84b2017-11-24 16:50:31 +0100409 ha_warning("parsing [%s:%d] : deprecated variable '%s' in '%s', please replace it with '%s'.\n",
410 curproxy->conf.args.file, curproxy->conf.args.line,
411 logformat_keywords[j].name, fmt_directive(curproxy), logformat_keywords[j].replace_by);
Thierry FOURNIER / OZON.IOeca4d952016-11-22 22:06:04 +0100412 return 1;
Willy Tarreau8a3f52f2012-12-20 21:23:42 +0100413 } else {
Thierry FOURNIER / OZON.IO8a4e4422016-11-23 00:41:28 +0100414 memprintf(err, "format variable '%s' is reserved for HTTP mode",
415 logformat_keywords[j].name);
Dragan Dosen61302da2019-04-30 00:40:02 +0200416 goto error_free;
William Lallemand723b73a2012-02-08 16:37:49 +0100417 }
William Lallemand723b73a2012-02-08 16:37:49 +0100418 }
419 }
Willy Tarreau8a3f52f2012-12-20 21:23:42 +0100420
421 j = var[var_len];
422 var[var_len] = 0;
Thierry FOURNIER / OZON.IO8a4e4422016-11-23 00:41:28 +0100423 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 +0100424 var[var_len] = j;
Dragan Dosen61302da2019-04-30 00:40:02 +0200425
426 error_free:
427 if (node) {
428 free(node->arg);
429 free(node);
430 }
Thierry FOURNIER / OZON.IOeca4d952016-11-22 22:06:04 +0100431 return 0;
William Lallemand723b73a2012-02-08 16:37:49 +0100432}
433
434/*
435 * push to the logformat linked list
436 *
437 * start: start pointer
438 * end: end text pointer
439 * type: string type
William Lallemand1d705562012-03-12 12:46:41 +0100440 * list_format: destination list
William Lallemand723b73a2012-02-08 16:37:49 +0100441 *
442 * LOG_TEXT: copy chars from start to end excluding end.
443 *
444*/
Thierry FOURNIER / OZON.IO8a4e4422016-11-23 00:41:28 +0100445int add_to_logformat_list(char *start, char *end, int type, struct list *list_format, char **err)
William Lallemand723b73a2012-02-08 16:37:49 +0100446{
447 char *str;
448
Willy Tarreaua3571662012-12-20 21:59:12 +0100449 if (type == LF_TEXT) { /* type text */
Vincent Bernat02779b62016-04-03 13:48:43 +0200450 struct logformat_node *node = calloc(1, sizeof(*node));
Thierry FOURNIER / OZON.IO9cbfef22016-11-22 23:24:10 +0100451 if (!node) {
Thierry FOURNIER / OZON.IO8a4e4422016-11-23 00:41:28 +0100452 memprintf(err, "out of memory error");
Thierry FOURNIER / OZON.IO9cbfef22016-11-22 23:24:10 +0100453 return 0;
454 }
Vincent Bernat02779b62016-04-03 13:48:43 +0200455 str = calloc(1, end - start + 1);
William Lallemand723b73a2012-02-08 16:37:49 +0100456 strncpy(str, start, end - start);
William Lallemand723b73a2012-02-08 16:37:49 +0100457 str[end - start] = '\0';
458 node->arg = str;
William Lallemand1d705562012-03-12 12:46:41 +0100459 node->type = LOG_FMT_TEXT; // type string
460 LIST_ADDQ(list_format, &node->list);
Willy Tarreaua3571662012-12-20 21:59:12 +0100461 } else if (type == LF_SEPARATOR) {
Vincent Bernat02779b62016-04-03 13:48:43 +0200462 struct logformat_node *node = calloc(1, sizeof(*node));
Thierry FOURNIER / OZON.IO9cbfef22016-11-22 23:24:10 +0100463 if (!node) {
Thierry FOURNIER / OZON.IO8a4e4422016-11-23 00:41:28 +0100464 memprintf(err, "out of memory error");
Thierry FOURNIER / OZON.IO9cbfef22016-11-22 23:24:10 +0100465 return 0;
466 }
William Lallemand1d705562012-03-12 12:46:41 +0100467 node->type = LOG_FMT_SEPARATOR;
468 LIST_ADDQ(list_format, &node->list);
William Lallemand723b73a2012-02-08 16:37:49 +0100469 }
Thierry FOURNIER / OZON.IOa2c38d72016-11-22 23:11:21 +0100470 return 1;
William Lallemand723b73a2012-02-08 16:37:49 +0100471}
472
473/*
Willy Tarreauc8368452012-12-21 00:09:23 +0100474 * Parse the sample fetch expression <text> and add a node to <list_format> upon
475 * success. At the moment, sample converters are not yet supported but fetch arguments
Willy Tarreaua4312fa2013-04-02 16:34:32 +0200476 * should work. The curpx->conf.args.ctx must be set by the caller.
Thierry FOURNIER / OZON.IOa2c38d72016-11-22 23:11:21 +0100477 *
478 * In error case, the function returns 0, otherwise it returns 1.
Willy Tarreauc8368452012-12-21 00:09:23 +0100479 */
Thierry FOURNIER / OZON.IO8a4e4422016-11-23 00:41:28 +0100480int 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 +0100481{
482 char *cmd[2];
Dragan Dosen61302da2019-04-30 00:40:02 +0200483 struct sample_expr *expr = NULL;
484 struct logformat_node *node = NULL;
Willy Tarreauc8368452012-12-21 00:09:23 +0100485 int cmd_arg;
486
487 cmd[0] = text;
488 cmd[1] = "";
489 cmd_arg = 0;
490
Thierry FOURNIER / OZON.IO8a4e4422016-11-23 00:41:28 +0100491 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 +0100492 if (!expr) {
Thierry FOURNIER / OZON.IO8a4e4422016-11-23 00:41:28 +0100493 memprintf(err, "failed to parse sample expression <%s> : %s", text, *err);
Dragan Dosen61302da2019-04-30 00:40:02 +0200494 goto error_free;
Willy Tarreauc8368452012-12-21 00:09:23 +0100495 }
496
Vincent Bernat02779b62016-04-03 13:48:43 +0200497 node = calloc(1, sizeof(*node));
Thierry FOURNIER / OZON.IO9cbfef22016-11-22 23:24:10 +0100498 if (!node) {
Thierry FOURNIER / OZON.IO8a4e4422016-11-23 00:41:28 +0100499 memprintf(err, "out of memory error");
Dragan Dosen61302da2019-04-30 00:40:02 +0200500 goto error_free;
Thierry FOURNIER / OZON.IO9cbfef22016-11-22 23:24:10 +0100501 }
Willy Tarreauc8368452012-12-21 00:09:23 +0100502 node->type = LOG_FMT_EXPR;
503 node->expr = expr;
504 node->options = options;
505
506 if (arg_len) {
507 node->arg = my_strndup(arg, arg_len);
Thierry FOURNIER / OZON.IO8a4e4422016-11-23 00:41:28 +0100508 if (!parse_logformat_var_args(node->arg, node, err))
Dragan Dosen61302da2019-04-30 00:40:02 +0200509 goto error_free;
Willy Tarreauc8368452012-12-21 00:09:23 +0100510 }
Willy Tarreau434c57c2013-01-08 01:10:24 +0100511 if (expr->fetch->val & cap & SMP_VAL_REQUEST)
Willy Tarreauc8368452012-12-21 00:09:23 +0100512 node->options |= LOG_OPT_REQ_CAP; /* fetch method is request-compatible */
513
Willy Tarreau434c57c2013-01-08 01:10:24 +0100514 if (expr->fetch->val & cap & SMP_VAL_RESPONSE)
Willy Tarreauc8368452012-12-21 00:09:23 +0100515 node->options |= LOG_OPT_RES_CAP; /* fetch method is response-compatible */
516
Thierry FOURNIER / OZON.IOa2c38d72016-11-22 23:11:21 +0100517 if (!(expr->fetch->val & cap)) {
Thierry FOURNIER / OZON.IO8a4e4422016-11-23 00:41:28 +0100518 memprintf(err, "sample fetch <%s> may not be reliably used here because it needs '%s' which is not available here",
519 text, sample_src_names(expr->fetch->use));
Dragan Dosen61302da2019-04-30 00:40:02 +0200520 goto error_free;
Thierry FOURNIER / OZON.IOa2c38d72016-11-22 23:11:21 +0100521 }
Willy Tarreau434c57c2013-01-08 01:10:24 +0100522
Christopher Faulet711ed6a2019-07-16 14:16:10 +0200523 /* check if we need to allocate an http_txn struct for HTTP parsing */
Willy Tarreauc8368452012-12-21 00:09:23 +0100524 /* Note, we may also need to set curpx->to_log with certain fetches */
Willy Tarreau25320b22013-03-24 07:22:08 +0100525 curpx->http_needed |= !!(expr->fetch->use & SMP_USE_HTTP_ANY);
Willy Tarreauc8368452012-12-21 00:09:23 +0100526
William Lallemand65ad6e12014-01-31 15:08:02 +0100527 /* FIXME: temporary workaround for missing LW_XPRT and LW_REQ flags
528 * needed with some sample fetches (eg: ssl*). We always set it for
529 * now on, but this will leave with sample capabilities soon.
Willy Tarreau1f31c732013-01-10 16:22:27 +0100530 */
531 curpx->to_log |= LW_XPRT;
William Lallemand65ad6e12014-01-31 15:08:02 +0100532 curpx->to_log |= LW_REQ;
Willy Tarreauc8368452012-12-21 00:09:23 +0100533 LIST_ADDQ(list_format, &node->list);
Thierry FOURNIER / OZON.IOa2c38d72016-11-22 23:11:21 +0100534 return 1;
Dragan Dosen61302da2019-04-30 00:40:02 +0200535
536 error_free:
537 release_sample_expr(expr);
538 if (node) {
539 free(node->arg);
540 free(node);
541 }
542 return 0;
Willy Tarreauc8368452012-12-21 00:09:23 +0100543}
544
545/*
William Lallemand723b73a2012-02-08 16:37:49 +0100546 * Parse the log_format string and fill a linked list.
547 * Variable name are preceded by % and composed by characters [a-zA-Z0-9]* : %varname
Willy Tarreaua4312fa2013-04-02 16:34:32 +0200548 * You can set arguments using { } : %{many arguments}varname.
549 * The curproxy->conf.args.ctx must be set by the caller.
William Lallemand1d705562012-03-12 12:46:41 +0100550 *
551 * str: the string to parse
552 * curproxy: the proxy affected
553 * list_format: the destination list
Willy Tarreau6cbbdbf2013-02-05 18:52:25 +0100554 * options: LOG_OPT_* to force on every node
Willy Tarreau434c57c2013-01-08 01:10:24 +0100555 * cap: all SMP_VAL_* flags supported by the consumer
Thierry FOURNIER / OZON.IOa2c38d72016-11-22 23:11:21 +0100556 *
Thierry FOURNIER / OZON.IO8a4e4422016-11-23 00:41:28 +0100557 * The function returns 1 in success case, otherwise, it returns 0 and err is filled.
William Lallemand723b73a2012-02-08 16:37:49 +0100558 */
Thierry FOURNIER / OZON.IO8a4e4422016-11-23 00:41:28 +0100559int 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 +0100560{
Willy Tarreaub83bc1e2012-12-24 12:36:33 +0100561 char *sp, *str, *backfmt; /* start pointer for text parts */
Willy Tarreau8a3f52f2012-12-20 21:23:42 +0100562 char *arg = NULL; /* start pointer for args */
563 char *var = NULL; /* start pointer for vars */
564 int arg_len = 0;
565 int var_len = 0;
566 int cformat; /* current token format */
567 int pformat; /* previous token format */
William Lallemand723b73a2012-02-08 16:37:49 +0100568 struct logformat_node *tmplf, *back;
569
Willy Tarreaub83bc1e2012-12-24 12:36:33 +0100570 sp = str = backfmt = strdup(fmt);
Thierry FOURNIER / OZON.IO9cbfef22016-11-22 23:24:10 +0100571 if (!str) {
Thierry FOURNIER / OZON.IO8a4e4422016-11-23 00:41:28 +0100572 memprintf(err, "out of memory error");
Thierry FOURNIER / OZON.IO9cbfef22016-11-22 23:24:10 +0100573 return 0;
574 }
William Lallemand1dc00ef2012-08-09 16:41:35 +0200575 curproxy->to_log |= LW_INIT;
William Lallemand5e19a282012-04-02 16:22:10 +0200576
William Lallemand723b73a2012-02-08 16:37:49 +0100577 /* flush the list first. */
William Lallemand1d705562012-03-12 12:46:41 +0100578 list_for_each_entry_safe(tmplf, back, list_format, list) {
William Lallemand723b73a2012-02-08 16:37:49 +0100579 LIST_DEL(&tmplf->list);
Dragan Dosen61302da2019-04-30 00:40:02 +0200580 release_sample_expr(tmplf->expr);
581 free(tmplf->arg);
William Lallemand723b73a2012-02-08 16:37:49 +0100582 free(tmplf);
583 }
584
Willy Tarreau8a3f52f2012-12-20 21:23:42 +0100585 for (cformat = LF_INIT; cformat != LF_END; str++) {
William Lallemand723b73a2012-02-08 16:37:49 +0100586 pformat = cformat;
587
Willy Tarreau8a3f52f2012-12-20 21:23:42 +0100588 if (!*str)
589 cformat = LF_END; // preset it to save all states from doing this
William Lallemand723b73a2012-02-08 16:37:49 +0100590
Joseph Herlant85b40592018-11-15 12:10:04 -0800591 /* The principle of the two-step state machine below is to first detect a change, and
Willy Tarreau8a3f52f2012-12-20 21:23:42 +0100592 * second have all common paths processed at one place. The common paths are the ones
593 * encountered in text areas (LF_INIT, LF_TEXT, LF_SEPARATOR) and at the end (LF_END).
594 * We use the common LF_INIT state to dispatch to the different final states.
595 */
596 switch (pformat) {
597 case LF_STARTVAR: // text immediately following a '%'
Willy Tarreauc8368452012-12-21 00:09:23 +0100598 arg = NULL; var = NULL;
Willy Tarreau8a3f52f2012-12-20 21:23:42 +0100599 arg_len = var_len = 0;
600 if (*str == '{') { // optional argument
601 cformat = LF_STARG;
602 arg = str + 1;
William Lallemand723b73a2012-02-08 16:37:49 +0100603 }
Willy Tarreauc8368452012-12-21 00:09:23 +0100604 else if (*str == '[') {
605 cformat = LF_STEXPR;
606 var = str + 1; // store expr in variable name
607 }
Willy Tarreau0f28f822013-12-16 01:38:33 +0100608 else if (isalpha((unsigned char)*str)) { // variable name
William Lallemand723b73a2012-02-08 16:37:49 +0100609 cformat = LF_VAR;
Willy Tarreau8a3f52f2012-12-20 21:23:42 +0100610 var = str;
William Lallemand723b73a2012-02-08 16:37:49 +0100611 }
Willy Tarreau8a3f52f2012-12-20 21:23:42 +0100612 else if (*str == '%')
613 cformat = LF_TEXT; // convert this character to a litteral (useful for '%')
Willy Tarreau0f28f822013-12-16 01:38:33 +0100614 else if (isdigit((unsigned char)*str) || *str == ' ' || *str == '\t') {
Willy Tarreau06d97f92013-12-02 17:45:48 +0100615 /* single '%' followed by blank or digit, send them both */
616 cformat = LF_TEXT;
617 pformat = LF_TEXT; /* finally we include the previous char as well */
618 sp = str - 1; /* send both the '%' and the current char */
Jim Freemana2278c82017-04-15 08:01:59 -0600619 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 +0100620 *str, (int)(str - backfmt), fmt);
Thierry FOURNIER / OZON.IOa2c38d72016-11-22 23:11:21 +0100621 return 0;
Willy Tarreau06d97f92013-12-02 17:45:48 +0100622
623 }
Willy Tarreau8a3f52f2012-12-20 21:23:42 +0100624 else
625 cformat = LF_INIT; // handle other cases of litterals
626 break;
627
628 case LF_STARG: // text immediately following '%{'
629 if (*str == '}') { // end of arg
William Lallemand723b73a2012-02-08 16:37:49 +0100630 cformat = LF_EDARG;
Willy Tarreau8a3f52f2012-12-20 21:23:42 +0100631 arg_len = str - arg;
632 *str = 0; // used for reporting errors
William Lallemand723b73a2012-02-08 16:37:49 +0100633 }
Willy Tarreau8a3f52f2012-12-20 21:23:42 +0100634 break;
635
636 case LF_EDARG: // text immediately following '%{arg}'
Willy Tarreauc8368452012-12-21 00:09:23 +0100637 if (*str == '[') {
638 cformat = LF_STEXPR;
639 var = str + 1; // store expr in variable name
640 break;
641 }
Willy Tarreau0f28f822013-12-16 01:38:33 +0100642 else if (isalnum((unsigned char)*str)) { // variable name
William Lallemand723b73a2012-02-08 16:37:49 +0100643 cformat = LF_VAR;
Willy Tarreau8a3f52f2012-12-20 21:23:42 +0100644 var = str;
645 break;
646 }
Thierry FOURNIER / OZON.IO8a4e4422016-11-23 00:41:28 +0100647 memprintf(err, "parse argument modifier without variable name near '%%{%s}'", arg);
Thierry FOURNIER / OZON.IOa2c38d72016-11-22 23:11:21 +0100648 return 0;
Willy Tarreau8a3f52f2012-12-20 21:23:42 +0100649
Willy Tarreauc8368452012-12-21 00:09:23 +0100650 case LF_STEXPR: // text immediately following '%['
651 if (*str == ']') { // end of arg
652 cformat = LF_EDEXPR;
653 var_len = str - var;
654 *str = 0; // needed for parsing the expression
655 }
656 break;
657
Willy Tarreau8a3f52f2012-12-20 21:23:42 +0100658 case LF_VAR: // text part of a variable name
659 var_len = str - var;
Willy Tarreau0f28f822013-12-16 01:38:33 +0100660 if (!isalnum((unsigned char)*str))
Willy Tarreau8a3f52f2012-12-20 21:23:42 +0100661 cformat = LF_INIT; // not variable name anymore
662 break;
663
Willy Tarreauc8368452012-12-21 00:09:23 +0100664 default: // LF_INIT, LF_TEXT, LF_SEPARATOR, LF_END, LF_EDEXPR
Willy Tarreau8a3f52f2012-12-20 21:23:42 +0100665 cformat = LF_INIT;
666 }
667
668 if (cformat == LF_INIT) { /* resynchronize state to text/sep/startvar */
669 switch (*str) {
670 case '%': cformat = LF_STARTVAR; break;
671 case ' ': cformat = LF_SEPARATOR; break;
672 case 0 : cformat = LF_END; break;
673 default : cformat = LF_TEXT; break;
William Lallemand723b73a2012-02-08 16:37:49 +0100674 }
675 }
676
Willy Tarreau8a3f52f2012-12-20 21:23:42 +0100677 if (cformat != pformat || pformat == LF_SEPARATOR) {
678 switch (pformat) {
679 case LF_VAR:
Thierry FOURNIER / OZON.IO8a4e4422016-11-23 00:41:28 +0100680 if (!parse_logformat_var(arg, arg_len, var, var_len, curproxy, list_format, &options, err))
Thierry FOURNIER / OZON.IOa2c38d72016-11-22 23:11:21 +0100681 return 0;
Willy Tarreau8a3f52f2012-12-20 21:23:42 +0100682 break;
Willy Tarreauc8368452012-12-21 00:09:23 +0100683 case LF_STEXPR:
Thierry FOURNIER / OZON.IO8a4e4422016-11-23 00:41:28 +0100684 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 +0100685 return 0;
Willy Tarreauc8368452012-12-21 00:09:23 +0100686 break;
Willy Tarreau8a3f52f2012-12-20 21:23:42 +0100687 case LF_TEXT:
688 case LF_SEPARATOR:
Thierry FOURNIER / OZON.IO8a4e4422016-11-23 00:41:28 +0100689 if (!add_to_logformat_list(sp, str, pformat, list_format, err))
Thierry FOURNIER / OZON.IOa2c38d72016-11-22 23:11:21 +0100690 return 0;
Willy Tarreau8a3f52f2012-12-20 21:23:42 +0100691 break;
692 }
693 sp = str; /* new start of text at every state switch and at every separator */
William Lallemand723b73a2012-02-08 16:37:49 +0100694 }
695 }
Willy Tarreau8a3f52f2012-12-20 21:23:42 +0100696
Thierry FOURNIER / OZON.IOa2c38d72016-11-22 23:11:21 +0100697 if (pformat == LF_STARTVAR || pformat == LF_STARG || pformat == LF_STEXPR) {
Thierry FOURNIER / OZON.IO8a4e4422016-11-23 00:41:28 +0100698 memprintf(err, "truncated line after '%s'", var ? var : arg ? arg : "%");
Thierry FOURNIER / OZON.IOa2c38d72016-11-22 23:11:21 +0100699 return 0;
700 }
Willy Tarreaub83bc1e2012-12-24 12:36:33 +0100701 free(backfmt);
Thierry FOURNIER / OZON.IOa2c38d72016-11-22 23:11:21 +0100702
703 return 1;
William Lallemand723b73a2012-02-08 16:37:49 +0100704}
705
Christopher Faulet4b0b79d2018-03-26 15:54:32 +0200706/*
Frédéric Lécailled95ea282019-04-24 16:14:33 +0200707 * Parse the first range of indexes from a string made of a list of comma seperated
708 * ranges of indexes. Note that an index may be considered as a particular range
709 * with a high limit to the low limit.
710 */
711int get_logsrv_smp_range(unsigned int *low, unsigned int *high, char **arg, char **err)
712{
713 char *end, *p;
714
715 *low = *high = 0;
716
717 p = *arg;
718 end = strchr(p, ',');
719 if (!end)
720 end = p + strlen(p);
721
722 *high = *low = read_uint((const char **)&p, end);
723 if (!*low || (p != end && *p != '-'))
724 goto err;
725
726 if (p == end)
727 goto done;
728
729 p++;
730 *high = read_uint((const char **)&p, end);
731 if (!*high || *high <= *low || p != end)
732 goto err;
733
734 done:
735 if (*end == ',')
736 end++;
737 *arg = end;
738 return 1;
739
740 err:
741 memprintf(err, "wrong sample range '%s'", *arg);
742 return 0;
743}
744
745/*
746 * Returns 1 if the range defined by <low> and <high> overlaps
747 * one of them in <rgs> array of ranges with <sz> the size of this
748 * array, 0 if not.
749 */
750int smp_log_ranges_overlap(struct smp_log_range *rgs, size_t sz,
751 unsigned int low, unsigned int high, char **err)
752{
753 size_t i;
754
755 for (i = 0; i < sz; i++) {
756 if ((low >= rgs[i].low && low <= rgs[i].high) ||
757 (high >= rgs[i].low && high <= rgs[i].high)) {
758 memprintf(err, "ranges are overlapping");
759 return 1;
760 }
761 }
762
763 return 0;
764}
765
766int smp_log_range_cmp(const void *a, const void *b)
767{
768 const struct smp_log_range *rg_a = a;
769 const struct smp_log_range *rg_b = b;
770
771 if (rg_a->high < rg_b->low)
772 return -1;
773 else if (rg_a->low > rg_b->high)
774 return 1;
775
776 return 0;
777}
778
779/*
Christopher Faulet4b0b79d2018-03-26 15:54:32 +0200780 * Parse "log" keyword and update <logsrvs> list accordingly.
781 *
782 * When <do_del> is set, it means the "no log" line was parsed, so all log
783 * servers in <logsrvs> are released.
784 *
785 * Otherwise, we try to parse the "log" line. First of all, when the list is not
786 * the global one, we look for the parameter "global". If we find it,
787 * global.logsrvs is copied. Else we parse each arguments.
788 *
789 * The function returns 1 in success case, otherwise, it returns 0 and err is
790 * filled.
791 */
792int parse_logsrv(char **args, struct list *logsrvs, int do_del, char **err)
793{
794 struct sockaddr_storage *sk;
795 struct logsrv *logsrv = NULL;
796 int port1, port2;
797 int cur_arg;
798
799 /*
800 * "no log": delete previous herited or defined syslog
801 * servers.
802 */
803 if (do_del) {
804 struct logsrv *back;
805
806 if (*(args[1]) != 0) {
807 memprintf(err, "'no log' does not expect arguments");
808 goto error;
809 }
810
811 list_for_each_entry_safe(logsrv, back, logsrvs, list) {
812 LIST_DEL(&logsrv->list);
813 free(logsrv);
814 }
815 return 1;
816 }
817
818 /*
819 * "log global": copy global.logrsvs linked list to the end of logsrvs
820 * list. But first, we check (logsrvs != global.logsrvs).
821 */
822 if (*(args[1]) && *(args[2]) == 0 && !strcmp(args[1], "global")) {
823 if (logsrvs == &global.logsrvs) {
824 memprintf(err, "'global' is not supported for a global syslog server");
825 goto error;
826 }
827 list_for_each_entry(logsrv, &global.logsrvs, list) {
Christopher Faulet28ac0992018-03-26 16:09:19 +0200828 struct logsrv *node;
829
830 list_for_each_entry(node, logsrvs, list) {
831 if (node->ref == logsrv)
832 goto skip_logsrv;
833 }
834
835 node = malloc(sizeof(*node));
Christopher Faulet4b0b79d2018-03-26 15:54:32 +0200836 memcpy(node, logsrv, sizeof(struct logsrv));
Christopher Faulet28ac0992018-03-26 16:09:19 +0200837 node->ref = logsrv;
Christopher Faulet4b0b79d2018-03-26 15:54:32 +0200838 LIST_INIT(&node->list);
839 LIST_ADDQ(logsrvs, &node->list);
Christopher Faulet28ac0992018-03-26 16:09:19 +0200840
841 skip_logsrv:
842 continue;
Christopher Faulet4b0b79d2018-03-26 15:54:32 +0200843 }
844 return 1;
845 }
846
847 /*
848 * "log <address> ...: parse a syslog server line
849 */
850 if (*(args[1]) == 0 || *(args[2]) == 0) {
851 memprintf(err, "expects <address> and <facility> %s as arguments",
852 ((logsrvs == &global.logsrvs) ? "" : "or global"));
853 goto error;
854 }
855
Willy Tarreau5a32ecc2018-11-12 07:34:59 +0100856 /* take care of "stdout" and "stderr" as regular aliases for fd@1 / fd@2 */
857 if (strcmp(args[1], "stdout") == 0)
858 args[1] = "fd@1";
859 else if (strcmp(args[1], "stderr") == 0)
860 args[1] = "fd@2";
861
Christopher Faulet4b0b79d2018-03-26 15:54:32 +0200862 logsrv = calloc(1, sizeof(*logsrv));
863 if (!logsrv) {
864 memprintf(err, "out of memory");
865 goto error;
866 }
867
868 /* skip address for now, it will be parsed at the end */
869 cur_arg = 2;
870
871 /* just after the address, a length may be specified */
872 logsrv->maxlen = MAX_SYSLOG_LEN;
873 if (strcmp(args[cur_arg], "len") == 0) {
874 int len = atoi(args[cur_arg+1]);
875 if (len < 80 || len > 65535) {
876 memprintf(err, "invalid log length '%s', must be between 80 and 65535",
877 args[cur_arg+1]);
878 goto error;
879 }
880 logsrv->maxlen = len;
881 cur_arg += 2;
882 }
883 if (logsrv->maxlen > global.max_syslog_len)
884 global.max_syslog_len = logsrv->maxlen;
885
886 /* after the length, a format may be specified */
887 if (strcmp(args[cur_arg], "format") == 0) {
888 logsrv->format = get_log_format(args[cur_arg+1]);
889 if (logsrv->format < 0) {
890 memprintf(err, "unknown log format '%s'", args[cur_arg+1]);
891 goto error;
892 }
893 cur_arg += 2;
894 }
895
Frédéric Lécailled95ea282019-04-24 16:14:33 +0200896 if (strcmp(args[cur_arg], "sample") == 0) {
897 unsigned low, high;
898 char *p, *beg, *end, *smp_sz_str;
899 struct smp_log_range *smp_rgs = NULL;
900 size_t smp_rgs_sz = 0, smp_sz = 0, new_smp_sz;
901
902 p = args[cur_arg+1];
903 smp_sz_str = strchr(p, ':');
904 if (!smp_sz_str) {
905 memprintf(err, "Missing sample size");
906 goto error;
907 }
908
909 *smp_sz_str++ = '\0';
910
911 end = p + strlen(p);
912
913 while (p != end) {
914 if (!get_logsrv_smp_range(&low, &high, &p, err))
915 goto error;
916
917 if (smp_rgs && smp_log_ranges_overlap(smp_rgs, smp_rgs_sz, low, high, err))
918 goto error;
919
920 smp_rgs = my_realloc2(smp_rgs, (smp_rgs_sz + 1) * sizeof *smp_rgs);
921 if (!smp_rgs) {
922 memprintf(err, "out of memory error");
923 goto error;
924 }
925
926 smp_rgs[smp_rgs_sz].low = low;
927 smp_rgs[smp_rgs_sz].high = high;
928 smp_rgs[smp_rgs_sz].sz = high - low + 1;
929 smp_rgs[smp_rgs_sz].curr_idx = 0;
930 if (smp_rgs[smp_rgs_sz].high > smp_sz)
931 smp_sz = smp_rgs[smp_rgs_sz].high;
932 smp_rgs_sz++;
933 }
934
Tim Duesterhus21648002019-06-23 22:10:10 +0200935 if (smp_rgs == NULL) {
936 memprintf(err, "no sampling ranges given");
937 goto error;
938 }
939
Frédéric Lécailled95ea282019-04-24 16:14:33 +0200940 beg = smp_sz_str;
941 end = beg + strlen(beg);
942 new_smp_sz = read_uint((const char **)&beg, end);
943 if (!new_smp_sz || beg != end) {
944 memprintf(err, "wrong sample size '%s' for sample range '%s'",
945 smp_sz_str, args[cur_arg+1]);
946 goto error;
947 }
948
949 if (new_smp_sz < smp_sz) {
950 memprintf(err, "sample size %zu should be greater or equal to "
951 "%zu the maximum of the high ranges limits",
952 new_smp_sz, smp_sz);
953 goto error;
954 }
955 smp_sz = new_smp_sz;
956
957 /* Let's order <smp_rgs> array. */
958 qsort(smp_rgs, smp_rgs_sz, sizeof(struct smp_log_range), smp_log_range_cmp);
959
960 logsrv->lb.smp_rgs = smp_rgs;
961 logsrv->lb.smp_rgs_sz = smp_rgs_sz;
962 logsrv->lb.smp_sz = smp_sz;
963
964 cur_arg += 2;
965 }
Frédéric Lécailled803e472019-04-25 07:42:09 +0200966 HA_SPIN_INIT(&logsrv->lock);
Christopher Faulet4b0b79d2018-03-26 15:54:32 +0200967 /* parse the facility */
968 logsrv->facility = get_log_facility(args[cur_arg]);
969 if (logsrv->facility < 0) {
970 memprintf(err, "unknown log facility '%s'", args[cur_arg]);
971 goto error;
972 }
973 cur_arg++;
974
975 /* parse the max syslog level (default: debug) */
976 logsrv->level = 7;
977 if (*(args[cur_arg])) {
978 logsrv->level = get_log_level(args[cur_arg]);
979 if (logsrv->level < 0) {
980 memprintf(err, "unknown optional log level '%s'", args[cur_arg]);
981 goto error;
982 }
983 cur_arg++;
984 }
985
986 /* parse the limit syslog level (default: emerg) */
987 logsrv->minlvl = 0;
988 if (*(args[cur_arg])) {
989 logsrv->minlvl = get_log_level(args[cur_arg]);
990 if (logsrv->minlvl < 0) {
991 memprintf(err, "unknown optional minimum log level '%s'", args[cur_arg]);
992 goto error;
993 }
994 cur_arg++;
995 }
996
997 /* Too many args */
998 if (*(args[cur_arg])) {
999 memprintf(err, "cannot handle unexpected argument '%s'", args[cur_arg]);
1000 goto error;
1001 }
1002
1003 /* now, back to the address */
Willy Tarreauf3dc30f2019-08-30 14:18:44 +02001004 logsrv->type = LOG_TARGET_DGRAM;
Willy Tarreauc046d162019-08-30 15:24:59 +02001005 if (strncmp(args[1], "ring@", 5) == 0) {
1006 struct sink *sink = sink_find(args[1] + 5);
1007
1008 if (!sink || sink->type != SINK_TYPE_BUFFER) {
1009 memprintf(err, "cannot find ring buffer '%s'", args[1] + 5);
1010 goto error;
1011 }
1012
1013 logsrv->addr.ss_family = AF_UNSPEC;
1014 logsrv->type = LOG_TARGET_BUFFER;
1015 logsrv->ring = sink->ctx.ring;
1016 goto done;
1017 }
1018
Willy Tarreauf3dc30f2019-08-30 14:18:44 +02001019 if (strncmp(args[1], "fd@", 3) == 0)
1020 logsrv->type = LOG_TARGET_FD;
1021
Christopher Faulet4b0b79d2018-03-26 15:54:32 +02001022 sk = str2sa_range(args[1], NULL, &port1, &port2, err, NULL, NULL, 1);
1023 if (!sk)
1024 goto error;
1025 logsrv->addr = *sk;
1026
1027 if (sk->ss_family == AF_INET || sk->ss_family == AF_INET6) {
1028 if (port1 != port2) {
1029 memprintf(err, "port ranges and offsets are not allowed in '%s'", args[1]);
1030 goto error;
1031 }
1032 logsrv->addr = *sk;
1033 if (!port1)
1034 set_host_port(&logsrv->addr, SYSLOG_PORT);
1035 }
Willy Tarreauc046d162019-08-30 15:24:59 +02001036 done:
Christopher Faulet4b0b79d2018-03-26 15:54:32 +02001037 LIST_ADDQ(logsrvs, &logsrv->list);
1038 return 1;
1039
1040 error:
1041 free(logsrv);
1042 return 0;
1043}
1044
1045
Christopher Fauletd4696382017-10-24 11:44:05 +02001046/* Generic function to display messages prefixed by a label */
1047static void print_message(const char *label, const char *fmt, va_list argp)
1048{
1049 struct tm tm;
1050 char *head, *msg;
1051
1052 head = msg = NULL;
1053
1054 get_localtime(date.tv_sec, &tm);
1055 memprintf(&head, "[%s] %03d/%02d%02d%02d (%d) : ",
1056 label, tm.tm_yday, tm.tm_hour, tm.tm_min, tm.tm_sec, (int)getpid());
1057 memvprintf(&msg, fmt, argp);
1058
1059 if (global.mode & MODE_STARTING)
1060 memprintf(&startup_logs, "%s%s%s", (startup_logs ? startup_logs : ""), head, msg);
1061
1062 fprintf(stderr, "%s%s", head, msg);
1063 fflush(stderr);
1064
1065 free(head);
1066 free(msg);
1067}
1068
Willy Tarreaubaaee002006-06-26 02:48:02 +02001069/*
1070 * Displays the message on stderr with the date and pid. Overrides the quiet
1071 * mode during startup.
1072 */
Christopher Faulet767a84b2017-11-24 16:50:31 +01001073void ha_alert(const char *fmt, ...)
Willy Tarreaubaaee002006-06-26 02:48:02 +02001074{
1075 va_list argp;
Willy Tarreaubaaee002006-06-26 02:48:02 +02001076
1077 if (!(global.mode & MODE_QUIET) || (global.mode & (MODE_VERBOSE | MODE_STARTING))) {
1078 va_start(argp, fmt);
Christopher Fauletd4696382017-10-24 11:44:05 +02001079 print_message("ALERT", fmt, argp);
Willy Tarreaubaaee002006-06-26 02:48:02 +02001080 va_end(argp);
1081 }
1082}
1083
1084
1085/*
1086 * Displays the message on stderr with the date and pid.
1087 */
Christopher Faulet767a84b2017-11-24 16:50:31 +01001088void ha_warning(const char *fmt, ...)
Willy Tarreaubaaee002006-06-26 02:48:02 +02001089{
1090 va_list argp;
Willy Tarreaubaaee002006-06-26 02:48:02 +02001091
1092 if (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE)) {
1093 va_start(argp, fmt);
Christopher Fauletd4696382017-10-24 11:44:05 +02001094 print_message("WARNING", fmt, argp);
Willy Tarreaubaaee002006-06-26 02:48:02 +02001095 va_end(argp);
1096 }
1097}
1098
1099/*
William Lallemand9c56a222018-11-21 18:04:52 +01001100 * Displays the message on stderr with the date and pid.
1101 */
1102void ha_notice(const char *fmt, ...)
1103{
1104 va_list argp;
1105
1106 if (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE)) {
1107 va_start(argp, fmt);
1108 print_message("NOTICE", fmt, argp);
1109 va_end(argp);
1110 }
1111}
1112
1113/*
Willy Tarreaubaaee002006-06-26 02:48:02 +02001114 * Displays the message on <out> only if quiet mode is not set.
1115 */
Willy Tarreaub17916e2006-10-15 15:17:57 +02001116void qfprintf(FILE *out, const char *fmt, ...)
Willy Tarreaubaaee002006-06-26 02:48:02 +02001117{
1118 va_list argp;
1119
1120 if (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE)) {
1121 va_start(argp, fmt);
1122 vfprintf(out, fmt, argp);
1123 fflush(out);
1124 va_end(argp);
1125 }
1126}
1127
1128/*
Dragan Dosen1322d092015-09-22 16:05:32 +02001129 * returns log format for <fmt> or -1 if not found.
1130 */
1131int get_log_format(const char *fmt)
1132{
1133 int format;
1134
1135 format = LOG_FORMATS - 1;
Dragan Dosen43885c72015-10-01 13:18:13 +02001136 while (format >= 0 && strcmp(log_formats[format].name, fmt))
Dragan Dosen1322d092015-09-22 16:05:32 +02001137 format--;
1138
1139 return format;
1140}
1141
1142/*
Willy Tarreaubaaee002006-06-26 02:48:02 +02001143 * returns log level for <lev> or -1 if not found.
1144 */
1145int get_log_level(const char *lev)
1146{
1147 int level;
1148
1149 level = NB_LOG_LEVELS - 1;
1150 while (level >= 0 && strcmp(log_levels[level], lev))
1151 level--;
1152
1153 return level;
1154}
1155
Willy Tarreaubaaee002006-06-26 02:48:02 +02001156/*
1157 * returns log facility for <fac> or -1 if not found.
1158 */
1159int get_log_facility(const char *fac)
1160{
1161 int facility;
1162
1163 facility = NB_LOG_FACILITIES - 1;
1164 while (facility >= 0 && strcmp(log_facilities[facility], fac))
1165 facility--;
William Lallemand2a4a44f2012-02-06 16:00:33 +01001166
Willy Tarreaubaaee002006-06-26 02:48:02 +02001167 return facility;
1168}
1169
William Lallemanda1cc3812012-02-08 16:38:44 +01001170/*
Dragan Dosen835b9212016-02-12 13:23:03 +01001171 * Encode the string.
1172 *
1173 * When using the +E log format option, it will try to escape '"\]'
1174 * characters with '\' as prefix. The same prefix should not be used as
1175 * <escape>.
1176 */
1177static char *lf_encode_string(char *start, char *stop,
Willy Tarreau1bfd6022019-06-07 11:10:07 +02001178 const char escape, const long *map,
Dragan Dosen835b9212016-02-12 13:23:03 +01001179 const char *string,
1180 struct logformat_node *node)
1181{
1182 if (node->options & LOG_OPT_ESC) {
1183 if (start < stop) {
1184 stop--; /* reserve one byte for the final '\0' */
1185 while (start < stop && *string != '\0') {
Willy Tarreau1bfd6022019-06-07 11:10:07 +02001186 if (!ha_bit_test((unsigned char)(*string), map)) {
1187 if (!ha_bit_test((unsigned char)(*string), rfc5424_escape_map))
Dragan Dosen835b9212016-02-12 13:23:03 +01001188 *start++ = *string;
1189 else {
1190 if (start + 2 >= stop)
1191 break;
1192 *start++ = '\\';
1193 *start++ = *string;
1194 }
1195 }
1196 else {
1197 if (start + 3 >= stop)
1198 break;
1199 *start++ = escape;
1200 *start++ = hextab[(*string >> 4) & 15];
1201 *start++ = hextab[*string & 15];
1202 }
1203 string++;
1204 }
1205 *start = '\0';
1206 }
1207 }
1208 else {
1209 return encode_string(start, stop, escape, map, string);
1210 }
1211
1212 return start;
1213}
1214
1215/*
1216 * Encode the chunk.
1217 *
1218 * When using the +E log format option, it will try to escape '"\]'
1219 * characters with '\' as prefix. The same prefix should not be used as
1220 * <escape>.
1221 */
1222static char *lf_encode_chunk(char *start, char *stop,
Willy Tarreau1bfd6022019-06-07 11:10:07 +02001223 const char escape, const long *map,
Willy Tarreau83061a82018-07-13 11:56:34 +02001224 const struct buffer *chunk,
Dragan Dosen835b9212016-02-12 13:23:03 +01001225 struct logformat_node *node)
1226{
1227 char *str, *end;
1228
1229 if (node->options & LOG_OPT_ESC) {
1230 if (start < stop) {
Willy Tarreau843b7cb2018-07-13 10:54:26 +02001231 str = chunk->area;
1232 end = chunk->area + chunk->data;
Dragan Dosen835b9212016-02-12 13:23:03 +01001233
1234 stop--; /* reserve one byte for the final '\0' */
1235 while (start < stop && str < end) {
Willy Tarreau1bfd6022019-06-07 11:10:07 +02001236 if (!ha_bit_test((unsigned char)(*str), map)) {
1237 if (!ha_bit_test((unsigned char)(*str), rfc5424_escape_map))
Dragan Dosen835b9212016-02-12 13:23:03 +01001238 *start++ = *str;
1239 else {
1240 if (start + 2 >= stop)
1241 break;
1242 *start++ = '\\';
1243 *start++ = *str;
1244 }
1245 }
1246 else {
1247 if (start + 3 >= stop)
1248 break;
1249 *start++ = escape;
1250 *start++ = hextab[(*str >> 4) & 15];
1251 *start++ = hextab[*str & 15];
1252 }
1253 str++;
1254 }
1255 *start = '\0';
1256 }
1257 }
1258 else {
1259 return encode_chunk(start, stop, escape, map, chunk);
1260 }
1261
1262 return start;
1263}
1264
1265/*
William Lallemanda1cc3812012-02-08 16:38:44 +01001266 * Write a string in the log string
Dragan Dosen835b9212016-02-12 13:23:03 +01001267 * Take cares of quote and escape options
William Lallemanda1cc3812012-02-08 16:38:44 +01001268 *
Joseph Herlant85b40592018-11-15 12:10:04 -08001269 * Return the address of the \0 character, or NULL on error
William Lallemanda1cc3812012-02-08 16:38:44 +01001270 */
Willy Tarreau26ffa852018-09-05 15:23:10 +02001271char *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 +01001272{
Willy Tarreau2b0108a2012-12-21 19:23:44 +01001273 if (size < 2)
1274 return NULL;
William Lallemanda1cc3812012-02-08 16:38:44 +01001275
Willy Tarreau2b0108a2012-12-21 19:23:44 +01001276 if (node->options & LOG_OPT_QUOTE) {
1277 *(dst++) = '"';
1278 size--;
William Lallemandbddd4fd2012-02-27 11:23:10 +01001279 }
Willy Tarreau2b0108a2012-12-21 19:23:44 +01001280
Willy Tarreau6cbbdbf2013-02-05 18:52:25 +01001281 if (src && len) {
Dragan Dosendb1b6f92016-07-25 11:35:02 +02001282 if (++len > size)
1283 len = size;
Dragan Dosen835b9212016-02-12 13:23:03 +01001284 if (node->options & LOG_OPT_ESC) {
Dragan Dosen835b9212016-02-12 13:23:03 +01001285 char *ret;
1286
Dragan Dosendb1b6f92016-07-25 11:35:02 +02001287 ret = escape_string(dst, dst + len, '\\', rfc5424_escape_map, src);
Dragan Dosen835b9212016-02-12 13:23:03 +01001288 if (ret == NULL || *ret != '\0')
1289 return NULL;
1290 len = ret - dst;
1291 }
1292 else {
Dragan Dosen835b9212016-02-12 13:23:03 +01001293 len = strlcpy2(dst, src, len);
1294 }
Willy Tarreau2b0108a2012-12-21 19:23:44 +01001295
1296 size -= len;
1297 dst += len;
1298 }
Willy Tarreau6cbbdbf2013-02-05 18:52:25 +01001299 else if ((node->options & (LOG_OPT_QUOTE|LOG_OPT_MANDATORY)) == LOG_OPT_MANDATORY) {
1300 if (size < 2)
1301 return NULL;
1302 *(dst++) = '-';
1303 }
Willy Tarreau2b0108a2012-12-21 19:23:44 +01001304
1305 if (node->options & LOG_OPT_QUOTE) {
1306 if (size < 2)
1307 return NULL;
1308 *(dst++) = '"';
1309 }
1310
1311 *dst = '\0';
William Lallemandbddd4fd2012-02-27 11:23:10 +01001312 return dst;
William Lallemanda1cc3812012-02-08 16:38:44 +01001313}
1314
Willy Tarreau26ffa852018-09-05 15:23:10 +02001315static inline char *lf_text(char *dst, const char *src, size_t size, const struct logformat_node *node)
Willy Tarreau2b0108a2012-12-21 19:23:44 +01001316{
1317 return lf_text_len(dst, src, size, size, node);
1318}
1319
William Lallemand5f232402012-04-05 18:02:55 +02001320/*
Joseph Herlant85b40592018-11-15 12:10:04 -08001321 * Write a IP address to the log string
William Lallemand5f232402012-04-05 18:02:55 +02001322 * +X option write in hexadecimal notation, most signifant byte on the left
1323 */
Willy Tarreau26ffa852018-09-05 15:23:10 +02001324char *lf_ip(char *dst, const struct sockaddr *sockaddr, size_t size, const struct logformat_node *node)
William Lallemand5f232402012-04-05 18:02:55 +02001325{
1326 char *ret = dst;
1327 int iret;
1328 char pn[INET6_ADDRSTRLEN];
1329
1330 if (node->options & LOG_OPT_HEXA) {
Radek Zajic594c4562019-03-22 10:21:54 +00001331 unsigned char *addr = NULL;
1332 switch (sockaddr->sa_family) {
1333 case AF_INET:
1334 addr = (unsigned char *)&((struct sockaddr_in *)sockaddr)->sin_addr.s_addr;
1335 iret = snprintf(dst, size, "%02X%02X%02X%02X", addr[0], addr[1], addr[2], addr[3]);
1336 break;
1337 case AF_INET6:
1338 addr = (unsigned char *)&((struct sockaddr_in6 *)sockaddr)->sin6_addr.s6_addr;
1339 iret = snprintf(dst, size, "%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X",
1340 addr[0], addr[1], addr[2], addr[3], addr[4], addr[5], addr[6], addr[7],
1341 addr[8], addr[9], addr[10], addr[11], addr[12], addr[13], addr[14], addr[15]);
1342 break;
1343 default:
1344 return NULL;
1345 }
William Lallemand5f232402012-04-05 18:02:55 +02001346 if (iret < 0 || iret > size)
1347 return NULL;
1348 ret += iret;
1349 } else {
1350 addr_to_str((struct sockaddr_storage *)sockaddr, pn, sizeof(pn));
1351 ret = lf_text(dst, pn, size, node);
1352 if (ret == NULL)
1353 return NULL;
1354 }
1355 return ret;
1356}
1357
1358/*
1359 * Write a port to the log
1360 * +X option write in hexadecimal notation, most signifant byte on the left
1361 */
Willy Tarreau26ffa852018-09-05 15:23:10 +02001362char *lf_port(char *dst, const struct sockaddr *sockaddr, size_t size, const struct logformat_node *node)
William Lallemand5f232402012-04-05 18:02:55 +02001363{
1364 char *ret = dst;
1365 int iret;
1366
1367 if (node->options & LOG_OPT_HEXA) {
1368 const unsigned char *port = (const unsigned char *)&((struct sockaddr_in *)sockaddr)->sin_port;
1369 iret = snprintf(dst, size, "%02X%02X", port[0], port[1]);
1370 if (iret < 0 || iret > size)
1371 return NULL;
1372 ret += iret;
1373 } else {
1374 ret = ltoa_o(get_host_port((struct sockaddr_storage *)sockaddr), dst, size);
1375 if (ret == NULL)
1376 return NULL;
1377 }
1378 return ret;
1379}
1380
Dragan Dosen1322d092015-09-22 16:05:32 +02001381/* Re-generate time-based part of the syslog header in RFC3164 format at
1382 * the beginning of logheader once a second and return the pointer to the
1383 * first character after it.
Willy Tarreaub1a2faf2012-03-19 16:51:53 +01001384 */
Dragan Dosen0b85ece2015-09-25 19:17:44 +02001385static char *update_log_hdr(const time_t time)
Willy Tarreaubaaee002006-06-26 02:48:02 +02001386{
Christopher Fauletf8188c62017-06-02 16:20:16 +02001387 static THREAD_LOCAL long tvsec;
Willy Tarreau83061a82018-07-13 11:56:34 +02001388 static THREAD_LOCAL struct buffer host = { };
Christopher Fauletf8188c62017-06-02 16:20:16 +02001389 static THREAD_LOCAL int sep = 0;
Willy Tarreaubaaee002006-06-26 02:48:02 +02001390
Willy Tarreau55e2f5a2019-05-05 10:11:39 +02001391 if (unlikely(time != tvsec || logheader_end == NULL)) {
Willy Tarreaubaaee002006-06-26 02:48:02 +02001392 /* this string is rebuild only once a second */
Willy Tarreaufe944602007-10-25 10:34:16 +02001393 struct tm tm;
Willy Tarreaub1a2faf2012-03-19 16:51:53 +01001394 int hdr_len;
Willy Tarreaufe944602007-10-25 10:34:16 +02001395
Dragan Dosen0b85ece2015-09-25 19:17:44 +02001396 tvsec = time;
Willy Tarreaufe944602007-10-25 10:34:16 +02001397 get_localtime(tvsec, &tm);
Willy Tarreaubaaee002006-06-26 02:48:02 +02001398
Willy Tarreau843b7cb2018-07-13 10:54:26 +02001399 if (unlikely(global.log_send_hostname != host.area)) {
1400 host.area = global.log_send_hostname;
1401 host.data = host.area ? strlen(host.area) : 0;
1402 sep = host.data ? 1 : 0;
Dragan Dosen43885c72015-10-01 13:18:13 +02001403 }
1404
Dragan Dosen59cee972015-09-19 22:09:02 +02001405 hdr_len = snprintf(logheader, global.max_syslog_len,
Dragan Dosen43885c72015-10-01 13:18:13 +02001406 "<<<<>%s %2d %02d:%02d:%02d %.*s%*s",
Willy Tarreaufe944602007-10-25 10:34:16 +02001407 monthname[tm.tm_mon],
Dragan Dosen43885c72015-10-01 13:18:13 +02001408 tm.tm_mday, tm.tm_hour, tm.tm_min, tm.tm_sec,
Willy Tarreau843b7cb2018-07-13 10:54:26 +02001409 (int)host.data, host.area, sep, "");
Willy Tarreaubaaee002006-06-26 02:48:02 +02001410 /* WARNING: depending upon implementations, snprintf may return
1411 * either -1 or the number of bytes that would be needed to store
1412 * the total message. In both cases, we must adjust it.
1413 */
Willy Tarreau18324f52014-06-27 18:10:07 +02001414 if (hdr_len < 0 || hdr_len > global.max_syslog_len)
1415 hdr_len = global.max_syslog_len;
Willy Tarreaubaaee002006-06-26 02:48:02 +02001416
Willy Tarreau55e2f5a2019-05-05 10:11:39 +02001417 logheader_end = logheader + hdr_len;
Willy Tarreaubaaee002006-06-26 02:48:02 +02001418 }
1419
Willy Tarreau55e2f5a2019-05-05 10:11:39 +02001420 logheader_end[0] = 0; // ensure we get rid of any previous attempt
Willy Tarreau094af4e2015-01-07 15:03:42 +01001421
Willy Tarreau55e2f5a2019-05-05 10:11:39 +02001422 return logheader_end;
William Lallemand2a4a44f2012-02-06 16:00:33 +01001423}
1424
Dragan Dosen1322d092015-09-22 16:05:32 +02001425/* Re-generate time-based part of the syslog header in RFC5424 format at
1426 * the beginning of logheader_rfc5424 once a second and return the pointer
1427 * to the first character after it.
1428 */
Dragan Dosen0b85ece2015-09-25 19:17:44 +02001429static char *update_log_hdr_rfc5424(const time_t time)
Dragan Dosen1322d092015-09-22 16:05:32 +02001430{
Christopher Fauletf8188c62017-06-02 16:20:16 +02001431 static THREAD_LOCAL long tvsec;
Benoit GARNIERb413c2a2016-03-27 11:08:03 +02001432 const char *gmt_offset;
Dragan Dosen1322d092015-09-22 16:05:32 +02001433
Willy Tarreau55e2f5a2019-05-05 10:11:39 +02001434 if (unlikely(time != tvsec || logheader_rfc5424_end == NULL)) {
Dragan Dosen1322d092015-09-22 16:05:32 +02001435 /* this string is rebuild only once a second */
1436 struct tm tm;
1437 int hdr_len;
1438
Dragan Dosen0b85ece2015-09-25 19:17:44 +02001439 tvsec = time;
Dragan Dosen1322d092015-09-22 16:05:32 +02001440 get_localtime(tvsec, &tm);
Benoit GARNIERe2e5bde2016-03-27 03:04:16 +02001441 gmt_offset = get_gmt_offset(time, &tm);
Dragan Dosen1322d092015-09-22 16:05:32 +02001442
1443 hdr_len = snprintf(logheader_rfc5424, global.max_syslog_len,
Dragan Dosen17def462015-10-09 21:31:43 +02001444 "<<<<>1 %4d-%02d-%02dT%02d:%02d:%02d%.3s:%.2s %s ",
Dragan Dosen1322d092015-09-22 16:05:32 +02001445 tm.tm_year+1900, tm.tm_mon+1, tm.tm_mday,
Dragan Dosen17def462015-10-09 21:31:43 +02001446 tm.tm_hour, tm.tm_min, tm.tm_sec,
Benoit GARNIERb413c2a2016-03-27 11:08:03 +02001447 gmt_offset, gmt_offset+3,
Dragan Dosen43885c72015-10-01 13:18:13 +02001448 global.log_send_hostname ? global.log_send_hostname : hostname);
Dragan Dosen1322d092015-09-22 16:05:32 +02001449 /* WARNING: depending upon implementations, snprintf may return
1450 * either -1 or the number of bytes that would be needed to store
1451 * the total message. In both cases, we must adjust it.
1452 */
1453 if (hdr_len < 0 || hdr_len > global.max_syslog_len)
1454 hdr_len = global.max_syslog_len;
1455
Willy Tarreau55e2f5a2019-05-05 10:11:39 +02001456 logheader_rfc5424_end = logheader_rfc5424 + hdr_len;
Dragan Dosen1322d092015-09-22 16:05:32 +02001457 }
1458
Willy Tarreau55e2f5a2019-05-05 10:11:39 +02001459 logheader_rfc5424_end[0] = 0; // ensure we get rid of any previous attempt
Dragan Dosen1322d092015-09-22 16:05:32 +02001460
Willy Tarreau55e2f5a2019-05-05 10:11:39 +02001461 return logheader_rfc5424_end;
Dragan Dosen1322d092015-09-22 16:05:32 +02001462}
1463
William Lallemand2a4a44f2012-02-06 16:00:33 +01001464/*
Dragan Dosen59cee972015-09-19 22:09:02 +02001465 * This function sends the syslog message using a printf format string. It
1466 * expects an LF-terminated message.
William Lallemand2a4a44f2012-02-06 16:00:33 +01001467 */
1468void send_log(struct proxy *p, int level, const char *format, ...)
1469{
1470 va_list argp;
Willy Tarreaub1a2faf2012-03-19 16:51:53 +01001471 int data_len;
William Lallemand2a4a44f2012-02-06 16:00:33 +01001472
Willy Tarreau8c97ab52015-01-15 16:29:53 +01001473 if (level < 0 || format == NULL || logline == NULL)
William Lallemand2a4a44f2012-02-06 16:00:33 +01001474 return;
1475
William Lallemand2a4a44f2012-02-06 16:00:33 +01001476 va_start(argp, format);
Dragan Dosen59cee972015-09-19 22:09:02 +02001477 data_len = vsnprintf(logline, global.max_syslog_len, format, argp);
Willy Tarreau18324f52014-06-27 18:10:07 +02001478 if (data_len < 0 || data_len > global.max_syslog_len)
1479 data_len = global.max_syslog_len;
Willy Tarreaubaaee002006-06-26 02:48:02 +02001480 va_end(argp);
William Lallemand2a4a44f2012-02-06 16:00:33 +01001481
Christopher Faulet5c6fefc2019-08-11 19:40:12 +02001482 __send_log((p ? &p->logsrvs : NULL), (p ? &p->log_tag : NULL), level,
1483 logline, data_len, default_rfc5424_sd_log_format, 2);
William Lallemand2a4a44f2012-02-06 16:00:33 +01001484}
1485
1486/*
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001487 * This function sends a syslog message to <logsrv>.
1488 * <pid_str> is the string to be used for the PID of the caller, <pid_size> is length.
1489 * Same thing for <sd> and <sd_size> which are used for the structured-data part
1490 * in RFC5424 formatted syslog messages, and <tag_str> and <tag_size> the syslog tag.
Dragan Dosen0b85ece2015-09-25 19:17:44 +02001491 * It overrides the last byte of the message vector with an LF character.
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001492 * Does not return any error,
William Lallemand2a4a44f2012-02-06 16:00:33 +01001493 */
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001494static inline void __do_send_log(struct logsrv *logsrv, int nblogger, char *pid_str, size_t pid_size,
1495 int level, char *message, size_t size, char *sd, size_t sd_size,
1496 char *tag_str, size_t tag_size)
William Lallemand2a4a44f2012-02-06 16:00:33 +01001497{
Christopher Fauletf8188c62017-06-02 16:20:16 +02001498 static THREAD_LOCAL struct iovec iovec[NB_MSG_IOVEC_ELEMENTS] = { };
1499 static THREAD_LOCAL struct msghdr msghdr = {
1500 //.msg_iov = iovec,
Dragan Dosen609ac2a2015-09-16 18:25:42 +02001501 .msg_iovlen = NB_MSG_IOVEC_ELEMENTS
1502 };
Christopher Fauletf8188c62017-06-02 16:20:16 +02001503 static THREAD_LOCAL int logfdunix = -1; /* syslog to AF_UNIX socket */
1504 static THREAD_LOCAL int logfdinet = -1; /* syslog to AF_INET socket */
1505 static THREAD_LOCAL char *dataptr = NULL;
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001506 time_t time = date.tv_sec;
Dragan Dosen1322d092015-09-22 16:05:32 +02001507 char *hdr, *hdr_ptr;
Dragan Dosen59cee972015-09-19 22:09:02 +02001508 size_t hdr_size;
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001509 int fac_level;
1510 int *plogfd;
1511 char *pid_sep1 = "", *pid_sep2 = "";
1512 char logheader_short[3];
1513 int sent;
1514 int maxlen;
1515 int hdr_max = 0;
1516 int tag_max = 0;
1517 int pid_sep1_max = 0;
Frédéric Lécaille90a10ae2019-05-14 10:57:58 +02001518 int pid_max = 0;
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001519 int pid_sep2_max = 0;
1520 int sd_max = 0;
1521 int max = 0;
Christopher Fauletf8188c62017-06-02 16:20:16 +02001522
1523 msghdr.msg_iov = iovec;
William Lallemand2a4a44f2012-02-06 16:00:33 +01001524
1525 dataptr = message;
Willy Tarreaubaaee002006-06-26 02:48:02 +02001526
Willy Tarreauf3dc30f2019-08-30 14:18:44 +02001527 if (logsrv->type == LOG_TARGET_FD) {
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001528 /* the socket's address is a file descriptor */
1529 plogfd = (int *)&((struct sockaddr_in *)&logsrv->addr)->sin_addr.s_addr;
Robert Tsai81ae1952007-12-05 10:47:29 +01001530 }
Willy Tarreauc046d162019-08-30 15:24:59 +02001531 else if (logsrv->type == LOG_TARGET_BUFFER) {
1532 plogfd = NULL;
1533 }
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001534 else if (logsrv->addr.ss_family == AF_UNIX)
1535 plogfd = &logfdunix;
1536 else
1537 plogfd = &logfdinet;
Robert Tsai81ae1952007-12-05 10:47:29 +01001538
Willy Tarreauc046d162019-08-30 15:24:59 +02001539 if (plogfd && unlikely(*plogfd < 0)) {
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001540 /* socket not successfully initialized yet */
1541 if ((*plogfd = socket(logsrv->addr.ss_family, SOCK_DGRAM,
1542 (logsrv->addr.ss_family == AF_UNIX) ? 0 : IPPROTO_UDP)) < 0) {
1543 static char once;
William Lallemand0f99e342011-10-12 17:50:54 +02001544
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001545 if (!once) {
1546 once = 1; /* note: no need for atomic ops here */
1547 ha_alert("socket() failed in logger #%d: %s (errno=%d)\n",
1548 nblogger, strerror(errno), errno);
1549 }
1550 return;
1551 } else {
1552 /* we don't want to receive anything on this socket */
1553 setsockopt(*plogfd, SOL_SOCKET, SO_RCVBUF, &zero, sizeof(zero));
1554 /* does nothing under Linux, maybe needed for others */
1555 shutdown(*plogfd, SHUT_RD);
1556 fcntl(*plogfd, F_SETFD, fcntl(*plogfd, F_GETFD, FD_CLOEXEC) | FD_CLOEXEC);
1557 }
Dragan Dosen43885c72015-10-01 13:18:13 +02001558 }
1559
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001560 switch (logsrv->format) {
1561 case LOG_FORMAT_RFC3164:
1562 hdr = logheader;
1563 hdr_ptr = update_log_hdr(time);
1564 break;
Willy Tarreauc7c7be22014-06-23 18:07:15 +02001565
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001566 case LOG_FORMAT_RFC5424:
1567 hdr = logheader_rfc5424;
1568 hdr_ptr = update_log_hdr_rfc5424(time);
1569 sd_max = sd_size; /* the SD part allowed only in RFC5424 */
1570 break;
William Lallemandbddd4fd2012-02-27 11:23:10 +01001571
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001572 case LOG_FORMAT_SHORT:
1573 /* all fields are known, skip the header generation */
1574 hdr = logheader_short;
1575 hdr[0] = '<';
1576 hdr[1] = '0' + MAX(level, logsrv->minlvl);
1577 hdr[2] = '>';
1578 hdr_ptr = hdr;
1579 hdr_max = 3;
1580 maxlen = logsrv->maxlen - hdr_max;
1581 max = MIN(size, maxlen) - 1;
1582 goto send;
Willy Tarreau204e3f12018-12-15 15:48:48 +01001583
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001584 case LOG_FORMAT_RAW:
1585 /* all fields are known, skip the header generation */
1586 hdr_ptr = hdr = "";
1587 hdr_max = 0;
1588 maxlen = logsrv->maxlen;
1589 max = MIN(size, maxlen) - 1;
1590 goto send;
Willy Tarreauc98aebc2018-03-20 11:17:29 +01001591
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001592 default:
1593 return; /* must never happen */
1594 }
Willy Tarreauc7c7be22014-06-23 18:07:15 +02001595
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001596 hdr_size = hdr_ptr - hdr;
Dragan Dosen1322d092015-09-22 16:05:32 +02001597
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001598 /* For each target, we may have a different facility.
1599 * We can also have a different log level for each message.
1600 * This induces variations in the message header length.
1601 * Since we don't want to recompute it each time, nor copy it every
1602 * time, we only change the facility in the pre-computed header,
1603 * and we change the pointer to the header accordingly.
1604 */
1605 fac_level = (logsrv->facility << 3) + MAX(level, logsrv->minlvl);
1606 hdr_ptr = hdr + 3; /* last digit of the log level */
1607 do {
1608 *hdr_ptr = '0' + fac_level % 10;
1609 fac_level /= 10;
1610 hdr_ptr--;
1611 } while (fac_level && hdr_ptr > hdr);
1612 *hdr_ptr = '<';
Dragan Dosen1322d092015-09-22 16:05:32 +02001613
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001614 hdr_max = hdr_size - (hdr_ptr - hdr);
Willy Tarreaue8746a02018-11-12 08:45:00 +01001615
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001616 /* time-based header */
1617 if (unlikely(hdr_size >= logsrv->maxlen)) {
1618 hdr_max = MIN(hdr_max, logsrv->maxlen) - 1;
1619 sd_max = 0;
1620 goto send;
1621 }
Willy Tarreauc1b06452018-11-12 11:57:56 +01001622
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001623 maxlen = logsrv->maxlen - hdr_max;
Dragan Dosen1322d092015-09-22 16:05:32 +02001624
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001625 /* tag */
Frédéric Lécaille90a10ae2019-05-14 10:57:58 +02001626 tag_max = tag_size;
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001627 if (unlikely(tag_max >= maxlen)) {
1628 tag_max = maxlen - 1;
1629 sd_max = 0;
1630 goto send;
1631 }
Dragan Dosen1322d092015-09-22 16:05:32 +02001632
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001633 maxlen -= tag_max;
William Lallemand2a4a44f2012-02-06 16:00:33 +01001634
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001635 /* first pid separator */
1636 pid_sep1_max = log_formats[logsrv->format].pid.sep1.data;
1637 if (unlikely(pid_sep1_max >= maxlen)) {
1638 pid_sep1_max = maxlen - 1;
1639 sd_max = 0;
1640 goto send;
1641 }
Dragan Dosen59cee972015-09-19 22:09:02 +02001642
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001643 pid_sep1 = log_formats[logsrv->format].pid.sep1.area;
1644 maxlen -= pid_sep1_max;
Dragan Dosen59cee972015-09-19 22:09:02 +02001645
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001646 /* pid */
Frédéric Lécaille90a10ae2019-05-14 10:57:58 +02001647 pid_max = pid_size;
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001648 if (unlikely(pid_size >= maxlen)) {
1649 pid_size = maxlen - 1;
1650 sd_max = 0;
1651 goto send;
1652 }
Dragan Dosen68d2e3a2015-09-19 22:35:44 +02001653
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001654 maxlen -= pid_size;
Dragan Dosen43885c72015-10-01 13:18:13 +02001655
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001656 /* second pid separator */
1657 pid_sep2_max = log_formats[logsrv->format].pid.sep2.data;
1658 if (unlikely(pid_sep2_max >= maxlen)) {
1659 pid_sep2_max = maxlen - 1;
1660 sd_max = 0;
1661 goto send;
1662 }
Dragan Dosen43885c72015-10-01 13:18:13 +02001663
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001664 pid_sep2 = log_formats[logsrv->format].pid.sep2.area;
1665 maxlen -= pid_sep2_max;
Dragan Dosen68d2e3a2015-09-19 22:35:44 +02001666
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001667 /* structured-data */
1668 if (sd_max >= maxlen) {
1669 sd_max = maxlen - 1;
1670 goto send;
1671 }
Dragan Dosen59cee972015-09-19 22:09:02 +02001672
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001673 max = MIN(size, maxlen - sd_max) - 1;
1674send:
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001675 if (logsrv->addr.ss_family == AF_UNSPEC) {
Willy Tarreauc046d162019-08-30 15:24:59 +02001676 /* the target is a file descriptor or a ring buffer */
Willy Tarreaud52a7f82019-08-30 14:05:35 +02001677 struct ist msg[7];
1678
1679 msg[0].ptr = hdr_ptr; msg[0].len = hdr_max;
1680 msg[1].ptr = tag_str; msg[1].len = tag_max;
1681 msg[2].ptr = pid_sep1; msg[2].len = pid_sep1_max;
1682 msg[3].ptr = pid_str; msg[3].len = pid_max;
1683 msg[4].ptr = pid_sep2; msg[4].len = pid_sep2_max;
1684 msg[5].ptr = sd; msg[5].len = sd_max;
1685 msg[6].ptr = dataptr; msg[6].len = max;
1686
Willy Tarreauc046d162019-08-30 15:24:59 +02001687 if (logsrv->type == LOG_TARGET_BUFFER)
1688 sent = ring_write(logsrv->ring, ~0, NULL, 0, msg, 7);
1689 else /* LOG_TARGET_FD */
1690 sent = fd_write_frag_line(*plogfd, ~0, NULL, 0, msg, 7, 1);
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001691 }
1692 else {
Willy Tarreaud52a7f82019-08-30 14:05:35 +02001693 iovec[0].iov_base = hdr_ptr;
1694 iovec[0].iov_len = hdr_max;
1695 iovec[1].iov_base = tag_str;
1696 iovec[1].iov_len = tag_max;
1697 iovec[2].iov_base = pid_sep1;
1698 iovec[2].iov_len = pid_sep1_max;
1699 iovec[3].iov_base = pid_str;
1700 iovec[3].iov_len = pid_max;
1701 iovec[4].iov_base = pid_sep2;
1702 iovec[4].iov_len = pid_sep2_max;
1703 iovec[5].iov_base = sd;
1704 iovec[5].iov_len = sd_max;
1705 iovec[6].iov_base = dataptr;
1706 iovec[6].iov_len = max;
1707 iovec[7].iov_base = "\n"; /* insert a \n at the end of the message */
1708 iovec[7].iov_len = 1;
1709
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001710 msghdr.msg_name = (struct sockaddr *)&logsrv->addr;
1711 msghdr.msg_namelen = get_addr_len(&logsrv->addr);
Dragan Dosen43885c72015-10-01 13:18:13 +02001712
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001713 sent = sendmsg(*plogfd, &msghdr, MSG_DONTWAIT | MSG_NOSIGNAL);
1714 }
Dragan Dosen43885c72015-10-01 13:18:13 +02001715
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001716 if (sent < 0) {
1717 static char once;
Dragan Dosen43885c72015-10-01 13:18:13 +02001718
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001719 if (errno == EAGAIN)
1720 _HA_ATOMIC_ADD(&dropped_logs, 1);
1721 else if (!once) {
1722 once = 1; /* note: no need for atomic ops here */
1723 ha_alert("sendmsg()/writev() failed in logger #%d: %s (errno=%d)\n",
1724 nblogger, strerror(errno), errno);
Dragan Dosen0b85ece2015-09-25 19:17:44 +02001725 }
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001726 }
1727}
Dragan Dosen59cee972015-09-19 22:09:02 +02001728
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001729/*
1730 * This function sends a syslog message.
1731 * It doesn't care about errors nor does it report them.
1732 * The arguments <sd> and <sd_size> are used for the structured-data part
1733 * in RFC5424 formatted syslog messages.
1734 */
Christopher Faulet5c6fefc2019-08-11 19:40:12 +02001735void __send_log(struct list *logsrvs, struct buffer *tag, int level,
1736 char *message, size_t size, char *sd, size_t sd_size)
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001737{
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001738 struct logsrv *logsrv;
1739 int nblogger;
1740 static THREAD_LOCAL int curr_pid;
1741 static THREAD_LOCAL char pidstr[100];
1742 static THREAD_LOCAL struct buffer pid;
Dragan Dosen609ac2a2015-09-16 18:25:42 +02001743
Christopher Faulet5c6fefc2019-08-11 19:40:12 +02001744 if (logsrvs == NULL) {
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001745 if (!LIST_ISEMPTY(&global.logsrvs)) {
1746 logsrvs = &global.logsrvs;
Willy Tarreau5a32ecc2018-11-12 07:34:59 +01001747 }
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001748 }
Christopher Faulet5c6fefc2019-08-11 19:40:12 +02001749 if (!tag || !tag->area)
1750 tag = &global.log_tag;
Willy Tarreau18324f52014-06-27 18:10:07 +02001751
Christopher Faulet5c6fefc2019-08-11 19:40:12 +02001752 if (!logsrvs || LIST_ISEMPTY(logsrvs))
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001753 return;
Willy Tarreauc98aebc2018-03-20 11:17:29 +01001754
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001755 if (unlikely(curr_pid != getpid())) {
1756 curr_pid = getpid();
1757 ltoa_o(curr_pid, pidstr, sizeof(pidstr));
1758 chunk_initstr(&pid, pidstr);
1759 }
1760
1761 /* Send log messages to syslog server. */
1762 nblogger = 0;
1763 list_for_each_entry(logsrv, logsrvs, list) {
Frédéric Lécailled803e472019-04-25 07:42:09 +02001764 static THREAD_LOCAL int in_range = 1;
1765
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001766 /* we can filter the level of the messages that are sent to each logger */
1767 if (level > logsrv->level)
1768 continue;
1769
Frédéric Lécailled803e472019-04-25 07:42:09 +02001770 if (logsrv->lb.smp_rgs) {
1771 struct smp_log_range *curr_rg;
1772
1773 HA_SPIN_LOCK(LOGSRV_LOCK, &logsrv->lock);
1774 curr_rg = &logsrv->lb.smp_rgs[logsrv->lb.curr_rg];
1775 in_range = in_smp_log_range(curr_rg, logsrv->lb.curr_idx);
1776 if (in_range) {
1777 /* Let's consume this range. */
1778 curr_rg->curr_idx = (curr_rg->curr_idx + 1) % curr_rg->sz;
1779 if (!curr_rg->curr_idx) {
1780 /* If consumed, let's select the next range. */
1781 logsrv->lb.curr_rg = (logsrv->lb.curr_rg + 1) % logsrv->lb.smp_rgs_sz;
1782 }
1783 }
1784 logsrv->lb.curr_idx = (logsrv->lb.curr_idx + 1) % logsrv->lb.smp_sz;
1785 HA_SPIN_UNLOCK(LOGSRV_LOCK, &logsrv->lock);
1786 }
1787 if (in_range)
1788 __do_send_log(logsrv, ++nblogger, pid.area, pid.data, level,
1789 message, size, sd, sd_size, tag->area, tag->data);
Willy Tarreaubaaee002006-06-26 02:48:02 +02001790 }
1791}
1792
1793
Willy Tarreauc89ccb62012-04-05 21:18:22 +02001794const 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 +01001795const char sess_set_cookie[8] = "NPDIRU67"; /* No set-cookie, Set-cookie found and left unchanged (passive),
1796 Set-cookie Deleted, Set-Cookie Inserted, Set-cookie Rewritten,
1797 Set-cookie Updated, unknown, unknown */
1798
William Lallemand1d705562012-03-12 12:46:41 +01001799/*
1800 * try to write a character if there is enough space, or goto out
1801 */
William Lallemandbddd4fd2012-02-27 11:23:10 +01001802#define LOGCHAR(x) do { \
William Lallemand1d705562012-03-12 12:46:41 +01001803 if (tmplog < dst + maxsize - 1) { \
William Lallemandbddd4fd2012-02-27 11:23:10 +01001804 *(tmplog++) = (x); \
1805 } else { \
1806 goto out; \
1807 } \
1808 } while(0)
1809
Dragan Dosen835b9212016-02-12 13:23:03 +01001810
Willy Tarreaub6b3df32018-11-26 16:31:20 +01001811/* Initializes some log data at boot */
1812static void init_log()
Dragan Dosen835b9212016-02-12 13:23:03 +01001813{
1814 char *tmp;
Willy Tarreaue10cd482018-09-10 18:16:53 +02001815 int i;
Dragan Dosen835b9212016-02-12 13:23:03 +01001816
1817 /* Initialize the escape map for the RFC5424 structured-data : '"\]'
1818 * inside PARAM-VALUE should be escaped with '\' as prefix.
1819 * See https://tools.ietf.org/html/rfc5424#section-6.3.3 for more
1820 * details.
1821 */
1822 memset(rfc5424_escape_map, 0, sizeof(rfc5424_escape_map));
1823
1824 tmp = "\"\\]";
1825 while (*tmp) {
Willy Tarreau1bfd6022019-06-07 11:10:07 +02001826 ha_bit_set(*tmp, rfc5424_escape_map);
Dragan Dosen835b9212016-02-12 13:23:03 +01001827 tmp++;
1828 }
Willy Tarreaue10cd482018-09-10 18:16:53 +02001829
1830 /* initialize the log header encoding map : '{|}"#' should be encoded with
1831 * '#' as prefix, as well as non-printable characters ( <32 or >= 127 ).
1832 * URL encoding only requires '"', '#' to be encoded as well as non-
1833 * printable characters above.
1834 */
1835 memset(hdr_encode_map, 0, sizeof(hdr_encode_map));
1836 memset(url_encode_map, 0, sizeof(url_encode_map));
1837 for (i = 0; i < 32; i++) {
Willy Tarreau1bfd6022019-06-07 11:10:07 +02001838 ha_bit_set(i, hdr_encode_map);
1839 ha_bit_set(i, url_encode_map);
Willy Tarreaue10cd482018-09-10 18:16:53 +02001840 }
1841 for (i = 127; i < 256; i++) {
Willy Tarreau1bfd6022019-06-07 11:10:07 +02001842 ha_bit_set(i, hdr_encode_map);
1843 ha_bit_set(i, url_encode_map);
Willy Tarreaue10cd482018-09-10 18:16:53 +02001844 }
1845
1846 tmp = "\"#{|}";
1847 while (*tmp) {
Willy Tarreau1bfd6022019-06-07 11:10:07 +02001848 ha_bit_set(*tmp, hdr_encode_map);
Willy Tarreaue10cd482018-09-10 18:16:53 +02001849 tmp++;
1850 }
1851
1852 tmp = "\"#";
1853 while (*tmp) {
Willy Tarreau1bfd6022019-06-07 11:10:07 +02001854 ha_bit_set(*tmp, url_encode_map);
Willy Tarreaue10cd482018-09-10 18:16:53 +02001855 tmp++;
1856 }
1857
1858 /* initialize the http header encoding map. The draft httpbis define the
1859 * header content as:
1860 *
1861 * HTTP-message = start-line
1862 * *( header-field CRLF )
1863 * CRLF
1864 * [ message-body ]
1865 * header-field = field-name ":" OWS field-value OWS
1866 * field-value = *( field-content / obs-fold )
1867 * field-content = field-vchar [ 1*( SP / HTAB ) field-vchar ]
1868 * obs-fold = CRLF 1*( SP / HTAB )
1869 * field-vchar = VCHAR / obs-text
1870 * VCHAR = %x21-7E
1871 * obs-text = %x80-FF
1872 *
1873 * All the chars are encoded except "VCHAR", "obs-text", SP and HTAB.
1874 * The encoded chars are form 0x00 to 0x08, 0x0a to 0x1f and 0x7f. The
Joseph Herlant85b40592018-11-15 12:10:04 -08001875 * "obs-fold" is voluntarily forgotten because haproxy remove this.
Willy Tarreaue10cd482018-09-10 18:16:53 +02001876 */
1877 memset(http_encode_map, 0, sizeof(http_encode_map));
1878 for (i = 0x00; i <= 0x08; i++)
Willy Tarreau1bfd6022019-06-07 11:10:07 +02001879 ha_bit_set(i, http_encode_map);
Willy Tarreaue10cd482018-09-10 18:16:53 +02001880 for (i = 0x0a; i <= 0x1f; i++)
Willy Tarreau1bfd6022019-06-07 11:10:07 +02001881 ha_bit_set(i, http_encode_map);
1882 ha_bit_set(0x7f, http_encode_map);
Dragan Dosen835b9212016-02-12 13:23:03 +01001883}
William Lallemand1d705562012-03-12 12:46:41 +01001884
Willy Tarreaub6b3df32018-11-26 16:31:20 +01001885INITCALL0(STG_PREPARE, init_log);
1886
Christopher Faulet0132d062017-07-26 15:33:35 +02001887/* Initialize log buffers used for syslog messages */
1888int init_log_buffers()
1889{
1890 logheader = my_realloc2(logheader, global.max_syslog_len + 1);
Willy Tarreau55e2f5a2019-05-05 10:11:39 +02001891 logheader_end = NULL;
Christopher Faulet0132d062017-07-26 15:33:35 +02001892 logheader_rfc5424 = my_realloc2(logheader_rfc5424, global.max_syslog_len + 1);
Willy Tarreau55e2f5a2019-05-05 10:11:39 +02001893 logheader_rfc5424_end = NULL;
Christopher Faulet0132d062017-07-26 15:33:35 +02001894 logline = my_realloc2(logline, global.max_syslog_len + 1);
1895 logline_rfc5424 = my_realloc2(logline_rfc5424, global.max_syslog_len + 1);
1896 if (!logheader || !logline_rfc5424 || !logline || !logline_rfc5424)
1897 return 0;
1898 return 1;
1899}
1900
1901/* Deinitialize log buffers used for syslog messages */
1902void deinit_log_buffers()
1903{
Olivier Houchard7c497112019-03-07 14:19:24 +01001904 void *tmp_startup_logs;
1905
Christopher Faulet0132d062017-07-26 15:33:35 +02001906 free(logheader);
1907 free(logheader_rfc5424);
1908 free(logline);
1909 free(logline_rfc5424);
Olivier Houchardd2ee3e72019-03-08 18:53:21 +01001910 tmp_startup_logs = _HA_ATOMIC_XCHG(&startup_logs, NULL);
Olivier Houchard7c497112019-03-07 14:19:24 +01001911 free(tmp_startup_logs);
1912
Christopher Faulet0132d062017-07-26 15:33:35 +02001913 logheader = NULL;
1914 logheader_rfc5424 = NULL;
1915 logline = NULL;
1916 logline_rfc5424 = NULL;
Christopher Fauletd4696382017-10-24 11:44:05 +02001917 startup_logs = NULL;
Christopher Faulet0132d062017-07-26 15:33:35 +02001918}
1919
Willy Tarreaudf974472012-12-28 02:44:01 +01001920/* Builds a log line in <dst> based on <list_format>, and stops before reaching
1921 * <maxsize> characters. Returns the size of the output string in characters,
1922 * not counting the trailing zero which is always added if the resulting size
Willy Tarreau09bb27c2018-09-05 16:55:15 +02001923 * is not zero. It requires a valid session and optionally a stream. If the
1924 * stream is NULL, default values will be assumed for the stream part.
Willy Tarreaudf974472012-12-28 02:44:01 +01001925 */
Willy Tarreau43c538e2018-09-05 14:58:15 +02001926int 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 +02001927{
Willy Tarreaue36cbcb2015-04-03 15:40:56 +02001928 struct proxy *fe = sess->fe;
Willy Tarreau09bb27c2018-09-05 16:55:15 +02001929 struct proxy *be;
1930 struct http_txn *txn;
1931 const struct strm_logs *logs;
Willy Tarreau8fa99842019-07-17 11:47:11 +02001932 struct connection *be_conn;
Willy Tarreau09bb27c2018-09-05 16:55:15 +02001933 unsigned int s_flags;
1934 unsigned int uniq_id;
Willy Tarreau83061a82018-07-13 11:56:34 +02001935 struct buffer chunk;
William Lallemandbddd4fd2012-02-27 11:23:10 +01001936 char *uri;
Andrew Hayworth0ebc55f2015-04-27 21:37:03 +00001937 char *spc;
Andrew Hayworthe63ac872015-07-31 16:14:16 +00001938 char *qmark;
Andrew Hayworth0ebc55f2015-04-27 21:37:03 +00001939 char *end;
Willy Tarreaufe944602007-10-25 10:34:16 +02001940 struct tm tm;
William Lallemandbddd4fd2012-02-27 11:23:10 +01001941 int t_request;
1942 int hdr;
1943 int last_isspace = 1;
Andrew Hayworth0ebc55f2015-04-27 21:37:03 +00001944 int nspaces = 0;
Willy Tarreaub1a2faf2012-03-19 16:51:53 +01001945 char *tmplog;
William Lallemand1d705562012-03-12 12:46:41 +01001946 char *ret;
1947 int iret;
William Lallemandbddd4fd2012-02-27 11:23:10 +01001948 struct logformat_node *tmp;
Thierry FOURNIER / OZON.IO4cac3592016-07-28 17:19:45 +02001949 struct timeval tv;
Willy Tarreau09bb27c2018-09-05 16:55:15 +02001950 struct strm_logs tmp_strm_log;
Willy Tarreaubaaee002006-06-26 02:48:02 +02001951
William Lallemandbddd4fd2012-02-27 11:23:10 +01001952 /* FIXME: let's limit ourselves to frontend logging for now. */
Willy Tarreaubaaee002006-06-26 02:48:02 +02001953
Willy Tarreau09bb27c2018-09-05 16:55:15 +02001954 if (likely(s)) {
1955 be = s->be;
1956 txn = s->txn;
1957 be_conn = cs_conn(objt_cs(s->si[1].end));
1958 s_flags = s->flags;
1959 uniq_id = s->uniq_id;
1960 logs = &s->logs;
1961 } else {
1962 /* we have no stream so we first need to initialize a few
1963 * things that are needed later. We do increment the request
1964 * ID so that it's uniquely assigned to this request just as
1965 * if the request had reached the point of being processed.
1966 * A request error is reported as it's the only element we have
1967 * here and which justifies emitting such a log.
1968 */
1969 be = fe;
1970 txn = NULL;
1971 be_conn = NULL;
1972 s_flags = SF_ERR_PRXCOND | SF_FINST_R;
Olivier Houchardd2ee3e72019-03-08 18:53:21 +01001973 uniq_id = _HA_ATOMIC_XADD(&global.req_count, 1);
Willy Tarreau09bb27c2018-09-05 16:55:15 +02001974
1975 /* prepare a valid log structure */
1976 tmp_strm_log.tv_accept = sess->tv_accept;
1977 tmp_strm_log.accept_date = sess->accept_date;
1978 tmp_strm_log.t_handshake = sess->t_handshake;
1979 tmp_strm_log.t_idle = tv_ms_elapsed(&sess->tv_accept, &now) - sess->t_handshake;
1980 tv_zero(&tmp_strm_log.tv_request);
1981 tmp_strm_log.t_queue = -1;
1982 tmp_strm_log.t_connect = -1;
1983 tmp_strm_log.t_data = -1;
1984 tmp_strm_log.t_close = tv_ms_elapsed(&sess->tv_accept, &now);
1985 tmp_strm_log.bytes_in = 0;
1986 tmp_strm_log.bytes_out = 0;
1987 tmp_strm_log.prx_queue_pos = 0;
1988 tmp_strm_log.srv_queue_pos = 0;
1989
1990 logs = &tmp_strm_log;
1991 }
1992
William Lallemandbddd4fd2012-02-27 11:23:10 +01001993 t_request = -1;
Willy Tarreau372ac5a2018-09-05 15:16:23 +02001994 if (tv_isge(&logs->tv_request, &logs->tv_accept))
1995 t_request = tv_ms_elapsed(&logs->tv_accept, &logs->tv_request);
William Lallemandbddd4fd2012-02-27 11:23:10 +01001996
William Lallemand1d705562012-03-12 12:46:41 +01001997 tmplog = dst;
Willy Tarreauc9bd0cc2009-05-10 11:57:02 +02001998
William Lallemandbddd4fd2012-02-27 11:23:10 +01001999 /* fill logbuffer */
William Lallemand1d705562012-03-12 12:46:41 +01002000 if (LIST_ISEMPTY(list_format))
2001 return 0;
William Lallemandbddd4fd2012-02-27 11:23:10 +01002002
William Lallemand1d705562012-03-12 12:46:41 +01002003 list_for_each_entry(tmp, list_format, list) {
Willy Tarreaub363a1f2013-10-01 10:45:07 +02002004 struct connection *conn;
Willy Tarreau4f653562012-10-12 19:48:16 +02002005 const char *src = NULL;
Willy Tarreauc8368452012-12-21 00:09:23 +01002006 struct sample *key;
Willy Tarreau83061a82018-07-13 11:56:34 +02002007 const struct buffer empty = { };
William Lallemandbddd4fd2012-02-27 11:23:10 +01002008
Willy Tarreauc8368452012-12-21 00:09:23 +01002009 switch (tmp->type) {
William Lallemand1d705562012-03-12 12:46:41 +01002010 case LOG_FMT_SEPARATOR:
William Lallemandbddd4fd2012-02-27 11:23:10 +01002011 if (!last_isspace) {
2012 LOGCHAR(' ');
2013 last_isspace = 1;
William Lallemandbddd4fd2012-02-27 11:23:10 +01002014 }
2015 break;
2016
William Lallemand1d705562012-03-12 12:46:41 +01002017 case LOG_FMT_TEXT: // text
William Lallemandbddd4fd2012-02-27 11:23:10 +01002018 src = tmp->arg;
William Lallemand5f232402012-04-05 18:02:55 +02002019 iret = strlcpy2(tmplog, src, dst + maxsize - tmplog);
William Lallemand1d705562012-03-12 12:46:41 +01002020 if (iret == 0)
William Lallemandbddd4fd2012-02-27 11:23:10 +01002021 goto out;
William Lallemand1d705562012-03-12 12:46:41 +01002022 tmplog += iret;
William Lallemandbddd4fd2012-02-27 11:23:10 +01002023 last_isspace = 0;
2024 break;
2025
Willy Tarreauc8368452012-12-21 00:09:23 +01002026 case LOG_FMT_EXPR: // sample expression, may be request or response
2027 key = NULL;
Olivier Houchardf90db442018-12-15 14:00:06 +01002028 if (tmp->options & LOG_OPT_REQ_CAP && s)
Adis Nezirovic79beb242015-07-06 15:41:02 +02002029 key = sample_fetch_as_type(be, sess, s, SMP_OPT_DIR_REQ|SMP_OPT_FINAL, tmp->expr, SMP_T_STR);
Olivier Houchardf90db442018-12-15 14:00:06 +01002030 if (!key && (tmp->options & LOG_OPT_RES_CAP) && s)
Adis Nezirovic79beb242015-07-06 15:41:02 +02002031 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 +01002032 if (tmp->options & LOG_OPT_HTTP)
Dragan Dosen835b9212016-02-12 13:23:03 +01002033 ret = lf_encode_chunk(tmplog, dst + maxsize,
2034 '%', http_encode_map, key ? &key->data.u.str : &empty, tmp);
Thierry FOURNIERd048d8b2014-03-13 16:46:18 +01002035 else
Willy Tarreau843b7cb2018-07-13 10:54:26 +02002036 ret = lf_text_len(tmplog,
2037 key ? key->data.u.str.area : NULL,
2038 key ? key->data.u.str.data : 0,
2039 dst + maxsize - tmplog,
2040 tmp);
Willy Tarreauc8368452012-12-21 00:09:23 +01002041 if (ret == 0)
2042 goto out;
2043 tmplog = ret;
2044 last_isspace = 0;
2045 break;
2046
Willy Tarreau2beef582012-12-20 17:22:52 +01002047 case LOG_FMT_CLIENTIP: // %ci
Willy Tarreau9ad7bd42015-04-03 19:19:59 +02002048 conn = objt_conn(sess->origin);
Willy Tarreau8fa99842019-07-17 11:47:11 +02002049 if (conn && conn_get_src(conn))
Willy Tarreau6c6365f2019-07-17 16:48:18 +02002050 ret = lf_ip(tmplog, (struct sockaddr *)conn->src, dst + maxsize - tmplog, tmp);
Willy Tarreaub363a1f2013-10-01 10:45:07 +02002051 else
2052 ret = lf_text_len(tmplog, NULL, 0, dst + maxsize - tmplog, tmp);
William Lallemand1d705562012-03-12 12:46:41 +01002053 if (ret == NULL)
William Lallemandbddd4fd2012-02-27 11:23:10 +01002054 goto out;
William Lallemand1d705562012-03-12 12:46:41 +01002055 tmplog = ret;
William Lallemandbddd4fd2012-02-27 11:23:10 +01002056 last_isspace = 0;
2057 break;
2058
Willy Tarreau2beef582012-12-20 17:22:52 +01002059 case LOG_FMT_CLIENTPORT: // %cp
Willy Tarreau9ad7bd42015-04-03 19:19:59 +02002060 conn = objt_conn(sess->origin);
Willy Tarreau8fa99842019-07-17 11:47:11 +02002061 if (conn && conn_get_src(conn)) {
Willy Tarreau6c6365f2019-07-17 16:48:18 +02002062 if (conn->src->ss_family == AF_UNIX) {
Willy Tarreaufb0afa72015-04-03 14:46:27 +02002063 ret = ltoa_o(sess->listener->luid, tmplog, dst + maxsize - tmplog);
Willy Tarreaub363a1f2013-10-01 10:45:07 +02002064 } else {
Willy Tarreau6c6365f2019-07-17 16:48:18 +02002065 ret = lf_port(tmplog, (struct sockaddr *)conn->src,
Willy Tarreaub363a1f2013-10-01 10:45:07 +02002066 dst + maxsize - tmplog, tmp);
2067 }
William Lallemand5f232402012-04-05 18:02:55 +02002068 }
Willy Tarreaub363a1f2013-10-01 10:45:07 +02002069 else
2070 ret = lf_text_len(tmplog, NULL, 0, dst + maxsize - tmplog, tmp);
2071
William Lallemand5f232402012-04-05 18:02:55 +02002072 if (ret == NULL)
2073 goto out;
2074 tmplog = ret;
2075 last_isspace = 0;
2076 break;
2077
Willy Tarreau2beef582012-12-20 17:22:52 +01002078 case LOG_FMT_FRONTENDIP: // %fi
Willy Tarreau9ad7bd42015-04-03 19:19:59 +02002079 conn = objt_conn(sess->origin);
Willy Tarreau8fa99842019-07-17 11:47:11 +02002080 if (conn && conn_get_dst(conn)) {
Willy Tarreau6c6365f2019-07-17 16:48:18 +02002081 ret = lf_ip(tmplog, (struct sockaddr *)conn->dst, dst + maxsize - tmplog, tmp);
Willy Tarreaub363a1f2013-10-01 10:45:07 +02002082 }
2083 else
2084 ret = lf_text_len(tmplog, NULL, 0, dst + maxsize - tmplog, tmp);
2085
William Lallemand1d705562012-03-12 12:46:41 +01002086 if (ret == NULL)
William Lallemandbddd4fd2012-02-27 11:23:10 +01002087 goto out;
William Lallemand1d705562012-03-12 12:46:41 +01002088 tmplog = ret;
William Lallemandbddd4fd2012-02-27 11:23:10 +01002089 last_isspace = 0;
2090 break;
2091
Willy Tarreau2beef582012-12-20 17:22:52 +01002092 case LOG_FMT_FRONTENDPORT: // %fp
Willy Tarreau9ad7bd42015-04-03 19:19:59 +02002093 conn = objt_conn(sess->origin);
Willy Tarreau8fa99842019-07-17 11:47:11 +02002094 if (conn && conn_get_dst(conn)) {
Willy Tarreau6c6365f2019-07-17 16:48:18 +02002095 if (conn->dst->ss_family == AF_UNIX)
Willy Tarreaufb0afa72015-04-03 14:46:27 +02002096 ret = ltoa_o(sess->listener->luid, tmplog, dst + maxsize - tmplog);
Willy Tarreaub363a1f2013-10-01 10:45:07 +02002097 else
Willy Tarreau6c6365f2019-07-17 16:48:18 +02002098 ret = lf_port(tmplog, (struct sockaddr *)conn->dst, dst + maxsize - tmplog, tmp);
William Lallemand5f232402012-04-05 18:02:55 +02002099 }
Willy Tarreaub363a1f2013-10-01 10:45:07 +02002100 else
2101 ret = lf_text_len(tmplog, NULL, 0, dst + maxsize - tmplog, tmp);
2102
William Lallemand5f232402012-04-05 18:02:55 +02002103 if (ret == NULL)
2104 goto out;
2105 tmplog = ret;
2106 last_isspace = 0;
2107 break;
2108
Willy Tarreau2beef582012-12-20 17:22:52 +01002109 case LOG_FMT_BACKENDIP: // %bi
Willy Tarreau8fa99842019-07-17 11:47:11 +02002110 if (be_conn && conn_get_src(be_conn))
Willy Tarreau6c6365f2019-07-17 16:48:18 +02002111 ret = lf_ip(tmplog, (const struct sockaddr *)be_conn->src, dst + maxsize - tmplog, tmp);
Willy Tarreaub363a1f2013-10-01 10:45:07 +02002112 else
2113 ret = lf_text_len(tmplog, NULL, 0, dst + maxsize - tmplog, tmp);
2114
William Lallemand1d705562012-03-12 12:46:41 +01002115 if (ret == NULL)
William Lallemandb7ff6a32012-03-02 14:35:21 +01002116 goto out;
William Lallemand1d705562012-03-12 12:46:41 +01002117 tmplog = ret;
William Lallemandb7ff6a32012-03-02 14:35:21 +01002118 last_isspace = 0;
2119 break;
2120
Willy Tarreau2beef582012-12-20 17:22:52 +01002121 case LOG_FMT_BACKENDPORT: // %bp
Willy Tarreau8fa99842019-07-17 11:47:11 +02002122 if (be_conn && conn_get_src(be_conn))
Willy Tarreau6c6365f2019-07-17 16:48:18 +02002123 ret = lf_port(tmplog, (struct sockaddr *)be_conn->src, dst + maxsize - tmplog, tmp);
Willy Tarreaub363a1f2013-10-01 10:45:07 +02002124 else
2125 ret = lf_text_len(tmplog, NULL, 0, dst + maxsize - tmplog, tmp);
2126
William Lallemand5f232402012-04-05 18:02:55 +02002127 if (ret == NULL)
2128 goto out;
2129 tmplog = ret;
2130 last_isspace = 0;
2131 break;
2132
Willy Tarreau2beef582012-12-20 17:22:52 +01002133 case LOG_FMT_SERVERIP: // %si
Willy Tarreau8fa99842019-07-17 11:47:11 +02002134 if (be_conn && conn_get_dst(be_conn))
Willy Tarreau6c6365f2019-07-17 16:48:18 +02002135 ret = lf_ip(tmplog, (struct sockaddr *)be_conn->dst, dst + maxsize - tmplog, tmp);
Willy Tarreaub363a1f2013-10-01 10:45:07 +02002136 else
2137 ret = lf_text_len(tmplog, NULL, 0, dst + maxsize - tmplog, tmp);
2138
William Lallemand5f232402012-04-05 18:02:55 +02002139 if (ret == NULL)
2140 goto out;
2141 tmplog = ret;
2142 last_isspace = 0;
2143 break;
2144
Willy Tarreau2beef582012-12-20 17:22:52 +01002145 case LOG_FMT_SERVERPORT: // %sp
Willy Tarreau8fa99842019-07-17 11:47:11 +02002146 if (be_conn && conn_get_dst(be_conn))
Willy Tarreau6c6365f2019-07-17 16:48:18 +02002147 ret = lf_port(tmplog, (struct sockaddr *)be_conn->dst, dst + maxsize - tmplog, tmp);
Willy Tarreaub363a1f2013-10-01 10:45:07 +02002148 else
2149 ret = lf_text_len(tmplog, NULL, 0, dst + maxsize - tmplog, tmp);
2150
William Lallemand1d705562012-03-12 12:46:41 +01002151 if (ret == NULL)
William Lallemandb7ff6a32012-03-02 14:35:21 +01002152 goto out;
William Lallemand1d705562012-03-12 12:46:41 +01002153 tmplog = ret;
William Lallemandb7ff6a32012-03-02 14:35:21 +01002154 last_isspace = 0;
2155 break;
2156
Thierry FOURNIER / OZON.IO4cac3592016-07-28 17:19:45 +02002157 case LOG_FMT_DATE: // %t = accept date
Willy Tarreau372ac5a2018-09-05 15:16:23 +02002158 get_localtime(logs->accept_date.tv_sec, &tm);
2159 ret = date2str_log(tmplog, &tm, &logs->accept_date, 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
Thierry FOURNIER / OZON.IO4cac3592016-07-28 17:19:45 +02002166 case LOG_FMT_tr: // %tr = start of request date
2167 /* Note that the timers are valid if we get here */
Willy Tarreau372ac5a2018-09-05 15:16:23 +02002168 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 +02002169 get_localtime(tv.tv_sec, &tm);
2170 ret = date2str_log(tmplog, &tm, &tv, dst + maxsize - tmplog);
2171 if (ret == NULL)
2172 goto out;
2173 tmplog = ret;
2174 last_isspace = 0;
2175 break;
2176
2177 case LOG_FMT_DATEGMT: // %T = accept date, GMT
Willy Tarreau372ac5a2018-09-05 15:16:23 +02002178 get_gmtime(logs->accept_date.tv_sec, &tm);
William Lallemand5f232402012-04-05 18:02:55 +02002179 ret = gmt2str_log(tmplog, &tm, dst + maxsize - tmplog);
William Lallemand1d705562012-03-12 12:46:41 +01002180 if (ret == NULL)
William Lallemandbddd4fd2012-02-27 11:23:10 +01002181 goto out;
William Lallemand1d705562012-03-12 12:46:41 +01002182 tmplog = ret;
William Lallemandbddd4fd2012-02-27 11:23:10 +01002183 last_isspace = 0;
2184 break;
2185
Thierry FOURNIER / OZON.IO4cac3592016-07-28 17:19:45 +02002186 case LOG_FMT_trg: // %trg = start of request date, GMT
Willy Tarreau372ac5a2018-09-05 15:16:23 +02002187 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 +02002188 get_gmtime(tv.tv_sec, &tm);
2189 ret = gmt2str_log(tmplog, &tm, dst + maxsize - tmplog);
2190 if (ret == NULL)
2191 goto out;
2192 tmplog = ret;
2193 last_isspace = 0;
2194 break;
2195
2196 case LOG_FMT_DATELOCAL: // %Tl = accept date, local
Willy Tarreau372ac5a2018-09-05 15:16:23 +02002197 get_localtime(logs->accept_date.tv_sec, &tm);
2198 ret = localdate2str_log(tmplog, logs->accept_date.tv_sec, &tm, dst + maxsize - tmplog);
Yuxans Yao4e25b012012-10-19 10:36:09 +08002199 if (ret == NULL)
2200 goto out;
2201 tmplog = ret;
2202 last_isspace = 0;
2203 break;
2204
Thierry FOURNIER / OZON.IO4cac3592016-07-28 17:19:45 +02002205 case LOG_FMT_trl: // %trl = start of request date, local
Willy Tarreau372ac5a2018-09-05 15:16:23 +02002206 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 +02002207 get_localtime(tv.tv_sec, &tm);
2208 ret = localdate2str_log(tmplog, tv.tv_sec, &tm, dst + maxsize - tmplog);
2209 if (ret == NULL)
2210 goto out;
2211 tmplog = ret;
2212 last_isspace = 0;
2213 break;
2214
William Lallemand5f232402012-04-05 18:02:55 +02002215 case LOG_FMT_TS: // %Ts
William Lallemand5f232402012-04-05 18:02:55 +02002216 if (tmp->options & LOG_OPT_HEXA) {
Willy Tarreau372ac5a2018-09-05 15:16:23 +02002217 iret = snprintf(tmplog, dst + maxsize - tmplog, "%04X", (unsigned int)logs->accept_date.tv_sec);
William Lallemand5f232402012-04-05 18:02:55 +02002218 if (iret < 0 || iret > dst + maxsize - tmplog)
2219 goto out;
2220 last_isspace = 0;
2221 tmplog += iret;
2222 } else {
Willy Tarreau372ac5a2018-09-05 15:16:23 +02002223 ret = ltoa_o(logs->accept_date.tv_sec, tmplog, dst + maxsize - tmplog);
William Lallemand5f232402012-04-05 18:02:55 +02002224 if (ret == NULL)
2225 goto out;
2226 tmplog = ret;
2227 last_isspace = 0;
2228 }
2229 break;
2230
William Lallemand1d705562012-03-12 12:46:41 +01002231 case LOG_FMT_MS: // %ms
William Lallemand5f232402012-04-05 18:02:55 +02002232 if (tmp->options & LOG_OPT_HEXA) {
Willy Tarreau372ac5a2018-09-05 15:16:23 +02002233 iret = snprintf(tmplog, dst + maxsize - tmplog, "%02X",(unsigned int)logs->accept_date.tv_usec/1000);
William Lallemand5f232402012-04-05 18:02:55 +02002234 if (iret < 0 || iret > dst + maxsize - tmplog)
2235 goto out;
2236 last_isspace = 0;
2237 tmplog += iret;
2238 } else {
2239 if ((dst + maxsize - tmplog) < 4)
William Lallemandbddd4fd2012-02-27 11:23:10 +01002240 goto out;
Willy Tarreau372ac5a2018-09-05 15:16:23 +02002241 ret = utoa_pad((unsigned int)logs->accept_date.tv_usec/1000,
Willy Tarreau9e60cd82013-01-24 01:18:16 +01002242 tmplog, 4);
2243 if (ret == NULL)
William Lallemand51b5dca2012-03-26 17:52:55 +02002244 goto out;
Willy Tarreau9e60cd82013-01-24 01:18:16 +01002245 tmplog = ret;
William Lallemandbddd4fd2012-02-27 11:23:10 +01002246 last_isspace = 0;
William Lallemand5f232402012-04-05 18:02:55 +02002247 }
2248 break;
William Lallemandbddd4fd2012-02-27 11:23:10 +01002249
William Lallemand1d705562012-03-12 12:46:41 +01002250 case LOG_FMT_FRONTEND: // %f
William Lallemandbddd4fd2012-02-27 11:23:10 +01002251 src = fe->id;
William Lallemand5f232402012-04-05 18:02:55 +02002252 ret = lf_text(tmplog, src, dst + maxsize - tmplog, tmp);
William Lallemand1d705562012-03-12 12:46:41 +01002253 if (ret == NULL)
William Lallemandbddd4fd2012-02-27 11:23:10 +01002254 goto out;
William Lallemand1d705562012-03-12 12:46:41 +01002255 tmplog = ret;
William Lallemand51b5dca2012-03-26 17:52:55 +02002256 last_isspace = 0;
William Lallemandbddd4fd2012-02-27 11:23:10 +01002257 break;
2258
Willy Tarreau773d65f2012-10-12 14:56:11 +02002259 case LOG_FMT_FRONTEND_XPRT: // %ft
2260 src = fe->id;
2261 if (tmp->options & LOG_OPT_QUOTE)
2262 LOGCHAR('"');
2263 iret = strlcpy2(tmplog, src, dst + maxsize - tmplog);
2264 if (iret == 0)
2265 goto out;
2266 tmplog += iret;
Willy Tarreaua261e9b2016-12-22 20:44:00 +01002267 if (sess->listener->bind_conf->xprt == xprt_get(XPRT_SSL))
Willy Tarreau773d65f2012-10-12 14:56:11 +02002268 LOGCHAR('~');
Willy Tarreau773d65f2012-10-12 14:56:11 +02002269 if (tmp->options & LOG_OPT_QUOTE)
2270 LOGCHAR('"');
2271 last_isspace = 0;
2272 break;
Willy Tarreauffc3fcd2012-10-12 20:17:54 +02002273#ifdef USE_OPENSSL
2274 case LOG_FMT_SSL_CIPHER: // %sslc
2275 src = NULL;
Willy Tarreau9ad7bd42015-04-03 19:19:59 +02002276 conn = objt_conn(sess->origin);
Willy Tarreaub363a1f2013-10-01 10:45:07 +02002277 if (conn) {
Emmanuel Hocdet01da5712017-10-13 16:59:49 +02002278 src = ssl_sock_get_cipher_name(conn);
Willy Tarreaub363a1f2013-10-01 10:45:07 +02002279 }
Willy Tarreauffc3fcd2012-10-12 20:17:54 +02002280 ret = lf_text(tmplog, src, dst + maxsize - tmplog, tmp);
2281 if (ret == NULL)
2282 goto out;
2283 tmplog = ret;
2284 last_isspace = 0;
2285 break;
Willy Tarreau773d65f2012-10-12 14:56:11 +02002286
Willy Tarreauffc3fcd2012-10-12 20:17:54 +02002287 case LOG_FMT_SSL_VERSION: // %sslv
2288 src = NULL;
Willy Tarreau9ad7bd42015-04-03 19:19:59 +02002289 conn = objt_conn(sess->origin);
Willy Tarreaub363a1f2013-10-01 10:45:07 +02002290 if (conn) {
Emmanuel Hocdet01da5712017-10-13 16:59:49 +02002291 src = ssl_sock_get_proto_version(conn);
Willy Tarreaub363a1f2013-10-01 10:45:07 +02002292 }
Willy Tarreauffc3fcd2012-10-12 20:17:54 +02002293 ret = lf_text(tmplog, src, dst + maxsize - tmplog, tmp);
2294 if (ret == NULL)
2295 goto out;
2296 tmplog = ret;
2297 last_isspace = 0;
2298 break;
2299#endif
William Lallemand1d705562012-03-12 12:46:41 +01002300 case LOG_FMT_BACKEND: // %b
William Lallemandbddd4fd2012-02-27 11:23:10 +01002301 src = be->id;
William Lallemand5f232402012-04-05 18:02:55 +02002302 ret = lf_text(tmplog, src, dst + maxsize - tmplog, tmp);
William Lallemand1d705562012-03-12 12:46:41 +01002303 if (ret == NULL)
William Lallemandbddd4fd2012-02-27 11:23:10 +01002304 goto out;
William Lallemand1d705562012-03-12 12:46:41 +01002305 tmplog = ret;
William Lallemand51b5dca2012-03-26 17:52:55 +02002306 last_isspace = 0;
William Lallemandbddd4fd2012-02-27 11:23:10 +01002307 break;
2308
William Lallemand1d705562012-03-12 12:46:41 +01002309 case LOG_FMT_SERVER: // %s
Willy Tarreaue1809df2018-09-05 15:30:16 +02002310 switch (obj_type(s ? s->target : NULL)) {
Willy Tarreaud79a3b22012-12-28 09:40:16 +01002311 case OBJ_TYPE_SERVER:
Willy Tarreau1aaf3242018-09-20 11:13:58 +02002312 src = __objt_server(s->target)->id;
Willy Tarreaud79a3b22012-12-28 09:40:16 +01002313 break;
2314 case OBJ_TYPE_APPLET:
Willy Tarreau1aaf3242018-09-20 11:13:58 +02002315 src = __objt_applet(s->target)->name;
Willy Tarreaud79a3b22012-12-28 09:40:16 +01002316 break;
2317 default:
2318 src = "<NOSRV>";
2319 break;
2320 }
William Lallemand5f232402012-04-05 18:02:55 +02002321 ret = lf_text(tmplog, src, dst + maxsize - tmplog, tmp);
William Lallemand1d705562012-03-12 12:46:41 +01002322 if (ret == NULL)
William Lallemandbddd4fd2012-02-27 11:23:10 +01002323 goto out;
William Lallemand1d705562012-03-12 12:46:41 +01002324 tmplog = ret;
William Lallemandbddd4fd2012-02-27 11:23:10 +01002325 last_isspace = 0;
2326 break;
2327
Thierry FOURNIER / OZON.IO4cac3592016-07-28 17:19:45 +02002328 case LOG_FMT_Th: // %Th = handshake time
Willy Tarreau372ac5a2018-09-05 15:16:23 +02002329 ret = ltoa_o(logs->t_handshake, tmplog, dst + maxsize - tmplog);
Thierry FOURNIER / OZON.IO4cac3592016-07-28 17:19:45 +02002330 if (ret == NULL)
2331 goto out;
2332 tmplog = ret;
2333 last_isspace = 0;
2334 break;
2335
2336 case LOG_FMT_Ti: // %Ti = HTTP idle time
Willy Tarreau372ac5a2018-09-05 15:16:23 +02002337 ret = ltoa_o(logs->t_idle, tmplog, dst + maxsize - tmplog);
Thierry FOURNIER / OZON.IO4cac3592016-07-28 17:19:45 +02002338 if (ret == NULL)
2339 goto out;
2340 tmplog = ret;
2341 last_isspace = 0;
2342 break;
2343
2344 case LOG_FMT_TR: // %TR = HTTP request time
Willy Tarreau372ac5a2018-09-05 15:16:23 +02002345 ret = ltoa_o((t_request >= 0) ? t_request - logs->t_idle - logs->t_handshake : -1,
Thierry FOURNIER / OZON.IO4cac3592016-07-28 17:19:45 +02002346 tmplog, dst + maxsize - tmplog);
2347 if (ret == NULL)
2348 goto out;
2349 tmplog = ret;
2350 last_isspace = 0;
2351 break;
2352
2353 case LOG_FMT_TQ: // %Tq = Th + Ti + TR
William Lallemand5f232402012-04-05 18:02:55 +02002354 ret = ltoa_o(t_request, tmplog, dst + maxsize - tmplog);
William Lallemand1d705562012-03-12 12:46:41 +01002355 if (ret == NULL)
William Lallemandbddd4fd2012-02-27 11:23:10 +01002356 goto out;
William Lallemand1d705562012-03-12 12:46:41 +01002357 tmplog = ret;
William Lallemandbddd4fd2012-02-27 11:23:10 +01002358 last_isspace = 0;
2359 break;
2360
William Lallemand1d705562012-03-12 12:46:41 +01002361 case LOG_FMT_TW: // %Tw
Willy Tarreau372ac5a2018-09-05 15:16:23 +02002362 ret = ltoa_o((logs->t_queue >= 0) ? logs->t_queue - t_request : -1,
William Lallemand5f232402012-04-05 18:02:55 +02002363 tmplog, dst + maxsize - tmplog);
William Lallemand1d705562012-03-12 12:46:41 +01002364 if (ret == NULL)
William Lallemandbddd4fd2012-02-27 11:23:10 +01002365 goto out;
William Lallemand1d705562012-03-12 12:46:41 +01002366 tmplog = ret;
William Lallemandbddd4fd2012-02-27 11:23:10 +01002367 last_isspace = 0;
2368 break;
2369
William Lallemand1d705562012-03-12 12:46:41 +01002370 case LOG_FMT_TC: // %Tc
Willy Tarreau372ac5a2018-09-05 15:16:23 +02002371 ret = ltoa_o((logs->t_connect >= 0) ? logs->t_connect - logs->t_queue : -1,
William Lallemand5f232402012-04-05 18:02:55 +02002372 tmplog, dst + maxsize - tmplog);
William Lallemand1d705562012-03-12 12:46:41 +01002373 if (ret == NULL)
William Lallemandbddd4fd2012-02-27 11:23:10 +01002374 goto out;
William Lallemand1d705562012-03-12 12:46:41 +01002375 tmplog = ret;
William Lallemandbddd4fd2012-02-27 11:23:10 +01002376 last_isspace = 0;
2377 break;
2378
Thierry FOURNIER / OZON.IO4cac3592016-07-28 17:19:45 +02002379 case LOG_FMT_Tr: // %Tr
Willy Tarreau372ac5a2018-09-05 15:16:23 +02002380 ret = ltoa_o((logs->t_data >= 0) ? logs->t_data - logs->t_connect : -1,
William Lallemand5f232402012-04-05 18:02:55 +02002381 tmplog, dst + maxsize - tmplog);
William Lallemand1d705562012-03-12 12:46:41 +01002382 if (ret == NULL)
William Lallemandbddd4fd2012-02-27 11:23:10 +01002383 goto out;
William Lallemand1d705562012-03-12 12:46:41 +01002384 tmplog = ret;
William Lallemandbddd4fd2012-02-27 11:23:10 +01002385 last_isspace = 0;
2386 break;
2387
Willy Tarreau27b639d2016-05-17 17:55:27 +02002388 case LOG_FMT_TD: // %Td
Willy Tarreaua21c0e62018-09-05 15:07:15 +02002389 if (be->mode == PR_MODE_HTTP)
Willy Tarreau372ac5a2018-09-05 15:16:23 +02002390 ret = ltoa_o((logs->t_data >= 0) ? logs->t_close - logs->t_data : -1,
Willy Tarreau27b639d2016-05-17 17:55:27 +02002391 tmplog, dst + maxsize - tmplog);
2392 else
Willy Tarreau372ac5a2018-09-05 15:16:23 +02002393 ret = ltoa_o((logs->t_connect >= 0) ? logs->t_close - logs->t_connect : -1,
Willy Tarreau27b639d2016-05-17 17:55:27 +02002394 tmplog, dst + maxsize - tmplog);
2395 if (ret == NULL)
2396 goto out;
2397 tmplog = ret;
2398 last_isspace = 0;
2399 break;
2400
Thierry FOURNIER / OZON.IO4cac3592016-07-28 17:19:45 +02002401 case LOG_FMT_Ta: // %Ta = active time = Tt - Th - Ti
2402 if (!(fe->to_log & LW_BYTES))
2403 LOGCHAR('+');
Willy Tarreau372ac5a2018-09-05 15:16:23 +02002404 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 +02002405 tmplog, dst + maxsize - tmplog);
2406 if (ret == NULL)
2407 goto out;
2408 tmplog = ret;
2409 last_isspace = 0;
2410 break;
2411
2412 case LOG_FMT_TT: // %Tt = total time
Willy Tarreaud79a3b22012-12-28 09:40:16 +01002413 if (!(fe->to_log & LW_BYTES))
William Lallemand1d705562012-03-12 12:46:41 +01002414 LOGCHAR('+');
Willy Tarreau372ac5a2018-09-05 15:16:23 +02002415 ret = ltoa_o(logs->t_close, tmplog, dst + maxsize - tmplog);
William Lallemand1d705562012-03-12 12:46:41 +01002416 if (ret == NULL)
William Lallemandbddd4fd2012-02-27 11:23:10 +01002417 goto out;
William Lallemand1d705562012-03-12 12:46:41 +01002418 tmplog = ret;
William Lallemandbddd4fd2012-02-27 11:23:10 +01002419 last_isspace = 0;
2420 break;
2421
Willy Tarreau2beef582012-12-20 17:22:52 +01002422 case LOG_FMT_STATUS: // %ST
Willy Tarreau57bc8912016-04-25 17:09:40 +02002423 ret = ltoa_o(txn ? txn->status : 0, tmplog, dst + maxsize - tmplog);
William Lallemand1d705562012-03-12 12:46:41 +01002424 if (ret == NULL)
William Lallemandbddd4fd2012-02-27 11:23:10 +01002425 goto out;
William Lallemand1d705562012-03-12 12:46:41 +01002426 tmplog = ret;
William Lallemandbddd4fd2012-02-27 11:23:10 +01002427 last_isspace = 0;
2428 break;
2429
William Lallemand1d705562012-03-12 12:46:41 +01002430 case LOG_FMT_BYTES: // %B
Willy Tarreaud79a3b22012-12-28 09:40:16 +01002431 if (!(fe->to_log & LW_BYTES))
William Lallemand1d705562012-03-12 12:46:41 +01002432 LOGCHAR('+');
Willy Tarreau372ac5a2018-09-05 15:16:23 +02002433 ret = lltoa(logs->bytes_out, tmplog, dst + maxsize - tmplog);
William Lallemand1d705562012-03-12 12:46:41 +01002434 if (ret == NULL)
William Lallemandbddd4fd2012-02-27 11:23:10 +01002435 goto out;
William Lallemand1d705562012-03-12 12:46:41 +01002436 tmplog = ret;
William Lallemandbddd4fd2012-02-27 11:23:10 +01002437 last_isspace = 0;
2438 break;
2439
Willy Tarreauc5259fd2012-12-20 15:38:04 +01002440 case LOG_FMT_BYTES_UP: // %U
Willy Tarreau372ac5a2018-09-05 15:16:23 +02002441 ret = lltoa(logs->bytes_in, tmplog, dst + maxsize - tmplog);
Willy Tarreauc5259fd2012-12-20 15:38:04 +01002442 if (ret == NULL)
2443 goto out;
2444 tmplog = ret;
2445 last_isspace = 0;
2446 break;
2447
Willy Tarreau2beef582012-12-20 17:22:52 +01002448 case LOG_FMT_CCLIENT: // %CC
Willy Tarreau57bc8912016-04-25 17:09:40 +02002449 src = txn ? txn->cli_cookie : NULL;
William Lallemand5f232402012-04-05 18:02:55 +02002450 ret = lf_text(tmplog, src, dst + maxsize - tmplog, tmp);
William Lallemand1d705562012-03-12 12:46:41 +01002451 if (ret == NULL)
William Lallemand51b5dca2012-03-26 17:52:55 +02002452 goto out;
William Lallemand1d705562012-03-12 12:46:41 +01002453 tmplog = ret;
William Lallemandbddd4fd2012-02-27 11:23:10 +01002454 last_isspace = 0;
2455 break;
2456
Willy Tarreau2beef582012-12-20 17:22:52 +01002457 case LOG_FMT_CSERVER: // %CS
Willy Tarreau57bc8912016-04-25 17:09:40 +02002458 src = txn ? txn->srv_cookie : NULL;
William Lallemand5f232402012-04-05 18:02:55 +02002459 ret = lf_text(tmplog, src, dst + maxsize - tmplog, tmp);
William Lallemand1d705562012-03-12 12:46:41 +01002460 if (ret == NULL)
William Lallemand51b5dca2012-03-26 17:52:55 +02002461 goto out;
William Lallemand1d705562012-03-12 12:46:41 +01002462 tmplog = ret;
William Lallemandbddd4fd2012-02-27 11:23:10 +01002463 last_isspace = 0;
2464 break;
2465
William Lallemand1d705562012-03-12 12:46:41 +01002466 case LOG_FMT_TERMSTATE: // %ts
Willy Tarreaub8bc5252018-09-05 15:51:28 +02002467 LOGCHAR(sess_term_cond[(s_flags & SF_ERR_MASK) >> SF_ERR_SHIFT]);
2468 LOGCHAR(sess_fin_state[(s_flags & SF_FINST_MASK) >> SF_FINST_SHIFT]);
Willy Tarreau6580c062012-03-12 15:09:42 +01002469 *tmplog = '\0';
2470 last_isspace = 0;
2471 break;
William Lallemandbddd4fd2012-02-27 11:23:10 +01002472
William Lallemand1d705562012-03-12 12:46:41 +01002473 case LOG_FMT_TERMSTATE_CK: // %tsc, same as TS with cookie state (for mode HTTP)
Willy Tarreaub8bc5252018-09-05 15:51:28 +02002474 LOGCHAR(sess_term_cond[(s_flags & SF_ERR_MASK) >> SF_ERR_SHIFT]);
2475 LOGCHAR(sess_fin_state[(s_flags & SF_FINST_MASK) >> SF_FINST_SHIFT]);
Willy Tarreau57bc8912016-04-25 17:09:40 +02002476 LOGCHAR((txn && (be->ck_opts & PR_CK_ANY)) ? sess_cookie[(txn->flags & TX_CK_MASK) >> TX_CK_SHIFT] : '-');
2477 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 +01002478 last_isspace = 0;
2479 break;
2480
William Lallemand1d705562012-03-12 12:46:41 +01002481 case LOG_FMT_ACTCONN: // %ac
William Lallemand5f232402012-04-05 18:02:55 +02002482 ret = ltoa_o(actconn, tmplog, dst + maxsize - tmplog);
William Lallemand1d705562012-03-12 12:46:41 +01002483 if (ret == NULL)
William Lallemandbddd4fd2012-02-27 11:23:10 +01002484 goto out;
William Lallemand1d705562012-03-12 12:46:41 +01002485 tmplog = ret;
William Lallemandbddd4fd2012-02-27 11:23:10 +01002486 last_isspace = 0;
2487 break;
2488
William Lallemand1d705562012-03-12 12:46:41 +01002489 case LOG_FMT_FECONN: // %fc
William Lallemand5f232402012-04-05 18:02:55 +02002490 ret = ltoa_o(fe->feconn, tmplog, dst + maxsize - tmplog);
William Lallemand1d705562012-03-12 12:46:41 +01002491 if (ret == NULL)
William Lallemandbddd4fd2012-02-27 11:23:10 +01002492 goto out;
William Lallemand1d705562012-03-12 12:46:41 +01002493 tmplog = ret;
William Lallemandbddd4fd2012-02-27 11:23:10 +01002494 last_isspace = 0;
2495 break;
2496
William Lallemand1d705562012-03-12 12:46:41 +01002497 case LOG_FMT_BECONN: // %bc
William Lallemand5f232402012-04-05 18:02:55 +02002498 ret = ltoa_o(be->beconn, tmplog, dst + maxsize - tmplog);
William Lallemand1d705562012-03-12 12:46:41 +01002499 if (ret == NULL)
William Lallemandbddd4fd2012-02-27 11:23:10 +01002500 goto out;
William Lallemand1d705562012-03-12 12:46:41 +01002501 tmplog = ret;
William Lallemandbddd4fd2012-02-27 11:23:10 +01002502 last_isspace = 0;
2503 break;
2504
William Lallemand1d705562012-03-12 12:46:41 +01002505 case LOG_FMT_SRVCONN: // %sc
Willy Tarreaue1809df2018-09-05 15:30:16 +02002506 ret = ultoa_o(objt_server(s ? s->target : NULL) ?
Willy Tarreau3fdb3662012-11-12 00:42:33 +01002507 objt_server(s->target)->cur_sess :
William Lallemand5f232402012-04-05 18:02:55 +02002508 0, tmplog, dst + maxsize - tmplog);
William Lallemand1d705562012-03-12 12:46:41 +01002509 if (ret == NULL)
William Lallemandbddd4fd2012-02-27 11:23:10 +01002510 goto out;
William Lallemand1d705562012-03-12 12:46:41 +01002511 tmplog = ret;
William Lallemandbddd4fd2012-02-27 11:23:10 +01002512 last_isspace = 0;
2513 break;
2514
William Lallemand1d705562012-03-12 12:46:41 +01002515 case LOG_FMT_RETRIES: // %rq
Willy Tarreaub8bc5252018-09-05 15:51:28 +02002516 if (s_flags & SF_REDISP)
William Lallemand1d705562012-03-12 12:46:41 +01002517 LOGCHAR('+');
Willy Tarreauabd71a52018-09-04 19:21:44 +02002518 ret = ltoa_o((s && s->si[1].conn_retries > 0) ?
Willy Tarreau350f4872014-11-28 14:42:25 +01002519 (be->conn_retries - s->si[1].conn_retries) :
William Lallemand5f232402012-04-05 18:02:55 +02002520 be->conn_retries, tmplog, dst + maxsize - tmplog);
William Lallemand1d705562012-03-12 12:46:41 +01002521 if (ret == NULL)
William Lallemand51b5dca2012-03-26 17:52:55 +02002522 goto out;
William Lallemand1d705562012-03-12 12:46:41 +01002523 tmplog = ret;
William Lallemandbddd4fd2012-02-27 11:23:10 +01002524 last_isspace = 0;
2525 break;
2526
William Lallemand1d705562012-03-12 12:46:41 +01002527 case LOG_FMT_SRVQUEUE: // %sq
Willy Tarreau372ac5a2018-09-05 15:16:23 +02002528 ret = ltoa_o(logs->srv_queue_pos, tmplog, dst + maxsize - tmplog);
William Lallemand1d705562012-03-12 12:46:41 +01002529 if (ret == NULL)
William Lallemandbddd4fd2012-02-27 11:23:10 +01002530 goto out;
William Lallemand1d705562012-03-12 12:46:41 +01002531 tmplog = ret;
William Lallemandbddd4fd2012-02-27 11:23:10 +01002532 last_isspace = 0;
2533 break;
2534
William Lallemand1d705562012-03-12 12:46:41 +01002535 case LOG_FMT_BCKQUEUE: // %bq
Willy Tarreau372ac5a2018-09-05 15:16:23 +02002536 ret = ltoa_o(logs->prx_queue_pos, tmplog, dst + maxsize - tmplog);
William Lallemand1d705562012-03-12 12:46:41 +01002537 if (ret == NULL)
William Lallemandbddd4fd2012-02-27 11:23:10 +01002538 goto out;
William Lallemand1d705562012-03-12 12:46:41 +01002539 tmplog = ret;
William Lallemandbddd4fd2012-02-27 11:23:10 +01002540 last_isspace = 0;
2541 break;
2542
William Lallemand1d705562012-03-12 12:46:41 +01002543 case LOG_FMT_HDRREQUEST: // %hr
William Lallemandbddd4fd2012-02-27 11:23:10 +01002544 /* request header */
Willy Tarreaud4f91662018-09-05 15:28:07 +02002545 if (fe->nb_req_cap && s && s->req_cap) {
William Lallemandbddd4fd2012-02-27 11:23:10 +01002546 if (tmp->options & LOG_OPT_QUOTE)
2547 LOGCHAR('"');
2548 LOGCHAR('{');
2549 for (hdr = 0; hdr < fe->nb_req_cap; hdr++) {
2550 if (hdr)
2551 LOGCHAR('|');
Willy Tarreaucb7dd012015-04-03 22:16:32 +02002552 if (s->req_cap[hdr] != NULL) {
Dragan Dosen835b9212016-02-12 13:23:03 +01002553 ret = lf_encode_string(tmplog, dst + maxsize,
2554 '#', hdr_encode_map, s->req_cap[hdr], tmp);
William Lallemand1d705562012-03-12 12:46:41 +01002555 if (ret == NULL || *ret != '\0')
William Lallemand51b5dca2012-03-26 17:52:55 +02002556 goto out;
William Lallemand1d705562012-03-12 12:46:41 +01002557 tmplog = ret;
William Lallemand51b5dca2012-03-26 17:52:55 +02002558 }
William Lallemandbddd4fd2012-02-27 11:23:10 +01002559 }
2560 LOGCHAR('}');
William Lallemand51b5dca2012-03-26 17:52:55 +02002561 if (tmp->options & LOG_OPT_QUOTE)
2562 LOGCHAR('"');
William Lallemandbddd4fd2012-02-27 11:23:10 +01002563 last_isspace = 0;
2564 }
William Lallemandbddd4fd2012-02-27 11:23:10 +01002565 break;
2566
William Lallemand1d705562012-03-12 12:46:41 +01002567 case LOG_FMT_HDRREQUESTLIST: // %hrl
William Lallemandbddd4fd2012-02-27 11:23:10 +01002568 /* request header list */
Willy Tarreaud4f91662018-09-05 15:28:07 +02002569 if (fe->nb_req_cap && s && s->req_cap) {
William Lallemandbddd4fd2012-02-27 11:23:10 +01002570 for (hdr = 0; hdr < fe->nb_req_cap; hdr++) {
2571 if (hdr > 0)
2572 LOGCHAR(' ');
2573 if (tmp->options & LOG_OPT_QUOTE)
2574 LOGCHAR('"');
Willy Tarreaucb7dd012015-04-03 22:16:32 +02002575 if (s->req_cap[hdr] != NULL) {
Dragan Dosen835b9212016-02-12 13:23:03 +01002576 ret = lf_encode_string(tmplog, dst + maxsize,
2577 '#', hdr_encode_map, s->req_cap[hdr], tmp);
William Lallemand1d705562012-03-12 12:46:41 +01002578 if (ret == NULL || *ret != '\0')
William Lallemand51b5dca2012-03-26 17:52:55 +02002579 goto out;
William Lallemand1d705562012-03-12 12:46:41 +01002580 tmplog = ret;
William Lallemandbddd4fd2012-02-27 11:23:10 +01002581 } else if (!(tmp->options & LOG_OPT_QUOTE))
2582 LOGCHAR('-');
2583 if (tmp->options & LOG_OPT_QUOTE)
2584 LOGCHAR('"');
William Lallemandbddd4fd2012-02-27 11:23:10 +01002585 last_isspace = 0;
2586 }
2587 }
2588 break;
Willy Tarreaubaaee002006-06-26 02:48:02 +02002589
William Lallemand1d705562012-03-12 12:46:41 +01002590
2591 case LOG_FMT_HDRRESPONS: // %hs
William Lallemandbddd4fd2012-02-27 11:23:10 +01002592 /* response header */
Willy Tarreaud4f91662018-09-05 15:28:07 +02002593 if (fe->nb_rsp_cap && s && s->res_cap) {
William Lallemandbddd4fd2012-02-27 11:23:10 +01002594 if (tmp->options & LOG_OPT_QUOTE)
2595 LOGCHAR('"');
2596 LOGCHAR('{');
2597 for (hdr = 0; hdr < fe->nb_rsp_cap; hdr++) {
2598 if (hdr)
2599 LOGCHAR('|');
Willy Tarreaucb7dd012015-04-03 22:16:32 +02002600 if (s->res_cap[hdr] != NULL) {
Dragan Dosen835b9212016-02-12 13:23:03 +01002601 ret = lf_encode_string(tmplog, dst + maxsize,
2602 '#', hdr_encode_map, s->res_cap[hdr], tmp);
William Lallemand1d705562012-03-12 12:46:41 +01002603 if (ret == NULL || *ret != '\0')
William Lallemand51b5dca2012-03-26 17:52:55 +02002604 goto out;
William Lallemand1d705562012-03-12 12:46:41 +01002605 tmplog = ret;
William Lallemand51b5dca2012-03-26 17:52:55 +02002606 }
William Lallemandbddd4fd2012-02-27 11:23:10 +01002607 }
2608 LOGCHAR('}');
2609 last_isspace = 0;
2610 if (tmp->options & LOG_OPT_QUOTE)
2611 LOGCHAR('"');
2612 }
William Lallemandbddd4fd2012-02-27 11:23:10 +01002613 break;
2614
William Lallemand1d705562012-03-12 12:46:41 +01002615 case LOG_FMT_HDRRESPONSLIST: // %hsl
William Lallemandbddd4fd2012-02-27 11:23:10 +01002616 /* response header list */
Willy Tarreaud4f91662018-09-05 15:28:07 +02002617 if (fe->nb_rsp_cap && s && s->res_cap) {
William Lallemandbddd4fd2012-02-27 11:23:10 +01002618 for (hdr = 0; hdr < fe->nb_rsp_cap; hdr++) {
2619 if (hdr > 0)
2620 LOGCHAR(' ');
2621 if (tmp->options & LOG_OPT_QUOTE)
2622 LOGCHAR('"');
Willy Tarreaucb7dd012015-04-03 22:16:32 +02002623 if (s->res_cap[hdr] != NULL) {
Dragan Dosen835b9212016-02-12 13:23:03 +01002624 ret = lf_encode_string(tmplog, dst + maxsize,
2625 '#', hdr_encode_map, s->res_cap[hdr], tmp);
William Lallemand1d705562012-03-12 12:46:41 +01002626 if (ret == NULL || *ret != '\0')
William Lallemand51b5dca2012-03-26 17:52:55 +02002627 goto out;
William Lallemand1d705562012-03-12 12:46:41 +01002628 tmplog = ret;
William Lallemandbddd4fd2012-02-27 11:23:10 +01002629 } else if (!(tmp->options & LOG_OPT_QUOTE))
2630 LOGCHAR('-');
2631 if (tmp->options & LOG_OPT_QUOTE)
2632 LOGCHAR('"');
William Lallemandbddd4fd2012-02-27 11:23:10 +01002633 last_isspace = 0;
2634 }
2635 }
2636 break;
2637
William Lallemand1d705562012-03-12 12:46:41 +01002638 case LOG_FMT_REQ: // %r
William Lallemandbddd4fd2012-02-27 11:23:10 +01002639 /* Request */
2640 if (tmp->options & LOG_OPT_QUOTE)
2641 LOGCHAR('"');
Willy Tarreau57bc8912016-04-25 17:09:40 +02002642 uri = txn && txn->uri ? txn->uri : "<BADREQ>";
Dragan Dosen835b9212016-02-12 13:23:03 +01002643 ret = lf_encode_string(tmplog, dst + maxsize,
2644 '#', url_encode_map, uri, tmp);
William Lallemand1d705562012-03-12 12:46:41 +01002645 if (ret == NULL || *ret != '\0')
William Lallemand51b5dca2012-03-26 17:52:55 +02002646 goto out;
William Lallemand1d705562012-03-12 12:46:41 +01002647 tmplog = ret;
William Lallemandbddd4fd2012-02-27 11:23:10 +01002648 if (tmp->options & LOG_OPT_QUOTE)
2649 LOGCHAR('"');
William Lallemandbddd4fd2012-02-27 11:23:10 +01002650 last_isspace = 0;
2651 break;
William Lallemand5f232402012-04-05 18:02:55 +02002652
Andrew Hayworth0ebc55f2015-04-27 21:37:03 +00002653 case LOG_FMT_HTTP_PATH: // %HP
Willy Tarreau57bc8912016-04-25 17:09:40 +02002654 uri = txn && txn->uri ? txn->uri : "<BADREQ>";
Andrew Hayworth0ebc55f2015-04-27 21:37:03 +00002655
Willy Tarreaub7636d12015-06-17 19:58:02 +02002656 if (tmp->options & LOG_OPT_QUOTE)
Andrew Hayworth0ebc55f2015-04-27 21:37:03 +00002657 LOGCHAR('"');
2658
2659 end = uri + strlen(uri);
2660 // look for the first whitespace character
2661 while (uri < end && !HTTP_IS_SPHT(*uri))
2662 uri++;
2663
2664 // keep advancing past multiple spaces
2665 while (uri < end && HTTP_IS_SPHT(*uri)) {
2666 uri++; nspaces++;
2667 }
2668
2669 // look for first space or question mark after url
2670 spc = uri;
2671 while (spc < end && *spc != '?' && !HTTP_IS_SPHT(*spc))
2672 spc++;
2673
Nenad Merdanovic54e439f2016-04-26 01:39:02 +02002674 if (!txn || !txn->uri || nspaces == 0) {
Willy Tarreau843b7cb2018-07-13 10:54:26 +02002675 chunk.area = "<BADREQ>";
2676 chunk.data = strlen("<BADREQ>");
Andrew Hayworth0ebc55f2015-04-27 21:37:03 +00002677 } else {
Willy Tarreau843b7cb2018-07-13 10:54:26 +02002678 chunk.area = uri;
2679 chunk.data = spc - uri;
Andrew Hayworth0ebc55f2015-04-27 21:37:03 +00002680 }
2681
Dragan Dosen835b9212016-02-12 13:23:03 +01002682 ret = lf_encode_chunk(tmplog, dst + maxsize, '#', url_encode_map, &chunk, tmp);
Andrew Hayworth0ebc55f2015-04-27 21:37:03 +00002683 if (ret == NULL || *ret != '\0')
2684 goto out;
2685
2686 tmplog = ret;
Willy Tarreaub7636d12015-06-17 19:58:02 +02002687 if (tmp->options & LOG_OPT_QUOTE)
Andrew Hayworth0ebc55f2015-04-27 21:37:03 +00002688 LOGCHAR('"');
2689
2690 last_isspace = 0;
2691 break;
2692
Andrew Hayworthe63ac872015-07-31 16:14:16 +00002693 case LOG_FMT_HTTP_QUERY: // %HQ
2694 if (tmp->options & LOG_OPT_QUOTE)
2695 LOGCHAR('"');
2696
Willy Tarreau57bc8912016-04-25 17:09:40 +02002697 if (!txn || !txn->uri) {
Willy Tarreau843b7cb2018-07-13 10:54:26 +02002698 chunk.area = "<BADREQ>";
2699 chunk.data = strlen("<BADREQ>");
Andrew Hayworthe63ac872015-07-31 16:14:16 +00002700 } else {
2701 uri = txn->uri;
2702 end = uri + strlen(uri);
2703 // look for the first question mark
2704 while (uri < end && *uri != '?')
2705 uri++;
2706
2707 qmark = uri;
2708 // look for first space or question mark after url
2709 while (uri < end && !HTTP_IS_SPHT(*uri))
2710 uri++;
2711
Willy Tarreau843b7cb2018-07-13 10:54:26 +02002712 chunk.area = qmark;
2713 chunk.data = uri - qmark;
Andrew Hayworthe63ac872015-07-31 16:14:16 +00002714 }
2715
Dragan Dosen835b9212016-02-12 13:23:03 +01002716 ret = lf_encode_chunk(tmplog, dst + maxsize, '#', url_encode_map, &chunk, tmp);
Andrew Hayworthe63ac872015-07-31 16:14:16 +00002717 if (ret == NULL || *ret != '\0')
2718 goto out;
2719
2720 tmplog = ret;
2721 if (tmp->options & LOG_OPT_QUOTE)
2722 LOGCHAR('"');
2723
2724 last_isspace = 0;
2725 break;
2726
Andrew Hayworth0ebc55f2015-04-27 21:37:03 +00002727 case LOG_FMT_HTTP_URI: // %HU
Willy Tarreau57bc8912016-04-25 17:09:40 +02002728 uri = txn && txn->uri ? txn->uri : "<BADREQ>";
Andrew Hayworth0ebc55f2015-04-27 21:37:03 +00002729
Willy Tarreaub7636d12015-06-17 19:58:02 +02002730 if (tmp->options & LOG_OPT_QUOTE)
Andrew Hayworth0ebc55f2015-04-27 21:37:03 +00002731 LOGCHAR('"');
2732
2733 end = uri + strlen(uri);
2734 // look for the first whitespace character
2735 while (uri < end && !HTTP_IS_SPHT(*uri))
2736 uri++;
2737
2738 // keep advancing past multiple spaces
2739 while (uri < end && HTTP_IS_SPHT(*uri)) {
2740 uri++; nspaces++;
2741 }
2742
2743 // look for first space after url
2744 spc = uri;
2745 while (spc < end && !HTTP_IS_SPHT(*spc))
2746 spc++;
2747
Willy Tarreau57bc8912016-04-25 17:09:40 +02002748 if (!txn || !txn->uri || nspaces == 0) {
Willy Tarreau843b7cb2018-07-13 10:54:26 +02002749 chunk.area = "<BADREQ>";
2750 chunk.data = strlen("<BADREQ>");
Andrew Hayworth0ebc55f2015-04-27 21:37:03 +00002751 } else {
Willy Tarreau843b7cb2018-07-13 10:54:26 +02002752 chunk.area = uri;
2753 chunk.data = spc - uri;
Andrew Hayworth0ebc55f2015-04-27 21:37:03 +00002754 }
2755
Dragan Dosen835b9212016-02-12 13:23:03 +01002756 ret = lf_encode_chunk(tmplog, dst + maxsize, '#', url_encode_map, &chunk, tmp);
Andrew Hayworth0ebc55f2015-04-27 21:37:03 +00002757 if (ret == NULL || *ret != '\0')
2758 goto out;
2759
2760 tmplog = ret;
Willy Tarreaub7636d12015-06-17 19:58:02 +02002761 if (tmp->options & LOG_OPT_QUOTE)
Andrew Hayworth0ebc55f2015-04-27 21:37:03 +00002762 LOGCHAR('"');
2763
2764 last_isspace = 0;
2765 break;
2766
2767 case LOG_FMT_HTTP_METHOD: // %HM
Willy Tarreau57bc8912016-04-25 17:09:40 +02002768 uri = txn && txn->uri ? txn->uri : "<BADREQ>";
Willy Tarreaub7636d12015-06-17 19:58:02 +02002769 if (tmp->options & LOG_OPT_QUOTE)
Andrew Hayworth0ebc55f2015-04-27 21:37:03 +00002770 LOGCHAR('"');
2771
2772 end = uri + strlen(uri);
2773 // look for the first whitespace character
2774 spc = uri;
2775 while (spc < end && !HTTP_IS_SPHT(*spc))
2776 spc++;
2777
2778 if (spc == end) { // odd case, we have txn->uri, but we only got a verb
Willy Tarreau843b7cb2018-07-13 10:54:26 +02002779 chunk.area = "<BADREQ>";
2780 chunk.data = strlen("<BADREQ>");
Andrew Hayworth0ebc55f2015-04-27 21:37:03 +00002781 } else {
Willy Tarreau843b7cb2018-07-13 10:54:26 +02002782 chunk.area = uri;
2783 chunk.data = spc - uri;
Andrew Hayworth0ebc55f2015-04-27 21:37:03 +00002784 }
2785
Dragan Dosen835b9212016-02-12 13:23:03 +01002786 ret = lf_encode_chunk(tmplog, dst + maxsize, '#', url_encode_map, &chunk, tmp);
Andrew Hayworth0ebc55f2015-04-27 21:37:03 +00002787 if (ret == NULL || *ret != '\0')
2788 goto out;
2789
2790 tmplog = ret;
Willy Tarreaub7636d12015-06-17 19:58:02 +02002791 if (tmp->options & LOG_OPT_QUOTE)
Andrew Hayworth0ebc55f2015-04-27 21:37:03 +00002792 LOGCHAR('"');
2793
2794 last_isspace = 0;
2795 break;
2796
2797 case LOG_FMT_HTTP_VERSION: // %HV
Willy Tarreau57bc8912016-04-25 17:09:40 +02002798 uri = txn && txn->uri ? txn->uri : "<BADREQ>";
Willy Tarreaub7636d12015-06-17 19:58:02 +02002799 if (tmp->options & LOG_OPT_QUOTE)
Andrew Hayworth0ebc55f2015-04-27 21:37:03 +00002800 LOGCHAR('"');
2801
2802 end = uri + strlen(uri);
2803 // look for the first whitespace character
2804 while (uri < end && !HTTP_IS_SPHT(*uri))
2805 uri++;
2806
2807 // keep advancing past multiple spaces
2808 while (uri < end && HTTP_IS_SPHT(*uri)) {
2809 uri++; nspaces++;
2810 }
2811
2812 // look for the next whitespace character
2813 while (uri < end && !HTTP_IS_SPHT(*uri))
2814 uri++;
2815
2816 // keep advancing past multiple spaces
2817 while (uri < end && HTTP_IS_SPHT(*uri))
2818 uri++;
2819
Willy Tarreau57bc8912016-04-25 17:09:40 +02002820 if (!txn || !txn->uri || nspaces == 0) {
Willy Tarreau843b7cb2018-07-13 10:54:26 +02002821 chunk.area = "<BADREQ>";
2822 chunk.data = strlen("<BADREQ>");
Andrew Hayworth0ebc55f2015-04-27 21:37:03 +00002823 } else if (uri == end) {
Willy Tarreau843b7cb2018-07-13 10:54:26 +02002824 chunk.area = "HTTP/0.9";
2825 chunk.data = strlen("HTTP/0.9");
Andrew Hayworth0ebc55f2015-04-27 21:37:03 +00002826 } else {
Willy Tarreau843b7cb2018-07-13 10:54:26 +02002827 chunk.area = uri;
2828 chunk.data = end - uri;
Andrew Hayworth0ebc55f2015-04-27 21:37:03 +00002829 }
2830
Dragan Dosen835b9212016-02-12 13:23:03 +01002831 ret = lf_encode_chunk(tmplog, dst + maxsize, '#', url_encode_map, &chunk, tmp);
Andrew Hayworth0ebc55f2015-04-27 21:37:03 +00002832 if (ret == NULL || *ret != '\0')
2833 goto out;
2834
2835 tmplog = ret;
Willy Tarreaub7636d12015-06-17 19:58:02 +02002836 if (tmp->options & LOG_OPT_QUOTE)
Andrew Hayworth0ebc55f2015-04-27 21:37:03 +00002837 LOGCHAR('"');
2838
2839 last_isspace = 0;
2840 break;
2841
William Lallemand5f232402012-04-05 18:02:55 +02002842 case LOG_FMT_COUNTER: // %rt
2843 if (tmp->options & LOG_OPT_HEXA) {
Willy Tarreau5cacab62018-09-05 15:52:59 +02002844 iret = snprintf(tmplog, dst + maxsize - tmplog, "%04X", uniq_id);
William Lallemand5f232402012-04-05 18:02:55 +02002845 if (iret < 0 || iret > dst + maxsize - tmplog)
2846 goto out;
2847 last_isspace = 0;
2848 tmplog += iret;
2849 } else {
Willy Tarreau5cacab62018-09-05 15:52:59 +02002850 ret = ltoa_o(uniq_id, tmplog, dst + maxsize - tmplog);
William Lallemand5f232402012-04-05 18:02:55 +02002851 if (ret == NULL)
2852 goto out;
2853 tmplog = ret;
2854 last_isspace = 0;
2855 }
2856 break;
2857
Willy Tarreau7346acb2014-08-28 15:03:15 +02002858 case LOG_FMT_LOGCNT: // %lc
2859 if (tmp->options & LOG_OPT_HEXA) {
Willy Tarreaue36cbcb2015-04-03 15:40:56 +02002860 iret = snprintf(tmplog, dst + maxsize - tmplog, "%04X", fe->log_count);
Willy Tarreau7346acb2014-08-28 15:03:15 +02002861 if (iret < 0 || iret > dst + maxsize - tmplog)
2862 goto out;
2863 last_isspace = 0;
2864 tmplog += iret;
2865 } else {
Willy Tarreaue36cbcb2015-04-03 15:40:56 +02002866 ret = ultoa_o(fe->log_count, tmplog, dst + maxsize - tmplog);
Willy Tarreau7346acb2014-08-28 15:03:15 +02002867 if (ret == NULL)
2868 goto out;
2869 tmplog = ret;
2870 last_isspace = 0;
2871 }
2872 break;
2873
William Lallemand5f232402012-04-05 18:02:55 +02002874 case LOG_FMT_HOSTNAME: // %H
2875 src = hostname;
2876 ret = lf_text(tmplog, src, dst + maxsize - tmplog, tmp);
2877 if (ret == NULL)
2878 goto out;
2879 tmplog = ret;
2880 last_isspace = 0;
2881 break;
2882
2883 case LOG_FMT_PID: // %pid
2884 if (tmp->options & LOG_OPT_HEXA) {
2885 iret = snprintf(tmplog, dst + maxsize - tmplog, "%04X", pid);
2886 if (iret < 0 || iret > dst + maxsize - tmplog)
2887 goto out;
2888 last_isspace = 0;
2889 tmplog += iret;
2890 } else {
2891 ret = ltoa_o(pid, tmplog, dst + maxsize - tmplog);
2892 if (ret == NULL)
2893 goto out;
2894 tmplog = ret;
2895 last_isspace = 0;
2896 }
2897 break;
William Lallemanda73203e2012-03-12 12:48:57 +01002898
2899 case LOG_FMT_UNIQUEID: // %ID
William Lallemand5b7ea3a2013-08-28 15:44:19 +02002900 ret = NULL;
Willy Tarreau02fdf4f2018-09-05 15:49:01 +02002901 src = s ? s->unique_id : NULL;
Thierry FOURNIER1be69102014-04-15 01:38:48 +02002902 ret = lf_text(tmplog, src, maxsize - (tmplog - dst), tmp);
William Lallemanda73203e2012-03-12 12:48:57 +01002903 if (ret == NULL)
2904 goto out;
2905 tmplog = ret;
2906 last_isspace = 0;
2907 break;
2908
William Lallemandbddd4fd2012-02-27 11:23:10 +01002909 }
2910 }
2911
2912out:
William Lallemand1d705562012-03-12 12:46:41 +01002913 /* *tmplog is a unused character */
2914 *tmplog = '\0';
Willy Tarreaudf974472012-12-28 02:44:01 +01002915 return tmplog - dst;
William Lallemandbddd4fd2012-02-27 11:23:10 +01002916
Willy Tarreaubaaee002006-06-26 02:48:02 +02002917}
2918
William Lallemand1d705562012-03-12 12:46:41 +01002919/*
Willy Tarreau87b09662015-04-03 00:22:06 +02002920 * send a log for the stream when we have enough info about it.
William Lallemand1d705562012-03-12 12:46:41 +01002921 * Will not log if the frontend has no log defined.
2922 */
Willy Tarreau87b09662015-04-03 00:22:06 +02002923void strm_log(struct stream *s)
William Lallemand1d705562012-03-12 12:46:41 +01002924{
Willy Tarreaue36cbcb2015-04-03 15:40:56 +02002925 struct session *sess = s->sess;
William Lallemand1d705562012-03-12 12:46:41 +01002926 int size, err, level;
Dragan Dosen0b85ece2015-09-25 19:17:44 +02002927 int sd_size = 0;
William Lallemand1d705562012-03-12 12:46:41 +01002928
2929 /* if we don't want to log normal traffic, return now */
Willy Tarreaue7dff022015-04-03 01:14:29 +02002930 err = (s->flags & SF_REDISP) ||
2931 ((s->flags & SF_ERR_MASK) > SF_ERR_LOCAL) ||
2932 (((s->flags & SF_ERR_MASK) == SF_ERR_NONE) &&
Willy Tarreau350f4872014-11-28 14:42:25 +01002933 (s->si[1].conn_retries != s->be->conn_retries)) ||
Willy Tarreaueee5b512015-04-03 23:46:31 +02002934 ((sess->fe->mode == PR_MODE_HTTP) && s->txn && s->txn->status >= 500);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002935
Willy Tarreaue36cbcb2015-04-03 15:40:56 +02002936 if (!err && (sess->fe->options2 & PR_O2_NOLOGNORM))
William Lallemand1d705562012-03-12 12:46:41 +01002937 return;
William Lallemandbddd4fd2012-02-27 11:23:10 +01002938
Willy Tarreaue36cbcb2015-04-03 15:40:56 +02002939 if (LIST_ISEMPTY(&sess->fe->logsrvs))
William Lallemand1d705562012-03-12 12:46:41 +01002940 return;
William Lallemandbddd4fd2012-02-27 11:23:10 +01002941
Willy Tarreauabcd5142013-06-11 17:18:02 +02002942 if (s->logs.level) { /* loglevel was overridden */
2943 if (s->logs.level == -1) {
2944 s->logs.logwait = 0; /* logs disabled */
2945 return;
2946 }
2947 level = s->logs.level - 1;
2948 }
2949 else {
2950 level = LOG_INFO;
Willy Tarreaue36cbcb2015-04-03 15:40:56 +02002951 if (err && (sess->fe->options2 & PR_O2_LOGERRORS))
Willy Tarreauabcd5142013-06-11 17:18:02 +02002952 level = LOG_ERR;
2953 }
William Lallemand1d705562012-03-12 12:46:41 +01002954
William Lallemand5b7ea3a2013-08-28 15:44:19 +02002955 /* if unique-id was not generated */
Willy Tarreaue36cbcb2015-04-03 15:40:56 +02002956 if (!s->unique_id && !LIST_ISEMPTY(&sess->fe->format_unique_id)) {
Willy Tarreaubafbe012017-11-24 17:34:44 +01002957 if ((s->unique_id = pool_alloc(pool_head_uniqueid)) != NULL)
Willy Tarreaue36cbcb2015-04-03 15:40:56 +02002958 build_logline(s, s->unique_id, UNIQUEID_LEN, &sess->fe->format_unique_id);
William Lallemand5b7ea3a2013-08-28 15:44:19 +02002959 }
2960
Dragan Dosen0b85ece2015-09-25 19:17:44 +02002961 if (!LIST_ISEMPTY(&sess->fe->logformat_sd)) {
2962 sd_size = build_logline(s, logline_rfc5424, global.max_syslog_len,
2963 &sess->fe->logformat_sd);
2964 }
2965
Dragan Dosen59cee972015-09-19 22:09:02 +02002966 size = build_logline(s, logline, global.max_syslog_len, &sess->fe->logformat);
William Lallemand1d705562012-03-12 12:46:41 +01002967 if (size > 0) {
Olivier Houchardd2ee3e72019-03-08 18:53:21 +01002968 _HA_ATOMIC_ADD(&sess->fe->log_count, 1);
Christopher Faulet5c6fefc2019-08-11 19:40:12 +02002969 __send_log(&sess->fe->logsrvs, &sess->fe->log_tag, level,
2970 logline, size + 1, logline_rfc5424, sd_size);
William Lallemand1d705562012-03-12 12:46:41 +01002971 s->logs.logwait = 0;
2972 }
2973}
William Lallemandbddd4fd2012-02-27 11:23:10 +01002974
Willy Tarreau53839352018-09-05 19:51:10 +02002975/*
2976 * send a minimalist log for the session. Will not log if the frontend has no
2977 * log defined. It is assumed that this is only used to report anomalies that
2978 * cannot lead to the creation of a regular stream. Because of this the log
2979 * level is LOG_INFO or LOG_ERR depending on the "log-separate-error" setting
2980 * in the frontend. The caller must simply know that it should not call this
Willy Tarreau9fa267d2018-10-05 10:22:27 +02002981 * function to report unimportant events. It is safe to call this function with
2982 * sess==NULL (will not do anything).
Willy Tarreau53839352018-09-05 19:51:10 +02002983 */
2984void sess_log(struct session *sess)
2985{
2986 int size, level;
2987 int sd_size = 0;
2988
Willy Tarreau9fa267d2018-10-05 10:22:27 +02002989 if (!sess)
2990 return;
2991
Willy Tarreau53839352018-09-05 19:51:10 +02002992 if (LIST_ISEMPTY(&sess->fe->logsrvs))
2993 return;
2994
2995 level = LOG_INFO;
2996 if (sess->fe->options2 & PR_O2_LOGERRORS)
2997 level = LOG_ERR;
2998
2999 if (!LIST_ISEMPTY(&sess->fe->logformat_sd)) {
3000 sd_size = sess_build_logline(sess, NULL,
3001 logline_rfc5424, global.max_syslog_len,
3002 &sess->fe->logformat_sd);
3003 }
3004
3005 size = sess_build_logline(sess, NULL, logline, global.max_syslog_len, &sess->fe->logformat);
3006 if (size > 0) {
Olivier Houchardd2ee3e72019-03-08 18:53:21 +01003007 _HA_ATOMIC_ADD(&sess->fe->log_count, 1);
Christopher Faulet5c6fefc2019-08-11 19:40:12 +02003008 __send_log(&sess->fe->logsrvs, &sess->fe->log_tag, level,
3009 logline, size + 1, logline_rfc5424, sd_size);
Willy Tarreau53839352018-09-05 19:51:10 +02003010 }
3011}
3012
Christopher Faulet5c6fefc2019-08-11 19:40:12 +02003013void app_log(struct list *logsrvs, struct buffer *tag, int level, const char *format, ...)
3014{
3015 va_list argp;
3016 int data_len;
3017
3018 if (level < 0 || format == NULL || logline == NULL)
3019 return;
3020
3021 va_start(argp, format);
3022 data_len = vsnprintf(logline, global.max_syslog_len, format, argp);
3023 if (data_len < 0 || data_len > global.max_syslog_len)
3024 data_len = global.max_syslog_len;
3025 va_end(argp);
3026
3027 __send_log(logsrvs, tag, level, logline, data_len, default_rfc5424_sd_log_format, 2);
3028}
3029
Christopher Fauletc1b730a2017-10-24 12:00:51 +02003030static int cli_io_handler_show_startup_logs(struct appctx *appctx)
3031{
3032 struct stream_interface *si = appctx->owner;
3033 const char *msg = (startup_logs ? startup_logs : "No startup alerts/warnings.\n");
3034
3035 if (ci_putstr(si_ic(si), msg) == -1) {
Willy Tarreaudb398432018-11-15 11:08:52 +01003036 si_rx_room_blk(si);
Christopher Fauletc1b730a2017-10-24 12:00:51 +02003037 return 0;
3038 }
3039 return 1;
3040}
3041
3042/* register cli keywords */
3043static struct cli_kw_list cli_kws = {{ },{
3044 { { "show", "startup-logs", NULL },
3045 "show startup-logs : report logs emitted during HAProxy startup",
3046 NULL, cli_io_handler_show_startup_logs },
3047 {{},}
3048}};
3049
Willy Tarreau0108d902018-11-25 19:14:37 +01003050INITCALL1(STG_REGISTER, cli_register_kw, &cli_kws);
3051
Willy Tarreau082b6282019-05-22 14:42:12 +02003052REGISTER_PER_THREAD_ALLOC(init_log_buffers);
3053REGISTER_PER_THREAD_FREE(deinit_log_buffers);
Willy Tarreau172f5ce2018-11-26 11:21:50 +01003054
Willy Tarreaubaaee002006-06-26 02:48:02 +02003055/*
3056 * Local variables:
3057 * c-indent-level: 8
3058 * c-basic-offset: 8
3059 * End:
3060 */