blob: 5d672942c8a6f0329d77a100530eea234f86adee [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 Tarreaubb869862020-04-16 10:52:41 +020032#include <common/version.h>
Willy Tarreaubaaee002006-06-26 02:48:02 +020033
Christopher Fauletc1b730a2017-10-24 12:00:51 +020034#include <types/cli.h>
Willy Tarreaubaaee002006-06-26 02:48:02 +020035#include <types/global.h>
William Lallemand723b73a2012-02-08 16:37:49 +010036#include <types/log.h>
Willy Tarreauec6c5df2008-07-15 00:22:45 +020037
Christopher Fauletc1b730a2017-10-24 12:00:51 +020038#include <proto/applet.h>
39#include <proto/cli.h>
Willy Tarreaud52a7f82019-08-30 14:05:35 +020040#include <proto/fd.h>
William Lallemand5f232402012-04-05 18:02:55 +020041#include <proto/frontend.h>
Willy Tarreauec6c5df2008-07-15 00:22:45 +020042#include <proto/log.h>
Willy Tarreauc046d162019-08-30 15:24:59 +020043#include <proto/ring.h>
Willy Tarreauc8368452012-12-21 00:09:23 +010044#include <proto/sample.h>
Willy Tarreauc046d162019-08-30 15:24:59 +020045#include <proto/sink.h>
Willy Tarreauc125cef2019-05-10 09:58:43 +020046#include <proto/ssl_sock.h>
Willy Tarreaufb0afa72015-04-03 14:46:27 +020047#include <proto/stream.h>
Willy Tarreau827aee92011-03-10 16:55:02 +010048#include <proto/stream_interface.h>
Willy Tarreaubaaee002006-06-26 02:48:02 +020049
Dragan Dosen43885c72015-10-01 13:18:13 +020050struct log_fmt {
51 char *name;
52 struct {
Willy Tarreau83061a82018-07-13 11:56:34 +020053 struct buffer sep1; /* first pid separator */
54 struct buffer sep2; /* second pid separator */
Dragan Dosen43885c72015-10-01 13:18:13 +020055 } pid;
56};
57
58static const struct log_fmt log_formats[LOG_FORMATS] = {
59 [LOG_FORMAT_RFC3164] = {
60 .name = "rfc3164",
61 .pid = {
Willy Tarreau843b7cb2018-07-13 10:54:26 +020062 .sep1 = { .area = "[", .data = 1 },
63 .sep2 = { .area = "]: ", .data = 3 }
Dragan Dosen43885c72015-10-01 13:18:13 +020064 }
65 },
66 [LOG_FORMAT_RFC5424] = {
67 .name = "rfc5424",
68 .pid = {
Willy Tarreau843b7cb2018-07-13 10:54:26 +020069 .sep1 = { .area = " ", .data = 1 },
70 .sep2 = { .area = " - ", .data = 3 }
Dragan Dosen43885c72015-10-01 13:18:13 +020071 }
Willy Tarreaue8746a02018-11-12 08:45:00 +010072 },
73 [LOG_FORMAT_SHORT] = {
74 .name = "short",
75 .pid = {
76 .sep1 = { .area = "", .data = 0 },
77 .sep2 = { .area = " ", .data = 1 },
78 }
79 },
Willy Tarreauc1b06452018-11-12 11:57:56 +010080 [LOG_FORMAT_RAW] = {
81 .name = "raw",
82 .pid = {
83 .sep1 = { .area = "", .data = 0 },
84 .sep2 = { .area = "", .data = 0 },
85 }
86 },
Dragan Dosen1322d092015-09-22 16:05:32 +020087};
88
Dragan Dosen835b9212016-02-12 13:23:03 +010089/*
90 * This map is used with all the FD_* macros to check whether a particular bit
Willy Tarreau1bfd6022019-06-07 11:10:07 +020091 * is set or not. Each bit represents an ACSII code. ha_bit_set() sets those
92 * bytes which should be escaped. When ha_bit_test() returns non-zero, it means
93 * that the byte should be escaped. Be careful to always pass bytes from 0 to
94 * 255 exclusively to the macros.
Dragan Dosen835b9212016-02-12 13:23:03 +010095 */
Willy Tarreau1bfd6022019-06-07 11:10:07 +020096long rfc5424_escape_map[(256/8) / sizeof(long)];
97long hdr_encode_map[(256/8) / sizeof(long)];
98long url_encode_map[(256/8) / sizeof(long)];
99long http_encode_map[(256/8) / sizeof(long)];
Dragan Dosen835b9212016-02-12 13:23:03 +0100100
Dragan Dosen835b9212016-02-12 13:23:03 +0100101
Willy Tarreaubaaee002006-06-26 02:48:02 +0200102const char *log_facilities[NB_LOG_FACILITIES] = {
103 "kern", "user", "mail", "daemon",
104 "auth", "syslog", "lpr", "news",
105 "uucp", "cron", "auth2", "ftp",
106 "ntp", "audit", "alert", "cron2",
107 "local0", "local1", "local2", "local3",
108 "local4", "local5", "local6", "local7"
109};
110
Willy Tarreaubaaee002006-06-26 02:48:02 +0200111const char *log_levels[NB_LOG_LEVELS] = {
112 "emerg", "alert", "crit", "err",
113 "warning", "notice", "info", "debug"
114};
115
Willy Tarreau570f2212013-06-10 16:42:09 +0200116const 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 +0200117const char sess_fin_state[8] = "-RCHDLQT"; /* cliRequest, srvConnect, srvHeader, Data, Last, Queue, Tarpit */
Willy Tarreaubaaee002006-06-26 02:48:02 +0200118
William Lallemand723b73a2012-02-08 16:37:49 +0100119
120/* log_format */
121struct logformat_type {
122 char *name;
123 int type;
William Lallemandbddd4fd2012-02-27 11:23:10 +0100124 int mode;
William Lallemand5e19a282012-04-02 16:22:10 +0200125 int lw; /* logwait bitsfield */
William Lallemandb7ff6a32012-03-02 14:35:21 +0100126 int (*config_callback)(struct logformat_node *node, struct proxy *curproxy);
Willy Tarreau2beef582012-12-20 17:22:52 +0100127 const char *replace_by; /* new option to use instead of old one */
William Lallemand723b73a2012-02-08 16:37:49 +0100128};
129
William Lallemandb7ff6a32012-03-02 14:35:21 +0100130int prepare_addrsource(struct logformat_node *node, struct proxy *curproxy);
131
William Lallemand723b73a2012-02-08 16:37:49 +0100132/* log_format variable names */
133static const struct logformat_type logformat_keywords[] = {
William Lallemand5e19a282012-04-02 16:22:10 +0200134 { "o", LOG_FMT_GLOBAL, PR_MODE_TCP, 0, NULL }, /* global option */
Willy Tarreau2beef582012-12-20 17:22:52 +0100135
136 /* please keep these lines sorted ! */
137 { "B", LOG_FMT_BYTES, PR_MODE_TCP, LW_BYTES, NULL }, /* bytes from server to client */
138 { "CC", LOG_FMT_CCLIENT, PR_MODE_HTTP, LW_REQHDR, NULL }, /* client cookie */
139 { "CS", LOG_FMT_CSERVER, PR_MODE_HTTP, LW_RSPHDR, NULL }, /* server cookie */
140 { "H", LOG_FMT_HOSTNAME, PR_MODE_TCP, LW_INIT, NULL }, /* Hostname */
Tim Duesterhuscf6e0c82020-03-13 12:34:24 +0100141 { "ID", LOG_FMT_UNIQUEID, PR_MODE_TCP, LW_BYTES, NULL }, /* Unique ID */
Willy Tarreau4bf99632014-06-13 12:21:40 +0200142 { "ST", LOG_FMT_STATUS, PR_MODE_TCP, LW_RESP, NULL }, /* status code */
William Lallemand5e19a282012-04-02 16:22:10 +0200143 { "T", LOG_FMT_DATEGMT, PR_MODE_TCP, LW_INIT, NULL }, /* date GMT */
Thierry FOURNIER / OZON.IO4cac3592016-07-28 17:19:45 +0200144 { "Ta", LOG_FMT_Ta, PR_MODE_HTTP, LW_BYTES, NULL }, /* Time active (tr to end) */
Willy Tarreau2beef582012-12-20 17:22:52 +0100145 { "Tc", LOG_FMT_TC, PR_MODE_TCP, LW_BYTES, NULL }, /* Tc */
Thierry FOURNIER / OZON.IO4cac3592016-07-28 17:19:45 +0200146 { "Th", LOG_FMT_Th, PR_MODE_TCP, LW_BYTES, NULL }, /* Time handshake */
147 { "Ti", LOG_FMT_Ti, PR_MODE_HTTP, LW_BYTES, NULL }, /* Time idle */
148 { "Tl", LOG_FMT_DATELOCAL, PR_MODE_TCP, LW_INIT, NULL }, /* date local timezone */
149 { "Tq", LOG_FMT_TQ, PR_MODE_HTTP, LW_BYTES, NULL }, /* Tq=Th+Ti+TR */
150 { "Tr", LOG_FMT_Tr, PR_MODE_HTTP, LW_BYTES, NULL }, /* Tr */
151 { "TR", LOG_FMT_TR, PR_MODE_HTTP, LW_BYTES, NULL }, /* Time to receive a valid request */
Willy Tarreau27b639d2016-05-17 17:55:27 +0200152 { "Td", LOG_FMT_TD, PR_MODE_TCP, LW_BYTES, NULL }, /* Td = Tt - (Tq + Tw + Tc + Tr) */
Willy Tarreau2beef582012-12-20 17:22:52 +0100153 { "Ts", LOG_FMT_TS, PR_MODE_TCP, LW_INIT, NULL }, /* timestamp GMT */
William Lallemand5e19a282012-04-02 16:22:10 +0200154 { "Tt", LOG_FMT_TT, PR_MODE_TCP, LW_BYTES, NULL }, /* Tt */
Damien Claisse57c8eb92020-04-28 12:09:19 +0000155 { "Tu", LOG_FMT_TU, PR_MODE_TCP, LW_BYTES, NULL }, /* Tu = Tt -Ti */
Willy Tarreau2beef582012-12-20 17:22:52 +0100156 { "Tw", LOG_FMT_TW, PR_MODE_TCP, LW_BYTES, NULL }, /* Tw */
157 { "U", LOG_FMT_BYTES_UP, PR_MODE_TCP, LW_BYTES, NULL }, /* bytes from client to server */
William Lallemand5e19a282012-04-02 16:22:10 +0200158 { "ac", LOG_FMT_ACTCONN, PR_MODE_TCP, LW_BYTES, NULL }, /* actconn */
Willy Tarreau2beef582012-12-20 17:22:52 +0100159 { "b", LOG_FMT_BACKEND, PR_MODE_TCP, LW_INIT, NULL }, /* backend */
William Lallemand5e19a282012-04-02 16:22:10 +0200160 { "bc", LOG_FMT_BECONN, PR_MODE_TCP, LW_BYTES, NULL }, /* beconn */
Willy Tarreau2beef582012-12-20 17:22:52 +0100161 { "bi", LOG_FMT_BACKENDIP, PR_MODE_TCP, LW_BCKIP, prepare_addrsource }, /* backend source ip */
162 { "bp", LOG_FMT_BACKENDPORT, PR_MODE_TCP, LW_BCKIP, prepare_addrsource }, /* backend source port */
William Lallemand5e19a282012-04-02 16:22:10 +0200163 { "bq", LOG_FMT_BCKQUEUE, PR_MODE_TCP, LW_BYTES, NULL }, /* backend_queue */
Willy Tarreaud02286d2017-06-23 11:23:43 +0200164 { "ci", LOG_FMT_CLIENTIP, PR_MODE_TCP, LW_CLIP | LW_XPRT, NULL }, /* client ip */
165 { "cp", LOG_FMT_CLIENTPORT, PR_MODE_TCP, LW_CLIP | LW_XPRT, NULL }, /* client port */
Willy Tarreau2beef582012-12-20 17:22:52 +0100166 { "f", LOG_FMT_FRONTEND, PR_MODE_TCP, LW_INIT, NULL }, /* frontend */
167 { "fc", LOG_FMT_FECONN, PR_MODE_TCP, LW_BYTES, NULL }, /* feconn */
Willy Tarreaud02286d2017-06-23 11:23:43 +0200168 { "fi", LOG_FMT_FRONTENDIP, PR_MODE_TCP, LW_FRTIP | LW_XPRT, NULL }, /* frontend ip */
169 { "fp", LOG_FMT_FRONTENDPORT, PR_MODE_TCP, LW_FRTIP | LW_XPRT, NULL }, /* frontend port */
Willy Tarreau2beef582012-12-20 17:22:52 +0100170 { "ft", LOG_FMT_FRONTEND_XPRT, PR_MODE_TCP, LW_INIT, NULL }, /* frontend with transport mode */
Willy Tarreaud9ed3d22014-06-13 12:23:06 +0200171 { "hr", LOG_FMT_HDRREQUEST, PR_MODE_TCP, LW_REQHDR, NULL }, /* header request */
172 { "hrl", LOG_FMT_HDRREQUESTLIST, PR_MODE_TCP, LW_REQHDR, NULL }, /* header request list */
173 { "hs", LOG_FMT_HDRRESPONS, PR_MODE_TCP, LW_RSPHDR, NULL }, /* header response */
174 { "hsl", LOG_FMT_HDRRESPONSLIST, PR_MODE_TCP, LW_RSPHDR, NULL }, /* header response list */
Andrew Hayworth0ebc55f2015-04-27 21:37:03 +0000175 { "HM", LOG_FMT_HTTP_METHOD, PR_MODE_HTTP, LW_REQ, NULL }, /* HTTP method */
176 { "HP", LOG_FMT_HTTP_PATH, PR_MODE_HTTP, LW_REQ, NULL }, /* HTTP path */
Andrew Hayworthe63ac872015-07-31 16:14:16 +0000177 { "HQ", LOG_FMT_HTTP_QUERY, PR_MODE_HTTP, LW_REQ, NULL }, /* HTTP query */
Andrew Hayworth0ebc55f2015-04-27 21:37:03 +0000178 { "HU", LOG_FMT_HTTP_URI, PR_MODE_HTTP, LW_REQ, NULL }, /* HTTP full URI */
179 { "HV", LOG_FMT_HTTP_VERSION, PR_MODE_HTTP, LW_REQ, NULL }, /* HTTP version */
Willy Tarreau7346acb2014-08-28 15:03:15 +0200180 { "lc", LOG_FMT_LOGCNT, PR_MODE_TCP, LW_INIT, NULL }, /* log counter */
Willy Tarreau2beef582012-12-20 17:22:52 +0100181 { "ms", LOG_FMT_MS, PR_MODE_TCP, LW_INIT, NULL }, /* accept date millisecond */
William Lallemand5e19a282012-04-02 16:22:10 +0200182 { "pid", LOG_FMT_PID, PR_MODE_TCP, LW_INIT, NULL }, /* log pid */
Willy Tarreau2beef582012-12-20 17:22:52 +0100183 { "r", LOG_FMT_REQ, PR_MODE_HTTP, LW_REQ, NULL }, /* request */
184 { "rc", LOG_FMT_RETRIES, PR_MODE_TCP, LW_BYTES, NULL }, /* retries */
Willy Tarreau1f0da242014-01-25 11:01:50 +0100185 { "rt", LOG_FMT_COUNTER, PR_MODE_TCP, LW_REQ, NULL }, /* request counter (HTTP or TCP session) */
Willy Tarreau2beef582012-12-20 17:22:52 +0100186 { "s", LOG_FMT_SERVER, PR_MODE_TCP, LW_SVID, NULL }, /* server */
187 { "sc", LOG_FMT_SRVCONN, PR_MODE_TCP, LW_BYTES, NULL }, /* srv_conn */
188 { "si", LOG_FMT_SERVERIP, PR_MODE_TCP, LW_SVIP, NULL }, /* server destination ip */
189 { "sp", LOG_FMT_SERVERPORT, PR_MODE_TCP, LW_SVIP, NULL }, /* server destination port */
190 { "sq", LOG_FMT_SRVQUEUE, PR_MODE_TCP, LW_BYTES, NULL }, /* srv_queue */
Willy Tarreauffc3fcd2012-10-12 20:17:54 +0200191 { "sslc", LOG_FMT_SSL_CIPHER, PR_MODE_TCP, LW_XPRT, NULL }, /* client-side SSL ciphers */
192 { "sslv", LOG_FMT_SSL_VERSION, PR_MODE_TCP, LW_XPRT, NULL }, /* client-side SSL protocol version */
Willy Tarreau2beef582012-12-20 17:22:52 +0100193 { "t", LOG_FMT_DATE, PR_MODE_TCP, LW_INIT, NULL }, /* date */
Thierry FOURNIER / OZON.IO4cac3592016-07-28 17:19:45 +0200194 { "tr", LOG_FMT_tr, PR_MODE_HTTP, LW_INIT, NULL }, /* date of start of request */
195 { "trg",LOG_FMT_trg, PR_MODE_HTTP, LW_INIT, NULL }, /* date of start of request, GMT */
196 { "trl",LOG_FMT_trl, PR_MODE_HTTP, LW_INIT, NULL }, /* date of start of request, local */
Willy Tarreau2beef582012-12-20 17:22:52 +0100197 { "ts", LOG_FMT_TERMSTATE, PR_MODE_TCP, LW_BYTES, NULL },/* termination state */
198 { "tsc", LOG_FMT_TERMSTATE_CK, PR_MODE_TCP, LW_INIT, NULL },/* termination state */
199
200 /* The following tags are deprecated and will be removed soon */
201 { "Bi", LOG_FMT_BACKENDIP, PR_MODE_TCP, LW_BCKIP, prepare_addrsource, "bi" }, /* backend source ip */
202 { "Bp", LOG_FMT_BACKENDPORT, PR_MODE_TCP, LW_BCKIP, prepare_addrsource, "bp" }, /* backend source port */
Willy Tarreaud02286d2017-06-23 11:23:43 +0200203 { "Ci", LOG_FMT_CLIENTIP, PR_MODE_TCP, LW_CLIP | LW_XPRT, NULL, "ci" }, /* client ip */
204 { "Cp", LOG_FMT_CLIENTPORT, PR_MODE_TCP, LW_CLIP | LW_XPRT, NULL, "cp" }, /* client port */
205 { "Fi", LOG_FMT_FRONTENDIP, PR_MODE_TCP, LW_FRTIP | LW_XPRT, NULL, "fi" }, /* frontend ip */
206 { "Fp", LOG_FMT_FRONTENDPORT, PR_MODE_TCP, LW_FRTIP | LW_XPRT, NULL, "fp" }, /* frontend port */
Willy Tarreau2beef582012-12-20 17:22:52 +0100207 { "Si", LOG_FMT_SERVERIP, PR_MODE_TCP, LW_SVIP, NULL, "si" }, /* server destination ip */
208 { "Sp", LOG_FMT_SERVERPORT, PR_MODE_TCP, LW_SVIP, NULL, "sp" }, /* server destination port */
209 { "cc", LOG_FMT_CCLIENT, PR_MODE_HTTP, LW_REQHDR, NULL, "CC" }, /* client cookie */
210 { "cs", LOG_FMT_CSERVER, PR_MODE_HTTP, LW_RSPHDR, NULL, "CS" }, /* server cookie */
211 { "st", LOG_FMT_STATUS, PR_MODE_HTTP, LW_RESP, NULL, "ST" }, /* status code */
William Lallemand5e19a282012-04-02 16:22:10 +0200212 { 0, 0, 0, 0, NULL }
William Lallemand723b73a2012-02-08 16:37:49 +0100213};
214
Thierry FOURNIER / OZON.IO4cac3592016-07-28 17:19:45 +0200215char 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
216char 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 +0100217char 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 +0100218char *log_format = NULL;
219
Dragan Dosen0b85ece2015-09-25 19:17:44 +0200220/* Default string used for structured-data part in RFC5424 formatted
221 * syslog messages.
222 */
223char default_rfc5424_sd_log_format[] = "- ";
Dragan Dosen1322d092015-09-22 16:05:32 +0200224
Willy Tarreau13ef7732018-11-12 07:25:28 +0100225/* total number of dropped logs */
226unsigned int dropped_logs = 0;
227
Dragan Dosen1322d092015-09-22 16:05:32 +0200228/* This is a global syslog header, common to all outgoing messages in
229 * RFC3164 format. It begins with time-based part and is updated by
230 * update_log_hdr().
Dragan Dosen59cee972015-09-19 22:09:02 +0200231 */
Christopher Fauletf8188c62017-06-02 16:20:16 +0200232THREAD_LOCAL char *logheader = NULL;
Willy Tarreau55e2f5a2019-05-05 10:11:39 +0200233THREAD_LOCAL char *logheader_end = NULL;
Dragan Dosen59cee972015-09-19 22:09:02 +0200234
Dragan Dosen1322d092015-09-22 16:05:32 +0200235/* This is a global syslog header for messages in RFC5424 format. It is
236 * updated by update_log_hdr_rfc5424().
237 */
Christopher Fauletf8188c62017-06-02 16:20:16 +0200238THREAD_LOCAL char *logheader_rfc5424 = NULL;
Willy Tarreau55e2f5a2019-05-05 10:11:39 +0200239THREAD_LOCAL char *logheader_rfc5424_end = NULL;
Dragan Dosen1322d092015-09-22 16:05:32 +0200240
Dragan Dosen59cee972015-09-19 22:09:02 +0200241/* This is a global syslog message buffer, common to all outgoing
242 * messages. It contains only the data part.
Willy Tarreaub1a2faf2012-03-19 16:51:53 +0100243 */
Christopher Fauletf8188c62017-06-02 16:20:16 +0200244THREAD_LOCAL char *logline = NULL;
Willy Tarreaub1a2faf2012-03-19 16:51:53 +0100245
Dragan Dosen0b85ece2015-09-25 19:17:44 +0200246/* A global syslog message buffer, common to all RFC5424 syslog messages.
247 * Currently, it is used for generating the structured-data part.
248 */
Christopher Fauletf8188c62017-06-02 16:20:16 +0200249THREAD_LOCAL char *logline_rfc5424 = NULL;
Dragan Dosen0b85ece2015-09-25 19:17:44 +0200250
Christopher Fauletd4696382017-10-24 11:44:05 +0200251/* A global buffer used to store all startup alerts/warnings. It will then be
252 * retrieve on the CLI. */
Willy Tarreau869efd52019-11-15 15:16:57 +0100253static struct ring *startup_logs = NULL;
Christopher Fauletd4696382017-10-24 11:44:05 +0200254
William Lallemand723b73a2012-02-08 16:37:49 +0100255struct logformat_var_args {
256 char *name;
257 int mask;
258};
259
260struct logformat_var_args var_args_list[] = {
261// global
262 { "M", LOG_OPT_MANDATORY },
263 { "Q", LOG_OPT_QUOTE },
William Lallemand5f232402012-04-05 18:02:55 +0200264 { "X", LOG_OPT_HEXA },
Dragan Dosen835b9212016-02-12 13:23:03 +0100265 { "E", LOG_OPT_ESC },
William Lallemand723b73a2012-02-08 16:37:49 +0100266 { 0, 0 }
267};
268
Willy Tarreaub1f3af22013-04-12 18:30:32 +0200269/* return the name of the directive used in the current proxy for which we're
270 * currently parsing a header, when it is known.
271 */
272static inline const char *fmt_directive(const struct proxy *curproxy)
273{
Willy Tarreaubf0addb2013-12-02 12:24:54 +0100274 switch (curproxy->conf.args.ctx) {
Willy Tarreau53e1a6d2015-07-09 11:20:00 +0200275 case ARGC_ACL:
276 return "acl";
277 case ARGC_STK:
278 return "stick";
279 case ARGC_TRK:
280 return "track-sc";
281 case ARGC_LOG:
282 return "log-format";
Dragan Dosen0b85ece2015-09-25 19:17:44 +0200283 case ARGC_LOGSD:
284 return "log-format-sd";
Willy Tarreaubf0addb2013-12-02 12:24:54 +0100285 case ARGC_HRQ:
Thierry FOURNIER1c0054f2013-11-20 15:09:52 +0100286 return "http-request";
Willy Tarreaubf0addb2013-12-02 12:24:54 +0100287 case ARGC_HRS:
Thierry FOURNIER1c0054f2013-11-20 15:09:52 +0100288 return "http-response";
Willy Tarreau53e1a6d2015-07-09 11:20:00 +0200289 case ARGC_UIF:
290 return "unique-id-format";
Thierry FOURNIERd18cd0f2013-11-29 12:15:45 +0100291 case ARGC_RDR:
Willy Tarreau53e1a6d2015-07-09 11:20:00 +0200292 return "redirect";
293 case ARGC_CAP:
294 return "capture";
Willy Tarreau28d976d2015-07-09 11:39:33 +0200295 case ARGC_SRV:
296 return "server";
Christopher Fauletf7e4e7e2016-10-27 22:29:49 +0200297 case ARGC_SPOE:
298 return "spoe-message";
Thierry FOURNIER / OZON.IO4ed1c952016-11-24 23:57:54 +0100299 case ARGC_UBK:
300 return "use_backend";
Willy Tarreaubf0addb2013-12-02 12:24:54 +0100301 default:
Willy Tarreau53e1a6d2015-07-09 11:20:00 +0200302 return "undefined(please report this bug)"; /* must never happen */
Willy Tarreaubf0addb2013-12-02 12:24:54 +0100303 }
Willy Tarreaub1f3af22013-04-12 18:30:32 +0200304}
305
William Lallemand723b73a2012-02-08 16:37:49 +0100306/*
William Lallemandb7ff6a32012-03-02 14:35:21 +0100307 * callback used to configure addr source retrieval
308 */
309int prepare_addrsource(struct logformat_node *node, struct proxy *curproxy)
310{
311 curproxy->options2 |= PR_O2_SRC_ADDR;
312
313 return 0;
314}
315
316
317/*
Thierry FOURNIER / OZON.IObca46f02016-11-22 23:13:04 +0100318 * Parse args in a logformat_var. Returns 0 in error
319 * case, otherwise, it returns 1.
William Lallemand723b73a2012-02-08 16:37:49 +0100320 */
Thierry FOURNIER / OZON.IO8a4e4422016-11-23 00:41:28 +0100321int parse_logformat_var_args(char *args, struct logformat_node *node, char **err)
William Lallemand723b73a2012-02-08 16:37:49 +0100322{
323 int i = 0;
324 int end = 0;
325 int flags = 0; // 1 = + 2 = -
326 char *sp = NULL; // start pointer
327
Thierry FOURNIER / OZON.IO8a4e4422016-11-23 00:41:28 +0100328 if (args == NULL) {
329 memprintf(err, "internal error: parse_logformat_var_args() expects non null 'args'");
Thierry FOURNIER / OZON.IObca46f02016-11-22 23:13:04 +0100330 return 0;
Thierry FOURNIER / OZON.IO8a4e4422016-11-23 00:41:28 +0100331 }
William Lallemand723b73a2012-02-08 16:37:49 +0100332
333 while (1) {
334 if (*args == '\0')
335 end = 1;
336
337 if (*args == '+') {
338 // add flag
339 sp = args + 1;
340 flags = 1;
341 }
342 if (*args == '-') {
343 // delete flag
344 sp = args + 1;
345 flags = 2;
346 }
347
348 if (*args == '\0' || *args == ',') {
349 *args = '\0';
Willy Tarreau254d44c2012-12-20 18:19:26 +0100350 for (i = 0; sp && var_args_list[i].name; i++) {
William Lallemand723b73a2012-02-08 16:37:49 +0100351 if (strcmp(sp, var_args_list[i].name) == 0) {
352 if (flags == 1) {
353 node->options |= var_args_list[i].mask;
354 break;
355 } else if (flags == 2) {
356 node->options &= ~var_args_list[i].mask;
357 break;
358 }
359 }
360 }
361 sp = NULL;
362 if (end)
363 break;
364 }
Willy Tarreau254d44c2012-12-20 18:19:26 +0100365 args++;
William Lallemand723b73a2012-02-08 16:37:49 +0100366 }
Thierry FOURNIER / OZON.IObca46f02016-11-22 23:13:04 +0100367 return 1;
William Lallemand723b73a2012-02-08 16:37:49 +0100368}
369
370/*
Willy Tarreau8a3f52f2012-12-20 21:23:42 +0100371 * Parse a variable '%varname' or '%{args}varname' in log-format. The caller
372 * must pass the args part in the <arg> pointer with its length in <arg_len>,
373 * and varname with its length in <var> and <var_len> respectively. <arg> is
374 * ignored when arg_len is 0. Neither <var> nor <var_len> may be null.
Thierry FOURNIER / OZON.IOeca4d952016-11-22 22:06:04 +0100375 * Returns false in error case and err is filled, otherwise returns true.
William Lallemand723b73a2012-02-08 16:37:49 +0100376 */
Thierry FOURNIER / OZON.IO8a4e4422016-11-23 00:41:28 +0100377int parse_logformat_var(char *arg, int arg_len, char *var, int var_len, struct proxy *curproxy, struct list *list_format, int *defoptions, char **err)
William Lallemand723b73a2012-02-08 16:37:49 +0100378{
Willy Tarreau8a3f52f2012-12-20 21:23:42 +0100379 int j;
Dragan Dosen61302da2019-04-30 00:40:02 +0200380 struct logformat_node *node = NULL;
William Lallemand723b73a2012-02-08 16:37:49 +0100381
Willy Tarreau8a3f52f2012-12-20 21:23:42 +0100382 for (j = 0; logformat_keywords[j].name; j++) { // search a log type
383 if (strlen(logformat_keywords[j].name) == var_len &&
384 strncmp(var, logformat_keywords[j].name, var_len) == 0) {
385 if (logformat_keywords[j].mode != PR_MODE_HTTP || curproxy->mode == PR_MODE_HTTP) {
Vincent Bernat02779b62016-04-03 13:48:43 +0200386 node = calloc(1, sizeof(*node));
Thierry FOURNIER / OZON.IO9cbfef22016-11-22 23:24:10 +0100387 if (!node) {
Thierry FOURNIER / OZON.IO8a4e4422016-11-23 00:41:28 +0100388 memprintf(err, "out of memory error");
Dragan Dosen61302da2019-04-30 00:40:02 +0200389 goto error_free;
Thierry FOURNIER / OZON.IO9cbfef22016-11-22 23:24:10 +0100390 }
Willy Tarreau8a3f52f2012-12-20 21:23:42 +0100391 node->type = logformat_keywords[j].type;
392 node->options = *defoptions;
393 if (arg_len) {
394 node->arg = my_strndup(arg, arg_len);
Thierry FOURNIER / OZON.IO8a4e4422016-11-23 00:41:28 +0100395 if (!parse_logformat_var_args(node->arg, node, err))
Dragan Dosen61302da2019-04-30 00:40:02 +0200396 goto error_free;
Willy Tarreau8a3f52f2012-12-20 21:23:42 +0100397 }
398 if (node->type == LOG_FMT_GLOBAL) {
399 *defoptions = node->options;
400 free(node->arg);
401 free(node);
402 } else {
403 if (logformat_keywords[j].config_callback &&
404 logformat_keywords[j].config_callback(node, curproxy) != 0) {
Dragan Dosen61302da2019-04-30 00:40:02 +0200405 goto error_free;
William Lallemand723b73a2012-02-08 16:37:49 +0100406 }
Willy Tarreau8a3f52f2012-12-20 21:23:42 +0100407 curproxy->to_log |= logformat_keywords[j].lw;
408 LIST_ADDQ(list_format, &node->list);
William Lallemand723b73a2012-02-08 16:37:49 +0100409 }
Willy Tarreau8a3f52f2012-12-20 21:23:42 +0100410 if (logformat_keywords[j].replace_by)
Christopher Faulet767a84b2017-11-24 16:50:31 +0100411 ha_warning("parsing [%s:%d] : deprecated variable '%s' in '%s', please replace it with '%s'.\n",
412 curproxy->conf.args.file, curproxy->conf.args.line,
413 logformat_keywords[j].name, fmt_directive(curproxy), logformat_keywords[j].replace_by);
Thierry FOURNIER / OZON.IOeca4d952016-11-22 22:06:04 +0100414 return 1;
Willy Tarreau8a3f52f2012-12-20 21:23:42 +0100415 } else {
Thierry FOURNIER / OZON.IO8a4e4422016-11-23 00:41:28 +0100416 memprintf(err, "format variable '%s' is reserved for HTTP mode",
417 logformat_keywords[j].name);
Dragan Dosen61302da2019-04-30 00:40:02 +0200418 goto error_free;
William Lallemand723b73a2012-02-08 16:37:49 +0100419 }
William Lallemand723b73a2012-02-08 16:37:49 +0100420 }
421 }
Willy Tarreau8a3f52f2012-12-20 21:23:42 +0100422
423 j = var[var_len];
424 var[var_len] = 0;
Thierry FOURNIER / OZON.IO8a4e4422016-11-23 00:41:28 +0100425 memprintf(err, "no such format variable '%s'. If you wanted to emit the '%%' character verbatim, you need to use '%%%%'", var);
Willy Tarreau8a3f52f2012-12-20 21:23:42 +0100426 var[var_len] = j;
Dragan Dosen61302da2019-04-30 00:40:02 +0200427
428 error_free:
429 if (node) {
430 free(node->arg);
431 free(node);
432 }
Thierry FOURNIER / OZON.IOeca4d952016-11-22 22:06:04 +0100433 return 0;
William Lallemand723b73a2012-02-08 16:37:49 +0100434}
435
436/*
437 * push to the logformat linked list
438 *
439 * start: start pointer
440 * end: end text pointer
441 * type: string type
William Lallemand1d705562012-03-12 12:46:41 +0100442 * list_format: destination list
William Lallemand723b73a2012-02-08 16:37:49 +0100443 *
444 * LOG_TEXT: copy chars from start to end excluding end.
445 *
446*/
Thierry FOURNIER / OZON.IO8a4e4422016-11-23 00:41:28 +0100447int add_to_logformat_list(char *start, char *end, int type, struct list *list_format, char **err)
William Lallemand723b73a2012-02-08 16:37:49 +0100448{
449 char *str;
450
Willy Tarreaua3571662012-12-20 21:59:12 +0100451 if (type == LF_TEXT) { /* type text */
Vincent Bernat02779b62016-04-03 13:48:43 +0200452 struct logformat_node *node = calloc(1, sizeof(*node));
Thierry FOURNIER / OZON.IO9cbfef22016-11-22 23:24:10 +0100453 if (!node) {
Thierry FOURNIER / OZON.IO8a4e4422016-11-23 00:41:28 +0100454 memprintf(err, "out of memory error");
Thierry FOURNIER / OZON.IO9cbfef22016-11-22 23:24:10 +0100455 return 0;
456 }
Vincent Bernat02779b62016-04-03 13:48:43 +0200457 str = calloc(1, end - start + 1);
William Lallemand723b73a2012-02-08 16:37:49 +0100458 strncpy(str, start, end - start);
William Lallemand723b73a2012-02-08 16:37:49 +0100459 str[end - start] = '\0';
460 node->arg = str;
William Lallemand1d705562012-03-12 12:46:41 +0100461 node->type = LOG_FMT_TEXT; // type string
462 LIST_ADDQ(list_format, &node->list);
Willy Tarreaua3571662012-12-20 21:59:12 +0100463 } else if (type == LF_SEPARATOR) {
Vincent Bernat02779b62016-04-03 13:48:43 +0200464 struct logformat_node *node = calloc(1, sizeof(*node));
Thierry FOURNIER / OZON.IO9cbfef22016-11-22 23:24:10 +0100465 if (!node) {
Thierry FOURNIER / OZON.IO8a4e4422016-11-23 00:41:28 +0100466 memprintf(err, "out of memory error");
Thierry FOURNIER / OZON.IO9cbfef22016-11-22 23:24:10 +0100467 return 0;
468 }
William Lallemand1d705562012-03-12 12:46:41 +0100469 node->type = LOG_FMT_SEPARATOR;
470 LIST_ADDQ(list_format, &node->list);
William Lallemand723b73a2012-02-08 16:37:49 +0100471 }
Thierry FOURNIER / OZON.IOa2c38d72016-11-22 23:11:21 +0100472 return 1;
William Lallemand723b73a2012-02-08 16:37:49 +0100473}
474
475/*
Willy Tarreauc8368452012-12-21 00:09:23 +0100476 * Parse the sample fetch expression <text> and add a node to <list_format> upon
477 * success. At the moment, sample converters are not yet supported but fetch arguments
Willy Tarreaucd0d2ed2020-02-14 17:33:06 +0100478 * should work. The curpx->conf.args.ctx must be set by the caller. If an end pointer
479 * is passed in <endptr>, it will be updated with the pointer to the first character
480 * not part of the sample expression.
Thierry FOURNIER / OZON.IOa2c38d72016-11-22 23:11:21 +0100481 *
482 * In error case, the function returns 0, otherwise it returns 1.
Willy Tarreauc8368452012-12-21 00:09:23 +0100483 */
Willy Tarreaucd0d2ed2020-02-14 17:33:06 +0100484int 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 +0100485{
486 char *cmd[2];
Dragan Dosen61302da2019-04-30 00:40:02 +0200487 struct sample_expr *expr = NULL;
488 struct logformat_node *node = NULL;
Willy Tarreauc8368452012-12-21 00:09:23 +0100489 int cmd_arg;
490
491 cmd[0] = text;
492 cmd[1] = "";
493 cmd_arg = 0;
494
Willy Tarreaucd0d2ed2020-02-14 17:33:06 +0100495 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 +0100496 if (!expr) {
Thierry FOURNIER / OZON.IO8a4e4422016-11-23 00:41:28 +0100497 memprintf(err, "failed to parse sample expression <%s> : %s", text, *err);
Dragan Dosen61302da2019-04-30 00:40:02 +0200498 goto error_free;
Willy Tarreauc8368452012-12-21 00:09:23 +0100499 }
500
Vincent Bernat02779b62016-04-03 13:48:43 +0200501 node = calloc(1, sizeof(*node));
Thierry FOURNIER / OZON.IO9cbfef22016-11-22 23:24:10 +0100502 if (!node) {
Thierry FOURNIER / OZON.IO8a4e4422016-11-23 00:41:28 +0100503 memprintf(err, "out of memory error");
Dragan Dosen61302da2019-04-30 00:40:02 +0200504 goto error_free;
Thierry FOURNIER / OZON.IO9cbfef22016-11-22 23:24:10 +0100505 }
Willy Tarreauc8368452012-12-21 00:09:23 +0100506 node->type = LOG_FMT_EXPR;
507 node->expr = expr;
508 node->options = options;
509
510 if (arg_len) {
511 node->arg = my_strndup(arg, arg_len);
Thierry FOURNIER / OZON.IO8a4e4422016-11-23 00:41:28 +0100512 if (!parse_logformat_var_args(node->arg, node, err))
Dragan Dosen61302da2019-04-30 00:40:02 +0200513 goto error_free;
Willy Tarreauc8368452012-12-21 00:09:23 +0100514 }
Willy Tarreau434c57c2013-01-08 01:10:24 +0100515 if (expr->fetch->val & cap & SMP_VAL_REQUEST)
Willy Tarreauc8368452012-12-21 00:09:23 +0100516 node->options |= LOG_OPT_REQ_CAP; /* fetch method is request-compatible */
517
Willy Tarreau434c57c2013-01-08 01:10:24 +0100518 if (expr->fetch->val & cap & SMP_VAL_RESPONSE)
Willy Tarreauc8368452012-12-21 00:09:23 +0100519 node->options |= LOG_OPT_RES_CAP; /* fetch method is response-compatible */
520
Thierry FOURNIER / OZON.IOa2c38d72016-11-22 23:11:21 +0100521 if (!(expr->fetch->val & cap)) {
Thierry FOURNIER / OZON.IO8a4e4422016-11-23 00:41:28 +0100522 memprintf(err, "sample fetch <%s> may not be reliably used here because it needs '%s' which is not available here",
523 text, sample_src_names(expr->fetch->use));
Dragan Dosen61302da2019-04-30 00:40:02 +0200524 goto error_free;
Thierry FOURNIER / OZON.IOa2c38d72016-11-22 23:11:21 +0100525 }
Willy Tarreau434c57c2013-01-08 01:10:24 +0100526
Christopher Faulet711ed6a2019-07-16 14:16:10 +0200527 /* check if we need to allocate an http_txn struct for HTTP parsing */
Willy Tarreauc8368452012-12-21 00:09:23 +0100528 /* Note, we may also need to set curpx->to_log with certain fetches */
Willy Tarreau25320b22013-03-24 07:22:08 +0100529 curpx->http_needed |= !!(expr->fetch->use & SMP_USE_HTTP_ANY);
Willy Tarreauc8368452012-12-21 00:09:23 +0100530
William Lallemand65ad6e12014-01-31 15:08:02 +0100531 /* FIXME: temporary workaround for missing LW_XPRT and LW_REQ flags
532 * needed with some sample fetches (eg: ssl*). We always set it for
533 * now on, but this will leave with sample capabilities soon.
Willy Tarreau1f31c732013-01-10 16:22:27 +0100534 */
535 curpx->to_log |= LW_XPRT;
Christopher Fauletd2236cd2020-04-06 18:29:14 +0200536 if (curpx->http_needed)
537 curpx->to_log |= LW_REQ;
Willy Tarreauc8368452012-12-21 00:09:23 +0100538 LIST_ADDQ(list_format, &node->list);
Thierry FOURNIER / OZON.IOa2c38d72016-11-22 23:11:21 +0100539 return 1;
Dragan Dosen61302da2019-04-30 00:40:02 +0200540
541 error_free:
542 release_sample_expr(expr);
543 if (node) {
544 free(node->arg);
545 free(node);
546 }
547 return 0;
Willy Tarreauc8368452012-12-21 00:09:23 +0100548}
549
550/*
William Lallemand723b73a2012-02-08 16:37:49 +0100551 * Parse the log_format string and fill a linked list.
552 * Variable name are preceded by % and composed by characters [a-zA-Z0-9]* : %varname
Willy Tarreaua4312fa2013-04-02 16:34:32 +0200553 * You can set arguments using { } : %{many arguments}varname.
554 * The curproxy->conf.args.ctx must be set by the caller.
William Lallemand1d705562012-03-12 12:46:41 +0100555 *
Ilya Shipitsinae40dbc2020-04-04 12:59:53 +0500556 * fmt: the string to parse
William Lallemand1d705562012-03-12 12:46:41 +0100557 * curproxy: the proxy affected
558 * list_format: the destination list
Willy Tarreau6cbbdbf2013-02-05 18:52:25 +0100559 * options: LOG_OPT_* to force on every node
Willy Tarreau434c57c2013-01-08 01:10:24 +0100560 * cap: all SMP_VAL_* flags supported by the consumer
Thierry FOURNIER / OZON.IOa2c38d72016-11-22 23:11:21 +0100561 *
Thierry FOURNIER / OZON.IO8a4e4422016-11-23 00:41:28 +0100562 * The function returns 1 in success case, otherwise, it returns 0 and err is filled.
William Lallemand723b73a2012-02-08 16:37:49 +0100563 */
Thierry FOURNIER / OZON.IO8a4e4422016-11-23 00:41:28 +0100564int 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 +0100565{
Willy Tarreaub83bc1e2012-12-24 12:36:33 +0100566 char *sp, *str, *backfmt; /* start pointer for text parts */
Willy Tarreau8a3f52f2012-12-20 21:23:42 +0100567 char *arg = NULL; /* start pointer for args */
568 char *var = NULL; /* start pointer for vars */
569 int arg_len = 0;
570 int var_len = 0;
571 int cformat; /* current token format */
572 int pformat; /* previous token format */
William Lallemand723b73a2012-02-08 16:37:49 +0100573 struct logformat_node *tmplf, *back;
574
Willy Tarreaub83bc1e2012-12-24 12:36:33 +0100575 sp = str = backfmt = strdup(fmt);
Thierry FOURNIER / OZON.IO9cbfef22016-11-22 23:24:10 +0100576 if (!str) {
Thierry FOURNIER / OZON.IO8a4e4422016-11-23 00:41:28 +0100577 memprintf(err, "out of memory error");
Thierry FOURNIER / OZON.IO9cbfef22016-11-22 23:24:10 +0100578 return 0;
579 }
William Lallemand1dc00ef2012-08-09 16:41:35 +0200580 curproxy->to_log |= LW_INIT;
William Lallemand5e19a282012-04-02 16:22:10 +0200581
William Lallemand723b73a2012-02-08 16:37:49 +0100582 /* flush the list first. */
William Lallemand1d705562012-03-12 12:46:41 +0100583 list_for_each_entry_safe(tmplf, back, list_format, list) {
William Lallemand723b73a2012-02-08 16:37:49 +0100584 LIST_DEL(&tmplf->list);
Dragan Dosen61302da2019-04-30 00:40:02 +0200585 release_sample_expr(tmplf->expr);
586 free(tmplf->arg);
William Lallemand723b73a2012-02-08 16:37:49 +0100587 free(tmplf);
588 }
589
Willy Tarreau8a3f52f2012-12-20 21:23:42 +0100590 for (cformat = LF_INIT; cformat != LF_END; str++) {
William Lallemand723b73a2012-02-08 16:37:49 +0100591 pformat = cformat;
592
Willy Tarreau8a3f52f2012-12-20 21:23:42 +0100593 if (!*str)
594 cformat = LF_END; // preset it to save all states from doing this
William Lallemand723b73a2012-02-08 16:37:49 +0100595
Joseph Herlant85b40592018-11-15 12:10:04 -0800596 /* The principle of the two-step state machine below is to first detect a change, and
Willy Tarreau8a3f52f2012-12-20 21:23:42 +0100597 * second have all common paths processed at one place. The common paths are the ones
598 * encountered in text areas (LF_INIT, LF_TEXT, LF_SEPARATOR) and at the end (LF_END).
599 * We use the common LF_INIT state to dispatch to the different final states.
600 */
601 switch (pformat) {
602 case LF_STARTVAR: // text immediately following a '%'
Willy Tarreauc8368452012-12-21 00:09:23 +0100603 arg = NULL; var = NULL;
Willy Tarreau8a3f52f2012-12-20 21:23:42 +0100604 arg_len = var_len = 0;
605 if (*str == '{') { // optional argument
606 cformat = LF_STARG;
607 arg = str + 1;
William Lallemand723b73a2012-02-08 16:37:49 +0100608 }
Willy Tarreauc8368452012-12-21 00:09:23 +0100609 else if (*str == '[') {
610 cformat = LF_STEXPR;
611 var = str + 1; // store expr in variable name
612 }
Willy Tarreau0f28f822013-12-16 01:38:33 +0100613 else if (isalpha((unsigned char)*str)) { // variable name
William Lallemand723b73a2012-02-08 16:37:49 +0100614 cformat = LF_VAR;
Willy Tarreau8a3f52f2012-12-20 21:23:42 +0100615 var = str;
William Lallemand723b73a2012-02-08 16:37:49 +0100616 }
Willy Tarreau8a3f52f2012-12-20 21:23:42 +0100617 else if (*str == '%')
Ilya Shipitsin856aabc2020-04-16 23:51:34 +0500618 cformat = LF_TEXT; // convert this character to a literal (useful for '%')
Willy Tarreau0f28f822013-12-16 01:38:33 +0100619 else if (isdigit((unsigned char)*str) || *str == ' ' || *str == '\t') {
Willy Tarreau06d97f92013-12-02 17:45:48 +0100620 /* single '%' followed by blank or digit, send them both */
621 cformat = LF_TEXT;
622 pformat = LF_TEXT; /* finally we include the previous char as well */
623 sp = str - 1; /* send both the '%' and the current char */
Jim Freemana2278c82017-04-15 08:01:59 -0600624 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 +0100625 *str, (int)(str - backfmt), fmt);
Willy Tarreau51013e82019-12-11 12:05:39 +0100626 goto fail;
Willy Tarreau06d97f92013-12-02 17:45:48 +0100627
628 }
Willy Tarreau8a3f52f2012-12-20 21:23:42 +0100629 else
Ilya Shipitsin856aabc2020-04-16 23:51:34 +0500630 cformat = LF_INIT; // handle other cases of literals
Willy Tarreau8a3f52f2012-12-20 21:23:42 +0100631 break;
632
633 case LF_STARG: // text immediately following '%{'
634 if (*str == '}') { // end of arg
William Lallemand723b73a2012-02-08 16:37:49 +0100635 cformat = LF_EDARG;
Willy Tarreau8a3f52f2012-12-20 21:23:42 +0100636 arg_len = str - arg;
637 *str = 0; // used for reporting errors
William Lallemand723b73a2012-02-08 16:37:49 +0100638 }
Willy Tarreau8a3f52f2012-12-20 21:23:42 +0100639 break;
640
641 case LF_EDARG: // text immediately following '%{arg}'
Willy Tarreauc8368452012-12-21 00:09:23 +0100642 if (*str == '[') {
643 cformat = LF_STEXPR;
644 var = str + 1; // store expr in variable name
645 break;
646 }
Willy Tarreau0f28f822013-12-16 01:38:33 +0100647 else if (isalnum((unsigned char)*str)) { // variable name
William Lallemand723b73a2012-02-08 16:37:49 +0100648 cformat = LF_VAR;
Willy Tarreau8a3f52f2012-12-20 21:23:42 +0100649 var = str;
650 break;
651 }
Thierry FOURNIER / OZON.IO8a4e4422016-11-23 00:41:28 +0100652 memprintf(err, "parse argument modifier without variable name near '%%{%s}'", arg);
Willy Tarreau51013e82019-12-11 12:05:39 +0100653 goto fail;
Willy Tarreau8a3f52f2012-12-20 21:23:42 +0100654
Willy Tarreauc8368452012-12-21 00:09:23 +0100655 case LF_STEXPR: // text immediately following '%['
Willy Tarreaucd0d2ed2020-02-14 17:33:06 +0100656 /* the whole sample expression is parsed at once,
657 * returning the pointer to the first character not
658 * part of the expression, which MUST be the trailing
659 * angle bracket.
660 */
661 if (!add_sample_to_logformat_list(var, arg, arg_len, curproxy, list_format, options, cap, err, &str))
662 goto fail;
663
664 if (*str == ']') {
665 // end of arg, go on with next state
666 cformat = pformat = LF_EDEXPR;
667 sp = str;
668 }
669 else {
670 char c = *str;
671 *str = 0;
Willy Tarreau90807112020-02-25 08:16:33 +0100672 if (isprint((unsigned char)c))
Willy Tarreaucd0d2ed2020-02-14 17:33:06 +0100673 memprintf(err, "expected ']' after '%s', but found '%c'", var, c);
674 else
675 memprintf(err, "missing ']' after '%s'", var);
Willy Tarreauc8368452012-12-21 00:09:23 +0100676 }
677 break;
678
Willy Tarreau8a3f52f2012-12-20 21:23:42 +0100679 case LF_VAR: // text part of a variable name
680 var_len = str - var;
Willy Tarreau0f28f822013-12-16 01:38:33 +0100681 if (!isalnum((unsigned char)*str))
Willy Tarreau8a3f52f2012-12-20 21:23:42 +0100682 cformat = LF_INIT; // not variable name anymore
683 break;
684
Willy Tarreauc8368452012-12-21 00:09:23 +0100685 default: // LF_INIT, LF_TEXT, LF_SEPARATOR, LF_END, LF_EDEXPR
Willy Tarreau8a3f52f2012-12-20 21:23:42 +0100686 cformat = LF_INIT;
687 }
688
689 if (cformat == LF_INIT) { /* resynchronize state to text/sep/startvar */
690 switch (*str) {
691 case '%': cformat = LF_STARTVAR; break;
692 case ' ': cformat = LF_SEPARATOR; break;
693 case 0 : cformat = LF_END; break;
694 default : cformat = LF_TEXT; break;
William Lallemand723b73a2012-02-08 16:37:49 +0100695 }
696 }
697
Willy Tarreau8a3f52f2012-12-20 21:23:42 +0100698 if (cformat != pformat || pformat == LF_SEPARATOR) {
699 switch (pformat) {
700 case LF_VAR:
Thierry FOURNIER / OZON.IO8a4e4422016-11-23 00:41:28 +0100701 if (!parse_logformat_var(arg, arg_len, var, var_len, curproxy, list_format, &options, err))
Willy Tarreau51013e82019-12-11 12:05:39 +0100702 goto fail;
Willy Tarreau8a3f52f2012-12-20 21:23:42 +0100703 break;
Willy Tarreauc8368452012-12-21 00:09:23 +0100704 case LF_STEXPR:
Willy Tarreaucd0d2ed2020-02-14 17:33:06 +0100705 if (!add_sample_to_logformat_list(var, arg, arg_len, curproxy, list_format, options, cap, err, &sp))
Willy Tarreau51013e82019-12-11 12:05:39 +0100706 goto fail;
Willy Tarreauc8368452012-12-21 00:09:23 +0100707 break;
Willy Tarreau8a3f52f2012-12-20 21:23:42 +0100708 case LF_TEXT:
709 case LF_SEPARATOR:
Thierry FOURNIER / OZON.IO8a4e4422016-11-23 00:41:28 +0100710 if (!add_to_logformat_list(sp, str, pformat, list_format, err))
Willy Tarreau51013e82019-12-11 12:05:39 +0100711 goto fail;
Willy Tarreau8a3f52f2012-12-20 21:23:42 +0100712 break;
713 }
714 sp = str; /* new start of text at every state switch and at every separator */
William Lallemand723b73a2012-02-08 16:37:49 +0100715 }
716 }
Willy Tarreau8a3f52f2012-12-20 21:23:42 +0100717
Thierry FOURNIER / OZON.IOa2c38d72016-11-22 23:11:21 +0100718 if (pformat == LF_STARTVAR || pformat == LF_STARG || pformat == LF_STEXPR) {
Thierry FOURNIER / OZON.IO8a4e4422016-11-23 00:41:28 +0100719 memprintf(err, "truncated line after '%s'", var ? var : arg ? arg : "%");
Willy Tarreau51013e82019-12-11 12:05:39 +0100720 goto fail;
Thierry FOURNIER / OZON.IOa2c38d72016-11-22 23:11:21 +0100721 }
Willy Tarreaub83bc1e2012-12-24 12:36:33 +0100722 free(backfmt);
Thierry FOURNIER / OZON.IOa2c38d72016-11-22 23:11:21 +0100723
724 return 1;
Willy Tarreau51013e82019-12-11 12:05:39 +0100725 fail:
726 free(backfmt);
727 return 0;
William Lallemand723b73a2012-02-08 16:37:49 +0100728}
729
Christopher Faulet4b0b79d2018-03-26 15:54:32 +0200730/*
Ilya Shipitsin856aabc2020-04-16 23:51:34 +0500731 * Parse the first range of indexes from a string made of a list of comma separated
Frédéric Lécailled95ea282019-04-24 16:14:33 +0200732 * ranges of indexes. Note that an index may be considered as a particular range
733 * with a high limit to the low limit.
734 */
735int get_logsrv_smp_range(unsigned int *low, unsigned int *high, char **arg, char **err)
736{
737 char *end, *p;
738
739 *low = *high = 0;
740
741 p = *arg;
742 end = strchr(p, ',');
743 if (!end)
744 end = p + strlen(p);
745
746 *high = *low = read_uint((const char **)&p, end);
747 if (!*low || (p != end && *p != '-'))
748 goto err;
749
750 if (p == end)
751 goto done;
752
753 p++;
754 *high = read_uint((const char **)&p, end);
755 if (!*high || *high <= *low || p != end)
756 goto err;
757
758 done:
759 if (*end == ',')
760 end++;
761 *arg = end;
762 return 1;
763
764 err:
765 memprintf(err, "wrong sample range '%s'", *arg);
766 return 0;
767}
768
769/*
770 * Returns 1 if the range defined by <low> and <high> overlaps
771 * one of them in <rgs> array of ranges with <sz> the size of this
772 * array, 0 if not.
773 */
774int smp_log_ranges_overlap(struct smp_log_range *rgs, size_t sz,
775 unsigned int low, unsigned int high, char **err)
776{
777 size_t i;
778
779 for (i = 0; i < sz; i++) {
780 if ((low >= rgs[i].low && low <= rgs[i].high) ||
781 (high >= rgs[i].low && high <= rgs[i].high)) {
782 memprintf(err, "ranges are overlapping");
783 return 1;
784 }
785 }
786
787 return 0;
788}
789
790int smp_log_range_cmp(const void *a, const void *b)
791{
792 const struct smp_log_range *rg_a = a;
793 const struct smp_log_range *rg_b = b;
794
795 if (rg_a->high < rg_b->low)
796 return -1;
797 else if (rg_a->low > rg_b->high)
798 return 1;
799
800 return 0;
801}
802
803/*
Christopher Faulet4b0b79d2018-03-26 15:54:32 +0200804 * Parse "log" keyword and update <logsrvs> list accordingly.
805 *
806 * When <do_del> is set, it means the "no log" line was parsed, so all log
807 * servers in <logsrvs> are released.
808 *
809 * Otherwise, we try to parse the "log" line. First of all, when the list is not
810 * the global one, we look for the parameter "global". If we find it,
811 * global.logsrvs is copied. Else we parse each arguments.
812 *
813 * The function returns 1 in success case, otherwise, it returns 0 and err is
814 * filled.
815 */
816int parse_logsrv(char **args, struct list *logsrvs, int do_del, char **err)
817{
818 struct sockaddr_storage *sk;
819 struct logsrv *logsrv = NULL;
820 int port1, port2;
821 int cur_arg;
822
823 /*
824 * "no log": delete previous herited or defined syslog
825 * servers.
826 */
827 if (do_del) {
828 struct logsrv *back;
829
830 if (*(args[1]) != 0) {
831 memprintf(err, "'no log' does not expect arguments");
832 goto error;
833 }
834
835 list_for_each_entry_safe(logsrv, back, logsrvs, list) {
836 LIST_DEL(&logsrv->list);
837 free(logsrv);
838 }
839 return 1;
840 }
841
842 /*
843 * "log global": copy global.logrsvs linked list to the end of logsrvs
844 * list. But first, we check (logsrvs != global.logsrvs).
845 */
846 if (*(args[1]) && *(args[2]) == 0 && !strcmp(args[1], "global")) {
847 if (logsrvs == &global.logsrvs) {
848 memprintf(err, "'global' is not supported for a global syslog server");
849 goto error;
850 }
851 list_for_each_entry(logsrv, &global.logsrvs, list) {
Christopher Faulet28ac0992018-03-26 16:09:19 +0200852 struct logsrv *node;
853
854 list_for_each_entry(node, logsrvs, list) {
855 if (node->ref == logsrv)
856 goto skip_logsrv;
857 }
858
859 node = malloc(sizeof(*node));
Christopher Faulet4b0b79d2018-03-26 15:54:32 +0200860 memcpy(node, logsrv, sizeof(struct logsrv));
Christopher Faulet28ac0992018-03-26 16:09:19 +0200861 node->ref = logsrv;
Christopher Faulet4b0b79d2018-03-26 15:54:32 +0200862 LIST_INIT(&node->list);
863 LIST_ADDQ(logsrvs, &node->list);
Christopher Faulet28ac0992018-03-26 16:09:19 +0200864
865 skip_logsrv:
866 continue;
Christopher Faulet4b0b79d2018-03-26 15:54:32 +0200867 }
868 return 1;
869 }
870
871 /*
872 * "log <address> ...: parse a syslog server line
873 */
874 if (*(args[1]) == 0 || *(args[2]) == 0) {
875 memprintf(err, "expects <address> and <facility> %s as arguments",
876 ((logsrvs == &global.logsrvs) ? "" : "or global"));
877 goto error;
878 }
879
Willy Tarreau5a32ecc2018-11-12 07:34:59 +0100880 /* take care of "stdout" and "stderr" as regular aliases for fd@1 / fd@2 */
881 if (strcmp(args[1], "stdout") == 0)
882 args[1] = "fd@1";
883 else if (strcmp(args[1], "stderr") == 0)
884 args[1] = "fd@2";
885
Christopher Faulet4b0b79d2018-03-26 15:54:32 +0200886 logsrv = calloc(1, sizeof(*logsrv));
887 if (!logsrv) {
888 memprintf(err, "out of memory");
889 goto error;
890 }
891
892 /* skip address for now, it will be parsed at the end */
893 cur_arg = 2;
894
895 /* just after the address, a length may be specified */
896 logsrv->maxlen = MAX_SYSLOG_LEN;
897 if (strcmp(args[cur_arg], "len") == 0) {
898 int len = atoi(args[cur_arg+1]);
899 if (len < 80 || len > 65535) {
900 memprintf(err, "invalid log length '%s', must be between 80 and 65535",
901 args[cur_arg+1]);
902 goto error;
903 }
904 logsrv->maxlen = len;
905 cur_arg += 2;
906 }
907 if (logsrv->maxlen > global.max_syslog_len)
908 global.max_syslog_len = logsrv->maxlen;
909
910 /* after the length, a format may be specified */
911 if (strcmp(args[cur_arg], "format") == 0) {
912 logsrv->format = get_log_format(args[cur_arg+1]);
913 if (logsrv->format < 0) {
914 memprintf(err, "unknown log format '%s'", args[cur_arg+1]);
915 goto error;
916 }
917 cur_arg += 2;
918 }
919
Frédéric Lécailled95ea282019-04-24 16:14:33 +0200920 if (strcmp(args[cur_arg], "sample") == 0) {
921 unsigned low, high;
922 char *p, *beg, *end, *smp_sz_str;
923 struct smp_log_range *smp_rgs = NULL;
924 size_t smp_rgs_sz = 0, smp_sz = 0, new_smp_sz;
925
926 p = args[cur_arg+1];
927 smp_sz_str = strchr(p, ':');
928 if (!smp_sz_str) {
929 memprintf(err, "Missing sample size");
930 goto error;
931 }
932
933 *smp_sz_str++ = '\0';
934
935 end = p + strlen(p);
936
937 while (p != end) {
938 if (!get_logsrv_smp_range(&low, &high, &p, err))
939 goto error;
940
941 if (smp_rgs && smp_log_ranges_overlap(smp_rgs, smp_rgs_sz, low, high, err))
942 goto error;
943
944 smp_rgs = my_realloc2(smp_rgs, (smp_rgs_sz + 1) * sizeof *smp_rgs);
945 if (!smp_rgs) {
946 memprintf(err, "out of memory error");
947 goto error;
948 }
949
950 smp_rgs[smp_rgs_sz].low = low;
951 smp_rgs[smp_rgs_sz].high = high;
952 smp_rgs[smp_rgs_sz].sz = high - low + 1;
953 smp_rgs[smp_rgs_sz].curr_idx = 0;
954 if (smp_rgs[smp_rgs_sz].high > smp_sz)
955 smp_sz = smp_rgs[smp_rgs_sz].high;
956 smp_rgs_sz++;
957 }
958
Tim Duesterhus21648002019-06-23 22:10:10 +0200959 if (smp_rgs == NULL) {
960 memprintf(err, "no sampling ranges given");
961 goto error;
962 }
963
Frédéric Lécailled95ea282019-04-24 16:14:33 +0200964 beg = smp_sz_str;
965 end = beg + strlen(beg);
966 new_smp_sz = read_uint((const char **)&beg, end);
967 if (!new_smp_sz || beg != end) {
968 memprintf(err, "wrong sample size '%s' for sample range '%s'",
969 smp_sz_str, args[cur_arg+1]);
970 goto error;
971 }
972
973 if (new_smp_sz < smp_sz) {
974 memprintf(err, "sample size %zu should be greater or equal to "
975 "%zu the maximum of the high ranges limits",
976 new_smp_sz, smp_sz);
977 goto error;
978 }
979 smp_sz = new_smp_sz;
980
981 /* Let's order <smp_rgs> array. */
982 qsort(smp_rgs, smp_rgs_sz, sizeof(struct smp_log_range), smp_log_range_cmp);
983
984 logsrv->lb.smp_rgs = smp_rgs;
985 logsrv->lb.smp_rgs_sz = smp_rgs_sz;
986 logsrv->lb.smp_sz = smp_sz;
987
988 cur_arg += 2;
989 }
Frédéric Lécailled803e472019-04-25 07:42:09 +0200990 HA_SPIN_INIT(&logsrv->lock);
Christopher Faulet4b0b79d2018-03-26 15:54:32 +0200991 /* parse the facility */
992 logsrv->facility = get_log_facility(args[cur_arg]);
993 if (logsrv->facility < 0) {
994 memprintf(err, "unknown log facility '%s'", args[cur_arg]);
995 goto error;
996 }
997 cur_arg++;
998
999 /* parse the max syslog level (default: debug) */
1000 logsrv->level = 7;
1001 if (*(args[cur_arg])) {
1002 logsrv->level = get_log_level(args[cur_arg]);
1003 if (logsrv->level < 0) {
1004 memprintf(err, "unknown optional log level '%s'", args[cur_arg]);
1005 goto error;
1006 }
1007 cur_arg++;
1008 }
1009
1010 /* parse the limit syslog level (default: emerg) */
1011 logsrv->minlvl = 0;
1012 if (*(args[cur_arg])) {
1013 logsrv->minlvl = get_log_level(args[cur_arg]);
1014 if (logsrv->minlvl < 0) {
1015 memprintf(err, "unknown optional minimum log level '%s'", args[cur_arg]);
1016 goto error;
1017 }
1018 cur_arg++;
1019 }
1020
1021 /* Too many args */
1022 if (*(args[cur_arg])) {
1023 memprintf(err, "cannot handle unexpected argument '%s'", args[cur_arg]);
1024 goto error;
1025 }
1026
1027 /* now, back to the address */
Willy Tarreauf3dc30f2019-08-30 14:18:44 +02001028 logsrv->type = LOG_TARGET_DGRAM;
Willy Tarreauc046d162019-08-30 15:24:59 +02001029 if (strncmp(args[1], "ring@", 5) == 0) {
1030 struct sink *sink = sink_find(args[1] + 5);
1031
1032 if (!sink || sink->type != SINK_TYPE_BUFFER) {
1033 memprintf(err, "cannot find ring buffer '%s'", args[1] + 5);
1034 goto error;
1035 }
1036
1037 logsrv->addr.ss_family = AF_UNSPEC;
1038 logsrv->type = LOG_TARGET_BUFFER;
1039 logsrv->ring = sink->ctx.ring;
1040 goto done;
1041 }
1042
Willy Tarreauf3dc30f2019-08-30 14:18:44 +02001043 if (strncmp(args[1], "fd@", 3) == 0)
1044 logsrv->type = LOG_TARGET_FD;
1045
Christopher Faulet4b0b79d2018-03-26 15:54:32 +02001046 sk = str2sa_range(args[1], NULL, &port1, &port2, err, NULL, NULL, 1);
1047 if (!sk)
1048 goto error;
1049 logsrv->addr = *sk;
1050
1051 if (sk->ss_family == AF_INET || sk->ss_family == AF_INET6) {
1052 if (port1 != port2) {
1053 memprintf(err, "port ranges and offsets are not allowed in '%s'", args[1]);
1054 goto error;
1055 }
1056 logsrv->addr = *sk;
1057 if (!port1)
1058 set_host_port(&logsrv->addr, SYSLOG_PORT);
1059 }
Willy Tarreauc046d162019-08-30 15:24:59 +02001060 done:
Christopher Faulet4b0b79d2018-03-26 15:54:32 +02001061 LIST_ADDQ(logsrvs, &logsrv->list);
1062 return 1;
1063
1064 error:
1065 free(logsrv);
1066 return 0;
1067}
1068
1069
Christopher Fauletd4696382017-10-24 11:44:05 +02001070/* Generic function to display messages prefixed by a label */
1071static void print_message(const char *label, const char *fmt, va_list argp)
1072{
1073 struct tm tm;
1074 char *head, *msg;
1075
1076 head = msg = NULL;
1077
1078 get_localtime(date.tv_sec, &tm);
1079 memprintf(&head, "[%s] %03d/%02d%02d%02d (%d) : ",
1080 label, tm.tm_yday, tm.tm_hour, tm.tm_min, tm.tm_sec, (int)getpid());
1081 memvprintf(&msg, fmt, argp);
1082
Willy Tarreau869efd52019-11-15 15:16:57 +01001083 if (global.mode & MODE_STARTING) {
1084 if (unlikely(!startup_logs))
1085 startup_logs = ring_new(STARTUP_LOG_SIZE);
1086
1087 if (likely(startup_logs)) {
1088 struct ist m[2];
1089
1090 m[0] = ist(head);
1091 m[1] = ist(msg);
1092 /* trim the trailing '\n' */
1093 if (m[1].len > 0 && m[1].ptr[m[1].len - 1] == '\n')
1094 m[1].len--;
1095 ring_write(startup_logs, ~0, 0, 0, m, 2);
1096 }
1097 }
Christopher Fauletd4696382017-10-24 11:44:05 +02001098
1099 fprintf(stderr, "%s%s", head, msg);
1100 fflush(stderr);
1101
1102 free(head);
1103 free(msg);
1104}
1105
Willy Tarreaubaaee002006-06-26 02:48:02 +02001106/*
1107 * Displays the message on stderr with the date and pid. Overrides the quiet
1108 * mode during startup.
1109 */
Christopher Faulet767a84b2017-11-24 16:50:31 +01001110void ha_alert(const char *fmt, ...)
Willy Tarreaubaaee002006-06-26 02:48:02 +02001111{
1112 va_list argp;
Willy Tarreaubaaee002006-06-26 02:48:02 +02001113
1114 if (!(global.mode & MODE_QUIET) || (global.mode & (MODE_VERBOSE | MODE_STARTING))) {
Willy Tarreaubb869862020-04-16 10:52:41 +02001115 if (!(warned & WARN_EXEC_PATH)) {
1116 const char *path = get_exec_path();
1117
1118 warned |= WARN_EXEC_PATH;
1119 ha_notice("haproxy version is %s\n", haproxy_version);
1120 if (path)
1121 ha_notice("path to executable is %s\n", path);
1122 }
Willy Tarreaubaaee002006-06-26 02:48:02 +02001123 va_start(argp, fmt);
Christopher Fauletd4696382017-10-24 11:44:05 +02001124 print_message("ALERT", fmt, argp);
Willy Tarreaubaaee002006-06-26 02:48:02 +02001125 va_end(argp);
1126 }
1127}
1128
1129
1130/*
1131 * Displays the message on stderr with the date and pid.
1132 */
Christopher Faulet767a84b2017-11-24 16:50:31 +01001133void ha_warning(const char *fmt, ...)
Willy Tarreaubaaee002006-06-26 02:48:02 +02001134{
1135 va_list argp;
Willy Tarreaubaaee002006-06-26 02:48:02 +02001136
Willy Tarreaubebd2122020-04-15 16:06:11 +02001137 warned |= WARN_ANY;
1138
Willy Tarreaubaaee002006-06-26 02:48:02 +02001139 if (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE)) {
1140 va_start(argp, fmt);
Christopher Fauletd4696382017-10-24 11:44:05 +02001141 print_message("WARNING", fmt, argp);
Willy Tarreaubaaee002006-06-26 02:48:02 +02001142 va_end(argp);
1143 }
1144}
1145
1146/*
William Lallemand9c56a222018-11-21 18:04:52 +01001147 * Displays the message on stderr with the date and pid.
1148 */
1149void ha_notice(const char *fmt, ...)
1150{
1151 va_list argp;
1152
1153 if (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE)) {
1154 va_start(argp, fmt);
1155 print_message("NOTICE", fmt, argp);
1156 va_end(argp);
1157 }
1158}
1159
1160/*
Willy Tarreaubaaee002006-06-26 02:48:02 +02001161 * Displays the message on <out> only if quiet mode is not set.
1162 */
Willy Tarreaub17916e2006-10-15 15:17:57 +02001163void qfprintf(FILE *out, const char *fmt, ...)
Willy Tarreaubaaee002006-06-26 02:48:02 +02001164{
1165 va_list argp;
1166
1167 if (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE)) {
1168 va_start(argp, fmt);
1169 vfprintf(out, fmt, argp);
1170 fflush(out);
1171 va_end(argp);
1172 }
1173}
1174
1175/*
Dragan Dosen1322d092015-09-22 16:05:32 +02001176 * returns log format for <fmt> or -1 if not found.
1177 */
1178int get_log_format(const char *fmt)
1179{
1180 int format;
1181
1182 format = LOG_FORMATS - 1;
Dragan Dosen43885c72015-10-01 13:18:13 +02001183 while (format >= 0 && strcmp(log_formats[format].name, fmt))
Dragan Dosen1322d092015-09-22 16:05:32 +02001184 format--;
1185
1186 return format;
1187}
1188
1189/*
Willy Tarreaubaaee002006-06-26 02:48:02 +02001190 * returns log level for <lev> or -1 if not found.
1191 */
1192int get_log_level(const char *lev)
1193{
1194 int level;
1195
1196 level = NB_LOG_LEVELS - 1;
1197 while (level >= 0 && strcmp(log_levels[level], lev))
1198 level--;
1199
1200 return level;
1201}
1202
Willy Tarreaubaaee002006-06-26 02:48:02 +02001203/*
1204 * returns log facility for <fac> or -1 if not found.
1205 */
1206int get_log_facility(const char *fac)
1207{
1208 int facility;
1209
1210 facility = NB_LOG_FACILITIES - 1;
1211 while (facility >= 0 && strcmp(log_facilities[facility], fac))
1212 facility--;
William Lallemand2a4a44f2012-02-06 16:00:33 +01001213
Willy Tarreaubaaee002006-06-26 02:48:02 +02001214 return facility;
1215}
1216
William Lallemanda1cc3812012-02-08 16:38:44 +01001217/*
Dragan Dosen835b9212016-02-12 13:23:03 +01001218 * Encode the string.
1219 *
1220 * When using the +E log format option, it will try to escape '"\]'
1221 * characters with '\' as prefix. The same prefix should not be used as
1222 * <escape>.
1223 */
1224static char *lf_encode_string(char *start, char *stop,
Willy Tarreau1bfd6022019-06-07 11:10:07 +02001225 const char escape, const long *map,
Dragan Dosen835b9212016-02-12 13:23:03 +01001226 const char *string,
1227 struct logformat_node *node)
1228{
1229 if (node->options & LOG_OPT_ESC) {
1230 if (start < stop) {
1231 stop--; /* reserve one byte for the final '\0' */
1232 while (start < stop && *string != '\0') {
Willy Tarreau1bfd6022019-06-07 11:10:07 +02001233 if (!ha_bit_test((unsigned char)(*string), map)) {
1234 if (!ha_bit_test((unsigned char)(*string), rfc5424_escape_map))
Dragan Dosen835b9212016-02-12 13:23:03 +01001235 *start++ = *string;
1236 else {
1237 if (start + 2 >= stop)
1238 break;
1239 *start++ = '\\';
1240 *start++ = *string;
1241 }
1242 }
1243 else {
1244 if (start + 3 >= stop)
1245 break;
1246 *start++ = escape;
1247 *start++ = hextab[(*string >> 4) & 15];
1248 *start++ = hextab[*string & 15];
1249 }
1250 string++;
1251 }
1252 *start = '\0';
1253 }
1254 }
1255 else {
1256 return encode_string(start, stop, escape, map, string);
1257 }
1258
1259 return start;
1260}
1261
1262/*
1263 * Encode the chunk.
1264 *
1265 * When using the +E log format option, it will try to escape '"\]'
1266 * characters with '\' as prefix. The same prefix should not be used as
1267 * <escape>.
1268 */
1269static char *lf_encode_chunk(char *start, char *stop,
Willy Tarreau1bfd6022019-06-07 11:10:07 +02001270 const char escape, const long *map,
Willy Tarreau83061a82018-07-13 11:56:34 +02001271 const struct buffer *chunk,
Dragan Dosen835b9212016-02-12 13:23:03 +01001272 struct logformat_node *node)
1273{
1274 char *str, *end;
1275
1276 if (node->options & LOG_OPT_ESC) {
1277 if (start < stop) {
Willy Tarreau843b7cb2018-07-13 10:54:26 +02001278 str = chunk->area;
1279 end = chunk->area + chunk->data;
Dragan Dosen835b9212016-02-12 13:23:03 +01001280
1281 stop--; /* reserve one byte for the final '\0' */
1282 while (start < stop && str < end) {
Willy Tarreau1bfd6022019-06-07 11:10:07 +02001283 if (!ha_bit_test((unsigned char)(*str), map)) {
1284 if (!ha_bit_test((unsigned char)(*str), rfc5424_escape_map))
Dragan Dosen835b9212016-02-12 13:23:03 +01001285 *start++ = *str;
1286 else {
1287 if (start + 2 >= stop)
1288 break;
1289 *start++ = '\\';
1290 *start++ = *str;
1291 }
1292 }
1293 else {
1294 if (start + 3 >= stop)
1295 break;
1296 *start++ = escape;
1297 *start++ = hextab[(*str >> 4) & 15];
1298 *start++ = hextab[*str & 15];
1299 }
1300 str++;
1301 }
1302 *start = '\0';
1303 }
1304 }
1305 else {
1306 return encode_chunk(start, stop, escape, map, chunk);
1307 }
1308
1309 return start;
1310}
1311
1312/*
William Lallemanda1cc3812012-02-08 16:38:44 +01001313 * Write a string in the log string
Dragan Dosen835b9212016-02-12 13:23:03 +01001314 * Take cares of quote and escape options
William Lallemanda1cc3812012-02-08 16:38:44 +01001315 *
Joseph Herlant85b40592018-11-15 12:10:04 -08001316 * Return the address of the \0 character, or NULL on error
William Lallemanda1cc3812012-02-08 16:38:44 +01001317 */
Willy Tarreau26ffa852018-09-05 15:23:10 +02001318char *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 +01001319{
Willy Tarreau2b0108a2012-12-21 19:23:44 +01001320 if (size < 2)
1321 return NULL;
William Lallemanda1cc3812012-02-08 16:38:44 +01001322
Willy Tarreau2b0108a2012-12-21 19:23:44 +01001323 if (node->options & LOG_OPT_QUOTE) {
1324 *(dst++) = '"';
1325 size--;
William Lallemandbddd4fd2012-02-27 11:23:10 +01001326 }
Willy Tarreau2b0108a2012-12-21 19:23:44 +01001327
Willy Tarreau6cbbdbf2013-02-05 18:52:25 +01001328 if (src && len) {
Dragan Dosendb1b6f92016-07-25 11:35:02 +02001329 if (++len > size)
1330 len = size;
Dragan Dosen835b9212016-02-12 13:23:03 +01001331 if (node->options & LOG_OPT_ESC) {
Dragan Dosen835b9212016-02-12 13:23:03 +01001332 char *ret;
1333
Dragan Dosendb1b6f92016-07-25 11:35:02 +02001334 ret = escape_string(dst, dst + len, '\\', rfc5424_escape_map, src);
Dragan Dosen835b9212016-02-12 13:23:03 +01001335 if (ret == NULL || *ret != '\0')
1336 return NULL;
1337 len = ret - dst;
1338 }
1339 else {
Dragan Dosen835b9212016-02-12 13:23:03 +01001340 len = strlcpy2(dst, src, len);
1341 }
Willy Tarreau2b0108a2012-12-21 19:23:44 +01001342
1343 size -= len;
1344 dst += len;
1345 }
Willy Tarreau6cbbdbf2013-02-05 18:52:25 +01001346 else if ((node->options & (LOG_OPT_QUOTE|LOG_OPT_MANDATORY)) == LOG_OPT_MANDATORY) {
1347 if (size < 2)
1348 return NULL;
1349 *(dst++) = '-';
1350 }
Willy Tarreau2b0108a2012-12-21 19:23:44 +01001351
1352 if (node->options & LOG_OPT_QUOTE) {
1353 if (size < 2)
1354 return NULL;
1355 *(dst++) = '"';
1356 }
1357
1358 *dst = '\0';
William Lallemandbddd4fd2012-02-27 11:23:10 +01001359 return dst;
William Lallemanda1cc3812012-02-08 16:38:44 +01001360}
1361
Willy Tarreau26ffa852018-09-05 15:23:10 +02001362static inline char *lf_text(char *dst, const char *src, size_t size, const struct logformat_node *node)
Willy Tarreau2b0108a2012-12-21 19:23:44 +01001363{
1364 return lf_text_len(dst, src, size, size, node);
1365}
1366
William Lallemand5f232402012-04-05 18:02:55 +02001367/*
Joseph Herlant85b40592018-11-15 12:10:04 -08001368 * Write a IP address to the log string
Ilya Shipitsin856aabc2020-04-16 23:51:34 +05001369 * +X option write in hexadecimal notation, most significant byte on the left
William Lallemand5f232402012-04-05 18:02:55 +02001370 */
Willy Tarreau26ffa852018-09-05 15:23:10 +02001371char *lf_ip(char *dst, const struct sockaddr *sockaddr, size_t size, const struct logformat_node *node)
William Lallemand5f232402012-04-05 18:02:55 +02001372{
1373 char *ret = dst;
1374 int iret;
1375 char pn[INET6_ADDRSTRLEN];
1376
1377 if (node->options & LOG_OPT_HEXA) {
Radek Zajic594c4562019-03-22 10:21:54 +00001378 unsigned char *addr = NULL;
1379 switch (sockaddr->sa_family) {
1380 case AF_INET:
1381 addr = (unsigned char *)&((struct sockaddr_in *)sockaddr)->sin_addr.s_addr;
1382 iret = snprintf(dst, size, "%02X%02X%02X%02X", addr[0], addr[1], addr[2], addr[3]);
1383 break;
1384 case AF_INET6:
1385 addr = (unsigned char *)&((struct sockaddr_in6 *)sockaddr)->sin6_addr.s6_addr;
1386 iret = snprintf(dst, size, "%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X",
1387 addr[0], addr[1], addr[2], addr[3], addr[4], addr[5], addr[6], addr[7],
1388 addr[8], addr[9], addr[10], addr[11], addr[12], addr[13], addr[14], addr[15]);
1389 break;
1390 default:
1391 return NULL;
1392 }
William Lallemand5f232402012-04-05 18:02:55 +02001393 if (iret < 0 || iret > size)
1394 return NULL;
1395 ret += iret;
1396 } else {
1397 addr_to_str((struct sockaddr_storage *)sockaddr, pn, sizeof(pn));
1398 ret = lf_text(dst, pn, size, node);
1399 if (ret == NULL)
1400 return NULL;
1401 }
1402 return ret;
1403}
1404
1405/*
1406 * Write a port to the log
Ilya Shipitsin856aabc2020-04-16 23:51:34 +05001407 * +X option write in hexadecimal notation, most significant byte on the left
William Lallemand5f232402012-04-05 18:02:55 +02001408 */
Willy Tarreau26ffa852018-09-05 15:23:10 +02001409char *lf_port(char *dst, const struct sockaddr *sockaddr, size_t size, const struct logformat_node *node)
William Lallemand5f232402012-04-05 18:02:55 +02001410{
1411 char *ret = dst;
1412 int iret;
1413
1414 if (node->options & LOG_OPT_HEXA) {
1415 const unsigned char *port = (const unsigned char *)&((struct sockaddr_in *)sockaddr)->sin_port;
1416 iret = snprintf(dst, size, "%02X%02X", port[0], port[1]);
1417 if (iret < 0 || iret > size)
1418 return NULL;
1419 ret += iret;
1420 } else {
1421 ret = ltoa_o(get_host_port((struct sockaddr_storage *)sockaddr), dst, size);
1422 if (ret == NULL)
1423 return NULL;
1424 }
1425 return ret;
1426}
1427
Dragan Dosen1322d092015-09-22 16:05:32 +02001428/* Re-generate time-based part of the syslog header in RFC3164 format at
1429 * the beginning of logheader once a second and return the pointer to the
1430 * first character after it.
Willy Tarreaub1a2faf2012-03-19 16:51:53 +01001431 */
Dragan Dosen0b85ece2015-09-25 19:17:44 +02001432static char *update_log_hdr(const time_t time)
Willy Tarreaubaaee002006-06-26 02:48:02 +02001433{
Christopher Fauletf8188c62017-06-02 16:20:16 +02001434 static THREAD_LOCAL long tvsec;
Willy Tarreau83061a82018-07-13 11:56:34 +02001435 static THREAD_LOCAL struct buffer host = { };
Christopher Fauletf8188c62017-06-02 16:20:16 +02001436 static THREAD_LOCAL int sep = 0;
Willy Tarreaubaaee002006-06-26 02:48:02 +02001437
Willy Tarreau55e2f5a2019-05-05 10:11:39 +02001438 if (unlikely(time != tvsec || logheader_end == NULL)) {
Willy Tarreaubaaee002006-06-26 02:48:02 +02001439 /* this string is rebuild only once a second */
Willy Tarreaufe944602007-10-25 10:34:16 +02001440 struct tm tm;
Willy Tarreaub1a2faf2012-03-19 16:51:53 +01001441 int hdr_len;
Willy Tarreaufe944602007-10-25 10:34:16 +02001442
Dragan Dosen0b85ece2015-09-25 19:17:44 +02001443 tvsec = time;
Willy Tarreaufe944602007-10-25 10:34:16 +02001444 get_localtime(tvsec, &tm);
Willy Tarreaubaaee002006-06-26 02:48:02 +02001445
Willy Tarreau843b7cb2018-07-13 10:54:26 +02001446 if (unlikely(global.log_send_hostname != host.area)) {
1447 host.area = global.log_send_hostname;
1448 host.data = host.area ? strlen(host.area) : 0;
1449 sep = host.data ? 1 : 0;
Dragan Dosen43885c72015-10-01 13:18:13 +02001450 }
1451
Dragan Dosen59cee972015-09-19 22:09:02 +02001452 hdr_len = snprintf(logheader, global.max_syslog_len,
Dragan Dosen43885c72015-10-01 13:18:13 +02001453 "<<<<>%s %2d %02d:%02d:%02d %.*s%*s",
Willy Tarreaufe944602007-10-25 10:34:16 +02001454 monthname[tm.tm_mon],
Dragan Dosen43885c72015-10-01 13:18:13 +02001455 tm.tm_mday, tm.tm_hour, tm.tm_min, tm.tm_sec,
Willy Tarreau843b7cb2018-07-13 10:54:26 +02001456 (int)host.data, host.area, sep, "");
Willy Tarreaubaaee002006-06-26 02:48:02 +02001457 /* WARNING: depending upon implementations, snprintf may return
1458 * either -1 or the number of bytes that would be needed to store
1459 * the total message. In both cases, we must adjust it.
1460 */
Willy Tarreau18324f52014-06-27 18:10:07 +02001461 if (hdr_len < 0 || hdr_len > global.max_syslog_len)
1462 hdr_len = global.max_syslog_len;
Willy Tarreaubaaee002006-06-26 02:48:02 +02001463
Willy Tarreau55e2f5a2019-05-05 10:11:39 +02001464 logheader_end = logheader + hdr_len;
Willy Tarreaubaaee002006-06-26 02:48:02 +02001465 }
1466
Willy Tarreau55e2f5a2019-05-05 10:11:39 +02001467 logheader_end[0] = 0; // ensure we get rid of any previous attempt
Willy Tarreau094af4e2015-01-07 15:03:42 +01001468
Willy Tarreau55e2f5a2019-05-05 10:11:39 +02001469 return logheader_end;
William Lallemand2a4a44f2012-02-06 16:00:33 +01001470}
1471
Dragan Dosen1322d092015-09-22 16:05:32 +02001472/* Re-generate time-based part of the syslog header in RFC5424 format at
1473 * the beginning of logheader_rfc5424 once a second and return the pointer
1474 * to the first character after it.
1475 */
Dragan Dosen0b85ece2015-09-25 19:17:44 +02001476static char *update_log_hdr_rfc5424(const time_t time)
Dragan Dosen1322d092015-09-22 16:05:32 +02001477{
Christopher Fauletf8188c62017-06-02 16:20:16 +02001478 static THREAD_LOCAL long tvsec;
Benoit GARNIERb413c2a2016-03-27 11:08:03 +02001479 const char *gmt_offset;
Dragan Dosen1322d092015-09-22 16:05:32 +02001480
Willy Tarreau55e2f5a2019-05-05 10:11:39 +02001481 if (unlikely(time != tvsec || logheader_rfc5424_end == NULL)) {
Dragan Dosen1322d092015-09-22 16:05:32 +02001482 /* this string is rebuild only once a second */
1483 struct tm tm;
1484 int hdr_len;
1485
Dragan Dosen0b85ece2015-09-25 19:17:44 +02001486 tvsec = time;
Dragan Dosen1322d092015-09-22 16:05:32 +02001487 get_localtime(tvsec, &tm);
Benoit GARNIERe2e5bde2016-03-27 03:04:16 +02001488 gmt_offset = get_gmt_offset(time, &tm);
Dragan Dosen1322d092015-09-22 16:05:32 +02001489
1490 hdr_len = snprintf(logheader_rfc5424, global.max_syslog_len,
Dragan Dosen17def462015-10-09 21:31:43 +02001491 "<<<<>1 %4d-%02d-%02dT%02d:%02d:%02d%.3s:%.2s %s ",
Dragan Dosen1322d092015-09-22 16:05:32 +02001492 tm.tm_year+1900, tm.tm_mon+1, tm.tm_mday,
Dragan Dosen17def462015-10-09 21:31:43 +02001493 tm.tm_hour, tm.tm_min, tm.tm_sec,
Benoit GARNIERb413c2a2016-03-27 11:08:03 +02001494 gmt_offset, gmt_offset+3,
Dragan Dosen43885c72015-10-01 13:18:13 +02001495 global.log_send_hostname ? global.log_send_hostname : hostname);
Dragan Dosen1322d092015-09-22 16:05:32 +02001496 /* WARNING: depending upon implementations, snprintf may return
1497 * either -1 or the number of bytes that would be needed to store
1498 * the total message. In both cases, we must adjust it.
1499 */
1500 if (hdr_len < 0 || hdr_len > global.max_syslog_len)
1501 hdr_len = global.max_syslog_len;
1502
Willy Tarreau55e2f5a2019-05-05 10:11:39 +02001503 logheader_rfc5424_end = logheader_rfc5424 + hdr_len;
Dragan Dosen1322d092015-09-22 16:05:32 +02001504 }
1505
Willy Tarreau55e2f5a2019-05-05 10:11:39 +02001506 logheader_rfc5424_end[0] = 0; // ensure we get rid of any previous attempt
Dragan Dosen1322d092015-09-22 16:05:32 +02001507
Willy Tarreau55e2f5a2019-05-05 10:11:39 +02001508 return logheader_rfc5424_end;
Dragan Dosen1322d092015-09-22 16:05:32 +02001509}
1510
William Lallemand2a4a44f2012-02-06 16:00:33 +01001511/*
Dragan Dosen59cee972015-09-19 22:09:02 +02001512 * This function sends the syslog message using a printf format string. It
1513 * expects an LF-terminated message.
William Lallemand2a4a44f2012-02-06 16:00:33 +01001514 */
1515void send_log(struct proxy *p, int level, const char *format, ...)
1516{
1517 va_list argp;
Willy Tarreaub1a2faf2012-03-19 16:51:53 +01001518 int data_len;
William Lallemand2a4a44f2012-02-06 16:00:33 +01001519
Willy Tarreau8c97ab52015-01-15 16:29:53 +01001520 if (level < 0 || format == NULL || logline == NULL)
William Lallemand2a4a44f2012-02-06 16:00:33 +01001521 return;
1522
William Lallemand2a4a44f2012-02-06 16:00:33 +01001523 va_start(argp, format);
Dragan Dosen59cee972015-09-19 22:09:02 +02001524 data_len = vsnprintf(logline, global.max_syslog_len, format, argp);
Willy Tarreau18324f52014-06-27 18:10:07 +02001525 if (data_len < 0 || data_len > global.max_syslog_len)
1526 data_len = global.max_syslog_len;
Willy Tarreaubaaee002006-06-26 02:48:02 +02001527 va_end(argp);
William Lallemand2a4a44f2012-02-06 16:00:33 +01001528
Christopher Faulet5c6fefc2019-08-11 19:40:12 +02001529 __send_log((p ? &p->logsrvs : NULL), (p ? &p->log_tag : NULL), level,
1530 logline, data_len, default_rfc5424_sd_log_format, 2);
William Lallemand2a4a44f2012-02-06 16:00:33 +01001531}
1532
1533/*
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001534 * This function sends a syslog message to <logsrv>.
1535 * <pid_str> is the string to be used for the PID of the caller, <pid_size> is length.
1536 * Same thing for <sd> and <sd_size> which are used for the structured-data part
1537 * in RFC5424 formatted syslog messages, and <tag_str> and <tag_size> the syslog tag.
Dragan Dosen0b85ece2015-09-25 19:17:44 +02001538 * It overrides the last byte of the message vector with an LF character.
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001539 * Does not return any error,
William Lallemand2a4a44f2012-02-06 16:00:33 +01001540 */
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001541static inline void __do_send_log(struct logsrv *logsrv, int nblogger, char *pid_str, size_t pid_size,
1542 int level, char *message, size_t size, char *sd, size_t sd_size,
1543 char *tag_str, size_t tag_size)
William Lallemand2a4a44f2012-02-06 16:00:33 +01001544{
Christopher Fauletf8188c62017-06-02 16:20:16 +02001545 static THREAD_LOCAL struct iovec iovec[NB_MSG_IOVEC_ELEMENTS] = { };
1546 static THREAD_LOCAL struct msghdr msghdr = {
1547 //.msg_iov = iovec,
Dragan Dosen609ac2a2015-09-16 18:25:42 +02001548 .msg_iovlen = NB_MSG_IOVEC_ELEMENTS
1549 };
Christopher Fauletf8188c62017-06-02 16:20:16 +02001550 static THREAD_LOCAL int logfdunix = -1; /* syslog to AF_UNIX socket */
1551 static THREAD_LOCAL int logfdinet = -1; /* syslog to AF_INET socket */
1552 static THREAD_LOCAL char *dataptr = NULL;
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001553 time_t time = date.tv_sec;
Dragan Dosen1322d092015-09-22 16:05:32 +02001554 char *hdr, *hdr_ptr;
Dragan Dosen59cee972015-09-19 22:09:02 +02001555 size_t hdr_size;
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001556 int fac_level;
1557 int *plogfd;
1558 char *pid_sep1 = "", *pid_sep2 = "";
1559 char logheader_short[3];
1560 int sent;
1561 int maxlen;
1562 int hdr_max = 0;
1563 int tag_max = 0;
1564 int pid_sep1_max = 0;
Frédéric Lécaille90a10ae2019-05-14 10:57:58 +02001565 int pid_max = 0;
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001566 int pid_sep2_max = 0;
1567 int sd_max = 0;
1568 int max = 0;
Christopher Fauletf8188c62017-06-02 16:20:16 +02001569
1570 msghdr.msg_iov = iovec;
William Lallemand2a4a44f2012-02-06 16:00:33 +01001571
1572 dataptr = message;
Willy Tarreaubaaee002006-06-26 02:48:02 +02001573
Willy Tarreauf3dc30f2019-08-30 14:18:44 +02001574 if (logsrv->type == LOG_TARGET_FD) {
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001575 /* the socket's address is a file descriptor */
1576 plogfd = (int *)&((struct sockaddr_in *)&logsrv->addr)->sin_addr.s_addr;
Robert Tsai81ae1952007-12-05 10:47:29 +01001577 }
Willy Tarreauc046d162019-08-30 15:24:59 +02001578 else if (logsrv->type == LOG_TARGET_BUFFER) {
1579 plogfd = NULL;
1580 }
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001581 else if (logsrv->addr.ss_family == AF_UNIX)
1582 plogfd = &logfdunix;
1583 else
1584 plogfd = &logfdinet;
Robert Tsai81ae1952007-12-05 10:47:29 +01001585
Willy Tarreauc046d162019-08-30 15:24:59 +02001586 if (plogfd && unlikely(*plogfd < 0)) {
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001587 /* socket not successfully initialized yet */
1588 if ((*plogfd = socket(logsrv->addr.ss_family, SOCK_DGRAM,
1589 (logsrv->addr.ss_family == AF_UNIX) ? 0 : IPPROTO_UDP)) < 0) {
1590 static char once;
William Lallemand0f99e342011-10-12 17:50:54 +02001591
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001592 if (!once) {
1593 once = 1; /* note: no need for atomic ops here */
1594 ha_alert("socket() failed in logger #%d: %s (errno=%d)\n",
1595 nblogger, strerror(errno), errno);
1596 }
1597 return;
1598 } else {
1599 /* we don't want to receive anything on this socket */
1600 setsockopt(*plogfd, SOL_SOCKET, SO_RCVBUF, &zero, sizeof(zero));
1601 /* does nothing under Linux, maybe needed for others */
1602 shutdown(*plogfd, SHUT_RD);
1603 fcntl(*plogfd, F_SETFD, fcntl(*plogfd, F_GETFD, FD_CLOEXEC) | FD_CLOEXEC);
1604 }
Dragan Dosen43885c72015-10-01 13:18:13 +02001605 }
1606
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001607 switch (logsrv->format) {
1608 case LOG_FORMAT_RFC3164:
1609 hdr = logheader;
1610 hdr_ptr = update_log_hdr(time);
1611 break;
Willy Tarreauc7c7be22014-06-23 18:07:15 +02001612
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001613 case LOG_FORMAT_RFC5424:
1614 hdr = logheader_rfc5424;
1615 hdr_ptr = update_log_hdr_rfc5424(time);
1616 sd_max = sd_size; /* the SD part allowed only in RFC5424 */
1617 break;
William Lallemandbddd4fd2012-02-27 11:23:10 +01001618
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001619 case LOG_FORMAT_SHORT:
1620 /* all fields are known, skip the header generation */
1621 hdr = logheader_short;
1622 hdr[0] = '<';
1623 hdr[1] = '0' + MAX(level, logsrv->minlvl);
1624 hdr[2] = '>';
1625 hdr_ptr = hdr;
1626 hdr_max = 3;
1627 maxlen = logsrv->maxlen - hdr_max;
1628 max = MIN(size, maxlen) - 1;
1629 goto send;
Willy Tarreau204e3f12018-12-15 15:48:48 +01001630
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001631 case LOG_FORMAT_RAW:
1632 /* all fields are known, skip the header generation */
1633 hdr_ptr = hdr = "";
1634 hdr_max = 0;
1635 maxlen = logsrv->maxlen;
1636 max = MIN(size, maxlen) - 1;
1637 goto send;
Willy Tarreauc98aebc2018-03-20 11:17:29 +01001638
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001639 default:
1640 return; /* must never happen */
1641 }
Willy Tarreauc7c7be22014-06-23 18:07:15 +02001642
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001643 hdr_size = hdr_ptr - hdr;
Dragan Dosen1322d092015-09-22 16:05:32 +02001644
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001645 /* For each target, we may have a different facility.
1646 * We can also have a different log level for each message.
1647 * This induces variations in the message header length.
1648 * Since we don't want to recompute it each time, nor copy it every
1649 * time, we only change the facility in the pre-computed header,
1650 * and we change the pointer to the header accordingly.
1651 */
1652 fac_level = (logsrv->facility << 3) + MAX(level, logsrv->minlvl);
1653 hdr_ptr = hdr + 3; /* last digit of the log level */
1654 do {
1655 *hdr_ptr = '0' + fac_level % 10;
1656 fac_level /= 10;
1657 hdr_ptr--;
1658 } while (fac_level && hdr_ptr > hdr);
1659 *hdr_ptr = '<';
Dragan Dosen1322d092015-09-22 16:05:32 +02001660
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001661 hdr_max = hdr_size - (hdr_ptr - hdr);
Willy Tarreaue8746a02018-11-12 08:45:00 +01001662
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001663 /* time-based header */
1664 if (unlikely(hdr_size >= logsrv->maxlen)) {
1665 hdr_max = MIN(hdr_max, logsrv->maxlen) - 1;
1666 sd_max = 0;
1667 goto send;
1668 }
Willy Tarreauc1b06452018-11-12 11:57:56 +01001669
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001670 maxlen = logsrv->maxlen - hdr_max;
Dragan Dosen1322d092015-09-22 16:05:32 +02001671
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001672 /* tag */
Frédéric Lécaille90a10ae2019-05-14 10:57:58 +02001673 tag_max = tag_size;
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001674 if (unlikely(tag_max >= maxlen)) {
1675 tag_max = maxlen - 1;
1676 sd_max = 0;
1677 goto send;
1678 }
Dragan Dosen1322d092015-09-22 16:05:32 +02001679
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001680 maxlen -= tag_max;
William Lallemand2a4a44f2012-02-06 16:00:33 +01001681
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001682 /* first pid separator */
1683 pid_sep1_max = log_formats[logsrv->format].pid.sep1.data;
1684 if (unlikely(pid_sep1_max >= maxlen)) {
1685 pid_sep1_max = maxlen - 1;
1686 sd_max = 0;
1687 goto send;
1688 }
Dragan Dosen59cee972015-09-19 22:09:02 +02001689
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001690 pid_sep1 = log_formats[logsrv->format].pid.sep1.area;
1691 maxlen -= pid_sep1_max;
Dragan Dosen59cee972015-09-19 22:09:02 +02001692
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001693 /* pid */
Frédéric Lécaille90a10ae2019-05-14 10:57:58 +02001694 pid_max = pid_size;
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001695 if (unlikely(pid_size >= maxlen)) {
1696 pid_size = maxlen - 1;
1697 sd_max = 0;
1698 goto send;
1699 }
Dragan Dosen68d2e3a2015-09-19 22:35:44 +02001700
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001701 maxlen -= pid_size;
Dragan Dosen43885c72015-10-01 13:18:13 +02001702
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001703 /* second pid separator */
1704 pid_sep2_max = log_formats[logsrv->format].pid.sep2.data;
1705 if (unlikely(pid_sep2_max >= maxlen)) {
1706 pid_sep2_max = maxlen - 1;
1707 sd_max = 0;
1708 goto send;
1709 }
Dragan Dosen43885c72015-10-01 13:18:13 +02001710
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001711 pid_sep2 = log_formats[logsrv->format].pid.sep2.area;
1712 maxlen -= pid_sep2_max;
Dragan Dosen68d2e3a2015-09-19 22:35:44 +02001713
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001714 /* structured-data */
1715 if (sd_max >= maxlen) {
1716 sd_max = maxlen - 1;
1717 goto send;
1718 }
Dragan Dosen59cee972015-09-19 22:09:02 +02001719
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001720 max = MIN(size, maxlen - sd_max) - 1;
1721send:
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001722 if (logsrv->addr.ss_family == AF_UNSPEC) {
Willy Tarreauc046d162019-08-30 15:24:59 +02001723 /* the target is a file descriptor or a ring buffer */
Willy Tarreaud52a7f82019-08-30 14:05:35 +02001724 struct ist msg[7];
1725
1726 msg[0].ptr = hdr_ptr; msg[0].len = hdr_max;
1727 msg[1].ptr = tag_str; msg[1].len = tag_max;
1728 msg[2].ptr = pid_sep1; msg[2].len = pid_sep1_max;
1729 msg[3].ptr = pid_str; msg[3].len = pid_max;
1730 msg[4].ptr = pid_sep2; msg[4].len = pid_sep2_max;
1731 msg[5].ptr = sd; msg[5].len = sd_max;
1732 msg[6].ptr = dataptr; msg[6].len = max;
1733
Willy Tarreauc046d162019-08-30 15:24:59 +02001734 if (logsrv->type == LOG_TARGET_BUFFER)
1735 sent = ring_write(logsrv->ring, ~0, NULL, 0, msg, 7);
1736 else /* LOG_TARGET_FD */
1737 sent = fd_write_frag_line(*plogfd, ~0, NULL, 0, msg, 7, 1);
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001738 }
1739 else {
Willy Tarreaud52a7f82019-08-30 14:05:35 +02001740 iovec[0].iov_base = hdr_ptr;
1741 iovec[0].iov_len = hdr_max;
1742 iovec[1].iov_base = tag_str;
1743 iovec[1].iov_len = tag_max;
1744 iovec[2].iov_base = pid_sep1;
1745 iovec[2].iov_len = pid_sep1_max;
1746 iovec[3].iov_base = pid_str;
1747 iovec[3].iov_len = pid_max;
1748 iovec[4].iov_base = pid_sep2;
1749 iovec[4].iov_len = pid_sep2_max;
1750 iovec[5].iov_base = sd;
1751 iovec[5].iov_len = sd_max;
1752 iovec[6].iov_base = dataptr;
1753 iovec[6].iov_len = max;
1754 iovec[7].iov_base = "\n"; /* insert a \n at the end of the message */
1755 iovec[7].iov_len = 1;
1756
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001757 msghdr.msg_name = (struct sockaddr *)&logsrv->addr;
1758 msghdr.msg_namelen = get_addr_len(&logsrv->addr);
Dragan Dosen43885c72015-10-01 13:18:13 +02001759
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001760 sent = sendmsg(*plogfd, &msghdr, MSG_DONTWAIT | MSG_NOSIGNAL);
1761 }
Dragan Dosen43885c72015-10-01 13:18:13 +02001762
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001763 if (sent < 0) {
1764 static char once;
Dragan Dosen43885c72015-10-01 13:18:13 +02001765
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001766 if (errno == EAGAIN)
1767 _HA_ATOMIC_ADD(&dropped_logs, 1);
1768 else if (!once) {
1769 once = 1; /* note: no need for atomic ops here */
1770 ha_alert("sendmsg()/writev() failed in logger #%d: %s (errno=%d)\n",
1771 nblogger, strerror(errno), errno);
Dragan Dosen0b85ece2015-09-25 19:17:44 +02001772 }
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001773 }
1774}
Dragan Dosen59cee972015-09-19 22:09:02 +02001775
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001776/*
1777 * This function sends a syslog message.
1778 * It doesn't care about errors nor does it report them.
1779 * The arguments <sd> and <sd_size> are used for the structured-data part
1780 * in RFC5424 formatted syslog messages.
1781 */
Christopher Faulet5c6fefc2019-08-11 19:40:12 +02001782void __send_log(struct list *logsrvs, struct buffer *tag, int level,
1783 char *message, size_t size, char *sd, size_t sd_size)
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001784{
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001785 struct logsrv *logsrv;
1786 int nblogger;
1787 static THREAD_LOCAL int curr_pid;
1788 static THREAD_LOCAL char pidstr[100];
1789 static THREAD_LOCAL struct buffer pid;
Dragan Dosen609ac2a2015-09-16 18:25:42 +02001790
Christopher Faulet5c6fefc2019-08-11 19:40:12 +02001791 if (logsrvs == NULL) {
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001792 if (!LIST_ISEMPTY(&global.logsrvs)) {
1793 logsrvs = &global.logsrvs;
Willy Tarreau5a32ecc2018-11-12 07:34:59 +01001794 }
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001795 }
Christopher Faulet5c6fefc2019-08-11 19:40:12 +02001796 if (!tag || !tag->area)
1797 tag = &global.log_tag;
Willy Tarreau18324f52014-06-27 18:10:07 +02001798
Christopher Faulet5c6fefc2019-08-11 19:40:12 +02001799 if (!logsrvs || LIST_ISEMPTY(logsrvs))
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001800 return;
Willy Tarreauc98aebc2018-03-20 11:17:29 +01001801
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001802 if (unlikely(curr_pid != getpid())) {
1803 curr_pid = getpid();
1804 ltoa_o(curr_pid, pidstr, sizeof(pidstr));
1805 chunk_initstr(&pid, pidstr);
1806 }
1807
1808 /* Send log messages to syslog server. */
1809 nblogger = 0;
1810 list_for_each_entry(logsrv, logsrvs, list) {
Frédéric Lécailled803e472019-04-25 07:42:09 +02001811 static THREAD_LOCAL int in_range = 1;
1812
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001813 /* we can filter the level of the messages that are sent to each logger */
1814 if (level > logsrv->level)
1815 continue;
1816
Frédéric Lécailled803e472019-04-25 07:42:09 +02001817 if (logsrv->lb.smp_rgs) {
1818 struct smp_log_range *curr_rg;
1819
1820 HA_SPIN_LOCK(LOGSRV_LOCK, &logsrv->lock);
1821 curr_rg = &logsrv->lb.smp_rgs[logsrv->lb.curr_rg];
1822 in_range = in_smp_log_range(curr_rg, logsrv->lb.curr_idx);
1823 if (in_range) {
1824 /* Let's consume this range. */
1825 curr_rg->curr_idx = (curr_rg->curr_idx + 1) % curr_rg->sz;
1826 if (!curr_rg->curr_idx) {
1827 /* If consumed, let's select the next range. */
1828 logsrv->lb.curr_rg = (logsrv->lb.curr_rg + 1) % logsrv->lb.smp_rgs_sz;
1829 }
1830 }
1831 logsrv->lb.curr_idx = (logsrv->lb.curr_idx + 1) % logsrv->lb.smp_sz;
1832 HA_SPIN_UNLOCK(LOGSRV_LOCK, &logsrv->lock);
1833 }
1834 if (in_range)
1835 __do_send_log(logsrv, ++nblogger, pid.area, pid.data, level,
1836 message, size, sd, sd_size, tag->area, tag->data);
Willy Tarreaubaaee002006-06-26 02:48:02 +02001837 }
1838}
1839
1840
Willy Tarreauc89ccb62012-04-05 21:18:22 +02001841const 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 +01001842const char sess_set_cookie[8] = "NPDIRU67"; /* No set-cookie, Set-cookie found and left unchanged (passive),
1843 Set-cookie Deleted, Set-Cookie Inserted, Set-cookie Rewritten,
1844 Set-cookie Updated, unknown, unknown */
1845
William Lallemand1d705562012-03-12 12:46:41 +01001846/*
1847 * try to write a character if there is enough space, or goto out
1848 */
William Lallemandbddd4fd2012-02-27 11:23:10 +01001849#define LOGCHAR(x) do { \
William Lallemand1d705562012-03-12 12:46:41 +01001850 if (tmplog < dst + maxsize - 1) { \
William Lallemandbddd4fd2012-02-27 11:23:10 +01001851 *(tmplog++) = (x); \
1852 } else { \
1853 goto out; \
1854 } \
1855 } while(0)
1856
Dragan Dosen835b9212016-02-12 13:23:03 +01001857
Willy Tarreaub6b3df32018-11-26 16:31:20 +01001858/* Initializes some log data at boot */
1859static void init_log()
Dragan Dosen835b9212016-02-12 13:23:03 +01001860{
1861 char *tmp;
Willy Tarreaue10cd482018-09-10 18:16:53 +02001862 int i;
Dragan Dosen835b9212016-02-12 13:23:03 +01001863
1864 /* Initialize the escape map for the RFC5424 structured-data : '"\]'
1865 * inside PARAM-VALUE should be escaped with '\' as prefix.
1866 * See https://tools.ietf.org/html/rfc5424#section-6.3.3 for more
1867 * details.
1868 */
1869 memset(rfc5424_escape_map, 0, sizeof(rfc5424_escape_map));
1870
1871 tmp = "\"\\]";
1872 while (*tmp) {
Willy Tarreau1bfd6022019-06-07 11:10:07 +02001873 ha_bit_set(*tmp, rfc5424_escape_map);
Dragan Dosen835b9212016-02-12 13:23:03 +01001874 tmp++;
1875 }
Willy Tarreaue10cd482018-09-10 18:16:53 +02001876
1877 /* initialize the log header encoding map : '{|}"#' should be encoded with
1878 * '#' as prefix, as well as non-printable characters ( <32 or >= 127 ).
1879 * URL encoding only requires '"', '#' to be encoded as well as non-
1880 * printable characters above.
1881 */
1882 memset(hdr_encode_map, 0, sizeof(hdr_encode_map));
1883 memset(url_encode_map, 0, sizeof(url_encode_map));
1884 for (i = 0; i < 32; i++) {
Willy Tarreau1bfd6022019-06-07 11:10:07 +02001885 ha_bit_set(i, hdr_encode_map);
1886 ha_bit_set(i, url_encode_map);
Willy Tarreaue10cd482018-09-10 18:16:53 +02001887 }
1888 for (i = 127; i < 256; i++) {
Willy Tarreau1bfd6022019-06-07 11:10:07 +02001889 ha_bit_set(i, hdr_encode_map);
1890 ha_bit_set(i, url_encode_map);
Willy Tarreaue10cd482018-09-10 18:16:53 +02001891 }
1892
1893 tmp = "\"#{|}";
1894 while (*tmp) {
Willy Tarreau1bfd6022019-06-07 11:10:07 +02001895 ha_bit_set(*tmp, hdr_encode_map);
Willy Tarreaue10cd482018-09-10 18:16:53 +02001896 tmp++;
1897 }
1898
1899 tmp = "\"#";
1900 while (*tmp) {
Willy Tarreau1bfd6022019-06-07 11:10:07 +02001901 ha_bit_set(*tmp, url_encode_map);
Willy Tarreaue10cd482018-09-10 18:16:53 +02001902 tmp++;
1903 }
1904
1905 /* initialize the http header encoding map. The draft httpbis define the
1906 * header content as:
1907 *
1908 * HTTP-message = start-line
1909 * *( header-field CRLF )
1910 * CRLF
1911 * [ message-body ]
1912 * header-field = field-name ":" OWS field-value OWS
1913 * field-value = *( field-content / obs-fold )
1914 * field-content = field-vchar [ 1*( SP / HTAB ) field-vchar ]
1915 * obs-fold = CRLF 1*( SP / HTAB )
1916 * field-vchar = VCHAR / obs-text
1917 * VCHAR = %x21-7E
1918 * obs-text = %x80-FF
1919 *
1920 * All the chars are encoded except "VCHAR", "obs-text", SP and HTAB.
1921 * The encoded chars are form 0x00 to 0x08, 0x0a to 0x1f and 0x7f. The
Joseph Herlant85b40592018-11-15 12:10:04 -08001922 * "obs-fold" is voluntarily forgotten because haproxy remove this.
Willy Tarreaue10cd482018-09-10 18:16:53 +02001923 */
1924 memset(http_encode_map, 0, sizeof(http_encode_map));
1925 for (i = 0x00; i <= 0x08; i++)
Willy Tarreau1bfd6022019-06-07 11:10:07 +02001926 ha_bit_set(i, http_encode_map);
Willy Tarreaue10cd482018-09-10 18:16:53 +02001927 for (i = 0x0a; i <= 0x1f; i++)
Willy Tarreau1bfd6022019-06-07 11:10:07 +02001928 ha_bit_set(i, http_encode_map);
1929 ha_bit_set(0x7f, http_encode_map);
Dragan Dosen835b9212016-02-12 13:23:03 +01001930}
William Lallemand1d705562012-03-12 12:46:41 +01001931
Willy Tarreaub6b3df32018-11-26 16:31:20 +01001932INITCALL0(STG_PREPARE, init_log);
1933
Christopher Faulet0132d062017-07-26 15:33:35 +02001934/* Initialize log buffers used for syslog messages */
1935int init_log_buffers()
1936{
1937 logheader = my_realloc2(logheader, global.max_syslog_len + 1);
Willy Tarreau55e2f5a2019-05-05 10:11:39 +02001938 logheader_end = NULL;
Christopher Faulet0132d062017-07-26 15:33:35 +02001939 logheader_rfc5424 = my_realloc2(logheader_rfc5424, global.max_syslog_len + 1);
Willy Tarreau55e2f5a2019-05-05 10:11:39 +02001940 logheader_rfc5424_end = NULL;
Christopher Faulet0132d062017-07-26 15:33:35 +02001941 logline = my_realloc2(logline, global.max_syslog_len + 1);
1942 logline_rfc5424 = my_realloc2(logline_rfc5424, global.max_syslog_len + 1);
1943 if (!logheader || !logline_rfc5424 || !logline || !logline_rfc5424)
1944 return 0;
1945 return 1;
1946}
1947
1948/* Deinitialize log buffers used for syslog messages */
1949void deinit_log_buffers()
1950{
1951 free(logheader);
1952 free(logheader_rfc5424);
1953 free(logline);
1954 free(logline_rfc5424);
Willy Tarreau869efd52019-11-15 15:16:57 +01001955 ring_free(_HA_ATOMIC_XCHG(&startup_logs, NULL));
Christopher Faulet0132d062017-07-26 15:33:35 +02001956 logheader = NULL;
1957 logheader_rfc5424 = NULL;
1958 logline = NULL;
1959 logline_rfc5424 = NULL;
1960}
1961
Willy Tarreaudf974472012-12-28 02:44:01 +01001962/* Builds a log line in <dst> based on <list_format>, and stops before reaching
1963 * <maxsize> characters. Returns the size of the output string in characters,
1964 * not counting the trailing zero which is always added if the resulting size
Willy Tarreau09bb27c2018-09-05 16:55:15 +02001965 * is not zero. It requires a valid session and optionally a stream. If the
1966 * stream is NULL, default values will be assumed for the stream part.
Willy Tarreaudf974472012-12-28 02:44:01 +01001967 */
Willy Tarreau43c538e2018-09-05 14:58:15 +02001968int 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 +02001969{
Willy Tarreaue36cbcb2015-04-03 15:40:56 +02001970 struct proxy *fe = sess->fe;
Willy Tarreau09bb27c2018-09-05 16:55:15 +02001971 struct proxy *be;
1972 struct http_txn *txn;
1973 const struct strm_logs *logs;
Willy Tarreau8fa99842019-07-17 11:47:11 +02001974 struct connection *be_conn;
Willy Tarreau09bb27c2018-09-05 16:55:15 +02001975 unsigned int s_flags;
1976 unsigned int uniq_id;
Willy Tarreau83061a82018-07-13 11:56:34 +02001977 struct buffer chunk;
William Lallemandbddd4fd2012-02-27 11:23:10 +01001978 char *uri;
Andrew Hayworth0ebc55f2015-04-27 21:37:03 +00001979 char *spc;
Andrew Hayworthe63ac872015-07-31 16:14:16 +00001980 char *qmark;
Andrew Hayworth0ebc55f2015-04-27 21:37:03 +00001981 char *end;
Willy Tarreaufe944602007-10-25 10:34:16 +02001982 struct tm tm;
William Lallemandbddd4fd2012-02-27 11:23:10 +01001983 int t_request;
1984 int hdr;
1985 int last_isspace = 1;
Andrew Hayworth0ebc55f2015-04-27 21:37:03 +00001986 int nspaces = 0;
Willy Tarreaub1a2faf2012-03-19 16:51:53 +01001987 char *tmplog;
William Lallemand1d705562012-03-12 12:46:41 +01001988 char *ret;
1989 int iret;
William Lallemandbddd4fd2012-02-27 11:23:10 +01001990 struct logformat_node *tmp;
Thierry FOURNIER / OZON.IO4cac3592016-07-28 17:19:45 +02001991 struct timeval tv;
Willy Tarreau09bb27c2018-09-05 16:55:15 +02001992 struct strm_logs tmp_strm_log;
Willy Tarreaubaaee002006-06-26 02:48:02 +02001993
William Lallemandbddd4fd2012-02-27 11:23:10 +01001994 /* FIXME: let's limit ourselves to frontend logging for now. */
Willy Tarreaubaaee002006-06-26 02:48:02 +02001995
Willy Tarreau09bb27c2018-09-05 16:55:15 +02001996 if (likely(s)) {
1997 be = s->be;
1998 txn = s->txn;
1999 be_conn = cs_conn(objt_cs(s->si[1].end));
2000 s_flags = s->flags;
2001 uniq_id = s->uniq_id;
2002 logs = &s->logs;
2003 } else {
2004 /* we have no stream so we first need to initialize a few
2005 * things that are needed later. We do increment the request
2006 * ID so that it's uniquely assigned to this request just as
2007 * if the request had reached the point of being processed.
2008 * A request error is reported as it's the only element we have
2009 * here and which justifies emitting such a log.
2010 */
2011 be = fe;
2012 txn = NULL;
2013 be_conn = NULL;
2014 s_flags = SF_ERR_PRXCOND | SF_FINST_R;
Olivier Houchardd2ee3e72019-03-08 18:53:21 +01002015 uniq_id = _HA_ATOMIC_XADD(&global.req_count, 1);
Willy Tarreau09bb27c2018-09-05 16:55:15 +02002016
2017 /* prepare a valid log structure */
2018 tmp_strm_log.tv_accept = sess->tv_accept;
2019 tmp_strm_log.accept_date = sess->accept_date;
2020 tmp_strm_log.t_handshake = sess->t_handshake;
2021 tmp_strm_log.t_idle = tv_ms_elapsed(&sess->tv_accept, &now) - sess->t_handshake;
2022 tv_zero(&tmp_strm_log.tv_request);
2023 tmp_strm_log.t_queue = -1;
2024 tmp_strm_log.t_connect = -1;
2025 tmp_strm_log.t_data = -1;
2026 tmp_strm_log.t_close = tv_ms_elapsed(&sess->tv_accept, &now);
2027 tmp_strm_log.bytes_in = 0;
2028 tmp_strm_log.bytes_out = 0;
2029 tmp_strm_log.prx_queue_pos = 0;
2030 tmp_strm_log.srv_queue_pos = 0;
2031
2032 logs = &tmp_strm_log;
2033 }
2034
William Lallemandbddd4fd2012-02-27 11:23:10 +01002035 t_request = -1;
Willy Tarreau372ac5a2018-09-05 15:16:23 +02002036 if (tv_isge(&logs->tv_request, &logs->tv_accept))
2037 t_request = tv_ms_elapsed(&logs->tv_accept, &logs->tv_request);
William Lallemandbddd4fd2012-02-27 11:23:10 +01002038
William Lallemand1d705562012-03-12 12:46:41 +01002039 tmplog = dst;
Willy Tarreauc9bd0cc2009-05-10 11:57:02 +02002040
William Lallemandbddd4fd2012-02-27 11:23:10 +01002041 /* fill logbuffer */
William Lallemand1d705562012-03-12 12:46:41 +01002042 if (LIST_ISEMPTY(list_format))
2043 return 0;
William Lallemandbddd4fd2012-02-27 11:23:10 +01002044
William Lallemand1d705562012-03-12 12:46:41 +01002045 list_for_each_entry(tmp, list_format, list) {
Willy Tarreaub363a1f2013-10-01 10:45:07 +02002046 struct connection *conn;
Willy Tarreau4f653562012-10-12 19:48:16 +02002047 const char *src = NULL;
Willy Tarreauc8368452012-12-21 00:09:23 +01002048 struct sample *key;
Willy Tarreau83061a82018-07-13 11:56:34 +02002049 const struct buffer empty = { };
William Lallemandbddd4fd2012-02-27 11:23:10 +01002050
Willy Tarreauc8368452012-12-21 00:09:23 +01002051 switch (tmp->type) {
William Lallemand1d705562012-03-12 12:46:41 +01002052 case LOG_FMT_SEPARATOR:
William Lallemandbddd4fd2012-02-27 11:23:10 +01002053 if (!last_isspace) {
2054 LOGCHAR(' ');
2055 last_isspace = 1;
William Lallemandbddd4fd2012-02-27 11:23:10 +01002056 }
2057 break;
2058
William Lallemand1d705562012-03-12 12:46:41 +01002059 case LOG_FMT_TEXT: // text
William Lallemandbddd4fd2012-02-27 11:23:10 +01002060 src = tmp->arg;
William Lallemand5f232402012-04-05 18:02:55 +02002061 iret = strlcpy2(tmplog, src, dst + maxsize - tmplog);
William Lallemand1d705562012-03-12 12:46:41 +01002062 if (iret == 0)
William Lallemandbddd4fd2012-02-27 11:23:10 +01002063 goto out;
William Lallemand1d705562012-03-12 12:46:41 +01002064 tmplog += iret;
William Lallemandbddd4fd2012-02-27 11:23:10 +01002065 last_isspace = 0;
2066 break;
2067
Willy Tarreauc8368452012-12-21 00:09:23 +01002068 case LOG_FMT_EXPR: // sample expression, may be request or response
2069 key = NULL;
Christopher Faulet5f940702020-04-06 10:40:02 +02002070 if (tmp->options & LOG_OPT_REQ_CAP)
Adis Nezirovic79beb242015-07-06 15:41:02 +02002071 key = sample_fetch_as_type(be, sess, s, SMP_OPT_DIR_REQ|SMP_OPT_FINAL, tmp->expr, SMP_T_STR);
Christopher Faulet5f940702020-04-06 10:40:02 +02002072 if (!key && (tmp->options & LOG_OPT_RES_CAP))
Adis Nezirovic79beb242015-07-06 15:41:02 +02002073 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 +01002074 if (tmp->options & LOG_OPT_HTTP)
Dragan Dosen835b9212016-02-12 13:23:03 +01002075 ret = lf_encode_chunk(tmplog, dst + maxsize,
2076 '%', http_encode_map, key ? &key->data.u.str : &empty, tmp);
Thierry FOURNIERd048d8b2014-03-13 16:46:18 +01002077 else
Willy Tarreau843b7cb2018-07-13 10:54:26 +02002078 ret = lf_text_len(tmplog,
2079 key ? key->data.u.str.area : NULL,
2080 key ? key->data.u.str.data : 0,
2081 dst + maxsize - tmplog,
2082 tmp);
Willy Tarreauc8368452012-12-21 00:09:23 +01002083 if (ret == 0)
2084 goto out;
2085 tmplog = ret;
2086 last_isspace = 0;
2087 break;
2088
Willy Tarreau2beef582012-12-20 17:22:52 +01002089 case LOG_FMT_CLIENTIP: // %ci
Willy Tarreau9ad7bd42015-04-03 19:19:59 +02002090 conn = objt_conn(sess->origin);
Willy Tarreau8fa99842019-07-17 11:47:11 +02002091 if (conn && conn_get_src(conn))
Willy Tarreau6c6365f2019-07-17 16:48:18 +02002092 ret = lf_ip(tmplog, (struct sockaddr *)conn->src, dst + maxsize - tmplog, tmp);
Willy Tarreaub363a1f2013-10-01 10:45:07 +02002093 else
2094 ret = lf_text_len(tmplog, NULL, 0, dst + maxsize - tmplog, tmp);
William Lallemand1d705562012-03-12 12:46:41 +01002095 if (ret == NULL)
William Lallemandbddd4fd2012-02-27 11:23:10 +01002096 goto out;
William Lallemand1d705562012-03-12 12:46:41 +01002097 tmplog = ret;
William Lallemandbddd4fd2012-02-27 11:23:10 +01002098 last_isspace = 0;
2099 break;
2100
Willy Tarreau2beef582012-12-20 17:22:52 +01002101 case LOG_FMT_CLIENTPORT: // %cp
Willy Tarreau9ad7bd42015-04-03 19:19:59 +02002102 conn = objt_conn(sess->origin);
Willy Tarreau8fa99842019-07-17 11:47:11 +02002103 if (conn && conn_get_src(conn)) {
Willy Tarreau6c6365f2019-07-17 16:48:18 +02002104 if (conn->src->ss_family == AF_UNIX) {
Willy Tarreaufb0afa72015-04-03 14:46:27 +02002105 ret = ltoa_o(sess->listener->luid, tmplog, dst + maxsize - tmplog);
Willy Tarreaub363a1f2013-10-01 10:45:07 +02002106 } else {
Willy Tarreau6c6365f2019-07-17 16:48:18 +02002107 ret = lf_port(tmplog, (struct sockaddr *)conn->src,
Willy Tarreaub363a1f2013-10-01 10:45:07 +02002108 dst + maxsize - tmplog, tmp);
2109 }
William Lallemand5f232402012-04-05 18:02:55 +02002110 }
Willy Tarreaub363a1f2013-10-01 10:45:07 +02002111 else
2112 ret = lf_text_len(tmplog, NULL, 0, dst + maxsize - tmplog, tmp);
2113
William Lallemand5f232402012-04-05 18:02:55 +02002114 if (ret == NULL)
2115 goto out;
2116 tmplog = ret;
2117 last_isspace = 0;
2118 break;
2119
Willy Tarreau2beef582012-12-20 17:22:52 +01002120 case LOG_FMT_FRONTENDIP: // %fi
Willy Tarreau9ad7bd42015-04-03 19:19:59 +02002121 conn = objt_conn(sess->origin);
Willy Tarreau8fa99842019-07-17 11:47:11 +02002122 if (conn && conn_get_dst(conn)) {
Willy Tarreau6c6365f2019-07-17 16:48:18 +02002123 ret = lf_ip(tmplog, (struct sockaddr *)conn->dst, dst + maxsize - tmplog, tmp);
Willy Tarreaub363a1f2013-10-01 10:45:07 +02002124 }
2125 else
2126 ret = lf_text_len(tmplog, NULL, 0, dst + maxsize - tmplog, tmp);
2127
William Lallemand1d705562012-03-12 12:46:41 +01002128 if (ret == NULL)
William Lallemandbddd4fd2012-02-27 11:23:10 +01002129 goto out;
William Lallemand1d705562012-03-12 12:46:41 +01002130 tmplog = ret;
William Lallemandbddd4fd2012-02-27 11:23:10 +01002131 last_isspace = 0;
2132 break;
2133
Willy Tarreau2beef582012-12-20 17:22:52 +01002134 case LOG_FMT_FRONTENDPORT: // %fp
Willy Tarreau9ad7bd42015-04-03 19:19:59 +02002135 conn = objt_conn(sess->origin);
Willy Tarreau8fa99842019-07-17 11:47:11 +02002136 if (conn && conn_get_dst(conn)) {
Willy Tarreau6c6365f2019-07-17 16:48:18 +02002137 if (conn->dst->ss_family == AF_UNIX)
Willy Tarreaufb0afa72015-04-03 14:46:27 +02002138 ret = ltoa_o(sess->listener->luid, tmplog, dst + maxsize - tmplog);
Willy Tarreaub363a1f2013-10-01 10:45:07 +02002139 else
Willy Tarreau6c6365f2019-07-17 16:48:18 +02002140 ret = lf_port(tmplog, (struct sockaddr *)conn->dst, dst + maxsize - tmplog, tmp);
William Lallemand5f232402012-04-05 18:02:55 +02002141 }
Willy Tarreaub363a1f2013-10-01 10:45:07 +02002142 else
2143 ret = lf_text_len(tmplog, NULL, 0, dst + maxsize - tmplog, tmp);
2144
William Lallemand5f232402012-04-05 18:02:55 +02002145 if (ret == NULL)
2146 goto out;
2147 tmplog = ret;
2148 last_isspace = 0;
2149 break;
2150
Willy Tarreau2beef582012-12-20 17:22:52 +01002151 case LOG_FMT_BACKENDIP: // %bi
Willy Tarreau8fa99842019-07-17 11:47:11 +02002152 if (be_conn && conn_get_src(be_conn))
Willy Tarreau6c6365f2019-07-17 16:48:18 +02002153 ret = lf_ip(tmplog, (const struct sockaddr *)be_conn->src, dst + maxsize - tmplog, tmp);
Willy Tarreaub363a1f2013-10-01 10:45:07 +02002154 else
2155 ret = lf_text_len(tmplog, NULL, 0, dst + maxsize - tmplog, tmp);
2156
William Lallemand1d705562012-03-12 12:46:41 +01002157 if (ret == NULL)
William Lallemandb7ff6a32012-03-02 14:35:21 +01002158 goto out;
William Lallemand1d705562012-03-12 12:46:41 +01002159 tmplog = ret;
William Lallemandb7ff6a32012-03-02 14:35:21 +01002160 last_isspace = 0;
2161 break;
2162
Willy Tarreau2beef582012-12-20 17:22:52 +01002163 case LOG_FMT_BACKENDPORT: // %bp
Willy Tarreau8fa99842019-07-17 11:47:11 +02002164 if (be_conn && conn_get_src(be_conn))
Willy Tarreau6c6365f2019-07-17 16:48:18 +02002165 ret = lf_port(tmplog, (struct sockaddr *)be_conn->src, dst + maxsize - tmplog, tmp);
Willy Tarreaub363a1f2013-10-01 10:45:07 +02002166 else
2167 ret = lf_text_len(tmplog, NULL, 0, dst + maxsize - tmplog, tmp);
2168
William Lallemand5f232402012-04-05 18:02:55 +02002169 if (ret == NULL)
2170 goto out;
2171 tmplog = ret;
2172 last_isspace = 0;
2173 break;
2174
Willy Tarreau2beef582012-12-20 17:22:52 +01002175 case LOG_FMT_SERVERIP: // %si
Willy Tarreau8fa99842019-07-17 11:47:11 +02002176 if (be_conn && conn_get_dst(be_conn))
Willy Tarreau6c6365f2019-07-17 16:48:18 +02002177 ret = lf_ip(tmplog, (struct sockaddr *)be_conn->dst, dst + maxsize - tmplog, tmp);
Willy Tarreaub363a1f2013-10-01 10:45:07 +02002178 else
2179 ret = lf_text_len(tmplog, NULL, 0, dst + maxsize - tmplog, tmp);
2180
William Lallemand5f232402012-04-05 18:02:55 +02002181 if (ret == NULL)
2182 goto out;
2183 tmplog = ret;
2184 last_isspace = 0;
2185 break;
2186
Willy Tarreau2beef582012-12-20 17:22:52 +01002187 case LOG_FMT_SERVERPORT: // %sp
Willy Tarreau8fa99842019-07-17 11:47:11 +02002188 if (be_conn && conn_get_dst(be_conn))
Willy Tarreau6c6365f2019-07-17 16:48:18 +02002189 ret = lf_port(tmplog, (struct sockaddr *)be_conn->dst, dst + maxsize - tmplog, tmp);
Willy Tarreaub363a1f2013-10-01 10:45:07 +02002190 else
2191 ret = lf_text_len(tmplog, NULL, 0, dst + maxsize - tmplog, tmp);
2192
William Lallemand1d705562012-03-12 12:46:41 +01002193 if (ret == NULL)
William Lallemandb7ff6a32012-03-02 14:35:21 +01002194 goto out;
William Lallemand1d705562012-03-12 12:46:41 +01002195 tmplog = ret;
William Lallemandb7ff6a32012-03-02 14:35:21 +01002196 last_isspace = 0;
2197 break;
2198
Thierry FOURNIER / OZON.IO4cac3592016-07-28 17:19:45 +02002199 case LOG_FMT_DATE: // %t = accept date
Willy Tarreau372ac5a2018-09-05 15:16:23 +02002200 get_localtime(logs->accept_date.tv_sec, &tm);
2201 ret = date2str_log(tmplog, &tm, &logs->accept_date, dst + maxsize - tmplog);
William Lallemand1d705562012-03-12 12:46:41 +01002202 if (ret == NULL)
William Lallemandbddd4fd2012-02-27 11:23:10 +01002203 goto out;
William Lallemand1d705562012-03-12 12:46:41 +01002204 tmplog = ret;
William Lallemandbddd4fd2012-02-27 11:23:10 +01002205 last_isspace = 0;
2206 break;
2207
Thierry FOURNIER / OZON.IO4cac3592016-07-28 17:19:45 +02002208 case LOG_FMT_tr: // %tr = start of request date
2209 /* Note that the timers are valid if we get here */
Willy Tarreau372ac5a2018-09-05 15:16:23 +02002210 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 +02002211 get_localtime(tv.tv_sec, &tm);
2212 ret = date2str_log(tmplog, &tm, &tv, dst + maxsize - tmplog);
2213 if (ret == NULL)
2214 goto out;
2215 tmplog = ret;
2216 last_isspace = 0;
2217 break;
2218
2219 case LOG_FMT_DATEGMT: // %T = accept date, GMT
Willy Tarreau372ac5a2018-09-05 15:16:23 +02002220 get_gmtime(logs->accept_date.tv_sec, &tm);
William Lallemand5f232402012-04-05 18:02:55 +02002221 ret = gmt2str_log(tmplog, &tm, dst + maxsize - tmplog);
William Lallemand1d705562012-03-12 12:46:41 +01002222 if (ret == NULL)
William Lallemandbddd4fd2012-02-27 11:23:10 +01002223 goto out;
William Lallemand1d705562012-03-12 12:46:41 +01002224 tmplog = ret;
William Lallemandbddd4fd2012-02-27 11:23:10 +01002225 last_isspace = 0;
2226 break;
2227
Thierry FOURNIER / OZON.IO4cac3592016-07-28 17:19:45 +02002228 case LOG_FMT_trg: // %trg = start of request date, GMT
Willy Tarreau372ac5a2018-09-05 15:16:23 +02002229 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 +02002230 get_gmtime(tv.tv_sec, &tm);
2231 ret = gmt2str_log(tmplog, &tm, dst + maxsize - tmplog);
2232 if (ret == NULL)
2233 goto out;
2234 tmplog = ret;
2235 last_isspace = 0;
2236 break;
2237
2238 case LOG_FMT_DATELOCAL: // %Tl = accept date, local
Willy Tarreau372ac5a2018-09-05 15:16:23 +02002239 get_localtime(logs->accept_date.tv_sec, &tm);
2240 ret = localdate2str_log(tmplog, logs->accept_date.tv_sec, &tm, dst + maxsize - tmplog);
Yuxans Yao4e25b012012-10-19 10:36:09 +08002241 if (ret == NULL)
2242 goto out;
2243 tmplog = ret;
2244 last_isspace = 0;
2245 break;
2246
Thierry FOURNIER / OZON.IO4cac3592016-07-28 17:19:45 +02002247 case LOG_FMT_trl: // %trl = start of request date, local
Willy Tarreau372ac5a2018-09-05 15:16:23 +02002248 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 +02002249 get_localtime(tv.tv_sec, &tm);
2250 ret = localdate2str_log(tmplog, tv.tv_sec, &tm, dst + maxsize - tmplog);
2251 if (ret == NULL)
2252 goto out;
2253 tmplog = ret;
2254 last_isspace = 0;
2255 break;
2256
William Lallemand5f232402012-04-05 18:02:55 +02002257 case LOG_FMT_TS: // %Ts
William Lallemand5f232402012-04-05 18:02:55 +02002258 if (tmp->options & LOG_OPT_HEXA) {
Willy Tarreau372ac5a2018-09-05 15:16:23 +02002259 iret = snprintf(tmplog, dst + maxsize - tmplog, "%04X", (unsigned int)logs->accept_date.tv_sec);
William Lallemand5f232402012-04-05 18:02:55 +02002260 if (iret < 0 || iret > dst + maxsize - tmplog)
2261 goto out;
2262 last_isspace = 0;
2263 tmplog += iret;
2264 } else {
Willy Tarreau372ac5a2018-09-05 15:16:23 +02002265 ret = ltoa_o(logs->accept_date.tv_sec, tmplog, dst + maxsize - tmplog);
William Lallemand5f232402012-04-05 18:02:55 +02002266 if (ret == NULL)
2267 goto out;
2268 tmplog = ret;
2269 last_isspace = 0;
2270 }
2271 break;
2272
William Lallemand1d705562012-03-12 12:46:41 +01002273 case LOG_FMT_MS: // %ms
William Lallemand5f232402012-04-05 18:02:55 +02002274 if (tmp->options & LOG_OPT_HEXA) {
Willy Tarreau372ac5a2018-09-05 15:16:23 +02002275 iret = snprintf(tmplog, dst + maxsize - tmplog, "%02X",(unsigned int)logs->accept_date.tv_usec/1000);
William Lallemand5f232402012-04-05 18:02:55 +02002276 if (iret < 0 || iret > dst + maxsize - tmplog)
2277 goto out;
2278 last_isspace = 0;
2279 tmplog += iret;
2280 } else {
2281 if ((dst + maxsize - tmplog) < 4)
William Lallemandbddd4fd2012-02-27 11:23:10 +01002282 goto out;
Willy Tarreau372ac5a2018-09-05 15:16:23 +02002283 ret = utoa_pad((unsigned int)logs->accept_date.tv_usec/1000,
Willy Tarreau9e60cd82013-01-24 01:18:16 +01002284 tmplog, 4);
2285 if (ret == NULL)
William Lallemand51b5dca2012-03-26 17:52:55 +02002286 goto out;
Willy Tarreau9e60cd82013-01-24 01:18:16 +01002287 tmplog = ret;
William Lallemandbddd4fd2012-02-27 11:23:10 +01002288 last_isspace = 0;
William Lallemand5f232402012-04-05 18:02:55 +02002289 }
2290 break;
William Lallemandbddd4fd2012-02-27 11:23:10 +01002291
William Lallemand1d705562012-03-12 12:46:41 +01002292 case LOG_FMT_FRONTEND: // %f
William Lallemandbddd4fd2012-02-27 11:23:10 +01002293 src = fe->id;
William Lallemand5f232402012-04-05 18:02:55 +02002294 ret = lf_text(tmplog, src, dst + maxsize - tmplog, tmp);
William Lallemand1d705562012-03-12 12:46:41 +01002295 if (ret == NULL)
William Lallemandbddd4fd2012-02-27 11:23:10 +01002296 goto out;
William Lallemand1d705562012-03-12 12:46:41 +01002297 tmplog = ret;
William Lallemand51b5dca2012-03-26 17:52:55 +02002298 last_isspace = 0;
William Lallemandbddd4fd2012-02-27 11:23:10 +01002299 break;
2300
Willy Tarreau773d65f2012-10-12 14:56:11 +02002301 case LOG_FMT_FRONTEND_XPRT: // %ft
2302 src = fe->id;
2303 if (tmp->options & LOG_OPT_QUOTE)
2304 LOGCHAR('"');
2305 iret = strlcpy2(tmplog, src, dst + maxsize - tmplog);
2306 if (iret == 0)
2307 goto out;
2308 tmplog += iret;
Willy Tarreaua261e9b2016-12-22 20:44:00 +01002309 if (sess->listener->bind_conf->xprt == xprt_get(XPRT_SSL))
Willy Tarreau773d65f2012-10-12 14:56:11 +02002310 LOGCHAR('~');
Willy Tarreau773d65f2012-10-12 14:56:11 +02002311 if (tmp->options & LOG_OPT_QUOTE)
2312 LOGCHAR('"');
2313 last_isspace = 0;
2314 break;
Willy Tarreauffc3fcd2012-10-12 20:17:54 +02002315#ifdef USE_OPENSSL
2316 case LOG_FMT_SSL_CIPHER: // %sslc
2317 src = NULL;
Willy Tarreau9ad7bd42015-04-03 19:19:59 +02002318 conn = objt_conn(sess->origin);
Willy Tarreaub363a1f2013-10-01 10:45:07 +02002319 if (conn) {
Emmanuel Hocdet01da5712017-10-13 16:59:49 +02002320 src = ssl_sock_get_cipher_name(conn);
Willy Tarreaub363a1f2013-10-01 10:45:07 +02002321 }
Willy Tarreauffc3fcd2012-10-12 20:17:54 +02002322 ret = lf_text(tmplog, src, dst + maxsize - tmplog, tmp);
2323 if (ret == NULL)
2324 goto out;
2325 tmplog = ret;
2326 last_isspace = 0;
2327 break;
Willy Tarreau773d65f2012-10-12 14:56:11 +02002328
Willy Tarreauffc3fcd2012-10-12 20:17:54 +02002329 case LOG_FMT_SSL_VERSION: // %sslv
2330 src = NULL;
Willy Tarreau9ad7bd42015-04-03 19:19:59 +02002331 conn = objt_conn(sess->origin);
Willy Tarreaub363a1f2013-10-01 10:45:07 +02002332 if (conn) {
Emmanuel Hocdet01da5712017-10-13 16:59:49 +02002333 src = ssl_sock_get_proto_version(conn);
Willy Tarreaub363a1f2013-10-01 10:45:07 +02002334 }
Willy Tarreauffc3fcd2012-10-12 20:17:54 +02002335 ret = lf_text(tmplog, src, dst + maxsize - tmplog, tmp);
2336 if (ret == NULL)
2337 goto out;
2338 tmplog = ret;
2339 last_isspace = 0;
2340 break;
2341#endif
William Lallemand1d705562012-03-12 12:46:41 +01002342 case LOG_FMT_BACKEND: // %b
William Lallemandbddd4fd2012-02-27 11:23:10 +01002343 src = be->id;
William Lallemand5f232402012-04-05 18:02:55 +02002344 ret = lf_text(tmplog, src, dst + maxsize - tmplog, tmp);
William Lallemand1d705562012-03-12 12:46:41 +01002345 if (ret == NULL)
William Lallemandbddd4fd2012-02-27 11:23:10 +01002346 goto out;
William Lallemand1d705562012-03-12 12:46:41 +01002347 tmplog = ret;
William Lallemand51b5dca2012-03-26 17:52:55 +02002348 last_isspace = 0;
William Lallemandbddd4fd2012-02-27 11:23:10 +01002349 break;
2350
William Lallemand1d705562012-03-12 12:46:41 +01002351 case LOG_FMT_SERVER: // %s
Willy Tarreaue1809df2018-09-05 15:30:16 +02002352 switch (obj_type(s ? s->target : NULL)) {
Willy Tarreaud79a3b22012-12-28 09:40:16 +01002353 case OBJ_TYPE_SERVER:
Willy Tarreau1aaf3242018-09-20 11:13:58 +02002354 src = __objt_server(s->target)->id;
Willy Tarreaud79a3b22012-12-28 09:40:16 +01002355 break;
2356 case OBJ_TYPE_APPLET:
Willy Tarreau1aaf3242018-09-20 11:13:58 +02002357 src = __objt_applet(s->target)->name;
Willy Tarreaud79a3b22012-12-28 09:40:16 +01002358 break;
2359 default:
2360 src = "<NOSRV>";
2361 break;
2362 }
William Lallemand5f232402012-04-05 18:02:55 +02002363 ret = lf_text(tmplog, src, dst + maxsize - tmplog, tmp);
William Lallemand1d705562012-03-12 12:46:41 +01002364 if (ret == NULL)
William Lallemandbddd4fd2012-02-27 11:23:10 +01002365 goto out;
William Lallemand1d705562012-03-12 12:46:41 +01002366 tmplog = ret;
William Lallemandbddd4fd2012-02-27 11:23:10 +01002367 last_isspace = 0;
2368 break;
2369
Thierry FOURNIER / OZON.IO4cac3592016-07-28 17:19:45 +02002370 case LOG_FMT_Th: // %Th = handshake time
Willy Tarreau372ac5a2018-09-05 15:16:23 +02002371 ret = ltoa_o(logs->t_handshake, tmplog, dst + maxsize - tmplog);
Thierry FOURNIER / OZON.IO4cac3592016-07-28 17:19:45 +02002372 if (ret == NULL)
2373 goto out;
2374 tmplog = ret;
2375 last_isspace = 0;
2376 break;
2377
2378 case LOG_FMT_Ti: // %Ti = HTTP idle time
Willy Tarreau372ac5a2018-09-05 15:16:23 +02002379 ret = ltoa_o(logs->t_idle, tmplog, dst + maxsize - tmplog);
Thierry FOURNIER / OZON.IO4cac3592016-07-28 17:19:45 +02002380 if (ret == NULL)
2381 goto out;
2382 tmplog = ret;
2383 last_isspace = 0;
2384 break;
2385
2386 case LOG_FMT_TR: // %TR = HTTP request time
Willy Tarreau372ac5a2018-09-05 15:16:23 +02002387 ret = ltoa_o((t_request >= 0) ? t_request - logs->t_idle - logs->t_handshake : -1,
Thierry FOURNIER / OZON.IO4cac3592016-07-28 17:19:45 +02002388 tmplog, dst + maxsize - tmplog);
2389 if (ret == NULL)
2390 goto out;
2391 tmplog = ret;
2392 last_isspace = 0;
2393 break;
2394
2395 case LOG_FMT_TQ: // %Tq = Th + Ti + TR
William Lallemand5f232402012-04-05 18:02:55 +02002396 ret = ltoa_o(t_request, tmplog, dst + maxsize - tmplog);
William Lallemand1d705562012-03-12 12:46:41 +01002397 if (ret == NULL)
William Lallemandbddd4fd2012-02-27 11:23:10 +01002398 goto out;
William Lallemand1d705562012-03-12 12:46:41 +01002399 tmplog = ret;
William Lallemandbddd4fd2012-02-27 11:23:10 +01002400 last_isspace = 0;
2401 break;
2402
William Lallemand1d705562012-03-12 12:46:41 +01002403 case LOG_FMT_TW: // %Tw
Willy Tarreau372ac5a2018-09-05 15:16:23 +02002404 ret = ltoa_o((logs->t_queue >= 0) ? logs->t_queue - t_request : -1,
William Lallemand5f232402012-04-05 18:02:55 +02002405 tmplog, dst + maxsize - tmplog);
William Lallemand1d705562012-03-12 12:46:41 +01002406 if (ret == NULL)
William Lallemandbddd4fd2012-02-27 11:23:10 +01002407 goto out;
William Lallemand1d705562012-03-12 12:46:41 +01002408 tmplog = ret;
William Lallemandbddd4fd2012-02-27 11:23:10 +01002409 last_isspace = 0;
2410 break;
2411
William Lallemand1d705562012-03-12 12:46:41 +01002412 case LOG_FMT_TC: // %Tc
Willy Tarreau372ac5a2018-09-05 15:16:23 +02002413 ret = ltoa_o((logs->t_connect >= 0) ? logs->t_connect - logs->t_queue : -1,
William Lallemand5f232402012-04-05 18:02:55 +02002414 tmplog, dst + maxsize - tmplog);
William Lallemand1d705562012-03-12 12:46:41 +01002415 if (ret == NULL)
William Lallemandbddd4fd2012-02-27 11:23:10 +01002416 goto out;
William Lallemand1d705562012-03-12 12:46:41 +01002417 tmplog = ret;
William Lallemandbddd4fd2012-02-27 11:23:10 +01002418 last_isspace = 0;
2419 break;
2420
Thierry FOURNIER / OZON.IO4cac3592016-07-28 17:19:45 +02002421 case LOG_FMT_Tr: // %Tr
Willy Tarreau372ac5a2018-09-05 15:16:23 +02002422 ret = ltoa_o((logs->t_data >= 0) ? logs->t_data - logs->t_connect : -1,
William Lallemand5f232402012-04-05 18:02:55 +02002423 tmplog, dst + maxsize - tmplog);
William Lallemand1d705562012-03-12 12:46:41 +01002424 if (ret == NULL)
William Lallemandbddd4fd2012-02-27 11:23:10 +01002425 goto out;
William Lallemand1d705562012-03-12 12:46:41 +01002426 tmplog = ret;
William Lallemandbddd4fd2012-02-27 11:23:10 +01002427 last_isspace = 0;
2428 break;
2429
Willy Tarreau27b639d2016-05-17 17:55:27 +02002430 case LOG_FMT_TD: // %Td
Willy Tarreaua21c0e62018-09-05 15:07:15 +02002431 if (be->mode == PR_MODE_HTTP)
Willy Tarreau372ac5a2018-09-05 15:16:23 +02002432 ret = ltoa_o((logs->t_data >= 0) ? logs->t_close - logs->t_data : -1,
Willy Tarreau27b639d2016-05-17 17:55:27 +02002433 tmplog, dst + maxsize - tmplog);
2434 else
Willy Tarreau372ac5a2018-09-05 15:16:23 +02002435 ret = ltoa_o((logs->t_connect >= 0) ? logs->t_close - logs->t_connect : -1,
Willy Tarreau27b639d2016-05-17 17:55:27 +02002436 tmplog, dst + maxsize - tmplog);
2437 if (ret == NULL)
2438 goto out;
2439 tmplog = ret;
2440 last_isspace = 0;
2441 break;
2442
Thierry FOURNIER / OZON.IO4cac3592016-07-28 17:19:45 +02002443 case LOG_FMT_Ta: // %Ta = active time = Tt - Th - Ti
2444 if (!(fe->to_log & LW_BYTES))
2445 LOGCHAR('+');
Willy Tarreau372ac5a2018-09-05 15:16:23 +02002446 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 +02002447 tmplog, dst + maxsize - tmplog);
2448 if (ret == NULL)
2449 goto out;
2450 tmplog = ret;
2451 last_isspace = 0;
2452 break;
2453
2454 case LOG_FMT_TT: // %Tt = total time
Willy Tarreaud79a3b22012-12-28 09:40:16 +01002455 if (!(fe->to_log & LW_BYTES))
William Lallemand1d705562012-03-12 12:46:41 +01002456 LOGCHAR('+');
Willy Tarreau372ac5a2018-09-05 15:16:23 +02002457 ret = ltoa_o(logs->t_close, tmplog, dst + maxsize - tmplog);
William Lallemand1d705562012-03-12 12:46:41 +01002458 if (ret == NULL)
William Lallemandbddd4fd2012-02-27 11:23:10 +01002459 goto out;
William Lallemand1d705562012-03-12 12:46:41 +01002460 tmplog = ret;
William Lallemandbddd4fd2012-02-27 11:23:10 +01002461 last_isspace = 0;
2462 break;
2463
Damien Claisse57c8eb92020-04-28 12:09:19 +00002464 case LOG_FMT_TU: // %Tu = total time seen by user = Tt - Ti
2465 if (!(fe->to_log & LW_BYTES))
2466 LOGCHAR('+');
2467 ret = ltoa_o(logs->t_close - (logs->t_idle >= 0 ? logs->t_idle : 0),
2468 tmplog, dst + maxsize - tmplog);
2469 if (ret == NULL)
2470 goto out;
2471 tmplog = ret;
2472 last_isspace = 0;
2473 break;
2474
Willy Tarreau2beef582012-12-20 17:22:52 +01002475 case LOG_FMT_STATUS: // %ST
Willy Tarreau57bc8912016-04-25 17:09:40 +02002476 ret = ltoa_o(txn ? txn->status : 0, tmplog, dst + maxsize - tmplog);
William Lallemand1d705562012-03-12 12:46:41 +01002477 if (ret == NULL)
William Lallemandbddd4fd2012-02-27 11:23:10 +01002478 goto out;
William Lallemand1d705562012-03-12 12:46:41 +01002479 tmplog = ret;
William Lallemandbddd4fd2012-02-27 11:23:10 +01002480 last_isspace = 0;
2481 break;
2482
William Lallemand1d705562012-03-12 12:46:41 +01002483 case LOG_FMT_BYTES: // %B
Willy Tarreaud79a3b22012-12-28 09:40:16 +01002484 if (!(fe->to_log & LW_BYTES))
William Lallemand1d705562012-03-12 12:46:41 +01002485 LOGCHAR('+');
Willy Tarreau372ac5a2018-09-05 15:16:23 +02002486 ret = lltoa(logs->bytes_out, tmplog, dst + maxsize - tmplog);
William Lallemand1d705562012-03-12 12:46:41 +01002487 if (ret == NULL)
William Lallemandbddd4fd2012-02-27 11:23:10 +01002488 goto out;
William Lallemand1d705562012-03-12 12:46:41 +01002489 tmplog = ret;
William Lallemandbddd4fd2012-02-27 11:23:10 +01002490 last_isspace = 0;
2491 break;
2492
Willy Tarreauc5259fd2012-12-20 15:38:04 +01002493 case LOG_FMT_BYTES_UP: // %U
Willy Tarreau372ac5a2018-09-05 15:16:23 +02002494 ret = lltoa(logs->bytes_in, tmplog, dst + maxsize - tmplog);
Willy Tarreauc5259fd2012-12-20 15:38:04 +01002495 if (ret == NULL)
2496 goto out;
2497 tmplog = ret;
2498 last_isspace = 0;
2499 break;
2500
Willy Tarreau2beef582012-12-20 17:22:52 +01002501 case LOG_FMT_CCLIENT: // %CC
Willy Tarreau57bc8912016-04-25 17:09:40 +02002502 src = txn ? txn->cli_cookie : NULL;
William Lallemand5f232402012-04-05 18:02:55 +02002503 ret = lf_text(tmplog, src, dst + maxsize - tmplog, tmp);
William Lallemand1d705562012-03-12 12:46:41 +01002504 if (ret == NULL)
William Lallemand51b5dca2012-03-26 17:52:55 +02002505 goto out;
William Lallemand1d705562012-03-12 12:46:41 +01002506 tmplog = ret;
William Lallemandbddd4fd2012-02-27 11:23:10 +01002507 last_isspace = 0;
2508 break;
2509
Willy Tarreau2beef582012-12-20 17:22:52 +01002510 case LOG_FMT_CSERVER: // %CS
Willy Tarreau57bc8912016-04-25 17:09:40 +02002511 src = txn ? txn->srv_cookie : NULL;
William Lallemand5f232402012-04-05 18:02:55 +02002512 ret = lf_text(tmplog, src, dst + maxsize - tmplog, tmp);
William Lallemand1d705562012-03-12 12:46:41 +01002513 if (ret == NULL)
William Lallemand51b5dca2012-03-26 17:52:55 +02002514 goto out;
William Lallemand1d705562012-03-12 12:46:41 +01002515 tmplog = ret;
William Lallemandbddd4fd2012-02-27 11:23:10 +01002516 last_isspace = 0;
2517 break;
2518
William Lallemand1d705562012-03-12 12:46:41 +01002519 case LOG_FMT_TERMSTATE: // %ts
Willy Tarreaub8bc5252018-09-05 15:51:28 +02002520 LOGCHAR(sess_term_cond[(s_flags & SF_ERR_MASK) >> SF_ERR_SHIFT]);
2521 LOGCHAR(sess_fin_state[(s_flags & SF_FINST_MASK) >> SF_FINST_SHIFT]);
Willy Tarreau6580c062012-03-12 15:09:42 +01002522 *tmplog = '\0';
2523 last_isspace = 0;
2524 break;
William Lallemandbddd4fd2012-02-27 11:23:10 +01002525
William Lallemand1d705562012-03-12 12:46:41 +01002526 case LOG_FMT_TERMSTATE_CK: // %tsc, same as TS with cookie state (for mode HTTP)
Willy Tarreaub8bc5252018-09-05 15:51:28 +02002527 LOGCHAR(sess_term_cond[(s_flags & SF_ERR_MASK) >> SF_ERR_SHIFT]);
2528 LOGCHAR(sess_fin_state[(s_flags & SF_FINST_MASK) >> SF_FINST_SHIFT]);
Willy Tarreau57bc8912016-04-25 17:09:40 +02002529 LOGCHAR((txn && (be->ck_opts & PR_CK_ANY)) ? sess_cookie[(txn->flags & TX_CK_MASK) >> TX_CK_SHIFT] : '-');
2530 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 +01002531 last_isspace = 0;
2532 break;
2533
William Lallemand1d705562012-03-12 12:46:41 +01002534 case LOG_FMT_ACTCONN: // %ac
William Lallemand5f232402012-04-05 18:02:55 +02002535 ret = ltoa_o(actconn, tmplog, dst + maxsize - tmplog);
William Lallemand1d705562012-03-12 12:46:41 +01002536 if (ret == NULL)
William Lallemandbddd4fd2012-02-27 11:23:10 +01002537 goto out;
William Lallemand1d705562012-03-12 12:46:41 +01002538 tmplog = ret;
William Lallemandbddd4fd2012-02-27 11:23:10 +01002539 last_isspace = 0;
2540 break;
2541
William Lallemand1d705562012-03-12 12:46:41 +01002542 case LOG_FMT_FECONN: // %fc
William Lallemand5f232402012-04-05 18:02:55 +02002543 ret = ltoa_o(fe->feconn, tmplog, dst + maxsize - tmplog);
William Lallemand1d705562012-03-12 12:46:41 +01002544 if (ret == NULL)
William Lallemandbddd4fd2012-02-27 11:23:10 +01002545 goto out;
William Lallemand1d705562012-03-12 12:46:41 +01002546 tmplog = ret;
William Lallemandbddd4fd2012-02-27 11:23:10 +01002547 last_isspace = 0;
2548 break;
2549
William Lallemand1d705562012-03-12 12:46:41 +01002550 case LOG_FMT_BECONN: // %bc
William Lallemand5f232402012-04-05 18:02:55 +02002551 ret = ltoa_o(be->beconn, tmplog, dst + maxsize - tmplog);
William Lallemand1d705562012-03-12 12:46:41 +01002552 if (ret == NULL)
William Lallemandbddd4fd2012-02-27 11:23:10 +01002553 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_SRVCONN: // %sc
Willy Tarreaue1809df2018-09-05 15:30:16 +02002559 ret = ultoa_o(objt_server(s ? s->target : NULL) ?
Willy Tarreau3fdb3662012-11-12 00:42:33 +01002560 objt_server(s->target)->cur_sess :
William Lallemand5f232402012-04-05 18:02:55 +02002561 0, tmplog, dst + maxsize - tmplog);
William Lallemand1d705562012-03-12 12:46:41 +01002562 if (ret == NULL)
William Lallemandbddd4fd2012-02-27 11:23:10 +01002563 goto out;
William Lallemand1d705562012-03-12 12:46:41 +01002564 tmplog = ret;
William Lallemandbddd4fd2012-02-27 11:23:10 +01002565 last_isspace = 0;
2566 break;
2567
William Lallemand1d705562012-03-12 12:46:41 +01002568 case LOG_FMT_RETRIES: // %rq
Willy Tarreaub8bc5252018-09-05 15:51:28 +02002569 if (s_flags & SF_REDISP)
William Lallemand1d705562012-03-12 12:46:41 +01002570 LOGCHAR('+');
Willy Tarreauabd71a52018-09-04 19:21:44 +02002571 ret = ltoa_o((s && s->si[1].conn_retries > 0) ?
Willy Tarreau350f4872014-11-28 14:42:25 +01002572 (be->conn_retries - s->si[1].conn_retries) :
William Lallemand5f232402012-04-05 18:02:55 +02002573 be->conn_retries, tmplog, dst + maxsize - tmplog);
William Lallemand1d705562012-03-12 12:46:41 +01002574 if (ret == NULL)
William Lallemand51b5dca2012-03-26 17:52:55 +02002575 goto out;
William Lallemand1d705562012-03-12 12:46:41 +01002576 tmplog = ret;
William Lallemandbddd4fd2012-02-27 11:23:10 +01002577 last_isspace = 0;
2578 break;
2579
William Lallemand1d705562012-03-12 12:46:41 +01002580 case LOG_FMT_SRVQUEUE: // %sq
Willy Tarreau372ac5a2018-09-05 15:16:23 +02002581 ret = ltoa_o(logs->srv_queue_pos, tmplog, dst + maxsize - tmplog);
William Lallemand1d705562012-03-12 12:46:41 +01002582 if (ret == NULL)
William Lallemandbddd4fd2012-02-27 11:23:10 +01002583 goto out;
William Lallemand1d705562012-03-12 12:46:41 +01002584 tmplog = ret;
William Lallemandbddd4fd2012-02-27 11:23:10 +01002585 last_isspace = 0;
2586 break;
2587
William Lallemand1d705562012-03-12 12:46:41 +01002588 case LOG_FMT_BCKQUEUE: // %bq
Willy Tarreau372ac5a2018-09-05 15:16:23 +02002589 ret = ltoa_o(logs->prx_queue_pos, tmplog, dst + maxsize - tmplog);
William Lallemand1d705562012-03-12 12:46:41 +01002590 if (ret == NULL)
William Lallemandbddd4fd2012-02-27 11:23:10 +01002591 goto out;
William Lallemand1d705562012-03-12 12:46:41 +01002592 tmplog = ret;
William Lallemandbddd4fd2012-02-27 11:23:10 +01002593 last_isspace = 0;
2594 break;
2595
William Lallemand1d705562012-03-12 12:46:41 +01002596 case LOG_FMT_HDRREQUEST: // %hr
William Lallemandbddd4fd2012-02-27 11:23:10 +01002597 /* request header */
Willy Tarreaud4f91662018-09-05 15:28:07 +02002598 if (fe->nb_req_cap && s && s->req_cap) {
William Lallemandbddd4fd2012-02-27 11:23:10 +01002599 if (tmp->options & LOG_OPT_QUOTE)
2600 LOGCHAR('"');
2601 LOGCHAR('{');
2602 for (hdr = 0; hdr < fe->nb_req_cap; hdr++) {
2603 if (hdr)
2604 LOGCHAR('|');
Willy Tarreaucb7dd012015-04-03 22:16:32 +02002605 if (s->req_cap[hdr] != NULL) {
Dragan Dosen835b9212016-02-12 13:23:03 +01002606 ret = lf_encode_string(tmplog, dst + maxsize,
2607 '#', hdr_encode_map, s->req_cap[hdr], tmp);
William Lallemand1d705562012-03-12 12:46:41 +01002608 if (ret == NULL || *ret != '\0')
William Lallemand51b5dca2012-03-26 17:52:55 +02002609 goto out;
William Lallemand1d705562012-03-12 12:46:41 +01002610 tmplog = ret;
William Lallemand51b5dca2012-03-26 17:52:55 +02002611 }
William Lallemandbddd4fd2012-02-27 11:23:10 +01002612 }
2613 LOGCHAR('}');
William Lallemand51b5dca2012-03-26 17:52:55 +02002614 if (tmp->options & LOG_OPT_QUOTE)
2615 LOGCHAR('"');
William Lallemandbddd4fd2012-02-27 11:23:10 +01002616 last_isspace = 0;
2617 }
William Lallemandbddd4fd2012-02-27 11:23:10 +01002618 break;
2619
William Lallemand1d705562012-03-12 12:46:41 +01002620 case LOG_FMT_HDRREQUESTLIST: // %hrl
William Lallemandbddd4fd2012-02-27 11:23:10 +01002621 /* request header list */
Willy Tarreaud4f91662018-09-05 15:28:07 +02002622 if (fe->nb_req_cap && s && s->req_cap) {
William Lallemandbddd4fd2012-02-27 11:23:10 +01002623 for (hdr = 0; hdr < fe->nb_req_cap; hdr++) {
2624 if (hdr > 0)
2625 LOGCHAR(' ');
2626 if (tmp->options & LOG_OPT_QUOTE)
2627 LOGCHAR('"');
Willy Tarreaucb7dd012015-04-03 22:16:32 +02002628 if (s->req_cap[hdr] != NULL) {
Dragan Dosen835b9212016-02-12 13:23:03 +01002629 ret = lf_encode_string(tmplog, dst + maxsize,
2630 '#', hdr_encode_map, s->req_cap[hdr], tmp);
William Lallemand1d705562012-03-12 12:46:41 +01002631 if (ret == NULL || *ret != '\0')
William Lallemand51b5dca2012-03-26 17:52:55 +02002632 goto out;
William Lallemand1d705562012-03-12 12:46:41 +01002633 tmplog = ret;
William Lallemandbddd4fd2012-02-27 11:23:10 +01002634 } else if (!(tmp->options & LOG_OPT_QUOTE))
2635 LOGCHAR('-');
2636 if (tmp->options & LOG_OPT_QUOTE)
2637 LOGCHAR('"');
William Lallemandbddd4fd2012-02-27 11:23:10 +01002638 last_isspace = 0;
2639 }
2640 }
2641 break;
Willy Tarreaubaaee002006-06-26 02:48:02 +02002642
William Lallemand1d705562012-03-12 12:46:41 +01002643
2644 case LOG_FMT_HDRRESPONS: // %hs
William Lallemandbddd4fd2012-02-27 11:23:10 +01002645 /* response header */
Willy Tarreaud4f91662018-09-05 15:28:07 +02002646 if (fe->nb_rsp_cap && s && s->res_cap) {
William Lallemandbddd4fd2012-02-27 11:23:10 +01002647 if (tmp->options & LOG_OPT_QUOTE)
2648 LOGCHAR('"');
2649 LOGCHAR('{');
2650 for (hdr = 0; hdr < fe->nb_rsp_cap; hdr++) {
2651 if (hdr)
2652 LOGCHAR('|');
Willy Tarreaucb7dd012015-04-03 22:16:32 +02002653 if (s->res_cap[hdr] != NULL) {
Dragan Dosen835b9212016-02-12 13:23:03 +01002654 ret = lf_encode_string(tmplog, dst + maxsize,
2655 '#', hdr_encode_map, s->res_cap[hdr], tmp);
William Lallemand1d705562012-03-12 12:46:41 +01002656 if (ret == NULL || *ret != '\0')
William Lallemand51b5dca2012-03-26 17:52:55 +02002657 goto out;
William Lallemand1d705562012-03-12 12:46:41 +01002658 tmplog = ret;
William Lallemand51b5dca2012-03-26 17:52:55 +02002659 }
William Lallemandbddd4fd2012-02-27 11:23:10 +01002660 }
2661 LOGCHAR('}');
2662 last_isspace = 0;
2663 if (tmp->options & LOG_OPT_QUOTE)
2664 LOGCHAR('"');
2665 }
William Lallemandbddd4fd2012-02-27 11:23:10 +01002666 break;
2667
William Lallemand1d705562012-03-12 12:46:41 +01002668 case LOG_FMT_HDRRESPONSLIST: // %hsl
William Lallemandbddd4fd2012-02-27 11:23:10 +01002669 /* response header list */
Willy Tarreaud4f91662018-09-05 15:28:07 +02002670 if (fe->nb_rsp_cap && s && s->res_cap) {
William Lallemandbddd4fd2012-02-27 11:23:10 +01002671 for (hdr = 0; hdr < fe->nb_rsp_cap; hdr++) {
2672 if (hdr > 0)
2673 LOGCHAR(' ');
2674 if (tmp->options & LOG_OPT_QUOTE)
2675 LOGCHAR('"');
Willy Tarreaucb7dd012015-04-03 22:16:32 +02002676 if (s->res_cap[hdr] != NULL) {
Dragan Dosen835b9212016-02-12 13:23:03 +01002677 ret = lf_encode_string(tmplog, dst + maxsize,
2678 '#', hdr_encode_map, s->res_cap[hdr], tmp);
William Lallemand1d705562012-03-12 12:46:41 +01002679 if (ret == NULL || *ret != '\0')
William Lallemand51b5dca2012-03-26 17:52:55 +02002680 goto out;
William Lallemand1d705562012-03-12 12:46:41 +01002681 tmplog = ret;
William Lallemandbddd4fd2012-02-27 11:23:10 +01002682 } else if (!(tmp->options & LOG_OPT_QUOTE))
2683 LOGCHAR('-');
2684 if (tmp->options & LOG_OPT_QUOTE)
2685 LOGCHAR('"');
William Lallemandbddd4fd2012-02-27 11:23:10 +01002686 last_isspace = 0;
2687 }
2688 }
2689 break;
2690
William Lallemand1d705562012-03-12 12:46:41 +01002691 case LOG_FMT_REQ: // %r
William Lallemandbddd4fd2012-02-27 11:23:10 +01002692 /* Request */
2693 if (tmp->options & LOG_OPT_QUOTE)
2694 LOGCHAR('"');
Willy Tarreau57bc8912016-04-25 17:09:40 +02002695 uri = txn && txn->uri ? txn->uri : "<BADREQ>";
Dragan Dosen835b9212016-02-12 13:23:03 +01002696 ret = lf_encode_string(tmplog, dst + maxsize,
2697 '#', url_encode_map, uri, tmp);
William Lallemand1d705562012-03-12 12:46:41 +01002698 if (ret == NULL || *ret != '\0')
William Lallemand51b5dca2012-03-26 17:52:55 +02002699 goto out;
William Lallemand1d705562012-03-12 12:46:41 +01002700 tmplog = ret;
William Lallemandbddd4fd2012-02-27 11:23:10 +01002701 if (tmp->options & LOG_OPT_QUOTE)
2702 LOGCHAR('"');
William Lallemandbddd4fd2012-02-27 11:23:10 +01002703 last_isspace = 0;
2704 break;
William Lallemand5f232402012-04-05 18:02:55 +02002705
Andrew Hayworth0ebc55f2015-04-27 21:37:03 +00002706 case LOG_FMT_HTTP_PATH: // %HP
Willy Tarreau57bc8912016-04-25 17:09:40 +02002707 uri = txn && txn->uri ? txn->uri : "<BADREQ>";
Andrew Hayworth0ebc55f2015-04-27 21:37:03 +00002708
Willy Tarreaub7636d12015-06-17 19:58:02 +02002709 if (tmp->options & LOG_OPT_QUOTE)
Andrew Hayworth0ebc55f2015-04-27 21:37:03 +00002710 LOGCHAR('"');
2711
2712 end = uri + strlen(uri);
2713 // look for the first whitespace character
2714 while (uri < end && !HTTP_IS_SPHT(*uri))
2715 uri++;
2716
2717 // keep advancing past multiple spaces
2718 while (uri < end && HTTP_IS_SPHT(*uri)) {
2719 uri++; nspaces++;
2720 }
2721
2722 // look for first space or question mark after url
2723 spc = uri;
2724 while (spc < end && *spc != '?' && !HTTP_IS_SPHT(*spc))
2725 spc++;
2726
Nenad Merdanovic54e439f2016-04-26 01:39:02 +02002727 if (!txn || !txn->uri || nspaces == 0) {
Willy Tarreau843b7cb2018-07-13 10:54:26 +02002728 chunk.area = "<BADREQ>";
2729 chunk.data = strlen("<BADREQ>");
Andrew Hayworth0ebc55f2015-04-27 21:37:03 +00002730 } else {
Willy Tarreau843b7cb2018-07-13 10:54:26 +02002731 chunk.area = uri;
2732 chunk.data = spc - uri;
Andrew Hayworth0ebc55f2015-04-27 21:37:03 +00002733 }
2734
Dragan Dosen835b9212016-02-12 13:23:03 +01002735 ret = lf_encode_chunk(tmplog, dst + maxsize, '#', url_encode_map, &chunk, tmp);
Andrew Hayworth0ebc55f2015-04-27 21:37:03 +00002736 if (ret == NULL || *ret != '\0')
2737 goto out;
2738
2739 tmplog = ret;
Willy Tarreaub7636d12015-06-17 19:58:02 +02002740 if (tmp->options & LOG_OPT_QUOTE)
Andrew Hayworth0ebc55f2015-04-27 21:37:03 +00002741 LOGCHAR('"');
2742
2743 last_isspace = 0;
2744 break;
2745
Andrew Hayworthe63ac872015-07-31 16:14:16 +00002746 case LOG_FMT_HTTP_QUERY: // %HQ
2747 if (tmp->options & LOG_OPT_QUOTE)
2748 LOGCHAR('"');
2749
Willy Tarreau57bc8912016-04-25 17:09:40 +02002750 if (!txn || !txn->uri) {
Willy Tarreau843b7cb2018-07-13 10:54:26 +02002751 chunk.area = "<BADREQ>";
2752 chunk.data = strlen("<BADREQ>");
Andrew Hayworthe63ac872015-07-31 16:14:16 +00002753 } else {
2754 uri = txn->uri;
2755 end = uri + strlen(uri);
2756 // look for the first question mark
2757 while (uri < end && *uri != '?')
2758 uri++;
2759
2760 qmark = uri;
2761 // look for first space or question mark after url
2762 while (uri < end && !HTTP_IS_SPHT(*uri))
2763 uri++;
2764
Willy Tarreau843b7cb2018-07-13 10:54:26 +02002765 chunk.area = qmark;
2766 chunk.data = uri - qmark;
Andrew Hayworthe63ac872015-07-31 16:14:16 +00002767 }
2768
Dragan Dosen835b9212016-02-12 13:23:03 +01002769 ret = lf_encode_chunk(tmplog, dst + maxsize, '#', url_encode_map, &chunk, tmp);
Andrew Hayworthe63ac872015-07-31 16:14:16 +00002770 if (ret == NULL || *ret != '\0')
2771 goto out;
2772
2773 tmplog = ret;
2774 if (tmp->options & LOG_OPT_QUOTE)
2775 LOGCHAR('"');
2776
2777 last_isspace = 0;
2778 break;
2779
Andrew Hayworth0ebc55f2015-04-27 21:37:03 +00002780 case LOG_FMT_HTTP_URI: // %HU
Willy Tarreau57bc8912016-04-25 17:09:40 +02002781 uri = txn && txn->uri ? txn->uri : "<BADREQ>";
Andrew Hayworth0ebc55f2015-04-27 21:37:03 +00002782
Willy Tarreaub7636d12015-06-17 19:58:02 +02002783 if (tmp->options & LOG_OPT_QUOTE)
Andrew Hayworth0ebc55f2015-04-27 21:37:03 +00002784 LOGCHAR('"');
2785
2786 end = uri + strlen(uri);
2787 // look for the first whitespace character
2788 while (uri < end && !HTTP_IS_SPHT(*uri))
2789 uri++;
2790
2791 // keep advancing past multiple spaces
2792 while (uri < end && HTTP_IS_SPHT(*uri)) {
2793 uri++; nspaces++;
2794 }
2795
2796 // look for first space after url
2797 spc = uri;
2798 while (spc < end && !HTTP_IS_SPHT(*spc))
2799 spc++;
2800
Willy Tarreau57bc8912016-04-25 17:09:40 +02002801 if (!txn || !txn->uri || nspaces == 0) {
Willy Tarreau843b7cb2018-07-13 10:54:26 +02002802 chunk.area = "<BADREQ>";
2803 chunk.data = strlen("<BADREQ>");
Andrew Hayworth0ebc55f2015-04-27 21:37:03 +00002804 } else {
Willy Tarreau843b7cb2018-07-13 10:54:26 +02002805 chunk.area = uri;
2806 chunk.data = spc - uri;
Andrew Hayworth0ebc55f2015-04-27 21:37:03 +00002807 }
2808
Dragan Dosen835b9212016-02-12 13:23:03 +01002809 ret = lf_encode_chunk(tmplog, dst + maxsize, '#', url_encode_map, &chunk, tmp);
Andrew Hayworth0ebc55f2015-04-27 21:37:03 +00002810 if (ret == NULL || *ret != '\0')
2811 goto out;
2812
2813 tmplog = ret;
Willy Tarreaub7636d12015-06-17 19:58:02 +02002814 if (tmp->options & LOG_OPT_QUOTE)
Andrew Hayworth0ebc55f2015-04-27 21:37:03 +00002815 LOGCHAR('"');
2816
2817 last_isspace = 0;
2818 break;
2819
2820 case LOG_FMT_HTTP_METHOD: // %HM
Willy Tarreau57bc8912016-04-25 17:09:40 +02002821 uri = txn && txn->uri ? txn->uri : "<BADREQ>";
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 end = uri + strlen(uri);
2826 // look for the first whitespace character
2827 spc = uri;
2828 while (spc < end && !HTTP_IS_SPHT(*spc))
2829 spc++;
2830
2831 if (spc == end) { // odd case, we have txn->uri, but we only got a verb
Willy Tarreau843b7cb2018-07-13 10:54:26 +02002832 chunk.area = "<BADREQ>";
2833 chunk.data = strlen("<BADREQ>");
Andrew Hayworth0ebc55f2015-04-27 21:37:03 +00002834 } else {
Willy Tarreau843b7cb2018-07-13 10:54:26 +02002835 chunk.area = uri;
2836 chunk.data = spc - uri;
Andrew Hayworth0ebc55f2015-04-27 21:37:03 +00002837 }
2838
Dragan Dosen835b9212016-02-12 13:23:03 +01002839 ret = lf_encode_chunk(tmplog, dst + maxsize, '#', url_encode_map, &chunk, tmp);
Andrew Hayworth0ebc55f2015-04-27 21:37:03 +00002840 if (ret == NULL || *ret != '\0')
2841 goto out;
2842
2843 tmplog = ret;
Willy Tarreaub7636d12015-06-17 19:58:02 +02002844 if (tmp->options & LOG_OPT_QUOTE)
Andrew Hayworth0ebc55f2015-04-27 21:37:03 +00002845 LOGCHAR('"');
2846
2847 last_isspace = 0;
2848 break;
2849
2850 case LOG_FMT_HTTP_VERSION: // %HV
Willy Tarreau57bc8912016-04-25 17:09:40 +02002851 uri = txn && txn->uri ? txn->uri : "<BADREQ>";
Willy Tarreaub7636d12015-06-17 19:58:02 +02002852 if (tmp->options & LOG_OPT_QUOTE)
Andrew Hayworth0ebc55f2015-04-27 21:37:03 +00002853 LOGCHAR('"');
2854
2855 end = uri + strlen(uri);
2856 // look for the first whitespace character
2857 while (uri < end && !HTTP_IS_SPHT(*uri))
2858 uri++;
2859
2860 // keep advancing past multiple spaces
2861 while (uri < end && HTTP_IS_SPHT(*uri)) {
2862 uri++; nspaces++;
2863 }
2864
2865 // look for the next whitespace character
2866 while (uri < end && !HTTP_IS_SPHT(*uri))
2867 uri++;
2868
2869 // keep advancing past multiple spaces
2870 while (uri < end && HTTP_IS_SPHT(*uri))
2871 uri++;
2872
Willy Tarreau57bc8912016-04-25 17:09:40 +02002873 if (!txn || !txn->uri || nspaces == 0) {
Willy Tarreau843b7cb2018-07-13 10:54:26 +02002874 chunk.area = "<BADREQ>";
2875 chunk.data = strlen("<BADREQ>");
Andrew Hayworth0ebc55f2015-04-27 21:37:03 +00002876 } else if (uri == end) {
Willy Tarreau843b7cb2018-07-13 10:54:26 +02002877 chunk.area = "HTTP/0.9";
2878 chunk.data = strlen("HTTP/0.9");
Andrew Hayworth0ebc55f2015-04-27 21:37:03 +00002879 } else {
Willy Tarreau843b7cb2018-07-13 10:54:26 +02002880 chunk.area = uri;
2881 chunk.data = end - uri;
Andrew Hayworth0ebc55f2015-04-27 21:37:03 +00002882 }
2883
Dragan Dosen835b9212016-02-12 13:23:03 +01002884 ret = lf_encode_chunk(tmplog, dst + maxsize, '#', url_encode_map, &chunk, tmp);
Andrew Hayworth0ebc55f2015-04-27 21:37:03 +00002885 if (ret == NULL || *ret != '\0')
2886 goto out;
2887
2888 tmplog = ret;
Willy Tarreaub7636d12015-06-17 19:58:02 +02002889 if (tmp->options & LOG_OPT_QUOTE)
Andrew Hayworth0ebc55f2015-04-27 21:37:03 +00002890 LOGCHAR('"');
2891
2892 last_isspace = 0;
2893 break;
2894
William Lallemand5f232402012-04-05 18:02:55 +02002895 case LOG_FMT_COUNTER: // %rt
2896 if (tmp->options & LOG_OPT_HEXA) {
Willy Tarreau5cacab62018-09-05 15:52:59 +02002897 iret = snprintf(tmplog, dst + maxsize - tmplog, "%04X", uniq_id);
William Lallemand5f232402012-04-05 18:02:55 +02002898 if (iret < 0 || iret > dst + maxsize - tmplog)
2899 goto out;
2900 last_isspace = 0;
2901 tmplog += iret;
2902 } else {
Willy Tarreau5cacab62018-09-05 15:52:59 +02002903 ret = ltoa_o(uniq_id, tmplog, dst + maxsize - tmplog);
William Lallemand5f232402012-04-05 18:02:55 +02002904 if (ret == NULL)
2905 goto out;
2906 tmplog = ret;
2907 last_isspace = 0;
2908 }
2909 break;
2910
Willy Tarreau7346acb2014-08-28 15:03:15 +02002911 case LOG_FMT_LOGCNT: // %lc
2912 if (tmp->options & LOG_OPT_HEXA) {
Willy Tarreaue36cbcb2015-04-03 15:40:56 +02002913 iret = snprintf(tmplog, dst + maxsize - tmplog, "%04X", fe->log_count);
Willy Tarreau7346acb2014-08-28 15:03:15 +02002914 if (iret < 0 || iret > dst + maxsize - tmplog)
2915 goto out;
2916 last_isspace = 0;
2917 tmplog += iret;
2918 } else {
Willy Tarreaue36cbcb2015-04-03 15:40:56 +02002919 ret = ultoa_o(fe->log_count, tmplog, dst + maxsize - tmplog);
Willy Tarreau7346acb2014-08-28 15:03:15 +02002920 if (ret == NULL)
2921 goto out;
2922 tmplog = ret;
2923 last_isspace = 0;
2924 }
2925 break;
2926
William Lallemand5f232402012-04-05 18:02:55 +02002927 case LOG_FMT_HOSTNAME: // %H
2928 src = hostname;
2929 ret = lf_text(tmplog, src, dst + maxsize - tmplog, tmp);
2930 if (ret == NULL)
2931 goto out;
2932 tmplog = ret;
2933 last_isspace = 0;
2934 break;
2935
2936 case LOG_FMT_PID: // %pid
2937 if (tmp->options & LOG_OPT_HEXA) {
2938 iret = snprintf(tmplog, dst + maxsize - tmplog, "%04X", pid);
2939 if (iret < 0 || iret > dst + maxsize - tmplog)
2940 goto out;
2941 last_isspace = 0;
2942 tmplog += iret;
2943 } else {
2944 ret = ltoa_o(pid, tmplog, dst + maxsize - tmplog);
2945 if (ret == NULL)
2946 goto out;
2947 tmplog = ret;
2948 last_isspace = 0;
2949 }
2950 break;
William Lallemanda73203e2012-03-12 12:48:57 +01002951
2952 case LOG_FMT_UNIQUEID: // %ID
William Lallemand5b7ea3a2013-08-28 15:44:19 +02002953 ret = NULL;
Tim Duesterhusa17e6622020-03-05 20:19:02 +01002954 if (s)
2955 ret = lf_text_len(tmplog, s->unique_id.ptr, s->unique_id.len, maxsize - (tmplog - dst), tmp);
2956 else
2957 ret = lf_text_len(tmplog, NULL, 0, maxsize - (tmplog - dst), tmp);
William Lallemanda73203e2012-03-12 12:48:57 +01002958 if (ret == NULL)
2959 goto out;
2960 tmplog = ret;
2961 last_isspace = 0;
2962 break;
2963
William Lallemandbddd4fd2012-02-27 11:23:10 +01002964 }
2965 }
2966
2967out:
William Lallemand1d705562012-03-12 12:46:41 +01002968 /* *tmplog is a unused character */
2969 *tmplog = '\0';
Willy Tarreaudf974472012-12-28 02:44:01 +01002970 return tmplog - dst;
William Lallemandbddd4fd2012-02-27 11:23:10 +01002971
Willy Tarreaubaaee002006-06-26 02:48:02 +02002972}
2973
William Lallemand1d705562012-03-12 12:46:41 +01002974/*
Willy Tarreau87b09662015-04-03 00:22:06 +02002975 * send a log for the stream when we have enough info about it.
William Lallemand1d705562012-03-12 12:46:41 +01002976 * Will not log if the frontend has no log defined.
2977 */
Willy Tarreau87b09662015-04-03 00:22:06 +02002978void strm_log(struct stream *s)
William Lallemand1d705562012-03-12 12:46:41 +01002979{
Willy Tarreaue36cbcb2015-04-03 15:40:56 +02002980 struct session *sess = s->sess;
William Lallemand1d705562012-03-12 12:46:41 +01002981 int size, err, level;
Dragan Dosen0b85ece2015-09-25 19:17:44 +02002982 int sd_size = 0;
William Lallemand1d705562012-03-12 12:46:41 +01002983
2984 /* if we don't want to log normal traffic, return now */
Willy Tarreaue7dff022015-04-03 01:14:29 +02002985 err = (s->flags & SF_REDISP) ||
2986 ((s->flags & SF_ERR_MASK) > SF_ERR_LOCAL) ||
2987 (((s->flags & SF_ERR_MASK) == SF_ERR_NONE) &&
Willy Tarreau350f4872014-11-28 14:42:25 +01002988 (s->si[1].conn_retries != s->be->conn_retries)) ||
Willy Tarreaueee5b512015-04-03 23:46:31 +02002989 ((sess->fe->mode == PR_MODE_HTTP) && s->txn && s->txn->status >= 500);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002990
Willy Tarreaue36cbcb2015-04-03 15:40:56 +02002991 if (!err && (sess->fe->options2 & PR_O2_NOLOGNORM))
William Lallemand1d705562012-03-12 12:46:41 +01002992 return;
William Lallemandbddd4fd2012-02-27 11:23:10 +01002993
Willy Tarreaue36cbcb2015-04-03 15:40:56 +02002994 if (LIST_ISEMPTY(&sess->fe->logsrvs))
William Lallemand1d705562012-03-12 12:46:41 +01002995 return;
William Lallemandbddd4fd2012-02-27 11:23:10 +01002996
Willy Tarreauabcd5142013-06-11 17:18:02 +02002997 if (s->logs.level) { /* loglevel was overridden */
2998 if (s->logs.level == -1) {
2999 s->logs.logwait = 0; /* logs disabled */
3000 return;
3001 }
3002 level = s->logs.level - 1;
3003 }
3004 else {
3005 level = LOG_INFO;
Willy Tarreaue36cbcb2015-04-03 15:40:56 +02003006 if (err && (sess->fe->options2 & PR_O2_LOGERRORS))
Willy Tarreauabcd5142013-06-11 17:18:02 +02003007 level = LOG_ERR;
3008 }
William Lallemand1d705562012-03-12 12:46:41 +01003009
William Lallemand5b7ea3a2013-08-28 15:44:19 +02003010 /* if unique-id was not generated */
Tim Duesterhusa17e6622020-03-05 20:19:02 +01003011 if (!isttest(s->unique_id) && !LIST_ISEMPTY(&sess->fe->format_unique_id)) {
Tim Duesterhus2825b4b2020-02-28 15:13:34 +01003012 stream_generate_unique_id(s, &sess->fe->format_unique_id);
William Lallemand5b7ea3a2013-08-28 15:44:19 +02003013 }
3014
Dragan Dosen0b85ece2015-09-25 19:17:44 +02003015 if (!LIST_ISEMPTY(&sess->fe->logformat_sd)) {
3016 sd_size = build_logline(s, logline_rfc5424, global.max_syslog_len,
3017 &sess->fe->logformat_sd);
3018 }
3019
Dragan Dosen59cee972015-09-19 22:09:02 +02003020 size = build_logline(s, logline, global.max_syslog_len, &sess->fe->logformat);
William Lallemand1d705562012-03-12 12:46:41 +01003021 if (size > 0) {
Olivier Houchardd2ee3e72019-03-08 18:53:21 +01003022 _HA_ATOMIC_ADD(&sess->fe->log_count, 1);
Christopher Faulet5c6fefc2019-08-11 19:40:12 +02003023 __send_log(&sess->fe->logsrvs, &sess->fe->log_tag, level,
3024 logline, size + 1, logline_rfc5424, sd_size);
William Lallemand1d705562012-03-12 12:46:41 +01003025 s->logs.logwait = 0;
3026 }
3027}
William Lallemandbddd4fd2012-02-27 11:23:10 +01003028
Willy Tarreau53839352018-09-05 19:51:10 +02003029/*
3030 * send a minimalist log for the session. Will not log if the frontend has no
3031 * log defined. It is assumed that this is only used to report anomalies that
3032 * cannot lead to the creation of a regular stream. Because of this the log
3033 * level is LOG_INFO or LOG_ERR depending on the "log-separate-error" setting
3034 * in the frontend. The caller must simply know that it should not call this
Willy Tarreau9fa267d2018-10-05 10:22:27 +02003035 * function to report unimportant events. It is safe to call this function with
3036 * sess==NULL (will not do anything).
Willy Tarreau53839352018-09-05 19:51:10 +02003037 */
3038void sess_log(struct session *sess)
3039{
3040 int size, level;
3041 int sd_size = 0;
3042
Willy Tarreau9fa267d2018-10-05 10:22:27 +02003043 if (!sess)
3044 return;
3045
Willy Tarreau53839352018-09-05 19:51:10 +02003046 if (LIST_ISEMPTY(&sess->fe->logsrvs))
3047 return;
3048
3049 level = LOG_INFO;
3050 if (sess->fe->options2 & PR_O2_LOGERRORS)
3051 level = LOG_ERR;
3052
3053 if (!LIST_ISEMPTY(&sess->fe->logformat_sd)) {
3054 sd_size = sess_build_logline(sess, NULL,
3055 logline_rfc5424, global.max_syslog_len,
3056 &sess->fe->logformat_sd);
3057 }
3058
3059 size = sess_build_logline(sess, NULL, logline, global.max_syslog_len, &sess->fe->logformat);
3060 if (size > 0) {
Olivier Houchardd2ee3e72019-03-08 18:53:21 +01003061 _HA_ATOMIC_ADD(&sess->fe->log_count, 1);
Christopher Faulet5c6fefc2019-08-11 19:40:12 +02003062 __send_log(&sess->fe->logsrvs, &sess->fe->log_tag, level,
3063 logline, size + 1, logline_rfc5424, sd_size);
Willy Tarreau53839352018-09-05 19:51:10 +02003064 }
3065}
3066
Christopher Faulet5c6fefc2019-08-11 19:40:12 +02003067void app_log(struct list *logsrvs, struct buffer *tag, int level, const char *format, ...)
3068{
3069 va_list argp;
3070 int data_len;
3071
3072 if (level < 0 || format == NULL || logline == NULL)
3073 return;
3074
3075 va_start(argp, format);
3076 data_len = vsnprintf(logline, global.max_syslog_len, format, argp);
3077 if (data_len < 0 || data_len > global.max_syslog_len)
3078 data_len = global.max_syslog_len;
3079 va_end(argp);
3080
3081 __send_log(logsrvs, tag, level, logline, data_len, default_rfc5424_sd_log_format, 2);
3082}
3083
Willy Tarreau869efd52019-11-15 15:16:57 +01003084/* parse the "show startup-logs" command, returns 1 if a message is returned, otherwise zero */
3085static int cli_parse_show_startup_logs(char **args, char *payload, struct appctx *appctx, void *private)
Christopher Fauletc1b730a2017-10-24 12:00:51 +02003086{
Willy Tarreau869efd52019-11-15 15:16:57 +01003087 if (!cli_has_level(appctx, ACCESS_LVL_OPER))
3088 return 1;
Christopher Fauletc1b730a2017-10-24 12:00:51 +02003089
Willy Tarreau869efd52019-11-15 15:16:57 +01003090 if (!startup_logs)
3091 return cli_msg(appctx, LOG_INFO, "\n"); // nothing to print
3092
3093 return ring_attach_cli(startup_logs, appctx);
Christopher Fauletc1b730a2017-10-24 12:00:51 +02003094}
3095
3096/* register cli keywords */
3097static struct cli_kw_list cli_kws = {{ },{
3098 { { "show", "startup-logs", NULL },
Willy Tarreau869efd52019-11-15 15:16:57 +01003099 "show startup-logs : report logs emitted during HAProxy startup", cli_parse_show_startup_logs, NULL, NULL },
Christopher Fauletc1b730a2017-10-24 12:00:51 +02003100 {{},}
3101}};
3102
Willy Tarreau0108d902018-11-25 19:14:37 +01003103INITCALL1(STG_REGISTER, cli_register_kw, &cli_kws);
3104
Willy Tarreau082b6282019-05-22 14:42:12 +02003105REGISTER_PER_THREAD_ALLOC(init_log_buffers);
3106REGISTER_PER_THREAD_FREE(deinit_log_buffers);
Willy Tarreau172f5ce2018-11-26 11:21:50 +01003107
Willy Tarreaubaaee002006-06-26 02:48:02 +02003108/*
3109 * Local variables:
3110 * c-indent-level: 8
3111 * c-basic-offset: 8
3112 * End:
3113 */