blob: c2153b84a8b215bff505c7f736aba63e6e5cb76f [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 */
Willy Tarreau2beef582012-12-20 17:22:52 +0100155 { "Tw", LOG_FMT_TW, PR_MODE_TCP, LW_BYTES, NULL }, /* Tw */
156 { "U", LOG_FMT_BYTES_UP, PR_MODE_TCP, LW_BYTES, NULL }, /* bytes from client to server */
William Lallemand5e19a282012-04-02 16:22:10 +0200157 { "ac", LOG_FMT_ACTCONN, PR_MODE_TCP, LW_BYTES, NULL }, /* actconn */
Willy Tarreau2beef582012-12-20 17:22:52 +0100158 { "b", LOG_FMT_BACKEND, PR_MODE_TCP, LW_INIT, NULL }, /* backend */
William Lallemand5e19a282012-04-02 16:22:10 +0200159 { "bc", LOG_FMT_BECONN, PR_MODE_TCP, LW_BYTES, NULL }, /* beconn */
Willy Tarreau2beef582012-12-20 17:22:52 +0100160 { "bi", LOG_FMT_BACKENDIP, PR_MODE_TCP, LW_BCKIP, prepare_addrsource }, /* backend source ip */
161 { "bp", LOG_FMT_BACKENDPORT, PR_MODE_TCP, LW_BCKIP, prepare_addrsource }, /* backend source port */
William Lallemand5e19a282012-04-02 16:22:10 +0200162 { "bq", LOG_FMT_BCKQUEUE, PR_MODE_TCP, LW_BYTES, NULL }, /* backend_queue */
Willy Tarreaud02286d2017-06-23 11:23:43 +0200163 { "ci", LOG_FMT_CLIENTIP, PR_MODE_TCP, LW_CLIP | LW_XPRT, NULL }, /* client ip */
164 { "cp", LOG_FMT_CLIENTPORT, PR_MODE_TCP, LW_CLIP | LW_XPRT, NULL }, /* client port */
Willy Tarreau2beef582012-12-20 17:22:52 +0100165 { "f", LOG_FMT_FRONTEND, PR_MODE_TCP, LW_INIT, NULL }, /* frontend */
166 { "fc", LOG_FMT_FECONN, PR_MODE_TCP, LW_BYTES, NULL }, /* feconn */
Willy Tarreaud02286d2017-06-23 11:23:43 +0200167 { "fi", LOG_FMT_FRONTENDIP, PR_MODE_TCP, LW_FRTIP | LW_XPRT, NULL }, /* frontend ip */
168 { "fp", LOG_FMT_FRONTENDPORT, PR_MODE_TCP, LW_FRTIP | LW_XPRT, NULL }, /* frontend port */
Willy Tarreau2beef582012-12-20 17:22:52 +0100169 { "ft", LOG_FMT_FRONTEND_XPRT, PR_MODE_TCP, LW_INIT, NULL }, /* frontend with transport mode */
Willy Tarreaud9ed3d22014-06-13 12:23:06 +0200170 { "hr", LOG_FMT_HDRREQUEST, PR_MODE_TCP, LW_REQHDR, NULL }, /* header request */
171 { "hrl", LOG_FMT_HDRREQUESTLIST, PR_MODE_TCP, LW_REQHDR, NULL }, /* header request list */
172 { "hs", LOG_FMT_HDRRESPONS, PR_MODE_TCP, LW_RSPHDR, NULL }, /* header response */
173 { "hsl", LOG_FMT_HDRRESPONSLIST, PR_MODE_TCP, LW_RSPHDR, NULL }, /* header response list */
Andrew Hayworth0ebc55f2015-04-27 21:37:03 +0000174 { "HM", LOG_FMT_HTTP_METHOD, PR_MODE_HTTP, LW_REQ, NULL }, /* HTTP method */
175 { "HP", LOG_FMT_HTTP_PATH, PR_MODE_HTTP, LW_REQ, NULL }, /* HTTP path */
Andrew Hayworthe63ac872015-07-31 16:14:16 +0000176 { "HQ", LOG_FMT_HTTP_QUERY, PR_MODE_HTTP, LW_REQ, NULL }, /* HTTP query */
Andrew Hayworth0ebc55f2015-04-27 21:37:03 +0000177 { "HU", LOG_FMT_HTTP_URI, PR_MODE_HTTP, LW_REQ, NULL }, /* HTTP full URI */
178 { "HV", LOG_FMT_HTTP_VERSION, PR_MODE_HTTP, LW_REQ, NULL }, /* HTTP version */
Willy Tarreau7346acb2014-08-28 15:03:15 +0200179 { "lc", LOG_FMT_LOGCNT, PR_MODE_TCP, LW_INIT, NULL }, /* log counter */
Willy Tarreau2beef582012-12-20 17:22:52 +0100180 { "ms", LOG_FMT_MS, PR_MODE_TCP, LW_INIT, NULL }, /* accept date millisecond */
William Lallemand5e19a282012-04-02 16:22:10 +0200181 { "pid", LOG_FMT_PID, PR_MODE_TCP, LW_INIT, NULL }, /* log pid */
Willy Tarreau2beef582012-12-20 17:22:52 +0100182 { "r", LOG_FMT_REQ, PR_MODE_HTTP, LW_REQ, NULL }, /* request */
183 { "rc", LOG_FMT_RETRIES, PR_MODE_TCP, LW_BYTES, NULL }, /* retries */
Willy Tarreau1f0da242014-01-25 11:01:50 +0100184 { "rt", LOG_FMT_COUNTER, PR_MODE_TCP, LW_REQ, NULL }, /* request counter (HTTP or TCP session) */
Willy Tarreau2beef582012-12-20 17:22:52 +0100185 { "s", LOG_FMT_SERVER, PR_MODE_TCP, LW_SVID, NULL }, /* server */
186 { "sc", LOG_FMT_SRVCONN, PR_MODE_TCP, LW_BYTES, NULL }, /* srv_conn */
187 { "si", LOG_FMT_SERVERIP, PR_MODE_TCP, LW_SVIP, NULL }, /* server destination ip */
188 { "sp", LOG_FMT_SERVERPORT, PR_MODE_TCP, LW_SVIP, NULL }, /* server destination port */
189 { "sq", LOG_FMT_SRVQUEUE, PR_MODE_TCP, LW_BYTES, NULL }, /* srv_queue */
Willy Tarreauffc3fcd2012-10-12 20:17:54 +0200190 { "sslc", LOG_FMT_SSL_CIPHER, PR_MODE_TCP, LW_XPRT, NULL }, /* client-side SSL ciphers */
191 { "sslv", LOG_FMT_SSL_VERSION, PR_MODE_TCP, LW_XPRT, NULL }, /* client-side SSL protocol version */
Willy Tarreau2beef582012-12-20 17:22:52 +0100192 { "t", LOG_FMT_DATE, PR_MODE_TCP, LW_INIT, NULL }, /* date */
Thierry FOURNIER / OZON.IO4cac3592016-07-28 17:19:45 +0200193 { "tr", LOG_FMT_tr, PR_MODE_HTTP, LW_INIT, NULL }, /* date of start of request */
194 { "trg",LOG_FMT_trg, PR_MODE_HTTP, LW_INIT, NULL }, /* date of start of request, GMT */
195 { "trl",LOG_FMT_trl, PR_MODE_HTTP, LW_INIT, NULL }, /* date of start of request, local */
Willy Tarreau2beef582012-12-20 17:22:52 +0100196 { "ts", LOG_FMT_TERMSTATE, PR_MODE_TCP, LW_BYTES, NULL },/* termination state */
197 { "tsc", LOG_FMT_TERMSTATE_CK, PR_MODE_TCP, LW_INIT, NULL },/* termination state */
198
199 /* The following tags are deprecated and will be removed soon */
200 { "Bi", LOG_FMT_BACKENDIP, PR_MODE_TCP, LW_BCKIP, prepare_addrsource, "bi" }, /* backend source ip */
201 { "Bp", LOG_FMT_BACKENDPORT, PR_MODE_TCP, LW_BCKIP, prepare_addrsource, "bp" }, /* backend source port */
Willy Tarreaud02286d2017-06-23 11:23:43 +0200202 { "Ci", LOG_FMT_CLIENTIP, PR_MODE_TCP, LW_CLIP | LW_XPRT, NULL, "ci" }, /* client ip */
203 { "Cp", LOG_FMT_CLIENTPORT, PR_MODE_TCP, LW_CLIP | LW_XPRT, NULL, "cp" }, /* client port */
204 { "Fi", LOG_FMT_FRONTENDIP, PR_MODE_TCP, LW_FRTIP | LW_XPRT, NULL, "fi" }, /* frontend ip */
205 { "Fp", LOG_FMT_FRONTENDPORT, PR_MODE_TCP, LW_FRTIP | LW_XPRT, NULL, "fp" }, /* frontend port */
Willy Tarreau2beef582012-12-20 17:22:52 +0100206 { "Si", LOG_FMT_SERVERIP, PR_MODE_TCP, LW_SVIP, NULL, "si" }, /* server destination ip */
207 { "Sp", LOG_FMT_SERVERPORT, PR_MODE_TCP, LW_SVIP, NULL, "sp" }, /* server destination port */
208 { "cc", LOG_FMT_CCLIENT, PR_MODE_HTTP, LW_REQHDR, NULL, "CC" }, /* client cookie */
209 { "cs", LOG_FMT_CSERVER, PR_MODE_HTTP, LW_RSPHDR, NULL, "CS" }, /* server cookie */
210 { "st", LOG_FMT_STATUS, PR_MODE_HTTP, LW_RESP, NULL, "ST" }, /* status code */
William Lallemand5e19a282012-04-02 16:22:10 +0200211 { 0, 0, 0, 0, NULL }
William Lallemand723b73a2012-02-08 16:37:49 +0100212};
213
Thierry FOURNIER / OZON.IO4cac3592016-07-28 17:19:45 +0200214char 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
215char 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 +0100216char 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 +0100217char *log_format = NULL;
218
Dragan Dosen0b85ece2015-09-25 19:17:44 +0200219/* Default string used for structured-data part in RFC5424 formatted
220 * syslog messages.
221 */
222char default_rfc5424_sd_log_format[] = "- ";
Dragan Dosen1322d092015-09-22 16:05:32 +0200223
Willy Tarreau13ef7732018-11-12 07:25:28 +0100224/* total number of dropped logs */
225unsigned int dropped_logs = 0;
226
Dragan Dosen1322d092015-09-22 16:05:32 +0200227/* This is a global syslog header, common to all outgoing messages in
228 * RFC3164 format. It begins with time-based part and is updated by
229 * update_log_hdr().
Dragan Dosen59cee972015-09-19 22:09:02 +0200230 */
Christopher Fauletf8188c62017-06-02 16:20:16 +0200231THREAD_LOCAL char *logheader = NULL;
Willy Tarreau55e2f5a2019-05-05 10:11:39 +0200232THREAD_LOCAL char *logheader_end = NULL;
Dragan Dosen59cee972015-09-19 22:09:02 +0200233
Dragan Dosen1322d092015-09-22 16:05:32 +0200234/* This is a global syslog header for messages in RFC5424 format. It is
235 * updated by update_log_hdr_rfc5424().
236 */
Christopher Fauletf8188c62017-06-02 16:20:16 +0200237THREAD_LOCAL char *logheader_rfc5424 = NULL;
Willy Tarreau55e2f5a2019-05-05 10:11:39 +0200238THREAD_LOCAL char *logheader_rfc5424_end = NULL;
Dragan Dosen1322d092015-09-22 16:05:32 +0200239
Dragan Dosen59cee972015-09-19 22:09:02 +0200240/* This is a global syslog message buffer, common to all outgoing
241 * messages. It contains only the data part.
Willy Tarreaub1a2faf2012-03-19 16:51:53 +0100242 */
Christopher Fauletf8188c62017-06-02 16:20:16 +0200243THREAD_LOCAL char *logline = NULL;
Willy Tarreaub1a2faf2012-03-19 16:51:53 +0100244
Dragan Dosen0b85ece2015-09-25 19:17:44 +0200245/* A global syslog message buffer, common to all RFC5424 syslog messages.
246 * Currently, it is used for generating the structured-data part.
247 */
Christopher Fauletf8188c62017-06-02 16:20:16 +0200248THREAD_LOCAL char *logline_rfc5424 = NULL;
Dragan Dosen0b85ece2015-09-25 19:17:44 +0200249
Christopher Fauletd4696382017-10-24 11:44:05 +0200250/* A global buffer used to store all startup alerts/warnings. It will then be
251 * retrieve on the CLI. */
Willy Tarreau869efd52019-11-15 15:16:57 +0100252static struct ring *startup_logs = NULL;
Christopher Fauletd4696382017-10-24 11:44:05 +0200253
William Lallemand723b73a2012-02-08 16:37:49 +0100254struct logformat_var_args {
255 char *name;
256 int mask;
257};
258
259struct logformat_var_args var_args_list[] = {
260// global
261 { "M", LOG_OPT_MANDATORY },
262 { "Q", LOG_OPT_QUOTE },
William Lallemand5f232402012-04-05 18:02:55 +0200263 { "X", LOG_OPT_HEXA },
Dragan Dosen835b9212016-02-12 13:23:03 +0100264 { "E", LOG_OPT_ESC },
William Lallemand723b73a2012-02-08 16:37:49 +0100265 { 0, 0 }
266};
267
Willy Tarreaub1f3af22013-04-12 18:30:32 +0200268/* return the name of the directive used in the current proxy for which we're
269 * currently parsing a header, when it is known.
270 */
271static inline const char *fmt_directive(const struct proxy *curproxy)
272{
Willy Tarreaubf0addb2013-12-02 12:24:54 +0100273 switch (curproxy->conf.args.ctx) {
Willy Tarreau53e1a6d2015-07-09 11:20:00 +0200274 case ARGC_ACL:
275 return "acl";
276 case ARGC_STK:
277 return "stick";
278 case ARGC_TRK:
279 return "track-sc";
280 case ARGC_LOG:
281 return "log-format";
Dragan Dosen0b85ece2015-09-25 19:17:44 +0200282 case ARGC_LOGSD:
283 return "log-format-sd";
Willy Tarreaubf0addb2013-12-02 12:24:54 +0100284 case ARGC_HRQ:
Thierry FOURNIER1c0054f2013-11-20 15:09:52 +0100285 return "http-request";
Willy Tarreaubf0addb2013-12-02 12:24:54 +0100286 case ARGC_HRS:
Thierry FOURNIER1c0054f2013-11-20 15:09:52 +0100287 return "http-response";
Willy Tarreau53e1a6d2015-07-09 11:20:00 +0200288 case ARGC_UIF:
289 return "unique-id-format";
Thierry FOURNIERd18cd0f2013-11-29 12:15:45 +0100290 case ARGC_RDR:
Willy Tarreau53e1a6d2015-07-09 11:20:00 +0200291 return "redirect";
292 case ARGC_CAP:
293 return "capture";
Willy Tarreau28d976d2015-07-09 11:39:33 +0200294 case ARGC_SRV:
295 return "server";
Christopher Fauletf7e4e7e2016-10-27 22:29:49 +0200296 case ARGC_SPOE:
297 return "spoe-message";
Thierry FOURNIER / OZON.IO4ed1c952016-11-24 23:57:54 +0100298 case ARGC_UBK:
299 return "use_backend";
Willy Tarreaubf0addb2013-12-02 12:24:54 +0100300 default:
Willy Tarreau53e1a6d2015-07-09 11:20:00 +0200301 return "undefined(please report this bug)"; /* must never happen */
Willy Tarreaubf0addb2013-12-02 12:24:54 +0100302 }
Willy Tarreaub1f3af22013-04-12 18:30:32 +0200303}
304
William Lallemand723b73a2012-02-08 16:37:49 +0100305/*
William Lallemandb7ff6a32012-03-02 14:35:21 +0100306 * callback used to configure addr source retrieval
307 */
308int prepare_addrsource(struct logformat_node *node, struct proxy *curproxy)
309{
310 curproxy->options2 |= PR_O2_SRC_ADDR;
311
312 return 0;
313}
314
315
316/*
Thierry FOURNIER / OZON.IObca46f02016-11-22 23:13:04 +0100317 * Parse args in a logformat_var. Returns 0 in error
318 * case, otherwise, it returns 1.
William Lallemand723b73a2012-02-08 16:37:49 +0100319 */
Thierry FOURNIER / OZON.IO8a4e4422016-11-23 00:41:28 +0100320int parse_logformat_var_args(char *args, struct logformat_node *node, char **err)
William Lallemand723b73a2012-02-08 16:37:49 +0100321{
322 int i = 0;
323 int end = 0;
324 int flags = 0; // 1 = + 2 = -
325 char *sp = NULL; // start pointer
326
Thierry FOURNIER / OZON.IO8a4e4422016-11-23 00:41:28 +0100327 if (args == NULL) {
328 memprintf(err, "internal error: parse_logformat_var_args() expects non null 'args'");
Thierry FOURNIER / OZON.IObca46f02016-11-22 23:13:04 +0100329 return 0;
Thierry FOURNIER / OZON.IO8a4e4422016-11-23 00:41:28 +0100330 }
William Lallemand723b73a2012-02-08 16:37:49 +0100331
332 while (1) {
333 if (*args == '\0')
334 end = 1;
335
336 if (*args == '+') {
337 // add flag
338 sp = args + 1;
339 flags = 1;
340 }
341 if (*args == '-') {
342 // delete flag
343 sp = args + 1;
344 flags = 2;
345 }
346
347 if (*args == '\0' || *args == ',') {
348 *args = '\0';
Willy Tarreau254d44c2012-12-20 18:19:26 +0100349 for (i = 0; sp && var_args_list[i].name; i++) {
William Lallemand723b73a2012-02-08 16:37:49 +0100350 if (strcmp(sp, var_args_list[i].name) == 0) {
351 if (flags == 1) {
352 node->options |= var_args_list[i].mask;
353 break;
354 } else if (flags == 2) {
355 node->options &= ~var_args_list[i].mask;
356 break;
357 }
358 }
359 }
360 sp = NULL;
361 if (end)
362 break;
363 }
Willy Tarreau254d44c2012-12-20 18:19:26 +0100364 args++;
William Lallemand723b73a2012-02-08 16:37:49 +0100365 }
Thierry FOURNIER / OZON.IObca46f02016-11-22 23:13:04 +0100366 return 1;
William Lallemand723b73a2012-02-08 16:37:49 +0100367}
368
369/*
Willy Tarreau8a3f52f2012-12-20 21:23:42 +0100370 * Parse a variable '%varname' or '%{args}varname' in log-format. The caller
371 * must pass the args part in the <arg> pointer with its length in <arg_len>,
372 * and varname with its length in <var> and <var_len> respectively. <arg> is
373 * ignored when arg_len is 0. Neither <var> nor <var_len> may be null.
Thierry FOURNIER / OZON.IOeca4d952016-11-22 22:06:04 +0100374 * Returns false in error case and err is filled, otherwise returns true.
William Lallemand723b73a2012-02-08 16:37:49 +0100375 */
Thierry FOURNIER / OZON.IO8a4e4422016-11-23 00:41:28 +0100376int 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 +0100377{
Willy Tarreau8a3f52f2012-12-20 21:23:42 +0100378 int j;
Dragan Dosen61302da2019-04-30 00:40:02 +0200379 struct logformat_node *node = NULL;
William Lallemand723b73a2012-02-08 16:37:49 +0100380
Willy Tarreau8a3f52f2012-12-20 21:23:42 +0100381 for (j = 0; logformat_keywords[j].name; j++) { // search a log type
382 if (strlen(logformat_keywords[j].name) == var_len &&
383 strncmp(var, logformat_keywords[j].name, var_len) == 0) {
384 if (logformat_keywords[j].mode != PR_MODE_HTTP || curproxy->mode == PR_MODE_HTTP) {
Vincent Bernat02779b62016-04-03 13:48:43 +0200385 node = calloc(1, sizeof(*node));
Thierry FOURNIER / OZON.IO9cbfef22016-11-22 23:24:10 +0100386 if (!node) {
Thierry FOURNIER / OZON.IO8a4e4422016-11-23 00:41:28 +0100387 memprintf(err, "out of memory error");
Dragan Dosen61302da2019-04-30 00:40:02 +0200388 goto error_free;
Thierry FOURNIER / OZON.IO9cbfef22016-11-22 23:24:10 +0100389 }
Willy Tarreau8a3f52f2012-12-20 21:23:42 +0100390 node->type = logformat_keywords[j].type;
391 node->options = *defoptions;
392 if (arg_len) {
393 node->arg = my_strndup(arg, arg_len);
Thierry FOURNIER / OZON.IO8a4e4422016-11-23 00:41:28 +0100394 if (!parse_logformat_var_args(node->arg, node, err))
Dragan Dosen61302da2019-04-30 00:40:02 +0200395 goto error_free;
Willy Tarreau8a3f52f2012-12-20 21:23:42 +0100396 }
397 if (node->type == LOG_FMT_GLOBAL) {
398 *defoptions = node->options;
399 free(node->arg);
400 free(node);
401 } else {
402 if (logformat_keywords[j].config_callback &&
403 logformat_keywords[j].config_callback(node, curproxy) != 0) {
Dragan Dosen61302da2019-04-30 00:40:02 +0200404 goto error_free;
William Lallemand723b73a2012-02-08 16:37:49 +0100405 }
Willy Tarreau8a3f52f2012-12-20 21:23:42 +0100406 curproxy->to_log |= logformat_keywords[j].lw;
407 LIST_ADDQ(list_format, &node->list);
William Lallemand723b73a2012-02-08 16:37:49 +0100408 }
Willy Tarreau8a3f52f2012-12-20 21:23:42 +0100409 if (logformat_keywords[j].replace_by)
Christopher Faulet767a84b2017-11-24 16:50:31 +0100410 ha_warning("parsing [%s:%d] : deprecated variable '%s' in '%s', please replace it with '%s'.\n",
411 curproxy->conf.args.file, curproxy->conf.args.line,
412 logformat_keywords[j].name, fmt_directive(curproxy), logformat_keywords[j].replace_by);
Thierry FOURNIER / OZON.IOeca4d952016-11-22 22:06:04 +0100413 return 1;
Willy Tarreau8a3f52f2012-12-20 21:23:42 +0100414 } else {
Thierry FOURNIER / OZON.IO8a4e4422016-11-23 00:41:28 +0100415 memprintf(err, "format variable '%s' is reserved for HTTP mode",
416 logformat_keywords[j].name);
Dragan Dosen61302da2019-04-30 00:40:02 +0200417 goto error_free;
William Lallemand723b73a2012-02-08 16:37:49 +0100418 }
William Lallemand723b73a2012-02-08 16:37:49 +0100419 }
420 }
Willy Tarreau8a3f52f2012-12-20 21:23:42 +0100421
422 j = var[var_len];
423 var[var_len] = 0;
Thierry FOURNIER / OZON.IO8a4e4422016-11-23 00:41:28 +0100424 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 +0100425 var[var_len] = j;
Dragan Dosen61302da2019-04-30 00:40:02 +0200426
427 error_free:
428 if (node) {
429 free(node->arg);
430 free(node);
431 }
Thierry FOURNIER / OZON.IOeca4d952016-11-22 22:06:04 +0100432 return 0;
William Lallemand723b73a2012-02-08 16:37:49 +0100433}
434
435/*
436 * push to the logformat linked list
437 *
438 * start: start pointer
439 * end: end text pointer
440 * type: string type
William Lallemand1d705562012-03-12 12:46:41 +0100441 * list_format: destination list
William Lallemand723b73a2012-02-08 16:37:49 +0100442 *
443 * LOG_TEXT: copy chars from start to end excluding end.
444 *
445*/
Thierry FOURNIER / OZON.IO8a4e4422016-11-23 00:41:28 +0100446int add_to_logformat_list(char *start, char *end, int type, struct list *list_format, char **err)
William Lallemand723b73a2012-02-08 16:37:49 +0100447{
448 char *str;
449
Willy Tarreaua3571662012-12-20 21:59:12 +0100450 if (type == LF_TEXT) { /* type text */
Vincent Bernat02779b62016-04-03 13:48:43 +0200451 struct logformat_node *node = calloc(1, sizeof(*node));
Thierry FOURNIER / OZON.IO9cbfef22016-11-22 23:24:10 +0100452 if (!node) {
Thierry FOURNIER / OZON.IO8a4e4422016-11-23 00:41:28 +0100453 memprintf(err, "out of memory error");
Thierry FOURNIER / OZON.IO9cbfef22016-11-22 23:24:10 +0100454 return 0;
455 }
Vincent Bernat02779b62016-04-03 13:48:43 +0200456 str = calloc(1, end - start + 1);
William Lallemand723b73a2012-02-08 16:37:49 +0100457 strncpy(str, start, end - start);
William Lallemand723b73a2012-02-08 16:37:49 +0100458 str[end - start] = '\0';
459 node->arg = str;
William Lallemand1d705562012-03-12 12:46:41 +0100460 node->type = LOG_FMT_TEXT; // type string
461 LIST_ADDQ(list_format, &node->list);
Willy Tarreaua3571662012-12-20 21:59:12 +0100462 } else if (type == LF_SEPARATOR) {
Vincent Bernat02779b62016-04-03 13:48:43 +0200463 struct logformat_node *node = calloc(1, sizeof(*node));
Thierry FOURNIER / OZON.IO9cbfef22016-11-22 23:24:10 +0100464 if (!node) {
Thierry FOURNIER / OZON.IO8a4e4422016-11-23 00:41:28 +0100465 memprintf(err, "out of memory error");
Thierry FOURNIER / OZON.IO9cbfef22016-11-22 23:24:10 +0100466 return 0;
467 }
William Lallemand1d705562012-03-12 12:46:41 +0100468 node->type = LOG_FMT_SEPARATOR;
469 LIST_ADDQ(list_format, &node->list);
William Lallemand723b73a2012-02-08 16:37:49 +0100470 }
Thierry FOURNIER / OZON.IOa2c38d72016-11-22 23:11:21 +0100471 return 1;
William Lallemand723b73a2012-02-08 16:37:49 +0100472}
473
474/*
Willy Tarreauc8368452012-12-21 00:09:23 +0100475 * Parse the sample fetch expression <text> and add a node to <list_format> upon
476 * success. At the moment, sample converters are not yet supported but fetch arguments
Willy Tarreaucd0d2ed2020-02-14 17:33:06 +0100477 * should work. The curpx->conf.args.ctx must be set by the caller. If an end pointer
478 * is passed in <endptr>, it will be updated with the pointer to the first character
479 * not part of the sample expression.
Thierry FOURNIER / OZON.IOa2c38d72016-11-22 23:11:21 +0100480 *
481 * In error case, the function returns 0, otherwise it returns 1.
Willy Tarreauc8368452012-12-21 00:09:23 +0100482 */
Willy Tarreaucd0d2ed2020-02-14 17:33:06 +0100483int 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 +0100484{
485 char *cmd[2];
Dragan Dosen61302da2019-04-30 00:40:02 +0200486 struct sample_expr *expr = NULL;
487 struct logformat_node *node = NULL;
Willy Tarreauc8368452012-12-21 00:09:23 +0100488 int cmd_arg;
489
490 cmd[0] = text;
491 cmd[1] = "";
492 cmd_arg = 0;
493
Willy Tarreaucd0d2ed2020-02-14 17:33:06 +0100494 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 +0100495 if (!expr) {
Thierry FOURNIER / OZON.IO8a4e4422016-11-23 00:41:28 +0100496 memprintf(err, "failed to parse sample expression <%s> : %s", text, *err);
Dragan Dosen61302da2019-04-30 00:40:02 +0200497 goto error_free;
Willy Tarreauc8368452012-12-21 00:09:23 +0100498 }
499
Vincent Bernat02779b62016-04-03 13:48:43 +0200500 node = calloc(1, sizeof(*node));
Thierry FOURNIER / OZON.IO9cbfef22016-11-22 23:24:10 +0100501 if (!node) {
Thierry FOURNIER / OZON.IO8a4e4422016-11-23 00:41:28 +0100502 memprintf(err, "out of memory error");
Dragan Dosen61302da2019-04-30 00:40:02 +0200503 goto error_free;
Thierry FOURNIER / OZON.IO9cbfef22016-11-22 23:24:10 +0100504 }
Willy Tarreauc8368452012-12-21 00:09:23 +0100505 node->type = LOG_FMT_EXPR;
506 node->expr = expr;
507 node->options = options;
508
509 if (arg_len) {
510 node->arg = my_strndup(arg, arg_len);
Thierry FOURNIER / OZON.IO8a4e4422016-11-23 00:41:28 +0100511 if (!parse_logformat_var_args(node->arg, node, err))
Dragan Dosen61302da2019-04-30 00:40:02 +0200512 goto error_free;
Willy Tarreauc8368452012-12-21 00:09:23 +0100513 }
Willy Tarreau434c57c2013-01-08 01:10:24 +0100514 if (expr->fetch->val & cap & SMP_VAL_REQUEST)
Willy Tarreauc8368452012-12-21 00:09:23 +0100515 node->options |= LOG_OPT_REQ_CAP; /* fetch method is request-compatible */
516
Willy Tarreau434c57c2013-01-08 01:10:24 +0100517 if (expr->fetch->val & cap & SMP_VAL_RESPONSE)
Willy Tarreauc8368452012-12-21 00:09:23 +0100518 node->options |= LOG_OPT_RES_CAP; /* fetch method is response-compatible */
519
Thierry FOURNIER / OZON.IOa2c38d72016-11-22 23:11:21 +0100520 if (!(expr->fetch->val & cap)) {
Thierry FOURNIER / OZON.IO8a4e4422016-11-23 00:41:28 +0100521 memprintf(err, "sample fetch <%s> may not be reliably used here because it needs '%s' which is not available here",
522 text, sample_src_names(expr->fetch->use));
Dragan Dosen61302da2019-04-30 00:40:02 +0200523 goto error_free;
Thierry FOURNIER / OZON.IOa2c38d72016-11-22 23:11:21 +0100524 }
Willy Tarreau434c57c2013-01-08 01:10:24 +0100525
Christopher Faulet711ed6a2019-07-16 14:16:10 +0200526 /* check if we need to allocate an http_txn struct for HTTP parsing */
Willy Tarreauc8368452012-12-21 00:09:23 +0100527 /* Note, we may also need to set curpx->to_log with certain fetches */
Willy Tarreau25320b22013-03-24 07:22:08 +0100528 curpx->http_needed |= !!(expr->fetch->use & SMP_USE_HTTP_ANY);
Willy Tarreauc8368452012-12-21 00:09:23 +0100529
William Lallemand65ad6e12014-01-31 15:08:02 +0100530 /* FIXME: temporary workaround for missing LW_XPRT and LW_REQ flags
531 * needed with some sample fetches (eg: ssl*). We always set it for
532 * now on, but this will leave with sample capabilities soon.
Willy Tarreau1f31c732013-01-10 16:22:27 +0100533 */
534 curpx->to_log |= LW_XPRT;
William Lallemand65ad6e12014-01-31 15:08:02 +0100535 curpx->to_log |= LW_REQ;
Willy Tarreauc8368452012-12-21 00:09:23 +0100536 LIST_ADDQ(list_format, &node->list);
Thierry FOURNIER / OZON.IOa2c38d72016-11-22 23:11:21 +0100537 return 1;
Dragan Dosen61302da2019-04-30 00:40:02 +0200538
539 error_free:
540 release_sample_expr(expr);
541 if (node) {
542 free(node->arg);
543 free(node);
544 }
545 return 0;
Willy Tarreauc8368452012-12-21 00:09:23 +0100546}
547
548/*
William Lallemand723b73a2012-02-08 16:37:49 +0100549 * Parse the log_format string and fill a linked list.
550 * Variable name are preceded by % and composed by characters [a-zA-Z0-9]* : %varname
Willy Tarreaua4312fa2013-04-02 16:34:32 +0200551 * You can set arguments using { } : %{many arguments}varname.
552 * The curproxy->conf.args.ctx must be set by the caller.
William Lallemand1d705562012-03-12 12:46:41 +0100553 *
554 * str: the string to parse
555 * curproxy: the proxy affected
556 * list_format: the destination list
Willy Tarreau6cbbdbf2013-02-05 18:52:25 +0100557 * options: LOG_OPT_* to force on every node
Willy Tarreau434c57c2013-01-08 01:10:24 +0100558 * cap: all SMP_VAL_* flags supported by the consumer
Thierry FOURNIER / OZON.IOa2c38d72016-11-22 23:11:21 +0100559 *
Thierry FOURNIER / OZON.IO8a4e4422016-11-23 00:41:28 +0100560 * The function returns 1 in success case, otherwise, it returns 0 and err is filled.
William Lallemand723b73a2012-02-08 16:37:49 +0100561 */
Thierry FOURNIER / OZON.IO8a4e4422016-11-23 00:41:28 +0100562int 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 +0100563{
Willy Tarreaub83bc1e2012-12-24 12:36:33 +0100564 char *sp, *str, *backfmt; /* start pointer for text parts */
Willy Tarreau8a3f52f2012-12-20 21:23:42 +0100565 char *arg = NULL; /* start pointer for args */
566 char *var = NULL; /* start pointer for vars */
567 int arg_len = 0;
568 int var_len = 0;
569 int cformat; /* current token format */
570 int pformat; /* previous token format */
William Lallemand723b73a2012-02-08 16:37:49 +0100571 struct logformat_node *tmplf, *back;
572
Willy Tarreaub83bc1e2012-12-24 12:36:33 +0100573 sp = str = backfmt = strdup(fmt);
Thierry FOURNIER / OZON.IO9cbfef22016-11-22 23:24:10 +0100574 if (!str) {
Thierry FOURNIER / OZON.IO8a4e4422016-11-23 00:41:28 +0100575 memprintf(err, "out of memory error");
Thierry FOURNIER / OZON.IO9cbfef22016-11-22 23:24:10 +0100576 return 0;
577 }
William Lallemand1dc00ef2012-08-09 16:41:35 +0200578 curproxy->to_log |= LW_INIT;
William Lallemand5e19a282012-04-02 16:22:10 +0200579
William Lallemand723b73a2012-02-08 16:37:49 +0100580 /* flush the list first. */
William Lallemand1d705562012-03-12 12:46:41 +0100581 list_for_each_entry_safe(tmplf, back, list_format, list) {
William Lallemand723b73a2012-02-08 16:37:49 +0100582 LIST_DEL(&tmplf->list);
Dragan Dosen61302da2019-04-30 00:40:02 +0200583 release_sample_expr(tmplf->expr);
584 free(tmplf->arg);
William Lallemand723b73a2012-02-08 16:37:49 +0100585 free(tmplf);
586 }
587
Willy Tarreau8a3f52f2012-12-20 21:23:42 +0100588 for (cformat = LF_INIT; cformat != LF_END; str++) {
William Lallemand723b73a2012-02-08 16:37:49 +0100589 pformat = cformat;
590
Willy Tarreau8a3f52f2012-12-20 21:23:42 +0100591 if (!*str)
592 cformat = LF_END; // preset it to save all states from doing this
William Lallemand723b73a2012-02-08 16:37:49 +0100593
Joseph Herlant85b40592018-11-15 12:10:04 -0800594 /* The principle of the two-step state machine below is to first detect a change, and
Willy Tarreau8a3f52f2012-12-20 21:23:42 +0100595 * second have all common paths processed at one place. The common paths are the ones
596 * encountered in text areas (LF_INIT, LF_TEXT, LF_SEPARATOR) and at the end (LF_END).
597 * We use the common LF_INIT state to dispatch to the different final states.
598 */
599 switch (pformat) {
600 case LF_STARTVAR: // text immediately following a '%'
Willy Tarreauc8368452012-12-21 00:09:23 +0100601 arg = NULL; var = NULL;
Willy Tarreau8a3f52f2012-12-20 21:23:42 +0100602 arg_len = var_len = 0;
603 if (*str == '{') { // optional argument
604 cformat = LF_STARG;
605 arg = str + 1;
William Lallemand723b73a2012-02-08 16:37:49 +0100606 }
Willy Tarreauc8368452012-12-21 00:09:23 +0100607 else if (*str == '[') {
608 cformat = LF_STEXPR;
609 var = str + 1; // store expr in variable name
610 }
Willy Tarreau0f28f822013-12-16 01:38:33 +0100611 else if (isalpha((unsigned char)*str)) { // variable name
William Lallemand723b73a2012-02-08 16:37:49 +0100612 cformat = LF_VAR;
Willy Tarreau8a3f52f2012-12-20 21:23:42 +0100613 var = str;
William Lallemand723b73a2012-02-08 16:37:49 +0100614 }
Willy Tarreau8a3f52f2012-12-20 21:23:42 +0100615 else if (*str == '%')
Ilya Shipitsin856aabc2020-04-16 23:51:34 +0500616 cformat = LF_TEXT; // convert this character to a literal (useful for '%')
Willy Tarreau0f28f822013-12-16 01:38:33 +0100617 else if (isdigit((unsigned char)*str) || *str == ' ' || *str == '\t') {
Willy Tarreau06d97f92013-12-02 17:45:48 +0100618 /* single '%' followed by blank or digit, send them both */
619 cformat = LF_TEXT;
620 pformat = LF_TEXT; /* finally we include the previous char as well */
621 sp = str - 1; /* send both the '%' and the current char */
Jim Freemana2278c82017-04-15 08:01:59 -0600622 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 +0100623 *str, (int)(str - backfmt), fmt);
Willy Tarreau51013e82019-12-11 12:05:39 +0100624 goto fail;
Willy Tarreau06d97f92013-12-02 17:45:48 +0100625
626 }
Willy Tarreau8a3f52f2012-12-20 21:23:42 +0100627 else
Ilya Shipitsin856aabc2020-04-16 23:51:34 +0500628 cformat = LF_INIT; // handle other cases of literals
Willy Tarreau8a3f52f2012-12-20 21:23:42 +0100629 break;
630
631 case LF_STARG: // text immediately following '%{'
632 if (*str == '}') { // end of arg
William Lallemand723b73a2012-02-08 16:37:49 +0100633 cformat = LF_EDARG;
Willy Tarreau8a3f52f2012-12-20 21:23:42 +0100634 arg_len = str - arg;
635 *str = 0; // used for reporting errors
William Lallemand723b73a2012-02-08 16:37:49 +0100636 }
Willy Tarreau8a3f52f2012-12-20 21:23:42 +0100637 break;
638
639 case LF_EDARG: // text immediately following '%{arg}'
Willy Tarreauc8368452012-12-21 00:09:23 +0100640 if (*str == '[') {
641 cformat = LF_STEXPR;
642 var = str + 1; // store expr in variable name
643 break;
644 }
Willy Tarreau0f28f822013-12-16 01:38:33 +0100645 else if (isalnum((unsigned char)*str)) { // variable name
William Lallemand723b73a2012-02-08 16:37:49 +0100646 cformat = LF_VAR;
Willy Tarreau8a3f52f2012-12-20 21:23:42 +0100647 var = str;
648 break;
649 }
Thierry FOURNIER / OZON.IO8a4e4422016-11-23 00:41:28 +0100650 memprintf(err, "parse argument modifier without variable name near '%%{%s}'", arg);
Willy Tarreau51013e82019-12-11 12:05:39 +0100651 goto fail;
Willy Tarreau8a3f52f2012-12-20 21:23:42 +0100652
Willy Tarreauc8368452012-12-21 00:09:23 +0100653 case LF_STEXPR: // text immediately following '%['
Willy Tarreaucd0d2ed2020-02-14 17:33:06 +0100654 /* the whole sample expression is parsed at once,
655 * returning the pointer to the first character not
656 * part of the expression, which MUST be the trailing
657 * angle bracket.
658 */
659 if (!add_sample_to_logformat_list(var, arg, arg_len, curproxy, list_format, options, cap, err, &str))
660 goto fail;
661
662 if (*str == ']') {
663 // end of arg, go on with next state
664 cformat = pformat = LF_EDEXPR;
665 sp = str;
666 }
667 else {
668 char c = *str;
669 *str = 0;
Willy Tarreau90807112020-02-25 08:16:33 +0100670 if (isprint((unsigned char)c))
Willy Tarreaucd0d2ed2020-02-14 17:33:06 +0100671 memprintf(err, "expected ']' after '%s', but found '%c'", var, c);
672 else
673 memprintf(err, "missing ']' after '%s'", var);
Willy Tarreauc8368452012-12-21 00:09:23 +0100674 }
675 break;
676
Willy Tarreau8a3f52f2012-12-20 21:23:42 +0100677 case LF_VAR: // text part of a variable name
678 var_len = str - var;
Willy Tarreau0f28f822013-12-16 01:38:33 +0100679 if (!isalnum((unsigned char)*str))
Willy Tarreau8a3f52f2012-12-20 21:23:42 +0100680 cformat = LF_INIT; // not variable name anymore
681 break;
682
Willy Tarreauc8368452012-12-21 00:09:23 +0100683 default: // LF_INIT, LF_TEXT, LF_SEPARATOR, LF_END, LF_EDEXPR
Willy Tarreau8a3f52f2012-12-20 21:23:42 +0100684 cformat = LF_INIT;
685 }
686
687 if (cformat == LF_INIT) { /* resynchronize state to text/sep/startvar */
688 switch (*str) {
689 case '%': cformat = LF_STARTVAR; break;
690 case ' ': cformat = LF_SEPARATOR; break;
691 case 0 : cformat = LF_END; break;
692 default : cformat = LF_TEXT; break;
William Lallemand723b73a2012-02-08 16:37:49 +0100693 }
694 }
695
Willy Tarreau8a3f52f2012-12-20 21:23:42 +0100696 if (cformat != pformat || pformat == LF_SEPARATOR) {
697 switch (pformat) {
698 case LF_VAR:
Thierry FOURNIER / OZON.IO8a4e4422016-11-23 00:41:28 +0100699 if (!parse_logformat_var(arg, arg_len, var, var_len, curproxy, list_format, &options, err))
Willy Tarreau51013e82019-12-11 12:05:39 +0100700 goto fail;
Willy Tarreau8a3f52f2012-12-20 21:23:42 +0100701 break;
Willy Tarreauc8368452012-12-21 00:09:23 +0100702 case LF_STEXPR:
Willy Tarreaucd0d2ed2020-02-14 17:33:06 +0100703 if (!add_sample_to_logformat_list(var, arg, arg_len, curproxy, list_format, options, cap, err, &sp))
Willy Tarreau51013e82019-12-11 12:05:39 +0100704 goto fail;
Willy Tarreauc8368452012-12-21 00:09:23 +0100705 break;
Willy Tarreau8a3f52f2012-12-20 21:23:42 +0100706 case LF_TEXT:
707 case LF_SEPARATOR:
Thierry FOURNIER / OZON.IO8a4e4422016-11-23 00:41:28 +0100708 if (!add_to_logformat_list(sp, str, pformat, list_format, err))
Willy Tarreau51013e82019-12-11 12:05:39 +0100709 goto fail;
Willy Tarreau8a3f52f2012-12-20 21:23:42 +0100710 break;
711 }
712 sp = str; /* new start of text at every state switch and at every separator */
William Lallemand723b73a2012-02-08 16:37:49 +0100713 }
714 }
Willy Tarreau8a3f52f2012-12-20 21:23:42 +0100715
Thierry FOURNIER / OZON.IOa2c38d72016-11-22 23:11:21 +0100716 if (pformat == LF_STARTVAR || pformat == LF_STARG || pformat == LF_STEXPR) {
Thierry FOURNIER / OZON.IO8a4e4422016-11-23 00:41:28 +0100717 memprintf(err, "truncated line after '%s'", var ? var : arg ? arg : "%");
Willy Tarreau51013e82019-12-11 12:05:39 +0100718 goto fail;
Thierry FOURNIER / OZON.IOa2c38d72016-11-22 23:11:21 +0100719 }
Willy Tarreaub83bc1e2012-12-24 12:36:33 +0100720 free(backfmt);
Thierry FOURNIER / OZON.IOa2c38d72016-11-22 23:11:21 +0100721
722 return 1;
Willy Tarreau51013e82019-12-11 12:05:39 +0100723 fail:
724 free(backfmt);
725 return 0;
William Lallemand723b73a2012-02-08 16:37:49 +0100726}
727
Christopher Faulet4b0b79d2018-03-26 15:54:32 +0200728/*
Ilya Shipitsin856aabc2020-04-16 23:51:34 +0500729 * 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 +0200730 * ranges of indexes. Note that an index may be considered as a particular range
731 * with a high limit to the low limit.
732 */
733int get_logsrv_smp_range(unsigned int *low, unsigned int *high, char **arg, char **err)
734{
735 char *end, *p;
736
737 *low = *high = 0;
738
739 p = *arg;
740 end = strchr(p, ',');
741 if (!end)
742 end = p + strlen(p);
743
744 *high = *low = read_uint((const char **)&p, end);
745 if (!*low || (p != end && *p != '-'))
746 goto err;
747
748 if (p == end)
749 goto done;
750
751 p++;
752 *high = read_uint((const char **)&p, end);
753 if (!*high || *high <= *low || p != end)
754 goto err;
755
756 done:
757 if (*end == ',')
758 end++;
759 *arg = end;
760 return 1;
761
762 err:
763 memprintf(err, "wrong sample range '%s'", *arg);
764 return 0;
765}
766
767/*
768 * Returns 1 if the range defined by <low> and <high> overlaps
769 * one of them in <rgs> array of ranges with <sz> the size of this
770 * array, 0 if not.
771 */
772int smp_log_ranges_overlap(struct smp_log_range *rgs, size_t sz,
773 unsigned int low, unsigned int high, char **err)
774{
775 size_t i;
776
777 for (i = 0; i < sz; i++) {
778 if ((low >= rgs[i].low && low <= rgs[i].high) ||
779 (high >= rgs[i].low && high <= rgs[i].high)) {
780 memprintf(err, "ranges are overlapping");
781 return 1;
782 }
783 }
784
785 return 0;
786}
787
788int smp_log_range_cmp(const void *a, const void *b)
789{
790 const struct smp_log_range *rg_a = a;
791 const struct smp_log_range *rg_b = b;
792
793 if (rg_a->high < rg_b->low)
794 return -1;
795 else if (rg_a->low > rg_b->high)
796 return 1;
797
798 return 0;
799}
800
801/*
Christopher Faulet4b0b79d2018-03-26 15:54:32 +0200802 * Parse "log" keyword and update <logsrvs> list accordingly.
803 *
804 * When <do_del> is set, it means the "no log" line was parsed, so all log
805 * servers in <logsrvs> are released.
806 *
807 * Otherwise, we try to parse the "log" line. First of all, when the list is not
808 * the global one, we look for the parameter "global". If we find it,
809 * global.logsrvs is copied. Else we parse each arguments.
810 *
811 * The function returns 1 in success case, otherwise, it returns 0 and err is
812 * filled.
813 */
814int parse_logsrv(char **args, struct list *logsrvs, int do_del, char **err)
815{
816 struct sockaddr_storage *sk;
817 struct logsrv *logsrv = NULL;
818 int port1, port2;
819 int cur_arg;
820
821 /*
822 * "no log": delete previous herited or defined syslog
823 * servers.
824 */
825 if (do_del) {
826 struct logsrv *back;
827
828 if (*(args[1]) != 0) {
829 memprintf(err, "'no log' does not expect arguments");
830 goto error;
831 }
832
833 list_for_each_entry_safe(logsrv, back, logsrvs, list) {
834 LIST_DEL(&logsrv->list);
835 free(logsrv);
836 }
837 return 1;
838 }
839
840 /*
841 * "log global": copy global.logrsvs linked list to the end of logsrvs
842 * list. But first, we check (logsrvs != global.logsrvs).
843 */
844 if (*(args[1]) && *(args[2]) == 0 && !strcmp(args[1], "global")) {
845 if (logsrvs == &global.logsrvs) {
846 memprintf(err, "'global' is not supported for a global syslog server");
847 goto error;
848 }
849 list_for_each_entry(logsrv, &global.logsrvs, list) {
Christopher Faulet28ac0992018-03-26 16:09:19 +0200850 struct logsrv *node;
851
852 list_for_each_entry(node, logsrvs, list) {
853 if (node->ref == logsrv)
854 goto skip_logsrv;
855 }
856
857 node = malloc(sizeof(*node));
Christopher Faulet4b0b79d2018-03-26 15:54:32 +0200858 memcpy(node, logsrv, sizeof(struct logsrv));
Christopher Faulet28ac0992018-03-26 16:09:19 +0200859 node->ref = logsrv;
Christopher Faulet4b0b79d2018-03-26 15:54:32 +0200860 LIST_INIT(&node->list);
861 LIST_ADDQ(logsrvs, &node->list);
Christopher Faulet28ac0992018-03-26 16:09:19 +0200862
863 skip_logsrv:
864 continue;
Christopher Faulet4b0b79d2018-03-26 15:54:32 +0200865 }
866 return 1;
867 }
868
869 /*
870 * "log <address> ...: parse a syslog server line
871 */
872 if (*(args[1]) == 0 || *(args[2]) == 0) {
873 memprintf(err, "expects <address> and <facility> %s as arguments",
874 ((logsrvs == &global.logsrvs) ? "" : "or global"));
875 goto error;
876 }
877
Willy Tarreau5a32ecc2018-11-12 07:34:59 +0100878 /* take care of "stdout" and "stderr" as regular aliases for fd@1 / fd@2 */
879 if (strcmp(args[1], "stdout") == 0)
880 args[1] = "fd@1";
881 else if (strcmp(args[1], "stderr") == 0)
882 args[1] = "fd@2";
883
Christopher Faulet4b0b79d2018-03-26 15:54:32 +0200884 logsrv = calloc(1, sizeof(*logsrv));
885 if (!logsrv) {
886 memprintf(err, "out of memory");
887 goto error;
888 }
889
890 /* skip address for now, it will be parsed at the end */
891 cur_arg = 2;
892
893 /* just after the address, a length may be specified */
894 logsrv->maxlen = MAX_SYSLOG_LEN;
895 if (strcmp(args[cur_arg], "len") == 0) {
896 int len = atoi(args[cur_arg+1]);
897 if (len < 80 || len > 65535) {
898 memprintf(err, "invalid log length '%s', must be between 80 and 65535",
899 args[cur_arg+1]);
900 goto error;
901 }
902 logsrv->maxlen = len;
903 cur_arg += 2;
904 }
905 if (logsrv->maxlen > global.max_syslog_len)
906 global.max_syslog_len = logsrv->maxlen;
907
908 /* after the length, a format may be specified */
909 if (strcmp(args[cur_arg], "format") == 0) {
910 logsrv->format = get_log_format(args[cur_arg+1]);
911 if (logsrv->format < 0) {
912 memprintf(err, "unknown log format '%s'", args[cur_arg+1]);
913 goto error;
914 }
915 cur_arg += 2;
916 }
917
Frédéric Lécailled95ea282019-04-24 16:14:33 +0200918 if (strcmp(args[cur_arg], "sample") == 0) {
919 unsigned low, high;
920 char *p, *beg, *end, *smp_sz_str;
921 struct smp_log_range *smp_rgs = NULL;
922 size_t smp_rgs_sz = 0, smp_sz = 0, new_smp_sz;
923
924 p = args[cur_arg+1];
925 smp_sz_str = strchr(p, ':');
926 if (!smp_sz_str) {
927 memprintf(err, "Missing sample size");
928 goto error;
929 }
930
931 *smp_sz_str++ = '\0';
932
933 end = p + strlen(p);
934
935 while (p != end) {
936 if (!get_logsrv_smp_range(&low, &high, &p, err))
937 goto error;
938
939 if (smp_rgs && smp_log_ranges_overlap(smp_rgs, smp_rgs_sz, low, high, err))
940 goto error;
941
942 smp_rgs = my_realloc2(smp_rgs, (smp_rgs_sz + 1) * sizeof *smp_rgs);
943 if (!smp_rgs) {
944 memprintf(err, "out of memory error");
945 goto error;
946 }
947
948 smp_rgs[smp_rgs_sz].low = low;
949 smp_rgs[smp_rgs_sz].high = high;
950 smp_rgs[smp_rgs_sz].sz = high - low + 1;
951 smp_rgs[smp_rgs_sz].curr_idx = 0;
952 if (smp_rgs[smp_rgs_sz].high > smp_sz)
953 smp_sz = smp_rgs[smp_rgs_sz].high;
954 smp_rgs_sz++;
955 }
956
Tim Duesterhus21648002019-06-23 22:10:10 +0200957 if (smp_rgs == NULL) {
958 memprintf(err, "no sampling ranges given");
959 goto error;
960 }
961
Frédéric Lécailled95ea282019-04-24 16:14:33 +0200962 beg = smp_sz_str;
963 end = beg + strlen(beg);
964 new_smp_sz = read_uint((const char **)&beg, end);
965 if (!new_smp_sz || beg != end) {
966 memprintf(err, "wrong sample size '%s' for sample range '%s'",
967 smp_sz_str, args[cur_arg+1]);
968 goto error;
969 }
970
971 if (new_smp_sz < smp_sz) {
972 memprintf(err, "sample size %zu should be greater or equal to "
973 "%zu the maximum of the high ranges limits",
974 new_smp_sz, smp_sz);
975 goto error;
976 }
977 smp_sz = new_smp_sz;
978
979 /* Let's order <smp_rgs> array. */
980 qsort(smp_rgs, smp_rgs_sz, sizeof(struct smp_log_range), smp_log_range_cmp);
981
982 logsrv->lb.smp_rgs = smp_rgs;
983 logsrv->lb.smp_rgs_sz = smp_rgs_sz;
984 logsrv->lb.smp_sz = smp_sz;
985
986 cur_arg += 2;
987 }
Frédéric Lécailled803e472019-04-25 07:42:09 +0200988 HA_SPIN_INIT(&logsrv->lock);
Christopher Faulet4b0b79d2018-03-26 15:54:32 +0200989 /* parse the facility */
990 logsrv->facility = get_log_facility(args[cur_arg]);
991 if (logsrv->facility < 0) {
992 memprintf(err, "unknown log facility '%s'", args[cur_arg]);
993 goto error;
994 }
995 cur_arg++;
996
997 /* parse the max syslog level (default: debug) */
998 logsrv->level = 7;
999 if (*(args[cur_arg])) {
1000 logsrv->level = get_log_level(args[cur_arg]);
1001 if (logsrv->level < 0) {
1002 memprintf(err, "unknown optional log level '%s'", args[cur_arg]);
1003 goto error;
1004 }
1005 cur_arg++;
1006 }
1007
1008 /* parse the limit syslog level (default: emerg) */
1009 logsrv->minlvl = 0;
1010 if (*(args[cur_arg])) {
1011 logsrv->minlvl = get_log_level(args[cur_arg]);
1012 if (logsrv->minlvl < 0) {
1013 memprintf(err, "unknown optional minimum log level '%s'", args[cur_arg]);
1014 goto error;
1015 }
1016 cur_arg++;
1017 }
1018
1019 /* Too many args */
1020 if (*(args[cur_arg])) {
1021 memprintf(err, "cannot handle unexpected argument '%s'", args[cur_arg]);
1022 goto error;
1023 }
1024
1025 /* now, back to the address */
Willy Tarreauf3dc30f2019-08-30 14:18:44 +02001026 logsrv->type = LOG_TARGET_DGRAM;
Willy Tarreauc046d162019-08-30 15:24:59 +02001027 if (strncmp(args[1], "ring@", 5) == 0) {
1028 struct sink *sink = sink_find(args[1] + 5);
1029
1030 if (!sink || sink->type != SINK_TYPE_BUFFER) {
1031 memprintf(err, "cannot find ring buffer '%s'", args[1] + 5);
1032 goto error;
1033 }
1034
1035 logsrv->addr.ss_family = AF_UNSPEC;
1036 logsrv->type = LOG_TARGET_BUFFER;
1037 logsrv->ring = sink->ctx.ring;
1038 goto done;
1039 }
1040
Willy Tarreauf3dc30f2019-08-30 14:18:44 +02001041 if (strncmp(args[1], "fd@", 3) == 0)
1042 logsrv->type = LOG_TARGET_FD;
1043
Christopher Faulet4b0b79d2018-03-26 15:54:32 +02001044 sk = str2sa_range(args[1], NULL, &port1, &port2, err, NULL, NULL, 1);
1045 if (!sk)
1046 goto error;
1047 logsrv->addr = *sk;
1048
1049 if (sk->ss_family == AF_INET || sk->ss_family == AF_INET6) {
1050 if (port1 != port2) {
1051 memprintf(err, "port ranges and offsets are not allowed in '%s'", args[1]);
1052 goto error;
1053 }
1054 logsrv->addr = *sk;
1055 if (!port1)
1056 set_host_port(&logsrv->addr, SYSLOG_PORT);
1057 }
Willy Tarreauc046d162019-08-30 15:24:59 +02001058 done:
Christopher Faulet4b0b79d2018-03-26 15:54:32 +02001059 LIST_ADDQ(logsrvs, &logsrv->list);
1060 return 1;
1061
1062 error:
1063 free(logsrv);
1064 return 0;
1065}
1066
1067
Christopher Fauletd4696382017-10-24 11:44:05 +02001068/* Generic function to display messages prefixed by a label */
1069static void print_message(const char *label, const char *fmt, va_list argp)
1070{
1071 struct tm tm;
1072 char *head, *msg;
1073
1074 head = msg = NULL;
1075
1076 get_localtime(date.tv_sec, &tm);
1077 memprintf(&head, "[%s] %03d/%02d%02d%02d (%d) : ",
1078 label, tm.tm_yday, tm.tm_hour, tm.tm_min, tm.tm_sec, (int)getpid());
1079 memvprintf(&msg, fmt, argp);
1080
Willy Tarreau869efd52019-11-15 15:16:57 +01001081 if (global.mode & MODE_STARTING) {
1082 if (unlikely(!startup_logs))
1083 startup_logs = ring_new(STARTUP_LOG_SIZE);
1084
1085 if (likely(startup_logs)) {
1086 struct ist m[2];
1087
1088 m[0] = ist(head);
1089 m[1] = ist(msg);
1090 /* trim the trailing '\n' */
1091 if (m[1].len > 0 && m[1].ptr[m[1].len - 1] == '\n')
1092 m[1].len--;
1093 ring_write(startup_logs, ~0, 0, 0, m, 2);
1094 }
1095 }
Christopher Fauletd4696382017-10-24 11:44:05 +02001096
1097 fprintf(stderr, "%s%s", head, msg);
1098 fflush(stderr);
1099
1100 free(head);
1101 free(msg);
1102}
1103
Willy Tarreaubaaee002006-06-26 02:48:02 +02001104/*
1105 * Displays the message on stderr with the date and pid. Overrides the quiet
1106 * mode during startup.
1107 */
Christopher Faulet767a84b2017-11-24 16:50:31 +01001108void ha_alert(const char *fmt, ...)
Willy Tarreaubaaee002006-06-26 02:48:02 +02001109{
1110 va_list argp;
Willy Tarreaubaaee002006-06-26 02:48:02 +02001111
1112 if (!(global.mode & MODE_QUIET) || (global.mode & (MODE_VERBOSE | MODE_STARTING))) {
Willy Tarreaubb869862020-04-16 10:52:41 +02001113 if (!(warned & WARN_EXEC_PATH)) {
1114 const char *path = get_exec_path();
1115
1116 warned |= WARN_EXEC_PATH;
1117 ha_notice("haproxy version is %s\n", haproxy_version);
1118 if (path)
1119 ha_notice("path to executable is %s\n", path);
1120 }
Willy Tarreaubaaee002006-06-26 02:48:02 +02001121 va_start(argp, fmt);
Christopher Fauletd4696382017-10-24 11:44:05 +02001122 print_message("ALERT", fmt, argp);
Willy Tarreaubaaee002006-06-26 02:48:02 +02001123 va_end(argp);
1124 }
1125}
1126
1127
1128/*
1129 * Displays the message on stderr with the date and pid.
1130 */
Christopher Faulet767a84b2017-11-24 16:50:31 +01001131void ha_warning(const char *fmt, ...)
Willy Tarreaubaaee002006-06-26 02:48:02 +02001132{
1133 va_list argp;
Willy Tarreaubaaee002006-06-26 02:48:02 +02001134
Willy Tarreaubebd2122020-04-15 16:06:11 +02001135 warned |= WARN_ANY;
1136
Willy Tarreaubaaee002006-06-26 02:48:02 +02001137 if (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE)) {
1138 va_start(argp, fmt);
Christopher Fauletd4696382017-10-24 11:44:05 +02001139 print_message("WARNING", fmt, argp);
Willy Tarreaubaaee002006-06-26 02:48:02 +02001140 va_end(argp);
1141 }
1142}
1143
1144/*
William Lallemand9c56a222018-11-21 18:04:52 +01001145 * Displays the message on stderr with the date and pid.
1146 */
1147void ha_notice(const char *fmt, ...)
1148{
1149 va_list argp;
1150
1151 if (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE)) {
1152 va_start(argp, fmt);
1153 print_message("NOTICE", fmt, argp);
1154 va_end(argp);
1155 }
1156}
1157
1158/*
Willy Tarreaubaaee002006-06-26 02:48:02 +02001159 * Displays the message on <out> only if quiet mode is not set.
1160 */
Willy Tarreaub17916e2006-10-15 15:17:57 +02001161void qfprintf(FILE *out, const char *fmt, ...)
Willy Tarreaubaaee002006-06-26 02:48:02 +02001162{
1163 va_list argp;
1164
1165 if (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE)) {
1166 va_start(argp, fmt);
1167 vfprintf(out, fmt, argp);
1168 fflush(out);
1169 va_end(argp);
1170 }
1171}
1172
1173/*
Dragan Dosen1322d092015-09-22 16:05:32 +02001174 * returns log format for <fmt> or -1 if not found.
1175 */
1176int get_log_format(const char *fmt)
1177{
1178 int format;
1179
1180 format = LOG_FORMATS - 1;
Dragan Dosen43885c72015-10-01 13:18:13 +02001181 while (format >= 0 && strcmp(log_formats[format].name, fmt))
Dragan Dosen1322d092015-09-22 16:05:32 +02001182 format--;
1183
1184 return format;
1185}
1186
1187/*
Willy Tarreaubaaee002006-06-26 02:48:02 +02001188 * returns log level for <lev> or -1 if not found.
1189 */
1190int get_log_level(const char *lev)
1191{
1192 int level;
1193
1194 level = NB_LOG_LEVELS - 1;
1195 while (level >= 0 && strcmp(log_levels[level], lev))
1196 level--;
1197
1198 return level;
1199}
1200
Willy Tarreaubaaee002006-06-26 02:48:02 +02001201/*
1202 * returns log facility for <fac> or -1 if not found.
1203 */
1204int get_log_facility(const char *fac)
1205{
1206 int facility;
1207
1208 facility = NB_LOG_FACILITIES - 1;
1209 while (facility >= 0 && strcmp(log_facilities[facility], fac))
1210 facility--;
William Lallemand2a4a44f2012-02-06 16:00:33 +01001211
Willy Tarreaubaaee002006-06-26 02:48:02 +02001212 return facility;
1213}
1214
William Lallemanda1cc3812012-02-08 16:38:44 +01001215/*
Dragan Dosen835b9212016-02-12 13:23:03 +01001216 * Encode the string.
1217 *
1218 * When using the +E log format option, it will try to escape '"\]'
1219 * characters with '\' as prefix. The same prefix should not be used as
1220 * <escape>.
1221 */
1222static char *lf_encode_string(char *start, char *stop,
Willy Tarreau1bfd6022019-06-07 11:10:07 +02001223 const char escape, const long *map,
Dragan Dosen835b9212016-02-12 13:23:03 +01001224 const char *string,
1225 struct logformat_node *node)
1226{
1227 if (node->options & LOG_OPT_ESC) {
1228 if (start < stop) {
1229 stop--; /* reserve one byte for the final '\0' */
1230 while (start < stop && *string != '\0') {
Willy Tarreau1bfd6022019-06-07 11:10:07 +02001231 if (!ha_bit_test((unsigned char)(*string), map)) {
1232 if (!ha_bit_test((unsigned char)(*string), rfc5424_escape_map))
Dragan Dosen835b9212016-02-12 13:23:03 +01001233 *start++ = *string;
1234 else {
1235 if (start + 2 >= stop)
1236 break;
1237 *start++ = '\\';
1238 *start++ = *string;
1239 }
1240 }
1241 else {
1242 if (start + 3 >= stop)
1243 break;
1244 *start++ = escape;
1245 *start++ = hextab[(*string >> 4) & 15];
1246 *start++ = hextab[*string & 15];
1247 }
1248 string++;
1249 }
1250 *start = '\0';
1251 }
1252 }
1253 else {
1254 return encode_string(start, stop, escape, map, string);
1255 }
1256
1257 return start;
1258}
1259
1260/*
1261 * Encode the chunk.
1262 *
1263 * When using the +E log format option, it will try to escape '"\]'
1264 * characters with '\' as prefix. The same prefix should not be used as
1265 * <escape>.
1266 */
1267static char *lf_encode_chunk(char *start, char *stop,
Willy Tarreau1bfd6022019-06-07 11:10:07 +02001268 const char escape, const long *map,
Willy Tarreau83061a82018-07-13 11:56:34 +02001269 const struct buffer *chunk,
Dragan Dosen835b9212016-02-12 13:23:03 +01001270 struct logformat_node *node)
1271{
1272 char *str, *end;
1273
1274 if (node->options & LOG_OPT_ESC) {
1275 if (start < stop) {
Willy Tarreau843b7cb2018-07-13 10:54:26 +02001276 str = chunk->area;
1277 end = chunk->area + chunk->data;
Dragan Dosen835b9212016-02-12 13:23:03 +01001278
1279 stop--; /* reserve one byte for the final '\0' */
1280 while (start < stop && str < end) {
Willy Tarreau1bfd6022019-06-07 11:10:07 +02001281 if (!ha_bit_test((unsigned char)(*str), map)) {
1282 if (!ha_bit_test((unsigned char)(*str), rfc5424_escape_map))
Dragan Dosen835b9212016-02-12 13:23:03 +01001283 *start++ = *str;
1284 else {
1285 if (start + 2 >= stop)
1286 break;
1287 *start++ = '\\';
1288 *start++ = *str;
1289 }
1290 }
1291 else {
1292 if (start + 3 >= stop)
1293 break;
1294 *start++ = escape;
1295 *start++ = hextab[(*str >> 4) & 15];
1296 *start++ = hextab[*str & 15];
1297 }
1298 str++;
1299 }
1300 *start = '\0';
1301 }
1302 }
1303 else {
1304 return encode_chunk(start, stop, escape, map, chunk);
1305 }
1306
1307 return start;
1308}
1309
1310/*
William Lallemanda1cc3812012-02-08 16:38:44 +01001311 * Write a string in the log string
Dragan Dosen835b9212016-02-12 13:23:03 +01001312 * Take cares of quote and escape options
William Lallemanda1cc3812012-02-08 16:38:44 +01001313 *
Joseph Herlant85b40592018-11-15 12:10:04 -08001314 * Return the address of the \0 character, or NULL on error
William Lallemanda1cc3812012-02-08 16:38:44 +01001315 */
Willy Tarreau26ffa852018-09-05 15:23:10 +02001316char *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 +01001317{
Willy Tarreau2b0108a2012-12-21 19:23:44 +01001318 if (size < 2)
1319 return NULL;
William Lallemanda1cc3812012-02-08 16:38:44 +01001320
Willy Tarreau2b0108a2012-12-21 19:23:44 +01001321 if (node->options & LOG_OPT_QUOTE) {
1322 *(dst++) = '"';
1323 size--;
William Lallemandbddd4fd2012-02-27 11:23:10 +01001324 }
Willy Tarreau2b0108a2012-12-21 19:23:44 +01001325
Willy Tarreau6cbbdbf2013-02-05 18:52:25 +01001326 if (src && len) {
Dragan Dosendb1b6f92016-07-25 11:35:02 +02001327 if (++len > size)
1328 len = size;
Dragan Dosen835b9212016-02-12 13:23:03 +01001329 if (node->options & LOG_OPT_ESC) {
Dragan Dosen835b9212016-02-12 13:23:03 +01001330 char *ret;
1331
Dragan Dosendb1b6f92016-07-25 11:35:02 +02001332 ret = escape_string(dst, dst + len, '\\', rfc5424_escape_map, src);
Dragan Dosen835b9212016-02-12 13:23:03 +01001333 if (ret == NULL || *ret != '\0')
1334 return NULL;
1335 len = ret - dst;
1336 }
1337 else {
Dragan Dosen835b9212016-02-12 13:23:03 +01001338 len = strlcpy2(dst, src, len);
1339 }
Willy Tarreau2b0108a2012-12-21 19:23:44 +01001340
1341 size -= len;
1342 dst += len;
1343 }
Willy Tarreau6cbbdbf2013-02-05 18:52:25 +01001344 else if ((node->options & (LOG_OPT_QUOTE|LOG_OPT_MANDATORY)) == LOG_OPT_MANDATORY) {
1345 if (size < 2)
1346 return NULL;
1347 *(dst++) = '-';
1348 }
Willy Tarreau2b0108a2012-12-21 19:23:44 +01001349
1350 if (node->options & LOG_OPT_QUOTE) {
1351 if (size < 2)
1352 return NULL;
1353 *(dst++) = '"';
1354 }
1355
1356 *dst = '\0';
William Lallemandbddd4fd2012-02-27 11:23:10 +01001357 return dst;
William Lallemanda1cc3812012-02-08 16:38:44 +01001358}
1359
Willy Tarreau26ffa852018-09-05 15:23:10 +02001360static inline char *lf_text(char *dst, const char *src, size_t size, const struct logformat_node *node)
Willy Tarreau2b0108a2012-12-21 19:23:44 +01001361{
1362 return lf_text_len(dst, src, size, size, node);
1363}
1364
William Lallemand5f232402012-04-05 18:02:55 +02001365/*
Joseph Herlant85b40592018-11-15 12:10:04 -08001366 * Write a IP address to the log string
Ilya Shipitsin856aabc2020-04-16 23:51:34 +05001367 * +X option write in hexadecimal notation, most significant byte on the left
William Lallemand5f232402012-04-05 18:02:55 +02001368 */
Willy Tarreau26ffa852018-09-05 15:23:10 +02001369char *lf_ip(char *dst, const struct sockaddr *sockaddr, size_t size, const struct logformat_node *node)
William Lallemand5f232402012-04-05 18:02:55 +02001370{
1371 char *ret = dst;
1372 int iret;
1373 char pn[INET6_ADDRSTRLEN];
1374
1375 if (node->options & LOG_OPT_HEXA) {
Radek Zajic594c4562019-03-22 10:21:54 +00001376 unsigned char *addr = NULL;
1377 switch (sockaddr->sa_family) {
1378 case AF_INET:
1379 addr = (unsigned char *)&((struct sockaddr_in *)sockaddr)->sin_addr.s_addr;
1380 iret = snprintf(dst, size, "%02X%02X%02X%02X", addr[0], addr[1], addr[2], addr[3]);
1381 break;
1382 case AF_INET6:
1383 addr = (unsigned char *)&((struct sockaddr_in6 *)sockaddr)->sin6_addr.s6_addr;
1384 iret = snprintf(dst, size, "%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X",
1385 addr[0], addr[1], addr[2], addr[3], addr[4], addr[5], addr[6], addr[7],
1386 addr[8], addr[9], addr[10], addr[11], addr[12], addr[13], addr[14], addr[15]);
1387 break;
1388 default:
1389 return NULL;
1390 }
William Lallemand5f232402012-04-05 18:02:55 +02001391 if (iret < 0 || iret > size)
1392 return NULL;
1393 ret += iret;
1394 } else {
1395 addr_to_str((struct sockaddr_storage *)sockaddr, pn, sizeof(pn));
1396 ret = lf_text(dst, pn, size, node);
1397 if (ret == NULL)
1398 return NULL;
1399 }
1400 return ret;
1401}
1402
1403/*
1404 * Write a port to the log
Ilya Shipitsin856aabc2020-04-16 23:51:34 +05001405 * +X option write in hexadecimal notation, most significant byte on the left
William Lallemand5f232402012-04-05 18:02:55 +02001406 */
Willy Tarreau26ffa852018-09-05 15:23:10 +02001407char *lf_port(char *dst, const struct sockaddr *sockaddr, size_t size, const struct logformat_node *node)
William Lallemand5f232402012-04-05 18:02:55 +02001408{
1409 char *ret = dst;
1410 int iret;
1411
1412 if (node->options & LOG_OPT_HEXA) {
1413 const unsigned char *port = (const unsigned char *)&((struct sockaddr_in *)sockaddr)->sin_port;
1414 iret = snprintf(dst, size, "%02X%02X", port[0], port[1]);
1415 if (iret < 0 || iret > size)
1416 return NULL;
1417 ret += iret;
1418 } else {
1419 ret = ltoa_o(get_host_port((struct sockaddr_storage *)sockaddr), dst, size);
1420 if (ret == NULL)
1421 return NULL;
1422 }
1423 return ret;
1424}
1425
Dragan Dosen1322d092015-09-22 16:05:32 +02001426/* Re-generate time-based part of the syslog header in RFC3164 format at
1427 * the beginning of logheader once a second and return the pointer to the
1428 * first character after it.
Willy Tarreaub1a2faf2012-03-19 16:51:53 +01001429 */
Dragan Dosen0b85ece2015-09-25 19:17:44 +02001430static char *update_log_hdr(const time_t time)
Willy Tarreaubaaee002006-06-26 02:48:02 +02001431{
Christopher Fauletf8188c62017-06-02 16:20:16 +02001432 static THREAD_LOCAL long tvsec;
Willy Tarreau83061a82018-07-13 11:56:34 +02001433 static THREAD_LOCAL struct buffer host = { };
Christopher Fauletf8188c62017-06-02 16:20:16 +02001434 static THREAD_LOCAL int sep = 0;
Willy Tarreaubaaee002006-06-26 02:48:02 +02001435
Willy Tarreau55e2f5a2019-05-05 10:11:39 +02001436 if (unlikely(time != tvsec || logheader_end == NULL)) {
Willy Tarreaubaaee002006-06-26 02:48:02 +02001437 /* this string is rebuild only once a second */
Willy Tarreaufe944602007-10-25 10:34:16 +02001438 struct tm tm;
Willy Tarreaub1a2faf2012-03-19 16:51:53 +01001439 int hdr_len;
Willy Tarreaufe944602007-10-25 10:34:16 +02001440
Dragan Dosen0b85ece2015-09-25 19:17:44 +02001441 tvsec = time;
Willy Tarreaufe944602007-10-25 10:34:16 +02001442 get_localtime(tvsec, &tm);
Willy Tarreaubaaee002006-06-26 02:48:02 +02001443
Willy Tarreau843b7cb2018-07-13 10:54:26 +02001444 if (unlikely(global.log_send_hostname != host.area)) {
1445 host.area = global.log_send_hostname;
1446 host.data = host.area ? strlen(host.area) : 0;
1447 sep = host.data ? 1 : 0;
Dragan Dosen43885c72015-10-01 13:18:13 +02001448 }
1449
Dragan Dosen59cee972015-09-19 22:09:02 +02001450 hdr_len = snprintf(logheader, global.max_syslog_len,
Dragan Dosen43885c72015-10-01 13:18:13 +02001451 "<<<<>%s %2d %02d:%02d:%02d %.*s%*s",
Willy Tarreaufe944602007-10-25 10:34:16 +02001452 monthname[tm.tm_mon],
Dragan Dosen43885c72015-10-01 13:18:13 +02001453 tm.tm_mday, tm.tm_hour, tm.tm_min, tm.tm_sec,
Willy Tarreau843b7cb2018-07-13 10:54:26 +02001454 (int)host.data, host.area, sep, "");
Willy Tarreaubaaee002006-06-26 02:48:02 +02001455 /* WARNING: depending upon implementations, snprintf may return
1456 * either -1 or the number of bytes that would be needed to store
1457 * the total message. In both cases, we must adjust it.
1458 */
Willy Tarreau18324f52014-06-27 18:10:07 +02001459 if (hdr_len < 0 || hdr_len > global.max_syslog_len)
1460 hdr_len = global.max_syslog_len;
Willy Tarreaubaaee002006-06-26 02:48:02 +02001461
Willy Tarreau55e2f5a2019-05-05 10:11:39 +02001462 logheader_end = logheader + hdr_len;
Willy Tarreaubaaee002006-06-26 02:48:02 +02001463 }
1464
Willy Tarreau55e2f5a2019-05-05 10:11:39 +02001465 logheader_end[0] = 0; // ensure we get rid of any previous attempt
Willy Tarreau094af4e2015-01-07 15:03:42 +01001466
Willy Tarreau55e2f5a2019-05-05 10:11:39 +02001467 return logheader_end;
William Lallemand2a4a44f2012-02-06 16:00:33 +01001468}
1469
Dragan Dosen1322d092015-09-22 16:05:32 +02001470/* Re-generate time-based part of the syslog header in RFC5424 format at
1471 * the beginning of logheader_rfc5424 once a second and return the pointer
1472 * to the first character after it.
1473 */
Dragan Dosen0b85ece2015-09-25 19:17:44 +02001474static char *update_log_hdr_rfc5424(const time_t time)
Dragan Dosen1322d092015-09-22 16:05:32 +02001475{
Christopher Fauletf8188c62017-06-02 16:20:16 +02001476 static THREAD_LOCAL long tvsec;
Benoit GARNIERb413c2a2016-03-27 11:08:03 +02001477 const char *gmt_offset;
Dragan Dosen1322d092015-09-22 16:05:32 +02001478
Willy Tarreau55e2f5a2019-05-05 10:11:39 +02001479 if (unlikely(time != tvsec || logheader_rfc5424_end == NULL)) {
Dragan Dosen1322d092015-09-22 16:05:32 +02001480 /* this string is rebuild only once a second */
1481 struct tm tm;
1482 int hdr_len;
1483
Dragan Dosen0b85ece2015-09-25 19:17:44 +02001484 tvsec = time;
Dragan Dosen1322d092015-09-22 16:05:32 +02001485 get_localtime(tvsec, &tm);
Benoit GARNIERe2e5bde2016-03-27 03:04:16 +02001486 gmt_offset = get_gmt_offset(time, &tm);
Dragan Dosen1322d092015-09-22 16:05:32 +02001487
1488 hdr_len = snprintf(logheader_rfc5424, global.max_syslog_len,
Dragan Dosen17def462015-10-09 21:31:43 +02001489 "<<<<>1 %4d-%02d-%02dT%02d:%02d:%02d%.3s:%.2s %s ",
Dragan Dosen1322d092015-09-22 16:05:32 +02001490 tm.tm_year+1900, tm.tm_mon+1, tm.tm_mday,
Dragan Dosen17def462015-10-09 21:31:43 +02001491 tm.tm_hour, tm.tm_min, tm.tm_sec,
Benoit GARNIERb413c2a2016-03-27 11:08:03 +02001492 gmt_offset, gmt_offset+3,
Dragan Dosen43885c72015-10-01 13:18:13 +02001493 global.log_send_hostname ? global.log_send_hostname : hostname);
Dragan Dosen1322d092015-09-22 16:05:32 +02001494 /* WARNING: depending upon implementations, snprintf may return
1495 * either -1 or the number of bytes that would be needed to store
1496 * the total message. In both cases, we must adjust it.
1497 */
1498 if (hdr_len < 0 || hdr_len > global.max_syslog_len)
1499 hdr_len = global.max_syslog_len;
1500
Willy Tarreau55e2f5a2019-05-05 10:11:39 +02001501 logheader_rfc5424_end = logheader_rfc5424 + hdr_len;
Dragan Dosen1322d092015-09-22 16:05:32 +02001502 }
1503
Willy Tarreau55e2f5a2019-05-05 10:11:39 +02001504 logheader_rfc5424_end[0] = 0; // ensure we get rid of any previous attempt
Dragan Dosen1322d092015-09-22 16:05:32 +02001505
Willy Tarreau55e2f5a2019-05-05 10:11:39 +02001506 return logheader_rfc5424_end;
Dragan Dosen1322d092015-09-22 16:05:32 +02001507}
1508
William Lallemand2a4a44f2012-02-06 16:00:33 +01001509/*
Dragan Dosen59cee972015-09-19 22:09:02 +02001510 * This function sends the syslog message using a printf format string. It
1511 * expects an LF-terminated message.
William Lallemand2a4a44f2012-02-06 16:00:33 +01001512 */
1513void send_log(struct proxy *p, int level, const char *format, ...)
1514{
1515 va_list argp;
Willy Tarreaub1a2faf2012-03-19 16:51:53 +01001516 int data_len;
William Lallemand2a4a44f2012-02-06 16:00:33 +01001517
Willy Tarreau8c97ab52015-01-15 16:29:53 +01001518 if (level < 0 || format == NULL || logline == NULL)
William Lallemand2a4a44f2012-02-06 16:00:33 +01001519 return;
1520
William Lallemand2a4a44f2012-02-06 16:00:33 +01001521 va_start(argp, format);
Dragan Dosen59cee972015-09-19 22:09:02 +02001522 data_len = vsnprintf(logline, global.max_syslog_len, format, argp);
Willy Tarreau18324f52014-06-27 18:10:07 +02001523 if (data_len < 0 || data_len > global.max_syslog_len)
1524 data_len = global.max_syslog_len;
Willy Tarreaubaaee002006-06-26 02:48:02 +02001525 va_end(argp);
William Lallemand2a4a44f2012-02-06 16:00:33 +01001526
Christopher Faulet5c6fefc2019-08-11 19:40:12 +02001527 __send_log((p ? &p->logsrvs : NULL), (p ? &p->log_tag : NULL), level,
1528 logline, data_len, default_rfc5424_sd_log_format, 2);
William Lallemand2a4a44f2012-02-06 16:00:33 +01001529}
1530
1531/*
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001532 * This function sends a syslog message to <logsrv>.
1533 * <pid_str> is the string to be used for the PID of the caller, <pid_size> is length.
1534 * Same thing for <sd> and <sd_size> which are used for the structured-data part
1535 * in RFC5424 formatted syslog messages, and <tag_str> and <tag_size> the syslog tag.
Dragan Dosen0b85ece2015-09-25 19:17:44 +02001536 * It overrides the last byte of the message vector with an LF character.
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001537 * Does not return any error,
William Lallemand2a4a44f2012-02-06 16:00:33 +01001538 */
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001539static inline void __do_send_log(struct logsrv *logsrv, int nblogger, char *pid_str, size_t pid_size,
1540 int level, char *message, size_t size, char *sd, size_t sd_size,
1541 char *tag_str, size_t tag_size)
William Lallemand2a4a44f2012-02-06 16:00:33 +01001542{
Christopher Fauletf8188c62017-06-02 16:20:16 +02001543 static THREAD_LOCAL struct iovec iovec[NB_MSG_IOVEC_ELEMENTS] = { };
1544 static THREAD_LOCAL struct msghdr msghdr = {
1545 //.msg_iov = iovec,
Dragan Dosen609ac2a2015-09-16 18:25:42 +02001546 .msg_iovlen = NB_MSG_IOVEC_ELEMENTS
1547 };
Christopher Fauletf8188c62017-06-02 16:20:16 +02001548 static THREAD_LOCAL int logfdunix = -1; /* syslog to AF_UNIX socket */
1549 static THREAD_LOCAL int logfdinet = -1; /* syslog to AF_INET socket */
1550 static THREAD_LOCAL char *dataptr = NULL;
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001551 time_t time = date.tv_sec;
Dragan Dosen1322d092015-09-22 16:05:32 +02001552 char *hdr, *hdr_ptr;
Dragan Dosen59cee972015-09-19 22:09:02 +02001553 size_t hdr_size;
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001554 int fac_level;
1555 int *plogfd;
1556 char *pid_sep1 = "", *pid_sep2 = "";
1557 char logheader_short[3];
1558 int sent;
1559 int maxlen;
1560 int hdr_max = 0;
1561 int tag_max = 0;
1562 int pid_sep1_max = 0;
Frédéric Lécaille90a10ae2019-05-14 10:57:58 +02001563 int pid_max = 0;
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001564 int pid_sep2_max = 0;
1565 int sd_max = 0;
1566 int max = 0;
Christopher Fauletf8188c62017-06-02 16:20:16 +02001567
1568 msghdr.msg_iov = iovec;
William Lallemand2a4a44f2012-02-06 16:00:33 +01001569
1570 dataptr = message;
Willy Tarreaubaaee002006-06-26 02:48:02 +02001571
Willy Tarreauf3dc30f2019-08-30 14:18:44 +02001572 if (logsrv->type == LOG_TARGET_FD) {
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001573 /* the socket's address is a file descriptor */
1574 plogfd = (int *)&((struct sockaddr_in *)&logsrv->addr)->sin_addr.s_addr;
Robert Tsai81ae1952007-12-05 10:47:29 +01001575 }
Willy Tarreauc046d162019-08-30 15:24:59 +02001576 else if (logsrv->type == LOG_TARGET_BUFFER) {
1577 plogfd = NULL;
1578 }
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001579 else if (logsrv->addr.ss_family == AF_UNIX)
1580 plogfd = &logfdunix;
1581 else
1582 plogfd = &logfdinet;
Robert Tsai81ae1952007-12-05 10:47:29 +01001583
Willy Tarreauc046d162019-08-30 15:24:59 +02001584 if (plogfd && unlikely(*plogfd < 0)) {
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001585 /* socket not successfully initialized yet */
1586 if ((*plogfd = socket(logsrv->addr.ss_family, SOCK_DGRAM,
1587 (logsrv->addr.ss_family == AF_UNIX) ? 0 : IPPROTO_UDP)) < 0) {
1588 static char once;
William Lallemand0f99e342011-10-12 17:50:54 +02001589
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001590 if (!once) {
1591 once = 1; /* note: no need for atomic ops here */
1592 ha_alert("socket() failed in logger #%d: %s (errno=%d)\n",
1593 nblogger, strerror(errno), errno);
1594 }
1595 return;
1596 } else {
1597 /* we don't want to receive anything on this socket */
1598 setsockopt(*plogfd, SOL_SOCKET, SO_RCVBUF, &zero, sizeof(zero));
1599 /* does nothing under Linux, maybe needed for others */
1600 shutdown(*plogfd, SHUT_RD);
1601 fcntl(*plogfd, F_SETFD, fcntl(*plogfd, F_GETFD, FD_CLOEXEC) | FD_CLOEXEC);
1602 }
Dragan Dosen43885c72015-10-01 13:18:13 +02001603 }
1604
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001605 switch (logsrv->format) {
1606 case LOG_FORMAT_RFC3164:
1607 hdr = logheader;
1608 hdr_ptr = update_log_hdr(time);
1609 break;
Willy Tarreauc7c7be22014-06-23 18:07:15 +02001610
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001611 case LOG_FORMAT_RFC5424:
1612 hdr = logheader_rfc5424;
1613 hdr_ptr = update_log_hdr_rfc5424(time);
1614 sd_max = sd_size; /* the SD part allowed only in RFC5424 */
1615 break;
William Lallemandbddd4fd2012-02-27 11:23:10 +01001616
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001617 case LOG_FORMAT_SHORT:
1618 /* all fields are known, skip the header generation */
1619 hdr = logheader_short;
1620 hdr[0] = '<';
1621 hdr[1] = '0' + MAX(level, logsrv->minlvl);
1622 hdr[2] = '>';
1623 hdr_ptr = hdr;
1624 hdr_max = 3;
1625 maxlen = logsrv->maxlen - hdr_max;
1626 max = MIN(size, maxlen) - 1;
1627 goto send;
Willy Tarreau204e3f12018-12-15 15:48:48 +01001628
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001629 case LOG_FORMAT_RAW:
1630 /* all fields are known, skip the header generation */
1631 hdr_ptr = hdr = "";
1632 hdr_max = 0;
1633 maxlen = logsrv->maxlen;
1634 max = MIN(size, maxlen) - 1;
1635 goto send;
Willy Tarreauc98aebc2018-03-20 11:17:29 +01001636
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001637 default:
1638 return; /* must never happen */
1639 }
Willy Tarreauc7c7be22014-06-23 18:07:15 +02001640
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001641 hdr_size = hdr_ptr - hdr;
Dragan Dosen1322d092015-09-22 16:05:32 +02001642
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001643 /* For each target, we may have a different facility.
1644 * We can also have a different log level for each message.
1645 * This induces variations in the message header length.
1646 * Since we don't want to recompute it each time, nor copy it every
1647 * time, we only change the facility in the pre-computed header,
1648 * and we change the pointer to the header accordingly.
1649 */
1650 fac_level = (logsrv->facility << 3) + MAX(level, logsrv->minlvl);
1651 hdr_ptr = hdr + 3; /* last digit of the log level */
1652 do {
1653 *hdr_ptr = '0' + fac_level % 10;
1654 fac_level /= 10;
1655 hdr_ptr--;
1656 } while (fac_level && hdr_ptr > hdr);
1657 *hdr_ptr = '<';
Dragan Dosen1322d092015-09-22 16:05:32 +02001658
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001659 hdr_max = hdr_size - (hdr_ptr - hdr);
Willy Tarreaue8746a02018-11-12 08:45:00 +01001660
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001661 /* time-based header */
1662 if (unlikely(hdr_size >= logsrv->maxlen)) {
1663 hdr_max = MIN(hdr_max, logsrv->maxlen) - 1;
1664 sd_max = 0;
1665 goto send;
1666 }
Willy Tarreauc1b06452018-11-12 11:57:56 +01001667
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001668 maxlen = logsrv->maxlen - hdr_max;
Dragan Dosen1322d092015-09-22 16:05:32 +02001669
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001670 /* tag */
Frédéric Lécaille90a10ae2019-05-14 10:57:58 +02001671 tag_max = tag_size;
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001672 if (unlikely(tag_max >= maxlen)) {
1673 tag_max = maxlen - 1;
1674 sd_max = 0;
1675 goto send;
1676 }
Dragan Dosen1322d092015-09-22 16:05:32 +02001677
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001678 maxlen -= tag_max;
William Lallemand2a4a44f2012-02-06 16:00:33 +01001679
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001680 /* first pid separator */
1681 pid_sep1_max = log_formats[logsrv->format].pid.sep1.data;
1682 if (unlikely(pid_sep1_max >= maxlen)) {
1683 pid_sep1_max = maxlen - 1;
1684 sd_max = 0;
1685 goto send;
1686 }
Dragan Dosen59cee972015-09-19 22:09:02 +02001687
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001688 pid_sep1 = log_formats[logsrv->format].pid.sep1.area;
1689 maxlen -= pid_sep1_max;
Dragan Dosen59cee972015-09-19 22:09:02 +02001690
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001691 /* pid */
Frédéric Lécaille90a10ae2019-05-14 10:57:58 +02001692 pid_max = pid_size;
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001693 if (unlikely(pid_size >= maxlen)) {
1694 pid_size = maxlen - 1;
1695 sd_max = 0;
1696 goto send;
1697 }
Dragan Dosen68d2e3a2015-09-19 22:35:44 +02001698
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001699 maxlen -= pid_size;
Dragan Dosen43885c72015-10-01 13:18:13 +02001700
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001701 /* second pid separator */
1702 pid_sep2_max = log_formats[logsrv->format].pid.sep2.data;
1703 if (unlikely(pid_sep2_max >= maxlen)) {
1704 pid_sep2_max = maxlen - 1;
1705 sd_max = 0;
1706 goto send;
1707 }
Dragan Dosen43885c72015-10-01 13:18:13 +02001708
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001709 pid_sep2 = log_formats[logsrv->format].pid.sep2.area;
1710 maxlen -= pid_sep2_max;
Dragan Dosen68d2e3a2015-09-19 22:35:44 +02001711
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001712 /* structured-data */
1713 if (sd_max >= maxlen) {
1714 sd_max = maxlen - 1;
1715 goto send;
1716 }
Dragan Dosen59cee972015-09-19 22:09:02 +02001717
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001718 max = MIN(size, maxlen - sd_max) - 1;
1719send:
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001720 if (logsrv->addr.ss_family == AF_UNSPEC) {
Willy Tarreauc046d162019-08-30 15:24:59 +02001721 /* the target is a file descriptor or a ring buffer */
Willy Tarreaud52a7f82019-08-30 14:05:35 +02001722 struct ist msg[7];
1723
1724 msg[0].ptr = hdr_ptr; msg[0].len = hdr_max;
1725 msg[1].ptr = tag_str; msg[1].len = tag_max;
1726 msg[2].ptr = pid_sep1; msg[2].len = pid_sep1_max;
1727 msg[3].ptr = pid_str; msg[3].len = pid_max;
1728 msg[4].ptr = pid_sep2; msg[4].len = pid_sep2_max;
1729 msg[5].ptr = sd; msg[5].len = sd_max;
1730 msg[6].ptr = dataptr; msg[6].len = max;
1731
Willy Tarreauc046d162019-08-30 15:24:59 +02001732 if (logsrv->type == LOG_TARGET_BUFFER)
1733 sent = ring_write(logsrv->ring, ~0, NULL, 0, msg, 7);
1734 else /* LOG_TARGET_FD */
1735 sent = fd_write_frag_line(*plogfd, ~0, NULL, 0, msg, 7, 1);
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001736 }
1737 else {
Willy Tarreaud52a7f82019-08-30 14:05:35 +02001738 iovec[0].iov_base = hdr_ptr;
1739 iovec[0].iov_len = hdr_max;
1740 iovec[1].iov_base = tag_str;
1741 iovec[1].iov_len = tag_max;
1742 iovec[2].iov_base = pid_sep1;
1743 iovec[2].iov_len = pid_sep1_max;
1744 iovec[3].iov_base = pid_str;
1745 iovec[3].iov_len = pid_max;
1746 iovec[4].iov_base = pid_sep2;
1747 iovec[4].iov_len = pid_sep2_max;
1748 iovec[5].iov_base = sd;
1749 iovec[5].iov_len = sd_max;
1750 iovec[6].iov_base = dataptr;
1751 iovec[6].iov_len = max;
1752 iovec[7].iov_base = "\n"; /* insert a \n at the end of the message */
1753 iovec[7].iov_len = 1;
1754
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001755 msghdr.msg_name = (struct sockaddr *)&logsrv->addr;
1756 msghdr.msg_namelen = get_addr_len(&logsrv->addr);
Dragan Dosen43885c72015-10-01 13:18:13 +02001757
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001758 sent = sendmsg(*plogfd, &msghdr, MSG_DONTWAIT | MSG_NOSIGNAL);
1759 }
Dragan Dosen43885c72015-10-01 13:18:13 +02001760
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001761 if (sent < 0) {
1762 static char once;
Dragan Dosen43885c72015-10-01 13:18:13 +02001763
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001764 if (errno == EAGAIN)
1765 _HA_ATOMIC_ADD(&dropped_logs, 1);
1766 else if (!once) {
1767 once = 1; /* note: no need for atomic ops here */
1768 ha_alert("sendmsg()/writev() failed in logger #%d: %s (errno=%d)\n",
1769 nblogger, strerror(errno), errno);
Dragan Dosen0b85ece2015-09-25 19:17:44 +02001770 }
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001771 }
1772}
Dragan Dosen59cee972015-09-19 22:09:02 +02001773
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001774/*
1775 * This function sends a syslog message.
1776 * It doesn't care about errors nor does it report them.
1777 * The arguments <sd> and <sd_size> are used for the structured-data part
1778 * in RFC5424 formatted syslog messages.
1779 */
Christopher Faulet5c6fefc2019-08-11 19:40:12 +02001780void __send_log(struct list *logsrvs, struct buffer *tag, int level,
1781 char *message, size_t size, char *sd, size_t sd_size)
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001782{
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001783 struct logsrv *logsrv;
1784 int nblogger;
1785 static THREAD_LOCAL int curr_pid;
1786 static THREAD_LOCAL char pidstr[100];
1787 static THREAD_LOCAL struct buffer pid;
Dragan Dosen609ac2a2015-09-16 18:25:42 +02001788
Christopher Faulet5c6fefc2019-08-11 19:40:12 +02001789 if (logsrvs == NULL) {
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001790 if (!LIST_ISEMPTY(&global.logsrvs)) {
1791 logsrvs = &global.logsrvs;
Willy Tarreau5a32ecc2018-11-12 07:34:59 +01001792 }
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001793 }
Christopher Faulet5c6fefc2019-08-11 19:40:12 +02001794 if (!tag || !tag->area)
1795 tag = &global.log_tag;
Willy Tarreau18324f52014-06-27 18:10:07 +02001796
Christopher Faulet5c6fefc2019-08-11 19:40:12 +02001797 if (!logsrvs || LIST_ISEMPTY(logsrvs))
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001798 return;
Willy Tarreauc98aebc2018-03-20 11:17:29 +01001799
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001800 if (unlikely(curr_pid != getpid())) {
1801 curr_pid = getpid();
1802 ltoa_o(curr_pid, pidstr, sizeof(pidstr));
1803 chunk_initstr(&pid, pidstr);
1804 }
1805
1806 /* Send log messages to syslog server. */
1807 nblogger = 0;
1808 list_for_each_entry(logsrv, logsrvs, list) {
Frédéric Lécailled803e472019-04-25 07:42:09 +02001809 static THREAD_LOCAL int in_range = 1;
1810
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001811 /* we can filter the level of the messages that are sent to each logger */
1812 if (level > logsrv->level)
1813 continue;
1814
Frédéric Lécailled803e472019-04-25 07:42:09 +02001815 if (logsrv->lb.smp_rgs) {
1816 struct smp_log_range *curr_rg;
1817
1818 HA_SPIN_LOCK(LOGSRV_LOCK, &logsrv->lock);
1819 curr_rg = &logsrv->lb.smp_rgs[logsrv->lb.curr_rg];
1820 in_range = in_smp_log_range(curr_rg, logsrv->lb.curr_idx);
1821 if (in_range) {
1822 /* Let's consume this range. */
1823 curr_rg->curr_idx = (curr_rg->curr_idx + 1) % curr_rg->sz;
1824 if (!curr_rg->curr_idx) {
1825 /* If consumed, let's select the next range. */
1826 logsrv->lb.curr_rg = (logsrv->lb.curr_rg + 1) % logsrv->lb.smp_rgs_sz;
1827 }
1828 }
1829 logsrv->lb.curr_idx = (logsrv->lb.curr_idx + 1) % logsrv->lb.smp_sz;
1830 HA_SPIN_UNLOCK(LOGSRV_LOCK, &logsrv->lock);
1831 }
1832 if (in_range)
1833 __do_send_log(logsrv, ++nblogger, pid.area, pid.data, level,
1834 message, size, sd, sd_size, tag->area, tag->data);
Willy Tarreaubaaee002006-06-26 02:48:02 +02001835 }
1836}
1837
1838
Willy Tarreauc89ccb62012-04-05 21:18:22 +02001839const 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 +01001840const char sess_set_cookie[8] = "NPDIRU67"; /* No set-cookie, Set-cookie found and left unchanged (passive),
1841 Set-cookie Deleted, Set-Cookie Inserted, Set-cookie Rewritten,
1842 Set-cookie Updated, unknown, unknown */
1843
William Lallemand1d705562012-03-12 12:46:41 +01001844/*
1845 * try to write a character if there is enough space, or goto out
1846 */
William Lallemandbddd4fd2012-02-27 11:23:10 +01001847#define LOGCHAR(x) do { \
William Lallemand1d705562012-03-12 12:46:41 +01001848 if (tmplog < dst + maxsize - 1) { \
William Lallemandbddd4fd2012-02-27 11:23:10 +01001849 *(tmplog++) = (x); \
1850 } else { \
1851 goto out; \
1852 } \
1853 } while(0)
1854
Dragan Dosen835b9212016-02-12 13:23:03 +01001855
Willy Tarreaub6b3df32018-11-26 16:31:20 +01001856/* Initializes some log data at boot */
1857static void init_log()
Dragan Dosen835b9212016-02-12 13:23:03 +01001858{
1859 char *tmp;
Willy Tarreaue10cd482018-09-10 18:16:53 +02001860 int i;
Dragan Dosen835b9212016-02-12 13:23:03 +01001861
1862 /* Initialize the escape map for the RFC5424 structured-data : '"\]'
1863 * inside PARAM-VALUE should be escaped with '\' as prefix.
1864 * See https://tools.ietf.org/html/rfc5424#section-6.3.3 for more
1865 * details.
1866 */
1867 memset(rfc5424_escape_map, 0, sizeof(rfc5424_escape_map));
1868
1869 tmp = "\"\\]";
1870 while (*tmp) {
Willy Tarreau1bfd6022019-06-07 11:10:07 +02001871 ha_bit_set(*tmp, rfc5424_escape_map);
Dragan Dosen835b9212016-02-12 13:23:03 +01001872 tmp++;
1873 }
Willy Tarreaue10cd482018-09-10 18:16:53 +02001874
1875 /* initialize the log header encoding map : '{|}"#' should be encoded with
1876 * '#' as prefix, as well as non-printable characters ( <32 or >= 127 ).
1877 * URL encoding only requires '"', '#' to be encoded as well as non-
1878 * printable characters above.
1879 */
1880 memset(hdr_encode_map, 0, sizeof(hdr_encode_map));
1881 memset(url_encode_map, 0, sizeof(url_encode_map));
1882 for (i = 0; i < 32; i++) {
Willy Tarreau1bfd6022019-06-07 11:10:07 +02001883 ha_bit_set(i, hdr_encode_map);
1884 ha_bit_set(i, url_encode_map);
Willy Tarreaue10cd482018-09-10 18:16:53 +02001885 }
1886 for (i = 127; i < 256; i++) {
Willy Tarreau1bfd6022019-06-07 11:10:07 +02001887 ha_bit_set(i, hdr_encode_map);
1888 ha_bit_set(i, url_encode_map);
Willy Tarreaue10cd482018-09-10 18:16:53 +02001889 }
1890
1891 tmp = "\"#{|}";
1892 while (*tmp) {
Willy Tarreau1bfd6022019-06-07 11:10:07 +02001893 ha_bit_set(*tmp, hdr_encode_map);
Willy Tarreaue10cd482018-09-10 18:16:53 +02001894 tmp++;
1895 }
1896
1897 tmp = "\"#";
1898 while (*tmp) {
Willy Tarreau1bfd6022019-06-07 11:10:07 +02001899 ha_bit_set(*tmp, url_encode_map);
Willy Tarreaue10cd482018-09-10 18:16:53 +02001900 tmp++;
1901 }
1902
1903 /* initialize the http header encoding map. The draft httpbis define the
1904 * header content as:
1905 *
1906 * HTTP-message = start-line
1907 * *( header-field CRLF )
1908 * CRLF
1909 * [ message-body ]
1910 * header-field = field-name ":" OWS field-value OWS
1911 * field-value = *( field-content / obs-fold )
1912 * field-content = field-vchar [ 1*( SP / HTAB ) field-vchar ]
1913 * obs-fold = CRLF 1*( SP / HTAB )
1914 * field-vchar = VCHAR / obs-text
1915 * VCHAR = %x21-7E
1916 * obs-text = %x80-FF
1917 *
1918 * All the chars are encoded except "VCHAR", "obs-text", SP and HTAB.
1919 * The encoded chars are form 0x00 to 0x08, 0x0a to 0x1f and 0x7f. The
Joseph Herlant85b40592018-11-15 12:10:04 -08001920 * "obs-fold" is voluntarily forgotten because haproxy remove this.
Willy Tarreaue10cd482018-09-10 18:16:53 +02001921 */
1922 memset(http_encode_map, 0, sizeof(http_encode_map));
1923 for (i = 0x00; i <= 0x08; i++)
Willy Tarreau1bfd6022019-06-07 11:10:07 +02001924 ha_bit_set(i, http_encode_map);
Willy Tarreaue10cd482018-09-10 18:16:53 +02001925 for (i = 0x0a; i <= 0x1f; i++)
Willy Tarreau1bfd6022019-06-07 11:10:07 +02001926 ha_bit_set(i, http_encode_map);
1927 ha_bit_set(0x7f, http_encode_map);
Dragan Dosen835b9212016-02-12 13:23:03 +01001928}
William Lallemand1d705562012-03-12 12:46:41 +01001929
Willy Tarreaub6b3df32018-11-26 16:31:20 +01001930INITCALL0(STG_PREPARE, init_log);
1931
Christopher Faulet0132d062017-07-26 15:33:35 +02001932/* Initialize log buffers used for syslog messages */
1933int init_log_buffers()
1934{
1935 logheader = my_realloc2(logheader, global.max_syslog_len + 1);
Willy Tarreau55e2f5a2019-05-05 10:11:39 +02001936 logheader_end = NULL;
Christopher Faulet0132d062017-07-26 15:33:35 +02001937 logheader_rfc5424 = my_realloc2(logheader_rfc5424, global.max_syslog_len + 1);
Willy Tarreau55e2f5a2019-05-05 10:11:39 +02001938 logheader_rfc5424_end = NULL;
Christopher Faulet0132d062017-07-26 15:33:35 +02001939 logline = my_realloc2(logline, global.max_syslog_len + 1);
1940 logline_rfc5424 = my_realloc2(logline_rfc5424, global.max_syslog_len + 1);
1941 if (!logheader || !logline_rfc5424 || !logline || !logline_rfc5424)
1942 return 0;
1943 return 1;
1944}
1945
1946/* Deinitialize log buffers used for syslog messages */
1947void deinit_log_buffers()
1948{
1949 free(logheader);
1950 free(logheader_rfc5424);
1951 free(logline);
1952 free(logline_rfc5424);
Willy Tarreau869efd52019-11-15 15:16:57 +01001953 ring_free(_HA_ATOMIC_XCHG(&startup_logs, NULL));
Christopher Faulet0132d062017-07-26 15:33:35 +02001954 logheader = NULL;
1955 logheader_rfc5424 = NULL;
1956 logline = NULL;
1957 logline_rfc5424 = NULL;
1958}
1959
Willy Tarreaudf974472012-12-28 02:44:01 +01001960/* Builds a log line in <dst> based on <list_format>, and stops before reaching
1961 * <maxsize> characters. Returns the size of the output string in characters,
1962 * not counting the trailing zero which is always added if the resulting size
Willy Tarreau09bb27c2018-09-05 16:55:15 +02001963 * is not zero. It requires a valid session and optionally a stream. If the
1964 * stream is NULL, default values will be assumed for the stream part.
Willy Tarreaudf974472012-12-28 02:44:01 +01001965 */
Willy Tarreau43c538e2018-09-05 14:58:15 +02001966int 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 +02001967{
Willy Tarreaue36cbcb2015-04-03 15:40:56 +02001968 struct proxy *fe = sess->fe;
Willy Tarreau09bb27c2018-09-05 16:55:15 +02001969 struct proxy *be;
1970 struct http_txn *txn;
1971 const struct strm_logs *logs;
Willy Tarreau8fa99842019-07-17 11:47:11 +02001972 struct connection *be_conn;
Willy Tarreau09bb27c2018-09-05 16:55:15 +02001973 unsigned int s_flags;
1974 unsigned int uniq_id;
Willy Tarreau83061a82018-07-13 11:56:34 +02001975 struct buffer chunk;
William Lallemandbddd4fd2012-02-27 11:23:10 +01001976 char *uri;
Andrew Hayworth0ebc55f2015-04-27 21:37:03 +00001977 char *spc;
Andrew Hayworthe63ac872015-07-31 16:14:16 +00001978 char *qmark;
Andrew Hayworth0ebc55f2015-04-27 21:37:03 +00001979 char *end;
Willy Tarreaufe944602007-10-25 10:34:16 +02001980 struct tm tm;
William Lallemandbddd4fd2012-02-27 11:23:10 +01001981 int t_request;
1982 int hdr;
1983 int last_isspace = 1;
Andrew Hayworth0ebc55f2015-04-27 21:37:03 +00001984 int nspaces = 0;
Willy Tarreaub1a2faf2012-03-19 16:51:53 +01001985 char *tmplog;
William Lallemand1d705562012-03-12 12:46:41 +01001986 char *ret;
1987 int iret;
William Lallemandbddd4fd2012-02-27 11:23:10 +01001988 struct logformat_node *tmp;
Thierry FOURNIER / OZON.IO4cac3592016-07-28 17:19:45 +02001989 struct timeval tv;
Willy Tarreau09bb27c2018-09-05 16:55:15 +02001990 struct strm_logs tmp_strm_log;
Willy Tarreaubaaee002006-06-26 02:48:02 +02001991
William Lallemandbddd4fd2012-02-27 11:23:10 +01001992 /* FIXME: let's limit ourselves to frontend logging for now. */
Willy Tarreaubaaee002006-06-26 02:48:02 +02001993
Willy Tarreau09bb27c2018-09-05 16:55:15 +02001994 if (likely(s)) {
1995 be = s->be;
1996 txn = s->txn;
1997 be_conn = cs_conn(objt_cs(s->si[1].end));
1998 s_flags = s->flags;
1999 uniq_id = s->uniq_id;
2000 logs = &s->logs;
2001 } else {
2002 /* we have no stream so we first need to initialize a few
2003 * things that are needed later. We do increment the request
2004 * ID so that it's uniquely assigned to this request just as
2005 * if the request had reached the point of being processed.
2006 * A request error is reported as it's the only element we have
2007 * here and which justifies emitting such a log.
2008 */
2009 be = fe;
2010 txn = NULL;
2011 be_conn = NULL;
2012 s_flags = SF_ERR_PRXCOND | SF_FINST_R;
Olivier Houchardd2ee3e72019-03-08 18:53:21 +01002013 uniq_id = _HA_ATOMIC_XADD(&global.req_count, 1);
Willy Tarreau09bb27c2018-09-05 16:55:15 +02002014
2015 /* prepare a valid log structure */
2016 tmp_strm_log.tv_accept = sess->tv_accept;
2017 tmp_strm_log.accept_date = sess->accept_date;
2018 tmp_strm_log.t_handshake = sess->t_handshake;
2019 tmp_strm_log.t_idle = tv_ms_elapsed(&sess->tv_accept, &now) - sess->t_handshake;
2020 tv_zero(&tmp_strm_log.tv_request);
2021 tmp_strm_log.t_queue = -1;
2022 tmp_strm_log.t_connect = -1;
2023 tmp_strm_log.t_data = -1;
2024 tmp_strm_log.t_close = tv_ms_elapsed(&sess->tv_accept, &now);
2025 tmp_strm_log.bytes_in = 0;
2026 tmp_strm_log.bytes_out = 0;
2027 tmp_strm_log.prx_queue_pos = 0;
2028 tmp_strm_log.srv_queue_pos = 0;
2029
2030 logs = &tmp_strm_log;
2031 }
2032
William Lallemandbddd4fd2012-02-27 11:23:10 +01002033 t_request = -1;
Willy Tarreau372ac5a2018-09-05 15:16:23 +02002034 if (tv_isge(&logs->tv_request, &logs->tv_accept))
2035 t_request = tv_ms_elapsed(&logs->tv_accept, &logs->tv_request);
William Lallemandbddd4fd2012-02-27 11:23:10 +01002036
William Lallemand1d705562012-03-12 12:46:41 +01002037 tmplog = dst;
Willy Tarreauc9bd0cc2009-05-10 11:57:02 +02002038
William Lallemandbddd4fd2012-02-27 11:23:10 +01002039 /* fill logbuffer */
William Lallemand1d705562012-03-12 12:46:41 +01002040 if (LIST_ISEMPTY(list_format))
2041 return 0;
William Lallemandbddd4fd2012-02-27 11:23:10 +01002042
William Lallemand1d705562012-03-12 12:46:41 +01002043 list_for_each_entry(tmp, list_format, list) {
Willy Tarreaub363a1f2013-10-01 10:45:07 +02002044 struct connection *conn;
Willy Tarreau4f653562012-10-12 19:48:16 +02002045 const char *src = NULL;
Willy Tarreauc8368452012-12-21 00:09:23 +01002046 struct sample *key;
Willy Tarreau83061a82018-07-13 11:56:34 +02002047 const struct buffer empty = { };
William Lallemandbddd4fd2012-02-27 11:23:10 +01002048
Willy Tarreauc8368452012-12-21 00:09:23 +01002049 switch (tmp->type) {
William Lallemand1d705562012-03-12 12:46:41 +01002050 case LOG_FMT_SEPARATOR:
William Lallemandbddd4fd2012-02-27 11:23:10 +01002051 if (!last_isspace) {
2052 LOGCHAR(' ');
2053 last_isspace = 1;
William Lallemandbddd4fd2012-02-27 11:23:10 +01002054 }
2055 break;
2056
William Lallemand1d705562012-03-12 12:46:41 +01002057 case LOG_FMT_TEXT: // text
William Lallemandbddd4fd2012-02-27 11:23:10 +01002058 src = tmp->arg;
William Lallemand5f232402012-04-05 18:02:55 +02002059 iret = strlcpy2(tmplog, src, dst + maxsize - tmplog);
William Lallemand1d705562012-03-12 12:46:41 +01002060 if (iret == 0)
William Lallemandbddd4fd2012-02-27 11:23:10 +01002061 goto out;
William Lallemand1d705562012-03-12 12:46:41 +01002062 tmplog += iret;
William Lallemandbddd4fd2012-02-27 11:23:10 +01002063 last_isspace = 0;
2064 break;
2065
Willy Tarreauc8368452012-12-21 00:09:23 +01002066 case LOG_FMT_EXPR: // sample expression, may be request or response
2067 key = NULL;
Olivier Houchardf90db442018-12-15 14:00:06 +01002068 if (tmp->options & LOG_OPT_REQ_CAP && s)
Adis Nezirovic79beb242015-07-06 15:41:02 +02002069 key = sample_fetch_as_type(be, sess, s, SMP_OPT_DIR_REQ|SMP_OPT_FINAL, tmp->expr, SMP_T_STR);
Olivier Houchardf90db442018-12-15 14:00:06 +01002070 if (!key && (tmp->options & LOG_OPT_RES_CAP) && s)
Adis Nezirovic79beb242015-07-06 15:41:02 +02002071 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 +01002072 if (tmp->options & LOG_OPT_HTTP)
Dragan Dosen835b9212016-02-12 13:23:03 +01002073 ret = lf_encode_chunk(tmplog, dst + maxsize,
2074 '%', http_encode_map, key ? &key->data.u.str : &empty, tmp);
Thierry FOURNIERd048d8b2014-03-13 16:46:18 +01002075 else
Willy Tarreau843b7cb2018-07-13 10:54:26 +02002076 ret = lf_text_len(tmplog,
2077 key ? key->data.u.str.area : NULL,
2078 key ? key->data.u.str.data : 0,
2079 dst + maxsize - tmplog,
2080 tmp);
Willy Tarreauc8368452012-12-21 00:09:23 +01002081 if (ret == 0)
2082 goto out;
2083 tmplog = ret;
2084 last_isspace = 0;
2085 break;
2086
Willy Tarreau2beef582012-12-20 17:22:52 +01002087 case LOG_FMT_CLIENTIP: // %ci
Willy Tarreau9ad7bd42015-04-03 19:19:59 +02002088 conn = objt_conn(sess->origin);
Willy Tarreau8fa99842019-07-17 11:47:11 +02002089 if (conn && conn_get_src(conn))
Willy Tarreau6c6365f2019-07-17 16:48:18 +02002090 ret = lf_ip(tmplog, (struct sockaddr *)conn->src, dst + maxsize - tmplog, tmp);
Willy Tarreaub363a1f2013-10-01 10:45:07 +02002091 else
2092 ret = lf_text_len(tmplog, NULL, 0, dst + maxsize - tmplog, tmp);
William Lallemand1d705562012-03-12 12:46:41 +01002093 if (ret == NULL)
William Lallemandbddd4fd2012-02-27 11:23:10 +01002094 goto out;
William Lallemand1d705562012-03-12 12:46:41 +01002095 tmplog = ret;
William Lallemandbddd4fd2012-02-27 11:23:10 +01002096 last_isspace = 0;
2097 break;
2098
Willy Tarreau2beef582012-12-20 17:22:52 +01002099 case LOG_FMT_CLIENTPORT: // %cp
Willy Tarreau9ad7bd42015-04-03 19:19:59 +02002100 conn = objt_conn(sess->origin);
Willy Tarreau8fa99842019-07-17 11:47:11 +02002101 if (conn && conn_get_src(conn)) {
Willy Tarreau6c6365f2019-07-17 16:48:18 +02002102 if (conn->src->ss_family == AF_UNIX) {
Willy Tarreaufb0afa72015-04-03 14:46:27 +02002103 ret = ltoa_o(sess->listener->luid, tmplog, dst + maxsize - tmplog);
Willy Tarreaub363a1f2013-10-01 10:45:07 +02002104 } else {
Willy Tarreau6c6365f2019-07-17 16:48:18 +02002105 ret = lf_port(tmplog, (struct sockaddr *)conn->src,
Willy Tarreaub363a1f2013-10-01 10:45:07 +02002106 dst + maxsize - tmplog, tmp);
2107 }
William Lallemand5f232402012-04-05 18:02:55 +02002108 }
Willy Tarreaub363a1f2013-10-01 10:45:07 +02002109 else
2110 ret = lf_text_len(tmplog, NULL, 0, dst + maxsize - tmplog, tmp);
2111
William Lallemand5f232402012-04-05 18:02:55 +02002112 if (ret == NULL)
2113 goto out;
2114 tmplog = ret;
2115 last_isspace = 0;
2116 break;
2117
Willy Tarreau2beef582012-12-20 17:22:52 +01002118 case LOG_FMT_FRONTENDIP: // %fi
Willy Tarreau9ad7bd42015-04-03 19:19:59 +02002119 conn = objt_conn(sess->origin);
Willy Tarreau8fa99842019-07-17 11:47:11 +02002120 if (conn && conn_get_dst(conn)) {
Willy Tarreau6c6365f2019-07-17 16:48:18 +02002121 ret = lf_ip(tmplog, (struct sockaddr *)conn->dst, dst + maxsize - tmplog, tmp);
Willy Tarreaub363a1f2013-10-01 10:45:07 +02002122 }
2123 else
2124 ret = lf_text_len(tmplog, NULL, 0, dst + maxsize - tmplog, tmp);
2125
William Lallemand1d705562012-03-12 12:46:41 +01002126 if (ret == NULL)
William Lallemandbddd4fd2012-02-27 11:23:10 +01002127 goto out;
William Lallemand1d705562012-03-12 12:46:41 +01002128 tmplog = ret;
William Lallemandbddd4fd2012-02-27 11:23:10 +01002129 last_isspace = 0;
2130 break;
2131
Willy Tarreau2beef582012-12-20 17:22:52 +01002132 case LOG_FMT_FRONTENDPORT: // %fp
Willy Tarreau9ad7bd42015-04-03 19:19:59 +02002133 conn = objt_conn(sess->origin);
Willy Tarreau8fa99842019-07-17 11:47:11 +02002134 if (conn && conn_get_dst(conn)) {
Willy Tarreau6c6365f2019-07-17 16:48:18 +02002135 if (conn->dst->ss_family == AF_UNIX)
Willy Tarreaufb0afa72015-04-03 14:46:27 +02002136 ret = ltoa_o(sess->listener->luid, tmplog, dst + maxsize - tmplog);
Willy Tarreaub363a1f2013-10-01 10:45:07 +02002137 else
Willy Tarreau6c6365f2019-07-17 16:48:18 +02002138 ret = lf_port(tmplog, (struct sockaddr *)conn->dst, dst + maxsize - tmplog, tmp);
William Lallemand5f232402012-04-05 18:02:55 +02002139 }
Willy Tarreaub363a1f2013-10-01 10:45:07 +02002140 else
2141 ret = lf_text_len(tmplog, NULL, 0, dst + maxsize - tmplog, tmp);
2142
William Lallemand5f232402012-04-05 18:02:55 +02002143 if (ret == NULL)
2144 goto out;
2145 tmplog = ret;
2146 last_isspace = 0;
2147 break;
2148
Willy Tarreau2beef582012-12-20 17:22:52 +01002149 case LOG_FMT_BACKENDIP: // %bi
Willy Tarreau8fa99842019-07-17 11:47:11 +02002150 if (be_conn && conn_get_src(be_conn))
Willy Tarreau6c6365f2019-07-17 16:48:18 +02002151 ret = lf_ip(tmplog, (const struct sockaddr *)be_conn->src, dst + maxsize - tmplog, tmp);
Willy Tarreaub363a1f2013-10-01 10:45:07 +02002152 else
2153 ret = lf_text_len(tmplog, NULL, 0, dst + maxsize - tmplog, tmp);
2154
William Lallemand1d705562012-03-12 12:46:41 +01002155 if (ret == NULL)
William Lallemandb7ff6a32012-03-02 14:35:21 +01002156 goto out;
William Lallemand1d705562012-03-12 12:46:41 +01002157 tmplog = ret;
William Lallemandb7ff6a32012-03-02 14:35:21 +01002158 last_isspace = 0;
2159 break;
2160
Willy Tarreau2beef582012-12-20 17:22:52 +01002161 case LOG_FMT_BACKENDPORT: // %bp
Willy Tarreau8fa99842019-07-17 11:47:11 +02002162 if (be_conn && conn_get_src(be_conn))
Willy Tarreau6c6365f2019-07-17 16:48:18 +02002163 ret = lf_port(tmplog, (struct sockaddr *)be_conn->src, dst + maxsize - tmplog, tmp);
Willy Tarreaub363a1f2013-10-01 10:45:07 +02002164 else
2165 ret = lf_text_len(tmplog, NULL, 0, dst + maxsize - tmplog, tmp);
2166
William Lallemand5f232402012-04-05 18:02:55 +02002167 if (ret == NULL)
2168 goto out;
2169 tmplog = ret;
2170 last_isspace = 0;
2171 break;
2172
Willy Tarreau2beef582012-12-20 17:22:52 +01002173 case LOG_FMT_SERVERIP: // %si
Willy Tarreau8fa99842019-07-17 11:47:11 +02002174 if (be_conn && conn_get_dst(be_conn))
Willy Tarreau6c6365f2019-07-17 16:48:18 +02002175 ret = lf_ip(tmplog, (struct sockaddr *)be_conn->dst, dst + maxsize - tmplog, tmp);
Willy Tarreaub363a1f2013-10-01 10:45:07 +02002176 else
2177 ret = lf_text_len(tmplog, NULL, 0, dst + maxsize - tmplog, tmp);
2178
William Lallemand5f232402012-04-05 18:02:55 +02002179 if (ret == NULL)
2180 goto out;
2181 tmplog = ret;
2182 last_isspace = 0;
2183 break;
2184
Willy Tarreau2beef582012-12-20 17:22:52 +01002185 case LOG_FMT_SERVERPORT: // %sp
Willy Tarreau8fa99842019-07-17 11:47:11 +02002186 if (be_conn && conn_get_dst(be_conn))
Willy Tarreau6c6365f2019-07-17 16:48:18 +02002187 ret = lf_port(tmplog, (struct sockaddr *)be_conn->dst, dst + maxsize - tmplog, tmp);
Willy Tarreaub363a1f2013-10-01 10:45:07 +02002188 else
2189 ret = lf_text_len(tmplog, NULL, 0, dst + maxsize - tmplog, tmp);
2190
William Lallemand1d705562012-03-12 12:46:41 +01002191 if (ret == NULL)
William Lallemandb7ff6a32012-03-02 14:35:21 +01002192 goto out;
William Lallemand1d705562012-03-12 12:46:41 +01002193 tmplog = ret;
William Lallemandb7ff6a32012-03-02 14:35:21 +01002194 last_isspace = 0;
2195 break;
2196
Thierry FOURNIER / OZON.IO4cac3592016-07-28 17:19:45 +02002197 case LOG_FMT_DATE: // %t = accept date
Willy Tarreau372ac5a2018-09-05 15:16:23 +02002198 get_localtime(logs->accept_date.tv_sec, &tm);
2199 ret = date2str_log(tmplog, &tm, &logs->accept_date, dst + maxsize - tmplog);
William Lallemand1d705562012-03-12 12:46:41 +01002200 if (ret == NULL)
William Lallemandbddd4fd2012-02-27 11:23:10 +01002201 goto out;
William Lallemand1d705562012-03-12 12:46:41 +01002202 tmplog = ret;
William Lallemandbddd4fd2012-02-27 11:23:10 +01002203 last_isspace = 0;
2204 break;
2205
Thierry FOURNIER / OZON.IO4cac3592016-07-28 17:19:45 +02002206 case LOG_FMT_tr: // %tr = start of request date
2207 /* Note that the timers are valid if we get here */
Willy Tarreau372ac5a2018-09-05 15:16:23 +02002208 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 +02002209 get_localtime(tv.tv_sec, &tm);
2210 ret = date2str_log(tmplog, &tm, &tv, dst + maxsize - tmplog);
2211 if (ret == NULL)
2212 goto out;
2213 tmplog = ret;
2214 last_isspace = 0;
2215 break;
2216
2217 case LOG_FMT_DATEGMT: // %T = accept date, GMT
Willy Tarreau372ac5a2018-09-05 15:16:23 +02002218 get_gmtime(logs->accept_date.tv_sec, &tm);
William Lallemand5f232402012-04-05 18:02:55 +02002219 ret = gmt2str_log(tmplog, &tm, dst + maxsize - tmplog);
William Lallemand1d705562012-03-12 12:46:41 +01002220 if (ret == NULL)
William Lallemandbddd4fd2012-02-27 11:23:10 +01002221 goto out;
William Lallemand1d705562012-03-12 12:46:41 +01002222 tmplog = ret;
William Lallemandbddd4fd2012-02-27 11:23:10 +01002223 last_isspace = 0;
2224 break;
2225
Thierry FOURNIER / OZON.IO4cac3592016-07-28 17:19:45 +02002226 case LOG_FMT_trg: // %trg = start of request date, GMT
Willy Tarreau372ac5a2018-09-05 15:16:23 +02002227 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 +02002228 get_gmtime(tv.tv_sec, &tm);
2229 ret = gmt2str_log(tmplog, &tm, dst + maxsize - tmplog);
2230 if (ret == NULL)
2231 goto out;
2232 tmplog = ret;
2233 last_isspace = 0;
2234 break;
2235
2236 case LOG_FMT_DATELOCAL: // %Tl = accept date, local
Willy Tarreau372ac5a2018-09-05 15:16:23 +02002237 get_localtime(logs->accept_date.tv_sec, &tm);
2238 ret = localdate2str_log(tmplog, logs->accept_date.tv_sec, &tm, dst + maxsize - tmplog);
Yuxans Yao4e25b012012-10-19 10:36:09 +08002239 if (ret == NULL)
2240 goto out;
2241 tmplog = ret;
2242 last_isspace = 0;
2243 break;
2244
Thierry FOURNIER / OZON.IO4cac3592016-07-28 17:19:45 +02002245 case LOG_FMT_trl: // %trl = start of request date, local
Willy Tarreau372ac5a2018-09-05 15:16:23 +02002246 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 +02002247 get_localtime(tv.tv_sec, &tm);
2248 ret = localdate2str_log(tmplog, tv.tv_sec, &tm, dst + maxsize - tmplog);
2249 if (ret == NULL)
2250 goto out;
2251 tmplog = ret;
2252 last_isspace = 0;
2253 break;
2254
William Lallemand5f232402012-04-05 18:02:55 +02002255 case LOG_FMT_TS: // %Ts
William Lallemand5f232402012-04-05 18:02:55 +02002256 if (tmp->options & LOG_OPT_HEXA) {
Willy Tarreau372ac5a2018-09-05 15:16:23 +02002257 iret = snprintf(tmplog, dst + maxsize - tmplog, "%04X", (unsigned int)logs->accept_date.tv_sec);
William Lallemand5f232402012-04-05 18:02:55 +02002258 if (iret < 0 || iret > dst + maxsize - tmplog)
2259 goto out;
2260 last_isspace = 0;
2261 tmplog += iret;
2262 } else {
Willy Tarreau372ac5a2018-09-05 15:16:23 +02002263 ret = ltoa_o(logs->accept_date.tv_sec, tmplog, dst + maxsize - tmplog);
William Lallemand5f232402012-04-05 18:02:55 +02002264 if (ret == NULL)
2265 goto out;
2266 tmplog = ret;
2267 last_isspace = 0;
2268 }
2269 break;
2270
William Lallemand1d705562012-03-12 12:46:41 +01002271 case LOG_FMT_MS: // %ms
William Lallemand5f232402012-04-05 18:02:55 +02002272 if (tmp->options & LOG_OPT_HEXA) {
Willy Tarreau372ac5a2018-09-05 15:16:23 +02002273 iret = snprintf(tmplog, dst + maxsize - tmplog, "%02X",(unsigned int)logs->accept_date.tv_usec/1000);
William Lallemand5f232402012-04-05 18:02:55 +02002274 if (iret < 0 || iret > dst + maxsize - tmplog)
2275 goto out;
2276 last_isspace = 0;
2277 tmplog += iret;
2278 } else {
2279 if ((dst + maxsize - tmplog) < 4)
William Lallemandbddd4fd2012-02-27 11:23:10 +01002280 goto out;
Willy Tarreau372ac5a2018-09-05 15:16:23 +02002281 ret = utoa_pad((unsigned int)logs->accept_date.tv_usec/1000,
Willy Tarreau9e60cd82013-01-24 01:18:16 +01002282 tmplog, 4);
2283 if (ret == NULL)
William Lallemand51b5dca2012-03-26 17:52:55 +02002284 goto out;
Willy Tarreau9e60cd82013-01-24 01:18:16 +01002285 tmplog = ret;
William Lallemandbddd4fd2012-02-27 11:23:10 +01002286 last_isspace = 0;
William Lallemand5f232402012-04-05 18:02:55 +02002287 }
2288 break;
William Lallemandbddd4fd2012-02-27 11:23:10 +01002289
William Lallemand1d705562012-03-12 12:46:41 +01002290 case LOG_FMT_FRONTEND: // %f
William Lallemandbddd4fd2012-02-27 11:23:10 +01002291 src = fe->id;
William Lallemand5f232402012-04-05 18:02:55 +02002292 ret = lf_text(tmplog, src, dst + maxsize - tmplog, tmp);
William Lallemand1d705562012-03-12 12:46:41 +01002293 if (ret == NULL)
William Lallemandbddd4fd2012-02-27 11:23:10 +01002294 goto out;
William Lallemand1d705562012-03-12 12:46:41 +01002295 tmplog = ret;
William Lallemand51b5dca2012-03-26 17:52:55 +02002296 last_isspace = 0;
William Lallemandbddd4fd2012-02-27 11:23:10 +01002297 break;
2298
Willy Tarreau773d65f2012-10-12 14:56:11 +02002299 case LOG_FMT_FRONTEND_XPRT: // %ft
2300 src = fe->id;
2301 if (tmp->options & LOG_OPT_QUOTE)
2302 LOGCHAR('"');
2303 iret = strlcpy2(tmplog, src, dst + maxsize - tmplog);
2304 if (iret == 0)
2305 goto out;
2306 tmplog += iret;
Willy Tarreaua261e9b2016-12-22 20:44:00 +01002307 if (sess->listener->bind_conf->xprt == xprt_get(XPRT_SSL))
Willy Tarreau773d65f2012-10-12 14:56:11 +02002308 LOGCHAR('~');
Willy Tarreau773d65f2012-10-12 14:56:11 +02002309 if (tmp->options & LOG_OPT_QUOTE)
2310 LOGCHAR('"');
2311 last_isspace = 0;
2312 break;
Willy Tarreauffc3fcd2012-10-12 20:17:54 +02002313#ifdef USE_OPENSSL
2314 case LOG_FMT_SSL_CIPHER: // %sslc
2315 src = NULL;
Willy Tarreau9ad7bd42015-04-03 19:19:59 +02002316 conn = objt_conn(sess->origin);
Willy Tarreaub363a1f2013-10-01 10:45:07 +02002317 if (conn) {
Emmanuel Hocdet01da5712017-10-13 16:59:49 +02002318 src = ssl_sock_get_cipher_name(conn);
Willy Tarreaub363a1f2013-10-01 10:45:07 +02002319 }
Willy Tarreauffc3fcd2012-10-12 20:17:54 +02002320 ret = lf_text(tmplog, src, dst + maxsize - tmplog, tmp);
2321 if (ret == NULL)
2322 goto out;
2323 tmplog = ret;
2324 last_isspace = 0;
2325 break;
Willy Tarreau773d65f2012-10-12 14:56:11 +02002326
Willy Tarreauffc3fcd2012-10-12 20:17:54 +02002327 case LOG_FMT_SSL_VERSION: // %sslv
2328 src = NULL;
Willy Tarreau9ad7bd42015-04-03 19:19:59 +02002329 conn = objt_conn(sess->origin);
Willy Tarreaub363a1f2013-10-01 10:45:07 +02002330 if (conn) {
Emmanuel Hocdet01da5712017-10-13 16:59:49 +02002331 src = ssl_sock_get_proto_version(conn);
Willy Tarreaub363a1f2013-10-01 10:45:07 +02002332 }
Willy Tarreauffc3fcd2012-10-12 20:17:54 +02002333 ret = lf_text(tmplog, src, dst + maxsize - tmplog, tmp);
2334 if (ret == NULL)
2335 goto out;
2336 tmplog = ret;
2337 last_isspace = 0;
2338 break;
2339#endif
William Lallemand1d705562012-03-12 12:46:41 +01002340 case LOG_FMT_BACKEND: // %b
William Lallemandbddd4fd2012-02-27 11:23:10 +01002341 src = be->id;
William Lallemand5f232402012-04-05 18:02:55 +02002342 ret = lf_text(tmplog, src, dst + maxsize - tmplog, tmp);
William Lallemand1d705562012-03-12 12:46:41 +01002343 if (ret == NULL)
William Lallemandbddd4fd2012-02-27 11:23:10 +01002344 goto out;
William Lallemand1d705562012-03-12 12:46:41 +01002345 tmplog = ret;
William Lallemand51b5dca2012-03-26 17:52:55 +02002346 last_isspace = 0;
William Lallemandbddd4fd2012-02-27 11:23:10 +01002347 break;
2348
William Lallemand1d705562012-03-12 12:46:41 +01002349 case LOG_FMT_SERVER: // %s
Willy Tarreaue1809df2018-09-05 15:30:16 +02002350 switch (obj_type(s ? s->target : NULL)) {
Willy Tarreaud79a3b22012-12-28 09:40:16 +01002351 case OBJ_TYPE_SERVER:
Willy Tarreau1aaf3242018-09-20 11:13:58 +02002352 src = __objt_server(s->target)->id;
Willy Tarreaud79a3b22012-12-28 09:40:16 +01002353 break;
2354 case OBJ_TYPE_APPLET:
Willy Tarreau1aaf3242018-09-20 11:13:58 +02002355 src = __objt_applet(s->target)->name;
Willy Tarreaud79a3b22012-12-28 09:40:16 +01002356 break;
2357 default:
2358 src = "<NOSRV>";
2359 break;
2360 }
William Lallemand5f232402012-04-05 18:02:55 +02002361 ret = lf_text(tmplog, src, dst + maxsize - tmplog, tmp);
William Lallemand1d705562012-03-12 12:46:41 +01002362 if (ret == NULL)
William Lallemandbddd4fd2012-02-27 11:23:10 +01002363 goto out;
William Lallemand1d705562012-03-12 12:46:41 +01002364 tmplog = ret;
William Lallemandbddd4fd2012-02-27 11:23:10 +01002365 last_isspace = 0;
2366 break;
2367
Thierry FOURNIER / OZON.IO4cac3592016-07-28 17:19:45 +02002368 case LOG_FMT_Th: // %Th = handshake time
Willy Tarreau372ac5a2018-09-05 15:16:23 +02002369 ret = ltoa_o(logs->t_handshake, tmplog, dst + maxsize - tmplog);
Thierry FOURNIER / OZON.IO4cac3592016-07-28 17:19:45 +02002370 if (ret == NULL)
2371 goto out;
2372 tmplog = ret;
2373 last_isspace = 0;
2374 break;
2375
2376 case LOG_FMT_Ti: // %Ti = HTTP idle time
Willy Tarreau372ac5a2018-09-05 15:16:23 +02002377 ret = ltoa_o(logs->t_idle, tmplog, dst + maxsize - tmplog);
Thierry FOURNIER / OZON.IO4cac3592016-07-28 17:19:45 +02002378 if (ret == NULL)
2379 goto out;
2380 tmplog = ret;
2381 last_isspace = 0;
2382 break;
2383
2384 case LOG_FMT_TR: // %TR = HTTP request time
Willy Tarreau372ac5a2018-09-05 15:16:23 +02002385 ret = ltoa_o((t_request >= 0) ? t_request - logs->t_idle - logs->t_handshake : -1,
Thierry FOURNIER / OZON.IO4cac3592016-07-28 17:19:45 +02002386 tmplog, dst + maxsize - tmplog);
2387 if (ret == NULL)
2388 goto out;
2389 tmplog = ret;
2390 last_isspace = 0;
2391 break;
2392
2393 case LOG_FMT_TQ: // %Tq = Th + Ti + TR
William Lallemand5f232402012-04-05 18:02:55 +02002394 ret = ltoa_o(t_request, tmplog, dst + maxsize - tmplog);
William Lallemand1d705562012-03-12 12:46:41 +01002395 if (ret == NULL)
William Lallemandbddd4fd2012-02-27 11:23:10 +01002396 goto out;
William Lallemand1d705562012-03-12 12:46:41 +01002397 tmplog = ret;
William Lallemandbddd4fd2012-02-27 11:23:10 +01002398 last_isspace = 0;
2399 break;
2400
William Lallemand1d705562012-03-12 12:46:41 +01002401 case LOG_FMT_TW: // %Tw
Willy Tarreau372ac5a2018-09-05 15:16:23 +02002402 ret = ltoa_o((logs->t_queue >= 0) ? logs->t_queue - t_request : -1,
William Lallemand5f232402012-04-05 18:02:55 +02002403 tmplog, dst + maxsize - tmplog);
William Lallemand1d705562012-03-12 12:46:41 +01002404 if (ret == NULL)
William Lallemandbddd4fd2012-02-27 11:23:10 +01002405 goto out;
William Lallemand1d705562012-03-12 12:46:41 +01002406 tmplog = ret;
William Lallemandbddd4fd2012-02-27 11:23:10 +01002407 last_isspace = 0;
2408 break;
2409
William Lallemand1d705562012-03-12 12:46:41 +01002410 case LOG_FMT_TC: // %Tc
Willy Tarreau372ac5a2018-09-05 15:16:23 +02002411 ret = ltoa_o((logs->t_connect >= 0) ? logs->t_connect - logs->t_queue : -1,
William Lallemand5f232402012-04-05 18:02:55 +02002412 tmplog, dst + maxsize - tmplog);
William Lallemand1d705562012-03-12 12:46:41 +01002413 if (ret == NULL)
William Lallemandbddd4fd2012-02-27 11:23:10 +01002414 goto out;
William Lallemand1d705562012-03-12 12:46:41 +01002415 tmplog = ret;
William Lallemandbddd4fd2012-02-27 11:23:10 +01002416 last_isspace = 0;
2417 break;
2418
Thierry FOURNIER / OZON.IO4cac3592016-07-28 17:19:45 +02002419 case LOG_FMT_Tr: // %Tr
Willy Tarreau372ac5a2018-09-05 15:16:23 +02002420 ret = ltoa_o((logs->t_data >= 0) ? logs->t_data - logs->t_connect : -1,
William Lallemand5f232402012-04-05 18:02:55 +02002421 tmplog, dst + maxsize - tmplog);
William Lallemand1d705562012-03-12 12:46:41 +01002422 if (ret == NULL)
William Lallemandbddd4fd2012-02-27 11:23:10 +01002423 goto out;
William Lallemand1d705562012-03-12 12:46:41 +01002424 tmplog = ret;
William Lallemandbddd4fd2012-02-27 11:23:10 +01002425 last_isspace = 0;
2426 break;
2427
Willy Tarreau27b639d2016-05-17 17:55:27 +02002428 case LOG_FMT_TD: // %Td
Willy Tarreaua21c0e62018-09-05 15:07:15 +02002429 if (be->mode == PR_MODE_HTTP)
Willy Tarreau372ac5a2018-09-05 15:16:23 +02002430 ret = ltoa_o((logs->t_data >= 0) ? logs->t_close - logs->t_data : -1,
Willy Tarreau27b639d2016-05-17 17:55:27 +02002431 tmplog, dst + maxsize - tmplog);
2432 else
Willy Tarreau372ac5a2018-09-05 15:16:23 +02002433 ret = ltoa_o((logs->t_connect >= 0) ? logs->t_close - logs->t_connect : -1,
Willy Tarreau27b639d2016-05-17 17:55:27 +02002434 tmplog, dst + maxsize - tmplog);
2435 if (ret == NULL)
2436 goto out;
2437 tmplog = ret;
2438 last_isspace = 0;
2439 break;
2440
Thierry FOURNIER / OZON.IO4cac3592016-07-28 17:19:45 +02002441 case LOG_FMT_Ta: // %Ta = active time = Tt - Th - Ti
2442 if (!(fe->to_log & LW_BYTES))
2443 LOGCHAR('+');
Willy Tarreau372ac5a2018-09-05 15:16:23 +02002444 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 +02002445 tmplog, dst + maxsize - tmplog);
2446 if (ret == NULL)
2447 goto out;
2448 tmplog = ret;
2449 last_isspace = 0;
2450 break;
2451
2452 case LOG_FMT_TT: // %Tt = total time
Willy Tarreaud79a3b22012-12-28 09:40:16 +01002453 if (!(fe->to_log & LW_BYTES))
William Lallemand1d705562012-03-12 12:46:41 +01002454 LOGCHAR('+');
Willy Tarreau372ac5a2018-09-05 15:16:23 +02002455 ret = ltoa_o(logs->t_close, tmplog, dst + maxsize - tmplog);
William Lallemand1d705562012-03-12 12:46:41 +01002456 if (ret == NULL)
William Lallemandbddd4fd2012-02-27 11:23:10 +01002457 goto out;
William Lallemand1d705562012-03-12 12:46:41 +01002458 tmplog = ret;
William Lallemandbddd4fd2012-02-27 11:23:10 +01002459 last_isspace = 0;
2460 break;
2461
Willy Tarreau2beef582012-12-20 17:22:52 +01002462 case LOG_FMT_STATUS: // %ST
Willy Tarreau57bc8912016-04-25 17:09:40 +02002463 ret = ltoa_o(txn ? txn->status : 0, tmplog, dst + maxsize - tmplog);
William Lallemand1d705562012-03-12 12:46:41 +01002464 if (ret == NULL)
William Lallemandbddd4fd2012-02-27 11:23:10 +01002465 goto out;
William Lallemand1d705562012-03-12 12:46:41 +01002466 tmplog = ret;
William Lallemandbddd4fd2012-02-27 11:23:10 +01002467 last_isspace = 0;
2468 break;
2469
William Lallemand1d705562012-03-12 12:46:41 +01002470 case LOG_FMT_BYTES: // %B
Willy Tarreaud79a3b22012-12-28 09:40:16 +01002471 if (!(fe->to_log & LW_BYTES))
William Lallemand1d705562012-03-12 12:46:41 +01002472 LOGCHAR('+');
Willy Tarreau372ac5a2018-09-05 15:16:23 +02002473 ret = lltoa(logs->bytes_out, tmplog, dst + maxsize - tmplog);
William Lallemand1d705562012-03-12 12:46:41 +01002474 if (ret == NULL)
William Lallemandbddd4fd2012-02-27 11:23:10 +01002475 goto out;
William Lallemand1d705562012-03-12 12:46:41 +01002476 tmplog = ret;
William Lallemandbddd4fd2012-02-27 11:23:10 +01002477 last_isspace = 0;
2478 break;
2479
Willy Tarreauc5259fd2012-12-20 15:38:04 +01002480 case LOG_FMT_BYTES_UP: // %U
Willy Tarreau372ac5a2018-09-05 15:16:23 +02002481 ret = lltoa(logs->bytes_in, tmplog, dst + maxsize - tmplog);
Willy Tarreauc5259fd2012-12-20 15:38:04 +01002482 if (ret == NULL)
2483 goto out;
2484 tmplog = ret;
2485 last_isspace = 0;
2486 break;
2487
Willy Tarreau2beef582012-12-20 17:22:52 +01002488 case LOG_FMT_CCLIENT: // %CC
Willy Tarreau57bc8912016-04-25 17:09:40 +02002489 src = txn ? txn->cli_cookie : NULL;
William Lallemand5f232402012-04-05 18:02:55 +02002490 ret = lf_text(tmplog, src, dst + maxsize - tmplog, tmp);
William Lallemand1d705562012-03-12 12:46:41 +01002491 if (ret == NULL)
William Lallemand51b5dca2012-03-26 17:52:55 +02002492 goto out;
William Lallemand1d705562012-03-12 12:46:41 +01002493 tmplog = ret;
William Lallemandbddd4fd2012-02-27 11:23:10 +01002494 last_isspace = 0;
2495 break;
2496
Willy Tarreau2beef582012-12-20 17:22:52 +01002497 case LOG_FMT_CSERVER: // %CS
Willy Tarreau57bc8912016-04-25 17:09:40 +02002498 src = txn ? txn->srv_cookie : NULL;
William Lallemand5f232402012-04-05 18:02:55 +02002499 ret = lf_text(tmplog, src, dst + maxsize - tmplog, tmp);
William Lallemand1d705562012-03-12 12:46:41 +01002500 if (ret == NULL)
William Lallemand51b5dca2012-03-26 17:52:55 +02002501 goto out;
William Lallemand1d705562012-03-12 12:46:41 +01002502 tmplog = ret;
William Lallemandbddd4fd2012-02-27 11:23:10 +01002503 last_isspace = 0;
2504 break;
2505
William Lallemand1d705562012-03-12 12:46:41 +01002506 case LOG_FMT_TERMSTATE: // %ts
Willy Tarreaub8bc5252018-09-05 15:51:28 +02002507 LOGCHAR(sess_term_cond[(s_flags & SF_ERR_MASK) >> SF_ERR_SHIFT]);
2508 LOGCHAR(sess_fin_state[(s_flags & SF_FINST_MASK) >> SF_FINST_SHIFT]);
Willy Tarreau6580c062012-03-12 15:09:42 +01002509 *tmplog = '\0';
2510 last_isspace = 0;
2511 break;
William Lallemandbddd4fd2012-02-27 11:23:10 +01002512
William Lallemand1d705562012-03-12 12:46:41 +01002513 case LOG_FMT_TERMSTATE_CK: // %tsc, same as TS with cookie state (for mode HTTP)
Willy Tarreaub8bc5252018-09-05 15:51:28 +02002514 LOGCHAR(sess_term_cond[(s_flags & SF_ERR_MASK) >> SF_ERR_SHIFT]);
2515 LOGCHAR(sess_fin_state[(s_flags & SF_FINST_MASK) >> SF_FINST_SHIFT]);
Willy Tarreau57bc8912016-04-25 17:09:40 +02002516 LOGCHAR((txn && (be->ck_opts & PR_CK_ANY)) ? sess_cookie[(txn->flags & TX_CK_MASK) >> TX_CK_SHIFT] : '-');
2517 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 +01002518 last_isspace = 0;
2519 break;
2520
William Lallemand1d705562012-03-12 12:46:41 +01002521 case LOG_FMT_ACTCONN: // %ac
William Lallemand5f232402012-04-05 18:02:55 +02002522 ret = ltoa_o(actconn, tmplog, dst + maxsize - tmplog);
William Lallemand1d705562012-03-12 12:46:41 +01002523 if (ret == NULL)
William Lallemandbddd4fd2012-02-27 11:23:10 +01002524 goto out;
William Lallemand1d705562012-03-12 12:46:41 +01002525 tmplog = ret;
William Lallemandbddd4fd2012-02-27 11:23:10 +01002526 last_isspace = 0;
2527 break;
2528
William Lallemand1d705562012-03-12 12:46:41 +01002529 case LOG_FMT_FECONN: // %fc
William Lallemand5f232402012-04-05 18:02:55 +02002530 ret = ltoa_o(fe->feconn, tmplog, dst + maxsize - tmplog);
William Lallemand1d705562012-03-12 12:46:41 +01002531 if (ret == NULL)
William Lallemandbddd4fd2012-02-27 11:23:10 +01002532 goto out;
William Lallemand1d705562012-03-12 12:46:41 +01002533 tmplog = ret;
William Lallemandbddd4fd2012-02-27 11:23:10 +01002534 last_isspace = 0;
2535 break;
2536
William Lallemand1d705562012-03-12 12:46:41 +01002537 case LOG_FMT_BECONN: // %bc
William Lallemand5f232402012-04-05 18:02:55 +02002538 ret = ltoa_o(be->beconn, tmplog, dst + maxsize - tmplog);
William Lallemand1d705562012-03-12 12:46:41 +01002539 if (ret == NULL)
William Lallemandbddd4fd2012-02-27 11:23:10 +01002540 goto out;
William Lallemand1d705562012-03-12 12:46:41 +01002541 tmplog = ret;
William Lallemandbddd4fd2012-02-27 11:23:10 +01002542 last_isspace = 0;
2543 break;
2544
William Lallemand1d705562012-03-12 12:46:41 +01002545 case LOG_FMT_SRVCONN: // %sc
Willy Tarreaue1809df2018-09-05 15:30:16 +02002546 ret = ultoa_o(objt_server(s ? s->target : NULL) ?
Willy Tarreau3fdb3662012-11-12 00:42:33 +01002547 objt_server(s->target)->cur_sess :
William Lallemand5f232402012-04-05 18:02:55 +02002548 0, tmplog, dst + maxsize - tmplog);
William Lallemand1d705562012-03-12 12:46:41 +01002549 if (ret == NULL)
William Lallemandbddd4fd2012-02-27 11:23:10 +01002550 goto out;
William Lallemand1d705562012-03-12 12:46:41 +01002551 tmplog = ret;
William Lallemandbddd4fd2012-02-27 11:23:10 +01002552 last_isspace = 0;
2553 break;
2554
William Lallemand1d705562012-03-12 12:46:41 +01002555 case LOG_FMT_RETRIES: // %rq
Willy Tarreaub8bc5252018-09-05 15:51:28 +02002556 if (s_flags & SF_REDISP)
William Lallemand1d705562012-03-12 12:46:41 +01002557 LOGCHAR('+');
Willy Tarreauabd71a52018-09-04 19:21:44 +02002558 ret = ltoa_o((s && s->si[1].conn_retries > 0) ?
Willy Tarreau350f4872014-11-28 14:42:25 +01002559 (be->conn_retries - s->si[1].conn_retries) :
William Lallemand5f232402012-04-05 18:02:55 +02002560 be->conn_retries, tmplog, dst + maxsize - tmplog);
William Lallemand1d705562012-03-12 12:46:41 +01002561 if (ret == NULL)
William Lallemand51b5dca2012-03-26 17:52:55 +02002562 goto out;
William Lallemand1d705562012-03-12 12:46:41 +01002563 tmplog = ret;
William Lallemandbddd4fd2012-02-27 11:23:10 +01002564 last_isspace = 0;
2565 break;
2566
William Lallemand1d705562012-03-12 12:46:41 +01002567 case LOG_FMT_SRVQUEUE: // %sq
Willy Tarreau372ac5a2018-09-05 15:16:23 +02002568 ret = ltoa_o(logs->srv_queue_pos, tmplog, dst + maxsize - tmplog);
William Lallemand1d705562012-03-12 12:46:41 +01002569 if (ret == NULL)
William Lallemandbddd4fd2012-02-27 11:23:10 +01002570 goto out;
William Lallemand1d705562012-03-12 12:46:41 +01002571 tmplog = ret;
William Lallemandbddd4fd2012-02-27 11:23:10 +01002572 last_isspace = 0;
2573 break;
2574
William Lallemand1d705562012-03-12 12:46:41 +01002575 case LOG_FMT_BCKQUEUE: // %bq
Willy Tarreau372ac5a2018-09-05 15:16:23 +02002576 ret = ltoa_o(logs->prx_queue_pos, tmplog, dst + maxsize - tmplog);
William Lallemand1d705562012-03-12 12:46:41 +01002577 if (ret == NULL)
William Lallemandbddd4fd2012-02-27 11:23:10 +01002578 goto out;
William Lallemand1d705562012-03-12 12:46:41 +01002579 tmplog = ret;
William Lallemandbddd4fd2012-02-27 11:23:10 +01002580 last_isspace = 0;
2581 break;
2582
William Lallemand1d705562012-03-12 12:46:41 +01002583 case LOG_FMT_HDRREQUEST: // %hr
William Lallemandbddd4fd2012-02-27 11:23:10 +01002584 /* request header */
Willy Tarreaud4f91662018-09-05 15:28:07 +02002585 if (fe->nb_req_cap && s && s->req_cap) {
William Lallemandbddd4fd2012-02-27 11:23:10 +01002586 if (tmp->options & LOG_OPT_QUOTE)
2587 LOGCHAR('"');
2588 LOGCHAR('{');
2589 for (hdr = 0; hdr < fe->nb_req_cap; hdr++) {
2590 if (hdr)
2591 LOGCHAR('|');
Willy Tarreaucb7dd012015-04-03 22:16:32 +02002592 if (s->req_cap[hdr] != NULL) {
Dragan Dosen835b9212016-02-12 13:23:03 +01002593 ret = lf_encode_string(tmplog, dst + maxsize,
2594 '#', hdr_encode_map, s->req_cap[hdr], tmp);
William Lallemand1d705562012-03-12 12:46:41 +01002595 if (ret == NULL || *ret != '\0')
William Lallemand51b5dca2012-03-26 17:52:55 +02002596 goto out;
William Lallemand1d705562012-03-12 12:46:41 +01002597 tmplog = ret;
William Lallemand51b5dca2012-03-26 17:52:55 +02002598 }
William Lallemandbddd4fd2012-02-27 11:23:10 +01002599 }
2600 LOGCHAR('}');
William Lallemand51b5dca2012-03-26 17:52:55 +02002601 if (tmp->options & LOG_OPT_QUOTE)
2602 LOGCHAR('"');
William Lallemandbddd4fd2012-02-27 11:23:10 +01002603 last_isspace = 0;
2604 }
William Lallemandbddd4fd2012-02-27 11:23:10 +01002605 break;
2606
William Lallemand1d705562012-03-12 12:46:41 +01002607 case LOG_FMT_HDRREQUESTLIST: // %hrl
William Lallemandbddd4fd2012-02-27 11:23:10 +01002608 /* request header list */
Willy Tarreaud4f91662018-09-05 15:28:07 +02002609 if (fe->nb_req_cap && s && s->req_cap) {
William Lallemandbddd4fd2012-02-27 11:23:10 +01002610 for (hdr = 0; hdr < fe->nb_req_cap; hdr++) {
2611 if (hdr > 0)
2612 LOGCHAR(' ');
2613 if (tmp->options & LOG_OPT_QUOTE)
2614 LOGCHAR('"');
Willy Tarreaucb7dd012015-04-03 22:16:32 +02002615 if (s->req_cap[hdr] != NULL) {
Dragan Dosen835b9212016-02-12 13:23:03 +01002616 ret = lf_encode_string(tmplog, dst + maxsize,
2617 '#', hdr_encode_map, s->req_cap[hdr], tmp);
William Lallemand1d705562012-03-12 12:46:41 +01002618 if (ret == NULL || *ret != '\0')
William Lallemand51b5dca2012-03-26 17:52:55 +02002619 goto out;
William Lallemand1d705562012-03-12 12:46:41 +01002620 tmplog = ret;
William Lallemandbddd4fd2012-02-27 11:23:10 +01002621 } else if (!(tmp->options & LOG_OPT_QUOTE))
2622 LOGCHAR('-');
2623 if (tmp->options & LOG_OPT_QUOTE)
2624 LOGCHAR('"');
William Lallemandbddd4fd2012-02-27 11:23:10 +01002625 last_isspace = 0;
2626 }
2627 }
2628 break;
Willy Tarreaubaaee002006-06-26 02:48:02 +02002629
William Lallemand1d705562012-03-12 12:46:41 +01002630
2631 case LOG_FMT_HDRRESPONS: // %hs
William Lallemandbddd4fd2012-02-27 11:23:10 +01002632 /* response header */
Willy Tarreaud4f91662018-09-05 15:28:07 +02002633 if (fe->nb_rsp_cap && s && s->res_cap) {
William Lallemandbddd4fd2012-02-27 11:23:10 +01002634 if (tmp->options & LOG_OPT_QUOTE)
2635 LOGCHAR('"');
2636 LOGCHAR('{');
2637 for (hdr = 0; hdr < fe->nb_rsp_cap; hdr++) {
2638 if (hdr)
2639 LOGCHAR('|');
Willy Tarreaucb7dd012015-04-03 22:16:32 +02002640 if (s->res_cap[hdr] != NULL) {
Dragan Dosen835b9212016-02-12 13:23:03 +01002641 ret = lf_encode_string(tmplog, dst + maxsize,
2642 '#', hdr_encode_map, s->res_cap[hdr], tmp);
William Lallemand1d705562012-03-12 12:46:41 +01002643 if (ret == NULL || *ret != '\0')
William Lallemand51b5dca2012-03-26 17:52:55 +02002644 goto out;
William Lallemand1d705562012-03-12 12:46:41 +01002645 tmplog = ret;
William Lallemand51b5dca2012-03-26 17:52:55 +02002646 }
William Lallemandbddd4fd2012-02-27 11:23:10 +01002647 }
2648 LOGCHAR('}');
2649 last_isspace = 0;
2650 if (tmp->options & LOG_OPT_QUOTE)
2651 LOGCHAR('"');
2652 }
William Lallemandbddd4fd2012-02-27 11:23:10 +01002653 break;
2654
William Lallemand1d705562012-03-12 12:46:41 +01002655 case LOG_FMT_HDRRESPONSLIST: // %hsl
William Lallemandbddd4fd2012-02-27 11:23:10 +01002656 /* response header list */
Willy Tarreaud4f91662018-09-05 15:28:07 +02002657 if (fe->nb_rsp_cap && s && s->res_cap) {
William Lallemandbddd4fd2012-02-27 11:23:10 +01002658 for (hdr = 0; hdr < fe->nb_rsp_cap; hdr++) {
2659 if (hdr > 0)
2660 LOGCHAR(' ');
2661 if (tmp->options & LOG_OPT_QUOTE)
2662 LOGCHAR('"');
Willy Tarreaucb7dd012015-04-03 22:16:32 +02002663 if (s->res_cap[hdr] != NULL) {
Dragan Dosen835b9212016-02-12 13:23:03 +01002664 ret = lf_encode_string(tmplog, dst + maxsize,
2665 '#', hdr_encode_map, s->res_cap[hdr], tmp);
William Lallemand1d705562012-03-12 12:46:41 +01002666 if (ret == NULL || *ret != '\0')
William Lallemand51b5dca2012-03-26 17:52:55 +02002667 goto out;
William Lallemand1d705562012-03-12 12:46:41 +01002668 tmplog = ret;
William Lallemandbddd4fd2012-02-27 11:23:10 +01002669 } else if (!(tmp->options & LOG_OPT_QUOTE))
2670 LOGCHAR('-');
2671 if (tmp->options & LOG_OPT_QUOTE)
2672 LOGCHAR('"');
William Lallemandbddd4fd2012-02-27 11:23:10 +01002673 last_isspace = 0;
2674 }
2675 }
2676 break;
2677
William Lallemand1d705562012-03-12 12:46:41 +01002678 case LOG_FMT_REQ: // %r
William Lallemandbddd4fd2012-02-27 11:23:10 +01002679 /* Request */
2680 if (tmp->options & LOG_OPT_QUOTE)
2681 LOGCHAR('"');
Willy Tarreau57bc8912016-04-25 17:09:40 +02002682 uri = txn && txn->uri ? txn->uri : "<BADREQ>";
Dragan Dosen835b9212016-02-12 13:23:03 +01002683 ret = lf_encode_string(tmplog, dst + maxsize,
2684 '#', url_encode_map, uri, tmp);
William Lallemand1d705562012-03-12 12:46:41 +01002685 if (ret == NULL || *ret != '\0')
William Lallemand51b5dca2012-03-26 17:52:55 +02002686 goto out;
William Lallemand1d705562012-03-12 12:46:41 +01002687 tmplog = ret;
William Lallemandbddd4fd2012-02-27 11:23:10 +01002688 if (tmp->options & LOG_OPT_QUOTE)
2689 LOGCHAR('"');
William Lallemandbddd4fd2012-02-27 11:23:10 +01002690 last_isspace = 0;
2691 break;
William Lallemand5f232402012-04-05 18:02:55 +02002692
Andrew Hayworth0ebc55f2015-04-27 21:37:03 +00002693 case LOG_FMT_HTTP_PATH: // %HP
Willy Tarreau57bc8912016-04-25 17:09:40 +02002694 uri = txn && txn->uri ? txn->uri : "<BADREQ>";
Andrew Hayworth0ebc55f2015-04-27 21:37:03 +00002695
Willy Tarreaub7636d12015-06-17 19:58:02 +02002696 if (tmp->options & LOG_OPT_QUOTE)
Andrew Hayworth0ebc55f2015-04-27 21:37:03 +00002697 LOGCHAR('"');
2698
2699 end = uri + strlen(uri);
2700 // look for the first whitespace character
2701 while (uri < end && !HTTP_IS_SPHT(*uri))
2702 uri++;
2703
2704 // keep advancing past multiple spaces
2705 while (uri < end && HTTP_IS_SPHT(*uri)) {
2706 uri++; nspaces++;
2707 }
2708
2709 // look for first space or question mark after url
2710 spc = uri;
2711 while (spc < end && *spc != '?' && !HTTP_IS_SPHT(*spc))
2712 spc++;
2713
Nenad Merdanovic54e439f2016-04-26 01:39:02 +02002714 if (!txn || !txn->uri || nspaces == 0) {
Willy Tarreau843b7cb2018-07-13 10:54:26 +02002715 chunk.area = "<BADREQ>";
2716 chunk.data = strlen("<BADREQ>");
Andrew Hayworth0ebc55f2015-04-27 21:37:03 +00002717 } else {
Willy Tarreau843b7cb2018-07-13 10:54:26 +02002718 chunk.area = uri;
2719 chunk.data = spc - uri;
Andrew Hayworth0ebc55f2015-04-27 21:37:03 +00002720 }
2721
Dragan Dosen835b9212016-02-12 13:23:03 +01002722 ret = lf_encode_chunk(tmplog, dst + maxsize, '#', url_encode_map, &chunk, tmp);
Andrew Hayworth0ebc55f2015-04-27 21:37:03 +00002723 if (ret == NULL || *ret != '\0')
2724 goto out;
2725
2726 tmplog = ret;
Willy Tarreaub7636d12015-06-17 19:58:02 +02002727 if (tmp->options & LOG_OPT_QUOTE)
Andrew Hayworth0ebc55f2015-04-27 21:37:03 +00002728 LOGCHAR('"');
2729
2730 last_isspace = 0;
2731 break;
2732
Andrew Hayworthe63ac872015-07-31 16:14:16 +00002733 case LOG_FMT_HTTP_QUERY: // %HQ
2734 if (tmp->options & LOG_OPT_QUOTE)
2735 LOGCHAR('"');
2736
Willy Tarreau57bc8912016-04-25 17:09:40 +02002737 if (!txn || !txn->uri) {
Willy Tarreau843b7cb2018-07-13 10:54:26 +02002738 chunk.area = "<BADREQ>";
2739 chunk.data = strlen("<BADREQ>");
Andrew Hayworthe63ac872015-07-31 16:14:16 +00002740 } else {
2741 uri = txn->uri;
2742 end = uri + strlen(uri);
2743 // look for the first question mark
2744 while (uri < end && *uri != '?')
2745 uri++;
2746
2747 qmark = uri;
2748 // look for first space or question mark after url
2749 while (uri < end && !HTTP_IS_SPHT(*uri))
2750 uri++;
2751
Willy Tarreau843b7cb2018-07-13 10:54:26 +02002752 chunk.area = qmark;
2753 chunk.data = uri - qmark;
Andrew Hayworthe63ac872015-07-31 16:14:16 +00002754 }
2755
Dragan Dosen835b9212016-02-12 13:23:03 +01002756 ret = lf_encode_chunk(tmplog, dst + maxsize, '#', url_encode_map, &chunk, tmp);
Andrew Hayworthe63ac872015-07-31 16:14:16 +00002757 if (ret == NULL || *ret != '\0')
2758 goto out;
2759
2760 tmplog = ret;
2761 if (tmp->options & LOG_OPT_QUOTE)
2762 LOGCHAR('"');
2763
2764 last_isspace = 0;
2765 break;
2766
Andrew Hayworth0ebc55f2015-04-27 21:37:03 +00002767 case LOG_FMT_HTTP_URI: // %HU
Willy Tarreau57bc8912016-04-25 17:09:40 +02002768 uri = txn && txn->uri ? txn->uri : "<BADREQ>";
Andrew Hayworth0ebc55f2015-04-27 21:37:03 +00002769
Willy Tarreaub7636d12015-06-17 19:58:02 +02002770 if (tmp->options & LOG_OPT_QUOTE)
Andrew Hayworth0ebc55f2015-04-27 21:37:03 +00002771 LOGCHAR('"');
2772
2773 end = uri + strlen(uri);
2774 // look for the first whitespace character
2775 while (uri < end && !HTTP_IS_SPHT(*uri))
2776 uri++;
2777
2778 // keep advancing past multiple spaces
2779 while (uri < end && HTTP_IS_SPHT(*uri)) {
2780 uri++; nspaces++;
2781 }
2782
2783 // look for first space after url
2784 spc = uri;
2785 while (spc < end && !HTTP_IS_SPHT(*spc))
2786 spc++;
2787
Willy Tarreau57bc8912016-04-25 17:09:40 +02002788 if (!txn || !txn->uri || nspaces == 0) {
Willy Tarreau843b7cb2018-07-13 10:54:26 +02002789 chunk.area = "<BADREQ>";
2790 chunk.data = strlen("<BADREQ>");
Andrew Hayworth0ebc55f2015-04-27 21:37:03 +00002791 } else {
Willy Tarreau843b7cb2018-07-13 10:54:26 +02002792 chunk.area = uri;
2793 chunk.data = spc - uri;
Andrew Hayworth0ebc55f2015-04-27 21:37:03 +00002794 }
2795
Dragan Dosen835b9212016-02-12 13:23:03 +01002796 ret = lf_encode_chunk(tmplog, dst + maxsize, '#', url_encode_map, &chunk, tmp);
Andrew Hayworth0ebc55f2015-04-27 21:37:03 +00002797 if (ret == NULL || *ret != '\0')
2798 goto out;
2799
2800 tmplog = ret;
Willy Tarreaub7636d12015-06-17 19:58:02 +02002801 if (tmp->options & LOG_OPT_QUOTE)
Andrew Hayworth0ebc55f2015-04-27 21:37:03 +00002802 LOGCHAR('"');
2803
2804 last_isspace = 0;
2805 break;
2806
2807 case LOG_FMT_HTTP_METHOD: // %HM
Willy Tarreau57bc8912016-04-25 17:09:40 +02002808 uri = txn && txn->uri ? txn->uri : "<BADREQ>";
Willy Tarreaub7636d12015-06-17 19:58:02 +02002809 if (tmp->options & LOG_OPT_QUOTE)
Andrew Hayworth0ebc55f2015-04-27 21:37:03 +00002810 LOGCHAR('"');
2811
2812 end = uri + strlen(uri);
2813 // look for the first whitespace character
2814 spc = uri;
2815 while (spc < end && !HTTP_IS_SPHT(*spc))
2816 spc++;
2817
2818 if (spc == end) { // odd case, we have txn->uri, but we only got a verb
Willy Tarreau843b7cb2018-07-13 10:54:26 +02002819 chunk.area = "<BADREQ>";
2820 chunk.data = strlen("<BADREQ>");
Andrew Hayworth0ebc55f2015-04-27 21:37:03 +00002821 } else {
Willy Tarreau843b7cb2018-07-13 10:54:26 +02002822 chunk.area = uri;
2823 chunk.data = spc - uri;
Andrew Hayworth0ebc55f2015-04-27 21:37:03 +00002824 }
2825
Dragan Dosen835b9212016-02-12 13:23:03 +01002826 ret = lf_encode_chunk(tmplog, dst + maxsize, '#', url_encode_map, &chunk, tmp);
Andrew Hayworth0ebc55f2015-04-27 21:37:03 +00002827 if (ret == NULL || *ret != '\0')
2828 goto out;
2829
2830 tmplog = ret;
Willy Tarreaub7636d12015-06-17 19:58:02 +02002831 if (tmp->options & LOG_OPT_QUOTE)
Andrew Hayworth0ebc55f2015-04-27 21:37:03 +00002832 LOGCHAR('"');
2833
2834 last_isspace = 0;
2835 break;
2836
2837 case LOG_FMT_HTTP_VERSION: // %HV
Willy Tarreau57bc8912016-04-25 17:09:40 +02002838 uri = txn && txn->uri ? txn->uri : "<BADREQ>";
Willy Tarreaub7636d12015-06-17 19:58:02 +02002839 if (tmp->options & LOG_OPT_QUOTE)
Andrew Hayworth0ebc55f2015-04-27 21:37:03 +00002840 LOGCHAR('"');
2841
2842 end = uri + strlen(uri);
2843 // look for the first whitespace character
2844 while (uri < end && !HTTP_IS_SPHT(*uri))
2845 uri++;
2846
2847 // keep advancing past multiple spaces
2848 while (uri < end && HTTP_IS_SPHT(*uri)) {
2849 uri++; nspaces++;
2850 }
2851
2852 // look for the next whitespace character
2853 while (uri < end && !HTTP_IS_SPHT(*uri))
2854 uri++;
2855
2856 // keep advancing past multiple spaces
2857 while (uri < end && HTTP_IS_SPHT(*uri))
2858 uri++;
2859
Willy Tarreau57bc8912016-04-25 17:09:40 +02002860 if (!txn || !txn->uri || nspaces == 0) {
Willy Tarreau843b7cb2018-07-13 10:54:26 +02002861 chunk.area = "<BADREQ>";
2862 chunk.data = strlen("<BADREQ>");
Andrew Hayworth0ebc55f2015-04-27 21:37:03 +00002863 } else if (uri == end) {
Willy Tarreau843b7cb2018-07-13 10:54:26 +02002864 chunk.area = "HTTP/0.9";
2865 chunk.data = strlen("HTTP/0.9");
Andrew Hayworth0ebc55f2015-04-27 21:37:03 +00002866 } else {
Willy Tarreau843b7cb2018-07-13 10:54:26 +02002867 chunk.area = uri;
2868 chunk.data = end - uri;
Andrew Hayworth0ebc55f2015-04-27 21:37:03 +00002869 }
2870
Dragan Dosen835b9212016-02-12 13:23:03 +01002871 ret = lf_encode_chunk(tmplog, dst + maxsize, '#', url_encode_map, &chunk, tmp);
Andrew Hayworth0ebc55f2015-04-27 21:37:03 +00002872 if (ret == NULL || *ret != '\0')
2873 goto out;
2874
2875 tmplog = ret;
Willy Tarreaub7636d12015-06-17 19:58:02 +02002876 if (tmp->options & LOG_OPT_QUOTE)
Andrew Hayworth0ebc55f2015-04-27 21:37:03 +00002877 LOGCHAR('"');
2878
2879 last_isspace = 0;
2880 break;
2881
William Lallemand5f232402012-04-05 18:02:55 +02002882 case LOG_FMT_COUNTER: // %rt
2883 if (tmp->options & LOG_OPT_HEXA) {
Willy Tarreau5cacab62018-09-05 15:52:59 +02002884 iret = snprintf(tmplog, dst + maxsize - tmplog, "%04X", uniq_id);
William Lallemand5f232402012-04-05 18:02:55 +02002885 if (iret < 0 || iret > dst + maxsize - tmplog)
2886 goto out;
2887 last_isspace = 0;
2888 tmplog += iret;
2889 } else {
Willy Tarreau5cacab62018-09-05 15:52:59 +02002890 ret = ltoa_o(uniq_id, tmplog, dst + maxsize - tmplog);
William Lallemand5f232402012-04-05 18:02:55 +02002891 if (ret == NULL)
2892 goto out;
2893 tmplog = ret;
2894 last_isspace = 0;
2895 }
2896 break;
2897
Willy Tarreau7346acb2014-08-28 15:03:15 +02002898 case LOG_FMT_LOGCNT: // %lc
2899 if (tmp->options & LOG_OPT_HEXA) {
Willy Tarreaue36cbcb2015-04-03 15:40:56 +02002900 iret = snprintf(tmplog, dst + maxsize - tmplog, "%04X", fe->log_count);
Willy Tarreau7346acb2014-08-28 15:03:15 +02002901 if (iret < 0 || iret > dst + maxsize - tmplog)
2902 goto out;
2903 last_isspace = 0;
2904 tmplog += iret;
2905 } else {
Willy Tarreaue36cbcb2015-04-03 15:40:56 +02002906 ret = ultoa_o(fe->log_count, tmplog, dst + maxsize - tmplog);
Willy Tarreau7346acb2014-08-28 15:03:15 +02002907 if (ret == NULL)
2908 goto out;
2909 tmplog = ret;
2910 last_isspace = 0;
2911 }
2912 break;
2913
William Lallemand5f232402012-04-05 18:02:55 +02002914 case LOG_FMT_HOSTNAME: // %H
2915 src = hostname;
2916 ret = lf_text(tmplog, src, dst + maxsize - tmplog, tmp);
2917 if (ret == NULL)
2918 goto out;
2919 tmplog = ret;
2920 last_isspace = 0;
2921 break;
2922
2923 case LOG_FMT_PID: // %pid
2924 if (tmp->options & LOG_OPT_HEXA) {
2925 iret = snprintf(tmplog, dst + maxsize - tmplog, "%04X", pid);
2926 if (iret < 0 || iret > dst + maxsize - tmplog)
2927 goto out;
2928 last_isspace = 0;
2929 tmplog += iret;
2930 } else {
2931 ret = ltoa_o(pid, tmplog, dst + maxsize - tmplog);
2932 if (ret == NULL)
2933 goto out;
2934 tmplog = ret;
2935 last_isspace = 0;
2936 }
2937 break;
William Lallemanda73203e2012-03-12 12:48:57 +01002938
2939 case LOG_FMT_UNIQUEID: // %ID
William Lallemand5b7ea3a2013-08-28 15:44:19 +02002940 ret = NULL;
Tim Duesterhusa17e6622020-03-05 20:19:02 +01002941 if (s)
2942 ret = lf_text_len(tmplog, s->unique_id.ptr, s->unique_id.len, maxsize - (tmplog - dst), tmp);
2943 else
2944 ret = lf_text_len(tmplog, NULL, 0, maxsize - (tmplog - dst), tmp);
William Lallemanda73203e2012-03-12 12:48:57 +01002945 if (ret == NULL)
2946 goto out;
2947 tmplog = ret;
2948 last_isspace = 0;
2949 break;
2950
William Lallemandbddd4fd2012-02-27 11:23:10 +01002951 }
2952 }
2953
2954out:
William Lallemand1d705562012-03-12 12:46:41 +01002955 /* *tmplog is a unused character */
2956 *tmplog = '\0';
Willy Tarreaudf974472012-12-28 02:44:01 +01002957 return tmplog - dst;
William Lallemandbddd4fd2012-02-27 11:23:10 +01002958
Willy Tarreaubaaee002006-06-26 02:48:02 +02002959}
2960
William Lallemand1d705562012-03-12 12:46:41 +01002961/*
Willy Tarreau87b09662015-04-03 00:22:06 +02002962 * send a log for the stream when we have enough info about it.
William Lallemand1d705562012-03-12 12:46:41 +01002963 * Will not log if the frontend has no log defined.
2964 */
Willy Tarreau87b09662015-04-03 00:22:06 +02002965void strm_log(struct stream *s)
William Lallemand1d705562012-03-12 12:46:41 +01002966{
Willy Tarreaue36cbcb2015-04-03 15:40:56 +02002967 struct session *sess = s->sess;
William Lallemand1d705562012-03-12 12:46:41 +01002968 int size, err, level;
Dragan Dosen0b85ece2015-09-25 19:17:44 +02002969 int sd_size = 0;
William Lallemand1d705562012-03-12 12:46:41 +01002970
2971 /* if we don't want to log normal traffic, return now */
Willy Tarreaue7dff022015-04-03 01:14:29 +02002972 err = (s->flags & SF_REDISP) ||
2973 ((s->flags & SF_ERR_MASK) > SF_ERR_LOCAL) ||
2974 (((s->flags & SF_ERR_MASK) == SF_ERR_NONE) &&
Willy Tarreau350f4872014-11-28 14:42:25 +01002975 (s->si[1].conn_retries != s->be->conn_retries)) ||
Willy Tarreaueee5b512015-04-03 23:46:31 +02002976 ((sess->fe->mode == PR_MODE_HTTP) && s->txn && s->txn->status >= 500);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002977
Willy Tarreaue36cbcb2015-04-03 15:40:56 +02002978 if (!err && (sess->fe->options2 & PR_O2_NOLOGNORM))
William Lallemand1d705562012-03-12 12:46:41 +01002979 return;
William Lallemandbddd4fd2012-02-27 11:23:10 +01002980
Willy Tarreaue36cbcb2015-04-03 15:40:56 +02002981 if (LIST_ISEMPTY(&sess->fe->logsrvs))
William Lallemand1d705562012-03-12 12:46:41 +01002982 return;
William Lallemandbddd4fd2012-02-27 11:23:10 +01002983
Willy Tarreauabcd5142013-06-11 17:18:02 +02002984 if (s->logs.level) { /* loglevel was overridden */
2985 if (s->logs.level == -1) {
2986 s->logs.logwait = 0; /* logs disabled */
2987 return;
2988 }
2989 level = s->logs.level - 1;
2990 }
2991 else {
2992 level = LOG_INFO;
Willy Tarreaue36cbcb2015-04-03 15:40:56 +02002993 if (err && (sess->fe->options2 & PR_O2_LOGERRORS))
Willy Tarreauabcd5142013-06-11 17:18:02 +02002994 level = LOG_ERR;
2995 }
William Lallemand1d705562012-03-12 12:46:41 +01002996
William Lallemand5b7ea3a2013-08-28 15:44:19 +02002997 /* if unique-id was not generated */
Tim Duesterhusa17e6622020-03-05 20:19:02 +01002998 if (!isttest(s->unique_id) && !LIST_ISEMPTY(&sess->fe->format_unique_id)) {
Tim Duesterhus2825b4b2020-02-28 15:13:34 +01002999 stream_generate_unique_id(s, &sess->fe->format_unique_id);
William Lallemand5b7ea3a2013-08-28 15:44:19 +02003000 }
3001
Dragan Dosen0b85ece2015-09-25 19:17:44 +02003002 if (!LIST_ISEMPTY(&sess->fe->logformat_sd)) {
3003 sd_size = build_logline(s, logline_rfc5424, global.max_syslog_len,
3004 &sess->fe->logformat_sd);
3005 }
3006
Dragan Dosen59cee972015-09-19 22:09:02 +02003007 size = build_logline(s, logline, global.max_syslog_len, &sess->fe->logformat);
William Lallemand1d705562012-03-12 12:46:41 +01003008 if (size > 0) {
Olivier Houchardd2ee3e72019-03-08 18:53:21 +01003009 _HA_ATOMIC_ADD(&sess->fe->log_count, 1);
Christopher Faulet5c6fefc2019-08-11 19:40:12 +02003010 __send_log(&sess->fe->logsrvs, &sess->fe->log_tag, level,
3011 logline, size + 1, logline_rfc5424, sd_size);
William Lallemand1d705562012-03-12 12:46:41 +01003012 s->logs.logwait = 0;
3013 }
3014}
William Lallemandbddd4fd2012-02-27 11:23:10 +01003015
Willy Tarreau53839352018-09-05 19:51:10 +02003016/*
3017 * send a minimalist log for the session. Will not log if the frontend has no
3018 * log defined. It is assumed that this is only used to report anomalies that
3019 * cannot lead to the creation of a regular stream. Because of this the log
3020 * level is LOG_INFO or LOG_ERR depending on the "log-separate-error" setting
3021 * in the frontend. The caller must simply know that it should not call this
Willy Tarreau9fa267d2018-10-05 10:22:27 +02003022 * function to report unimportant events. It is safe to call this function with
3023 * sess==NULL (will not do anything).
Willy Tarreau53839352018-09-05 19:51:10 +02003024 */
3025void sess_log(struct session *sess)
3026{
3027 int size, level;
3028 int sd_size = 0;
3029
Willy Tarreau9fa267d2018-10-05 10:22:27 +02003030 if (!sess)
3031 return;
3032
Willy Tarreau53839352018-09-05 19:51:10 +02003033 if (LIST_ISEMPTY(&sess->fe->logsrvs))
3034 return;
3035
3036 level = LOG_INFO;
3037 if (sess->fe->options2 & PR_O2_LOGERRORS)
3038 level = LOG_ERR;
3039
3040 if (!LIST_ISEMPTY(&sess->fe->logformat_sd)) {
3041 sd_size = sess_build_logline(sess, NULL,
3042 logline_rfc5424, global.max_syslog_len,
3043 &sess->fe->logformat_sd);
3044 }
3045
3046 size = sess_build_logline(sess, NULL, logline, global.max_syslog_len, &sess->fe->logformat);
3047 if (size > 0) {
Olivier Houchardd2ee3e72019-03-08 18:53:21 +01003048 _HA_ATOMIC_ADD(&sess->fe->log_count, 1);
Christopher Faulet5c6fefc2019-08-11 19:40:12 +02003049 __send_log(&sess->fe->logsrvs, &sess->fe->log_tag, level,
3050 logline, size + 1, logline_rfc5424, sd_size);
Willy Tarreau53839352018-09-05 19:51:10 +02003051 }
3052}
3053
Christopher Faulet5c6fefc2019-08-11 19:40:12 +02003054void app_log(struct list *logsrvs, struct buffer *tag, int level, const char *format, ...)
3055{
3056 va_list argp;
3057 int data_len;
3058
3059 if (level < 0 || format == NULL || logline == NULL)
3060 return;
3061
3062 va_start(argp, format);
3063 data_len = vsnprintf(logline, global.max_syslog_len, format, argp);
3064 if (data_len < 0 || data_len > global.max_syslog_len)
3065 data_len = global.max_syslog_len;
3066 va_end(argp);
3067
3068 __send_log(logsrvs, tag, level, logline, data_len, default_rfc5424_sd_log_format, 2);
3069}
3070
Willy Tarreau869efd52019-11-15 15:16:57 +01003071/* parse the "show startup-logs" command, returns 1 if a message is returned, otherwise zero */
3072static int cli_parse_show_startup_logs(char **args, char *payload, struct appctx *appctx, void *private)
Christopher Fauletc1b730a2017-10-24 12:00:51 +02003073{
Willy Tarreau869efd52019-11-15 15:16:57 +01003074 if (!cli_has_level(appctx, ACCESS_LVL_OPER))
3075 return 1;
Christopher Fauletc1b730a2017-10-24 12:00:51 +02003076
Willy Tarreau869efd52019-11-15 15:16:57 +01003077 if (!startup_logs)
3078 return cli_msg(appctx, LOG_INFO, "\n"); // nothing to print
3079
3080 return ring_attach_cli(startup_logs, appctx);
Christopher Fauletc1b730a2017-10-24 12:00:51 +02003081}
3082
3083/* register cli keywords */
3084static struct cli_kw_list cli_kws = {{ },{
3085 { { "show", "startup-logs", NULL },
Willy Tarreau869efd52019-11-15 15:16:57 +01003086 "show startup-logs : report logs emitted during HAProxy startup", cli_parse_show_startup_logs, NULL, NULL },
Christopher Fauletc1b730a2017-10-24 12:00:51 +02003087 {{},}
3088}};
3089
Willy Tarreau0108d902018-11-25 19:14:37 +01003090INITCALL1(STG_REGISTER, cli_register_kw, &cli_kws);
3091
Willy Tarreau082b6282019-05-22 14:42:12 +02003092REGISTER_PER_THREAD_ALLOC(init_log_buffers);
3093REGISTER_PER_THREAD_FREE(deinit_log_buffers);
Willy Tarreau172f5ce2018-11-26 11:21:50 +01003094
Willy Tarreaubaaee002006-06-26 02:48:02 +02003095/*
3096 * Local variables:
3097 * c-indent-level: 8
3098 * c-basic-offset: 8
3099 * End:
3100 */