blob: 23e6c475757cca042a0f19e6ba87cdbf1258a9e3 [file] [log] [blame]
Willy Tarreaubaaee002006-06-26 02:48:02 +02001/*
2 * General logging functions.
3 *
Willy Tarreaub7f694f2008-06-22 17:18:02 +02004 * Copyright 2000-2008 Willy Tarreau <w@1wt.eu>
Willy Tarreaubaaee002006-06-26 02:48:02 +02005 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License
8 * as published by the Free Software Foundation; either version
9 * 2 of the License, or (at your option) any later version.
10 *
11 */
12
Willy Tarreau8a3f52f2012-12-20 21:23:42 +010013#include <ctype.h>
Willy Tarreauc8f24f82007-11-30 18:38:35 +010014#include <fcntl.h>
Willy Tarreaubaaee002006-06-26 02:48:02 +020015#include <stdarg.h>
16#include <stdio.h>
17#include <stdlib.h>
18#include <string.h>
19#include <syslog.h>
20#include <time.h>
21#include <unistd.h>
Robert Tsai81ae1952007-12-05 10:47:29 +010022#include <errno.h>
Willy Tarreaubaaee002006-06-26 02:48:02 +020023
24#include <sys/time.h>
Willy Tarreau077edcb2016-08-10 18:30:56 +020025#include <sys/uio.h>
Willy Tarreaubaaee002006-06-26 02:48:02 +020026
Willy Tarreaue3ba5f02006-06-29 18:54:54 +020027#include <common/config.h>
Willy Tarreaud6d06902009-08-19 11:22:33 +020028#include <common/compat.h>
Willy Tarreau0108d902018-11-25 19:14:37 +010029#include <common/initcall.h>
Willy Tarreau2dd0d472006-06-29 17:53:05 +020030#include <common/standard.h>
Willy Tarreaufb278672006-10-15 15:38:50 +020031#include <common/time.h>
Willy Tarreaubaaee002006-06-26 02:48:02 +020032
Christopher Fauletc1b730a2017-10-24 12:00:51 +020033#include <types/cli.h>
Willy Tarreaubaaee002006-06-26 02:48:02 +020034#include <types/global.h>
William Lallemand723b73a2012-02-08 16:37:49 +010035#include <types/log.h>
Willy Tarreauec6c5df2008-07-15 00:22:45 +020036
Christopher Fauletc1b730a2017-10-24 12:00:51 +020037#include <proto/applet.h>
38#include <proto/cli.h>
Willy Tarreaud52a7f82019-08-30 14:05:35 +020039#include <proto/fd.h>
William Lallemand5f232402012-04-05 18:02:55 +020040#include <proto/frontend.h>
Willy Tarreauec6c5df2008-07-15 00:22:45 +020041#include <proto/log.h>
Willy Tarreauc046d162019-08-30 15:24:59 +020042#include <proto/ring.h>
Willy Tarreauc8368452012-12-21 00:09:23 +010043#include <proto/sample.h>
Willy Tarreauc046d162019-08-30 15:24:59 +020044#include <proto/sink.h>
Willy Tarreauc125cef2019-05-10 09:58:43 +020045#include <proto/ssl_sock.h>
Willy Tarreaufb0afa72015-04-03 14:46:27 +020046#include <proto/stream.h>
Willy Tarreau827aee92011-03-10 16:55:02 +010047#include <proto/stream_interface.h>
Willy Tarreaubaaee002006-06-26 02:48:02 +020048
Dragan Dosen43885c72015-10-01 13:18:13 +020049struct log_fmt {
50 char *name;
51 struct {
Willy Tarreau83061a82018-07-13 11:56:34 +020052 struct buffer sep1; /* first pid separator */
53 struct buffer sep2; /* second pid separator */
Dragan Dosen43885c72015-10-01 13:18:13 +020054 } pid;
55};
56
57static const struct log_fmt log_formats[LOG_FORMATS] = {
58 [LOG_FORMAT_RFC3164] = {
59 .name = "rfc3164",
60 .pid = {
Willy Tarreau843b7cb2018-07-13 10:54:26 +020061 .sep1 = { .area = "[", .data = 1 },
62 .sep2 = { .area = "]: ", .data = 3 }
Dragan Dosen43885c72015-10-01 13:18:13 +020063 }
64 },
65 [LOG_FORMAT_RFC5424] = {
66 .name = "rfc5424",
67 .pid = {
Willy Tarreau843b7cb2018-07-13 10:54:26 +020068 .sep1 = { .area = " ", .data = 1 },
69 .sep2 = { .area = " - ", .data = 3 }
Dragan Dosen43885c72015-10-01 13:18:13 +020070 }
Willy Tarreaue8746a02018-11-12 08:45:00 +010071 },
72 [LOG_FORMAT_SHORT] = {
73 .name = "short",
74 .pid = {
75 .sep1 = { .area = "", .data = 0 },
76 .sep2 = { .area = " ", .data = 1 },
77 }
78 },
Willy Tarreauc1b06452018-11-12 11:57:56 +010079 [LOG_FORMAT_RAW] = {
80 .name = "raw",
81 .pid = {
82 .sep1 = { .area = "", .data = 0 },
83 .sep2 = { .area = "", .data = 0 },
84 }
85 },
Dragan Dosen1322d092015-09-22 16:05:32 +020086};
87
Dragan Dosen835b9212016-02-12 13:23:03 +010088/*
89 * This map is used with all the FD_* macros to check whether a particular bit
Willy Tarreau1bfd6022019-06-07 11:10:07 +020090 * is set or not. Each bit represents an ACSII code. ha_bit_set() sets those
91 * bytes which should be escaped. When ha_bit_test() returns non-zero, it means
92 * that the byte should be escaped. Be careful to always pass bytes from 0 to
93 * 255 exclusively to the macros.
Dragan Dosen835b9212016-02-12 13:23:03 +010094 */
Willy Tarreau1bfd6022019-06-07 11:10:07 +020095long rfc5424_escape_map[(256/8) / sizeof(long)];
96long hdr_encode_map[(256/8) / sizeof(long)];
97long url_encode_map[(256/8) / sizeof(long)];
98long http_encode_map[(256/8) / sizeof(long)];
Dragan Dosen835b9212016-02-12 13:23:03 +010099
Dragan Dosen835b9212016-02-12 13:23:03 +0100100
Willy Tarreaubaaee002006-06-26 02:48:02 +0200101const char *log_facilities[NB_LOG_FACILITIES] = {
102 "kern", "user", "mail", "daemon",
103 "auth", "syslog", "lpr", "news",
104 "uucp", "cron", "auth2", "ftp",
105 "ntp", "audit", "alert", "cron2",
106 "local0", "local1", "local2", "local3",
107 "local4", "local5", "local6", "local7"
108};
109
Willy Tarreaubaaee002006-06-26 02:48:02 +0200110const char *log_levels[NB_LOG_LEVELS] = {
111 "emerg", "alert", "crit", "err",
112 "warning", "notice", "info", "debug"
113};
114
Willy Tarreau570f2212013-06-10 16:42:09 +0200115const char sess_term_cond[16] = "-LcCsSPRIDKUIIII"; /* normal, Local, CliTo, CliErr, SrvTo, SrvErr, PxErr, Resource, Internal, Down, Killed, Up, -- */
Willy Tarreaub8750a82006-09-03 09:56:00 +0200116const char sess_fin_state[8] = "-RCHDLQT"; /* cliRequest, srvConnect, srvHeader, Data, Last, Queue, Tarpit */
Willy Tarreaubaaee002006-06-26 02:48:02 +0200117
William Lallemand723b73a2012-02-08 16:37:49 +0100118
119/* log_format */
120struct logformat_type {
121 char *name;
122 int type;
William Lallemandbddd4fd2012-02-27 11:23:10 +0100123 int mode;
William Lallemand5e19a282012-04-02 16:22:10 +0200124 int lw; /* logwait bitsfield */
William Lallemandb7ff6a32012-03-02 14:35:21 +0100125 int (*config_callback)(struct logformat_node *node, struct proxy *curproxy);
Willy Tarreau2beef582012-12-20 17:22:52 +0100126 const char *replace_by; /* new option to use instead of old one */
William Lallemand723b73a2012-02-08 16:37:49 +0100127};
128
William Lallemandb7ff6a32012-03-02 14:35:21 +0100129int prepare_addrsource(struct logformat_node *node, struct proxy *curproxy);
130
William Lallemand723b73a2012-02-08 16:37:49 +0100131/* log_format variable names */
132static const struct logformat_type logformat_keywords[] = {
William Lallemand5e19a282012-04-02 16:22:10 +0200133 { "o", LOG_FMT_GLOBAL, PR_MODE_TCP, 0, NULL }, /* global option */
Willy Tarreau2beef582012-12-20 17:22:52 +0100134
135 /* please keep these lines sorted ! */
136 { "B", LOG_FMT_BYTES, PR_MODE_TCP, LW_BYTES, NULL }, /* bytes from server to client */
137 { "CC", LOG_FMT_CCLIENT, PR_MODE_HTTP, LW_REQHDR, NULL }, /* client cookie */
138 { "CS", LOG_FMT_CSERVER, PR_MODE_HTTP, LW_RSPHDR, NULL }, /* server cookie */
139 { "H", LOG_FMT_HOSTNAME, PR_MODE_TCP, LW_INIT, NULL }, /* Hostname */
140 { "ID", LOG_FMT_UNIQUEID, PR_MODE_HTTP, LW_BYTES, NULL }, /* Unique ID */
Willy Tarreau4bf99632014-06-13 12:21:40 +0200141 { "ST", LOG_FMT_STATUS, PR_MODE_TCP, LW_RESP, NULL }, /* status code */
William Lallemand5e19a282012-04-02 16:22:10 +0200142 { "T", LOG_FMT_DATEGMT, PR_MODE_TCP, LW_INIT, NULL }, /* date GMT */
Thierry FOURNIER / OZON.IO4cac3592016-07-28 17:19:45 +0200143 { "Ta", LOG_FMT_Ta, PR_MODE_HTTP, LW_BYTES, NULL }, /* Time active (tr to end) */
Willy Tarreau2beef582012-12-20 17:22:52 +0100144 { "Tc", LOG_FMT_TC, PR_MODE_TCP, LW_BYTES, NULL }, /* Tc */
Thierry FOURNIER / OZON.IO4cac3592016-07-28 17:19:45 +0200145 { "Th", LOG_FMT_Th, PR_MODE_TCP, LW_BYTES, NULL }, /* Time handshake */
146 { "Ti", LOG_FMT_Ti, PR_MODE_HTTP, LW_BYTES, NULL }, /* Time idle */
147 { "Tl", LOG_FMT_DATELOCAL, PR_MODE_TCP, LW_INIT, NULL }, /* date local timezone */
148 { "Tq", LOG_FMT_TQ, PR_MODE_HTTP, LW_BYTES, NULL }, /* Tq=Th+Ti+TR */
149 { "Tr", LOG_FMT_Tr, PR_MODE_HTTP, LW_BYTES, NULL }, /* Tr */
150 { "TR", LOG_FMT_TR, PR_MODE_HTTP, LW_BYTES, NULL }, /* Time to receive a valid request */
Willy Tarreau27b639d2016-05-17 17:55:27 +0200151 { "Td", LOG_FMT_TD, PR_MODE_TCP, LW_BYTES, NULL }, /* Td = Tt - (Tq + Tw + Tc + Tr) */
Willy Tarreau2beef582012-12-20 17:22:52 +0100152 { "Ts", LOG_FMT_TS, PR_MODE_TCP, LW_INIT, NULL }, /* timestamp GMT */
William Lallemand5e19a282012-04-02 16:22:10 +0200153 { "Tt", LOG_FMT_TT, PR_MODE_TCP, LW_BYTES, NULL }, /* Tt */
Willy Tarreau2beef582012-12-20 17:22:52 +0100154 { "Tw", LOG_FMT_TW, PR_MODE_TCP, LW_BYTES, NULL }, /* Tw */
155 { "U", LOG_FMT_BYTES_UP, PR_MODE_TCP, LW_BYTES, NULL }, /* bytes from client to server */
William Lallemand5e19a282012-04-02 16:22:10 +0200156 { "ac", LOG_FMT_ACTCONN, PR_MODE_TCP, LW_BYTES, NULL }, /* actconn */
Willy Tarreau2beef582012-12-20 17:22:52 +0100157 { "b", LOG_FMT_BACKEND, PR_MODE_TCP, LW_INIT, NULL }, /* backend */
William Lallemand5e19a282012-04-02 16:22:10 +0200158 { "bc", LOG_FMT_BECONN, PR_MODE_TCP, LW_BYTES, NULL }, /* beconn */
Willy Tarreau2beef582012-12-20 17:22:52 +0100159 { "bi", LOG_FMT_BACKENDIP, PR_MODE_TCP, LW_BCKIP, prepare_addrsource }, /* backend source ip */
160 { "bp", LOG_FMT_BACKENDPORT, PR_MODE_TCP, LW_BCKIP, prepare_addrsource }, /* backend source port */
William Lallemand5e19a282012-04-02 16:22:10 +0200161 { "bq", LOG_FMT_BCKQUEUE, PR_MODE_TCP, LW_BYTES, NULL }, /* backend_queue */
Willy Tarreaud02286d2017-06-23 11:23:43 +0200162 { "ci", LOG_FMT_CLIENTIP, PR_MODE_TCP, LW_CLIP | LW_XPRT, NULL }, /* client ip */
163 { "cp", LOG_FMT_CLIENTPORT, PR_MODE_TCP, LW_CLIP | LW_XPRT, NULL }, /* client port */
Willy Tarreau2beef582012-12-20 17:22:52 +0100164 { "f", LOG_FMT_FRONTEND, PR_MODE_TCP, LW_INIT, NULL }, /* frontend */
165 { "fc", LOG_FMT_FECONN, PR_MODE_TCP, LW_BYTES, NULL }, /* feconn */
Willy Tarreaud02286d2017-06-23 11:23:43 +0200166 { "fi", LOG_FMT_FRONTENDIP, PR_MODE_TCP, LW_FRTIP | LW_XPRT, NULL }, /* frontend ip */
167 { "fp", LOG_FMT_FRONTENDPORT, PR_MODE_TCP, LW_FRTIP | LW_XPRT, NULL }, /* frontend port */
Willy Tarreau2beef582012-12-20 17:22:52 +0100168 { "ft", LOG_FMT_FRONTEND_XPRT, PR_MODE_TCP, LW_INIT, NULL }, /* frontend with transport mode */
Willy Tarreaud9ed3d22014-06-13 12:23:06 +0200169 { "hr", LOG_FMT_HDRREQUEST, PR_MODE_TCP, LW_REQHDR, NULL }, /* header request */
170 { "hrl", LOG_FMT_HDRREQUESTLIST, PR_MODE_TCP, LW_REQHDR, NULL }, /* header request list */
171 { "hs", LOG_FMT_HDRRESPONS, PR_MODE_TCP, LW_RSPHDR, NULL }, /* header response */
172 { "hsl", LOG_FMT_HDRRESPONSLIST, PR_MODE_TCP, LW_RSPHDR, NULL }, /* header response list */
Andrew Hayworth0ebc55f2015-04-27 21:37:03 +0000173 { "HM", LOG_FMT_HTTP_METHOD, PR_MODE_HTTP, LW_REQ, NULL }, /* HTTP method */
174 { "HP", LOG_FMT_HTTP_PATH, PR_MODE_HTTP, LW_REQ, NULL }, /* HTTP path */
Andrew Hayworthe63ac872015-07-31 16:14:16 +0000175 { "HQ", LOG_FMT_HTTP_QUERY, PR_MODE_HTTP, LW_REQ, NULL }, /* HTTP query */
Andrew Hayworth0ebc55f2015-04-27 21:37:03 +0000176 { "HU", LOG_FMT_HTTP_URI, PR_MODE_HTTP, LW_REQ, NULL }, /* HTTP full URI */
177 { "HV", LOG_FMT_HTTP_VERSION, PR_MODE_HTTP, LW_REQ, NULL }, /* HTTP version */
Willy Tarreau7346acb2014-08-28 15:03:15 +0200178 { "lc", LOG_FMT_LOGCNT, PR_MODE_TCP, LW_INIT, NULL }, /* log counter */
Willy Tarreau2beef582012-12-20 17:22:52 +0100179 { "ms", LOG_FMT_MS, PR_MODE_TCP, LW_INIT, NULL }, /* accept date millisecond */
William Lallemand5e19a282012-04-02 16:22:10 +0200180 { "pid", LOG_FMT_PID, PR_MODE_TCP, LW_INIT, NULL }, /* log pid */
Willy Tarreau2beef582012-12-20 17:22:52 +0100181 { "r", LOG_FMT_REQ, PR_MODE_HTTP, LW_REQ, NULL }, /* request */
182 { "rc", LOG_FMT_RETRIES, PR_MODE_TCP, LW_BYTES, NULL }, /* retries */
Willy Tarreau1f0da242014-01-25 11:01:50 +0100183 { "rt", LOG_FMT_COUNTER, PR_MODE_TCP, LW_REQ, NULL }, /* request counter (HTTP or TCP session) */
Willy Tarreau2beef582012-12-20 17:22:52 +0100184 { "s", LOG_FMT_SERVER, PR_MODE_TCP, LW_SVID, NULL }, /* server */
185 { "sc", LOG_FMT_SRVCONN, PR_MODE_TCP, LW_BYTES, NULL }, /* srv_conn */
186 { "si", LOG_FMT_SERVERIP, PR_MODE_TCP, LW_SVIP, NULL }, /* server destination ip */
187 { "sp", LOG_FMT_SERVERPORT, PR_MODE_TCP, LW_SVIP, NULL }, /* server destination port */
188 { "sq", LOG_FMT_SRVQUEUE, PR_MODE_TCP, LW_BYTES, NULL }, /* srv_queue */
Willy Tarreauffc3fcd2012-10-12 20:17:54 +0200189 { "sslc", LOG_FMT_SSL_CIPHER, PR_MODE_TCP, LW_XPRT, NULL }, /* client-side SSL ciphers */
190 { "sslv", LOG_FMT_SSL_VERSION, PR_MODE_TCP, LW_XPRT, NULL }, /* client-side SSL protocol version */
Willy Tarreau2beef582012-12-20 17:22:52 +0100191 { "t", LOG_FMT_DATE, PR_MODE_TCP, LW_INIT, NULL }, /* date */
Thierry FOURNIER / OZON.IO4cac3592016-07-28 17:19:45 +0200192 { "tr", LOG_FMT_tr, PR_MODE_HTTP, LW_INIT, NULL }, /* date of start of request */
193 { "trg",LOG_FMT_trg, PR_MODE_HTTP, LW_INIT, NULL }, /* date of start of request, GMT */
194 { "trl",LOG_FMT_trl, PR_MODE_HTTP, LW_INIT, NULL }, /* date of start of request, local */
Willy Tarreau2beef582012-12-20 17:22:52 +0100195 { "ts", LOG_FMT_TERMSTATE, PR_MODE_TCP, LW_BYTES, NULL },/* termination state */
196 { "tsc", LOG_FMT_TERMSTATE_CK, PR_MODE_TCP, LW_INIT, NULL },/* termination state */
197
198 /* The following tags are deprecated and will be removed soon */
199 { "Bi", LOG_FMT_BACKENDIP, PR_MODE_TCP, LW_BCKIP, prepare_addrsource, "bi" }, /* backend source ip */
200 { "Bp", LOG_FMT_BACKENDPORT, PR_MODE_TCP, LW_BCKIP, prepare_addrsource, "bp" }, /* backend source port */
Willy Tarreaud02286d2017-06-23 11:23:43 +0200201 { "Ci", LOG_FMT_CLIENTIP, PR_MODE_TCP, LW_CLIP | LW_XPRT, NULL, "ci" }, /* client ip */
202 { "Cp", LOG_FMT_CLIENTPORT, PR_MODE_TCP, LW_CLIP | LW_XPRT, NULL, "cp" }, /* client port */
203 { "Fi", LOG_FMT_FRONTENDIP, PR_MODE_TCP, LW_FRTIP | LW_XPRT, NULL, "fi" }, /* frontend ip */
204 { "Fp", LOG_FMT_FRONTENDPORT, PR_MODE_TCP, LW_FRTIP | LW_XPRT, NULL, "fp" }, /* frontend port */
Willy Tarreau2beef582012-12-20 17:22:52 +0100205 { "Si", LOG_FMT_SERVERIP, PR_MODE_TCP, LW_SVIP, NULL, "si" }, /* server destination ip */
206 { "Sp", LOG_FMT_SERVERPORT, PR_MODE_TCP, LW_SVIP, NULL, "sp" }, /* server destination port */
207 { "cc", LOG_FMT_CCLIENT, PR_MODE_HTTP, LW_REQHDR, NULL, "CC" }, /* client cookie */
208 { "cs", LOG_FMT_CSERVER, PR_MODE_HTTP, LW_RSPHDR, NULL, "CS" }, /* server cookie */
209 { "st", LOG_FMT_STATUS, PR_MODE_HTTP, LW_RESP, NULL, "ST" }, /* status code */
William Lallemand5e19a282012-04-02 16:22:10 +0200210 { 0, 0, 0, 0, NULL }
William Lallemand723b73a2012-02-08 16:37:49 +0100211};
212
Thierry FOURNIER / OZON.IO4cac3592016-07-28 17:19:45 +0200213char default_http_log_format[] = "%ci:%cp [%tr] %ft %b/%s %TR/%Tw/%Tc/%Tr/%Ta %ST %B %CC %CS %tsc %ac/%fc/%bc/%sc/%rc %sq/%bq %hr %hs %{+Q}r"; // default format
214char clf_http_log_format[] = "%{+Q}o %{-Q}ci - - [%trg] %r %ST %B \"\" \"\" %cp %ms %ft %b %s %TR %Tw %Tc %Tr %Ta %tsc %ac %fc %bc %sc %rc %sq %bq %CC %CS %hrl %hsl";
Willy Tarreau2beef582012-12-20 17:22:52 +0100215char default_tcp_log_format[] = "%ci:%cp [%t] %ft %b/%s %Tw/%Tc/%Tt %B %ts %ac/%fc/%bc/%sc/%rc %sq/%bq";
William Lallemand723b73a2012-02-08 16:37:49 +0100216char *log_format = NULL;
217
Dragan Dosen0b85ece2015-09-25 19:17:44 +0200218/* Default string used for structured-data part in RFC5424 formatted
219 * syslog messages.
220 */
221char default_rfc5424_sd_log_format[] = "- ";
Dragan Dosen1322d092015-09-22 16:05:32 +0200222
Willy Tarreau13ef7732018-11-12 07:25:28 +0100223/* total number of dropped logs */
224unsigned int dropped_logs = 0;
225
Dragan Dosen1322d092015-09-22 16:05:32 +0200226/* This is a global syslog header, common to all outgoing messages in
227 * RFC3164 format. It begins with time-based part and is updated by
228 * update_log_hdr().
Dragan Dosen59cee972015-09-19 22:09:02 +0200229 */
Christopher Fauletf8188c62017-06-02 16:20:16 +0200230THREAD_LOCAL char *logheader = NULL;
Willy Tarreau55e2f5a2019-05-05 10:11:39 +0200231THREAD_LOCAL char *logheader_end = NULL;
Dragan Dosen59cee972015-09-19 22:09:02 +0200232
Dragan Dosen1322d092015-09-22 16:05:32 +0200233/* This is a global syslog header for messages in RFC5424 format. It is
234 * updated by update_log_hdr_rfc5424().
235 */
Christopher Fauletf8188c62017-06-02 16:20:16 +0200236THREAD_LOCAL char *logheader_rfc5424 = NULL;
Willy Tarreau55e2f5a2019-05-05 10:11:39 +0200237THREAD_LOCAL char *logheader_rfc5424_end = NULL;
Dragan Dosen1322d092015-09-22 16:05:32 +0200238
Dragan Dosen59cee972015-09-19 22:09:02 +0200239/* This is a global syslog message buffer, common to all outgoing
240 * messages. It contains only the data part.
Willy Tarreaub1a2faf2012-03-19 16:51:53 +0100241 */
Christopher Fauletf8188c62017-06-02 16:20:16 +0200242THREAD_LOCAL char *logline = NULL;
Willy Tarreaub1a2faf2012-03-19 16:51:53 +0100243
Dragan Dosen0b85ece2015-09-25 19:17:44 +0200244/* A global syslog message buffer, common to all RFC5424 syslog messages.
245 * Currently, it is used for generating the structured-data part.
246 */
Christopher Fauletf8188c62017-06-02 16:20:16 +0200247THREAD_LOCAL char *logline_rfc5424 = NULL;
Dragan Dosen0b85ece2015-09-25 19:17:44 +0200248
Christopher Fauletd4696382017-10-24 11:44:05 +0200249/* A global buffer used to store all startup alerts/warnings. It will then be
250 * retrieve on the CLI. */
Willy Tarreau869efd52019-11-15 15:16:57 +0100251static struct ring *startup_logs = NULL;
Christopher Fauletd4696382017-10-24 11:44:05 +0200252
William Lallemand723b73a2012-02-08 16:37:49 +0100253struct logformat_var_args {
254 char *name;
255 int mask;
256};
257
258struct logformat_var_args var_args_list[] = {
259// global
260 { "M", LOG_OPT_MANDATORY },
261 { "Q", LOG_OPT_QUOTE },
William Lallemand5f232402012-04-05 18:02:55 +0200262 { "X", LOG_OPT_HEXA },
Dragan Dosen835b9212016-02-12 13:23:03 +0100263 { "E", LOG_OPT_ESC },
William Lallemand723b73a2012-02-08 16:37:49 +0100264 { 0, 0 }
265};
266
Willy Tarreaub1f3af22013-04-12 18:30:32 +0200267/* return the name of the directive used in the current proxy for which we're
268 * currently parsing a header, when it is known.
269 */
270static inline const char *fmt_directive(const struct proxy *curproxy)
271{
Willy Tarreaubf0addb2013-12-02 12:24:54 +0100272 switch (curproxy->conf.args.ctx) {
Willy Tarreau53e1a6d2015-07-09 11:20:00 +0200273 case ARGC_ACL:
274 return "acl";
275 case ARGC_STK:
276 return "stick";
277 case ARGC_TRK:
278 return "track-sc";
279 case ARGC_LOG:
280 return "log-format";
Dragan Dosen0b85ece2015-09-25 19:17:44 +0200281 case ARGC_LOGSD:
282 return "log-format-sd";
Willy Tarreaubf0addb2013-12-02 12:24:54 +0100283 case ARGC_HRQ:
Thierry FOURNIER1c0054f2013-11-20 15:09:52 +0100284 return "http-request";
Willy Tarreaubf0addb2013-12-02 12:24:54 +0100285 case ARGC_HRS:
Thierry FOURNIER1c0054f2013-11-20 15:09:52 +0100286 return "http-response";
Willy Tarreau53e1a6d2015-07-09 11:20:00 +0200287 case ARGC_UIF:
288 return "unique-id-format";
Thierry FOURNIERd18cd0f2013-11-29 12:15:45 +0100289 case ARGC_RDR:
Willy Tarreau53e1a6d2015-07-09 11:20:00 +0200290 return "redirect";
291 case ARGC_CAP:
292 return "capture";
Willy Tarreau28d976d2015-07-09 11:39:33 +0200293 case ARGC_SRV:
294 return "server";
Christopher Fauletf7e4e7e2016-10-27 22:29:49 +0200295 case ARGC_SPOE:
296 return "spoe-message";
Thierry FOURNIER / OZON.IO4ed1c952016-11-24 23:57:54 +0100297 case ARGC_UBK:
298 return "use_backend";
Willy Tarreaubf0addb2013-12-02 12:24:54 +0100299 default:
Willy Tarreau53e1a6d2015-07-09 11:20:00 +0200300 return "undefined(please report this bug)"; /* must never happen */
Willy Tarreaubf0addb2013-12-02 12:24:54 +0100301 }
Willy Tarreaub1f3af22013-04-12 18:30:32 +0200302}
303
William Lallemand723b73a2012-02-08 16:37:49 +0100304/*
William Lallemandb7ff6a32012-03-02 14:35:21 +0100305 * callback used to configure addr source retrieval
306 */
307int prepare_addrsource(struct logformat_node *node, struct proxy *curproxy)
308{
309 curproxy->options2 |= PR_O2_SRC_ADDR;
310
311 return 0;
312}
313
314
315/*
Thierry FOURNIER / OZON.IObca46f02016-11-22 23:13:04 +0100316 * Parse args in a logformat_var. Returns 0 in error
317 * case, otherwise, it returns 1.
William Lallemand723b73a2012-02-08 16:37:49 +0100318 */
Thierry FOURNIER / OZON.IO8a4e4422016-11-23 00:41:28 +0100319int parse_logformat_var_args(char *args, struct logformat_node *node, char **err)
William Lallemand723b73a2012-02-08 16:37:49 +0100320{
321 int i = 0;
322 int end = 0;
323 int flags = 0; // 1 = + 2 = -
324 char *sp = NULL; // start pointer
325
Thierry FOURNIER / OZON.IO8a4e4422016-11-23 00:41:28 +0100326 if (args == NULL) {
327 memprintf(err, "internal error: parse_logformat_var_args() expects non null 'args'");
Thierry FOURNIER / OZON.IObca46f02016-11-22 23:13:04 +0100328 return 0;
Thierry FOURNIER / OZON.IO8a4e4422016-11-23 00:41:28 +0100329 }
William Lallemand723b73a2012-02-08 16:37:49 +0100330
331 while (1) {
332 if (*args == '\0')
333 end = 1;
334
335 if (*args == '+') {
336 // add flag
337 sp = args + 1;
338 flags = 1;
339 }
340 if (*args == '-') {
341 // delete flag
342 sp = args + 1;
343 flags = 2;
344 }
345
346 if (*args == '\0' || *args == ',') {
347 *args = '\0';
Willy Tarreau254d44c2012-12-20 18:19:26 +0100348 for (i = 0; sp && var_args_list[i].name; i++) {
William Lallemand723b73a2012-02-08 16:37:49 +0100349 if (strcmp(sp, var_args_list[i].name) == 0) {
350 if (flags == 1) {
351 node->options |= var_args_list[i].mask;
352 break;
353 } else if (flags == 2) {
354 node->options &= ~var_args_list[i].mask;
355 break;
356 }
357 }
358 }
359 sp = NULL;
360 if (end)
361 break;
362 }
Willy Tarreau254d44c2012-12-20 18:19:26 +0100363 args++;
William Lallemand723b73a2012-02-08 16:37:49 +0100364 }
Thierry FOURNIER / OZON.IObca46f02016-11-22 23:13:04 +0100365 return 1;
William Lallemand723b73a2012-02-08 16:37:49 +0100366}
367
368/*
Willy Tarreau8a3f52f2012-12-20 21:23:42 +0100369 * Parse a variable '%varname' or '%{args}varname' in log-format. The caller
370 * must pass the args part in the <arg> pointer with its length in <arg_len>,
371 * and varname with its length in <var> and <var_len> respectively. <arg> is
372 * ignored when arg_len is 0. Neither <var> nor <var_len> may be null.
Thierry FOURNIER / OZON.IOeca4d952016-11-22 22:06:04 +0100373 * Returns false in error case and err is filled, otherwise returns true.
William Lallemand723b73a2012-02-08 16:37:49 +0100374 */
Thierry FOURNIER / OZON.IO8a4e4422016-11-23 00:41:28 +0100375int parse_logformat_var(char *arg, int arg_len, char *var, int var_len, struct proxy *curproxy, struct list *list_format, int *defoptions, char **err)
William Lallemand723b73a2012-02-08 16:37:49 +0100376{
Willy Tarreau8a3f52f2012-12-20 21:23:42 +0100377 int j;
Dragan Dosen61302da2019-04-30 00:40:02 +0200378 struct logformat_node *node = NULL;
William Lallemand723b73a2012-02-08 16:37:49 +0100379
Willy Tarreau8a3f52f2012-12-20 21:23:42 +0100380 for (j = 0; logformat_keywords[j].name; j++) { // search a log type
381 if (strlen(logformat_keywords[j].name) == var_len &&
382 strncmp(var, logformat_keywords[j].name, var_len) == 0) {
383 if (logformat_keywords[j].mode != PR_MODE_HTTP || curproxy->mode == PR_MODE_HTTP) {
Vincent Bernat02779b62016-04-03 13:48:43 +0200384 node = calloc(1, sizeof(*node));
Thierry FOURNIER / OZON.IO9cbfef22016-11-22 23:24:10 +0100385 if (!node) {
Thierry FOURNIER / OZON.IO8a4e4422016-11-23 00:41:28 +0100386 memprintf(err, "out of memory error");
Dragan Dosen61302da2019-04-30 00:40:02 +0200387 goto error_free;
Thierry FOURNIER / OZON.IO9cbfef22016-11-22 23:24:10 +0100388 }
Willy Tarreau8a3f52f2012-12-20 21:23:42 +0100389 node->type = logformat_keywords[j].type;
390 node->options = *defoptions;
391 if (arg_len) {
392 node->arg = my_strndup(arg, arg_len);
Thierry FOURNIER / OZON.IO8a4e4422016-11-23 00:41:28 +0100393 if (!parse_logformat_var_args(node->arg, node, err))
Dragan Dosen61302da2019-04-30 00:40:02 +0200394 goto error_free;
Willy Tarreau8a3f52f2012-12-20 21:23:42 +0100395 }
396 if (node->type == LOG_FMT_GLOBAL) {
397 *defoptions = node->options;
398 free(node->arg);
399 free(node);
400 } else {
401 if (logformat_keywords[j].config_callback &&
402 logformat_keywords[j].config_callback(node, curproxy) != 0) {
Dragan Dosen61302da2019-04-30 00:40:02 +0200403 goto error_free;
William Lallemand723b73a2012-02-08 16:37:49 +0100404 }
Willy Tarreau8a3f52f2012-12-20 21:23:42 +0100405 curproxy->to_log |= logformat_keywords[j].lw;
406 LIST_ADDQ(list_format, &node->list);
William Lallemand723b73a2012-02-08 16:37:49 +0100407 }
Willy Tarreau8a3f52f2012-12-20 21:23:42 +0100408 if (logformat_keywords[j].replace_by)
Christopher Faulet767a84b2017-11-24 16:50:31 +0100409 ha_warning("parsing [%s:%d] : deprecated variable '%s' in '%s', please replace it with '%s'.\n",
410 curproxy->conf.args.file, curproxy->conf.args.line,
411 logformat_keywords[j].name, fmt_directive(curproxy), logformat_keywords[j].replace_by);
Thierry FOURNIER / OZON.IOeca4d952016-11-22 22:06:04 +0100412 return 1;
Willy Tarreau8a3f52f2012-12-20 21:23:42 +0100413 } else {
Thierry FOURNIER / OZON.IO8a4e4422016-11-23 00:41:28 +0100414 memprintf(err, "format variable '%s' is reserved for HTTP mode",
415 logformat_keywords[j].name);
Dragan Dosen61302da2019-04-30 00:40:02 +0200416 goto error_free;
William Lallemand723b73a2012-02-08 16:37:49 +0100417 }
William Lallemand723b73a2012-02-08 16:37:49 +0100418 }
419 }
Willy Tarreau8a3f52f2012-12-20 21:23:42 +0100420
421 j = var[var_len];
422 var[var_len] = 0;
Thierry FOURNIER / OZON.IO8a4e4422016-11-23 00:41:28 +0100423 memprintf(err, "no such format variable '%s'. If you wanted to emit the '%%' character verbatim, you need to use '%%%%'", var);
Willy Tarreau8a3f52f2012-12-20 21:23:42 +0100424 var[var_len] = j;
Dragan Dosen61302da2019-04-30 00:40:02 +0200425
426 error_free:
427 if (node) {
428 free(node->arg);
429 free(node);
430 }
Thierry FOURNIER / OZON.IOeca4d952016-11-22 22:06:04 +0100431 return 0;
William Lallemand723b73a2012-02-08 16:37:49 +0100432}
433
434/*
435 * push to the logformat linked list
436 *
437 * start: start pointer
438 * end: end text pointer
439 * type: string type
William Lallemand1d705562012-03-12 12:46:41 +0100440 * list_format: destination list
William Lallemand723b73a2012-02-08 16:37:49 +0100441 *
442 * LOG_TEXT: copy chars from start to end excluding end.
443 *
444*/
Thierry FOURNIER / OZON.IO8a4e4422016-11-23 00:41:28 +0100445int add_to_logformat_list(char *start, char *end, int type, struct list *list_format, char **err)
William Lallemand723b73a2012-02-08 16:37:49 +0100446{
447 char *str;
448
Willy Tarreaua3571662012-12-20 21:59:12 +0100449 if (type == LF_TEXT) { /* type text */
Vincent Bernat02779b62016-04-03 13:48:43 +0200450 struct logformat_node *node = calloc(1, sizeof(*node));
Thierry FOURNIER / OZON.IO9cbfef22016-11-22 23:24:10 +0100451 if (!node) {
Thierry FOURNIER / OZON.IO8a4e4422016-11-23 00:41:28 +0100452 memprintf(err, "out of memory error");
Thierry FOURNIER / OZON.IO9cbfef22016-11-22 23:24:10 +0100453 return 0;
454 }
Vincent Bernat02779b62016-04-03 13:48:43 +0200455 str = calloc(1, end - start + 1);
William Lallemand723b73a2012-02-08 16:37:49 +0100456 strncpy(str, start, end - start);
William Lallemand723b73a2012-02-08 16:37:49 +0100457 str[end - start] = '\0';
458 node->arg = str;
William Lallemand1d705562012-03-12 12:46:41 +0100459 node->type = LOG_FMT_TEXT; // type string
460 LIST_ADDQ(list_format, &node->list);
Willy Tarreaua3571662012-12-20 21:59:12 +0100461 } else if (type == LF_SEPARATOR) {
Vincent Bernat02779b62016-04-03 13:48:43 +0200462 struct logformat_node *node = calloc(1, sizeof(*node));
Thierry FOURNIER / OZON.IO9cbfef22016-11-22 23:24:10 +0100463 if (!node) {
Thierry FOURNIER / OZON.IO8a4e4422016-11-23 00:41:28 +0100464 memprintf(err, "out of memory error");
Thierry FOURNIER / OZON.IO9cbfef22016-11-22 23:24:10 +0100465 return 0;
466 }
William Lallemand1d705562012-03-12 12:46:41 +0100467 node->type = LOG_FMT_SEPARATOR;
468 LIST_ADDQ(list_format, &node->list);
William Lallemand723b73a2012-02-08 16:37:49 +0100469 }
Thierry FOURNIER / OZON.IOa2c38d72016-11-22 23:11:21 +0100470 return 1;
William Lallemand723b73a2012-02-08 16:37:49 +0100471}
472
473/*
Willy Tarreauc8368452012-12-21 00:09:23 +0100474 * Parse the sample fetch expression <text> and add a node to <list_format> upon
475 * success. At the moment, sample converters are not yet supported but fetch arguments
Willy Tarreaua4312fa2013-04-02 16:34:32 +0200476 * should work. The curpx->conf.args.ctx must be set by the caller.
Thierry FOURNIER / OZON.IOa2c38d72016-11-22 23:11:21 +0100477 *
478 * In error case, the function returns 0, otherwise it returns 1.
Willy Tarreauc8368452012-12-21 00:09:23 +0100479 */
Thierry FOURNIER / OZON.IO8a4e4422016-11-23 00:41:28 +0100480int add_sample_to_logformat_list(char *text, char *arg, int arg_len, struct proxy *curpx, struct list *list_format, int options, int cap, char **err)
Willy Tarreauc8368452012-12-21 00:09:23 +0100481{
482 char *cmd[2];
Dragan Dosen61302da2019-04-30 00:40:02 +0200483 struct sample_expr *expr = NULL;
484 struct logformat_node *node = NULL;
Willy Tarreauc8368452012-12-21 00:09:23 +0100485 int cmd_arg;
486
487 cmd[0] = text;
488 cmd[1] = "";
489 cmd_arg = 0;
490
Thierry FOURNIER / OZON.IO8a4e4422016-11-23 00:41:28 +0100491 expr = sample_parse_expr(cmd, &cmd_arg, curpx->conf.args.file, curpx->conf.args.line, err, &curpx->conf.args);
Willy Tarreauc8368452012-12-21 00:09:23 +0100492 if (!expr) {
Thierry FOURNIER / OZON.IO8a4e4422016-11-23 00:41:28 +0100493 memprintf(err, "failed to parse sample expression <%s> : %s", text, *err);
Dragan Dosen61302da2019-04-30 00:40:02 +0200494 goto error_free;
Willy Tarreauc8368452012-12-21 00:09:23 +0100495 }
496
Vincent Bernat02779b62016-04-03 13:48:43 +0200497 node = calloc(1, sizeof(*node));
Thierry FOURNIER / OZON.IO9cbfef22016-11-22 23:24:10 +0100498 if (!node) {
Thierry FOURNIER / OZON.IO8a4e4422016-11-23 00:41:28 +0100499 memprintf(err, "out of memory error");
Dragan Dosen61302da2019-04-30 00:40:02 +0200500 goto error_free;
Thierry FOURNIER / OZON.IO9cbfef22016-11-22 23:24:10 +0100501 }
Willy Tarreauc8368452012-12-21 00:09:23 +0100502 node->type = LOG_FMT_EXPR;
503 node->expr = expr;
504 node->options = options;
505
506 if (arg_len) {
507 node->arg = my_strndup(arg, arg_len);
Thierry FOURNIER / OZON.IO8a4e4422016-11-23 00:41:28 +0100508 if (!parse_logformat_var_args(node->arg, node, err))
Dragan Dosen61302da2019-04-30 00:40:02 +0200509 goto error_free;
Willy Tarreauc8368452012-12-21 00:09:23 +0100510 }
Willy Tarreau434c57c2013-01-08 01:10:24 +0100511 if (expr->fetch->val & cap & SMP_VAL_REQUEST)
Willy Tarreauc8368452012-12-21 00:09:23 +0100512 node->options |= LOG_OPT_REQ_CAP; /* fetch method is request-compatible */
513
Willy Tarreau434c57c2013-01-08 01:10:24 +0100514 if (expr->fetch->val & cap & SMP_VAL_RESPONSE)
Willy Tarreauc8368452012-12-21 00:09:23 +0100515 node->options |= LOG_OPT_RES_CAP; /* fetch method is response-compatible */
516
Thierry FOURNIER / OZON.IOa2c38d72016-11-22 23:11:21 +0100517 if (!(expr->fetch->val & cap)) {
Thierry FOURNIER / OZON.IO8a4e4422016-11-23 00:41:28 +0100518 memprintf(err, "sample fetch <%s> may not be reliably used here because it needs '%s' which is not available here",
519 text, sample_src_names(expr->fetch->use));
Dragan Dosen61302da2019-04-30 00:40:02 +0200520 goto error_free;
Thierry FOURNIER / OZON.IOa2c38d72016-11-22 23:11:21 +0100521 }
Willy Tarreau434c57c2013-01-08 01:10:24 +0100522
Christopher Faulet711ed6a2019-07-16 14:16:10 +0200523 /* check if we need to allocate an http_txn struct for HTTP parsing */
Willy Tarreauc8368452012-12-21 00:09:23 +0100524 /* Note, we may also need to set curpx->to_log with certain fetches */
Willy Tarreau25320b22013-03-24 07:22:08 +0100525 curpx->http_needed |= !!(expr->fetch->use & SMP_USE_HTTP_ANY);
Willy Tarreauc8368452012-12-21 00:09:23 +0100526
William Lallemand65ad6e12014-01-31 15:08:02 +0100527 /* FIXME: temporary workaround for missing LW_XPRT and LW_REQ flags
528 * needed with some sample fetches (eg: ssl*). We always set it for
529 * now on, but this will leave with sample capabilities soon.
Willy Tarreau1f31c732013-01-10 16:22:27 +0100530 */
531 curpx->to_log |= LW_XPRT;
William Lallemand65ad6e12014-01-31 15:08:02 +0100532 curpx->to_log |= LW_REQ;
Willy Tarreauc8368452012-12-21 00:09:23 +0100533 LIST_ADDQ(list_format, &node->list);
Thierry FOURNIER / OZON.IOa2c38d72016-11-22 23:11:21 +0100534 return 1;
Dragan Dosen61302da2019-04-30 00:40:02 +0200535
536 error_free:
537 release_sample_expr(expr);
538 if (node) {
539 free(node->arg);
540 free(node);
541 }
542 return 0;
Willy Tarreauc8368452012-12-21 00:09:23 +0100543}
544
545/*
William Lallemand723b73a2012-02-08 16:37:49 +0100546 * Parse the log_format string and fill a linked list.
547 * Variable name are preceded by % and composed by characters [a-zA-Z0-9]* : %varname
Willy Tarreaua4312fa2013-04-02 16:34:32 +0200548 * You can set arguments using { } : %{many arguments}varname.
549 * The curproxy->conf.args.ctx must be set by the caller.
William Lallemand1d705562012-03-12 12:46:41 +0100550 *
551 * str: the string to parse
552 * curproxy: the proxy affected
553 * list_format: the destination list
Willy Tarreau6cbbdbf2013-02-05 18:52:25 +0100554 * options: LOG_OPT_* to force on every node
Willy Tarreau434c57c2013-01-08 01:10:24 +0100555 * cap: all SMP_VAL_* flags supported by the consumer
Thierry FOURNIER / OZON.IOa2c38d72016-11-22 23:11:21 +0100556 *
Thierry FOURNIER / OZON.IO8a4e4422016-11-23 00:41:28 +0100557 * The function returns 1 in success case, otherwise, it returns 0 and err is filled.
William Lallemand723b73a2012-02-08 16:37:49 +0100558 */
Thierry FOURNIER / OZON.IO8a4e4422016-11-23 00:41:28 +0100559int parse_logformat_string(const char *fmt, struct proxy *curproxy, struct list *list_format, int options, int cap, char **err)
William Lallemand723b73a2012-02-08 16:37:49 +0100560{
Willy Tarreaub83bc1e2012-12-24 12:36:33 +0100561 char *sp, *str, *backfmt; /* start pointer for text parts */
Willy Tarreau8a3f52f2012-12-20 21:23:42 +0100562 char *arg = NULL; /* start pointer for args */
563 char *var = NULL; /* start pointer for vars */
564 int arg_len = 0;
565 int var_len = 0;
566 int cformat; /* current token format */
567 int pformat; /* previous token format */
William Lallemand723b73a2012-02-08 16:37:49 +0100568 struct logformat_node *tmplf, *back;
569
Willy Tarreaub83bc1e2012-12-24 12:36:33 +0100570 sp = str = backfmt = strdup(fmt);
Thierry FOURNIER / OZON.IO9cbfef22016-11-22 23:24:10 +0100571 if (!str) {
Thierry FOURNIER / OZON.IO8a4e4422016-11-23 00:41:28 +0100572 memprintf(err, "out of memory error");
Thierry FOURNIER / OZON.IO9cbfef22016-11-22 23:24:10 +0100573 return 0;
574 }
William Lallemand1dc00ef2012-08-09 16:41:35 +0200575 curproxy->to_log |= LW_INIT;
William Lallemand5e19a282012-04-02 16:22:10 +0200576
William Lallemand723b73a2012-02-08 16:37:49 +0100577 /* flush the list first. */
William Lallemand1d705562012-03-12 12:46:41 +0100578 list_for_each_entry_safe(tmplf, back, list_format, list) {
William Lallemand723b73a2012-02-08 16:37:49 +0100579 LIST_DEL(&tmplf->list);
Dragan Dosen61302da2019-04-30 00:40:02 +0200580 release_sample_expr(tmplf->expr);
581 free(tmplf->arg);
William Lallemand723b73a2012-02-08 16:37:49 +0100582 free(tmplf);
583 }
584
Willy Tarreau8a3f52f2012-12-20 21:23:42 +0100585 for (cformat = LF_INIT; cformat != LF_END; str++) {
William Lallemand723b73a2012-02-08 16:37:49 +0100586 pformat = cformat;
587
Willy Tarreau8a3f52f2012-12-20 21:23:42 +0100588 if (!*str)
589 cformat = LF_END; // preset it to save all states from doing this
William Lallemand723b73a2012-02-08 16:37:49 +0100590
Joseph Herlant85b40592018-11-15 12:10:04 -0800591 /* The principle of the two-step state machine below is to first detect a change, and
Willy Tarreau8a3f52f2012-12-20 21:23:42 +0100592 * second have all common paths processed at one place. The common paths are the ones
593 * encountered in text areas (LF_INIT, LF_TEXT, LF_SEPARATOR) and at the end (LF_END).
594 * We use the common LF_INIT state to dispatch to the different final states.
595 */
596 switch (pformat) {
597 case LF_STARTVAR: // text immediately following a '%'
Willy Tarreauc8368452012-12-21 00:09:23 +0100598 arg = NULL; var = NULL;
Willy Tarreau8a3f52f2012-12-20 21:23:42 +0100599 arg_len = var_len = 0;
600 if (*str == '{') { // optional argument
601 cformat = LF_STARG;
602 arg = str + 1;
William Lallemand723b73a2012-02-08 16:37:49 +0100603 }
Willy Tarreauc8368452012-12-21 00:09:23 +0100604 else if (*str == '[') {
605 cformat = LF_STEXPR;
606 var = str + 1; // store expr in variable name
607 }
Willy Tarreau0f28f822013-12-16 01:38:33 +0100608 else if (isalpha((unsigned char)*str)) { // variable name
William Lallemand723b73a2012-02-08 16:37:49 +0100609 cformat = LF_VAR;
Willy Tarreau8a3f52f2012-12-20 21:23:42 +0100610 var = str;
William Lallemand723b73a2012-02-08 16:37:49 +0100611 }
Willy Tarreau8a3f52f2012-12-20 21:23:42 +0100612 else if (*str == '%')
613 cformat = LF_TEXT; // convert this character to a litteral (useful for '%')
Willy Tarreau0f28f822013-12-16 01:38:33 +0100614 else if (isdigit((unsigned char)*str) || *str == ' ' || *str == '\t') {
Willy Tarreau06d97f92013-12-02 17:45:48 +0100615 /* single '%' followed by blank or digit, send them both */
616 cformat = LF_TEXT;
617 pformat = LF_TEXT; /* finally we include the previous char as well */
618 sp = str - 1; /* send both the '%' and the current char */
Jim Freemana2278c82017-04-15 08:01:59 -0600619 memprintf(err, "unexpected variable name near '%c' at position %d line : '%s'. Maybe you want to write a single '%%', use the syntax '%%%%'",
Thierry FOURNIER / OZON.IO8a4e4422016-11-23 00:41:28 +0100620 *str, (int)(str - backfmt), fmt);
Willy Tarreau51013e82019-12-11 12:05:39 +0100621 goto fail;
Willy Tarreau06d97f92013-12-02 17:45:48 +0100622
623 }
Willy Tarreau8a3f52f2012-12-20 21:23:42 +0100624 else
625 cformat = LF_INIT; // handle other cases of litterals
626 break;
627
628 case LF_STARG: // text immediately following '%{'
629 if (*str == '}') { // end of arg
William Lallemand723b73a2012-02-08 16:37:49 +0100630 cformat = LF_EDARG;
Willy Tarreau8a3f52f2012-12-20 21:23:42 +0100631 arg_len = str - arg;
632 *str = 0; // used for reporting errors
William Lallemand723b73a2012-02-08 16:37:49 +0100633 }
Willy Tarreau8a3f52f2012-12-20 21:23:42 +0100634 break;
635
636 case LF_EDARG: // text immediately following '%{arg}'
Willy Tarreauc8368452012-12-21 00:09:23 +0100637 if (*str == '[') {
638 cformat = LF_STEXPR;
639 var = str + 1; // store expr in variable name
640 break;
641 }
Willy Tarreau0f28f822013-12-16 01:38:33 +0100642 else if (isalnum((unsigned char)*str)) { // variable name
William Lallemand723b73a2012-02-08 16:37:49 +0100643 cformat = LF_VAR;
Willy Tarreau8a3f52f2012-12-20 21:23:42 +0100644 var = str;
645 break;
646 }
Thierry FOURNIER / OZON.IO8a4e4422016-11-23 00:41:28 +0100647 memprintf(err, "parse argument modifier without variable name near '%%{%s}'", arg);
Willy Tarreau51013e82019-12-11 12:05:39 +0100648 goto fail;
Willy Tarreau8a3f52f2012-12-20 21:23:42 +0100649
Willy Tarreauc8368452012-12-21 00:09:23 +0100650 case LF_STEXPR: // text immediately following '%['
651 if (*str == ']') { // end of arg
652 cformat = LF_EDEXPR;
653 var_len = str - var;
654 *str = 0; // needed for parsing the expression
655 }
656 break;
657
Willy Tarreau8a3f52f2012-12-20 21:23:42 +0100658 case LF_VAR: // text part of a variable name
659 var_len = str - var;
Willy Tarreau0f28f822013-12-16 01:38:33 +0100660 if (!isalnum((unsigned char)*str))
Willy Tarreau8a3f52f2012-12-20 21:23:42 +0100661 cformat = LF_INIT; // not variable name anymore
662 break;
663
Willy Tarreauc8368452012-12-21 00:09:23 +0100664 default: // LF_INIT, LF_TEXT, LF_SEPARATOR, LF_END, LF_EDEXPR
Willy Tarreau8a3f52f2012-12-20 21:23:42 +0100665 cformat = LF_INIT;
666 }
667
668 if (cformat == LF_INIT) { /* resynchronize state to text/sep/startvar */
669 switch (*str) {
670 case '%': cformat = LF_STARTVAR; break;
671 case ' ': cformat = LF_SEPARATOR; break;
672 case 0 : cformat = LF_END; break;
673 default : cformat = LF_TEXT; break;
William Lallemand723b73a2012-02-08 16:37:49 +0100674 }
675 }
676
Willy Tarreau8a3f52f2012-12-20 21:23:42 +0100677 if (cformat != pformat || pformat == LF_SEPARATOR) {
678 switch (pformat) {
679 case LF_VAR:
Thierry FOURNIER / OZON.IO8a4e4422016-11-23 00:41:28 +0100680 if (!parse_logformat_var(arg, arg_len, var, var_len, curproxy, list_format, &options, err))
Willy Tarreau51013e82019-12-11 12:05:39 +0100681 goto fail;
Willy Tarreau8a3f52f2012-12-20 21:23:42 +0100682 break;
Willy Tarreauc8368452012-12-21 00:09:23 +0100683 case LF_STEXPR:
Thierry FOURNIER / OZON.IO8a4e4422016-11-23 00:41:28 +0100684 if (!add_sample_to_logformat_list(var, arg, arg_len, curproxy, list_format, options, cap, err))
Willy Tarreau51013e82019-12-11 12:05:39 +0100685 goto fail;
Willy Tarreauc8368452012-12-21 00:09:23 +0100686 break;
Willy Tarreau8a3f52f2012-12-20 21:23:42 +0100687 case LF_TEXT:
688 case LF_SEPARATOR:
Thierry FOURNIER / OZON.IO8a4e4422016-11-23 00:41:28 +0100689 if (!add_to_logformat_list(sp, str, pformat, list_format, err))
Willy Tarreau51013e82019-12-11 12:05:39 +0100690 goto fail;
Willy Tarreau8a3f52f2012-12-20 21:23:42 +0100691 break;
692 }
693 sp = str; /* new start of text at every state switch and at every separator */
William Lallemand723b73a2012-02-08 16:37:49 +0100694 }
695 }
Willy Tarreau8a3f52f2012-12-20 21:23:42 +0100696
Thierry FOURNIER / OZON.IOa2c38d72016-11-22 23:11:21 +0100697 if (pformat == LF_STARTVAR || pformat == LF_STARG || pformat == LF_STEXPR) {
Thierry FOURNIER / OZON.IO8a4e4422016-11-23 00:41:28 +0100698 memprintf(err, "truncated line after '%s'", var ? var : arg ? arg : "%");
Willy Tarreau51013e82019-12-11 12:05:39 +0100699 goto fail;
Thierry FOURNIER / OZON.IOa2c38d72016-11-22 23:11:21 +0100700 }
Willy Tarreaub83bc1e2012-12-24 12:36:33 +0100701 free(backfmt);
Thierry FOURNIER / OZON.IOa2c38d72016-11-22 23:11:21 +0100702
703 return 1;
Willy Tarreau51013e82019-12-11 12:05:39 +0100704 fail:
705 free(backfmt);
706 return 0;
William Lallemand723b73a2012-02-08 16:37:49 +0100707}
708
Christopher Faulet4b0b79d2018-03-26 15:54:32 +0200709/*
Frédéric Lécailled95ea282019-04-24 16:14:33 +0200710 * Parse the first range of indexes from a string made of a list of comma seperated
711 * ranges of indexes. Note that an index may be considered as a particular range
712 * with a high limit to the low limit.
713 */
714int get_logsrv_smp_range(unsigned int *low, unsigned int *high, char **arg, char **err)
715{
716 char *end, *p;
717
718 *low = *high = 0;
719
720 p = *arg;
721 end = strchr(p, ',');
722 if (!end)
723 end = p + strlen(p);
724
725 *high = *low = read_uint((const char **)&p, end);
726 if (!*low || (p != end && *p != '-'))
727 goto err;
728
729 if (p == end)
730 goto done;
731
732 p++;
733 *high = read_uint((const char **)&p, end);
734 if (!*high || *high <= *low || p != end)
735 goto err;
736
737 done:
738 if (*end == ',')
739 end++;
740 *arg = end;
741 return 1;
742
743 err:
744 memprintf(err, "wrong sample range '%s'", *arg);
745 return 0;
746}
747
748/*
749 * Returns 1 if the range defined by <low> and <high> overlaps
750 * one of them in <rgs> array of ranges with <sz> the size of this
751 * array, 0 if not.
752 */
753int smp_log_ranges_overlap(struct smp_log_range *rgs, size_t sz,
754 unsigned int low, unsigned int high, char **err)
755{
756 size_t i;
757
758 for (i = 0; i < sz; i++) {
759 if ((low >= rgs[i].low && low <= rgs[i].high) ||
760 (high >= rgs[i].low && high <= rgs[i].high)) {
761 memprintf(err, "ranges are overlapping");
762 return 1;
763 }
764 }
765
766 return 0;
767}
768
769int smp_log_range_cmp(const void *a, const void *b)
770{
771 const struct smp_log_range *rg_a = a;
772 const struct smp_log_range *rg_b = b;
773
774 if (rg_a->high < rg_b->low)
775 return -1;
776 else if (rg_a->low > rg_b->high)
777 return 1;
778
779 return 0;
780}
781
782/*
Christopher Faulet4b0b79d2018-03-26 15:54:32 +0200783 * Parse "log" keyword and update <logsrvs> list accordingly.
784 *
785 * When <do_del> is set, it means the "no log" line was parsed, so all log
786 * servers in <logsrvs> are released.
787 *
788 * Otherwise, we try to parse the "log" line. First of all, when the list is not
789 * the global one, we look for the parameter "global". If we find it,
790 * global.logsrvs is copied. Else we parse each arguments.
791 *
792 * The function returns 1 in success case, otherwise, it returns 0 and err is
793 * filled.
794 */
795int parse_logsrv(char **args, struct list *logsrvs, int do_del, char **err)
796{
797 struct sockaddr_storage *sk;
798 struct logsrv *logsrv = NULL;
799 int port1, port2;
800 int cur_arg;
801
802 /*
803 * "no log": delete previous herited or defined syslog
804 * servers.
805 */
806 if (do_del) {
807 struct logsrv *back;
808
809 if (*(args[1]) != 0) {
810 memprintf(err, "'no log' does not expect arguments");
811 goto error;
812 }
813
814 list_for_each_entry_safe(logsrv, back, logsrvs, list) {
815 LIST_DEL(&logsrv->list);
816 free(logsrv);
817 }
818 return 1;
819 }
820
821 /*
822 * "log global": copy global.logrsvs linked list to the end of logsrvs
823 * list. But first, we check (logsrvs != global.logsrvs).
824 */
825 if (*(args[1]) && *(args[2]) == 0 && !strcmp(args[1], "global")) {
826 if (logsrvs == &global.logsrvs) {
827 memprintf(err, "'global' is not supported for a global syslog server");
828 goto error;
829 }
830 list_for_each_entry(logsrv, &global.logsrvs, list) {
Christopher Faulet28ac0992018-03-26 16:09:19 +0200831 struct logsrv *node;
832
833 list_for_each_entry(node, logsrvs, list) {
834 if (node->ref == logsrv)
835 goto skip_logsrv;
836 }
837
838 node = malloc(sizeof(*node));
Christopher Faulet4b0b79d2018-03-26 15:54:32 +0200839 memcpy(node, logsrv, sizeof(struct logsrv));
Christopher Faulet28ac0992018-03-26 16:09:19 +0200840 node->ref = logsrv;
Christopher Faulet4b0b79d2018-03-26 15:54:32 +0200841 LIST_INIT(&node->list);
842 LIST_ADDQ(logsrvs, &node->list);
Christopher Faulet28ac0992018-03-26 16:09:19 +0200843
844 skip_logsrv:
845 continue;
Christopher Faulet4b0b79d2018-03-26 15:54:32 +0200846 }
847 return 1;
848 }
849
850 /*
851 * "log <address> ...: parse a syslog server line
852 */
853 if (*(args[1]) == 0 || *(args[2]) == 0) {
854 memprintf(err, "expects <address> and <facility> %s as arguments",
855 ((logsrvs == &global.logsrvs) ? "" : "or global"));
856 goto error;
857 }
858
Willy Tarreau5a32ecc2018-11-12 07:34:59 +0100859 /* take care of "stdout" and "stderr" as regular aliases for fd@1 / fd@2 */
860 if (strcmp(args[1], "stdout") == 0)
861 args[1] = "fd@1";
862 else if (strcmp(args[1], "stderr") == 0)
863 args[1] = "fd@2";
864
Christopher Faulet4b0b79d2018-03-26 15:54:32 +0200865 logsrv = calloc(1, sizeof(*logsrv));
866 if (!logsrv) {
867 memprintf(err, "out of memory");
868 goto error;
869 }
870
871 /* skip address for now, it will be parsed at the end */
872 cur_arg = 2;
873
874 /* just after the address, a length may be specified */
875 logsrv->maxlen = MAX_SYSLOG_LEN;
876 if (strcmp(args[cur_arg], "len") == 0) {
877 int len = atoi(args[cur_arg+1]);
878 if (len < 80 || len > 65535) {
879 memprintf(err, "invalid log length '%s', must be between 80 and 65535",
880 args[cur_arg+1]);
881 goto error;
882 }
883 logsrv->maxlen = len;
884 cur_arg += 2;
885 }
886 if (logsrv->maxlen > global.max_syslog_len)
887 global.max_syslog_len = logsrv->maxlen;
888
889 /* after the length, a format may be specified */
890 if (strcmp(args[cur_arg], "format") == 0) {
891 logsrv->format = get_log_format(args[cur_arg+1]);
892 if (logsrv->format < 0) {
893 memprintf(err, "unknown log format '%s'", args[cur_arg+1]);
894 goto error;
895 }
896 cur_arg += 2;
897 }
898
Frédéric Lécailled95ea282019-04-24 16:14:33 +0200899 if (strcmp(args[cur_arg], "sample") == 0) {
900 unsigned low, high;
901 char *p, *beg, *end, *smp_sz_str;
902 struct smp_log_range *smp_rgs = NULL;
903 size_t smp_rgs_sz = 0, smp_sz = 0, new_smp_sz;
904
905 p = args[cur_arg+1];
906 smp_sz_str = strchr(p, ':');
907 if (!smp_sz_str) {
908 memprintf(err, "Missing sample size");
909 goto error;
910 }
911
912 *smp_sz_str++ = '\0';
913
914 end = p + strlen(p);
915
916 while (p != end) {
917 if (!get_logsrv_smp_range(&low, &high, &p, err))
918 goto error;
919
920 if (smp_rgs && smp_log_ranges_overlap(smp_rgs, smp_rgs_sz, low, high, err))
921 goto error;
922
923 smp_rgs = my_realloc2(smp_rgs, (smp_rgs_sz + 1) * sizeof *smp_rgs);
924 if (!smp_rgs) {
925 memprintf(err, "out of memory error");
926 goto error;
927 }
928
929 smp_rgs[smp_rgs_sz].low = low;
930 smp_rgs[smp_rgs_sz].high = high;
931 smp_rgs[smp_rgs_sz].sz = high - low + 1;
932 smp_rgs[smp_rgs_sz].curr_idx = 0;
933 if (smp_rgs[smp_rgs_sz].high > smp_sz)
934 smp_sz = smp_rgs[smp_rgs_sz].high;
935 smp_rgs_sz++;
936 }
937
Tim Duesterhus21648002019-06-23 22:10:10 +0200938 if (smp_rgs == NULL) {
939 memprintf(err, "no sampling ranges given");
940 goto error;
941 }
942
Frédéric Lécailled95ea282019-04-24 16:14:33 +0200943 beg = smp_sz_str;
944 end = beg + strlen(beg);
945 new_smp_sz = read_uint((const char **)&beg, end);
946 if (!new_smp_sz || beg != end) {
947 memprintf(err, "wrong sample size '%s' for sample range '%s'",
948 smp_sz_str, args[cur_arg+1]);
949 goto error;
950 }
951
952 if (new_smp_sz < smp_sz) {
953 memprintf(err, "sample size %zu should be greater or equal to "
954 "%zu the maximum of the high ranges limits",
955 new_smp_sz, smp_sz);
956 goto error;
957 }
958 smp_sz = new_smp_sz;
959
960 /* Let's order <smp_rgs> array. */
961 qsort(smp_rgs, smp_rgs_sz, sizeof(struct smp_log_range), smp_log_range_cmp);
962
963 logsrv->lb.smp_rgs = smp_rgs;
964 logsrv->lb.smp_rgs_sz = smp_rgs_sz;
965 logsrv->lb.smp_sz = smp_sz;
966
967 cur_arg += 2;
968 }
Frédéric Lécailled803e472019-04-25 07:42:09 +0200969 HA_SPIN_INIT(&logsrv->lock);
Christopher Faulet4b0b79d2018-03-26 15:54:32 +0200970 /* parse the facility */
971 logsrv->facility = get_log_facility(args[cur_arg]);
972 if (logsrv->facility < 0) {
973 memprintf(err, "unknown log facility '%s'", args[cur_arg]);
974 goto error;
975 }
976 cur_arg++;
977
978 /* parse the max syslog level (default: debug) */
979 logsrv->level = 7;
980 if (*(args[cur_arg])) {
981 logsrv->level = get_log_level(args[cur_arg]);
982 if (logsrv->level < 0) {
983 memprintf(err, "unknown optional log level '%s'", args[cur_arg]);
984 goto error;
985 }
986 cur_arg++;
987 }
988
989 /* parse the limit syslog level (default: emerg) */
990 logsrv->minlvl = 0;
991 if (*(args[cur_arg])) {
992 logsrv->minlvl = get_log_level(args[cur_arg]);
993 if (logsrv->minlvl < 0) {
994 memprintf(err, "unknown optional minimum log level '%s'", args[cur_arg]);
995 goto error;
996 }
997 cur_arg++;
998 }
999
1000 /* Too many args */
1001 if (*(args[cur_arg])) {
1002 memprintf(err, "cannot handle unexpected argument '%s'", args[cur_arg]);
1003 goto error;
1004 }
1005
1006 /* now, back to the address */
Willy Tarreauf3dc30f2019-08-30 14:18:44 +02001007 logsrv->type = LOG_TARGET_DGRAM;
Willy Tarreauc046d162019-08-30 15:24:59 +02001008 if (strncmp(args[1], "ring@", 5) == 0) {
1009 struct sink *sink = sink_find(args[1] + 5);
1010
1011 if (!sink || sink->type != SINK_TYPE_BUFFER) {
1012 memprintf(err, "cannot find ring buffer '%s'", args[1] + 5);
1013 goto error;
1014 }
1015
1016 logsrv->addr.ss_family = AF_UNSPEC;
1017 logsrv->type = LOG_TARGET_BUFFER;
1018 logsrv->ring = sink->ctx.ring;
1019 goto done;
1020 }
1021
Willy Tarreauf3dc30f2019-08-30 14:18:44 +02001022 if (strncmp(args[1], "fd@", 3) == 0)
1023 logsrv->type = LOG_TARGET_FD;
1024
Christopher Faulet4b0b79d2018-03-26 15:54:32 +02001025 sk = str2sa_range(args[1], NULL, &port1, &port2, err, NULL, NULL, 1);
1026 if (!sk)
1027 goto error;
1028 logsrv->addr = *sk;
1029
1030 if (sk->ss_family == AF_INET || sk->ss_family == AF_INET6) {
1031 if (port1 != port2) {
1032 memprintf(err, "port ranges and offsets are not allowed in '%s'", args[1]);
1033 goto error;
1034 }
1035 logsrv->addr = *sk;
1036 if (!port1)
1037 set_host_port(&logsrv->addr, SYSLOG_PORT);
1038 }
Willy Tarreauc046d162019-08-30 15:24:59 +02001039 done:
Christopher Faulet4b0b79d2018-03-26 15:54:32 +02001040 LIST_ADDQ(logsrvs, &logsrv->list);
1041 return 1;
1042
1043 error:
1044 free(logsrv);
1045 return 0;
1046}
1047
1048
Christopher Fauletd4696382017-10-24 11:44:05 +02001049/* Generic function to display messages prefixed by a label */
1050static void print_message(const char *label, const char *fmt, va_list argp)
1051{
1052 struct tm tm;
1053 char *head, *msg;
1054
1055 head = msg = NULL;
1056
1057 get_localtime(date.tv_sec, &tm);
1058 memprintf(&head, "[%s] %03d/%02d%02d%02d (%d) : ",
1059 label, tm.tm_yday, tm.tm_hour, tm.tm_min, tm.tm_sec, (int)getpid());
1060 memvprintf(&msg, fmt, argp);
1061
Willy Tarreau869efd52019-11-15 15:16:57 +01001062 if (global.mode & MODE_STARTING) {
1063 if (unlikely(!startup_logs))
1064 startup_logs = ring_new(STARTUP_LOG_SIZE);
1065
1066 if (likely(startup_logs)) {
1067 struct ist m[2];
1068
1069 m[0] = ist(head);
1070 m[1] = ist(msg);
1071 /* trim the trailing '\n' */
1072 if (m[1].len > 0 && m[1].ptr[m[1].len - 1] == '\n')
1073 m[1].len--;
1074 ring_write(startup_logs, ~0, 0, 0, m, 2);
1075 }
1076 }
Christopher Fauletd4696382017-10-24 11:44:05 +02001077
1078 fprintf(stderr, "%s%s", head, msg);
1079 fflush(stderr);
1080
1081 free(head);
1082 free(msg);
1083}
1084
Willy Tarreaubaaee002006-06-26 02:48:02 +02001085/*
1086 * Displays the message on stderr with the date and pid. Overrides the quiet
1087 * mode during startup.
1088 */
Christopher Faulet767a84b2017-11-24 16:50:31 +01001089void ha_alert(const char *fmt, ...)
Willy Tarreaubaaee002006-06-26 02:48:02 +02001090{
1091 va_list argp;
Willy Tarreaubaaee002006-06-26 02:48:02 +02001092
1093 if (!(global.mode & MODE_QUIET) || (global.mode & (MODE_VERBOSE | MODE_STARTING))) {
1094 va_start(argp, fmt);
Christopher Fauletd4696382017-10-24 11:44:05 +02001095 print_message("ALERT", fmt, argp);
Willy Tarreaubaaee002006-06-26 02:48:02 +02001096 va_end(argp);
1097 }
1098}
1099
1100
1101/*
1102 * Displays the message on stderr with the date and pid.
1103 */
Christopher Faulet767a84b2017-11-24 16:50:31 +01001104void ha_warning(const char *fmt, ...)
Willy Tarreaubaaee002006-06-26 02:48:02 +02001105{
1106 va_list argp;
Willy Tarreaubaaee002006-06-26 02:48:02 +02001107
1108 if (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE)) {
1109 va_start(argp, fmt);
Christopher Fauletd4696382017-10-24 11:44:05 +02001110 print_message("WARNING", fmt, argp);
Willy Tarreaubaaee002006-06-26 02:48:02 +02001111 va_end(argp);
1112 }
1113}
1114
1115/*
William Lallemand9c56a222018-11-21 18:04:52 +01001116 * Displays the message on stderr with the date and pid.
1117 */
1118void ha_notice(const char *fmt, ...)
1119{
1120 va_list argp;
1121
1122 if (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE)) {
1123 va_start(argp, fmt);
1124 print_message("NOTICE", fmt, argp);
1125 va_end(argp);
1126 }
1127}
1128
1129/*
Willy Tarreaubaaee002006-06-26 02:48:02 +02001130 * Displays the message on <out> only if quiet mode is not set.
1131 */
Willy Tarreaub17916e2006-10-15 15:17:57 +02001132void qfprintf(FILE *out, const char *fmt, ...)
Willy Tarreaubaaee002006-06-26 02:48:02 +02001133{
1134 va_list argp;
1135
1136 if (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE)) {
1137 va_start(argp, fmt);
1138 vfprintf(out, fmt, argp);
1139 fflush(out);
1140 va_end(argp);
1141 }
1142}
1143
1144/*
Dragan Dosen1322d092015-09-22 16:05:32 +02001145 * returns log format for <fmt> or -1 if not found.
1146 */
1147int get_log_format(const char *fmt)
1148{
1149 int format;
1150
1151 format = LOG_FORMATS - 1;
Dragan Dosen43885c72015-10-01 13:18:13 +02001152 while (format >= 0 && strcmp(log_formats[format].name, fmt))
Dragan Dosen1322d092015-09-22 16:05:32 +02001153 format--;
1154
1155 return format;
1156}
1157
1158/*
Willy Tarreaubaaee002006-06-26 02:48:02 +02001159 * returns log level for <lev> or -1 if not found.
1160 */
1161int get_log_level(const char *lev)
1162{
1163 int level;
1164
1165 level = NB_LOG_LEVELS - 1;
1166 while (level >= 0 && strcmp(log_levels[level], lev))
1167 level--;
1168
1169 return level;
1170}
1171
Willy Tarreaubaaee002006-06-26 02:48:02 +02001172/*
1173 * returns log facility for <fac> or -1 if not found.
1174 */
1175int get_log_facility(const char *fac)
1176{
1177 int facility;
1178
1179 facility = NB_LOG_FACILITIES - 1;
1180 while (facility >= 0 && strcmp(log_facilities[facility], fac))
1181 facility--;
William Lallemand2a4a44f2012-02-06 16:00:33 +01001182
Willy Tarreaubaaee002006-06-26 02:48:02 +02001183 return facility;
1184}
1185
William Lallemanda1cc3812012-02-08 16:38:44 +01001186/*
Dragan Dosen835b9212016-02-12 13:23:03 +01001187 * Encode the string.
1188 *
1189 * When using the +E log format option, it will try to escape '"\]'
1190 * characters with '\' as prefix. The same prefix should not be used as
1191 * <escape>.
1192 */
1193static char *lf_encode_string(char *start, char *stop,
Willy Tarreau1bfd6022019-06-07 11:10:07 +02001194 const char escape, const long *map,
Dragan Dosen835b9212016-02-12 13:23:03 +01001195 const char *string,
1196 struct logformat_node *node)
1197{
1198 if (node->options & LOG_OPT_ESC) {
1199 if (start < stop) {
1200 stop--; /* reserve one byte for the final '\0' */
1201 while (start < stop && *string != '\0') {
Willy Tarreau1bfd6022019-06-07 11:10:07 +02001202 if (!ha_bit_test((unsigned char)(*string), map)) {
1203 if (!ha_bit_test((unsigned char)(*string), rfc5424_escape_map))
Dragan Dosen835b9212016-02-12 13:23:03 +01001204 *start++ = *string;
1205 else {
1206 if (start + 2 >= stop)
1207 break;
1208 *start++ = '\\';
1209 *start++ = *string;
1210 }
1211 }
1212 else {
1213 if (start + 3 >= stop)
1214 break;
1215 *start++ = escape;
1216 *start++ = hextab[(*string >> 4) & 15];
1217 *start++ = hextab[*string & 15];
1218 }
1219 string++;
1220 }
1221 *start = '\0';
1222 }
1223 }
1224 else {
1225 return encode_string(start, stop, escape, map, string);
1226 }
1227
1228 return start;
1229}
1230
1231/*
1232 * Encode the chunk.
1233 *
1234 * When using the +E log format option, it will try to escape '"\]'
1235 * characters with '\' as prefix. The same prefix should not be used as
1236 * <escape>.
1237 */
1238static char *lf_encode_chunk(char *start, char *stop,
Willy Tarreau1bfd6022019-06-07 11:10:07 +02001239 const char escape, const long *map,
Willy Tarreau83061a82018-07-13 11:56:34 +02001240 const struct buffer *chunk,
Dragan Dosen835b9212016-02-12 13:23:03 +01001241 struct logformat_node *node)
1242{
1243 char *str, *end;
1244
1245 if (node->options & LOG_OPT_ESC) {
1246 if (start < stop) {
Willy Tarreau843b7cb2018-07-13 10:54:26 +02001247 str = chunk->area;
1248 end = chunk->area + chunk->data;
Dragan Dosen835b9212016-02-12 13:23:03 +01001249
1250 stop--; /* reserve one byte for the final '\0' */
1251 while (start < stop && str < end) {
Willy Tarreau1bfd6022019-06-07 11:10:07 +02001252 if (!ha_bit_test((unsigned char)(*str), map)) {
1253 if (!ha_bit_test((unsigned char)(*str), rfc5424_escape_map))
Dragan Dosen835b9212016-02-12 13:23:03 +01001254 *start++ = *str;
1255 else {
1256 if (start + 2 >= stop)
1257 break;
1258 *start++ = '\\';
1259 *start++ = *str;
1260 }
1261 }
1262 else {
1263 if (start + 3 >= stop)
1264 break;
1265 *start++ = escape;
1266 *start++ = hextab[(*str >> 4) & 15];
1267 *start++ = hextab[*str & 15];
1268 }
1269 str++;
1270 }
1271 *start = '\0';
1272 }
1273 }
1274 else {
1275 return encode_chunk(start, stop, escape, map, chunk);
1276 }
1277
1278 return start;
1279}
1280
1281/*
William Lallemanda1cc3812012-02-08 16:38:44 +01001282 * Write a string in the log string
Dragan Dosen835b9212016-02-12 13:23:03 +01001283 * Take cares of quote and escape options
William Lallemanda1cc3812012-02-08 16:38:44 +01001284 *
Joseph Herlant85b40592018-11-15 12:10:04 -08001285 * Return the address of the \0 character, or NULL on error
William Lallemanda1cc3812012-02-08 16:38:44 +01001286 */
Willy Tarreau26ffa852018-09-05 15:23:10 +02001287char *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 +01001288{
Willy Tarreau2b0108a2012-12-21 19:23:44 +01001289 if (size < 2)
1290 return NULL;
William Lallemanda1cc3812012-02-08 16:38:44 +01001291
Willy Tarreau2b0108a2012-12-21 19:23:44 +01001292 if (node->options & LOG_OPT_QUOTE) {
1293 *(dst++) = '"';
1294 size--;
William Lallemandbddd4fd2012-02-27 11:23:10 +01001295 }
Willy Tarreau2b0108a2012-12-21 19:23:44 +01001296
Willy Tarreau6cbbdbf2013-02-05 18:52:25 +01001297 if (src && len) {
Dragan Dosendb1b6f92016-07-25 11:35:02 +02001298 if (++len > size)
1299 len = size;
Dragan Dosen835b9212016-02-12 13:23:03 +01001300 if (node->options & LOG_OPT_ESC) {
Dragan Dosen835b9212016-02-12 13:23:03 +01001301 char *ret;
1302
Dragan Dosendb1b6f92016-07-25 11:35:02 +02001303 ret = escape_string(dst, dst + len, '\\', rfc5424_escape_map, src);
Dragan Dosen835b9212016-02-12 13:23:03 +01001304 if (ret == NULL || *ret != '\0')
1305 return NULL;
1306 len = ret - dst;
1307 }
1308 else {
Dragan Dosen835b9212016-02-12 13:23:03 +01001309 len = strlcpy2(dst, src, len);
1310 }
Willy Tarreau2b0108a2012-12-21 19:23:44 +01001311
1312 size -= len;
1313 dst += len;
1314 }
Willy Tarreau6cbbdbf2013-02-05 18:52:25 +01001315 else if ((node->options & (LOG_OPT_QUOTE|LOG_OPT_MANDATORY)) == LOG_OPT_MANDATORY) {
1316 if (size < 2)
1317 return NULL;
1318 *(dst++) = '-';
1319 }
Willy Tarreau2b0108a2012-12-21 19:23:44 +01001320
1321 if (node->options & LOG_OPT_QUOTE) {
1322 if (size < 2)
1323 return NULL;
1324 *(dst++) = '"';
1325 }
1326
1327 *dst = '\0';
William Lallemandbddd4fd2012-02-27 11:23:10 +01001328 return dst;
William Lallemanda1cc3812012-02-08 16:38:44 +01001329}
1330
Willy Tarreau26ffa852018-09-05 15:23:10 +02001331static inline char *lf_text(char *dst, const char *src, size_t size, const struct logformat_node *node)
Willy Tarreau2b0108a2012-12-21 19:23:44 +01001332{
1333 return lf_text_len(dst, src, size, size, node);
1334}
1335
William Lallemand5f232402012-04-05 18:02:55 +02001336/*
Joseph Herlant85b40592018-11-15 12:10:04 -08001337 * Write a IP address to the log string
William Lallemand5f232402012-04-05 18:02:55 +02001338 * +X option write in hexadecimal notation, most signifant byte on the left
1339 */
Willy Tarreau26ffa852018-09-05 15:23:10 +02001340char *lf_ip(char *dst, const struct sockaddr *sockaddr, size_t size, const struct logformat_node *node)
William Lallemand5f232402012-04-05 18:02:55 +02001341{
1342 char *ret = dst;
1343 int iret;
1344 char pn[INET6_ADDRSTRLEN];
1345
1346 if (node->options & LOG_OPT_HEXA) {
Radek Zajic594c4562019-03-22 10:21:54 +00001347 unsigned char *addr = NULL;
1348 switch (sockaddr->sa_family) {
1349 case AF_INET:
1350 addr = (unsigned char *)&((struct sockaddr_in *)sockaddr)->sin_addr.s_addr;
1351 iret = snprintf(dst, size, "%02X%02X%02X%02X", addr[0], addr[1], addr[2], addr[3]);
1352 break;
1353 case AF_INET6:
1354 addr = (unsigned char *)&((struct sockaddr_in6 *)sockaddr)->sin6_addr.s6_addr;
1355 iret = snprintf(dst, size, "%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X",
1356 addr[0], addr[1], addr[2], addr[3], addr[4], addr[5], addr[6], addr[7],
1357 addr[8], addr[9], addr[10], addr[11], addr[12], addr[13], addr[14], addr[15]);
1358 break;
1359 default:
1360 return NULL;
1361 }
William Lallemand5f232402012-04-05 18:02:55 +02001362 if (iret < 0 || iret > size)
1363 return NULL;
1364 ret += iret;
1365 } else {
1366 addr_to_str((struct sockaddr_storage *)sockaddr, pn, sizeof(pn));
1367 ret = lf_text(dst, pn, size, node);
1368 if (ret == NULL)
1369 return NULL;
1370 }
1371 return ret;
1372}
1373
1374/*
1375 * Write a port to the log
1376 * +X option write in hexadecimal notation, most signifant byte on the left
1377 */
Willy Tarreau26ffa852018-09-05 15:23:10 +02001378char *lf_port(char *dst, const struct sockaddr *sockaddr, size_t size, const struct logformat_node *node)
William Lallemand5f232402012-04-05 18:02:55 +02001379{
1380 char *ret = dst;
1381 int iret;
1382
1383 if (node->options & LOG_OPT_HEXA) {
1384 const unsigned char *port = (const unsigned char *)&((struct sockaddr_in *)sockaddr)->sin_port;
1385 iret = snprintf(dst, size, "%02X%02X", port[0], port[1]);
1386 if (iret < 0 || iret > size)
1387 return NULL;
1388 ret += iret;
1389 } else {
1390 ret = ltoa_o(get_host_port((struct sockaddr_storage *)sockaddr), dst, size);
1391 if (ret == NULL)
1392 return NULL;
1393 }
1394 return ret;
1395}
1396
Dragan Dosen1322d092015-09-22 16:05:32 +02001397/* Re-generate time-based part of the syslog header in RFC3164 format at
1398 * the beginning of logheader once a second and return the pointer to the
1399 * first character after it.
Willy Tarreaub1a2faf2012-03-19 16:51:53 +01001400 */
Dragan Dosen0b85ece2015-09-25 19:17:44 +02001401static char *update_log_hdr(const time_t time)
Willy Tarreaubaaee002006-06-26 02:48:02 +02001402{
Christopher Fauletf8188c62017-06-02 16:20:16 +02001403 static THREAD_LOCAL long tvsec;
Willy Tarreau83061a82018-07-13 11:56:34 +02001404 static THREAD_LOCAL struct buffer host = { };
Christopher Fauletf8188c62017-06-02 16:20:16 +02001405 static THREAD_LOCAL int sep = 0;
Willy Tarreaubaaee002006-06-26 02:48:02 +02001406
Willy Tarreau55e2f5a2019-05-05 10:11:39 +02001407 if (unlikely(time != tvsec || logheader_end == NULL)) {
Willy Tarreaubaaee002006-06-26 02:48:02 +02001408 /* this string is rebuild only once a second */
Willy Tarreaufe944602007-10-25 10:34:16 +02001409 struct tm tm;
Willy Tarreaub1a2faf2012-03-19 16:51:53 +01001410 int hdr_len;
Willy Tarreaufe944602007-10-25 10:34:16 +02001411
Dragan Dosen0b85ece2015-09-25 19:17:44 +02001412 tvsec = time;
Willy Tarreaufe944602007-10-25 10:34:16 +02001413 get_localtime(tvsec, &tm);
Willy Tarreaubaaee002006-06-26 02:48:02 +02001414
Willy Tarreau843b7cb2018-07-13 10:54:26 +02001415 if (unlikely(global.log_send_hostname != host.area)) {
1416 host.area = global.log_send_hostname;
1417 host.data = host.area ? strlen(host.area) : 0;
1418 sep = host.data ? 1 : 0;
Dragan Dosen43885c72015-10-01 13:18:13 +02001419 }
1420
Dragan Dosen59cee972015-09-19 22:09:02 +02001421 hdr_len = snprintf(logheader, global.max_syslog_len,
Dragan Dosen43885c72015-10-01 13:18:13 +02001422 "<<<<>%s %2d %02d:%02d:%02d %.*s%*s",
Willy Tarreaufe944602007-10-25 10:34:16 +02001423 monthname[tm.tm_mon],
Dragan Dosen43885c72015-10-01 13:18:13 +02001424 tm.tm_mday, tm.tm_hour, tm.tm_min, tm.tm_sec,
Willy Tarreau843b7cb2018-07-13 10:54:26 +02001425 (int)host.data, host.area, sep, "");
Willy Tarreaubaaee002006-06-26 02:48:02 +02001426 /* WARNING: depending upon implementations, snprintf may return
1427 * either -1 or the number of bytes that would be needed to store
1428 * the total message. In both cases, we must adjust it.
1429 */
Willy Tarreau18324f52014-06-27 18:10:07 +02001430 if (hdr_len < 0 || hdr_len > global.max_syslog_len)
1431 hdr_len = global.max_syslog_len;
Willy Tarreaubaaee002006-06-26 02:48:02 +02001432
Willy Tarreau55e2f5a2019-05-05 10:11:39 +02001433 logheader_end = logheader + hdr_len;
Willy Tarreaubaaee002006-06-26 02:48:02 +02001434 }
1435
Willy Tarreau55e2f5a2019-05-05 10:11:39 +02001436 logheader_end[0] = 0; // ensure we get rid of any previous attempt
Willy Tarreau094af4e2015-01-07 15:03:42 +01001437
Willy Tarreau55e2f5a2019-05-05 10:11:39 +02001438 return logheader_end;
William Lallemand2a4a44f2012-02-06 16:00:33 +01001439}
1440
Dragan Dosen1322d092015-09-22 16:05:32 +02001441/* Re-generate time-based part of the syslog header in RFC5424 format at
1442 * the beginning of logheader_rfc5424 once a second and return the pointer
1443 * to the first character after it.
1444 */
Dragan Dosen0b85ece2015-09-25 19:17:44 +02001445static char *update_log_hdr_rfc5424(const time_t time)
Dragan Dosen1322d092015-09-22 16:05:32 +02001446{
Christopher Fauletf8188c62017-06-02 16:20:16 +02001447 static THREAD_LOCAL long tvsec;
Benoit GARNIERb413c2a2016-03-27 11:08:03 +02001448 const char *gmt_offset;
Dragan Dosen1322d092015-09-22 16:05:32 +02001449
Willy Tarreau55e2f5a2019-05-05 10:11:39 +02001450 if (unlikely(time != tvsec || logheader_rfc5424_end == NULL)) {
Dragan Dosen1322d092015-09-22 16:05:32 +02001451 /* this string is rebuild only once a second */
1452 struct tm tm;
1453 int hdr_len;
1454
Dragan Dosen0b85ece2015-09-25 19:17:44 +02001455 tvsec = time;
Dragan Dosen1322d092015-09-22 16:05:32 +02001456 get_localtime(tvsec, &tm);
Benoit GARNIERe2e5bde2016-03-27 03:04:16 +02001457 gmt_offset = get_gmt_offset(time, &tm);
Dragan Dosen1322d092015-09-22 16:05:32 +02001458
1459 hdr_len = snprintf(logheader_rfc5424, global.max_syslog_len,
Dragan Dosen17def462015-10-09 21:31:43 +02001460 "<<<<>1 %4d-%02d-%02dT%02d:%02d:%02d%.3s:%.2s %s ",
Dragan Dosen1322d092015-09-22 16:05:32 +02001461 tm.tm_year+1900, tm.tm_mon+1, tm.tm_mday,
Dragan Dosen17def462015-10-09 21:31:43 +02001462 tm.tm_hour, tm.tm_min, tm.tm_sec,
Benoit GARNIERb413c2a2016-03-27 11:08:03 +02001463 gmt_offset, gmt_offset+3,
Dragan Dosen43885c72015-10-01 13:18:13 +02001464 global.log_send_hostname ? global.log_send_hostname : hostname);
Dragan Dosen1322d092015-09-22 16:05:32 +02001465 /* WARNING: depending upon implementations, snprintf may return
1466 * either -1 or the number of bytes that would be needed to store
1467 * the total message. In both cases, we must adjust it.
1468 */
1469 if (hdr_len < 0 || hdr_len > global.max_syslog_len)
1470 hdr_len = global.max_syslog_len;
1471
Willy Tarreau55e2f5a2019-05-05 10:11:39 +02001472 logheader_rfc5424_end = logheader_rfc5424 + hdr_len;
Dragan Dosen1322d092015-09-22 16:05:32 +02001473 }
1474
Willy Tarreau55e2f5a2019-05-05 10:11:39 +02001475 logheader_rfc5424_end[0] = 0; // ensure we get rid of any previous attempt
Dragan Dosen1322d092015-09-22 16:05:32 +02001476
Willy Tarreau55e2f5a2019-05-05 10:11:39 +02001477 return logheader_rfc5424_end;
Dragan Dosen1322d092015-09-22 16:05:32 +02001478}
1479
William Lallemand2a4a44f2012-02-06 16:00:33 +01001480/*
Dragan Dosen59cee972015-09-19 22:09:02 +02001481 * This function sends the syslog message using a printf format string. It
1482 * expects an LF-terminated message.
William Lallemand2a4a44f2012-02-06 16:00:33 +01001483 */
1484void send_log(struct proxy *p, int level, const char *format, ...)
1485{
1486 va_list argp;
Willy Tarreaub1a2faf2012-03-19 16:51:53 +01001487 int data_len;
William Lallemand2a4a44f2012-02-06 16:00:33 +01001488
Willy Tarreau8c97ab52015-01-15 16:29:53 +01001489 if (level < 0 || format == NULL || logline == NULL)
William Lallemand2a4a44f2012-02-06 16:00:33 +01001490 return;
1491
William Lallemand2a4a44f2012-02-06 16:00:33 +01001492 va_start(argp, format);
Dragan Dosen59cee972015-09-19 22:09:02 +02001493 data_len = vsnprintf(logline, global.max_syslog_len, format, argp);
Willy Tarreau18324f52014-06-27 18:10:07 +02001494 if (data_len < 0 || data_len > global.max_syslog_len)
1495 data_len = global.max_syslog_len;
Willy Tarreaubaaee002006-06-26 02:48:02 +02001496 va_end(argp);
William Lallemand2a4a44f2012-02-06 16:00:33 +01001497
Christopher Faulet5c6fefc2019-08-11 19:40:12 +02001498 __send_log((p ? &p->logsrvs : NULL), (p ? &p->log_tag : NULL), level,
1499 logline, data_len, default_rfc5424_sd_log_format, 2);
William Lallemand2a4a44f2012-02-06 16:00:33 +01001500}
1501
1502/*
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001503 * This function sends a syslog message to <logsrv>.
1504 * <pid_str> is the string to be used for the PID of the caller, <pid_size> is length.
1505 * Same thing for <sd> and <sd_size> which are used for the structured-data part
1506 * in RFC5424 formatted syslog messages, and <tag_str> and <tag_size> the syslog tag.
Dragan Dosen0b85ece2015-09-25 19:17:44 +02001507 * It overrides the last byte of the message vector with an LF character.
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001508 * Does not return any error,
William Lallemand2a4a44f2012-02-06 16:00:33 +01001509 */
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001510static inline void __do_send_log(struct logsrv *logsrv, int nblogger, char *pid_str, size_t pid_size,
1511 int level, char *message, size_t size, char *sd, size_t sd_size,
1512 char *tag_str, size_t tag_size)
William Lallemand2a4a44f2012-02-06 16:00:33 +01001513{
Christopher Fauletf8188c62017-06-02 16:20:16 +02001514 static THREAD_LOCAL struct iovec iovec[NB_MSG_IOVEC_ELEMENTS] = { };
1515 static THREAD_LOCAL struct msghdr msghdr = {
1516 //.msg_iov = iovec,
Dragan Dosen609ac2a2015-09-16 18:25:42 +02001517 .msg_iovlen = NB_MSG_IOVEC_ELEMENTS
1518 };
Christopher Fauletf8188c62017-06-02 16:20:16 +02001519 static THREAD_LOCAL int logfdunix = -1; /* syslog to AF_UNIX socket */
1520 static THREAD_LOCAL int logfdinet = -1; /* syslog to AF_INET socket */
1521 static THREAD_LOCAL char *dataptr = NULL;
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001522 time_t time = date.tv_sec;
Dragan Dosen1322d092015-09-22 16:05:32 +02001523 char *hdr, *hdr_ptr;
Dragan Dosen59cee972015-09-19 22:09:02 +02001524 size_t hdr_size;
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001525 int fac_level;
1526 int *plogfd;
1527 char *pid_sep1 = "", *pid_sep2 = "";
1528 char logheader_short[3];
1529 int sent;
1530 int maxlen;
1531 int hdr_max = 0;
1532 int tag_max = 0;
1533 int pid_sep1_max = 0;
Frédéric Lécaille90a10ae2019-05-14 10:57:58 +02001534 int pid_max = 0;
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001535 int pid_sep2_max = 0;
1536 int sd_max = 0;
1537 int max = 0;
Christopher Fauletf8188c62017-06-02 16:20:16 +02001538
1539 msghdr.msg_iov = iovec;
William Lallemand2a4a44f2012-02-06 16:00:33 +01001540
1541 dataptr = message;
Willy Tarreaubaaee002006-06-26 02:48:02 +02001542
Willy Tarreauf3dc30f2019-08-30 14:18:44 +02001543 if (logsrv->type == LOG_TARGET_FD) {
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001544 /* the socket's address is a file descriptor */
1545 plogfd = (int *)&((struct sockaddr_in *)&logsrv->addr)->sin_addr.s_addr;
Robert Tsai81ae1952007-12-05 10:47:29 +01001546 }
Willy Tarreauc046d162019-08-30 15:24:59 +02001547 else if (logsrv->type == LOG_TARGET_BUFFER) {
1548 plogfd = NULL;
1549 }
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001550 else if (logsrv->addr.ss_family == AF_UNIX)
1551 plogfd = &logfdunix;
1552 else
1553 plogfd = &logfdinet;
Robert Tsai81ae1952007-12-05 10:47:29 +01001554
Willy Tarreauc046d162019-08-30 15:24:59 +02001555 if (plogfd && unlikely(*plogfd < 0)) {
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001556 /* socket not successfully initialized yet */
1557 if ((*plogfd = socket(logsrv->addr.ss_family, SOCK_DGRAM,
1558 (logsrv->addr.ss_family == AF_UNIX) ? 0 : IPPROTO_UDP)) < 0) {
1559 static char once;
William Lallemand0f99e342011-10-12 17:50:54 +02001560
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001561 if (!once) {
1562 once = 1; /* note: no need for atomic ops here */
1563 ha_alert("socket() failed in logger #%d: %s (errno=%d)\n",
1564 nblogger, strerror(errno), errno);
1565 }
1566 return;
1567 } else {
1568 /* we don't want to receive anything on this socket */
1569 setsockopt(*plogfd, SOL_SOCKET, SO_RCVBUF, &zero, sizeof(zero));
1570 /* does nothing under Linux, maybe needed for others */
1571 shutdown(*plogfd, SHUT_RD);
1572 fcntl(*plogfd, F_SETFD, fcntl(*plogfd, F_GETFD, FD_CLOEXEC) | FD_CLOEXEC);
1573 }
Dragan Dosen43885c72015-10-01 13:18:13 +02001574 }
1575
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001576 switch (logsrv->format) {
1577 case LOG_FORMAT_RFC3164:
1578 hdr = logheader;
1579 hdr_ptr = update_log_hdr(time);
1580 break;
Willy Tarreauc7c7be22014-06-23 18:07:15 +02001581
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001582 case LOG_FORMAT_RFC5424:
1583 hdr = logheader_rfc5424;
1584 hdr_ptr = update_log_hdr_rfc5424(time);
1585 sd_max = sd_size; /* the SD part allowed only in RFC5424 */
1586 break;
William Lallemandbddd4fd2012-02-27 11:23:10 +01001587
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001588 case LOG_FORMAT_SHORT:
1589 /* all fields are known, skip the header generation */
1590 hdr = logheader_short;
1591 hdr[0] = '<';
1592 hdr[1] = '0' + MAX(level, logsrv->minlvl);
1593 hdr[2] = '>';
1594 hdr_ptr = hdr;
1595 hdr_max = 3;
1596 maxlen = logsrv->maxlen - hdr_max;
1597 max = MIN(size, maxlen) - 1;
1598 goto send;
Willy Tarreau204e3f12018-12-15 15:48:48 +01001599
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001600 case LOG_FORMAT_RAW:
1601 /* all fields are known, skip the header generation */
1602 hdr_ptr = hdr = "";
1603 hdr_max = 0;
1604 maxlen = logsrv->maxlen;
1605 max = MIN(size, maxlen) - 1;
1606 goto send;
Willy Tarreauc98aebc2018-03-20 11:17:29 +01001607
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001608 default:
1609 return; /* must never happen */
1610 }
Willy Tarreauc7c7be22014-06-23 18:07:15 +02001611
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001612 hdr_size = hdr_ptr - hdr;
Dragan Dosen1322d092015-09-22 16:05:32 +02001613
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001614 /* For each target, we may have a different facility.
1615 * We can also have a different log level for each message.
1616 * This induces variations in the message header length.
1617 * Since we don't want to recompute it each time, nor copy it every
1618 * time, we only change the facility in the pre-computed header,
1619 * and we change the pointer to the header accordingly.
1620 */
1621 fac_level = (logsrv->facility << 3) + MAX(level, logsrv->minlvl);
1622 hdr_ptr = hdr + 3; /* last digit of the log level */
1623 do {
1624 *hdr_ptr = '0' + fac_level % 10;
1625 fac_level /= 10;
1626 hdr_ptr--;
1627 } while (fac_level && hdr_ptr > hdr);
1628 *hdr_ptr = '<';
Dragan Dosen1322d092015-09-22 16:05:32 +02001629
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001630 hdr_max = hdr_size - (hdr_ptr - hdr);
Willy Tarreaue8746a02018-11-12 08:45:00 +01001631
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001632 /* time-based header */
1633 if (unlikely(hdr_size >= logsrv->maxlen)) {
1634 hdr_max = MIN(hdr_max, logsrv->maxlen) - 1;
1635 sd_max = 0;
1636 goto send;
1637 }
Willy Tarreauc1b06452018-11-12 11:57:56 +01001638
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001639 maxlen = logsrv->maxlen - hdr_max;
Dragan Dosen1322d092015-09-22 16:05:32 +02001640
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001641 /* tag */
Frédéric Lécaille90a10ae2019-05-14 10:57:58 +02001642 tag_max = tag_size;
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001643 if (unlikely(tag_max >= maxlen)) {
1644 tag_max = maxlen - 1;
1645 sd_max = 0;
1646 goto send;
1647 }
Dragan Dosen1322d092015-09-22 16:05:32 +02001648
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001649 maxlen -= tag_max;
William Lallemand2a4a44f2012-02-06 16:00:33 +01001650
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001651 /* first pid separator */
1652 pid_sep1_max = log_formats[logsrv->format].pid.sep1.data;
1653 if (unlikely(pid_sep1_max >= maxlen)) {
1654 pid_sep1_max = maxlen - 1;
1655 sd_max = 0;
1656 goto send;
1657 }
Dragan Dosen59cee972015-09-19 22:09:02 +02001658
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001659 pid_sep1 = log_formats[logsrv->format].pid.sep1.area;
1660 maxlen -= pid_sep1_max;
Dragan Dosen59cee972015-09-19 22:09:02 +02001661
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001662 /* pid */
Frédéric Lécaille90a10ae2019-05-14 10:57:58 +02001663 pid_max = pid_size;
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001664 if (unlikely(pid_size >= maxlen)) {
1665 pid_size = maxlen - 1;
1666 sd_max = 0;
1667 goto send;
1668 }
Dragan Dosen68d2e3a2015-09-19 22:35:44 +02001669
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001670 maxlen -= pid_size;
Dragan Dosen43885c72015-10-01 13:18:13 +02001671
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001672 /* second pid separator */
1673 pid_sep2_max = log_formats[logsrv->format].pid.sep2.data;
1674 if (unlikely(pid_sep2_max >= maxlen)) {
1675 pid_sep2_max = maxlen - 1;
1676 sd_max = 0;
1677 goto send;
1678 }
Dragan Dosen43885c72015-10-01 13:18:13 +02001679
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001680 pid_sep2 = log_formats[logsrv->format].pid.sep2.area;
1681 maxlen -= pid_sep2_max;
Dragan Dosen68d2e3a2015-09-19 22:35:44 +02001682
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001683 /* structured-data */
1684 if (sd_max >= maxlen) {
1685 sd_max = maxlen - 1;
1686 goto send;
1687 }
Dragan Dosen59cee972015-09-19 22:09:02 +02001688
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001689 max = MIN(size, maxlen - sd_max) - 1;
1690send:
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001691 if (logsrv->addr.ss_family == AF_UNSPEC) {
Willy Tarreauc046d162019-08-30 15:24:59 +02001692 /* the target is a file descriptor or a ring buffer */
Willy Tarreaud52a7f82019-08-30 14:05:35 +02001693 struct ist msg[7];
1694
1695 msg[0].ptr = hdr_ptr; msg[0].len = hdr_max;
1696 msg[1].ptr = tag_str; msg[1].len = tag_max;
1697 msg[2].ptr = pid_sep1; msg[2].len = pid_sep1_max;
1698 msg[3].ptr = pid_str; msg[3].len = pid_max;
1699 msg[4].ptr = pid_sep2; msg[4].len = pid_sep2_max;
1700 msg[5].ptr = sd; msg[5].len = sd_max;
1701 msg[6].ptr = dataptr; msg[6].len = max;
1702
Willy Tarreauc046d162019-08-30 15:24:59 +02001703 if (logsrv->type == LOG_TARGET_BUFFER)
1704 sent = ring_write(logsrv->ring, ~0, NULL, 0, msg, 7);
1705 else /* LOG_TARGET_FD */
1706 sent = fd_write_frag_line(*plogfd, ~0, NULL, 0, msg, 7, 1);
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001707 }
1708 else {
Willy Tarreaud52a7f82019-08-30 14:05:35 +02001709 iovec[0].iov_base = hdr_ptr;
1710 iovec[0].iov_len = hdr_max;
1711 iovec[1].iov_base = tag_str;
1712 iovec[1].iov_len = tag_max;
1713 iovec[2].iov_base = pid_sep1;
1714 iovec[2].iov_len = pid_sep1_max;
1715 iovec[3].iov_base = pid_str;
1716 iovec[3].iov_len = pid_max;
1717 iovec[4].iov_base = pid_sep2;
1718 iovec[4].iov_len = pid_sep2_max;
1719 iovec[5].iov_base = sd;
1720 iovec[5].iov_len = sd_max;
1721 iovec[6].iov_base = dataptr;
1722 iovec[6].iov_len = max;
1723 iovec[7].iov_base = "\n"; /* insert a \n at the end of the message */
1724 iovec[7].iov_len = 1;
1725
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001726 msghdr.msg_name = (struct sockaddr *)&logsrv->addr;
1727 msghdr.msg_namelen = get_addr_len(&logsrv->addr);
Dragan Dosen43885c72015-10-01 13:18:13 +02001728
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001729 sent = sendmsg(*plogfd, &msghdr, MSG_DONTWAIT | MSG_NOSIGNAL);
1730 }
Dragan Dosen43885c72015-10-01 13:18:13 +02001731
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001732 if (sent < 0) {
1733 static char once;
Dragan Dosen43885c72015-10-01 13:18:13 +02001734
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001735 if (errno == EAGAIN)
1736 _HA_ATOMIC_ADD(&dropped_logs, 1);
1737 else if (!once) {
1738 once = 1; /* note: no need for atomic ops here */
1739 ha_alert("sendmsg()/writev() failed in logger #%d: %s (errno=%d)\n",
1740 nblogger, strerror(errno), errno);
Dragan Dosen0b85ece2015-09-25 19:17:44 +02001741 }
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001742 }
1743}
Dragan Dosen59cee972015-09-19 22:09:02 +02001744
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001745/*
1746 * This function sends a syslog message.
1747 * It doesn't care about errors nor does it report them.
1748 * The arguments <sd> and <sd_size> are used for the structured-data part
1749 * in RFC5424 formatted syslog messages.
1750 */
Christopher Faulet5c6fefc2019-08-11 19:40:12 +02001751void __send_log(struct list *logsrvs, struct buffer *tag, int level,
1752 char *message, size_t size, char *sd, size_t sd_size)
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001753{
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001754 struct logsrv *logsrv;
1755 int nblogger;
1756 static THREAD_LOCAL int curr_pid;
1757 static THREAD_LOCAL char pidstr[100];
1758 static THREAD_LOCAL struct buffer pid;
Dragan Dosen609ac2a2015-09-16 18:25:42 +02001759
Christopher Faulet5c6fefc2019-08-11 19:40:12 +02001760 if (logsrvs == NULL) {
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001761 if (!LIST_ISEMPTY(&global.logsrvs)) {
1762 logsrvs = &global.logsrvs;
Willy Tarreau5a32ecc2018-11-12 07:34:59 +01001763 }
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001764 }
Christopher Faulet5c6fefc2019-08-11 19:40:12 +02001765 if (!tag || !tag->area)
1766 tag = &global.log_tag;
Willy Tarreau18324f52014-06-27 18:10:07 +02001767
Christopher Faulet5c6fefc2019-08-11 19:40:12 +02001768 if (!logsrvs || LIST_ISEMPTY(logsrvs))
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001769 return;
Willy Tarreauc98aebc2018-03-20 11:17:29 +01001770
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001771 if (unlikely(curr_pid != getpid())) {
1772 curr_pid = getpid();
1773 ltoa_o(curr_pid, pidstr, sizeof(pidstr));
1774 chunk_initstr(&pid, pidstr);
1775 }
1776
1777 /* Send log messages to syslog server. */
1778 nblogger = 0;
1779 list_for_each_entry(logsrv, logsrvs, list) {
Frédéric Lécailled803e472019-04-25 07:42:09 +02001780 static THREAD_LOCAL int in_range = 1;
1781
Frédéric Lécaille0bad8402019-04-10 08:22:17 +02001782 /* we can filter the level of the messages that are sent to each logger */
1783 if (level > logsrv->level)
1784 continue;
1785
Frédéric Lécailled803e472019-04-25 07:42:09 +02001786 if (logsrv->lb.smp_rgs) {
1787 struct smp_log_range *curr_rg;
1788
1789 HA_SPIN_LOCK(LOGSRV_LOCK, &logsrv->lock);
1790 curr_rg = &logsrv->lb.smp_rgs[logsrv->lb.curr_rg];
1791 in_range = in_smp_log_range(curr_rg, logsrv->lb.curr_idx);
1792 if (in_range) {
1793 /* Let's consume this range. */
1794 curr_rg->curr_idx = (curr_rg->curr_idx + 1) % curr_rg->sz;
1795 if (!curr_rg->curr_idx) {
1796 /* If consumed, let's select the next range. */
1797 logsrv->lb.curr_rg = (logsrv->lb.curr_rg + 1) % logsrv->lb.smp_rgs_sz;
1798 }
1799 }
1800 logsrv->lb.curr_idx = (logsrv->lb.curr_idx + 1) % logsrv->lb.smp_sz;
1801 HA_SPIN_UNLOCK(LOGSRV_LOCK, &logsrv->lock);
1802 }
1803 if (in_range)
1804 __do_send_log(logsrv, ++nblogger, pid.area, pid.data, level,
1805 message, size, sd, sd_size, tag->area, tag->data);
Willy Tarreaubaaee002006-06-26 02:48:02 +02001806 }
1807}
1808
1809
Willy Tarreauc89ccb62012-04-05 21:18:22 +02001810const 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 +01001811const char sess_set_cookie[8] = "NPDIRU67"; /* No set-cookie, Set-cookie found and left unchanged (passive),
1812 Set-cookie Deleted, Set-Cookie Inserted, Set-cookie Rewritten,
1813 Set-cookie Updated, unknown, unknown */
1814
William Lallemand1d705562012-03-12 12:46:41 +01001815/*
1816 * try to write a character if there is enough space, or goto out
1817 */
William Lallemandbddd4fd2012-02-27 11:23:10 +01001818#define LOGCHAR(x) do { \
William Lallemand1d705562012-03-12 12:46:41 +01001819 if (tmplog < dst + maxsize - 1) { \
William Lallemandbddd4fd2012-02-27 11:23:10 +01001820 *(tmplog++) = (x); \
1821 } else { \
1822 goto out; \
1823 } \
1824 } while(0)
1825
Dragan Dosen835b9212016-02-12 13:23:03 +01001826
Willy Tarreaub6b3df32018-11-26 16:31:20 +01001827/* Initializes some log data at boot */
1828static void init_log()
Dragan Dosen835b9212016-02-12 13:23:03 +01001829{
1830 char *tmp;
Willy Tarreaue10cd482018-09-10 18:16:53 +02001831 int i;
Dragan Dosen835b9212016-02-12 13:23:03 +01001832
1833 /* Initialize the escape map for the RFC5424 structured-data : '"\]'
1834 * inside PARAM-VALUE should be escaped with '\' as prefix.
1835 * See https://tools.ietf.org/html/rfc5424#section-6.3.3 for more
1836 * details.
1837 */
1838 memset(rfc5424_escape_map, 0, sizeof(rfc5424_escape_map));
1839
1840 tmp = "\"\\]";
1841 while (*tmp) {
Willy Tarreau1bfd6022019-06-07 11:10:07 +02001842 ha_bit_set(*tmp, rfc5424_escape_map);
Dragan Dosen835b9212016-02-12 13:23:03 +01001843 tmp++;
1844 }
Willy Tarreaue10cd482018-09-10 18:16:53 +02001845
1846 /* initialize the log header encoding map : '{|}"#' should be encoded with
1847 * '#' as prefix, as well as non-printable characters ( <32 or >= 127 ).
1848 * URL encoding only requires '"', '#' to be encoded as well as non-
1849 * printable characters above.
1850 */
1851 memset(hdr_encode_map, 0, sizeof(hdr_encode_map));
1852 memset(url_encode_map, 0, sizeof(url_encode_map));
1853 for (i = 0; i < 32; i++) {
Willy Tarreau1bfd6022019-06-07 11:10:07 +02001854 ha_bit_set(i, hdr_encode_map);
1855 ha_bit_set(i, url_encode_map);
Willy Tarreaue10cd482018-09-10 18:16:53 +02001856 }
1857 for (i = 127; i < 256; i++) {
Willy Tarreau1bfd6022019-06-07 11:10:07 +02001858 ha_bit_set(i, hdr_encode_map);
1859 ha_bit_set(i, url_encode_map);
Willy Tarreaue10cd482018-09-10 18:16:53 +02001860 }
1861
1862 tmp = "\"#{|}";
1863 while (*tmp) {
Willy Tarreau1bfd6022019-06-07 11:10:07 +02001864 ha_bit_set(*tmp, hdr_encode_map);
Willy Tarreaue10cd482018-09-10 18:16:53 +02001865 tmp++;
1866 }
1867
1868 tmp = "\"#";
1869 while (*tmp) {
Willy Tarreau1bfd6022019-06-07 11:10:07 +02001870 ha_bit_set(*tmp, url_encode_map);
Willy Tarreaue10cd482018-09-10 18:16:53 +02001871 tmp++;
1872 }
1873
1874 /* initialize the http header encoding map. The draft httpbis define the
1875 * header content as:
1876 *
1877 * HTTP-message = start-line
1878 * *( header-field CRLF )
1879 * CRLF
1880 * [ message-body ]
1881 * header-field = field-name ":" OWS field-value OWS
1882 * field-value = *( field-content / obs-fold )
1883 * field-content = field-vchar [ 1*( SP / HTAB ) field-vchar ]
1884 * obs-fold = CRLF 1*( SP / HTAB )
1885 * field-vchar = VCHAR / obs-text
1886 * VCHAR = %x21-7E
1887 * obs-text = %x80-FF
1888 *
1889 * All the chars are encoded except "VCHAR", "obs-text", SP and HTAB.
1890 * The encoded chars are form 0x00 to 0x08, 0x0a to 0x1f and 0x7f. The
Joseph Herlant85b40592018-11-15 12:10:04 -08001891 * "obs-fold" is voluntarily forgotten because haproxy remove this.
Willy Tarreaue10cd482018-09-10 18:16:53 +02001892 */
1893 memset(http_encode_map, 0, sizeof(http_encode_map));
1894 for (i = 0x00; i <= 0x08; i++)
Willy Tarreau1bfd6022019-06-07 11:10:07 +02001895 ha_bit_set(i, http_encode_map);
Willy Tarreaue10cd482018-09-10 18:16:53 +02001896 for (i = 0x0a; i <= 0x1f; i++)
Willy Tarreau1bfd6022019-06-07 11:10:07 +02001897 ha_bit_set(i, http_encode_map);
1898 ha_bit_set(0x7f, http_encode_map);
Dragan Dosen835b9212016-02-12 13:23:03 +01001899}
William Lallemand1d705562012-03-12 12:46:41 +01001900
Willy Tarreaub6b3df32018-11-26 16:31:20 +01001901INITCALL0(STG_PREPARE, init_log);
1902
Christopher Faulet0132d062017-07-26 15:33:35 +02001903/* Initialize log buffers used for syslog messages */
1904int init_log_buffers()
1905{
1906 logheader = my_realloc2(logheader, global.max_syslog_len + 1);
Willy Tarreau55e2f5a2019-05-05 10:11:39 +02001907 logheader_end = NULL;
Christopher Faulet0132d062017-07-26 15:33:35 +02001908 logheader_rfc5424 = my_realloc2(logheader_rfc5424, global.max_syslog_len + 1);
Willy Tarreau55e2f5a2019-05-05 10:11:39 +02001909 logheader_rfc5424_end = NULL;
Christopher Faulet0132d062017-07-26 15:33:35 +02001910 logline = my_realloc2(logline, global.max_syslog_len + 1);
1911 logline_rfc5424 = my_realloc2(logline_rfc5424, global.max_syslog_len + 1);
1912 if (!logheader || !logline_rfc5424 || !logline || !logline_rfc5424)
1913 return 0;
1914 return 1;
1915}
1916
1917/* Deinitialize log buffers used for syslog messages */
1918void deinit_log_buffers()
1919{
1920 free(logheader);
1921 free(logheader_rfc5424);
1922 free(logline);
1923 free(logline_rfc5424);
Willy Tarreau869efd52019-11-15 15:16:57 +01001924 ring_free(_HA_ATOMIC_XCHG(&startup_logs, NULL));
Christopher Faulet0132d062017-07-26 15:33:35 +02001925 logheader = NULL;
1926 logheader_rfc5424 = NULL;
1927 logline = NULL;
1928 logline_rfc5424 = NULL;
1929}
1930
Willy Tarreaudf974472012-12-28 02:44:01 +01001931/* Builds a log line in <dst> based on <list_format>, and stops before reaching
1932 * <maxsize> characters. Returns the size of the output string in characters,
1933 * not counting the trailing zero which is always added if the resulting size
Willy Tarreau09bb27c2018-09-05 16:55:15 +02001934 * is not zero. It requires a valid session and optionally a stream. If the
1935 * stream is NULL, default values will be assumed for the stream part.
Willy Tarreaudf974472012-12-28 02:44:01 +01001936 */
Willy Tarreau43c538e2018-09-05 14:58:15 +02001937int 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 +02001938{
Willy Tarreaue36cbcb2015-04-03 15:40:56 +02001939 struct proxy *fe = sess->fe;
Willy Tarreau09bb27c2018-09-05 16:55:15 +02001940 struct proxy *be;
1941 struct http_txn *txn;
1942 const struct strm_logs *logs;
Willy Tarreau8fa99842019-07-17 11:47:11 +02001943 struct connection *be_conn;
Willy Tarreau09bb27c2018-09-05 16:55:15 +02001944 unsigned int s_flags;
1945 unsigned int uniq_id;
Willy Tarreau83061a82018-07-13 11:56:34 +02001946 struct buffer chunk;
William Lallemandbddd4fd2012-02-27 11:23:10 +01001947 char *uri;
Andrew Hayworth0ebc55f2015-04-27 21:37:03 +00001948 char *spc;
Andrew Hayworthe63ac872015-07-31 16:14:16 +00001949 char *qmark;
Andrew Hayworth0ebc55f2015-04-27 21:37:03 +00001950 char *end;
Willy Tarreaufe944602007-10-25 10:34:16 +02001951 struct tm tm;
William Lallemandbddd4fd2012-02-27 11:23:10 +01001952 int t_request;
1953 int hdr;
1954 int last_isspace = 1;
Andrew Hayworth0ebc55f2015-04-27 21:37:03 +00001955 int nspaces = 0;
Willy Tarreaub1a2faf2012-03-19 16:51:53 +01001956 char *tmplog;
William Lallemand1d705562012-03-12 12:46:41 +01001957 char *ret;
1958 int iret;
William Lallemandbddd4fd2012-02-27 11:23:10 +01001959 struct logformat_node *tmp;
Thierry FOURNIER / OZON.IO4cac3592016-07-28 17:19:45 +02001960 struct timeval tv;
Willy Tarreau09bb27c2018-09-05 16:55:15 +02001961 struct strm_logs tmp_strm_log;
Willy Tarreaubaaee002006-06-26 02:48:02 +02001962
William Lallemandbddd4fd2012-02-27 11:23:10 +01001963 /* FIXME: let's limit ourselves to frontend logging for now. */
Willy Tarreaubaaee002006-06-26 02:48:02 +02001964
Willy Tarreau09bb27c2018-09-05 16:55:15 +02001965 if (likely(s)) {
1966 be = s->be;
1967 txn = s->txn;
1968 be_conn = cs_conn(objt_cs(s->si[1].end));
1969 s_flags = s->flags;
1970 uniq_id = s->uniq_id;
1971 logs = &s->logs;
1972 } else {
1973 /* we have no stream so we first need to initialize a few
1974 * things that are needed later. We do increment the request
1975 * ID so that it's uniquely assigned to this request just as
1976 * if the request had reached the point of being processed.
1977 * A request error is reported as it's the only element we have
1978 * here and which justifies emitting such a log.
1979 */
1980 be = fe;
1981 txn = NULL;
1982 be_conn = NULL;
1983 s_flags = SF_ERR_PRXCOND | SF_FINST_R;
Olivier Houchardd2ee3e72019-03-08 18:53:21 +01001984 uniq_id = _HA_ATOMIC_XADD(&global.req_count, 1);
Willy Tarreau09bb27c2018-09-05 16:55:15 +02001985
1986 /* prepare a valid log structure */
1987 tmp_strm_log.tv_accept = sess->tv_accept;
1988 tmp_strm_log.accept_date = sess->accept_date;
1989 tmp_strm_log.t_handshake = sess->t_handshake;
1990 tmp_strm_log.t_idle = tv_ms_elapsed(&sess->tv_accept, &now) - sess->t_handshake;
1991 tv_zero(&tmp_strm_log.tv_request);
1992 tmp_strm_log.t_queue = -1;
1993 tmp_strm_log.t_connect = -1;
1994 tmp_strm_log.t_data = -1;
1995 tmp_strm_log.t_close = tv_ms_elapsed(&sess->tv_accept, &now);
1996 tmp_strm_log.bytes_in = 0;
1997 tmp_strm_log.bytes_out = 0;
1998 tmp_strm_log.prx_queue_pos = 0;
1999 tmp_strm_log.srv_queue_pos = 0;
2000
2001 logs = &tmp_strm_log;
2002 }
2003
William Lallemandbddd4fd2012-02-27 11:23:10 +01002004 t_request = -1;
Willy Tarreau372ac5a2018-09-05 15:16:23 +02002005 if (tv_isge(&logs->tv_request, &logs->tv_accept))
2006 t_request = tv_ms_elapsed(&logs->tv_accept, &logs->tv_request);
William Lallemandbddd4fd2012-02-27 11:23:10 +01002007
William Lallemand1d705562012-03-12 12:46:41 +01002008 tmplog = dst;
Willy Tarreauc9bd0cc2009-05-10 11:57:02 +02002009
William Lallemandbddd4fd2012-02-27 11:23:10 +01002010 /* fill logbuffer */
William Lallemand1d705562012-03-12 12:46:41 +01002011 if (LIST_ISEMPTY(list_format))
2012 return 0;
William Lallemandbddd4fd2012-02-27 11:23:10 +01002013
William Lallemand1d705562012-03-12 12:46:41 +01002014 list_for_each_entry(tmp, list_format, list) {
Willy Tarreaub363a1f2013-10-01 10:45:07 +02002015 struct connection *conn;
Willy Tarreau4f653562012-10-12 19:48:16 +02002016 const char *src = NULL;
Willy Tarreauc8368452012-12-21 00:09:23 +01002017 struct sample *key;
Willy Tarreau83061a82018-07-13 11:56:34 +02002018 const struct buffer empty = { };
William Lallemandbddd4fd2012-02-27 11:23:10 +01002019
Willy Tarreauc8368452012-12-21 00:09:23 +01002020 switch (tmp->type) {
William Lallemand1d705562012-03-12 12:46:41 +01002021 case LOG_FMT_SEPARATOR:
William Lallemandbddd4fd2012-02-27 11:23:10 +01002022 if (!last_isspace) {
2023 LOGCHAR(' ');
2024 last_isspace = 1;
William Lallemandbddd4fd2012-02-27 11:23:10 +01002025 }
2026 break;
2027
William Lallemand1d705562012-03-12 12:46:41 +01002028 case LOG_FMT_TEXT: // text
William Lallemandbddd4fd2012-02-27 11:23:10 +01002029 src = tmp->arg;
William Lallemand5f232402012-04-05 18:02:55 +02002030 iret = strlcpy2(tmplog, src, dst + maxsize - tmplog);
William Lallemand1d705562012-03-12 12:46:41 +01002031 if (iret == 0)
William Lallemandbddd4fd2012-02-27 11:23:10 +01002032 goto out;
William Lallemand1d705562012-03-12 12:46:41 +01002033 tmplog += iret;
William Lallemandbddd4fd2012-02-27 11:23:10 +01002034 last_isspace = 0;
2035 break;
2036
Willy Tarreauc8368452012-12-21 00:09:23 +01002037 case LOG_FMT_EXPR: // sample expression, may be request or response
2038 key = NULL;
Olivier Houchardf90db442018-12-15 14:00:06 +01002039 if (tmp->options & LOG_OPT_REQ_CAP && s)
Adis Nezirovic79beb242015-07-06 15:41:02 +02002040 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 +01002041 if (!key && (tmp->options & LOG_OPT_RES_CAP) && s)
Adis Nezirovic79beb242015-07-06 15:41:02 +02002042 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 +01002043 if (tmp->options & LOG_OPT_HTTP)
Dragan Dosen835b9212016-02-12 13:23:03 +01002044 ret = lf_encode_chunk(tmplog, dst + maxsize,
2045 '%', http_encode_map, key ? &key->data.u.str : &empty, tmp);
Thierry FOURNIERd048d8b2014-03-13 16:46:18 +01002046 else
Willy Tarreau843b7cb2018-07-13 10:54:26 +02002047 ret = lf_text_len(tmplog,
2048 key ? key->data.u.str.area : NULL,
2049 key ? key->data.u.str.data : 0,
2050 dst + maxsize - tmplog,
2051 tmp);
Willy Tarreauc8368452012-12-21 00:09:23 +01002052 if (ret == 0)
2053 goto out;
2054 tmplog = ret;
2055 last_isspace = 0;
2056 break;
2057
Willy Tarreau2beef582012-12-20 17:22:52 +01002058 case LOG_FMT_CLIENTIP: // %ci
Willy Tarreau9ad7bd42015-04-03 19:19:59 +02002059 conn = objt_conn(sess->origin);
Willy Tarreau8fa99842019-07-17 11:47:11 +02002060 if (conn && conn_get_src(conn))
Willy Tarreau6c6365f2019-07-17 16:48:18 +02002061 ret = lf_ip(tmplog, (struct sockaddr *)conn->src, dst + maxsize - tmplog, tmp);
Willy Tarreaub363a1f2013-10-01 10:45:07 +02002062 else
2063 ret = lf_text_len(tmplog, NULL, 0, dst + maxsize - tmplog, tmp);
William Lallemand1d705562012-03-12 12:46:41 +01002064 if (ret == NULL)
William Lallemandbddd4fd2012-02-27 11:23:10 +01002065 goto out;
William Lallemand1d705562012-03-12 12:46:41 +01002066 tmplog = ret;
William Lallemandbddd4fd2012-02-27 11:23:10 +01002067 last_isspace = 0;
2068 break;
2069
Willy Tarreau2beef582012-12-20 17:22:52 +01002070 case LOG_FMT_CLIENTPORT: // %cp
Willy Tarreau9ad7bd42015-04-03 19:19:59 +02002071 conn = objt_conn(sess->origin);
Willy Tarreau8fa99842019-07-17 11:47:11 +02002072 if (conn && conn_get_src(conn)) {
Willy Tarreau6c6365f2019-07-17 16:48:18 +02002073 if (conn->src->ss_family == AF_UNIX) {
Willy Tarreaufb0afa72015-04-03 14:46:27 +02002074 ret = ltoa_o(sess->listener->luid, tmplog, dst + maxsize - tmplog);
Willy Tarreaub363a1f2013-10-01 10:45:07 +02002075 } else {
Willy Tarreau6c6365f2019-07-17 16:48:18 +02002076 ret = lf_port(tmplog, (struct sockaddr *)conn->src,
Willy Tarreaub363a1f2013-10-01 10:45:07 +02002077 dst + maxsize - tmplog, tmp);
2078 }
William Lallemand5f232402012-04-05 18:02:55 +02002079 }
Willy Tarreaub363a1f2013-10-01 10:45:07 +02002080 else
2081 ret = lf_text_len(tmplog, NULL, 0, dst + maxsize - tmplog, tmp);
2082
William Lallemand5f232402012-04-05 18:02:55 +02002083 if (ret == NULL)
2084 goto out;
2085 tmplog = ret;
2086 last_isspace = 0;
2087 break;
2088
Willy Tarreau2beef582012-12-20 17:22:52 +01002089 case LOG_FMT_FRONTENDIP: // %fi
Willy Tarreau9ad7bd42015-04-03 19:19:59 +02002090 conn = objt_conn(sess->origin);
Willy Tarreau8fa99842019-07-17 11:47:11 +02002091 if (conn && conn_get_dst(conn)) {
Willy Tarreau6c6365f2019-07-17 16:48:18 +02002092 ret = lf_ip(tmplog, (struct sockaddr *)conn->dst, dst + maxsize - tmplog, tmp);
Willy Tarreaub363a1f2013-10-01 10:45:07 +02002093 }
2094 else
2095 ret = lf_text_len(tmplog, NULL, 0, dst + maxsize - tmplog, tmp);
2096
William Lallemand1d705562012-03-12 12:46:41 +01002097 if (ret == NULL)
William Lallemandbddd4fd2012-02-27 11:23:10 +01002098 goto out;
William Lallemand1d705562012-03-12 12:46:41 +01002099 tmplog = ret;
William Lallemandbddd4fd2012-02-27 11:23:10 +01002100 last_isspace = 0;
2101 break;
2102
Willy Tarreau2beef582012-12-20 17:22:52 +01002103 case LOG_FMT_FRONTENDPORT: // %fp
Willy Tarreau9ad7bd42015-04-03 19:19:59 +02002104 conn = objt_conn(sess->origin);
Willy Tarreau8fa99842019-07-17 11:47:11 +02002105 if (conn && conn_get_dst(conn)) {
Willy Tarreau6c6365f2019-07-17 16:48:18 +02002106 if (conn->dst->ss_family == AF_UNIX)
Willy Tarreaufb0afa72015-04-03 14:46:27 +02002107 ret = ltoa_o(sess->listener->luid, tmplog, dst + maxsize - tmplog);
Willy Tarreaub363a1f2013-10-01 10:45:07 +02002108 else
Willy Tarreau6c6365f2019-07-17 16:48:18 +02002109 ret = lf_port(tmplog, (struct sockaddr *)conn->dst, dst + maxsize - tmplog, tmp);
William Lallemand5f232402012-04-05 18:02:55 +02002110 }
Willy Tarreaub363a1f2013-10-01 10:45:07 +02002111 else
2112 ret = lf_text_len(tmplog, NULL, 0, dst + maxsize - tmplog, tmp);
2113
William Lallemand5f232402012-04-05 18:02:55 +02002114 if (ret == NULL)
2115 goto out;
2116 tmplog = ret;
2117 last_isspace = 0;
2118 break;
2119
Willy Tarreau2beef582012-12-20 17:22:52 +01002120 case LOG_FMT_BACKENDIP: // %bi
Willy Tarreau8fa99842019-07-17 11:47:11 +02002121 if (be_conn && conn_get_src(be_conn))
Willy Tarreau6c6365f2019-07-17 16:48:18 +02002122 ret = lf_ip(tmplog, (const struct sockaddr *)be_conn->src, dst + maxsize - tmplog, tmp);
Willy Tarreaub363a1f2013-10-01 10:45:07 +02002123 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 Lallemandb7ff6a32012-03-02 14:35:21 +01002127 goto out;
William Lallemand1d705562012-03-12 12:46:41 +01002128 tmplog = ret;
William Lallemandb7ff6a32012-03-02 14:35:21 +01002129 last_isspace = 0;
2130 break;
2131
Willy Tarreau2beef582012-12-20 17:22:52 +01002132 case LOG_FMT_BACKENDPORT: // %bp
Willy Tarreau8fa99842019-07-17 11:47:11 +02002133 if (be_conn && conn_get_src(be_conn))
Willy Tarreau6c6365f2019-07-17 16:48:18 +02002134 ret = lf_port(tmplog, (struct sockaddr *)be_conn->src, dst + maxsize - tmplog, tmp);
Willy Tarreaub363a1f2013-10-01 10:45:07 +02002135 else
2136 ret = lf_text_len(tmplog, NULL, 0, dst + maxsize - tmplog, tmp);
2137
William Lallemand5f232402012-04-05 18:02:55 +02002138 if (ret == NULL)
2139 goto out;
2140 tmplog = ret;
2141 last_isspace = 0;
2142 break;
2143
Willy Tarreau2beef582012-12-20 17:22:52 +01002144 case LOG_FMT_SERVERIP: // %si
Willy Tarreau8fa99842019-07-17 11:47:11 +02002145 if (be_conn && conn_get_dst(be_conn))
Willy Tarreau6c6365f2019-07-17 16:48:18 +02002146 ret = lf_ip(tmplog, (struct sockaddr *)be_conn->dst, dst + maxsize - tmplog, tmp);
Willy Tarreaub363a1f2013-10-01 10:45:07 +02002147 else
2148 ret = lf_text_len(tmplog, NULL, 0, dst + maxsize - tmplog, tmp);
2149
William Lallemand5f232402012-04-05 18:02:55 +02002150 if (ret == NULL)
2151 goto out;
2152 tmplog = ret;
2153 last_isspace = 0;
2154 break;
2155
Willy Tarreau2beef582012-12-20 17:22:52 +01002156 case LOG_FMT_SERVERPORT: // %sp
Willy Tarreau8fa99842019-07-17 11:47:11 +02002157 if (be_conn && conn_get_dst(be_conn))
Willy Tarreau6c6365f2019-07-17 16:48:18 +02002158 ret = lf_port(tmplog, (struct sockaddr *)be_conn->dst, dst + maxsize - tmplog, tmp);
Willy Tarreaub363a1f2013-10-01 10:45:07 +02002159 else
2160 ret = lf_text_len(tmplog, NULL, 0, dst + maxsize - tmplog, tmp);
2161
William Lallemand1d705562012-03-12 12:46:41 +01002162 if (ret == NULL)
William Lallemandb7ff6a32012-03-02 14:35:21 +01002163 goto out;
William Lallemand1d705562012-03-12 12:46:41 +01002164 tmplog = ret;
William Lallemandb7ff6a32012-03-02 14:35:21 +01002165 last_isspace = 0;
2166 break;
2167
Thierry FOURNIER / OZON.IO4cac3592016-07-28 17:19:45 +02002168 case LOG_FMT_DATE: // %t = accept date
Willy Tarreau372ac5a2018-09-05 15:16:23 +02002169 get_localtime(logs->accept_date.tv_sec, &tm);
2170 ret = date2str_log(tmplog, &tm, &logs->accept_date, dst + maxsize - tmplog);
William Lallemand1d705562012-03-12 12:46:41 +01002171 if (ret == NULL)
William Lallemandbddd4fd2012-02-27 11:23:10 +01002172 goto out;
William Lallemand1d705562012-03-12 12:46:41 +01002173 tmplog = ret;
William Lallemandbddd4fd2012-02-27 11:23:10 +01002174 last_isspace = 0;
2175 break;
2176
Thierry FOURNIER / OZON.IO4cac3592016-07-28 17:19:45 +02002177 case LOG_FMT_tr: // %tr = start of request date
2178 /* Note that the timers are valid if we get here */
Willy Tarreau372ac5a2018-09-05 15:16:23 +02002179 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 +02002180 get_localtime(tv.tv_sec, &tm);
2181 ret = date2str_log(tmplog, &tm, &tv, dst + maxsize - tmplog);
2182 if (ret == NULL)
2183 goto out;
2184 tmplog = ret;
2185 last_isspace = 0;
2186 break;
2187
2188 case LOG_FMT_DATEGMT: // %T = accept date, GMT
Willy Tarreau372ac5a2018-09-05 15:16:23 +02002189 get_gmtime(logs->accept_date.tv_sec, &tm);
William Lallemand5f232402012-04-05 18:02:55 +02002190 ret = gmt2str_log(tmplog, &tm, dst + maxsize - tmplog);
William Lallemand1d705562012-03-12 12:46:41 +01002191 if (ret == NULL)
William Lallemandbddd4fd2012-02-27 11:23:10 +01002192 goto out;
William Lallemand1d705562012-03-12 12:46:41 +01002193 tmplog = ret;
William Lallemandbddd4fd2012-02-27 11:23:10 +01002194 last_isspace = 0;
2195 break;
2196
Thierry FOURNIER / OZON.IO4cac3592016-07-28 17:19:45 +02002197 case LOG_FMT_trg: // %trg = start of request date, GMT
Willy Tarreau372ac5a2018-09-05 15:16:23 +02002198 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 +02002199 get_gmtime(tv.tv_sec, &tm);
2200 ret = gmt2str_log(tmplog, &tm, dst + maxsize - tmplog);
2201 if (ret == NULL)
2202 goto out;
2203 tmplog = ret;
2204 last_isspace = 0;
2205 break;
2206
2207 case LOG_FMT_DATELOCAL: // %Tl = accept date, local
Willy Tarreau372ac5a2018-09-05 15:16:23 +02002208 get_localtime(logs->accept_date.tv_sec, &tm);
2209 ret = localdate2str_log(tmplog, logs->accept_date.tv_sec, &tm, dst + maxsize - tmplog);
Yuxans Yao4e25b012012-10-19 10:36:09 +08002210 if (ret == NULL)
2211 goto out;
2212 tmplog = ret;
2213 last_isspace = 0;
2214 break;
2215
Thierry FOURNIER / OZON.IO4cac3592016-07-28 17:19:45 +02002216 case LOG_FMT_trl: // %trl = start of request date, local
Willy Tarreau372ac5a2018-09-05 15:16:23 +02002217 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 +02002218 get_localtime(tv.tv_sec, &tm);
2219 ret = localdate2str_log(tmplog, tv.tv_sec, &tm, dst + maxsize - tmplog);
2220 if (ret == NULL)
2221 goto out;
2222 tmplog = ret;
2223 last_isspace = 0;
2224 break;
2225
William Lallemand5f232402012-04-05 18:02:55 +02002226 case LOG_FMT_TS: // %Ts
William Lallemand5f232402012-04-05 18:02:55 +02002227 if (tmp->options & LOG_OPT_HEXA) {
Willy Tarreau372ac5a2018-09-05 15:16:23 +02002228 iret = snprintf(tmplog, dst + maxsize - tmplog, "%04X", (unsigned int)logs->accept_date.tv_sec);
William Lallemand5f232402012-04-05 18:02:55 +02002229 if (iret < 0 || iret > dst + maxsize - tmplog)
2230 goto out;
2231 last_isspace = 0;
2232 tmplog += iret;
2233 } else {
Willy Tarreau372ac5a2018-09-05 15:16:23 +02002234 ret = ltoa_o(logs->accept_date.tv_sec, tmplog, dst + maxsize - tmplog);
William Lallemand5f232402012-04-05 18:02:55 +02002235 if (ret == NULL)
2236 goto out;
2237 tmplog = ret;
2238 last_isspace = 0;
2239 }
2240 break;
2241
William Lallemand1d705562012-03-12 12:46:41 +01002242 case LOG_FMT_MS: // %ms
William Lallemand5f232402012-04-05 18:02:55 +02002243 if (tmp->options & LOG_OPT_HEXA) {
Willy Tarreau372ac5a2018-09-05 15:16:23 +02002244 iret = snprintf(tmplog, dst + maxsize - tmplog, "%02X",(unsigned int)logs->accept_date.tv_usec/1000);
William Lallemand5f232402012-04-05 18:02:55 +02002245 if (iret < 0 || iret > dst + maxsize - tmplog)
2246 goto out;
2247 last_isspace = 0;
2248 tmplog += iret;
2249 } else {
2250 if ((dst + maxsize - tmplog) < 4)
William Lallemandbddd4fd2012-02-27 11:23:10 +01002251 goto out;
Willy Tarreau372ac5a2018-09-05 15:16:23 +02002252 ret = utoa_pad((unsigned int)logs->accept_date.tv_usec/1000,
Willy Tarreau9e60cd82013-01-24 01:18:16 +01002253 tmplog, 4);
2254 if (ret == NULL)
William Lallemand51b5dca2012-03-26 17:52:55 +02002255 goto out;
Willy Tarreau9e60cd82013-01-24 01:18:16 +01002256 tmplog = ret;
William Lallemandbddd4fd2012-02-27 11:23:10 +01002257 last_isspace = 0;
William Lallemand5f232402012-04-05 18:02:55 +02002258 }
2259 break;
William Lallemandbddd4fd2012-02-27 11:23:10 +01002260
William Lallemand1d705562012-03-12 12:46:41 +01002261 case LOG_FMT_FRONTEND: // %f
William Lallemandbddd4fd2012-02-27 11:23:10 +01002262 src = fe->id;
William Lallemand5f232402012-04-05 18:02:55 +02002263 ret = lf_text(tmplog, src, dst + maxsize - tmplog, tmp);
William Lallemand1d705562012-03-12 12:46:41 +01002264 if (ret == NULL)
William Lallemandbddd4fd2012-02-27 11:23:10 +01002265 goto out;
William Lallemand1d705562012-03-12 12:46:41 +01002266 tmplog = ret;
William Lallemand51b5dca2012-03-26 17:52:55 +02002267 last_isspace = 0;
William Lallemandbddd4fd2012-02-27 11:23:10 +01002268 break;
2269
Willy Tarreau773d65f2012-10-12 14:56:11 +02002270 case LOG_FMT_FRONTEND_XPRT: // %ft
2271 src = fe->id;
2272 if (tmp->options & LOG_OPT_QUOTE)
2273 LOGCHAR('"');
2274 iret = strlcpy2(tmplog, src, dst + maxsize - tmplog);
2275 if (iret == 0)
2276 goto out;
2277 tmplog += iret;
Willy Tarreaua261e9b2016-12-22 20:44:00 +01002278 if (sess->listener->bind_conf->xprt == xprt_get(XPRT_SSL))
Willy Tarreau773d65f2012-10-12 14:56:11 +02002279 LOGCHAR('~');
Willy Tarreau773d65f2012-10-12 14:56:11 +02002280 if (tmp->options & LOG_OPT_QUOTE)
2281 LOGCHAR('"');
2282 last_isspace = 0;
2283 break;
Willy Tarreauffc3fcd2012-10-12 20:17:54 +02002284#ifdef USE_OPENSSL
2285 case LOG_FMT_SSL_CIPHER: // %sslc
2286 src = NULL;
Willy Tarreau9ad7bd42015-04-03 19:19:59 +02002287 conn = objt_conn(sess->origin);
Willy Tarreaub363a1f2013-10-01 10:45:07 +02002288 if (conn) {
Emmanuel Hocdet01da5712017-10-13 16:59:49 +02002289 src = ssl_sock_get_cipher_name(conn);
Willy Tarreaub363a1f2013-10-01 10:45:07 +02002290 }
Willy Tarreauffc3fcd2012-10-12 20:17:54 +02002291 ret = lf_text(tmplog, src, dst + maxsize - tmplog, tmp);
2292 if (ret == NULL)
2293 goto out;
2294 tmplog = ret;
2295 last_isspace = 0;
2296 break;
Willy Tarreau773d65f2012-10-12 14:56:11 +02002297
Willy Tarreauffc3fcd2012-10-12 20:17:54 +02002298 case LOG_FMT_SSL_VERSION: // %sslv
2299 src = NULL;
Willy Tarreau9ad7bd42015-04-03 19:19:59 +02002300 conn = objt_conn(sess->origin);
Willy Tarreaub363a1f2013-10-01 10:45:07 +02002301 if (conn) {
Emmanuel Hocdet01da5712017-10-13 16:59:49 +02002302 src = ssl_sock_get_proto_version(conn);
Willy Tarreaub363a1f2013-10-01 10:45:07 +02002303 }
Willy Tarreauffc3fcd2012-10-12 20:17:54 +02002304 ret = lf_text(tmplog, src, dst + maxsize - tmplog, tmp);
2305 if (ret == NULL)
2306 goto out;
2307 tmplog = ret;
2308 last_isspace = 0;
2309 break;
2310#endif
William Lallemand1d705562012-03-12 12:46:41 +01002311 case LOG_FMT_BACKEND: // %b
William Lallemandbddd4fd2012-02-27 11:23:10 +01002312 src = be->id;
William Lallemand5f232402012-04-05 18:02:55 +02002313 ret = lf_text(tmplog, src, dst + maxsize - tmplog, tmp);
William Lallemand1d705562012-03-12 12:46:41 +01002314 if (ret == NULL)
William Lallemandbddd4fd2012-02-27 11:23:10 +01002315 goto out;
William Lallemand1d705562012-03-12 12:46:41 +01002316 tmplog = ret;
William Lallemand51b5dca2012-03-26 17:52:55 +02002317 last_isspace = 0;
William Lallemandbddd4fd2012-02-27 11:23:10 +01002318 break;
2319
William Lallemand1d705562012-03-12 12:46:41 +01002320 case LOG_FMT_SERVER: // %s
Willy Tarreaue1809df2018-09-05 15:30:16 +02002321 switch (obj_type(s ? s->target : NULL)) {
Willy Tarreaud79a3b22012-12-28 09:40:16 +01002322 case OBJ_TYPE_SERVER:
Willy Tarreau1aaf3242018-09-20 11:13:58 +02002323 src = __objt_server(s->target)->id;
Willy Tarreaud79a3b22012-12-28 09:40:16 +01002324 break;
2325 case OBJ_TYPE_APPLET:
Willy Tarreau1aaf3242018-09-20 11:13:58 +02002326 src = __objt_applet(s->target)->name;
Willy Tarreaud79a3b22012-12-28 09:40:16 +01002327 break;
2328 default:
2329 src = "<NOSRV>";
2330 break;
2331 }
William Lallemand5f232402012-04-05 18:02:55 +02002332 ret = lf_text(tmplog, src, dst + maxsize - tmplog, tmp);
William Lallemand1d705562012-03-12 12:46:41 +01002333 if (ret == NULL)
William Lallemandbddd4fd2012-02-27 11:23:10 +01002334 goto out;
William Lallemand1d705562012-03-12 12:46:41 +01002335 tmplog = ret;
William Lallemandbddd4fd2012-02-27 11:23:10 +01002336 last_isspace = 0;
2337 break;
2338
Thierry FOURNIER / OZON.IO4cac3592016-07-28 17:19:45 +02002339 case LOG_FMT_Th: // %Th = handshake time
Willy Tarreau372ac5a2018-09-05 15:16:23 +02002340 ret = ltoa_o(logs->t_handshake, tmplog, dst + maxsize - tmplog);
Thierry FOURNIER / OZON.IO4cac3592016-07-28 17:19:45 +02002341 if (ret == NULL)
2342 goto out;
2343 tmplog = ret;
2344 last_isspace = 0;
2345 break;
2346
2347 case LOG_FMT_Ti: // %Ti = HTTP idle time
Willy Tarreau372ac5a2018-09-05 15:16:23 +02002348 ret = ltoa_o(logs->t_idle, tmplog, dst + maxsize - tmplog);
Thierry FOURNIER / OZON.IO4cac3592016-07-28 17:19:45 +02002349 if (ret == NULL)
2350 goto out;
2351 tmplog = ret;
2352 last_isspace = 0;
2353 break;
2354
2355 case LOG_FMT_TR: // %TR = HTTP request time
Willy Tarreau372ac5a2018-09-05 15:16:23 +02002356 ret = ltoa_o((t_request >= 0) ? t_request - logs->t_idle - logs->t_handshake : -1,
Thierry FOURNIER / OZON.IO4cac3592016-07-28 17:19:45 +02002357 tmplog, dst + maxsize - tmplog);
2358 if (ret == NULL)
2359 goto out;
2360 tmplog = ret;
2361 last_isspace = 0;
2362 break;
2363
2364 case LOG_FMT_TQ: // %Tq = Th + Ti + TR
William Lallemand5f232402012-04-05 18:02:55 +02002365 ret = ltoa_o(t_request, tmplog, dst + maxsize - tmplog);
William Lallemand1d705562012-03-12 12:46:41 +01002366 if (ret == NULL)
William Lallemandbddd4fd2012-02-27 11:23:10 +01002367 goto out;
William Lallemand1d705562012-03-12 12:46:41 +01002368 tmplog = ret;
William Lallemandbddd4fd2012-02-27 11:23:10 +01002369 last_isspace = 0;
2370 break;
2371
William Lallemand1d705562012-03-12 12:46:41 +01002372 case LOG_FMT_TW: // %Tw
Willy Tarreau372ac5a2018-09-05 15:16:23 +02002373 ret = ltoa_o((logs->t_queue >= 0) ? logs->t_queue - t_request : -1,
William Lallemand5f232402012-04-05 18:02:55 +02002374 tmplog, dst + maxsize - tmplog);
William Lallemand1d705562012-03-12 12:46:41 +01002375 if (ret == NULL)
William Lallemandbddd4fd2012-02-27 11:23:10 +01002376 goto out;
William Lallemand1d705562012-03-12 12:46:41 +01002377 tmplog = ret;
William Lallemandbddd4fd2012-02-27 11:23:10 +01002378 last_isspace = 0;
2379 break;
2380
William Lallemand1d705562012-03-12 12:46:41 +01002381 case LOG_FMT_TC: // %Tc
Willy Tarreau372ac5a2018-09-05 15:16:23 +02002382 ret = ltoa_o((logs->t_connect >= 0) ? logs->t_connect - logs->t_queue : -1,
William Lallemand5f232402012-04-05 18:02:55 +02002383 tmplog, dst + maxsize - tmplog);
William Lallemand1d705562012-03-12 12:46:41 +01002384 if (ret == NULL)
William Lallemandbddd4fd2012-02-27 11:23:10 +01002385 goto out;
William Lallemand1d705562012-03-12 12:46:41 +01002386 tmplog = ret;
William Lallemandbddd4fd2012-02-27 11:23:10 +01002387 last_isspace = 0;
2388 break;
2389
Thierry FOURNIER / OZON.IO4cac3592016-07-28 17:19:45 +02002390 case LOG_FMT_Tr: // %Tr
Willy Tarreau372ac5a2018-09-05 15:16:23 +02002391 ret = ltoa_o((logs->t_data >= 0) ? logs->t_data - logs->t_connect : -1,
William Lallemand5f232402012-04-05 18:02:55 +02002392 tmplog, dst + maxsize - tmplog);
William Lallemand1d705562012-03-12 12:46:41 +01002393 if (ret == NULL)
William Lallemandbddd4fd2012-02-27 11:23:10 +01002394 goto out;
William Lallemand1d705562012-03-12 12:46:41 +01002395 tmplog = ret;
William Lallemandbddd4fd2012-02-27 11:23:10 +01002396 last_isspace = 0;
2397 break;
2398
Willy Tarreau27b639d2016-05-17 17:55:27 +02002399 case LOG_FMT_TD: // %Td
Willy Tarreaua21c0e62018-09-05 15:07:15 +02002400 if (be->mode == PR_MODE_HTTP)
Willy Tarreau372ac5a2018-09-05 15:16:23 +02002401 ret = ltoa_o((logs->t_data >= 0) ? logs->t_close - logs->t_data : -1,
Willy Tarreau27b639d2016-05-17 17:55:27 +02002402 tmplog, dst + maxsize - tmplog);
2403 else
Willy Tarreau372ac5a2018-09-05 15:16:23 +02002404 ret = ltoa_o((logs->t_connect >= 0) ? logs->t_close - logs->t_connect : -1,
Willy Tarreau27b639d2016-05-17 17:55:27 +02002405 tmplog, dst + maxsize - tmplog);
2406 if (ret == NULL)
2407 goto out;
2408 tmplog = ret;
2409 last_isspace = 0;
2410 break;
2411
Thierry FOURNIER / OZON.IO4cac3592016-07-28 17:19:45 +02002412 case LOG_FMT_Ta: // %Ta = active time = Tt - Th - Ti
2413 if (!(fe->to_log & LW_BYTES))
2414 LOGCHAR('+');
Willy Tarreau372ac5a2018-09-05 15:16:23 +02002415 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 +02002416 tmplog, dst + maxsize - tmplog);
2417 if (ret == NULL)
2418 goto out;
2419 tmplog = ret;
2420 last_isspace = 0;
2421 break;
2422
2423 case LOG_FMT_TT: // %Tt = total time
Willy Tarreaud79a3b22012-12-28 09:40:16 +01002424 if (!(fe->to_log & LW_BYTES))
William Lallemand1d705562012-03-12 12:46:41 +01002425 LOGCHAR('+');
Willy Tarreau372ac5a2018-09-05 15:16:23 +02002426 ret = ltoa_o(logs->t_close, tmplog, dst + maxsize - tmplog);
William Lallemand1d705562012-03-12 12:46:41 +01002427 if (ret == NULL)
William Lallemandbddd4fd2012-02-27 11:23:10 +01002428 goto out;
William Lallemand1d705562012-03-12 12:46:41 +01002429 tmplog = ret;
William Lallemandbddd4fd2012-02-27 11:23:10 +01002430 last_isspace = 0;
2431 break;
2432
Willy Tarreau2beef582012-12-20 17:22:52 +01002433 case LOG_FMT_STATUS: // %ST
Willy Tarreau57bc8912016-04-25 17:09:40 +02002434 ret = ltoa_o(txn ? txn->status : 0, tmplog, dst + maxsize - tmplog);
William Lallemand1d705562012-03-12 12:46:41 +01002435 if (ret == NULL)
William Lallemandbddd4fd2012-02-27 11:23:10 +01002436 goto out;
William Lallemand1d705562012-03-12 12:46:41 +01002437 tmplog = ret;
William Lallemandbddd4fd2012-02-27 11:23:10 +01002438 last_isspace = 0;
2439 break;
2440
William Lallemand1d705562012-03-12 12:46:41 +01002441 case LOG_FMT_BYTES: // %B
Willy Tarreaud79a3b22012-12-28 09:40:16 +01002442 if (!(fe->to_log & LW_BYTES))
William Lallemand1d705562012-03-12 12:46:41 +01002443 LOGCHAR('+');
Willy Tarreau372ac5a2018-09-05 15:16:23 +02002444 ret = lltoa(logs->bytes_out, tmplog, dst + maxsize - tmplog);
William Lallemand1d705562012-03-12 12:46:41 +01002445 if (ret == NULL)
William Lallemandbddd4fd2012-02-27 11:23:10 +01002446 goto out;
William Lallemand1d705562012-03-12 12:46:41 +01002447 tmplog = ret;
William Lallemandbddd4fd2012-02-27 11:23:10 +01002448 last_isspace = 0;
2449 break;
2450
Willy Tarreauc5259fd2012-12-20 15:38:04 +01002451 case LOG_FMT_BYTES_UP: // %U
Willy Tarreau372ac5a2018-09-05 15:16:23 +02002452 ret = lltoa(logs->bytes_in, tmplog, dst + maxsize - tmplog);
Willy Tarreauc5259fd2012-12-20 15:38:04 +01002453 if (ret == NULL)
2454 goto out;
2455 tmplog = ret;
2456 last_isspace = 0;
2457 break;
2458
Willy Tarreau2beef582012-12-20 17:22:52 +01002459 case LOG_FMT_CCLIENT: // %CC
Willy Tarreau57bc8912016-04-25 17:09:40 +02002460 src = txn ? txn->cli_cookie : NULL;
William Lallemand5f232402012-04-05 18:02:55 +02002461 ret = lf_text(tmplog, src, dst + maxsize - tmplog, tmp);
William Lallemand1d705562012-03-12 12:46:41 +01002462 if (ret == NULL)
William Lallemand51b5dca2012-03-26 17:52:55 +02002463 goto out;
William Lallemand1d705562012-03-12 12:46:41 +01002464 tmplog = ret;
William Lallemandbddd4fd2012-02-27 11:23:10 +01002465 last_isspace = 0;
2466 break;
2467
Willy Tarreau2beef582012-12-20 17:22:52 +01002468 case LOG_FMT_CSERVER: // %CS
Willy Tarreau57bc8912016-04-25 17:09:40 +02002469 src = txn ? txn->srv_cookie : NULL;
William Lallemand5f232402012-04-05 18:02:55 +02002470 ret = lf_text(tmplog, src, dst + maxsize - tmplog, tmp);
William Lallemand1d705562012-03-12 12:46:41 +01002471 if (ret == NULL)
William Lallemand51b5dca2012-03-26 17:52:55 +02002472 goto out;
William Lallemand1d705562012-03-12 12:46:41 +01002473 tmplog = ret;
William Lallemandbddd4fd2012-02-27 11:23:10 +01002474 last_isspace = 0;
2475 break;
2476
William Lallemand1d705562012-03-12 12:46:41 +01002477 case LOG_FMT_TERMSTATE: // %ts
Willy Tarreaub8bc5252018-09-05 15:51:28 +02002478 LOGCHAR(sess_term_cond[(s_flags & SF_ERR_MASK) >> SF_ERR_SHIFT]);
2479 LOGCHAR(sess_fin_state[(s_flags & SF_FINST_MASK) >> SF_FINST_SHIFT]);
Willy Tarreau6580c062012-03-12 15:09:42 +01002480 *tmplog = '\0';
2481 last_isspace = 0;
2482 break;
William Lallemandbddd4fd2012-02-27 11:23:10 +01002483
William Lallemand1d705562012-03-12 12:46:41 +01002484 case LOG_FMT_TERMSTATE_CK: // %tsc, same as TS with cookie state (for mode HTTP)
Willy Tarreaub8bc5252018-09-05 15:51:28 +02002485 LOGCHAR(sess_term_cond[(s_flags & SF_ERR_MASK) >> SF_ERR_SHIFT]);
2486 LOGCHAR(sess_fin_state[(s_flags & SF_FINST_MASK) >> SF_FINST_SHIFT]);
Willy Tarreau57bc8912016-04-25 17:09:40 +02002487 LOGCHAR((txn && (be->ck_opts & PR_CK_ANY)) ? sess_cookie[(txn->flags & TX_CK_MASK) >> TX_CK_SHIFT] : '-');
2488 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 +01002489 last_isspace = 0;
2490 break;
2491
William Lallemand1d705562012-03-12 12:46:41 +01002492 case LOG_FMT_ACTCONN: // %ac
William Lallemand5f232402012-04-05 18:02:55 +02002493 ret = ltoa_o(actconn, tmplog, dst + maxsize - tmplog);
William Lallemand1d705562012-03-12 12:46:41 +01002494 if (ret == NULL)
William Lallemandbddd4fd2012-02-27 11:23:10 +01002495 goto out;
William Lallemand1d705562012-03-12 12:46:41 +01002496 tmplog = ret;
William Lallemandbddd4fd2012-02-27 11:23:10 +01002497 last_isspace = 0;
2498 break;
2499
William Lallemand1d705562012-03-12 12:46:41 +01002500 case LOG_FMT_FECONN: // %fc
William Lallemand5f232402012-04-05 18:02:55 +02002501 ret = ltoa_o(fe->feconn, tmplog, dst + maxsize - tmplog);
William Lallemand1d705562012-03-12 12:46:41 +01002502 if (ret == NULL)
William Lallemandbddd4fd2012-02-27 11:23:10 +01002503 goto out;
William Lallemand1d705562012-03-12 12:46:41 +01002504 tmplog = ret;
William Lallemandbddd4fd2012-02-27 11:23:10 +01002505 last_isspace = 0;
2506 break;
2507
William Lallemand1d705562012-03-12 12:46:41 +01002508 case LOG_FMT_BECONN: // %bc
William Lallemand5f232402012-04-05 18:02:55 +02002509 ret = ltoa_o(be->beconn, tmplog, dst + maxsize - tmplog);
William Lallemand1d705562012-03-12 12:46:41 +01002510 if (ret == NULL)
William Lallemandbddd4fd2012-02-27 11:23:10 +01002511 goto out;
William Lallemand1d705562012-03-12 12:46:41 +01002512 tmplog = ret;
William Lallemandbddd4fd2012-02-27 11:23:10 +01002513 last_isspace = 0;
2514 break;
2515
William Lallemand1d705562012-03-12 12:46:41 +01002516 case LOG_FMT_SRVCONN: // %sc
Willy Tarreaue1809df2018-09-05 15:30:16 +02002517 ret = ultoa_o(objt_server(s ? s->target : NULL) ?
Willy Tarreau3fdb3662012-11-12 00:42:33 +01002518 objt_server(s->target)->cur_sess :
William Lallemand5f232402012-04-05 18:02:55 +02002519 0, tmplog, dst + maxsize - tmplog);
William Lallemand1d705562012-03-12 12:46:41 +01002520 if (ret == NULL)
William Lallemandbddd4fd2012-02-27 11:23:10 +01002521 goto out;
William Lallemand1d705562012-03-12 12:46:41 +01002522 tmplog = ret;
William Lallemandbddd4fd2012-02-27 11:23:10 +01002523 last_isspace = 0;
2524 break;
2525
William Lallemand1d705562012-03-12 12:46:41 +01002526 case LOG_FMT_RETRIES: // %rq
Willy Tarreaub8bc5252018-09-05 15:51:28 +02002527 if (s_flags & SF_REDISP)
William Lallemand1d705562012-03-12 12:46:41 +01002528 LOGCHAR('+');
Willy Tarreauabd71a52018-09-04 19:21:44 +02002529 ret = ltoa_o((s && s->si[1].conn_retries > 0) ?
Willy Tarreau350f4872014-11-28 14:42:25 +01002530 (be->conn_retries - s->si[1].conn_retries) :
William Lallemand5f232402012-04-05 18:02:55 +02002531 be->conn_retries, tmplog, dst + maxsize - tmplog);
William Lallemand1d705562012-03-12 12:46:41 +01002532 if (ret == NULL)
William Lallemand51b5dca2012-03-26 17:52:55 +02002533 goto out;
William Lallemand1d705562012-03-12 12:46:41 +01002534 tmplog = ret;
William Lallemandbddd4fd2012-02-27 11:23:10 +01002535 last_isspace = 0;
2536 break;
2537
William Lallemand1d705562012-03-12 12:46:41 +01002538 case LOG_FMT_SRVQUEUE: // %sq
Willy Tarreau372ac5a2018-09-05 15:16:23 +02002539 ret = ltoa_o(logs->srv_queue_pos, tmplog, dst + maxsize - tmplog);
William Lallemand1d705562012-03-12 12:46:41 +01002540 if (ret == NULL)
William Lallemandbddd4fd2012-02-27 11:23:10 +01002541 goto out;
William Lallemand1d705562012-03-12 12:46:41 +01002542 tmplog = ret;
William Lallemandbddd4fd2012-02-27 11:23:10 +01002543 last_isspace = 0;
2544 break;
2545
William Lallemand1d705562012-03-12 12:46:41 +01002546 case LOG_FMT_BCKQUEUE: // %bq
Willy Tarreau372ac5a2018-09-05 15:16:23 +02002547 ret = ltoa_o(logs->prx_queue_pos, tmplog, dst + maxsize - tmplog);
William Lallemand1d705562012-03-12 12:46:41 +01002548 if (ret == NULL)
William Lallemandbddd4fd2012-02-27 11:23:10 +01002549 goto out;
William Lallemand1d705562012-03-12 12:46:41 +01002550 tmplog = ret;
William Lallemandbddd4fd2012-02-27 11:23:10 +01002551 last_isspace = 0;
2552 break;
2553
William Lallemand1d705562012-03-12 12:46:41 +01002554 case LOG_FMT_HDRREQUEST: // %hr
William Lallemandbddd4fd2012-02-27 11:23:10 +01002555 /* request header */
Willy Tarreaud4f91662018-09-05 15:28:07 +02002556 if (fe->nb_req_cap && s && s->req_cap) {
William Lallemandbddd4fd2012-02-27 11:23:10 +01002557 if (tmp->options & LOG_OPT_QUOTE)
2558 LOGCHAR('"');
2559 LOGCHAR('{');
2560 for (hdr = 0; hdr < fe->nb_req_cap; hdr++) {
2561 if (hdr)
2562 LOGCHAR('|');
Willy Tarreaucb7dd012015-04-03 22:16:32 +02002563 if (s->req_cap[hdr] != NULL) {
Dragan Dosen835b9212016-02-12 13:23:03 +01002564 ret = lf_encode_string(tmplog, dst + maxsize,
2565 '#', hdr_encode_map, s->req_cap[hdr], tmp);
William Lallemand1d705562012-03-12 12:46:41 +01002566 if (ret == NULL || *ret != '\0')
William Lallemand51b5dca2012-03-26 17:52:55 +02002567 goto out;
William Lallemand1d705562012-03-12 12:46:41 +01002568 tmplog = ret;
William Lallemand51b5dca2012-03-26 17:52:55 +02002569 }
William Lallemandbddd4fd2012-02-27 11:23:10 +01002570 }
2571 LOGCHAR('}');
William Lallemand51b5dca2012-03-26 17:52:55 +02002572 if (tmp->options & LOG_OPT_QUOTE)
2573 LOGCHAR('"');
William Lallemandbddd4fd2012-02-27 11:23:10 +01002574 last_isspace = 0;
2575 }
William Lallemandbddd4fd2012-02-27 11:23:10 +01002576 break;
2577
William Lallemand1d705562012-03-12 12:46:41 +01002578 case LOG_FMT_HDRREQUESTLIST: // %hrl
William Lallemandbddd4fd2012-02-27 11:23:10 +01002579 /* request header list */
Willy Tarreaud4f91662018-09-05 15:28:07 +02002580 if (fe->nb_req_cap && s && s->req_cap) {
William Lallemandbddd4fd2012-02-27 11:23:10 +01002581 for (hdr = 0; hdr < fe->nb_req_cap; hdr++) {
2582 if (hdr > 0)
2583 LOGCHAR(' ');
2584 if (tmp->options & LOG_OPT_QUOTE)
2585 LOGCHAR('"');
Willy Tarreaucb7dd012015-04-03 22:16:32 +02002586 if (s->req_cap[hdr] != NULL) {
Dragan Dosen835b9212016-02-12 13:23:03 +01002587 ret = lf_encode_string(tmplog, dst + maxsize,
2588 '#', hdr_encode_map, s->req_cap[hdr], tmp);
William Lallemand1d705562012-03-12 12:46:41 +01002589 if (ret == NULL || *ret != '\0')
William Lallemand51b5dca2012-03-26 17:52:55 +02002590 goto out;
William Lallemand1d705562012-03-12 12:46:41 +01002591 tmplog = ret;
William Lallemandbddd4fd2012-02-27 11:23:10 +01002592 } else if (!(tmp->options & LOG_OPT_QUOTE))
2593 LOGCHAR('-');
2594 if (tmp->options & LOG_OPT_QUOTE)
2595 LOGCHAR('"');
William Lallemandbddd4fd2012-02-27 11:23:10 +01002596 last_isspace = 0;
2597 }
2598 }
2599 break;
Willy Tarreaubaaee002006-06-26 02:48:02 +02002600
William Lallemand1d705562012-03-12 12:46:41 +01002601
2602 case LOG_FMT_HDRRESPONS: // %hs
William Lallemandbddd4fd2012-02-27 11:23:10 +01002603 /* response header */
Willy Tarreaud4f91662018-09-05 15:28:07 +02002604 if (fe->nb_rsp_cap && s && s->res_cap) {
William Lallemandbddd4fd2012-02-27 11:23:10 +01002605 if (tmp->options & LOG_OPT_QUOTE)
2606 LOGCHAR('"');
2607 LOGCHAR('{');
2608 for (hdr = 0; hdr < fe->nb_rsp_cap; hdr++) {
2609 if (hdr)
2610 LOGCHAR('|');
Willy Tarreaucb7dd012015-04-03 22:16:32 +02002611 if (s->res_cap[hdr] != NULL) {
Dragan Dosen835b9212016-02-12 13:23:03 +01002612 ret = lf_encode_string(tmplog, dst + maxsize,
2613 '#', hdr_encode_map, s->res_cap[hdr], tmp);
William Lallemand1d705562012-03-12 12:46:41 +01002614 if (ret == NULL || *ret != '\0')
William Lallemand51b5dca2012-03-26 17:52:55 +02002615 goto out;
William Lallemand1d705562012-03-12 12:46:41 +01002616 tmplog = ret;
William Lallemand51b5dca2012-03-26 17:52:55 +02002617 }
William Lallemandbddd4fd2012-02-27 11:23:10 +01002618 }
2619 LOGCHAR('}');
2620 last_isspace = 0;
2621 if (tmp->options & LOG_OPT_QUOTE)
2622 LOGCHAR('"');
2623 }
William Lallemandbddd4fd2012-02-27 11:23:10 +01002624 break;
2625
William Lallemand1d705562012-03-12 12:46:41 +01002626 case LOG_FMT_HDRRESPONSLIST: // %hsl
William Lallemandbddd4fd2012-02-27 11:23:10 +01002627 /* response header list */
Willy Tarreaud4f91662018-09-05 15:28:07 +02002628 if (fe->nb_rsp_cap && s && s->res_cap) {
William Lallemandbddd4fd2012-02-27 11:23:10 +01002629 for (hdr = 0; hdr < fe->nb_rsp_cap; hdr++) {
2630 if (hdr > 0)
2631 LOGCHAR(' ');
2632 if (tmp->options & LOG_OPT_QUOTE)
2633 LOGCHAR('"');
Willy Tarreaucb7dd012015-04-03 22:16:32 +02002634 if (s->res_cap[hdr] != NULL) {
Dragan Dosen835b9212016-02-12 13:23:03 +01002635 ret = lf_encode_string(tmplog, dst + maxsize,
2636 '#', hdr_encode_map, s->res_cap[hdr], tmp);
William Lallemand1d705562012-03-12 12:46:41 +01002637 if (ret == NULL || *ret != '\0')
William Lallemand51b5dca2012-03-26 17:52:55 +02002638 goto out;
William Lallemand1d705562012-03-12 12:46:41 +01002639 tmplog = ret;
William Lallemandbddd4fd2012-02-27 11:23:10 +01002640 } else if (!(tmp->options & LOG_OPT_QUOTE))
2641 LOGCHAR('-');
2642 if (tmp->options & LOG_OPT_QUOTE)
2643 LOGCHAR('"');
William Lallemandbddd4fd2012-02-27 11:23:10 +01002644 last_isspace = 0;
2645 }
2646 }
2647 break;
2648
William Lallemand1d705562012-03-12 12:46:41 +01002649 case LOG_FMT_REQ: // %r
William Lallemandbddd4fd2012-02-27 11:23:10 +01002650 /* Request */
2651 if (tmp->options & LOG_OPT_QUOTE)
2652 LOGCHAR('"');
Willy Tarreau57bc8912016-04-25 17:09:40 +02002653 uri = txn && txn->uri ? txn->uri : "<BADREQ>";
Dragan Dosen835b9212016-02-12 13:23:03 +01002654 ret = lf_encode_string(tmplog, dst + maxsize,
2655 '#', url_encode_map, uri, tmp);
William Lallemand1d705562012-03-12 12:46:41 +01002656 if (ret == NULL || *ret != '\0')
William Lallemand51b5dca2012-03-26 17:52:55 +02002657 goto out;
William Lallemand1d705562012-03-12 12:46:41 +01002658 tmplog = ret;
William Lallemandbddd4fd2012-02-27 11:23:10 +01002659 if (tmp->options & LOG_OPT_QUOTE)
2660 LOGCHAR('"');
William Lallemandbddd4fd2012-02-27 11:23:10 +01002661 last_isspace = 0;
2662 break;
William Lallemand5f232402012-04-05 18:02:55 +02002663
Andrew Hayworth0ebc55f2015-04-27 21:37:03 +00002664 case LOG_FMT_HTTP_PATH: // %HP
Willy Tarreau57bc8912016-04-25 17:09:40 +02002665 uri = txn && txn->uri ? txn->uri : "<BADREQ>";
Andrew Hayworth0ebc55f2015-04-27 21:37:03 +00002666
Willy Tarreaub7636d12015-06-17 19:58:02 +02002667 if (tmp->options & LOG_OPT_QUOTE)
Andrew Hayworth0ebc55f2015-04-27 21:37:03 +00002668 LOGCHAR('"');
2669
2670 end = uri + strlen(uri);
2671 // look for the first whitespace character
2672 while (uri < end && !HTTP_IS_SPHT(*uri))
2673 uri++;
2674
2675 // keep advancing past multiple spaces
2676 while (uri < end && HTTP_IS_SPHT(*uri)) {
2677 uri++; nspaces++;
2678 }
2679
2680 // look for first space or question mark after url
2681 spc = uri;
2682 while (spc < end && *spc != '?' && !HTTP_IS_SPHT(*spc))
2683 spc++;
2684
Nenad Merdanovic54e439f2016-04-26 01:39:02 +02002685 if (!txn || !txn->uri || nspaces == 0) {
Willy Tarreau843b7cb2018-07-13 10:54:26 +02002686 chunk.area = "<BADREQ>";
2687 chunk.data = strlen("<BADREQ>");
Andrew Hayworth0ebc55f2015-04-27 21:37:03 +00002688 } else {
Willy Tarreau843b7cb2018-07-13 10:54:26 +02002689 chunk.area = uri;
2690 chunk.data = spc - uri;
Andrew Hayworth0ebc55f2015-04-27 21:37:03 +00002691 }
2692
Dragan Dosen835b9212016-02-12 13:23:03 +01002693 ret = lf_encode_chunk(tmplog, dst + maxsize, '#', url_encode_map, &chunk, tmp);
Andrew Hayworth0ebc55f2015-04-27 21:37:03 +00002694 if (ret == NULL || *ret != '\0')
2695 goto out;
2696
2697 tmplog = ret;
Willy Tarreaub7636d12015-06-17 19:58:02 +02002698 if (tmp->options & LOG_OPT_QUOTE)
Andrew Hayworth0ebc55f2015-04-27 21:37:03 +00002699 LOGCHAR('"');
2700
2701 last_isspace = 0;
2702 break;
2703
Andrew Hayworthe63ac872015-07-31 16:14:16 +00002704 case LOG_FMT_HTTP_QUERY: // %HQ
2705 if (tmp->options & LOG_OPT_QUOTE)
2706 LOGCHAR('"');
2707
Willy Tarreau57bc8912016-04-25 17:09:40 +02002708 if (!txn || !txn->uri) {
Willy Tarreau843b7cb2018-07-13 10:54:26 +02002709 chunk.area = "<BADREQ>";
2710 chunk.data = strlen("<BADREQ>");
Andrew Hayworthe63ac872015-07-31 16:14:16 +00002711 } else {
2712 uri = txn->uri;
2713 end = uri + strlen(uri);
2714 // look for the first question mark
2715 while (uri < end && *uri != '?')
2716 uri++;
2717
2718 qmark = uri;
2719 // look for first space or question mark after url
2720 while (uri < end && !HTTP_IS_SPHT(*uri))
2721 uri++;
2722
Willy Tarreau843b7cb2018-07-13 10:54:26 +02002723 chunk.area = qmark;
2724 chunk.data = uri - qmark;
Andrew Hayworthe63ac872015-07-31 16:14:16 +00002725 }
2726
Dragan Dosen835b9212016-02-12 13:23:03 +01002727 ret = lf_encode_chunk(tmplog, dst + maxsize, '#', url_encode_map, &chunk, tmp);
Andrew Hayworthe63ac872015-07-31 16:14:16 +00002728 if (ret == NULL || *ret != '\0')
2729 goto out;
2730
2731 tmplog = ret;
2732 if (tmp->options & LOG_OPT_QUOTE)
2733 LOGCHAR('"');
2734
2735 last_isspace = 0;
2736 break;
2737
Andrew Hayworth0ebc55f2015-04-27 21:37:03 +00002738 case LOG_FMT_HTTP_URI: // %HU
Willy Tarreau57bc8912016-04-25 17:09:40 +02002739 uri = txn && txn->uri ? txn->uri : "<BADREQ>";
Andrew Hayworth0ebc55f2015-04-27 21:37:03 +00002740
Willy Tarreaub7636d12015-06-17 19:58:02 +02002741 if (tmp->options & LOG_OPT_QUOTE)
Andrew Hayworth0ebc55f2015-04-27 21:37:03 +00002742 LOGCHAR('"');
2743
2744 end = uri + strlen(uri);
2745 // look for the first whitespace character
2746 while (uri < end && !HTTP_IS_SPHT(*uri))
2747 uri++;
2748
2749 // keep advancing past multiple spaces
2750 while (uri < end && HTTP_IS_SPHT(*uri)) {
2751 uri++; nspaces++;
2752 }
2753
2754 // look for first space after url
2755 spc = uri;
2756 while (spc < end && !HTTP_IS_SPHT(*spc))
2757 spc++;
2758
Willy Tarreau57bc8912016-04-25 17:09:40 +02002759 if (!txn || !txn->uri || nspaces == 0) {
Willy Tarreau843b7cb2018-07-13 10:54:26 +02002760 chunk.area = "<BADREQ>";
2761 chunk.data = strlen("<BADREQ>");
Andrew Hayworth0ebc55f2015-04-27 21:37:03 +00002762 } else {
Willy Tarreau843b7cb2018-07-13 10:54:26 +02002763 chunk.area = uri;
2764 chunk.data = spc - uri;
Andrew Hayworth0ebc55f2015-04-27 21:37:03 +00002765 }
2766
Dragan Dosen835b9212016-02-12 13:23:03 +01002767 ret = lf_encode_chunk(tmplog, dst + maxsize, '#', url_encode_map, &chunk, tmp);
Andrew Hayworth0ebc55f2015-04-27 21:37:03 +00002768 if (ret == NULL || *ret != '\0')
2769 goto out;
2770
2771 tmplog = ret;
Willy Tarreaub7636d12015-06-17 19:58:02 +02002772 if (tmp->options & LOG_OPT_QUOTE)
Andrew Hayworth0ebc55f2015-04-27 21:37:03 +00002773 LOGCHAR('"');
2774
2775 last_isspace = 0;
2776 break;
2777
2778 case LOG_FMT_HTTP_METHOD: // %HM
Willy Tarreau57bc8912016-04-25 17:09:40 +02002779 uri = txn && txn->uri ? txn->uri : "<BADREQ>";
Willy Tarreaub7636d12015-06-17 19:58:02 +02002780 if (tmp->options & LOG_OPT_QUOTE)
Andrew Hayworth0ebc55f2015-04-27 21:37:03 +00002781 LOGCHAR('"');
2782
2783 end = uri + strlen(uri);
2784 // look for the first whitespace character
2785 spc = uri;
2786 while (spc < end && !HTTP_IS_SPHT(*spc))
2787 spc++;
2788
2789 if (spc == end) { // odd case, we have txn->uri, but we only got a verb
Willy Tarreau843b7cb2018-07-13 10:54:26 +02002790 chunk.area = "<BADREQ>";
2791 chunk.data = strlen("<BADREQ>");
Andrew Hayworth0ebc55f2015-04-27 21:37:03 +00002792 } else {
Willy Tarreau843b7cb2018-07-13 10:54:26 +02002793 chunk.area = uri;
2794 chunk.data = spc - uri;
Andrew Hayworth0ebc55f2015-04-27 21:37:03 +00002795 }
2796
Dragan Dosen835b9212016-02-12 13:23:03 +01002797 ret = lf_encode_chunk(tmplog, dst + maxsize, '#', url_encode_map, &chunk, tmp);
Andrew Hayworth0ebc55f2015-04-27 21:37:03 +00002798 if (ret == NULL || *ret != '\0')
2799 goto out;
2800
2801 tmplog = ret;
Willy Tarreaub7636d12015-06-17 19:58:02 +02002802 if (tmp->options & LOG_OPT_QUOTE)
Andrew Hayworth0ebc55f2015-04-27 21:37:03 +00002803 LOGCHAR('"');
2804
2805 last_isspace = 0;
2806 break;
2807
2808 case LOG_FMT_HTTP_VERSION: // %HV
Willy Tarreau57bc8912016-04-25 17:09:40 +02002809 uri = txn && txn->uri ? txn->uri : "<BADREQ>";
Willy Tarreaub7636d12015-06-17 19:58:02 +02002810 if (tmp->options & LOG_OPT_QUOTE)
Andrew Hayworth0ebc55f2015-04-27 21:37:03 +00002811 LOGCHAR('"');
2812
2813 end = uri + strlen(uri);
2814 // look for the first whitespace character
2815 while (uri < end && !HTTP_IS_SPHT(*uri))
2816 uri++;
2817
2818 // keep advancing past multiple spaces
2819 while (uri < end && HTTP_IS_SPHT(*uri)) {
2820 uri++; nspaces++;
2821 }
2822
2823 // look for the next whitespace character
2824 while (uri < end && !HTTP_IS_SPHT(*uri))
2825 uri++;
2826
2827 // keep advancing past multiple spaces
2828 while (uri < end && HTTP_IS_SPHT(*uri))
2829 uri++;
2830
Willy Tarreau57bc8912016-04-25 17:09:40 +02002831 if (!txn || !txn->uri || nspaces == 0) {
Willy Tarreau843b7cb2018-07-13 10:54:26 +02002832 chunk.area = "<BADREQ>";
2833 chunk.data = strlen("<BADREQ>");
Andrew Hayworth0ebc55f2015-04-27 21:37:03 +00002834 } else if (uri == end) {
Willy Tarreau843b7cb2018-07-13 10:54:26 +02002835 chunk.area = "HTTP/0.9";
2836 chunk.data = strlen("HTTP/0.9");
Andrew Hayworth0ebc55f2015-04-27 21:37:03 +00002837 } else {
Willy Tarreau843b7cb2018-07-13 10:54:26 +02002838 chunk.area = uri;
2839 chunk.data = end - uri;
Andrew Hayworth0ebc55f2015-04-27 21:37:03 +00002840 }
2841
Dragan Dosen835b9212016-02-12 13:23:03 +01002842 ret = lf_encode_chunk(tmplog, dst + maxsize, '#', url_encode_map, &chunk, tmp);
Andrew Hayworth0ebc55f2015-04-27 21:37:03 +00002843 if (ret == NULL || *ret != '\0')
2844 goto out;
2845
2846 tmplog = ret;
Willy Tarreaub7636d12015-06-17 19:58:02 +02002847 if (tmp->options & LOG_OPT_QUOTE)
Andrew Hayworth0ebc55f2015-04-27 21:37:03 +00002848 LOGCHAR('"');
2849
2850 last_isspace = 0;
2851 break;
2852
William Lallemand5f232402012-04-05 18:02:55 +02002853 case LOG_FMT_COUNTER: // %rt
2854 if (tmp->options & LOG_OPT_HEXA) {
Willy Tarreau5cacab62018-09-05 15:52:59 +02002855 iret = snprintf(tmplog, dst + maxsize - tmplog, "%04X", uniq_id);
William Lallemand5f232402012-04-05 18:02:55 +02002856 if (iret < 0 || iret > dst + maxsize - tmplog)
2857 goto out;
2858 last_isspace = 0;
2859 tmplog += iret;
2860 } else {
Willy Tarreau5cacab62018-09-05 15:52:59 +02002861 ret = ltoa_o(uniq_id, tmplog, dst + maxsize - tmplog);
William Lallemand5f232402012-04-05 18:02:55 +02002862 if (ret == NULL)
2863 goto out;
2864 tmplog = ret;
2865 last_isspace = 0;
2866 }
2867 break;
2868
Willy Tarreau7346acb2014-08-28 15:03:15 +02002869 case LOG_FMT_LOGCNT: // %lc
2870 if (tmp->options & LOG_OPT_HEXA) {
Willy Tarreaue36cbcb2015-04-03 15:40:56 +02002871 iret = snprintf(tmplog, dst + maxsize - tmplog, "%04X", fe->log_count);
Willy Tarreau7346acb2014-08-28 15:03:15 +02002872 if (iret < 0 || iret > dst + maxsize - tmplog)
2873 goto out;
2874 last_isspace = 0;
2875 tmplog += iret;
2876 } else {
Willy Tarreaue36cbcb2015-04-03 15:40:56 +02002877 ret = ultoa_o(fe->log_count, tmplog, dst + maxsize - tmplog);
Willy Tarreau7346acb2014-08-28 15:03:15 +02002878 if (ret == NULL)
2879 goto out;
2880 tmplog = ret;
2881 last_isspace = 0;
2882 }
2883 break;
2884
William Lallemand5f232402012-04-05 18:02:55 +02002885 case LOG_FMT_HOSTNAME: // %H
2886 src = hostname;
2887 ret = lf_text(tmplog, src, dst + maxsize - tmplog, tmp);
2888 if (ret == NULL)
2889 goto out;
2890 tmplog = ret;
2891 last_isspace = 0;
2892 break;
2893
2894 case LOG_FMT_PID: // %pid
2895 if (tmp->options & LOG_OPT_HEXA) {
2896 iret = snprintf(tmplog, dst + maxsize - tmplog, "%04X", pid);
2897 if (iret < 0 || iret > dst + maxsize - tmplog)
2898 goto out;
2899 last_isspace = 0;
2900 tmplog += iret;
2901 } else {
2902 ret = ltoa_o(pid, tmplog, dst + maxsize - tmplog);
2903 if (ret == NULL)
2904 goto out;
2905 tmplog = ret;
2906 last_isspace = 0;
2907 }
2908 break;
William Lallemanda73203e2012-03-12 12:48:57 +01002909
2910 case LOG_FMT_UNIQUEID: // %ID
William Lallemand5b7ea3a2013-08-28 15:44:19 +02002911 ret = NULL;
Willy Tarreau02fdf4f2018-09-05 15:49:01 +02002912 src = s ? s->unique_id : NULL;
Thierry FOURNIER1be69102014-04-15 01:38:48 +02002913 ret = lf_text(tmplog, src, maxsize - (tmplog - dst), tmp);
William Lallemanda73203e2012-03-12 12:48:57 +01002914 if (ret == NULL)
2915 goto out;
2916 tmplog = ret;
2917 last_isspace = 0;
2918 break;
2919
William Lallemandbddd4fd2012-02-27 11:23:10 +01002920 }
2921 }
2922
2923out:
William Lallemand1d705562012-03-12 12:46:41 +01002924 /* *tmplog is a unused character */
2925 *tmplog = '\0';
Willy Tarreaudf974472012-12-28 02:44:01 +01002926 return tmplog - dst;
William Lallemandbddd4fd2012-02-27 11:23:10 +01002927
Willy Tarreaubaaee002006-06-26 02:48:02 +02002928}
2929
William Lallemand1d705562012-03-12 12:46:41 +01002930/*
Willy Tarreau87b09662015-04-03 00:22:06 +02002931 * send a log for the stream when we have enough info about it.
William Lallemand1d705562012-03-12 12:46:41 +01002932 * Will not log if the frontend has no log defined.
2933 */
Willy Tarreau87b09662015-04-03 00:22:06 +02002934void strm_log(struct stream *s)
William Lallemand1d705562012-03-12 12:46:41 +01002935{
Willy Tarreaue36cbcb2015-04-03 15:40:56 +02002936 struct session *sess = s->sess;
William Lallemand1d705562012-03-12 12:46:41 +01002937 int size, err, level;
Dragan Dosen0b85ece2015-09-25 19:17:44 +02002938 int sd_size = 0;
William Lallemand1d705562012-03-12 12:46:41 +01002939
2940 /* if we don't want to log normal traffic, return now */
Willy Tarreaue7dff022015-04-03 01:14:29 +02002941 err = (s->flags & SF_REDISP) ||
2942 ((s->flags & SF_ERR_MASK) > SF_ERR_LOCAL) ||
2943 (((s->flags & SF_ERR_MASK) == SF_ERR_NONE) &&
Willy Tarreau350f4872014-11-28 14:42:25 +01002944 (s->si[1].conn_retries != s->be->conn_retries)) ||
Willy Tarreaueee5b512015-04-03 23:46:31 +02002945 ((sess->fe->mode == PR_MODE_HTTP) && s->txn && s->txn->status >= 500);
Willy Tarreaubaaee002006-06-26 02:48:02 +02002946
Willy Tarreaue36cbcb2015-04-03 15:40:56 +02002947 if (!err && (sess->fe->options2 & PR_O2_NOLOGNORM))
William Lallemand1d705562012-03-12 12:46:41 +01002948 return;
William Lallemandbddd4fd2012-02-27 11:23:10 +01002949
Willy Tarreaue36cbcb2015-04-03 15:40:56 +02002950 if (LIST_ISEMPTY(&sess->fe->logsrvs))
William Lallemand1d705562012-03-12 12:46:41 +01002951 return;
William Lallemandbddd4fd2012-02-27 11:23:10 +01002952
Willy Tarreauabcd5142013-06-11 17:18:02 +02002953 if (s->logs.level) { /* loglevel was overridden */
2954 if (s->logs.level == -1) {
2955 s->logs.logwait = 0; /* logs disabled */
2956 return;
2957 }
2958 level = s->logs.level - 1;
2959 }
2960 else {
2961 level = LOG_INFO;
Willy Tarreaue36cbcb2015-04-03 15:40:56 +02002962 if (err && (sess->fe->options2 & PR_O2_LOGERRORS))
Willy Tarreauabcd5142013-06-11 17:18:02 +02002963 level = LOG_ERR;
2964 }
William Lallemand1d705562012-03-12 12:46:41 +01002965
William Lallemand5b7ea3a2013-08-28 15:44:19 +02002966 /* if unique-id was not generated */
Willy Tarreaue36cbcb2015-04-03 15:40:56 +02002967 if (!s->unique_id && !LIST_ISEMPTY(&sess->fe->format_unique_id)) {
Willy Tarreaubafbe012017-11-24 17:34:44 +01002968 if ((s->unique_id = pool_alloc(pool_head_uniqueid)) != NULL)
Willy Tarreaue36cbcb2015-04-03 15:40:56 +02002969 build_logline(s, s->unique_id, UNIQUEID_LEN, &sess->fe->format_unique_id);
William Lallemand5b7ea3a2013-08-28 15:44:19 +02002970 }
2971
Dragan Dosen0b85ece2015-09-25 19:17:44 +02002972 if (!LIST_ISEMPTY(&sess->fe->logformat_sd)) {
2973 sd_size = build_logline(s, logline_rfc5424, global.max_syslog_len,
2974 &sess->fe->logformat_sd);
2975 }
2976
Dragan Dosen59cee972015-09-19 22:09:02 +02002977 size = build_logline(s, logline, global.max_syslog_len, &sess->fe->logformat);
William Lallemand1d705562012-03-12 12:46:41 +01002978 if (size > 0) {
Olivier Houchardd2ee3e72019-03-08 18:53:21 +01002979 _HA_ATOMIC_ADD(&sess->fe->log_count, 1);
Christopher Faulet5c6fefc2019-08-11 19:40:12 +02002980 __send_log(&sess->fe->logsrvs, &sess->fe->log_tag, level,
2981 logline, size + 1, logline_rfc5424, sd_size);
William Lallemand1d705562012-03-12 12:46:41 +01002982 s->logs.logwait = 0;
2983 }
2984}
William Lallemandbddd4fd2012-02-27 11:23:10 +01002985
Willy Tarreau53839352018-09-05 19:51:10 +02002986/*
2987 * send a minimalist log for the session. Will not log if the frontend has no
2988 * log defined. It is assumed that this is only used to report anomalies that
2989 * cannot lead to the creation of a regular stream. Because of this the log
2990 * level is LOG_INFO or LOG_ERR depending on the "log-separate-error" setting
2991 * in the frontend. The caller must simply know that it should not call this
Willy Tarreau9fa267d2018-10-05 10:22:27 +02002992 * function to report unimportant events. It is safe to call this function with
2993 * sess==NULL (will not do anything).
Willy Tarreau53839352018-09-05 19:51:10 +02002994 */
2995void sess_log(struct session *sess)
2996{
2997 int size, level;
2998 int sd_size = 0;
2999
Willy Tarreau9fa267d2018-10-05 10:22:27 +02003000 if (!sess)
3001 return;
3002
Willy Tarreau53839352018-09-05 19:51:10 +02003003 if (LIST_ISEMPTY(&sess->fe->logsrvs))
3004 return;
3005
3006 level = LOG_INFO;
3007 if (sess->fe->options2 & PR_O2_LOGERRORS)
3008 level = LOG_ERR;
3009
3010 if (!LIST_ISEMPTY(&sess->fe->logformat_sd)) {
3011 sd_size = sess_build_logline(sess, NULL,
3012 logline_rfc5424, global.max_syslog_len,
3013 &sess->fe->logformat_sd);
3014 }
3015
3016 size = sess_build_logline(sess, NULL, logline, global.max_syslog_len, &sess->fe->logformat);
3017 if (size > 0) {
Olivier Houchardd2ee3e72019-03-08 18:53:21 +01003018 _HA_ATOMIC_ADD(&sess->fe->log_count, 1);
Christopher Faulet5c6fefc2019-08-11 19:40:12 +02003019 __send_log(&sess->fe->logsrvs, &sess->fe->log_tag, level,
3020 logline, size + 1, logline_rfc5424, sd_size);
Willy Tarreau53839352018-09-05 19:51:10 +02003021 }
3022}
3023
Christopher Faulet5c6fefc2019-08-11 19:40:12 +02003024void app_log(struct list *logsrvs, struct buffer *tag, int level, const char *format, ...)
3025{
3026 va_list argp;
3027 int data_len;
3028
3029 if (level < 0 || format == NULL || logline == NULL)
3030 return;
3031
3032 va_start(argp, format);
3033 data_len = vsnprintf(logline, global.max_syslog_len, format, argp);
3034 if (data_len < 0 || data_len > global.max_syslog_len)
3035 data_len = global.max_syslog_len;
3036 va_end(argp);
3037
3038 __send_log(logsrvs, tag, level, logline, data_len, default_rfc5424_sd_log_format, 2);
3039}
3040
Willy Tarreau869efd52019-11-15 15:16:57 +01003041/* parse the "show startup-logs" command, returns 1 if a message is returned, otherwise zero */
3042static int cli_parse_show_startup_logs(char **args, char *payload, struct appctx *appctx, void *private)
Christopher Fauletc1b730a2017-10-24 12:00:51 +02003043{
Willy Tarreau869efd52019-11-15 15:16:57 +01003044 if (!cli_has_level(appctx, ACCESS_LVL_OPER))
3045 return 1;
Christopher Fauletc1b730a2017-10-24 12:00:51 +02003046
Willy Tarreau869efd52019-11-15 15:16:57 +01003047 if (!startup_logs)
3048 return cli_msg(appctx, LOG_INFO, "\n"); // nothing to print
3049
3050 return ring_attach_cli(startup_logs, appctx);
Christopher Fauletc1b730a2017-10-24 12:00:51 +02003051}
3052
3053/* register cli keywords */
3054static struct cli_kw_list cli_kws = {{ },{
3055 { { "show", "startup-logs", NULL },
Willy Tarreau869efd52019-11-15 15:16:57 +01003056 "show startup-logs : report logs emitted during HAProxy startup", cli_parse_show_startup_logs, NULL, NULL },
Christopher Fauletc1b730a2017-10-24 12:00:51 +02003057 {{},}
3058}};
3059
Willy Tarreau0108d902018-11-25 19:14:37 +01003060INITCALL1(STG_REGISTER, cli_register_kw, &cli_kws);
3061
Willy Tarreau082b6282019-05-22 14:42:12 +02003062REGISTER_PER_THREAD_ALLOC(init_log_buffers);
3063REGISTER_PER_THREAD_FREE(deinit_log_buffers);
Willy Tarreau172f5ce2018-11-26 11:21:50 +01003064
Willy Tarreaubaaee002006-06-26 02:48:02 +02003065/*
3066 * Local variables:
3067 * c-indent-level: 8
3068 * c-basic-offset: 8
3069 * End:
3070 */