blob: 50b5080c4e80cb55f35868ec7ce71cca28f0a410 [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 */
Tim Duesterhuscf6e0c82020-03-13 12:34:24 +0100140 { "ID", LOG_FMT_UNIQUEID, PR_MODE_TCP, 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 Tarreau869efd52019-11-15 15:16:57 +0100251static struct ring *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 Tarreaucd0d2ed2020-02-14 17:33:06 +0100476 * should work. The curpx->conf.args.ctx must be set by the caller. If an end pointer
477 * is passed in <endptr>, it will be updated with the pointer to the first character
478 * not part of the sample expression.
Thierry FOURNIER / OZON.IOa2c38d72016-11-22 23:11:21 +0100479 *
480 * In error case, the function returns 0, otherwise it returns 1.
Willy Tarreauc8368452012-12-21 00:09:23 +0100481 */
Willy Tarreaucd0d2ed2020-02-14 17:33:06 +0100482int 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, char **endptr)
Willy Tarreauc8368452012-12-21 00:09:23 +0100483{
484 char *cmd[2];
Dragan Dosen61302da2019-04-30 00:40:02 +0200485 struct sample_expr *expr = NULL;
486 struct logformat_node *node = NULL;
Willy Tarreauc8368452012-12-21 00:09:23 +0100487 int cmd_arg;
488
489 cmd[0] = text;
490 cmd[1] = "";
491 cmd_arg = 0;
492
Willy Tarreaucd0d2ed2020-02-14 17:33:06 +0100493 expr = sample_parse_expr(cmd, &cmd_arg, curpx->conf.args.file, curpx->conf.args.line, err, &curpx->conf.args, endptr);
Willy Tarreauc8368452012-12-21 00:09:23 +0100494 if (!expr) {
Thierry FOURNIER / OZON.IO8a4e4422016-11-23 00:41:28 +0100495 memprintf(err, "failed to parse sample expression <%s> : %s", text, *err);
Dragan Dosen61302da2019-04-30 00:40:02 +0200496 goto error_free;
Willy Tarreauc8368452012-12-21 00:09:23 +0100497 }
498
Vincent Bernat02779b62016-04-03 13:48:43 +0200499 node = calloc(1, sizeof(*node));
Thierry FOURNIER / OZON.IO9cbfef22016-11-22 23:24:10 +0100500 if (!node) {
Thierry FOURNIER / OZON.IO8a4e4422016-11-23 00:41:28 +0100501 memprintf(err, "out of memory error");
Dragan Dosen61302da2019-04-30 00:40:02 +0200502 goto error_free;
Thierry FOURNIER / OZON.IO9cbfef22016-11-22 23:24:10 +0100503 }
Willy Tarreauc8368452012-12-21 00:09:23 +0100504 node->type = LOG_FMT_EXPR;
505 node->expr = expr;
506 node->options = options;
507
508 if (arg_len) {
509 node->arg = my_strndup(arg, arg_len);
Thierry FOURNIER / OZON.IO8a4e4422016-11-23 00:41:28 +0100510 if (!parse_logformat_var_args(node->arg, node, err))
Dragan Dosen61302da2019-04-30 00:40:02 +0200511 goto error_free;
Willy Tarreauc8368452012-12-21 00:09:23 +0100512 }
Willy Tarreau434c57c2013-01-08 01:10:24 +0100513 if (expr->fetch->val & cap & SMP_VAL_REQUEST)
Willy Tarreauc8368452012-12-21 00:09:23 +0100514 node->options |= LOG_OPT_REQ_CAP; /* fetch method is request-compatible */
515
Willy Tarreau434c57c2013-01-08 01:10:24 +0100516 if (expr->fetch->val & cap & SMP_VAL_RESPONSE)
Willy Tarreauc8368452012-12-21 00:09:23 +0100517 node->options |= LOG_OPT_RES_CAP; /* fetch method is response-compatible */
518
Thierry FOURNIER / OZON.IOa2c38d72016-11-22 23:11:21 +0100519 if (!(expr->fetch->val & cap)) {
Thierry FOURNIER / OZON.IO8a4e4422016-11-23 00:41:28 +0100520 memprintf(err, "sample fetch <%s> may not be reliably used here because it needs '%s' which is not available here",
521 text, sample_src_names(expr->fetch->use));
Dragan Dosen61302da2019-04-30 00:40:02 +0200522 goto error_free;
Thierry FOURNIER / OZON.IOa2c38d72016-11-22 23:11:21 +0100523 }
Willy Tarreau434c57c2013-01-08 01:10:24 +0100524
Christopher Faulet711ed6a2019-07-16 14:16:10 +0200525 /* check if we need to allocate an http_txn struct for HTTP parsing */
Willy Tarreauc8368452012-12-21 00:09:23 +0100526 /* Note, we may also need to set curpx->to_log with certain fetches */
Willy Tarreau25320b22013-03-24 07:22:08 +0100527 curpx->http_needed |= !!(expr->fetch->use & SMP_USE_HTTP_ANY);
Willy Tarreauc8368452012-12-21 00:09:23 +0100528
William Lallemand65ad6e12014-01-31 15:08:02 +0100529 /* FIXME: temporary workaround for missing LW_XPRT and LW_REQ flags
530 * needed with some sample fetches (eg: ssl*). We always set it for
531 * now on, but this will leave with sample capabilities soon.
Willy Tarreau1f31c732013-01-10 16:22:27 +0100532 */
533 curpx->to_log |= LW_XPRT;
William Lallemand65ad6e12014-01-31 15:08:02 +0100534 curpx->to_log |= LW_REQ;
Willy Tarreauc8368452012-12-21 00:09:23 +0100535 LIST_ADDQ(list_format, &node->list);
Thierry FOURNIER / OZON.IOa2c38d72016-11-22 23:11:21 +0100536 return 1;
Dragan Dosen61302da2019-04-30 00:40:02 +0200537
538 error_free:
539 release_sample_expr(expr);
540 if (node) {
541 free(node->arg);
542 free(node);
543 }
544 return 0;
Willy Tarreauc8368452012-12-21 00:09:23 +0100545}
546
547/*
William Lallemand723b73a2012-02-08 16:37:49 +0100548 * Parse the log_format string and fill a linked list.
549 * Variable name are preceded by % and composed by characters [a-zA-Z0-9]* : %varname
Willy Tarreaua4312fa2013-04-02 16:34:32 +0200550 * You can set arguments using { } : %{many arguments}varname.
551 * The curproxy->conf.args.ctx must be set by the caller.
William Lallemand1d705562012-03-12 12:46:41 +0100552 *
553 * str: the string to parse
554 * curproxy: the proxy affected
555 * list_format: the destination list
Willy Tarreau6cbbdbf2013-02-05 18:52:25 +0100556 * options: LOG_OPT_* to force on every node
Willy Tarreau434c57c2013-01-08 01:10:24 +0100557 * cap: all SMP_VAL_* flags supported by the consumer
Thierry FOURNIER / OZON.IOa2c38d72016-11-22 23:11:21 +0100558 *
Thierry FOURNIER / OZON.IO8a4e4422016-11-23 00:41:28 +0100559 * The function returns 1 in success case, otherwise, it returns 0 and err is filled.
William Lallemand723b73a2012-02-08 16:37:49 +0100560 */
Thierry FOURNIER / OZON.IO8a4e4422016-11-23 00:41:28 +0100561int 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 +0100562{
Willy Tarreaub83bc1e2012-12-24 12:36:33 +0100563 char *sp, *str, *backfmt; /* start pointer for text parts */
Willy Tarreau8a3f52f2012-12-20 21:23:42 +0100564 char *arg = NULL; /* start pointer for args */
565 char *var = NULL; /* start pointer for vars */
566 int arg_len = 0;
567 int var_len = 0;
568 int cformat; /* current token format */
569 int pformat; /* previous token format */
William Lallemand723b73a2012-02-08 16:37:49 +0100570 struct logformat_node *tmplf, *back;
571
Willy Tarreaub83bc1e2012-12-24 12:36:33 +0100572 sp = str = backfmt = strdup(fmt);
Thierry FOURNIER / OZON.IO9cbfef22016-11-22 23:24:10 +0100573 if (!str) {
Thierry FOURNIER / OZON.IO8a4e4422016-11-23 00:41:28 +0100574 memprintf(err, "out of memory error");
Thierry FOURNIER / OZON.IO9cbfef22016-11-22 23:24:10 +0100575 return 0;
576 }
William Lallemand1dc00ef2012-08-09 16:41:35 +0200577 curproxy->to_log |= LW_INIT;
William Lallemand5e19a282012-04-02 16:22:10 +0200578
William Lallemand723b73a2012-02-08 16:37:49 +0100579 /* flush the list first. */
William Lallemand1d705562012-03-12 12:46:41 +0100580 list_for_each_entry_safe(tmplf, back, list_format, list) {
William Lallemand723b73a2012-02-08 16:37:49 +0100581 LIST_DEL(&tmplf->list);
Dragan Dosen61302da2019-04-30 00:40:02 +0200582 release_sample_expr(tmplf->expr);
583 free(tmplf->arg);
William Lallemand723b73a2012-02-08 16:37:49 +0100584 free(tmplf);
585 }
586
Willy Tarreau8a3f52f2012-12-20 21:23:42 +0100587 for (cformat = LF_INIT; cformat != LF_END; str++) {
William Lallemand723b73a2012-02-08 16:37:49 +0100588 pformat = cformat;
589
Willy Tarreau8a3f52f2012-12-20 21:23:42 +0100590 if (!*str)
591 cformat = LF_END; // preset it to save all states from doing this
William Lallemand723b73a2012-02-08 16:37:49 +0100592
Joseph Herlant85b40592018-11-15 12:10:04 -0800593 /* The principle of the two-step state machine below is to first detect a change, and
Willy Tarreau8a3f52f2012-12-20 21:23:42 +0100594 * second have all common paths processed at one place. The common paths are the ones
595 * encountered in text areas (LF_INIT, LF_TEXT, LF_SEPARATOR) and at the end (LF_END).
596 * We use the common LF_INIT state to dispatch to the different final states.
597 */
598 switch (pformat) {
599 case LF_STARTVAR: // text immediately following a '%'
Willy Tarreauc8368452012-12-21 00:09:23 +0100600 arg = NULL; var = NULL;
Willy Tarreau8a3f52f2012-12-20 21:23:42 +0100601 arg_len = var_len = 0;
602 if (*str == '{') { // optional argument
603 cformat = LF_STARG;
604 arg = str + 1;
William Lallemand723b73a2012-02-08 16:37:49 +0100605 }
Willy Tarreauc8368452012-12-21 00:09:23 +0100606 else if (*str == '[') {
607 cformat = LF_STEXPR;
608 var = str + 1; // store expr in variable name
609 }
Willy Tarreau0f28f822013-12-16 01:38:33 +0100610 else if (isalpha((unsigned char)*str)) { // variable name
William Lallemand723b73a2012-02-08 16:37:49 +0100611 cformat = LF_VAR;
Willy Tarreau8a3f52f2012-12-20 21:23:42 +0100612 var = str;
William Lallemand723b73a2012-02-08 16:37:49 +0100613 }
Willy Tarreau8a3f52f2012-12-20 21:23:42 +0100614 else if (*str == '%')
615 cformat = LF_TEXT; // convert this character to a litteral (useful for '%')
Willy Tarreau0f28f822013-12-16 01:38:33 +0100616 else if (isdigit((unsigned char)*str) || *str == ' ' || *str == '\t') {
Willy Tarreau06d97f92013-12-02 17:45:48 +0100617 /* single '%' followed by blank or digit, send them both */
618 cformat = LF_TEXT;
619 pformat = LF_TEXT; /* finally we include the previous char as well */
620 sp = str - 1; /* send both the '%' and the current char */
Jim Freemana2278c82017-04-15 08:01:59 -0600621 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 +0100622 *str, (int)(str - backfmt), fmt);
Willy Tarreau51013e82019-12-11 12:05:39 +0100623 goto fail;
Willy Tarreau06d97f92013-12-02 17:45:48 +0100624
625 }
Willy Tarreau8a3f52f2012-12-20 21:23:42 +0100626 else
627 cformat = LF_INIT; // handle other cases of litterals
628 break;
629
630 case LF_STARG: // text immediately following '%{'
631 if (*str == '}') { // end of arg
William Lallemand723b73a2012-02-08 16:37:49 +0100632 cformat = LF_EDARG;
Willy Tarreau8a3f52f2012-12-20 21:23:42 +0100633 arg_len = str - arg;
634 *str = 0; // used for reporting errors
William Lallemand723b73a2012-02-08 16:37:49 +0100635 }
Willy Tarreau8a3f52f2012-12-20 21:23:42 +0100636 break;
637
638 case LF_EDARG: // text immediately following '%{arg}'
Willy Tarreauc8368452012-12-21 00:09:23 +0100639 if (*str == '[') {
640 cformat = LF_STEXPR;
641 var = str + 1; // store expr in variable name
642 break;
643 }
Willy Tarreau0f28f822013-12-16 01:38:33 +0100644 else if (isalnum((unsigned char)*str)) { // variable name
William Lallemand723b73a2012-02-08 16:37:49 +0100645 cformat = LF_VAR;
Willy Tarreau8a3f52f2012-12-20 21:23:42 +0100646 var = str;
647 break;
648 }
Thierry FOURNIER / OZON.IO8a4e4422016-11-23 00:41:28 +0100649 memprintf(err, "parse argument modifier without variable name near '%%{%s}'", arg);
Willy Tarreau51013e82019-12-11 12:05:39 +0100650 goto fail;
Willy Tarreau8a3f52f2012-12-20 21:23:42 +0100651
Willy Tarreauc8368452012-12-21 00:09:23 +0100652 case LF_STEXPR: // text immediately following '%['
Willy Tarreaucd0d2ed2020-02-14 17:33:06 +0100653 /* the whole sample expression is parsed at once,
654 * returning the pointer to the first character not
655 * part of the expression, which MUST be the trailing
656 * angle bracket.
657 */
658 if (!add_sample_to_logformat_list(var, arg, arg_len, curproxy, list_format, options, cap, err, &str))
659 goto fail;
660
661 if (*str == ']') {
662 // end of arg, go on with next state
663 cformat = pformat = LF_EDEXPR;
664 sp = str;
665 }
666 else {
667 char c = *str;
668 *str = 0;
Willy Tarreau90807112020-02-25 08:16:33 +0100669 if (isprint((unsigned char)c))
Willy Tarreaucd0d2ed2020-02-14 17:33:06 +0100670 memprintf(err, "expected ']' after '%s', but found '%c'", var, c);
671 else
672 memprintf(err, "missing ']' after '%s'", var);
Willy Tarreauc8368452012-12-21 00:09:23 +0100673 }
674 break;
675
Willy Tarreau8a3f52f2012-12-20 21:23:42 +0100676 case LF_VAR: // text part of a variable name
677 var_len = str - var;
Willy Tarreau0f28f822013-12-16 01:38:33 +0100678 if (!isalnum((unsigned char)*str))
Willy Tarreau8a3f52f2012-12-20 21:23:42 +0100679 cformat = LF_INIT; // not variable name anymore
680 break;
681
Willy Tarreauc8368452012-12-21 00:09:23 +0100682 default: // LF_INIT, LF_TEXT, LF_SEPARATOR, LF_END, LF_EDEXPR
Willy Tarreau8a3f52f2012-12-20 21:23:42 +0100683 cformat = LF_INIT;
684 }
685
686 if (cformat == LF_INIT) { /* resynchronize state to text/sep/startvar */
687 switch (*str) {
688 case '%': cformat = LF_STARTVAR; break;
689 case ' ': cformat = LF_SEPARATOR; break;
690 case 0 : cformat = LF_END; break;
691 default : cformat = LF_TEXT; break;
William Lallemand723b73a2012-02-08 16:37:49 +0100692 }
693 }
694
Willy Tarreau8a3f52f2012-12-20 21:23:42 +0100695 if (cformat != pformat || pformat == LF_SEPARATOR) {
696 switch (pformat) {
697 case LF_VAR:
Thierry FOURNIER / OZON.IO8a4e4422016-11-23 00:41:28 +0100698 if (!parse_logformat_var(arg, arg_len, var, var_len, curproxy, list_format, &options, err))
Willy Tarreau51013e82019-12-11 12:05:39 +0100699 goto fail;
Willy Tarreau8a3f52f2012-12-20 21:23:42 +0100700 break;
Willy Tarreauc8368452012-12-21 00:09:23 +0100701 case LF_STEXPR:
Willy Tarreaucd0d2ed2020-02-14 17:33:06 +0100702 if (!add_sample_to_logformat_list(var, arg, arg_len, curproxy, list_format, options, cap, err, &sp))
Willy Tarreau51013e82019-12-11 12:05:39 +0100703 goto fail;
Willy Tarreauc8368452012-12-21 00:09:23 +0100704 break;
Willy Tarreau8a3f52f2012-12-20 21:23:42 +0100705 case LF_TEXT:
706 case LF_SEPARATOR:
Thierry FOURNIER / OZON.IO8a4e4422016-11-23 00:41:28 +0100707 if (!add_to_logformat_list(sp, str, pformat, list_format, err))
Willy Tarreau51013e82019-12-11 12:05:39 +0100708 goto fail;
Willy Tarreau8a3f52f2012-12-20 21:23:42 +0100709 break;
710 }
711 sp = str; /* new start of text at every state switch and at every separator */
William Lallemand723b73a2012-02-08 16:37:49 +0100712 }
713 }
Willy Tarreau8a3f52f2012-12-20 21:23:42 +0100714
Thierry FOURNIER / OZON.IOa2c38d72016-11-22 23:11:21 +0100715 if (pformat == LF_STARTVAR || pformat == LF_STARG || pformat == LF_STEXPR) {
Thierry FOURNIER / OZON.IO8a4e4422016-11-23 00:41:28 +0100716 memprintf(err, "truncated line after '%s'", var ? var : arg ? arg : "%");
Willy Tarreau51013e82019-12-11 12:05:39 +0100717 goto fail;
Thierry FOURNIER / OZON.IOa2c38d72016-11-22 23:11:21 +0100718 }
Willy Tarreaub83bc1e2012-12-24 12:36:33 +0100719 free(backfmt);
Thierry FOURNIER / OZON.IOa2c38d72016-11-22 23:11:21 +0100720
721 return 1;
Willy Tarreau51013e82019-12-11 12:05:39 +0100722 fail:
723 free(backfmt);
724 return 0;
William Lallemand723b73a2012-02-08 16:37:49 +0100725}
726
Christopher Faulet4b0b79d2018-03-26 15:54:32 +0200727/*
Frédéric Lécailled95ea282019-04-24 16:14:33 +0200728 * Parse the first range of indexes from a string made of a list of comma seperated
729 * ranges of indexes. Note that an index may be considered as a particular range
730 * with a high limit to the low limit.
731 */
732int get_logsrv_smp_range(unsigned int *low, unsigned int *high, char **arg, char **err)
733{
734 char *end, *p;
735
736 *low = *high = 0;
737
738 p = *arg;
739 end = strchr(p, ',');
740 if (!end)
741 end = p + strlen(p);
742
743 *high = *low = read_uint((const char **)&p, end);
744 if (!*low || (p != end && *p != '-'))
745 goto err;
746
747 if (p == end)
748 goto done;
749
750 p++;
751 *high = read_uint((const char **)&p, end);
752 if (!*high || *high <= *low || p != end)
753 goto err;
754
755 done:
756 if (*end == ',')
757 end++;
758 *arg = end;
759 return 1;
760
761 err:
762 memprintf(err, "wrong sample range '%s'", *arg);
763 return 0;
764}
765
766/*
767 * Returns 1 if the range defined by <low> and <high> overlaps
768 * one of them in <rgs> array of ranges with <sz> the size of this
769 * array, 0 if not.
770 */
771int smp_log_ranges_overlap(struct smp_log_range *rgs, size_t sz,
772 unsigned int low, unsigned int high, char **err)
773{
774 size_t i;
775
776 for (i = 0; i < sz; i++) {
777 if ((low >= rgs[i].low && low <= rgs[i].high) ||
778 (high >= rgs[i].low && high <= rgs[i].high)) {
779 memprintf(err, "ranges are overlapping");
780 return 1;
781 }
782 }
783
784 return 0;
785}
786
787int smp_log_range_cmp(const void *a, const void *b)
788{
789 const struct smp_log_range *rg_a = a;
790 const struct smp_log_range *rg_b = b;
791
792 if (rg_a->high < rg_b->low)
793 return -1;
794 else if (rg_a->low > rg_b->high)
795 return 1;
796
797 return 0;
798}
799
800/*
Christopher Faulet4b0b79d2018-03-26 15:54:32 +0200801 * Parse "log" keyword and update <logsrvs> list accordingly.
802 *
803 * When <do_del> is set, it means the "no log" line was parsed, so all log
804 * servers in <logsrvs> are released.
805 *
806 * Otherwise, we try to parse the "log" line. First of all, when the list is not
807 * the global one, we look for the parameter "global". If we find it,
808 * global.logsrvs is copied. Else we parse each arguments.
809 *
810 * The function returns 1 in success case, otherwise, it returns 0 and err is
811 * filled.
812 */
813int parse_logsrv(char **args, struct list *logsrvs, int do_del, char **err)
814{
815 struct sockaddr_storage *sk;
816 struct logsrv *logsrv = NULL;
817 int port1, port2;
818 int cur_arg;
819
820 /*
821 * "no log": delete previous herited or defined syslog
822 * servers.
823 */
824 if (do_del) {
825 struct logsrv *back;
826
827 if (*(args[1]) != 0) {
828 memprintf(err, "'no log' does not expect arguments");
829 goto error;
830 }
831
832 list_for_each_entry_safe(logsrv, back, logsrvs, list) {
833 LIST_DEL(&logsrv->list);
834 free(logsrv);
835 }
836 return 1;
837 }
838
839 /*
840 * "log global": copy global.logrsvs linked list to the end of logsrvs
841 * list. But first, we check (logsrvs != global.logsrvs).
842 */
843 if (*(args[1]) && *(args[2]) == 0 && !strcmp(args[1], "global")) {
844 if (logsrvs == &global.logsrvs) {
845 memprintf(err, "'global' is not supported for a global syslog server");
846 goto error;
847 }
848 list_for_each_entry(logsrv, &global.logsrvs, list) {
Christopher Faulet28ac0992018-03-26 16:09:19 +0200849 struct logsrv *node;
850
851 list_for_each_entry(node, logsrvs, list) {
852 if (node->ref == logsrv)
853 goto skip_logsrv;
854 }
855
856 node = malloc(sizeof(*node));
Christopher Faulet4b0b79d2018-03-26 15:54:32 +0200857 memcpy(node, logsrv, sizeof(struct logsrv));
Christopher Faulet28ac0992018-03-26 16:09:19 +0200858 node->ref = logsrv;
Christopher Faulet4b0b79d2018-03-26 15:54:32 +0200859 LIST_INIT(&node->list);
860 LIST_ADDQ(logsrvs, &node->list);
Christopher Faulet28ac0992018-03-26 16:09:19 +0200861
862 skip_logsrv:
863 continue;
Christopher Faulet4b0b79d2018-03-26 15:54:32 +0200864 }
865 return 1;
866 }
867
868 /*
869 * "log <address> ...: parse a syslog server line
870 */
871 if (*(args[1]) == 0 || *(args[2]) == 0) {
872 memprintf(err, "expects <address> and <facility> %s as arguments",
873 ((logsrvs == &global.logsrvs) ? "" : "or global"));
874 goto error;
875 }
876
Willy Tarreau5a32ecc2018-11-12 07:34:59 +0100877 /* take care of "stdout" and "stderr" as regular aliases for fd@1 / fd@2 */
878 if (strcmp(args[1], "stdout") == 0)
879 args[1] = "fd@1";
880 else if (strcmp(args[1], "stderr") == 0)
881 args[1] = "fd@2";
882
Christopher Faulet4b0b79d2018-03-26 15:54:32 +0200883 logsrv = calloc(1, sizeof(*logsrv));
884 if (!logsrv) {
885 memprintf(err, "out of memory");
886 goto error;
887 }
888
889 /* skip address for now, it will be parsed at the end */
890 cur_arg = 2;
891
892 /* just after the address, a length may be specified */
893 logsrv->maxlen = MAX_SYSLOG_LEN;
894 if (strcmp(args[cur_arg], "len") == 0) {
895 int len = atoi(args[cur_arg+1]);
896 if (len < 80 || len > 65535) {
897 memprintf(err, "invalid log length '%s', must be between 80 and 65535",
898 args[cur_arg+1]);
899 goto error;
900 }
901 logsrv->maxlen = len;
902 cur_arg += 2;
903 }
904 if (logsrv->maxlen > global.max_syslog_len)
905 global.max_syslog_len = logsrv->maxlen;
906
907 /* after the length, a format may be specified */
908 if (strcmp(args[cur_arg], "format") == 0) {
909 logsrv->format = get_log_format(args[cur_arg+1]);
910 if (logsrv->format < 0) {
911 memprintf(err, "unknown log format '%s'", args[cur_arg+1]);
912 goto error;
913 }
914 cur_arg += 2;
915 }
916
Frédéric Lécailled95ea282019-04-24 16:14:33 +0200917 if (strcmp(args[cur_arg], "sample") == 0) {
918 unsigned low, high;
919 char *p, *beg, *end, *smp_sz_str;
920 struct smp_log_range *smp_rgs = NULL;
921 size_t smp_rgs_sz = 0, smp_sz = 0, new_smp_sz;
922
923 p = args[cur_arg+1];
924 smp_sz_str = strchr(p, ':');
925 if (!smp_sz_str) {
926 memprintf(err, "Missing sample size");
927 goto error;
928 }
929
930 *smp_sz_str++ = '\0';
931
932 end = p + strlen(p);
933
934 while (p != end) {
935 if (!get_logsrv_smp_range(&low, &high, &p, err))
936 goto error;
937
938 if (smp_rgs && smp_log_ranges_overlap(smp_rgs, smp_rgs_sz, low, high, err))
939 goto error;
940
941 smp_rgs = my_realloc2(smp_rgs, (smp_rgs_sz + 1) * sizeof *smp_rgs);
942 if (!smp_rgs) {
943 memprintf(err, "out of memory error");
944 goto error;
945 }
946
947 smp_rgs[smp_rgs_sz].low = low;
948 smp_rgs[smp_rgs_sz].high = high;
949 smp_rgs[smp_rgs_sz].sz = high - low + 1;
950 smp_rgs[smp_rgs_sz].curr_idx = 0;
951 if (smp_rgs[smp_rgs_sz].high > smp_sz)
952 smp_sz = smp_rgs[smp_rgs_sz].high;
953 smp_rgs_sz++;
954 }
955
Tim Duesterhus21648002019-06-23 22:10:10 +0200956 if (smp_rgs == NULL) {
957 memprintf(err, "no sampling ranges given");
958 goto error;
959 }
960
Frédéric Lécailled95ea282019-04-24 16:14:33 +0200961 beg = smp_sz_str;
962 end = beg + strlen(beg);
963 new_smp_sz = read_uint((const char **)&beg, end);
964 if (!new_smp_sz || beg != end) {
965 memprintf(err, "wrong sample size '%s' for sample range '%s'",
966 smp_sz_str, args[cur_arg+1]);
967 goto error;
968 }
969
970 if (new_smp_sz < smp_sz) {
971 memprintf(err, "sample size %zu should be greater or equal to "
972 "%zu the maximum of the high ranges limits",
973 new_smp_sz, smp_sz);
974 goto error;
975 }
976 smp_sz = new_smp_sz;
977
978 /* Let's order <smp_rgs> array. */
979 qsort(smp_rgs, smp_rgs_sz, sizeof(struct smp_log_range), smp_log_range_cmp);
980
981 logsrv->lb.smp_rgs = smp_rgs;
982 logsrv->lb.smp_rgs_sz = smp_rgs_sz;
983 logsrv->lb.smp_sz = smp_sz;
984
985 cur_arg += 2;
986 }
Frédéric Lécailled803e472019-04-25 07:42:09 +0200987 HA_SPIN_INIT(&logsrv->lock);
Christopher Faulet4b0b79d2018-03-26 15:54:32 +0200988 /* parse the facility */
989 logsrv->facility = get_log_facility(args[cur_arg]);
990 if (logsrv->facility < 0) {
991 memprintf(err, "unknown log facility '%s'", args[cur_arg]);
992 goto error;
993 }
994 cur_arg++;
995
996 /* parse the max syslog level (default: debug) */
997 logsrv->level = 7;
998 if (*(args[cur_arg])) {
999 logsrv->level = get_log_level(args[cur_arg]);
1000 if (logsrv->level < 0) {
1001 memprintf(err, "unknown optional log level '%s'", args[cur_arg]);
1002 goto error;
1003 }
1004 cur_arg++;
1005 }
1006
1007 /* parse the limit syslog level (default: emerg) */
1008 logsrv->minlvl = 0;
1009 if (*(args[cur_arg])) {
1010 logsrv->minlvl = get_log_level(args[cur_arg]);
1011 if (logsrv->minlvl < 0) {
1012 memprintf(err, "unknown optional minimum log level '%s'", args[cur_arg]);
1013 goto error;
1014 }
1015 cur_arg++;
1016 }
1017
1018 /* Too many args */
1019 if (*(args[cur_arg])) {
1020 memprintf(err, "cannot handle unexpected argument '%s'", args[cur_arg]);
1021 goto error;
1022 }
1023
1024 /* now, back to the address */
Willy Tarreauf3dc30f2019-08-30 14:18:44 +02001025 logsrv->type = LOG_TARGET_DGRAM;
Willy Tarreauc046d162019-08-30 15:24:59 +02001026 if (strncmp(args[1], "ring@", 5) == 0) {
1027 struct sink *sink = sink_find(args[1] + 5);
1028
1029 if (!sink || sink->type != SINK_TYPE_BUFFER) {
1030 memprintf(err, "cannot find ring buffer '%s'", args[1] + 5);
1031 goto error;
1032 }
1033
1034 logsrv->addr.ss_family = AF_UNSPEC;
1035 logsrv->type = LOG_TARGET_BUFFER;
1036 logsrv->ring = sink->ctx.ring;
1037 goto done;
1038 }
1039
Willy Tarreauf3dc30f2019-08-30 14:18:44 +02001040 if (strncmp(args[1], "fd@", 3) == 0)
1041 logsrv->type = LOG_TARGET_FD;
1042
Christopher Faulet4b0b79d2018-03-26 15:54:32 +02001043 sk = str2sa_range(args[1], NULL, &port1, &port2, err, NULL, NULL, 1);
1044 if (!sk)
1045 goto error;
1046 logsrv->addr = *sk;
1047
1048 if (sk->ss_family == AF_INET || sk->ss_family == AF_INET6) {
1049 if (port1 != port2) {
1050 memprintf(err, "port ranges and offsets are not allowed in '%s'", args[1]);
1051 goto error;
1052 }
1053 logsrv->addr = *sk;
1054 if (!port1)
1055 set_host_port(&logsrv->addr, SYSLOG_PORT);
1056 }
Willy Tarreauc046d162019-08-30 15:24:59 +02001057 done:
Christopher Faulet4b0b79d2018-03-26 15:54:32 +02001058 LIST_ADDQ(logsrvs, &logsrv->list);
1059 return 1;
1060
1061 error:
1062 free(logsrv);
1063 return 0;
1064}
1065
1066
Christopher Fauletd4696382017-10-24 11:44:05 +02001067/* Generic function to display messages prefixed by a label */
1068static void print_message(const char *label, const char *fmt, va_list argp)
1069{
1070 struct tm tm;
1071 char *head, *msg;
1072
1073 head = msg = NULL;
1074
1075 get_localtime(date.tv_sec, &tm);
1076 memprintf(&head, "[%s] %03d/%02d%02d%02d (%d) : ",
1077 label, tm.tm_yday, tm.tm_hour, tm.tm_min, tm.tm_sec, (int)getpid());
1078 memvprintf(&msg, fmt, argp);
1079
Willy Tarreau869efd52019-11-15 15:16:57 +01001080 if (global.mode & MODE_STARTING) {
1081 if (unlikely(!startup_logs))
1082 startup_logs = ring_new(STARTUP_LOG_SIZE);
1083
1084 if (likely(startup_logs)) {
1085 struct ist m[2];
1086
1087 m[0] = ist(head);
1088 m[1] = ist(msg);
1089 /* trim the trailing '\n' */
1090 if (m[1].len > 0 && m[1].ptr[m[1].len - 1] == '\n')
1091 m[1].len--;
1092 ring_write(startup_logs, ~0, 0, 0, m, 2);
1093 }
1094 }
Christopher Fauletd4696382017-10-24 11:44:05 +02001095
1096 fprintf(stderr, "%s%s", head, msg);
1097 fflush(stderr);
1098
1099 free(head);
1100 free(msg);
1101}
1102
Willy Tarreaubaaee002006-06-26 02:48:02 +02001103/*
1104 * Displays the message on stderr with the date and pid. Overrides the quiet
1105 * mode during startup.
1106 */
Christopher Faulet767a84b2017-11-24 16:50:31 +01001107void ha_alert(const char *fmt, ...)
Willy Tarreaubaaee002006-06-26 02:48:02 +02001108{
1109 va_list argp;
Willy Tarreaubaaee002006-06-26 02:48:02 +02001110
1111 if (!(global.mode & MODE_QUIET) || (global.mode & (MODE_VERBOSE | MODE_STARTING))) {
1112 va_start(argp, fmt);
Christopher Fauletd4696382017-10-24 11:44:05 +02001113 print_message("ALERT", fmt, argp);
Willy Tarreaubaaee002006-06-26 02:48:02 +02001114 va_end(argp);
1115 }
1116}
1117
1118
1119/*
1120 * Displays the message on stderr with the date and pid.
1121 */
Christopher Faulet767a84b2017-11-24 16:50:31 +01001122void ha_warning(const char *fmt, ...)
Willy Tarreaubaaee002006-06-26 02:48:02 +02001123{
1124 va_list argp;
Willy Tarreaubaaee002006-06-26 02:48:02 +02001125
Willy Tarreaubebd2122020-04-15 16:06:11 +02001126 warned |= WARN_ANY;
1127
Willy Tarreaubaaee002006-06-26 02:48:02 +02001128 if (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE)) {
1129 va_start(argp, fmt);
Christopher Fauletd4696382017-10-24 11:44:05 +02001130 print_message("WARNING", fmt, argp);
Willy Tarreaubaaee002006-06-26 02:48:02 +02001131 va_end(argp);
1132 }
1133}
1134
1135/*
William Lallemand9c56a222018-11-21 18:04:52 +01001136 * Displays the message on stderr with the date and pid.
1137 */
1138void ha_notice(const char *fmt, ...)
1139{
1140 va_list argp;
1141
1142 if (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE)) {
1143 va_start(argp, fmt);
1144 print_message("NOTICE", fmt, argp);
1145 va_end(argp);
1146 }
1147}
1148
1149/*
Willy Tarreaubaaee002006-06-26 02:48:02 +02001150 * Displays the message on <out> only if quiet mode is not set.
1151 */
Willy Tarreaub17916e2006-10-15 15:17:57 +02001152void qfprintf(FILE *out, const char *fmt, ...)
Willy Tarreaubaaee002006-06-26 02:48:02 +02001153{
1154 va_list argp;
1155
1156 if (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE)) {
1157 va_start(argp, fmt);
1158 vfprintf(out, fmt, argp);
1159 fflush(out);
1160 va_end(argp);
1161 }
1162}
1163
1164/*
Dragan Dosen1322d092015-09-22 16:05:32 +02001165 * returns log format for <fmt> or -1 if not found.
1166 */
1167int get_log_format(const char *fmt)
1168{
1169 int format;
1170
1171 format = LOG_FORMATS - 1;
Dragan Dosen43885c72015-10-01 13:18:13 +02001172 while (format >= 0 && strcmp(log_formats[format].name, fmt))
Dragan Dosen1322d092015-09-22 16:05:32 +02001173 format--;
1174
1175 return format;
1176}
1177
1178/*
Willy Tarreaubaaee002006-06-26 02:48:02 +02001179 * returns log level for <lev> or -1 if not found.
1180 */
1181int get_log_level(const char *lev)
1182{
1183 int level;
1184
1185 level = NB_LOG_LEVELS - 1;
1186 while (level >= 0 && strcmp(log_levels[level], lev))
1187 level--;
1188
1189 return level;
1190}
1191
Willy Tarreaubaaee002006-06-26 02:48:02 +02001192/*
1193 * returns log facility for <fac> or -1 if not found.
1194 */
1195int get_log_facility(const char *fac)
1196{
1197 int facility;
1198
1199 facility = NB_LOG_FACILITIES - 1;
1200 while (facility >= 0 && strcmp(log_facilities[facility], fac))
1201 facility--;
William Lallemand2a4a44f2012-02-06 16:00:33 +01001202
Willy Tarreaubaaee002006-06-26 02:48:02 +02001203 return facility;
1204}
1205
William Lallemanda1cc3812012-02-08 16:38:44 +01001206/*
Dragan Dosen835b9212016-02-12 13:23:03 +01001207 * Encode the string.
1208 *
1209 * When using the +E log format option, it will try to escape '"\]'
1210 * characters with '\' as prefix. The same prefix should not be used as
1211 * <escape>.
1212 */
1213static char *lf_encode_string(char *start, char *stop,
Willy Tarreau1bfd6022019-06-07 11:10:07 +02001214 const char escape, const long *map,
Dragan Dosen835b9212016-02-12 13:23:03 +01001215 const char *string,
1216 struct logformat_node *node)
1217{
1218 if (node->options & LOG_OPT_ESC) {
1219 if (start < stop) {
1220 stop--; /* reserve one byte for the final '\0' */
1221 while (start < stop && *string != '\0') {
Willy Tarreau1bfd6022019-06-07 11:10:07 +02001222 if (!ha_bit_test((unsigned char)(*string), map)) {
1223 if (!ha_bit_test((unsigned char)(*string), rfc5424_escape_map))
Dragan Dosen835b9212016-02-12 13:23:03 +01001224 *start++ = *string;
1225 else {
1226 if (start + 2 >= stop)
1227 break;
1228 *start++ = '\\';
1229 *start++ = *string;
1230 }
1231 }
1232 else {
1233 if (start + 3 >= stop)
1234 break;
1235 *start++ = escape;
1236 *start++ = hextab[(*string >> 4) & 15];
1237 *start++ = hextab[*string & 15];
1238 }
1239 string++;
1240 }
1241 *start = '\0';
1242 }
1243 }
1244 else {
1245 return encode_string(start, stop, escape, map, string);
1246 }
1247
1248 return start;
1249}
1250
1251/*
1252 * Encode the chunk.
1253 *
1254 * When using the +E log format option, it will try to escape '"\]'
1255 * characters with '\' as prefix. The same prefix should not be used as
1256 * <escape>.
1257 */
1258static char *lf_encode_chunk(char *start, char *stop,
Willy Tarreau1bfd6022019-06-07 11:10:07 +02001259 const char escape, const long *map,
Willy Tarreau83061a82018-07-13 11:56:34 +02001260 const struct buffer *chunk,
Dragan Dosen835b9212016-02-12 13:23:03 +01001261 struct logformat_node *node)
1262{
1263 char *str, *end;
1264
1265 if (node->options & LOG_OPT_ESC) {
1266 if (start < stop) {
Willy Tarreau843b7cb2018-07-13 10:54:26 +02001267 str = chunk->area;
1268 end = chunk->area + chunk->data;
Dragan Dosen835b9212016-02-12 13:23:03 +01001269
1270 stop--; /* reserve one byte for the final '\0' */
1271 while (start < stop && str < end) {
Willy Tarreau1bfd6022019-06-07 11:10:07 +02001272 if (!ha_bit_test((unsigned char)(*str), map)) {
1273 if (!ha_bit_test((unsigned char)(*str), rfc5424_escape_map))
Dragan Dosen835b9212016-02-12 13:23:03 +01001274 *start++ = *str;
1275 else {
1276 if (start + 2 >= stop)
1277 break;
1278 *start++ = '\\';
1279 *start++ = *str;
1280 }
1281 }
1282 else {
1283 if (start + 3 >= stop)
1284 break;
1285 *start++ = escape;
1286 *start++ = hextab[(*str >> 4) & 15];
1287 *start++ = hextab[*str & 15];
1288 }
1289 str++;
1290 }
1291 *start = '\0';
1292 }
1293 }
1294 else {
1295 return encode_chunk(start, stop, escape, map, chunk);
1296 }
1297
1298 return start;
1299}
1300
1301/*
William Lallemanda1cc3812012-02-08 16:38:44 +01001302 * Write a string in the log string
Dragan Dosen835b9212016-02-12 13:23:03 +01001303 * Take cares of quote and escape options
William Lallemanda1cc3812012-02-08 16:38:44 +01001304 *
Joseph Herlant85b40592018-11-15 12:10:04 -08001305 * Return the address of the \0 character, or NULL on error
William Lallemanda1cc3812012-02-08 16:38:44 +01001306 */
Willy Tarreau26ffa852018-09-05 15:23:10 +02001307char *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 +01001308{
Willy Tarreau2b0108a2012-12-21 19:23:44 +01001309 if (size < 2)
1310 return NULL;
William Lallemanda1cc3812012-02-08 16:38:44 +01001311
Willy Tarreau2b0108a2012-12-21 19:23:44 +01001312 if (node->options & LOG_OPT_QUOTE) {
1313 *(dst++) = '"';
1314 size--;
William Lallemandbddd4fd2012-02-27 11:23:10 +01001315 }
Willy Tarreau2b0108a2012-12-21 19:23:44 +01001316
Willy Tarreau6cbbdbf2013-02-05 18:52:25 +01001317 if (src && len) {
Dragan Dosendb1b6f92016-07-25 11:35:02 +02001318 if (++len > size)
1319 len = size;
Dragan Dosen835b9212016-02-12 13:23:03 +01001320 if (node->options & LOG_OPT_ESC) {
Dragan Dosen835b9212016-02-12 13:23:03 +01001321 char *ret;
1322
Dragan Dosendb1b6f92016-07-25 11:35:02 +02001323 ret = escape_string(dst, dst + len, '\\', rfc5424_escape_map, src);
Dragan Dosen835b9212016-02-12 13:23:03 +01001324 if (ret == NULL || *ret != '\0')
1325 return NULL;
1326 len = ret - dst;
1327 }
1328 else {
Dragan Dosen835b9212016-02-12 13:23:03 +01001329 len = strlcpy2(dst, src, len);
1330 }
Willy Tarreau2b0108a2012-12-21 19:23:44 +01001331
1332 size -= len;
1333 dst += len;
1334 }
Willy Tarreau6cbbdbf2013-02-05 18:52:25 +01001335 else if ((node->options & (LOG_OPT_QUOTE|LOG_OPT_MANDATORY)) == LOG_OPT_MANDATORY) {
1336 if (size < 2)
1337 return NULL;
1338 *(dst++) = '-';
1339 }
Willy Tarreau2b0108a2012-12-21 19:23:44 +01001340
1341 if (node->options & LOG_OPT_QUOTE) {
1342 if (size < 2)
1343 return NULL;
1344 *(dst++) = '"';
1345 }
1346
1347 *dst = '\0';
William Lallemandbddd4fd2012-02-27 11:23:10 +01001348 return dst;
William Lallemanda1cc3812012-02-08 16:38:44 +01001349}
1350
Willy Tarreau26ffa852018-09-05 15:23:10 +02001351static inline char *lf_text(char *dst, const char *src, size_t size, const struct logformat_node *node)
Willy Tarreau2b0108a2012-12-21 19:23:44 +01001352{
1353 return lf_text_len(dst, src, size, size, node);
1354}
1355
William Lallemand5f232402012-04-05 18:02:55 +02001356/*
Joseph Herlant85b40592018-11-15 12:10:04 -08001357 * Write a IP address to the log string
William Lallemand5f232402012-04-05 18:02:55 +02001358 * +X option write in hexadecimal notation, most signifant byte on the left
1359 */
Willy Tarreau26ffa852018-09-05 15:23:10 +02001360char *lf_ip(char *dst, const struct sockaddr *sockaddr, size_t size, const struct logformat_node *node)
William Lallemand5f232402012-04-05 18:02:55 +02001361{
1362 char *ret = dst;
1363 int iret;
1364 char pn[INET6_ADDRSTRLEN];
1365
1366 if (node->options & LOG_OPT_HEXA) {
Radek Zajic594c4562019-03-22 10:21:54 +00001367 unsigned char *addr = NULL;
1368 switch (sockaddr->sa_family) {
1369 case AF_INET:
1370 addr = (unsigned char *)&((struct sockaddr_in *)sockaddr)->sin_addr.s_addr;
1371 iret = snprintf(dst, size, "%02X%02X%02X%02X", addr[0], addr[1], addr[2], addr[3]);
1372 break;
1373 case AF_INET6:
1374 addr = (unsigned char *)&((struct sockaddr_in6 *)sockaddr)->sin6_addr.s6_addr;
1375 iret = snprintf(dst, size, "%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X",
1376 addr[0], addr[1], addr[2], addr[3], addr[4], addr[5], addr[6], addr[7],
1377 addr[8], addr[9], addr[10], addr[11], addr[12], addr[13], addr[14], addr[15]);
1378 break;
1379 default:
1380 return NULL;
1381 }
William Lallemand5f232402012-04-05 18:02:55 +02001382 if (iret < 0 || iret > size)
1383 return NULL;
1384 ret += iret;
1385 } else {
1386 addr_to_str((struct sockaddr_storage *)sockaddr, pn, sizeof(pn));
1387 ret = lf_text(dst, pn, size, node);
1388 if (ret == NULL)
1389 return NULL;
1390 }
1391 return ret;
1392}
1393
1394/*
1395 * Write a port to the log
1396 * +X option write in hexadecimal notation, most signifant byte on the left
1397 */
Willy Tarreau26ffa852018-09-05 15:23:10 +02001398char *lf_port(char *dst, const struct sockaddr *sockaddr, size_t size, const struct logformat_node *node)
William Lallemand5f232402012-04-05 18:02:55 +02001399{
1400 char *ret = dst;
1401 int iret;
1402
1403 if (node->options & LOG_OPT_HEXA) {
1404 const unsigned char *port = (const unsigned char *)&((struct sockaddr_in *)sockaddr)->sin_port;
1405 iret = snprintf(dst, size, "%02X%02X", port[0], port[1]);
1406 if (iret < 0 || iret > size)
1407 return NULL;
1408 ret += iret;
1409 } else {
1410 ret = ltoa_o(get_host_port((struct sockaddr_storage *)sockaddr), dst, size);
1411 if (ret == NULL)
1412 return NULL;
1413 }
1414 return ret;
1415}
1416
Dragan Dosen1322d092015-09-22 16:05:32 +02001417/* Re-generate time-based part of the syslog header in RFC3164 format at
1418 * the beginning of logheader once a second and return the pointer to the
1419 * first character after it.
Willy Tarreaub1a2faf2012-03-19 16:51:53 +01001420 */
Dragan Dosen0b85ece2015-09-25 19:17:44 +02001421static char *update_log_hdr(const time_t time)
Willy Tarreaubaaee002006-06-26 02:48:02 +02001422{
Christopher Fauletf8188c62017-06-02 16:20:16 +02001423 static THREAD_LOCAL long tvsec;
Willy Tarreau83061a82018-07-13 11:56:34 +02001424 static THREAD_LOCAL struct buffer host = { };
Christopher Fauletf8188c62017-06-02 16:20:16 +02001425 static THREAD_LOCAL int sep = 0;
Willy Tarreaubaaee002006-06-26 02:48:02 +02001426
Willy Tarreau55e2f5a2019-05-05 10:11:39 +02001427 if (unlikely(time != tvsec || logheader_end == NULL)) {
Willy Tarreaubaaee002006-06-26 02:48:02 +02001428 /* this string is rebuild only once a second */
Willy Tarreaufe944602007-10-25 10:34:16 +02001429 struct tm tm;
Willy Tarreaub1a2faf2012-03-19 16:51:53 +01001430 int hdr_len;
Willy Tarreaufe944602007-10-25 10:34:16 +02001431
Dragan Dosen0b85ece2015-09-25 19:17:44 +02001432 tvsec = time;
Willy Tarreaufe944602007-10-25 10:34:16 +02001433 get_localtime(tvsec, &tm);
Willy Tarreaubaaee002006-06-26 02:48:02 +02001434
Willy Tarreau843b7cb2018-07-13 10:54:26 +02001435 if (unlikely(global.log_send_hostname != host.area)) {
1436 host.area = global.log_send_hostname;
1437 host.data = host.area ? strlen(host.area) : 0;
1438 sep = host.data ? 1 : 0;
Dragan Dosen43885c72015-10-01 13:18:13 +02001439 }
1440
Dragan Dosen59cee972015-09-19 22:09:02 +02001441 hdr_len = snprintf(logheader, global.max_syslog_len,
Dragan Dosen43885c72015-10-01 13:18:13 +02001442 "<<<<>%s %2d %02d:%02d:%02d %.*s%*s",
Willy Tarreaufe944602007-10-25 10:34:16 +02001443 monthname[tm.tm_mon],
Dragan Dosen43885c72015-10-01 13:18:13 +02001444 tm.tm_mday, tm.tm_hour, tm.tm_min, tm.tm_sec,
Willy Tarreau843b7cb2018-07-13 10:54:26 +02001445 (int)host.data, host.area, sep, "");
Willy Tarreaubaaee002006-06-26 02:48:02 +02001446 /* WARNING: depending upon implementations, snprintf may return
1447 * either -1 or the number of bytes that would be needed to store
1448 * the total message. In both cases, we must adjust it.
1449 */
Willy Tarreau18324f52014-06-27 18:10:07 +02001450 if (hdr_len < 0 || hdr_len > global.max_syslog_len)
1451 hdr_len = global.max_syslog_len;
Willy Tarreaubaaee002006-06-26 02:48:02 +02001452
Willy Tarreau55e2f5a2019-05-05 10:11:39 +02001453 logheader_end = logheader + hdr_len;
Willy Tarreaubaaee002006-06-26 02:48:02 +02001454 }
1455
Willy Tarreau55e2f5a2019-05-05 10:11:39 +02001456 logheader_end[0] = 0; // ensure we get rid of any previous attempt
Willy Tarreau094af4e2015-01-07 15:03:42 +01001457
Willy Tarreau55e2f5a2019-05-05 10:11:39 +02001458 return logheader_end;
William Lallemand2a4a44f2012-02-06 16:00:33 +01001459}
1460
Dragan Dosen1322d092015-09-22 16:05:32 +02001461/* Re-generate time-based part of the syslog header in RFC5424 format at
1462 * the beginning of logheader_rfc5424 once a second and return the pointer
1463 * to the first character after it.
1464 */
Dragan Dosen0b85ece2015-09-25 19:17:44 +02001465static char *update_log_hdr_rfc5424(const time_t time)
Dragan Dosen1322d092015-09-22 16:05:32 +02001466{
Christopher Fauletf8188c62017-06-02 16:20:16 +02001467 static THREAD_LOCAL long tvsec;
Benoit GARNIERb413c2a2016-03-27 11:08:03 +02001468 const char *gmt_offset;
Dragan Dosen1322d092015-09-22 16:05:32 +02001469
Willy Tarreau55e2f5a2019-05-05 10:11:39 +02001470 if (unlikely(time != tvsec || logheader_rfc5424_end == NULL)) {
Dragan Dosen1322d092015-09-22 16:05:32 +02001471 /* this string is rebuild only once a second */
1472 struct tm tm;
1473 int hdr_len;
1474
Dragan Dosen0b85ece2015-09-25 19:17:44 +02001475 tvsec = time;
Dragan Dosen1322d092015-09-22 16:05:32 +02001476 get_localtime(tvsec, &tm);
Benoit GARNIERe2e5bde2016-03-27 03:04:16 +02001477 gmt_offset = get_gmt_offset(time, &tm);
Dragan Dosen1322d092015-09-22 16:05:32 +02001478
1479 hdr_len = snprintf(logheader_rfc5424, global.max_syslog_len,
Dragan Dosen17def462015-10-09 21:31:43 +02001480 "<<<<>1 %4d-%02d-%02dT%02d:%02d:%02d%.3s:%.2s %s ",
Dragan Dosen1322d092015-09-22 16:05:32 +02001481 tm.tm_year+1900, tm.tm_mon+1, tm.tm_mday,
Dragan Dosen17def462015-10-09 21:31:43 +02001482 tm.tm_hour, tm.tm_min, tm.tm_sec,
Benoit GARNIERb413c2a2016-03-27 11:08:03 +02001483 gmt_offset, gmt_offset+3,
Dragan Dosen43885c72015-10-01 13:18:13 +02001484 global.log_send_hostname ? global.log_send_hostname : hostname);
Dragan Dosen1322d092015-09-22 16:05:32 +02001485 /* WARNING: depending upon implementations, snprintf may return
1486 * either -1 or the number of bytes that would be needed to store
1487 * the total message. In both cases, we must adjust it.
1488 */
1489 if (hdr_len < 0 || hdr_len > global.max_syslog_len)
1490 hdr_len = global.max_syslog_len;
1491
Willy Tarreau55e2f5a2019-05-05 10:11:39 +02001492 logheader_rfc5424_end = logheader_rfc5424 + hdr_len;
Dragan Dosen1322d092015-09-22 16:05:32 +02001493 }
1494
Willy Tarreau55e2f5a2019-05-05 10:11:39 +02001495 logheader_rfc5424_end[0] = 0; // ensure we get rid of any previous attempt
Dragan Dosen1322d092015-09-22 16:05:32 +02001496
Willy Tarreau55e2f5a2019-05-05 10:11:39 +02001497 return logheader_rfc5424_end;
Dragan Dosen1322d092015-09-22 16:05:32 +02001498}
1499
William Lallemand2a4a44f2012-02-06 16:00:33 +01001500/*
Dragan Dosen59cee972015-09-19 22:09:02 +02001501 * This function sends the syslog message using a printf format string. It
1502 * expects an LF-terminated message.
William Lallemand2a4a44f2012-02-06 16:00:33 +01001503 */
1504void send_log(struct proxy *p, int level, const char *format, ...)
1505{
1506 va_list argp;
Willy Tarreaub1a2faf2012-03-19 16:51:53 +01001507 int data_len;
William Lallemand2a4a44f2012-02-06 16:00:33 +01001508
Willy Tarreau8c97ab52015-01-15 16:29:53 +01001509 if (level < 0 || format == NULL || logline == NULL)
William Lallemand2a4a44f2012-02-06 16:00:33 +01001510 return;
1511
William Lallemand2a4a44f2012-02-06 16:00:33 +01001512 va_start(argp, format);
Dragan Dosen59cee972015-09-19 22:09:02 +02001513 data_len = vsnprintf(logline, global.max_syslog_len, format, argp);
Willy Tarreau18324f52014-06-27 18:10:07 +02001514 if (data_len < 0 || data_len > global.max_syslog_len)
1515 data_len = global.max_syslog_len;
Willy Tarreaubaaee002006-06-26 02:48:02 +02001516 va_end(argp);
William Lallemand2a4a44f2012-02-06 16:00:33 +01001517
Christopher Faulet5c6fefc2019-08-11 19:40:12 +02001518 __send_log((p ? &p->logsrvs : NULL), (p ? &p->log_tag : NULL), level,
1519 logline, data_len, default_rfc5424_sd_log_format, 2);
William Lallemand2a4a44f2012-02-06 16:00:33 +01001520}
1521
1522/*
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001523 * This function sends a syslog message to <logsrv>.
1524 * <pid_str> is the string to be used for the PID of the caller, <pid_size> is length.
1525 * Same thing for <sd> and <sd_size> which are used for the structured-data part
1526 * in RFC5424 formatted syslog messages, and <tag_str> and <tag_size> the syslog tag.
Dragan Dosen0b85ece2015-09-25 19:17:44 +02001527 * It overrides the last byte of the message vector with an LF character.
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001528 * Does not return any error,
William Lallemand2a4a44f2012-02-06 16:00:33 +01001529 */
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001530static inline void __do_send_log(struct logsrv *logsrv, int nblogger, char *pid_str, size_t pid_size,
1531 int level, char *message, size_t size, char *sd, size_t sd_size,
1532 char *tag_str, size_t tag_size)
William Lallemand2a4a44f2012-02-06 16:00:33 +01001533{
Christopher Fauletf8188c62017-06-02 16:20:16 +02001534 static THREAD_LOCAL struct iovec iovec[NB_MSG_IOVEC_ELEMENTS] = { };
1535 static THREAD_LOCAL struct msghdr msghdr = {
1536 //.msg_iov = iovec,
Dragan Dosen609ac2a2015-09-16 18:25:42 +02001537 .msg_iovlen = NB_MSG_IOVEC_ELEMENTS
1538 };
Christopher Fauletf8188c62017-06-02 16:20:16 +02001539 static THREAD_LOCAL int logfdunix = -1; /* syslog to AF_UNIX socket */
1540 static THREAD_LOCAL int logfdinet = -1; /* syslog to AF_INET socket */
1541 static THREAD_LOCAL char *dataptr = NULL;
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001542 time_t time = date.tv_sec;
Dragan Dosen1322d092015-09-22 16:05:32 +02001543 char *hdr, *hdr_ptr;
Dragan Dosen59cee972015-09-19 22:09:02 +02001544 size_t hdr_size;
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001545 int fac_level;
1546 int *plogfd;
1547 char *pid_sep1 = "", *pid_sep2 = "";
1548 char logheader_short[3];
1549 int sent;
1550 int maxlen;
1551 int hdr_max = 0;
1552 int tag_max = 0;
1553 int pid_sep1_max = 0;
Frédéric Lécaille90a10ae2019-05-14 10:57:58 +02001554 int pid_max = 0;
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001555 int pid_sep2_max = 0;
1556 int sd_max = 0;
1557 int max = 0;
Christopher Fauletf8188c62017-06-02 16:20:16 +02001558
1559 msghdr.msg_iov = iovec;
William Lallemand2a4a44f2012-02-06 16:00:33 +01001560
1561 dataptr = message;
Willy Tarreaubaaee002006-06-26 02:48:02 +02001562
Willy Tarreauf3dc30f2019-08-30 14:18:44 +02001563 if (logsrv->type == LOG_TARGET_FD) {
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001564 /* the socket's address is a file descriptor */
1565 plogfd = (int *)&((struct sockaddr_in *)&logsrv->addr)->sin_addr.s_addr;
Robert Tsai81ae1952007-12-05 10:47:29 +01001566 }
Willy Tarreauc046d162019-08-30 15:24:59 +02001567 else if (logsrv->type == LOG_TARGET_BUFFER) {
1568 plogfd = NULL;
1569 }
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001570 else if (logsrv->addr.ss_family == AF_UNIX)
1571 plogfd = &logfdunix;
1572 else
1573 plogfd = &logfdinet;
Robert Tsai81ae1952007-12-05 10:47:29 +01001574
Willy Tarreauc046d162019-08-30 15:24:59 +02001575 if (plogfd && unlikely(*plogfd < 0)) {
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001576 /* socket not successfully initialized yet */
1577 if ((*plogfd = socket(logsrv->addr.ss_family, SOCK_DGRAM,
1578 (logsrv->addr.ss_family == AF_UNIX) ? 0 : IPPROTO_UDP)) < 0) {
1579 static char once;
William Lallemand0f99e342011-10-12 17:50:54 +02001580
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001581 if (!once) {
1582 once = 1; /* note: no need for atomic ops here */
1583 ha_alert("socket() failed in logger #%d: %s (errno=%d)\n",
1584 nblogger, strerror(errno), errno);
1585 }
1586 return;
1587 } else {
1588 /* we don't want to receive anything on this socket */
1589 setsockopt(*plogfd, SOL_SOCKET, SO_RCVBUF, &zero, sizeof(zero));
1590 /* does nothing under Linux, maybe needed for others */
1591 shutdown(*plogfd, SHUT_RD);
1592 fcntl(*plogfd, F_SETFD, fcntl(*plogfd, F_GETFD, FD_CLOEXEC) | FD_CLOEXEC);
1593 }
Dragan Dosen43885c72015-10-01 13:18:13 +02001594 }
1595
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001596 switch (logsrv->format) {
1597 case LOG_FORMAT_RFC3164:
1598 hdr = logheader;
1599 hdr_ptr = update_log_hdr(time);
1600 break;
Willy Tarreauc7c7be22014-06-23 18:07:15 +02001601
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001602 case LOG_FORMAT_RFC5424:
1603 hdr = logheader_rfc5424;
1604 hdr_ptr = update_log_hdr_rfc5424(time);
1605 sd_max = sd_size; /* the SD part allowed only in RFC5424 */
1606 break;
William Lallemandbddd4fd2012-02-27 11:23:10 +01001607
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001608 case LOG_FORMAT_SHORT:
1609 /* all fields are known, skip the header generation */
1610 hdr = logheader_short;
1611 hdr[0] = '<';
1612 hdr[1] = '0' + MAX(level, logsrv->minlvl);
1613 hdr[2] = '>';
1614 hdr_ptr = hdr;
1615 hdr_max = 3;
1616 maxlen = logsrv->maxlen - hdr_max;
1617 max = MIN(size, maxlen) - 1;
1618 goto send;
Willy Tarreau204e3f12018-12-15 15:48:48 +01001619
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001620 case LOG_FORMAT_RAW:
1621 /* all fields are known, skip the header generation */
1622 hdr_ptr = hdr = "";
1623 hdr_max = 0;
1624 maxlen = logsrv->maxlen;
1625 max = MIN(size, maxlen) - 1;
1626 goto send;
Willy Tarreauc98aebc2018-03-20 11:17:29 +01001627
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001628 default:
1629 return; /* must never happen */
1630 }
Willy Tarreauc7c7be22014-06-23 18:07:15 +02001631
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001632 hdr_size = hdr_ptr - hdr;
Dragan Dosen1322d092015-09-22 16:05:32 +02001633
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001634 /* For each target, we may have a different facility.
1635 * We can also have a different log level for each message.
1636 * This induces variations in the message header length.
1637 * Since we don't want to recompute it each time, nor copy it every
1638 * time, we only change the facility in the pre-computed header,
1639 * and we change the pointer to the header accordingly.
1640 */
1641 fac_level = (logsrv->facility << 3) + MAX(level, logsrv->minlvl);
1642 hdr_ptr = hdr + 3; /* last digit of the log level */
1643 do {
1644 *hdr_ptr = '0' + fac_level % 10;
1645 fac_level /= 10;
1646 hdr_ptr--;
1647 } while (fac_level && hdr_ptr > hdr);
1648 *hdr_ptr = '<';
Dragan Dosen1322d092015-09-22 16:05:32 +02001649
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001650 hdr_max = hdr_size - (hdr_ptr - hdr);
Willy Tarreaue8746a02018-11-12 08:45:00 +01001651
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001652 /* time-based header */
1653 if (unlikely(hdr_size >= logsrv->maxlen)) {
1654 hdr_max = MIN(hdr_max, logsrv->maxlen) - 1;
1655 sd_max = 0;
1656 goto send;
1657 }
Willy Tarreauc1b06452018-11-12 11:57:56 +01001658
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001659 maxlen = logsrv->maxlen - hdr_max;
Dragan Dosen1322d092015-09-22 16:05:32 +02001660
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001661 /* tag */
Frédéric Lécaille90a10ae2019-05-14 10:57:58 +02001662 tag_max = tag_size;
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001663 if (unlikely(tag_max >= maxlen)) {
1664 tag_max = maxlen - 1;
1665 sd_max = 0;
1666 goto send;
1667 }
Dragan Dosen1322d092015-09-22 16:05:32 +02001668
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001669 maxlen -= tag_max;
William Lallemand2a4a44f2012-02-06 16:00:33 +01001670
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001671 /* first pid separator */
1672 pid_sep1_max = log_formats[logsrv->format].pid.sep1.data;
1673 if (unlikely(pid_sep1_max >= maxlen)) {
1674 pid_sep1_max = maxlen - 1;
1675 sd_max = 0;
1676 goto send;
1677 }
Dragan Dosen59cee972015-09-19 22:09:02 +02001678
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001679 pid_sep1 = log_formats[logsrv->format].pid.sep1.area;
1680 maxlen -= pid_sep1_max;
Dragan Dosen59cee972015-09-19 22:09:02 +02001681
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001682 /* pid */
Frédéric Lécaille90a10ae2019-05-14 10:57:58 +02001683 pid_max = pid_size;
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001684 if (unlikely(pid_size >= maxlen)) {
1685 pid_size = maxlen - 1;
1686 sd_max = 0;
1687 goto send;
1688 }
Dragan Dosen68d2e3a2015-09-19 22:35:44 +02001689
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001690 maxlen -= pid_size;
Dragan Dosen43885c72015-10-01 13:18:13 +02001691
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001692 /* second pid separator */
1693 pid_sep2_max = log_formats[logsrv->format].pid.sep2.data;
1694 if (unlikely(pid_sep2_max >= maxlen)) {
1695 pid_sep2_max = maxlen - 1;
1696 sd_max = 0;
1697 goto send;
1698 }
Dragan Dosen43885c72015-10-01 13:18:13 +02001699
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001700 pid_sep2 = log_formats[logsrv->format].pid.sep2.area;
1701 maxlen -= pid_sep2_max;
Dragan Dosen68d2e3a2015-09-19 22:35:44 +02001702
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001703 /* structured-data */
1704 if (sd_max >= maxlen) {
1705 sd_max = maxlen - 1;
1706 goto send;
1707 }
Dragan Dosen59cee972015-09-19 22:09:02 +02001708
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001709 max = MIN(size, maxlen - sd_max) - 1;
1710send:
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001711 if (logsrv->addr.ss_family == AF_UNSPEC) {
Willy Tarreauc046d162019-08-30 15:24:59 +02001712 /* the target is a file descriptor or a ring buffer */
Willy Tarreaud52a7f82019-08-30 14:05:35 +02001713 struct ist msg[7];
1714
1715 msg[0].ptr = hdr_ptr; msg[0].len = hdr_max;
1716 msg[1].ptr = tag_str; msg[1].len = tag_max;
1717 msg[2].ptr = pid_sep1; msg[2].len = pid_sep1_max;
1718 msg[3].ptr = pid_str; msg[3].len = pid_max;
1719 msg[4].ptr = pid_sep2; msg[4].len = pid_sep2_max;
1720 msg[5].ptr = sd; msg[5].len = sd_max;
1721 msg[6].ptr = dataptr; msg[6].len = max;
1722
Willy Tarreauc046d162019-08-30 15:24:59 +02001723 if (logsrv->type == LOG_TARGET_BUFFER)
1724 sent = ring_write(logsrv->ring, ~0, NULL, 0, msg, 7);
1725 else /* LOG_TARGET_FD */
1726 sent = fd_write_frag_line(*plogfd, ~0, NULL, 0, msg, 7, 1);
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001727 }
1728 else {
Willy Tarreaud52a7f82019-08-30 14:05:35 +02001729 iovec[0].iov_base = hdr_ptr;
1730 iovec[0].iov_len = hdr_max;
1731 iovec[1].iov_base = tag_str;
1732 iovec[1].iov_len = tag_max;
1733 iovec[2].iov_base = pid_sep1;
1734 iovec[2].iov_len = pid_sep1_max;
1735 iovec[3].iov_base = pid_str;
1736 iovec[3].iov_len = pid_max;
1737 iovec[4].iov_base = pid_sep2;
1738 iovec[4].iov_len = pid_sep2_max;
1739 iovec[5].iov_base = sd;
1740 iovec[5].iov_len = sd_max;
1741 iovec[6].iov_base = dataptr;
1742 iovec[6].iov_len = max;
1743 iovec[7].iov_base = "\n"; /* insert a \n at the end of the message */
1744 iovec[7].iov_len = 1;
1745
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001746 msghdr.msg_name = (struct sockaddr *)&logsrv->addr;
1747 msghdr.msg_namelen = get_addr_len(&logsrv->addr);
Dragan Dosen43885c72015-10-01 13:18:13 +02001748
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001749 sent = sendmsg(*plogfd, &msghdr, MSG_DONTWAIT | MSG_NOSIGNAL);
1750 }
Dragan Dosen43885c72015-10-01 13:18:13 +02001751
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001752 if (sent < 0) {
1753 static char once;
Dragan Dosen43885c72015-10-01 13:18:13 +02001754
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001755 if (errno == EAGAIN)
1756 _HA_ATOMIC_ADD(&dropped_logs, 1);
1757 else if (!once) {
1758 once = 1; /* note: no need for atomic ops here */
1759 ha_alert("sendmsg()/writev() failed in logger #%d: %s (errno=%d)\n",
1760 nblogger, strerror(errno), errno);
Dragan Dosen0b85ece2015-09-25 19:17:44 +02001761 }
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001762 }
1763}
Dragan Dosen59cee972015-09-19 22:09:02 +02001764
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001765/*
1766 * This function sends a syslog message.
1767 * It doesn't care about errors nor does it report them.
1768 * The arguments <sd> and <sd_size> are used for the structured-data part
1769 * in RFC5424 formatted syslog messages.
1770 */
Christopher Faulet5c6fefc2019-08-11 19:40:12 +02001771void __send_log(struct list *logsrvs, struct buffer *tag, int level,
1772 char *message, size_t size, char *sd, size_t sd_size)
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001773{
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001774 struct logsrv *logsrv;
1775 int nblogger;
1776 static THREAD_LOCAL int curr_pid;
1777 static THREAD_LOCAL char pidstr[100];
1778 static THREAD_LOCAL struct buffer pid;
Dragan Dosen609ac2a2015-09-16 18:25:42 +02001779
Christopher Faulet5c6fefc2019-08-11 19:40:12 +02001780 if (logsrvs == NULL) {
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001781 if (!LIST_ISEMPTY(&global.logsrvs)) {
1782 logsrvs = &global.logsrvs;
Willy Tarreau5a32ecc2018-11-12 07:34:59 +01001783 }
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001784 }
Christopher Faulet5c6fefc2019-08-11 19:40:12 +02001785 if (!tag || !tag->area)
1786 tag = &global.log_tag;
Willy Tarreau18324f52014-06-27 18:10:07 +02001787
Christopher Faulet5c6fefc2019-08-11 19:40:12 +02001788 if (!logsrvs || LIST_ISEMPTY(logsrvs))
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001789 return;
Willy Tarreauc98aebc2018-03-20 11:17:29 +01001790
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001791 if (unlikely(curr_pid != getpid())) {
1792 curr_pid = getpid();
1793 ltoa_o(curr_pid, pidstr, sizeof(pidstr));
1794 chunk_initstr(&pid, pidstr);
1795 }
1796
1797 /* Send log messages to syslog server. */
1798 nblogger = 0;
1799 list_for_each_entry(logsrv, logsrvs, list) {
Frédéric Lécailled803e472019-04-25 07:42:09 +02001800 static THREAD_LOCAL int in_range = 1;
1801
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001802 /* we can filter the level of the messages that are sent to each logger */
1803 if (level > logsrv->level)
1804 continue;
1805
Frédéric Lécailled803e472019-04-25 07:42:09 +02001806 if (logsrv->lb.smp_rgs) {
1807 struct smp_log_range *curr_rg;
1808
1809 HA_SPIN_LOCK(LOGSRV_LOCK, &logsrv->lock);
1810 curr_rg = &logsrv->lb.smp_rgs[logsrv->lb.curr_rg];
1811 in_range = in_smp_log_range(curr_rg, logsrv->lb.curr_idx);
1812 if (in_range) {
1813 /* Let's consume this range. */
1814 curr_rg->curr_idx = (curr_rg->curr_idx + 1) % curr_rg->sz;
1815 if (!curr_rg->curr_idx) {
1816 /* If consumed, let's select the next range. */
1817 logsrv->lb.curr_rg = (logsrv->lb.curr_rg + 1) % logsrv->lb.smp_rgs_sz;
1818 }
1819 }
1820 logsrv->lb.curr_idx = (logsrv->lb.curr_idx + 1) % logsrv->lb.smp_sz;
1821 HA_SPIN_UNLOCK(LOGSRV_LOCK, &logsrv->lock);
1822 }
1823 if (in_range)
1824 __do_send_log(logsrv, ++nblogger, pid.area, pid.data, level,
1825 message, size, sd, sd_size, tag->area, tag->data);
Willy Tarreaubaaee002006-06-26 02:48:02 +02001826 }
1827}
1828
1829
Willy Tarreauc89ccb62012-04-05 21:18:22 +02001830const 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 +01001831const char sess_set_cookie[8] = "NPDIRU67"; /* No set-cookie, Set-cookie found and left unchanged (passive),
1832 Set-cookie Deleted, Set-Cookie Inserted, Set-cookie Rewritten,
1833 Set-cookie Updated, unknown, unknown */
1834
William Lallemand1d705562012-03-12 12:46:41 +01001835/*
1836 * try to write a character if there is enough space, or goto out
1837 */
William Lallemandbddd4fd2012-02-27 11:23:10 +01001838#define LOGCHAR(x) do { \
William Lallemand1d705562012-03-12 12:46:41 +01001839 if (tmplog < dst + maxsize - 1) { \
William Lallemandbddd4fd2012-02-27 11:23:10 +01001840 *(tmplog++) = (x); \
1841 } else { \
1842 goto out; \
1843 } \
1844 } while(0)
1845
Dragan Dosen835b9212016-02-12 13:23:03 +01001846
Willy Tarreaub6b3df32018-11-26 16:31:20 +01001847/* Initializes some log data at boot */
1848static void init_log()
Dragan Dosen835b9212016-02-12 13:23:03 +01001849{
1850 char *tmp;
Willy Tarreaue10cd482018-09-10 18:16:53 +02001851 int i;
Dragan Dosen835b9212016-02-12 13:23:03 +01001852
1853 /* Initialize the escape map for the RFC5424 structured-data : '"\]'
1854 * inside PARAM-VALUE should be escaped with '\' as prefix.
1855 * See https://tools.ietf.org/html/rfc5424#section-6.3.3 for more
1856 * details.
1857 */
1858 memset(rfc5424_escape_map, 0, sizeof(rfc5424_escape_map));
1859
1860 tmp = "\"\\]";
1861 while (*tmp) {
Willy Tarreau1bfd6022019-06-07 11:10:07 +02001862 ha_bit_set(*tmp, rfc5424_escape_map);
Dragan Dosen835b9212016-02-12 13:23:03 +01001863 tmp++;
1864 }
Willy Tarreaue10cd482018-09-10 18:16:53 +02001865
1866 /* initialize the log header encoding map : '{|}"#' should be encoded with
1867 * '#' as prefix, as well as non-printable characters ( <32 or >= 127 ).
1868 * URL encoding only requires '"', '#' to be encoded as well as non-
1869 * printable characters above.
1870 */
1871 memset(hdr_encode_map, 0, sizeof(hdr_encode_map));
1872 memset(url_encode_map, 0, sizeof(url_encode_map));
1873 for (i = 0; i < 32; i++) {
Willy Tarreau1bfd6022019-06-07 11:10:07 +02001874 ha_bit_set(i, hdr_encode_map);
1875 ha_bit_set(i, url_encode_map);
Willy Tarreaue10cd482018-09-10 18:16:53 +02001876 }
1877 for (i = 127; i < 256; i++) {
Willy Tarreau1bfd6022019-06-07 11:10:07 +02001878 ha_bit_set(i, hdr_encode_map);
1879 ha_bit_set(i, url_encode_map);
Willy Tarreaue10cd482018-09-10 18:16:53 +02001880 }
1881
1882 tmp = "\"#{|}";
1883 while (*tmp) {
Willy Tarreau1bfd6022019-06-07 11:10:07 +02001884 ha_bit_set(*tmp, hdr_encode_map);
Willy Tarreaue10cd482018-09-10 18:16:53 +02001885 tmp++;
1886 }
1887
1888 tmp = "\"#";
1889 while (*tmp) {
Willy Tarreau1bfd6022019-06-07 11:10:07 +02001890 ha_bit_set(*tmp, url_encode_map);
Willy Tarreaue10cd482018-09-10 18:16:53 +02001891 tmp++;
1892 }
1893
1894 /* initialize the http header encoding map. The draft httpbis define the
1895 * header content as:
1896 *
1897 * HTTP-message = start-line
1898 * *( header-field CRLF )
1899 * CRLF
1900 * [ message-body ]
1901 * header-field = field-name ":" OWS field-value OWS
1902 * field-value = *( field-content / obs-fold )
1903 * field-content = field-vchar [ 1*( SP / HTAB ) field-vchar ]
1904 * obs-fold = CRLF 1*( SP / HTAB )
1905 * field-vchar = VCHAR / obs-text
1906 * VCHAR = %x21-7E
1907 * obs-text = %x80-FF
1908 *
1909 * All the chars are encoded except "VCHAR", "obs-text", SP and HTAB.
1910 * The encoded chars are form 0x00 to 0x08, 0x0a to 0x1f and 0x7f. The
Joseph Herlant85b40592018-11-15 12:10:04 -08001911 * "obs-fold" is voluntarily forgotten because haproxy remove this.
Willy Tarreaue10cd482018-09-10 18:16:53 +02001912 */
1913 memset(http_encode_map, 0, sizeof(http_encode_map));
1914 for (i = 0x00; i <= 0x08; i++)
Willy Tarreau1bfd6022019-06-07 11:10:07 +02001915 ha_bit_set(i, http_encode_map);
Willy Tarreaue10cd482018-09-10 18:16:53 +02001916 for (i = 0x0a; i <= 0x1f; i++)
Willy Tarreau1bfd6022019-06-07 11:10:07 +02001917 ha_bit_set(i, http_encode_map);
1918 ha_bit_set(0x7f, http_encode_map);
Dragan Dosen835b9212016-02-12 13:23:03 +01001919}
William Lallemand1d705562012-03-12 12:46:41 +01001920
Willy Tarreaub6b3df32018-11-26 16:31:20 +01001921INITCALL0(STG_PREPARE, init_log);
1922
Christopher Faulet0132d062017-07-26 15:33:35 +02001923/* Initialize log buffers used for syslog messages */
1924int init_log_buffers()
1925{
1926 logheader = my_realloc2(logheader, global.max_syslog_len + 1);
Willy Tarreau55e2f5a2019-05-05 10:11:39 +02001927 logheader_end = NULL;
Christopher Faulet0132d062017-07-26 15:33:35 +02001928 logheader_rfc5424 = my_realloc2(logheader_rfc5424, global.max_syslog_len + 1);
Willy Tarreau55e2f5a2019-05-05 10:11:39 +02001929 logheader_rfc5424_end = NULL;
Christopher Faulet0132d062017-07-26 15:33:35 +02001930 logline = my_realloc2(logline, global.max_syslog_len + 1);
1931 logline_rfc5424 = my_realloc2(logline_rfc5424, global.max_syslog_len + 1);
1932 if (!logheader || !logline_rfc5424 || !logline || !logline_rfc5424)
1933 return 0;
1934 return 1;
1935}
1936
1937/* Deinitialize log buffers used for syslog messages */
1938void deinit_log_buffers()
1939{
1940 free(logheader);
1941 free(logheader_rfc5424);
1942 free(logline);
1943 free(logline_rfc5424);
Willy Tarreau869efd52019-11-15 15:16:57 +01001944 ring_free(_HA_ATOMIC_XCHG(&startup_logs, NULL));
Christopher Faulet0132d062017-07-26 15:33:35 +02001945 logheader = NULL;
1946 logheader_rfc5424 = NULL;
1947 logline = NULL;
1948 logline_rfc5424 = NULL;
1949}
1950
Willy Tarreaudf974472012-12-28 02:44:01 +01001951/* Builds a log line in <dst> based on <list_format>, and stops before reaching
1952 * <maxsize> characters. Returns the size of the output string in characters,
1953 * not counting the trailing zero which is always added if the resulting size
Willy Tarreau09bb27c2018-09-05 16:55:15 +02001954 * is not zero. It requires a valid session and optionally a stream. If the
1955 * stream is NULL, default values will be assumed for the stream part.
Willy Tarreaudf974472012-12-28 02:44:01 +01001956 */
Willy Tarreau43c538e2018-09-05 14:58:15 +02001957int 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 +02001958{
Willy Tarreaue36cbcb2015-04-03 15:40:56 +02001959 struct proxy *fe = sess->fe;
Willy Tarreau09bb27c2018-09-05 16:55:15 +02001960 struct proxy *be;
1961 struct http_txn *txn;
1962 const struct strm_logs *logs;
Willy Tarreau8fa99842019-07-17 11:47:11 +02001963 struct connection *be_conn;
Willy Tarreau09bb27c2018-09-05 16:55:15 +02001964 unsigned int s_flags;
1965 unsigned int uniq_id;
Willy Tarreau83061a82018-07-13 11:56:34 +02001966 struct buffer chunk;
William Lallemandbddd4fd2012-02-27 11:23:10 +01001967 char *uri;
Andrew Hayworth0ebc55f2015-04-27 21:37:03 +00001968 char *spc;
Andrew Hayworthe63ac872015-07-31 16:14:16 +00001969 char *qmark;
Andrew Hayworth0ebc55f2015-04-27 21:37:03 +00001970 char *end;
Willy Tarreaufe944602007-10-25 10:34:16 +02001971 struct tm tm;
William Lallemandbddd4fd2012-02-27 11:23:10 +01001972 int t_request;
1973 int hdr;
1974 int last_isspace = 1;
Andrew Hayworth0ebc55f2015-04-27 21:37:03 +00001975 int nspaces = 0;
Willy Tarreaub1a2faf2012-03-19 16:51:53 +01001976 char *tmplog;
William Lallemand1d705562012-03-12 12:46:41 +01001977 char *ret;
1978 int iret;
William Lallemandbddd4fd2012-02-27 11:23:10 +01001979 struct logformat_node *tmp;
Thierry FOURNIER / OZON.IO4cac3592016-07-28 17:19:45 +02001980 struct timeval tv;
Willy Tarreau09bb27c2018-09-05 16:55:15 +02001981 struct strm_logs tmp_strm_log;
Willy Tarreaubaaee002006-06-26 02:48:02 +02001982
William Lallemandbddd4fd2012-02-27 11:23:10 +01001983 /* FIXME: let's limit ourselves to frontend logging for now. */
Willy Tarreaubaaee002006-06-26 02:48:02 +02001984
Willy Tarreau09bb27c2018-09-05 16:55:15 +02001985 if (likely(s)) {
1986 be = s->be;
1987 txn = s->txn;
1988 be_conn = cs_conn(objt_cs(s->si[1].end));
1989 s_flags = s->flags;
1990 uniq_id = s->uniq_id;
1991 logs = &s->logs;
1992 } else {
1993 /* we have no stream so we first need to initialize a few
1994 * things that are needed later. We do increment the request
1995 * ID so that it's uniquely assigned to this request just as
1996 * if the request had reached the point of being processed.
1997 * A request error is reported as it's the only element we have
1998 * here and which justifies emitting such a log.
1999 */
2000 be = fe;
2001 txn = NULL;
2002 be_conn = NULL;
2003 s_flags = SF_ERR_PRXCOND | SF_FINST_R;
Olivier Houchardd2ee3e72019-03-08 18:53:21 +01002004 uniq_id = _HA_ATOMIC_XADD(&global.req_count, 1);
Willy Tarreau09bb27c2018-09-05 16:55:15 +02002005
2006 /* prepare a valid log structure */
2007 tmp_strm_log.tv_accept = sess->tv_accept;
2008 tmp_strm_log.accept_date = sess->accept_date;
2009 tmp_strm_log.t_handshake = sess->t_handshake;
2010 tmp_strm_log.t_idle = tv_ms_elapsed(&sess->tv_accept, &now) - sess->t_handshake;
2011 tv_zero(&tmp_strm_log.tv_request);
2012 tmp_strm_log.t_queue = -1;
2013 tmp_strm_log.t_connect = -1;
2014 tmp_strm_log.t_data = -1;
2015 tmp_strm_log.t_close = tv_ms_elapsed(&sess->tv_accept, &now);
2016 tmp_strm_log.bytes_in = 0;
2017 tmp_strm_log.bytes_out = 0;
2018 tmp_strm_log.prx_queue_pos = 0;
2019 tmp_strm_log.srv_queue_pos = 0;
2020
2021 logs = &tmp_strm_log;
2022 }
2023
William Lallemandbddd4fd2012-02-27 11:23:10 +01002024 t_request = -1;
Willy Tarreau372ac5a2018-09-05 15:16:23 +02002025 if (tv_isge(&logs->tv_request, &logs->tv_accept))
2026 t_request = tv_ms_elapsed(&logs->tv_accept, &logs->tv_request);
William Lallemandbddd4fd2012-02-27 11:23:10 +01002027
William Lallemand1d705562012-03-12 12:46:41 +01002028 tmplog = dst;
Willy Tarreauc9bd0cc2009-05-10 11:57:02 +02002029
William Lallemandbddd4fd2012-02-27 11:23:10 +01002030 /* fill logbuffer */
William Lallemand1d705562012-03-12 12:46:41 +01002031 if (LIST_ISEMPTY(list_format))
2032 return 0;
William Lallemandbddd4fd2012-02-27 11:23:10 +01002033
William Lallemand1d705562012-03-12 12:46:41 +01002034 list_for_each_entry(tmp, list_format, list) {
Willy Tarreaub363a1f2013-10-01 10:45:07 +02002035 struct connection *conn;
Willy Tarreau4f653562012-10-12 19:48:16 +02002036 const char *src = NULL;
Willy Tarreauc8368452012-12-21 00:09:23 +01002037 struct sample *key;
Willy Tarreau83061a82018-07-13 11:56:34 +02002038 const struct buffer empty = { };
William Lallemandbddd4fd2012-02-27 11:23:10 +01002039
Willy Tarreauc8368452012-12-21 00:09:23 +01002040 switch (tmp->type) {
William Lallemand1d705562012-03-12 12:46:41 +01002041 case LOG_FMT_SEPARATOR:
William Lallemandbddd4fd2012-02-27 11:23:10 +01002042 if (!last_isspace) {
2043 LOGCHAR(' ');
2044 last_isspace = 1;
William Lallemandbddd4fd2012-02-27 11:23:10 +01002045 }
2046 break;
2047
William Lallemand1d705562012-03-12 12:46:41 +01002048 case LOG_FMT_TEXT: // text
William Lallemandbddd4fd2012-02-27 11:23:10 +01002049 src = tmp->arg;
William Lallemand5f232402012-04-05 18:02:55 +02002050 iret = strlcpy2(tmplog, src, dst + maxsize - tmplog);
William Lallemand1d705562012-03-12 12:46:41 +01002051 if (iret == 0)
William Lallemandbddd4fd2012-02-27 11:23:10 +01002052 goto out;
William Lallemand1d705562012-03-12 12:46:41 +01002053 tmplog += iret;
William Lallemandbddd4fd2012-02-27 11:23:10 +01002054 last_isspace = 0;
2055 break;
2056
Willy Tarreauc8368452012-12-21 00:09:23 +01002057 case LOG_FMT_EXPR: // sample expression, may be request or response
2058 key = NULL;
Olivier Houchardf90db442018-12-15 14:00:06 +01002059 if (tmp->options & LOG_OPT_REQ_CAP && s)
Adis Nezirovic79beb242015-07-06 15:41:02 +02002060 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 +01002061 if (!key && (tmp->options & LOG_OPT_RES_CAP) && s)
Adis Nezirovic79beb242015-07-06 15:41:02 +02002062 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 +01002063 if (tmp->options & LOG_OPT_HTTP)
Dragan Dosen835b9212016-02-12 13:23:03 +01002064 ret = lf_encode_chunk(tmplog, dst + maxsize,
2065 '%', http_encode_map, key ? &key->data.u.str : &empty, tmp);
Thierry FOURNIERd048d8b2014-03-13 16:46:18 +01002066 else
Willy Tarreau843b7cb2018-07-13 10:54:26 +02002067 ret = lf_text_len(tmplog,
2068 key ? key->data.u.str.area : NULL,
2069 key ? key->data.u.str.data : 0,
2070 dst + maxsize - tmplog,
2071 tmp);
Willy Tarreauc8368452012-12-21 00:09:23 +01002072 if (ret == 0)
2073 goto out;
2074 tmplog = ret;
2075 last_isspace = 0;
2076 break;
2077
Willy Tarreau2beef582012-12-20 17:22:52 +01002078 case LOG_FMT_CLIENTIP: // %ci
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_src(conn))
Willy Tarreau6c6365f2019-07-17 16:48:18 +02002081 ret = lf_ip(tmplog, (struct sockaddr *)conn->src, dst + maxsize - tmplog, tmp);
Willy Tarreaub363a1f2013-10-01 10:45:07 +02002082 else
2083 ret = lf_text_len(tmplog, NULL, 0, dst + maxsize - tmplog, tmp);
William Lallemand1d705562012-03-12 12:46:41 +01002084 if (ret == NULL)
William Lallemandbddd4fd2012-02-27 11:23:10 +01002085 goto out;
William Lallemand1d705562012-03-12 12:46:41 +01002086 tmplog = ret;
William Lallemandbddd4fd2012-02-27 11:23:10 +01002087 last_isspace = 0;
2088 break;
2089
Willy Tarreau2beef582012-12-20 17:22:52 +01002090 case LOG_FMT_CLIENTPORT: // %cp
Willy Tarreau9ad7bd42015-04-03 19:19:59 +02002091 conn = objt_conn(sess->origin);
Willy Tarreau8fa99842019-07-17 11:47:11 +02002092 if (conn && conn_get_src(conn)) {
Willy Tarreau6c6365f2019-07-17 16:48:18 +02002093 if (conn->src->ss_family == AF_UNIX) {
Willy Tarreaufb0afa72015-04-03 14:46:27 +02002094 ret = ltoa_o(sess->listener->luid, tmplog, dst + maxsize - tmplog);
Willy Tarreaub363a1f2013-10-01 10:45:07 +02002095 } else {
Willy Tarreau6c6365f2019-07-17 16:48:18 +02002096 ret = lf_port(tmplog, (struct sockaddr *)conn->src,
Willy Tarreaub363a1f2013-10-01 10:45:07 +02002097 dst + maxsize - tmplog, tmp);
2098 }
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_FRONTENDIP: // %fi
Willy Tarreau9ad7bd42015-04-03 19:19:59 +02002110 conn = objt_conn(sess->origin);
Willy Tarreau8fa99842019-07-17 11:47:11 +02002111 if (conn && conn_get_dst(conn)) {
Willy Tarreau6c6365f2019-07-17 16:48:18 +02002112 ret = lf_ip(tmplog, (struct sockaddr *)conn->dst, dst + maxsize - tmplog, tmp);
Willy Tarreaub363a1f2013-10-01 10:45:07 +02002113 }
2114 else
2115 ret = lf_text_len(tmplog, NULL, 0, dst + maxsize - tmplog, tmp);
2116
William Lallemand1d705562012-03-12 12:46:41 +01002117 if (ret == NULL)
William Lallemandbddd4fd2012-02-27 11:23:10 +01002118 goto out;
William Lallemand1d705562012-03-12 12:46:41 +01002119 tmplog = ret;
William Lallemandbddd4fd2012-02-27 11:23:10 +01002120 last_isspace = 0;
2121 break;
2122
Willy Tarreau2beef582012-12-20 17:22:52 +01002123 case LOG_FMT_FRONTENDPORT: // %fp
Willy Tarreau9ad7bd42015-04-03 19:19:59 +02002124 conn = objt_conn(sess->origin);
Willy Tarreau8fa99842019-07-17 11:47:11 +02002125 if (conn && conn_get_dst(conn)) {
Willy Tarreau6c6365f2019-07-17 16:48:18 +02002126 if (conn->dst->ss_family == AF_UNIX)
Willy Tarreaufb0afa72015-04-03 14:46:27 +02002127 ret = ltoa_o(sess->listener->luid, tmplog, dst + maxsize - tmplog);
Willy Tarreaub363a1f2013-10-01 10:45:07 +02002128 else
Willy Tarreau6c6365f2019-07-17 16:48:18 +02002129 ret = lf_port(tmplog, (struct sockaddr *)conn->dst, dst + maxsize - tmplog, tmp);
William Lallemand5f232402012-04-05 18:02:55 +02002130 }
Willy Tarreaub363a1f2013-10-01 10:45:07 +02002131 else
2132 ret = lf_text_len(tmplog, NULL, 0, dst + maxsize - tmplog, tmp);
2133
William Lallemand5f232402012-04-05 18:02:55 +02002134 if (ret == NULL)
2135 goto out;
2136 tmplog = ret;
2137 last_isspace = 0;
2138 break;
2139
Willy Tarreau2beef582012-12-20 17:22:52 +01002140 case LOG_FMT_BACKENDIP: // %bi
Willy Tarreau8fa99842019-07-17 11:47:11 +02002141 if (be_conn && conn_get_src(be_conn))
Willy Tarreau6c6365f2019-07-17 16:48:18 +02002142 ret = lf_ip(tmplog, (const struct sockaddr *)be_conn->src, dst + maxsize - tmplog, tmp);
Willy Tarreaub363a1f2013-10-01 10:45:07 +02002143 else
2144 ret = lf_text_len(tmplog, NULL, 0, dst + maxsize - tmplog, tmp);
2145
William Lallemand1d705562012-03-12 12:46:41 +01002146 if (ret == NULL)
William Lallemandb7ff6a32012-03-02 14:35:21 +01002147 goto out;
William Lallemand1d705562012-03-12 12:46:41 +01002148 tmplog = ret;
William Lallemandb7ff6a32012-03-02 14:35:21 +01002149 last_isspace = 0;
2150 break;
2151
Willy Tarreau2beef582012-12-20 17:22:52 +01002152 case LOG_FMT_BACKENDPORT: // %bp
Willy Tarreau8fa99842019-07-17 11:47:11 +02002153 if (be_conn && conn_get_src(be_conn))
Willy Tarreau6c6365f2019-07-17 16:48:18 +02002154 ret = lf_port(tmplog, (struct sockaddr *)be_conn->src, dst + maxsize - tmplog, tmp);
Willy Tarreaub363a1f2013-10-01 10:45:07 +02002155 else
2156 ret = lf_text_len(tmplog, NULL, 0, dst + maxsize - tmplog, tmp);
2157
William Lallemand5f232402012-04-05 18:02:55 +02002158 if (ret == NULL)
2159 goto out;
2160 tmplog = ret;
2161 last_isspace = 0;
2162 break;
2163
Willy Tarreau2beef582012-12-20 17:22:52 +01002164 case LOG_FMT_SERVERIP: // %si
Willy Tarreau8fa99842019-07-17 11:47:11 +02002165 if (be_conn && conn_get_dst(be_conn))
Willy Tarreau6c6365f2019-07-17 16:48:18 +02002166 ret = lf_ip(tmplog, (struct sockaddr *)be_conn->dst, dst + maxsize - tmplog, tmp);
Willy Tarreaub363a1f2013-10-01 10:45:07 +02002167 else
2168 ret = lf_text_len(tmplog, NULL, 0, dst + maxsize - tmplog, tmp);
2169
William Lallemand5f232402012-04-05 18:02:55 +02002170 if (ret == NULL)
2171 goto out;
2172 tmplog = ret;
2173 last_isspace = 0;
2174 break;
2175
Willy Tarreau2beef582012-12-20 17:22:52 +01002176 case LOG_FMT_SERVERPORT: // %sp
Willy Tarreau8fa99842019-07-17 11:47:11 +02002177 if (be_conn && conn_get_dst(be_conn))
Willy Tarreau6c6365f2019-07-17 16:48:18 +02002178 ret = lf_port(tmplog, (struct sockaddr *)be_conn->dst, dst + maxsize - tmplog, tmp);
Willy Tarreaub363a1f2013-10-01 10:45:07 +02002179 else
2180 ret = lf_text_len(tmplog, NULL, 0, dst + maxsize - tmplog, tmp);
2181
William Lallemand1d705562012-03-12 12:46:41 +01002182 if (ret == NULL)
William Lallemandb7ff6a32012-03-02 14:35:21 +01002183 goto out;
William Lallemand1d705562012-03-12 12:46:41 +01002184 tmplog = ret;
William Lallemandb7ff6a32012-03-02 14:35:21 +01002185 last_isspace = 0;
2186 break;
2187
Thierry FOURNIER / OZON.IO4cac3592016-07-28 17:19:45 +02002188 case LOG_FMT_DATE: // %t = accept date
Willy Tarreau372ac5a2018-09-05 15:16:23 +02002189 get_localtime(logs->accept_date.tv_sec, &tm);
2190 ret = date2str_log(tmplog, &tm, &logs->accept_date, dst + maxsize - tmplog);
William Lallemand1d705562012-03-12 12:46:41 +01002191 if (ret == NULL)
William Lallemandbddd4fd2012-02-27 11:23:10 +01002192 goto out;
William Lallemand1d705562012-03-12 12:46:41 +01002193 tmplog = ret;
William Lallemandbddd4fd2012-02-27 11:23:10 +01002194 last_isspace = 0;
2195 break;
2196
Thierry FOURNIER / OZON.IO4cac3592016-07-28 17:19:45 +02002197 case LOG_FMT_tr: // %tr = start of request date
2198 /* Note that the timers are valid if we get here */
Willy Tarreau372ac5a2018-09-05 15:16:23 +02002199 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 +02002200 get_localtime(tv.tv_sec, &tm);
2201 ret = date2str_log(tmplog, &tm, &tv, dst + maxsize - tmplog);
2202 if (ret == NULL)
2203 goto out;
2204 tmplog = ret;
2205 last_isspace = 0;
2206 break;
2207
2208 case LOG_FMT_DATEGMT: // %T = accept date, GMT
Willy Tarreau372ac5a2018-09-05 15:16:23 +02002209 get_gmtime(logs->accept_date.tv_sec, &tm);
William Lallemand5f232402012-04-05 18:02:55 +02002210 ret = gmt2str_log(tmplog, &tm, dst + maxsize - tmplog);
William Lallemand1d705562012-03-12 12:46:41 +01002211 if (ret == NULL)
William Lallemandbddd4fd2012-02-27 11:23:10 +01002212 goto out;
William Lallemand1d705562012-03-12 12:46:41 +01002213 tmplog = ret;
William Lallemandbddd4fd2012-02-27 11:23:10 +01002214 last_isspace = 0;
2215 break;
2216
Thierry FOURNIER / OZON.IO4cac3592016-07-28 17:19:45 +02002217 case LOG_FMT_trg: // %trg = start of request date, GMT
Willy Tarreau372ac5a2018-09-05 15:16:23 +02002218 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 +02002219 get_gmtime(tv.tv_sec, &tm);
2220 ret = gmt2str_log(tmplog, &tm, dst + maxsize - tmplog);
2221 if (ret == NULL)
2222 goto out;
2223 tmplog = ret;
2224 last_isspace = 0;
2225 break;
2226
2227 case LOG_FMT_DATELOCAL: // %Tl = accept date, local
Willy Tarreau372ac5a2018-09-05 15:16:23 +02002228 get_localtime(logs->accept_date.tv_sec, &tm);
2229 ret = localdate2str_log(tmplog, logs->accept_date.tv_sec, &tm, dst + maxsize - tmplog);
Yuxans Yao4e25b012012-10-19 10:36:09 +08002230 if (ret == NULL)
2231 goto out;
2232 tmplog = ret;
2233 last_isspace = 0;
2234 break;
2235
Thierry FOURNIER / OZON.IO4cac3592016-07-28 17:19:45 +02002236 case LOG_FMT_trl: // %trl = start of request date, local
Willy Tarreau372ac5a2018-09-05 15:16:23 +02002237 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 +02002238 get_localtime(tv.tv_sec, &tm);
2239 ret = localdate2str_log(tmplog, tv.tv_sec, &tm, dst + maxsize - tmplog);
2240 if (ret == NULL)
2241 goto out;
2242 tmplog = ret;
2243 last_isspace = 0;
2244 break;
2245
William Lallemand5f232402012-04-05 18:02:55 +02002246 case LOG_FMT_TS: // %Ts
William Lallemand5f232402012-04-05 18:02:55 +02002247 if (tmp->options & LOG_OPT_HEXA) {
Willy Tarreau372ac5a2018-09-05 15:16:23 +02002248 iret = snprintf(tmplog, dst + maxsize - tmplog, "%04X", (unsigned int)logs->accept_date.tv_sec);
William Lallemand5f232402012-04-05 18:02:55 +02002249 if (iret < 0 || iret > dst + maxsize - tmplog)
2250 goto out;
2251 last_isspace = 0;
2252 tmplog += iret;
2253 } else {
Willy Tarreau372ac5a2018-09-05 15:16:23 +02002254 ret = ltoa_o(logs->accept_date.tv_sec, tmplog, dst + maxsize - tmplog);
William Lallemand5f232402012-04-05 18:02:55 +02002255 if (ret == NULL)
2256 goto out;
2257 tmplog = ret;
2258 last_isspace = 0;
2259 }
2260 break;
2261
William Lallemand1d705562012-03-12 12:46:41 +01002262 case LOG_FMT_MS: // %ms
William Lallemand5f232402012-04-05 18:02:55 +02002263 if (tmp->options & LOG_OPT_HEXA) {
Willy Tarreau372ac5a2018-09-05 15:16:23 +02002264 iret = snprintf(tmplog, dst + maxsize - tmplog, "%02X",(unsigned int)logs->accept_date.tv_usec/1000);
William Lallemand5f232402012-04-05 18:02:55 +02002265 if (iret < 0 || iret > dst + maxsize - tmplog)
2266 goto out;
2267 last_isspace = 0;
2268 tmplog += iret;
2269 } else {
2270 if ((dst + maxsize - tmplog) < 4)
William Lallemandbddd4fd2012-02-27 11:23:10 +01002271 goto out;
Willy Tarreau372ac5a2018-09-05 15:16:23 +02002272 ret = utoa_pad((unsigned int)logs->accept_date.tv_usec/1000,
Willy Tarreau9e60cd82013-01-24 01:18:16 +01002273 tmplog, 4);
2274 if (ret == NULL)
William Lallemand51b5dca2012-03-26 17:52:55 +02002275 goto out;
Willy Tarreau9e60cd82013-01-24 01:18:16 +01002276 tmplog = ret;
William Lallemandbddd4fd2012-02-27 11:23:10 +01002277 last_isspace = 0;
William Lallemand5f232402012-04-05 18:02:55 +02002278 }
2279 break;
William Lallemandbddd4fd2012-02-27 11:23:10 +01002280
William Lallemand1d705562012-03-12 12:46:41 +01002281 case LOG_FMT_FRONTEND: // %f
William Lallemandbddd4fd2012-02-27 11:23:10 +01002282 src = fe->id;
William Lallemand5f232402012-04-05 18:02:55 +02002283 ret = lf_text(tmplog, src, dst + maxsize - tmplog, tmp);
William Lallemand1d705562012-03-12 12:46:41 +01002284 if (ret == NULL)
William Lallemandbddd4fd2012-02-27 11:23:10 +01002285 goto out;
William Lallemand1d705562012-03-12 12:46:41 +01002286 tmplog = ret;
William Lallemand51b5dca2012-03-26 17:52:55 +02002287 last_isspace = 0;
William Lallemandbddd4fd2012-02-27 11:23:10 +01002288 break;
2289
Willy Tarreau773d65f2012-10-12 14:56:11 +02002290 case LOG_FMT_FRONTEND_XPRT: // %ft
2291 src = fe->id;
2292 if (tmp->options & LOG_OPT_QUOTE)
2293 LOGCHAR('"');
2294 iret = strlcpy2(tmplog, src, dst + maxsize - tmplog);
2295 if (iret == 0)
2296 goto out;
2297 tmplog += iret;
Willy Tarreaua261e9b2016-12-22 20:44:00 +01002298 if (sess->listener->bind_conf->xprt == xprt_get(XPRT_SSL))
Willy Tarreau773d65f2012-10-12 14:56:11 +02002299 LOGCHAR('~');
Willy Tarreau773d65f2012-10-12 14:56:11 +02002300 if (tmp->options & LOG_OPT_QUOTE)
2301 LOGCHAR('"');
2302 last_isspace = 0;
2303 break;
Willy Tarreauffc3fcd2012-10-12 20:17:54 +02002304#ifdef USE_OPENSSL
2305 case LOG_FMT_SSL_CIPHER: // %sslc
2306 src = NULL;
Willy Tarreau9ad7bd42015-04-03 19:19:59 +02002307 conn = objt_conn(sess->origin);
Willy Tarreaub363a1f2013-10-01 10:45:07 +02002308 if (conn) {
Emmanuel Hocdet01da5712017-10-13 16:59:49 +02002309 src = ssl_sock_get_cipher_name(conn);
Willy Tarreaub363a1f2013-10-01 10:45:07 +02002310 }
Willy Tarreauffc3fcd2012-10-12 20:17:54 +02002311 ret = lf_text(tmplog, src, dst + maxsize - tmplog, tmp);
2312 if (ret == NULL)
2313 goto out;
2314 tmplog = ret;
2315 last_isspace = 0;
2316 break;
Willy Tarreau773d65f2012-10-12 14:56:11 +02002317
Willy Tarreauffc3fcd2012-10-12 20:17:54 +02002318 case LOG_FMT_SSL_VERSION: // %sslv
2319 src = NULL;
Willy Tarreau9ad7bd42015-04-03 19:19:59 +02002320 conn = objt_conn(sess->origin);
Willy Tarreaub363a1f2013-10-01 10:45:07 +02002321 if (conn) {
Emmanuel Hocdet01da5712017-10-13 16:59:49 +02002322 src = ssl_sock_get_proto_version(conn);
Willy Tarreaub363a1f2013-10-01 10:45:07 +02002323 }
Willy Tarreauffc3fcd2012-10-12 20:17:54 +02002324 ret = lf_text(tmplog, src, dst + maxsize - tmplog, tmp);
2325 if (ret == NULL)
2326 goto out;
2327 tmplog = ret;
2328 last_isspace = 0;
2329 break;
2330#endif
William Lallemand1d705562012-03-12 12:46:41 +01002331 case LOG_FMT_BACKEND: // %b
William Lallemandbddd4fd2012-02-27 11:23:10 +01002332 src = be->id;
William Lallemand5f232402012-04-05 18:02:55 +02002333 ret = lf_text(tmplog, src, dst + maxsize - tmplog, tmp);
William Lallemand1d705562012-03-12 12:46:41 +01002334 if (ret == NULL)
William Lallemandbddd4fd2012-02-27 11:23:10 +01002335 goto out;
William Lallemand1d705562012-03-12 12:46:41 +01002336 tmplog = ret;
William Lallemand51b5dca2012-03-26 17:52:55 +02002337 last_isspace = 0;
William Lallemandbddd4fd2012-02-27 11:23:10 +01002338 break;
2339
William Lallemand1d705562012-03-12 12:46:41 +01002340 case LOG_FMT_SERVER: // %s
Willy Tarreaue1809df2018-09-05 15:30:16 +02002341 switch (obj_type(s ? s->target : NULL)) {
Willy Tarreaud79a3b22012-12-28 09:40:16 +01002342 case OBJ_TYPE_SERVER:
Willy Tarreau1aaf3242018-09-20 11:13:58 +02002343 src = __objt_server(s->target)->id;
Willy Tarreaud79a3b22012-12-28 09:40:16 +01002344 break;
2345 case OBJ_TYPE_APPLET:
Willy Tarreau1aaf3242018-09-20 11:13:58 +02002346 src = __objt_applet(s->target)->name;
Willy Tarreaud79a3b22012-12-28 09:40:16 +01002347 break;
2348 default:
2349 src = "<NOSRV>";
2350 break;
2351 }
William Lallemand5f232402012-04-05 18:02:55 +02002352 ret = lf_text(tmplog, src, dst + maxsize - tmplog, tmp);
William Lallemand1d705562012-03-12 12:46:41 +01002353 if (ret == NULL)
William Lallemandbddd4fd2012-02-27 11:23:10 +01002354 goto out;
William Lallemand1d705562012-03-12 12:46:41 +01002355 tmplog = ret;
William Lallemandbddd4fd2012-02-27 11:23:10 +01002356 last_isspace = 0;
2357 break;
2358
Thierry FOURNIER / OZON.IO4cac3592016-07-28 17:19:45 +02002359 case LOG_FMT_Th: // %Th = handshake time
Willy Tarreau372ac5a2018-09-05 15:16:23 +02002360 ret = ltoa_o(logs->t_handshake, tmplog, dst + maxsize - tmplog);
Thierry FOURNIER / OZON.IO4cac3592016-07-28 17:19:45 +02002361 if (ret == NULL)
2362 goto out;
2363 tmplog = ret;
2364 last_isspace = 0;
2365 break;
2366
2367 case LOG_FMT_Ti: // %Ti = HTTP idle time
Willy Tarreau372ac5a2018-09-05 15:16:23 +02002368 ret = ltoa_o(logs->t_idle, tmplog, dst + maxsize - tmplog);
Thierry FOURNIER / OZON.IO4cac3592016-07-28 17:19:45 +02002369 if (ret == NULL)
2370 goto out;
2371 tmplog = ret;
2372 last_isspace = 0;
2373 break;
2374
2375 case LOG_FMT_TR: // %TR = HTTP request time
Willy Tarreau372ac5a2018-09-05 15:16:23 +02002376 ret = ltoa_o((t_request >= 0) ? t_request - logs->t_idle - logs->t_handshake : -1,
Thierry FOURNIER / OZON.IO4cac3592016-07-28 17:19:45 +02002377 tmplog, dst + maxsize - tmplog);
2378 if (ret == NULL)
2379 goto out;
2380 tmplog = ret;
2381 last_isspace = 0;
2382 break;
2383
2384 case LOG_FMT_TQ: // %Tq = Th + Ti + TR
William Lallemand5f232402012-04-05 18:02:55 +02002385 ret = ltoa_o(t_request, tmplog, dst + maxsize - tmplog);
William Lallemand1d705562012-03-12 12:46:41 +01002386 if (ret == NULL)
William Lallemandbddd4fd2012-02-27 11:23:10 +01002387 goto out;
William Lallemand1d705562012-03-12 12:46:41 +01002388 tmplog = ret;
William Lallemandbddd4fd2012-02-27 11:23:10 +01002389 last_isspace = 0;
2390 break;
2391
William Lallemand1d705562012-03-12 12:46:41 +01002392 case LOG_FMT_TW: // %Tw
Willy Tarreau372ac5a2018-09-05 15:16:23 +02002393 ret = ltoa_o((logs->t_queue >= 0) ? logs->t_queue - t_request : -1,
William Lallemand5f232402012-04-05 18:02:55 +02002394 tmplog, dst + maxsize - tmplog);
William Lallemand1d705562012-03-12 12:46:41 +01002395 if (ret == NULL)
William Lallemandbddd4fd2012-02-27 11:23:10 +01002396 goto out;
William Lallemand1d705562012-03-12 12:46:41 +01002397 tmplog = ret;
William Lallemandbddd4fd2012-02-27 11:23:10 +01002398 last_isspace = 0;
2399 break;
2400
William Lallemand1d705562012-03-12 12:46:41 +01002401 case LOG_FMT_TC: // %Tc
Willy Tarreau372ac5a2018-09-05 15:16:23 +02002402 ret = ltoa_o((logs->t_connect >= 0) ? logs->t_connect - logs->t_queue : -1,
William Lallemand5f232402012-04-05 18:02:55 +02002403 tmplog, dst + maxsize - tmplog);
William Lallemand1d705562012-03-12 12:46:41 +01002404 if (ret == NULL)
William Lallemandbddd4fd2012-02-27 11:23:10 +01002405 goto out;
William Lallemand1d705562012-03-12 12:46:41 +01002406 tmplog = ret;
William Lallemandbddd4fd2012-02-27 11:23:10 +01002407 last_isspace = 0;
2408 break;
2409
Thierry FOURNIER / OZON.IO4cac3592016-07-28 17:19:45 +02002410 case LOG_FMT_Tr: // %Tr
Willy Tarreau372ac5a2018-09-05 15:16:23 +02002411 ret = ltoa_o((logs->t_data >= 0) ? logs->t_data - logs->t_connect : -1,
William Lallemand5f232402012-04-05 18:02:55 +02002412 tmplog, dst + maxsize - tmplog);
William Lallemand1d705562012-03-12 12:46:41 +01002413 if (ret == NULL)
William Lallemandbddd4fd2012-02-27 11:23:10 +01002414 goto out;
William Lallemand1d705562012-03-12 12:46:41 +01002415 tmplog = ret;
William Lallemandbddd4fd2012-02-27 11:23:10 +01002416 last_isspace = 0;
2417 break;
2418
Willy Tarreau27b639d2016-05-17 17:55:27 +02002419 case LOG_FMT_TD: // %Td
Willy Tarreaua21c0e62018-09-05 15:07:15 +02002420 if (be->mode == PR_MODE_HTTP)
Willy Tarreau372ac5a2018-09-05 15:16:23 +02002421 ret = ltoa_o((logs->t_data >= 0) ? logs->t_close - logs->t_data : -1,
Willy Tarreau27b639d2016-05-17 17:55:27 +02002422 tmplog, dst + maxsize - tmplog);
2423 else
Willy Tarreau372ac5a2018-09-05 15:16:23 +02002424 ret = ltoa_o((logs->t_connect >= 0) ? logs->t_close - logs->t_connect : -1,
Willy Tarreau27b639d2016-05-17 17:55:27 +02002425 tmplog, dst + maxsize - tmplog);
2426 if (ret == NULL)
2427 goto out;
2428 tmplog = ret;
2429 last_isspace = 0;
2430 break;
2431
Thierry FOURNIER / OZON.IO4cac3592016-07-28 17:19:45 +02002432 case LOG_FMT_Ta: // %Ta = active time = Tt - Th - Ti
2433 if (!(fe->to_log & LW_BYTES))
2434 LOGCHAR('+');
Willy Tarreau372ac5a2018-09-05 15:16:23 +02002435 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 +02002436 tmplog, dst + maxsize - tmplog);
2437 if (ret == NULL)
2438 goto out;
2439 tmplog = ret;
2440 last_isspace = 0;
2441 break;
2442
2443 case LOG_FMT_TT: // %Tt = total time
Willy Tarreaud79a3b22012-12-28 09:40:16 +01002444 if (!(fe->to_log & LW_BYTES))
William Lallemand1d705562012-03-12 12:46:41 +01002445 LOGCHAR('+');
Willy Tarreau372ac5a2018-09-05 15:16:23 +02002446 ret = ltoa_o(logs->t_close, tmplog, dst + maxsize - tmplog);
William Lallemand1d705562012-03-12 12:46:41 +01002447 if (ret == NULL)
William Lallemandbddd4fd2012-02-27 11:23:10 +01002448 goto out;
William Lallemand1d705562012-03-12 12:46:41 +01002449 tmplog = ret;
William Lallemandbddd4fd2012-02-27 11:23:10 +01002450 last_isspace = 0;
2451 break;
2452
Willy Tarreau2beef582012-12-20 17:22:52 +01002453 case LOG_FMT_STATUS: // %ST
Willy Tarreau57bc8912016-04-25 17:09:40 +02002454 ret = ltoa_o(txn ? txn->status : 0, tmplog, dst + maxsize - tmplog);
William Lallemand1d705562012-03-12 12:46:41 +01002455 if (ret == NULL)
William Lallemandbddd4fd2012-02-27 11:23:10 +01002456 goto out;
William Lallemand1d705562012-03-12 12:46:41 +01002457 tmplog = ret;
William Lallemandbddd4fd2012-02-27 11:23:10 +01002458 last_isspace = 0;
2459 break;
2460
William Lallemand1d705562012-03-12 12:46:41 +01002461 case LOG_FMT_BYTES: // %B
Willy Tarreaud79a3b22012-12-28 09:40:16 +01002462 if (!(fe->to_log & LW_BYTES))
William Lallemand1d705562012-03-12 12:46:41 +01002463 LOGCHAR('+');
Willy Tarreau372ac5a2018-09-05 15:16:23 +02002464 ret = lltoa(logs->bytes_out, tmplog, dst + maxsize - tmplog);
William Lallemand1d705562012-03-12 12:46:41 +01002465 if (ret == NULL)
William Lallemandbddd4fd2012-02-27 11:23:10 +01002466 goto out;
William Lallemand1d705562012-03-12 12:46:41 +01002467 tmplog = ret;
William Lallemandbddd4fd2012-02-27 11:23:10 +01002468 last_isspace = 0;
2469 break;
2470
Willy Tarreauc5259fd2012-12-20 15:38:04 +01002471 case LOG_FMT_BYTES_UP: // %U
Willy Tarreau372ac5a2018-09-05 15:16:23 +02002472 ret = lltoa(logs->bytes_in, tmplog, dst + maxsize - tmplog);
Willy Tarreauc5259fd2012-12-20 15:38:04 +01002473 if (ret == NULL)
2474 goto out;
2475 tmplog = ret;
2476 last_isspace = 0;
2477 break;
2478
Willy Tarreau2beef582012-12-20 17:22:52 +01002479 case LOG_FMT_CCLIENT: // %CC
Willy Tarreau57bc8912016-04-25 17:09:40 +02002480 src = txn ? txn->cli_cookie : NULL;
William Lallemand5f232402012-04-05 18:02:55 +02002481 ret = lf_text(tmplog, src, dst + maxsize - tmplog, tmp);
William Lallemand1d705562012-03-12 12:46:41 +01002482 if (ret == NULL)
William Lallemand51b5dca2012-03-26 17:52:55 +02002483 goto out;
William Lallemand1d705562012-03-12 12:46:41 +01002484 tmplog = ret;
William Lallemandbddd4fd2012-02-27 11:23:10 +01002485 last_isspace = 0;
2486 break;
2487
Willy Tarreau2beef582012-12-20 17:22:52 +01002488 case LOG_FMT_CSERVER: // %CS
Willy Tarreau57bc8912016-04-25 17:09:40 +02002489 src = txn ? txn->srv_cookie : NULL;
William Lallemand5f232402012-04-05 18:02:55 +02002490 ret = lf_text(tmplog, src, dst + maxsize - tmplog, tmp);
William Lallemand1d705562012-03-12 12:46:41 +01002491 if (ret == NULL)
William Lallemand51b5dca2012-03-26 17:52:55 +02002492 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_TERMSTATE: // %ts
Willy Tarreaub8bc5252018-09-05 15:51:28 +02002498 LOGCHAR(sess_term_cond[(s_flags & SF_ERR_MASK) >> SF_ERR_SHIFT]);
2499 LOGCHAR(sess_fin_state[(s_flags & SF_FINST_MASK) >> SF_FINST_SHIFT]);
Willy Tarreau6580c062012-03-12 15:09:42 +01002500 *tmplog = '\0';
2501 last_isspace = 0;
2502 break;
William Lallemandbddd4fd2012-02-27 11:23:10 +01002503
William Lallemand1d705562012-03-12 12:46:41 +01002504 case LOG_FMT_TERMSTATE_CK: // %tsc, same as TS with cookie state (for mode HTTP)
Willy Tarreaub8bc5252018-09-05 15:51:28 +02002505 LOGCHAR(sess_term_cond[(s_flags & SF_ERR_MASK) >> SF_ERR_SHIFT]);
2506 LOGCHAR(sess_fin_state[(s_flags & SF_FINST_MASK) >> SF_FINST_SHIFT]);
Willy Tarreau57bc8912016-04-25 17:09:40 +02002507 LOGCHAR((txn && (be->ck_opts & PR_CK_ANY)) ? sess_cookie[(txn->flags & TX_CK_MASK) >> TX_CK_SHIFT] : '-');
2508 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 +01002509 last_isspace = 0;
2510 break;
2511
William Lallemand1d705562012-03-12 12:46:41 +01002512 case LOG_FMT_ACTCONN: // %ac
William Lallemand5f232402012-04-05 18:02:55 +02002513 ret = ltoa_o(actconn, tmplog, dst + maxsize - tmplog);
William Lallemand1d705562012-03-12 12:46:41 +01002514 if (ret == NULL)
William Lallemandbddd4fd2012-02-27 11:23:10 +01002515 goto out;
William Lallemand1d705562012-03-12 12:46:41 +01002516 tmplog = ret;
William Lallemandbddd4fd2012-02-27 11:23:10 +01002517 last_isspace = 0;
2518 break;
2519
William Lallemand1d705562012-03-12 12:46:41 +01002520 case LOG_FMT_FECONN: // %fc
William Lallemand5f232402012-04-05 18:02:55 +02002521 ret = ltoa_o(fe->feconn, tmplog, dst + maxsize - tmplog);
William Lallemand1d705562012-03-12 12:46:41 +01002522 if (ret == NULL)
William Lallemandbddd4fd2012-02-27 11:23:10 +01002523 goto out;
William Lallemand1d705562012-03-12 12:46:41 +01002524 tmplog = ret;
William Lallemandbddd4fd2012-02-27 11:23:10 +01002525 last_isspace = 0;
2526 break;
2527
William Lallemand1d705562012-03-12 12:46:41 +01002528 case LOG_FMT_BECONN: // %bc
William Lallemand5f232402012-04-05 18:02:55 +02002529 ret = ltoa_o(be->beconn, tmplog, dst + maxsize - tmplog);
William Lallemand1d705562012-03-12 12:46:41 +01002530 if (ret == NULL)
William Lallemandbddd4fd2012-02-27 11:23:10 +01002531 goto out;
William Lallemand1d705562012-03-12 12:46:41 +01002532 tmplog = ret;
William Lallemandbddd4fd2012-02-27 11:23:10 +01002533 last_isspace = 0;
2534 break;
2535
William Lallemand1d705562012-03-12 12:46:41 +01002536 case LOG_FMT_SRVCONN: // %sc
Willy Tarreaue1809df2018-09-05 15:30:16 +02002537 ret = ultoa_o(objt_server(s ? s->target : NULL) ?
Willy Tarreau3fdb3662012-11-12 00:42:33 +01002538 objt_server(s->target)->cur_sess :
William Lallemand5f232402012-04-05 18:02:55 +02002539 0, tmplog, dst + maxsize - tmplog);
William Lallemand1d705562012-03-12 12:46:41 +01002540 if (ret == NULL)
William Lallemandbddd4fd2012-02-27 11:23:10 +01002541 goto out;
William Lallemand1d705562012-03-12 12:46:41 +01002542 tmplog = ret;
William Lallemandbddd4fd2012-02-27 11:23:10 +01002543 last_isspace = 0;
2544 break;
2545
William Lallemand1d705562012-03-12 12:46:41 +01002546 case LOG_FMT_RETRIES: // %rq
Willy Tarreaub8bc5252018-09-05 15:51:28 +02002547 if (s_flags & SF_REDISP)
William Lallemand1d705562012-03-12 12:46:41 +01002548 LOGCHAR('+');
Willy Tarreauabd71a52018-09-04 19:21:44 +02002549 ret = ltoa_o((s && s->si[1].conn_retries > 0) ?
Willy Tarreau350f4872014-11-28 14:42:25 +01002550 (be->conn_retries - s->si[1].conn_retries) :
William Lallemand5f232402012-04-05 18:02:55 +02002551 be->conn_retries, tmplog, dst + maxsize - tmplog);
William Lallemand1d705562012-03-12 12:46:41 +01002552 if (ret == NULL)
William Lallemand51b5dca2012-03-26 17:52:55 +02002553 goto out;
William Lallemand1d705562012-03-12 12:46:41 +01002554 tmplog = ret;
William Lallemandbddd4fd2012-02-27 11:23:10 +01002555 last_isspace = 0;
2556 break;
2557
William Lallemand1d705562012-03-12 12:46:41 +01002558 case LOG_FMT_SRVQUEUE: // %sq
Willy Tarreau372ac5a2018-09-05 15:16:23 +02002559 ret = ltoa_o(logs->srv_queue_pos, tmplog, dst + maxsize - tmplog);
William Lallemand1d705562012-03-12 12:46:41 +01002560 if (ret == NULL)
William Lallemandbddd4fd2012-02-27 11:23:10 +01002561 goto out;
William Lallemand1d705562012-03-12 12:46:41 +01002562 tmplog = ret;
William Lallemandbddd4fd2012-02-27 11:23:10 +01002563 last_isspace = 0;
2564 break;
2565
William Lallemand1d705562012-03-12 12:46:41 +01002566 case LOG_FMT_BCKQUEUE: // %bq
Willy Tarreau372ac5a2018-09-05 15:16:23 +02002567 ret = ltoa_o(logs->prx_queue_pos, tmplog, dst + maxsize - tmplog);
William Lallemand1d705562012-03-12 12:46:41 +01002568 if (ret == NULL)
William Lallemandbddd4fd2012-02-27 11:23:10 +01002569 goto out;
William Lallemand1d705562012-03-12 12:46:41 +01002570 tmplog = ret;
William Lallemandbddd4fd2012-02-27 11:23:10 +01002571 last_isspace = 0;
2572 break;
2573
William Lallemand1d705562012-03-12 12:46:41 +01002574 case LOG_FMT_HDRREQUEST: // %hr
William Lallemandbddd4fd2012-02-27 11:23:10 +01002575 /* request header */
Willy Tarreaud4f91662018-09-05 15:28:07 +02002576 if (fe->nb_req_cap && s && s->req_cap) {
William Lallemandbddd4fd2012-02-27 11:23:10 +01002577 if (tmp->options & LOG_OPT_QUOTE)
2578 LOGCHAR('"');
2579 LOGCHAR('{');
2580 for (hdr = 0; hdr < fe->nb_req_cap; hdr++) {
2581 if (hdr)
2582 LOGCHAR('|');
Willy Tarreaucb7dd012015-04-03 22:16:32 +02002583 if (s->req_cap[hdr] != NULL) {
Dragan Dosen835b9212016-02-12 13:23:03 +01002584 ret = lf_encode_string(tmplog, dst + maxsize,
2585 '#', hdr_encode_map, s->req_cap[hdr], tmp);
William Lallemand1d705562012-03-12 12:46:41 +01002586 if (ret == NULL || *ret != '\0')
William Lallemand51b5dca2012-03-26 17:52:55 +02002587 goto out;
William Lallemand1d705562012-03-12 12:46:41 +01002588 tmplog = ret;
William Lallemand51b5dca2012-03-26 17:52:55 +02002589 }
William Lallemandbddd4fd2012-02-27 11:23:10 +01002590 }
2591 LOGCHAR('}');
William Lallemand51b5dca2012-03-26 17:52:55 +02002592 if (tmp->options & LOG_OPT_QUOTE)
2593 LOGCHAR('"');
William Lallemandbddd4fd2012-02-27 11:23:10 +01002594 last_isspace = 0;
2595 }
William Lallemandbddd4fd2012-02-27 11:23:10 +01002596 break;
2597
William Lallemand1d705562012-03-12 12:46:41 +01002598 case LOG_FMT_HDRREQUESTLIST: // %hrl
William Lallemandbddd4fd2012-02-27 11:23:10 +01002599 /* request header list */
Willy Tarreaud4f91662018-09-05 15:28:07 +02002600 if (fe->nb_req_cap && s && s->req_cap) {
William Lallemandbddd4fd2012-02-27 11:23:10 +01002601 for (hdr = 0; hdr < fe->nb_req_cap; hdr++) {
2602 if (hdr > 0)
2603 LOGCHAR(' ');
2604 if (tmp->options & LOG_OPT_QUOTE)
2605 LOGCHAR('"');
Willy Tarreaucb7dd012015-04-03 22:16:32 +02002606 if (s->req_cap[hdr] != NULL) {
Dragan Dosen835b9212016-02-12 13:23:03 +01002607 ret = lf_encode_string(tmplog, dst + maxsize,
2608 '#', hdr_encode_map, s->req_cap[hdr], tmp);
William Lallemand1d705562012-03-12 12:46:41 +01002609 if (ret == NULL || *ret != '\0')
William Lallemand51b5dca2012-03-26 17:52:55 +02002610 goto out;
William Lallemand1d705562012-03-12 12:46:41 +01002611 tmplog = ret;
William Lallemandbddd4fd2012-02-27 11:23:10 +01002612 } else if (!(tmp->options & LOG_OPT_QUOTE))
2613 LOGCHAR('-');
2614 if (tmp->options & LOG_OPT_QUOTE)
2615 LOGCHAR('"');
William Lallemandbddd4fd2012-02-27 11:23:10 +01002616 last_isspace = 0;
2617 }
2618 }
2619 break;
Willy Tarreaubaaee002006-06-26 02:48:02 +02002620
William Lallemand1d705562012-03-12 12:46:41 +01002621
2622 case LOG_FMT_HDRRESPONS: // %hs
William Lallemandbddd4fd2012-02-27 11:23:10 +01002623 /* response header */
Willy Tarreaud4f91662018-09-05 15:28:07 +02002624 if (fe->nb_rsp_cap && s && s->res_cap) {
William Lallemandbddd4fd2012-02-27 11:23:10 +01002625 if (tmp->options & LOG_OPT_QUOTE)
2626 LOGCHAR('"');
2627 LOGCHAR('{');
2628 for (hdr = 0; hdr < fe->nb_rsp_cap; hdr++) {
2629 if (hdr)
2630 LOGCHAR('|');
Willy Tarreaucb7dd012015-04-03 22:16:32 +02002631 if (s->res_cap[hdr] != NULL) {
Dragan Dosen835b9212016-02-12 13:23:03 +01002632 ret = lf_encode_string(tmplog, dst + maxsize,
2633 '#', hdr_encode_map, s->res_cap[hdr], tmp);
William Lallemand1d705562012-03-12 12:46:41 +01002634 if (ret == NULL || *ret != '\0')
William Lallemand51b5dca2012-03-26 17:52:55 +02002635 goto out;
William Lallemand1d705562012-03-12 12:46:41 +01002636 tmplog = ret;
William Lallemand51b5dca2012-03-26 17:52:55 +02002637 }
William Lallemandbddd4fd2012-02-27 11:23:10 +01002638 }
2639 LOGCHAR('}');
2640 last_isspace = 0;
2641 if (tmp->options & LOG_OPT_QUOTE)
2642 LOGCHAR('"');
2643 }
William Lallemandbddd4fd2012-02-27 11:23:10 +01002644 break;
2645
William Lallemand1d705562012-03-12 12:46:41 +01002646 case LOG_FMT_HDRRESPONSLIST: // %hsl
William Lallemandbddd4fd2012-02-27 11:23:10 +01002647 /* response header list */
Willy Tarreaud4f91662018-09-05 15:28:07 +02002648 if (fe->nb_rsp_cap && s && s->res_cap) {
William Lallemandbddd4fd2012-02-27 11:23:10 +01002649 for (hdr = 0; hdr < fe->nb_rsp_cap; hdr++) {
2650 if (hdr > 0)
2651 LOGCHAR(' ');
2652 if (tmp->options & LOG_OPT_QUOTE)
2653 LOGCHAR('"');
Willy Tarreaucb7dd012015-04-03 22:16:32 +02002654 if (s->res_cap[hdr] != NULL) {
Dragan Dosen835b9212016-02-12 13:23:03 +01002655 ret = lf_encode_string(tmplog, dst + maxsize,
2656 '#', hdr_encode_map, s->res_cap[hdr], tmp);
William Lallemand1d705562012-03-12 12:46:41 +01002657 if (ret == NULL || *ret != '\0')
William Lallemand51b5dca2012-03-26 17:52:55 +02002658 goto out;
William Lallemand1d705562012-03-12 12:46:41 +01002659 tmplog = ret;
William Lallemandbddd4fd2012-02-27 11:23:10 +01002660 } else if (!(tmp->options & LOG_OPT_QUOTE))
2661 LOGCHAR('-');
2662 if (tmp->options & LOG_OPT_QUOTE)
2663 LOGCHAR('"');
William Lallemandbddd4fd2012-02-27 11:23:10 +01002664 last_isspace = 0;
2665 }
2666 }
2667 break;
2668
William Lallemand1d705562012-03-12 12:46:41 +01002669 case LOG_FMT_REQ: // %r
William Lallemandbddd4fd2012-02-27 11:23:10 +01002670 /* Request */
2671 if (tmp->options & LOG_OPT_QUOTE)
2672 LOGCHAR('"');
Willy Tarreau57bc8912016-04-25 17:09:40 +02002673 uri = txn && txn->uri ? txn->uri : "<BADREQ>";
Dragan Dosen835b9212016-02-12 13:23:03 +01002674 ret = lf_encode_string(tmplog, dst + maxsize,
2675 '#', url_encode_map, uri, tmp);
William Lallemand1d705562012-03-12 12:46:41 +01002676 if (ret == NULL || *ret != '\0')
William Lallemand51b5dca2012-03-26 17:52:55 +02002677 goto out;
William Lallemand1d705562012-03-12 12:46:41 +01002678 tmplog = ret;
William Lallemandbddd4fd2012-02-27 11:23:10 +01002679 if (tmp->options & LOG_OPT_QUOTE)
2680 LOGCHAR('"');
William Lallemandbddd4fd2012-02-27 11:23:10 +01002681 last_isspace = 0;
2682 break;
William Lallemand5f232402012-04-05 18:02:55 +02002683
Andrew Hayworth0ebc55f2015-04-27 21:37:03 +00002684 case LOG_FMT_HTTP_PATH: // %HP
Willy Tarreau57bc8912016-04-25 17:09:40 +02002685 uri = txn && txn->uri ? txn->uri : "<BADREQ>";
Andrew Hayworth0ebc55f2015-04-27 21:37:03 +00002686
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 end = uri + strlen(uri);
2691 // look for the first whitespace character
2692 while (uri < end && !HTTP_IS_SPHT(*uri))
2693 uri++;
2694
2695 // keep advancing past multiple spaces
2696 while (uri < end && HTTP_IS_SPHT(*uri)) {
2697 uri++; nspaces++;
2698 }
2699
2700 // look for first space or question mark after url
2701 spc = uri;
2702 while (spc < end && *spc != '?' && !HTTP_IS_SPHT(*spc))
2703 spc++;
2704
Nenad Merdanovic54e439f2016-04-26 01:39:02 +02002705 if (!txn || !txn->uri || nspaces == 0) {
Willy Tarreau843b7cb2018-07-13 10:54:26 +02002706 chunk.area = "<BADREQ>";
2707 chunk.data = strlen("<BADREQ>");
Andrew Hayworth0ebc55f2015-04-27 21:37:03 +00002708 } else {
Willy Tarreau843b7cb2018-07-13 10:54:26 +02002709 chunk.area = uri;
2710 chunk.data = spc - uri;
Andrew Hayworth0ebc55f2015-04-27 21:37:03 +00002711 }
2712
Dragan Dosen835b9212016-02-12 13:23:03 +01002713 ret = lf_encode_chunk(tmplog, dst + maxsize, '#', url_encode_map, &chunk, tmp);
Andrew Hayworth0ebc55f2015-04-27 21:37:03 +00002714 if (ret == NULL || *ret != '\0')
2715 goto out;
2716
2717 tmplog = ret;
Willy Tarreaub7636d12015-06-17 19:58:02 +02002718 if (tmp->options & LOG_OPT_QUOTE)
Andrew Hayworth0ebc55f2015-04-27 21:37:03 +00002719 LOGCHAR('"');
2720
2721 last_isspace = 0;
2722 break;
2723
Andrew Hayworthe63ac872015-07-31 16:14:16 +00002724 case LOG_FMT_HTTP_QUERY: // %HQ
2725 if (tmp->options & LOG_OPT_QUOTE)
2726 LOGCHAR('"');
2727
Willy Tarreau57bc8912016-04-25 17:09:40 +02002728 if (!txn || !txn->uri) {
Willy Tarreau843b7cb2018-07-13 10:54:26 +02002729 chunk.area = "<BADREQ>";
2730 chunk.data = strlen("<BADREQ>");
Andrew Hayworthe63ac872015-07-31 16:14:16 +00002731 } else {
2732 uri = txn->uri;
2733 end = uri + strlen(uri);
2734 // look for the first question mark
2735 while (uri < end && *uri != '?')
2736 uri++;
2737
2738 qmark = uri;
2739 // look for first space or question mark after url
2740 while (uri < end && !HTTP_IS_SPHT(*uri))
2741 uri++;
2742
Willy Tarreau843b7cb2018-07-13 10:54:26 +02002743 chunk.area = qmark;
2744 chunk.data = uri - qmark;
Andrew Hayworthe63ac872015-07-31 16:14:16 +00002745 }
2746
Dragan Dosen835b9212016-02-12 13:23:03 +01002747 ret = lf_encode_chunk(tmplog, dst + maxsize, '#', url_encode_map, &chunk, tmp);
Andrew Hayworthe63ac872015-07-31 16:14:16 +00002748 if (ret == NULL || *ret != '\0')
2749 goto out;
2750
2751 tmplog = ret;
2752 if (tmp->options & LOG_OPT_QUOTE)
2753 LOGCHAR('"');
2754
2755 last_isspace = 0;
2756 break;
2757
Andrew Hayworth0ebc55f2015-04-27 21:37:03 +00002758 case LOG_FMT_HTTP_URI: // %HU
Willy Tarreau57bc8912016-04-25 17:09:40 +02002759 uri = txn && txn->uri ? txn->uri : "<BADREQ>";
Andrew Hayworth0ebc55f2015-04-27 21:37:03 +00002760
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 end = uri + strlen(uri);
2765 // look for the first whitespace character
2766 while (uri < end && !HTTP_IS_SPHT(*uri))
2767 uri++;
2768
2769 // keep advancing past multiple spaces
2770 while (uri < end && HTTP_IS_SPHT(*uri)) {
2771 uri++; nspaces++;
2772 }
2773
2774 // look for first space after url
2775 spc = uri;
2776 while (spc < end && !HTTP_IS_SPHT(*spc))
2777 spc++;
2778
Willy Tarreau57bc8912016-04-25 17:09:40 +02002779 if (!txn || !txn->uri || nspaces == 0) {
Willy Tarreau843b7cb2018-07-13 10:54:26 +02002780 chunk.area = "<BADREQ>";
2781 chunk.data = strlen("<BADREQ>");
Andrew Hayworth0ebc55f2015-04-27 21:37:03 +00002782 } else {
Willy Tarreau843b7cb2018-07-13 10:54:26 +02002783 chunk.area = uri;
2784 chunk.data = spc - uri;
Andrew Hayworth0ebc55f2015-04-27 21:37:03 +00002785 }
2786
Dragan Dosen835b9212016-02-12 13:23:03 +01002787 ret = lf_encode_chunk(tmplog, dst + maxsize, '#', url_encode_map, &chunk, tmp);
Andrew Hayworth0ebc55f2015-04-27 21:37:03 +00002788 if (ret == NULL || *ret != '\0')
2789 goto out;
2790
2791 tmplog = ret;
Willy Tarreaub7636d12015-06-17 19:58:02 +02002792 if (tmp->options & LOG_OPT_QUOTE)
Andrew Hayworth0ebc55f2015-04-27 21:37:03 +00002793 LOGCHAR('"');
2794
2795 last_isspace = 0;
2796 break;
2797
2798 case LOG_FMT_HTTP_METHOD: // %HM
Willy Tarreau57bc8912016-04-25 17:09:40 +02002799 uri = txn && txn->uri ? txn->uri : "<BADREQ>";
Willy Tarreaub7636d12015-06-17 19:58:02 +02002800 if (tmp->options & LOG_OPT_QUOTE)
Andrew Hayworth0ebc55f2015-04-27 21:37:03 +00002801 LOGCHAR('"');
2802
2803 end = uri + strlen(uri);
2804 // look for the first whitespace character
2805 spc = uri;
2806 while (spc < end && !HTTP_IS_SPHT(*spc))
2807 spc++;
2808
2809 if (spc == end) { // odd case, we have txn->uri, but we only got a verb
Willy Tarreau843b7cb2018-07-13 10:54:26 +02002810 chunk.area = "<BADREQ>";
2811 chunk.data = strlen("<BADREQ>");
Andrew Hayworth0ebc55f2015-04-27 21:37:03 +00002812 } else {
Willy Tarreau843b7cb2018-07-13 10:54:26 +02002813 chunk.area = uri;
2814 chunk.data = spc - uri;
Andrew Hayworth0ebc55f2015-04-27 21:37:03 +00002815 }
2816
Dragan Dosen835b9212016-02-12 13:23:03 +01002817 ret = lf_encode_chunk(tmplog, dst + maxsize, '#', url_encode_map, &chunk, tmp);
Andrew Hayworth0ebc55f2015-04-27 21:37:03 +00002818 if (ret == NULL || *ret != '\0')
2819 goto out;
2820
2821 tmplog = ret;
Willy Tarreaub7636d12015-06-17 19:58:02 +02002822 if (tmp->options & LOG_OPT_QUOTE)
Andrew Hayworth0ebc55f2015-04-27 21:37:03 +00002823 LOGCHAR('"');
2824
2825 last_isspace = 0;
2826 break;
2827
2828 case LOG_FMT_HTTP_VERSION: // %HV
Willy Tarreau57bc8912016-04-25 17:09:40 +02002829 uri = txn && txn->uri ? txn->uri : "<BADREQ>";
Willy Tarreaub7636d12015-06-17 19:58:02 +02002830 if (tmp->options & LOG_OPT_QUOTE)
Andrew Hayworth0ebc55f2015-04-27 21:37:03 +00002831 LOGCHAR('"');
2832
2833 end = uri + strlen(uri);
2834 // look for the first whitespace character
2835 while (uri < end && !HTTP_IS_SPHT(*uri))
2836 uri++;
2837
2838 // keep advancing past multiple spaces
2839 while (uri < end && HTTP_IS_SPHT(*uri)) {
2840 uri++; nspaces++;
2841 }
2842
2843 // look for the next whitespace character
2844 while (uri < end && !HTTP_IS_SPHT(*uri))
2845 uri++;
2846
2847 // keep advancing past multiple spaces
2848 while (uri < end && HTTP_IS_SPHT(*uri))
2849 uri++;
2850
Willy Tarreau57bc8912016-04-25 17:09:40 +02002851 if (!txn || !txn->uri || nspaces == 0) {
Willy Tarreau843b7cb2018-07-13 10:54:26 +02002852 chunk.area = "<BADREQ>";
2853 chunk.data = strlen("<BADREQ>");
Andrew Hayworth0ebc55f2015-04-27 21:37:03 +00002854 } else if (uri == end) {
Willy Tarreau843b7cb2018-07-13 10:54:26 +02002855 chunk.area = "HTTP/0.9";
2856 chunk.data = strlen("HTTP/0.9");
Andrew Hayworth0ebc55f2015-04-27 21:37:03 +00002857 } else {
Willy Tarreau843b7cb2018-07-13 10:54:26 +02002858 chunk.area = uri;
2859 chunk.data = end - uri;
Andrew Hayworth0ebc55f2015-04-27 21:37:03 +00002860 }
2861
Dragan Dosen835b9212016-02-12 13:23:03 +01002862 ret = lf_encode_chunk(tmplog, dst + maxsize, '#', url_encode_map, &chunk, tmp);
Andrew Hayworth0ebc55f2015-04-27 21:37:03 +00002863 if (ret == NULL || *ret != '\0')
2864 goto out;
2865
2866 tmplog = ret;
Willy Tarreaub7636d12015-06-17 19:58:02 +02002867 if (tmp->options & LOG_OPT_QUOTE)
Andrew Hayworth0ebc55f2015-04-27 21:37:03 +00002868 LOGCHAR('"');
2869
2870 last_isspace = 0;
2871 break;
2872
William Lallemand5f232402012-04-05 18:02:55 +02002873 case LOG_FMT_COUNTER: // %rt
2874 if (tmp->options & LOG_OPT_HEXA) {
Willy Tarreau5cacab62018-09-05 15:52:59 +02002875 iret = snprintf(tmplog, dst + maxsize - tmplog, "%04X", uniq_id);
William Lallemand5f232402012-04-05 18:02:55 +02002876 if (iret < 0 || iret > dst + maxsize - tmplog)
2877 goto out;
2878 last_isspace = 0;
2879 tmplog += iret;
2880 } else {
Willy Tarreau5cacab62018-09-05 15:52:59 +02002881 ret = ltoa_o(uniq_id, tmplog, dst + maxsize - tmplog);
William Lallemand5f232402012-04-05 18:02:55 +02002882 if (ret == NULL)
2883 goto out;
2884 tmplog = ret;
2885 last_isspace = 0;
2886 }
2887 break;
2888
Willy Tarreau7346acb2014-08-28 15:03:15 +02002889 case LOG_FMT_LOGCNT: // %lc
2890 if (tmp->options & LOG_OPT_HEXA) {
Willy Tarreaue36cbcb2015-04-03 15:40:56 +02002891 iret = snprintf(tmplog, dst + maxsize - tmplog, "%04X", fe->log_count);
Willy Tarreau7346acb2014-08-28 15:03:15 +02002892 if (iret < 0 || iret > dst + maxsize - tmplog)
2893 goto out;
2894 last_isspace = 0;
2895 tmplog += iret;
2896 } else {
Willy Tarreaue36cbcb2015-04-03 15:40:56 +02002897 ret = ultoa_o(fe->log_count, tmplog, dst + maxsize - tmplog);
Willy Tarreau7346acb2014-08-28 15:03:15 +02002898 if (ret == NULL)
2899 goto out;
2900 tmplog = ret;
2901 last_isspace = 0;
2902 }
2903 break;
2904
William Lallemand5f232402012-04-05 18:02:55 +02002905 case LOG_FMT_HOSTNAME: // %H
2906 src = hostname;
2907 ret = lf_text(tmplog, src, dst + maxsize - tmplog, tmp);
2908 if (ret == NULL)
2909 goto out;
2910 tmplog = ret;
2911 last_isspace = 0;
2912 break;
2913
2914 case LOG_FMT_PID: // %pid
2915 if (tmp->options & LOG_OPT_HEXA) {
2916 iret = snprintf(tmplog, dst + maxsize - tmplog, "%04X", pid);
2917 if (iret < 0 || iret > dst + maxsize - tmplog)
2918 goto out;
2919 last_isspace = 0;
2920 tmplog += iret;
2921 } else {
2922 ret = ltoa_o(pid, tmplog, dst + maxsize - tmplog);
2923 if (ret == NULL)
2924 goto out;
2925 tmplog = ret;
2926 last_isspace = 0;
2927 }
2928 break;
William Lallemanda73203e2012-03-12 12:48:57 +01002929
2930 case LOG_FMT_UNIQUEID: // %ID
William Lallemand5b7ea3a2013-08-28 15:44:19 +02002931 ret = NULL;
Tim Duesterhusa17e6622020-03-05 20:19:02 +01002932 if (s)
2933 ret = lf_text_len(tmplog, s->unique_id.ptr, s->unique_id.len, maxsize - (tmplog - dst), tmp);
2934 else
2935 ret = lf_text_len(tmplog, NULL, 0, maxsize - (tmplog - dst), tmp);
William Lallemanda73203e2012-03-12 12:48:57 +01002936 if (ret == NULL)
2937 goto out;
2938 tmplog = ret;
2939 last_isspace = 0;
2940 break;
2941
William Lallemandbddd4fd2012-02-27 11:23:10 +01002942 }
2943 }
2944
2945out:
William Lallemand1d705562012-03-12 12:46:41 +01002946 /* *tmplog is a unused character */
2947 *tmplog = '\0';
Willy Tarreaudf974472012-12-28 02:44:01 +01002948 return tmplog - dst;
William Lallemandbddd4fd2012-02-27 11:23:10 +01002949
Willy Tarreaubaaee002006-06-26 02:48:02 +02002950}
2951
William Lallemand1d705562012-03-12 12:46:41 +01002952/*
Willy Tarreau87b09662015-04-03 00:22:06 +02002953 * send a log for the stream when we have enough info about it.
William Lallemand1d705562012-03-12 12:46:41 +01002954 * Will not log if the frontend has no log defined.
2955 */
Willy Tarreau87b09662015-04-03 00:22:06 +02002956void strm_log(struct stream *s)
William Lallemand1d705562012-03-12 12:46:41 +01002957{
Willy Tarreaue36cbcb2015-04-03 15:40:56 +02002958 struct session *sess = s->sess;
William Lallemand1d705562012-03-12 12:46:41 +01002959 int size, err, level;
Dragan Dosen0b85ece2015-09-25 19:17:44 +02002960 int sd_size = 0;
William Lallemand1d705562012-03-12 12:46:41 +01002961
2962 /* if we don't want to log normal traffic, return now */
Willy Tarreaue7dff022015-04-03 01:14:29 +02002963 err = (s->flags & SF_REDISP) ||
2964 ((s->flags & SF_ERR_MASK) > SF_ERR_LOCAL) ||
2965 (((s->flags & SF_ERR_MASK) == SF_ERR_NONE) &&
Willy Tarreau350f4872014-11-28 14:42:25 +01002966 (s->si[1].conn_retries != s->be->conn_retries)) ||
Willy Tarreaueee5b512015-04-03 23:46:31 +02002967 ((sess->fe->mode == PR_MODE_HTTP) && s->txn && s->txn->status >= 500);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002968
Willy Tarreaue36cbcb2015-04-03 15:40:56 +02002969 if (!err && (sess->fe->options2 & PR_O2_NOLOGNORM))
William Lallemand1d705562012-03-12 12:46:41 +01002970 return;
William Lallemandbddd4fd2012-02-27 11:23:10 +01002971
Willy Tarreaue36cbcb2015-04-03 15:40:56 +02002972 if (LIST_ISEMPTY(&sess->fe->logsrvs))
William Lallemand1d705562012-03-12 12:46:41 +01002973 return;
William Lallemandbddd4fd2012-02-27 11:23:10 +01002974
Willy Tarreauabcd5142013-06-11 17:18:02 +02002975 if (s->logs.level) { /* loglevel was overridden */
2976 if (s->logs.level == -1) {
2977 s->logs.logwait = 0; /* logs disabled */
2978 return;
2979 }
2980 level = s->logs.level - 1;
2981 }
2982 else {
2983 level = LOG_INFO;
Willy Tarreaue36cbcb2015-04-03 15:40:56 +02002984 if (err && (sess->fe->options2 & PR_O2_LOGERRORS))
Willy Tarreauabcd5142013-06-11 17:18:02 +02002985 level = LOG_ERR;
2986 }
William Lallemand1d705562012-03-12 12:46:41 +01002987
William Lallemand5b7ea3a2013-08-28 15:44:19 +02002988 /* if unique-id was not generated */
Tim Duesterhusa17e6622020-03-05 20:19:02 +01002989 if (!isttest(s->unique_id) && !LIST_ISEMPTY(&sess->fe->format_unique_id)) {
Tim Duesterhus2825b4b2020-02-28 15:13:34 +01002990 stream_generate_unique_id(s, &sess->fe->format_unique_id);
William Lallemand5b7ea3a2013-08-28 15:44:19 +02002991 }
2992
Dragan Dosen0b85ece2015-09-25 19:17:44 +02002993 if (!LIST_ISEMPTY(&sess->fe->logformat_sd)) {
2994 sd_size = build_logline(s, logline_rfc5424, global.max_syslog_len,
2995 &sess->fe->logformat_sd);
2996 }
2997
Dragan Dosen59cee972015-09-19 22:09:02 +02002998 size = build_logline(s, logline, global.max_syslog_len, &sess->fe->logformat);
William Lallemand1d705562012-03-12 12:46:41 +01002999 if (size > 0) {
Olivier Houchardd2ee3e72019-03-08 18:53:21 +01003000 _HA_ATOMIC_ADD(&sess->fe->log_count, 1);
Christopher Faulet5c6fefc2019-08-11 19:40:12 +02003001 __send_log(&sess->fe->logsrvs, &sess->fe->log_tag, level,
3002 logline, size + 1, logline_rfc5424, sd_size);
William Lallemand1d705562012-03-12 12:46:41 +01003003 s->logs.logwait = 0;
3004 }
3005}
William Lallemandbddd4fd2012-02-27 11:23:10 +01003006
Willy Tarreau53839352018-09-05 19:51:10 +02003007/*
3008 * send a minimalist log for the session. Will not log if the frontend has no
3009 * log defined. It is assumed that this is only used to report anomalies that
3010 * cannot lead to the creation of a regular stream. Because of this the log
3011 * level is LOG_INFO or LOG_ERR depending on the "log-separate-error" setting
3012 * in the frontend. The caller must simply know that it should not call this
Willy Tarreau9fa267d2018-10-05 10:22:27 +02003013 * function to report unimportant events. It is safe to call this function with
3014 * sess==NULL (will not do anything).
Willy Tarreau53839352018-09-05 19:51:10 +02003015 */
3016void sess_log(struct session *sess)
3017{
3018 int size, level;
3019 int sd_size = 0;
3020
Willy Tarreau9fa267d2018-10-05 10:22:27 +02003021 if (!sess)
3022 return;
3023
Willy Tarreau53839352018-09-05 19:51:10 +02003024 if (LIST_ISEMPTY(&sess->fe->logsrvs))
3025 return;
3026
3027 level = LOG_INFO;
3028 if (sess->fe->options2 & PR_O2_LOGERRORS)
3029 level = LOG_ERR;
3030
3031 if (!LIST_ISEMPTY(&sess->fe->logformat_sd)) {
3032 sd_size = sess_build_logline(sess, NULL,
3033 logline_rfc5424, global.max_syslog_len,
3034 &sess->fe->logformat_sd);
3035 }
3036
3037 size = sess_build_logline(sess, NULL, logline, global.max_syslog_len, &sess->fe->logformat);
3038 if (size > 0) {
Olivier Houchardd2ee3e72019-03-08 18:53:21 +01003039 _HA_ATOMIC_ADD(&sess->fe->log_count, 1);
Christopher Faulet5c6fefc2019-08-11 19:40:12 +02003040 __send_log(&sess->fe->logsrvs, &sess->fe->log_tag, level,
3041 logline, size + 1, logline_rfc5424, sd_size);
Willy Tarreau53839352018-09-05 19:51:10 +02003042 }
3043}
3044
Christopher Faulet5c6fefc2019-08-11 19:40:12 +02003045void app_log(struct list *logsrvs, struct buffer *tag, int level, const char *format, ...)
3046{
3047 va_list argp;
3048 int data_len;
3049
3050 if (level < 0 || format == NULL || logline == NULL)
3051 return;
3052
3053 va_start(argp, format);
3054 data_len = vsnprintf(logline, global.max_syslog_len, format, argp);
3055 if (data_len < 0 || data_len > global.max_syslog_len)
3056 data_len = global.max_syslog_len;
3057 va_end(argp);
3058
3059 __send_log(logsrvs, tag, level, logline, data_len, default_rfc5424_sd_log_format, 2);
3060}
3061
Willy Tarreau869efd52019-11-15 15:16:57 +01003062/* parse the "show startup-logs" command, returns 1 if a message is returned, otherwise zero */
3063static int cli_parse_show_startup_logs(char **args, char *payload, struct appctx *appctx, void *private)
Christopher Fauletc1b730a2017-10-24 12:00:51 +02003064{
Willy Tarreau869efd52019-11-15 15:16:57 +01003065 if (!cli_has_level(appctx, ACCESS_LVL_OPER))
3066 return 1;
Christopher Fauletc1b730a2017-10-24 12:00:51 +02003067
Willy Tarreau869efd52019-11-15 15:16:57 +01003068 if (!startup_logs)
3069 return cli_msg(appctx, LOG_INFO, "\n"); // nothing to print
3070
3071 return ring_attach_cli(startup_logs, appctx);
Christopher Fauletc1b730a2017-10-24 12:00:51 +02003072}
3073
3074/* register cli keywords */
3075static struct cli_kw_list cli_kws = {{ },{
3076 { { "show", "startup-logs", NULL },
Willy Tarreau869efd52019-11-15 15:16:57 +01003077 "show startup-logs : report logs emitted during HAProxy startup", cli_parse_show_startup_logs, NULL, NULL },
Christopher Fauletc1b730a2017-10-24 12:00:51 +02003078 {{},}
3079}};
3080
Willy Tarreau0108d902018-11-25 19:14:37 +01003081INITCALL1(STG_REGISTER, cli_register_kw, &cli_kws);
3082
Willy Tarreau082b6282019-05-22 14:42:12 +02003083REGISTER_PER_THREAD_ALLOC(init_log_buffers);
3084REGISTER_PER_THREAD_FREE(deinit_log_buffers);
Willy Tarreau172f5ce2018-11-26 11:21:50 +01003085
Willy Tarreaubaaee002006-06-26 02:48:02 +02003086/*
3087 * Local variables:
3088 * c-indent-level: 8
3089 * c-basic-offset: 8
3090 * End:
3091 */