2006-06-25 20:48:02 -04:00
/*
* General logging functions .
*
2008-06-22 11:18:02 -04:00
* Copyright 2000 - 2008 Willy Tarreau < w @ 1 wt . eu >
2006-06-25 20:48:02 -04:00
*
* This program is free software ; you can redistribute it and / or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation ; either version
* 2 of the License , or ( at your option ) any later version .
*
*/
2012-12-20 15:23:42 -05:00
# include <ctype.h>
2006-06-25 20:48:02 -04:00
# include <stdarg.h>
# include <stdio.h>
# include <stdlib.h>
# include <string.h>
# include <syslog.h>
# include <time.h>
# include <unistd.h>
2007-12-05 04:47:29 -05:00
# include <errno.h>
2006-06-25 20:48:02 -04:00
# include <sys/time.h>
2016-08-10 12:30:56 -04:00
# include <sys/uio.h>
2006-06-25 20:48:02 -04:00
2020-05-27 06:58:42 -04:00
# include <haproxy/api.h>
2022-04-04 05:29:28 -04:00
# include <haproxy/applet.h>
2020-07-07 08:19:42 -04:00
# include <haproxy/cfgparse.h>
2021-10-08 03:33:24 -04:00
# include <haproxy/clock.h>
2020-06-09 03:07:15 -04:00
# include <haproxy/fd.h>
2020-06-04 05:23:07 -04:00
# include <haproxy/frontend.h>
2020-06-09 03:07:15 -04:00
# include <haproxy/global.h>
2020-06-02 13:11:26 -04:00
# include <haproxy/http.h>
2021-10-06 12:56:42 -04:00
# include <haproxy/http_ana.h>
2020-07-07 08:19:42 -04:00
# include <haproxy/listener.h>
2024-03-28 10:42:37 -04:00
# include <haproxy/lb_chash.h>
# include <haproxy/lb_fwrr.h>
# include <haproxy/lb_map.h>
# include <haproxy/lb_ss.h>
2020-06-04 16:01:04 -04:00
# include <haproxy/log.h>
2020-07-07 08:19:42 -04:00
# include <haproxy/proxy.h>
2020-06-09 03:07:15 -04:00
# include <haproxy/sample.h>
2022-05-27 03:25:10 -04:00
# include <haproxy/sc_strm.h>
2020-06-09 03:07:15 -04:00
# include <haproxy/sink.h>
2020-06-04 14:30:20 -04:00
# include <haproxy/ssl_sock.h>
2022-05-27 03:47:12 -04:00
# include <haproxy/stconn.h>
2020-06-04 17:46:14 -04:00
# include <haproxy/stream.h>
2023-11-16 04:48:34 -05:00
# include <haproxy/action.h>
2020-06-01 05:05:15 -04:00
# include <haproxy/time.h>
2023-09-19 04:51:53 -04:00
# include <haproxy/hash.h>
2020-06-09 03:07:15 -04:00
# include <haproxy/tools.h>
2024-02-27 01:58:26 -05:00
# include <haproxy/vecpair.h>
2006-06-25 20:48:02 -04:00
2020-07-09 17:23:34 -04:00
/* global recv logs counter */
int cum_log_messages ;
2006-06-25 20:48:02 -04:00
2020-07-07 08:19:42 -04:00
/* log forward proxy list */
struct proxy * cfg_log_forward ;
2020-07-06 09:54:06 -04:00
struct log_fmt_st {
2015-10-01 07:18:13 -04:00
char * name ;
} ;
2020-07-06 09:54:06 -04:00
static const struct log_fmt_st log_formats [ LOG_FORMATS ] = {
2020-11-27 10:24:34 -05:00
[ LOG_FORMAT_LOCAL ] = {
. name = " local " ,
} ,
2015-10-01 07:18:13 -04:00
[ LOG_FORMAT_RFC3164 ] = {
. name = " rfc3164 " ,
} ,
[ LOG_FORMAT_RFC5424 ] = {
. name = " rfc5424 " ,
2020-07-06 09:54:06 -04:00
} ,
[ LOG_FORMAT_PRIO ] = {
. name = " priority " ,
2018-11-12 02:45:00 -05:00
} ,
[ LOG_FORMAT_SHORT ] = {
. name = " short " ,
2020-07-06 09:54:06 -04:00
} ,
[ LOG_FORMAT_TIMED ] = {
. name = " timed " ,
} ,
[ LOG_FORMAT_ISO ] = {
. name = " iso " ,
2018-11-12 02:45:00 -05:00
} ,
2018-11-12 05:57:56 -05:00
[ LOG_FORMAT_RAW ] = {
. name = " raw " ,
} ,
2015-09-22 10:05:32 -04:00
} ;
2024-05-06 08:33:16 -04:00
/* get human readable representation for log_orig enum members */
const char * log_orig_to_str ( enum log_orig orig )
{
switch ( orig ) {
case LOG_ORIG_SESS_ERROR :
return " sess_error " ;
case LOG_ORIG_SESS_KILL :
return " sess_killed " ;
case LOG_ORIG_TXN_ACCEPT :
return " txn_accept " ;
case LOG_ORIG_TXN_REQUEST :
return " txn_request " ;
case LOG_ORIG_TXN_CONNECT :
return " txn_connect " ;
case LOG_ORIG_TXN_RESPONSE :
return " txn_response " ;
case LOG_ORIG_TXN_CLOSE :
return " txn_close " ;
default :
break ;
}
return " unspec " ;
}
2016-02-12 07:23:03 -05:00
/*
* This map is used with all the FD_ * macros to check whether a particular bit
2023-11-21 13:54:16 -05:00
* is set or not . Each bit represents an ASCII code . ha_bit_set ( ) sets those
2019-06-07 05:10:07 -04:00
* bytes which should be escaped . When ha_bit_test ( ) returns non - zero , it means
* that the byte should be escaped . Be careful to always pass bytes from 0 to
* 255 exclusively to the macros .
2016-02-12 07:23:03 -05:00
*/
2024-04-26 08:23:43 -04:00
long no_escape_map [ ( 256 / 8 ) / sizeof ( long ) ] ;
2019-06-07 05:10:07 -04:00
long rfc5424_escape_map [ ( 256 / 8 ) / sizeof ( long ) ] ;
2024-04-22 08:40:04 -04:00
long json_escape_map [ ( 256 / 8 ) / sizeof ( long ) ] ;
2019-06-07 05:10:07 -04:00
long hdr_encode_map [ ( 256 / 8 ) / sizeof ( long ) ] ;
long url_encode_map [ ( 256 / 8 ) / sizeof ( long ) ] ;
long http_encode_map [ ( 256 / 8 ) / sizeof ( long ) ] ;
2016-02-12 07:23:03 -05:00
2006-06-25 20:48:02 -04:00
const char * log_facilities [ NB_LOG_FACILITIES ] = {
" kern " , " user " , " mail " , " daemon " ,
" auth " , " syslog " , " lpr " , " news " ,
" uucp " , " cron " , " auth2 " , " ftp " ,
" ntp " , " audit " , " alert " , " cron2 " ,
" local0 " , " local1 " , " local2 " , " local3 " ,
" local4 " , " local5 " , " local6 " , " local7 "
} ;
const char * log_levels [ NB_LOG_LEVELS ] = {
" emerg " , " alert " , " crit " , " err " ,
" warning " , " notice " , " info " , " debug "
} ;
2013-06-10 10:42:09 -04:00
const char sess_term_cond [ 16 ] = " -LcCsSPRIDKUIIII " ; /* normal, Local, CliTo, CliErr, SrvTo, SrvErr, PxErr, Resource, Internal, Down, Killed, Up, -- */
2006-09-03 03:56:00 -04:00
const char sess_fin_state [ 8 ] = " -RCHDLQT " ; /* cliRequest, srvConnect, srvHeader, Data, Last, Queue, Tarpit */
2024-04-30 10:45:34 -04:00
const struct buffer empty = { } ;
2006-06-25 20:48:02 -04:00
2012-02-08 10:37:49 -05:00
2012-03-02 08:35:21 -05:00
int prepare_addrsource ( struct logformat_node * node , struct proxy * curproxy ) ;
MINOR: log: rename 'log-format tag' to 'log-format alias'
In 2.9 we started to introduce an ambiguity in the documentation by
referring to historical log-format variables ('%var') as log-format
tags in 739c4e5b1e ("MINOR: sample: accept_date / request_date return
%Ts / %tr timestamp values") and 454c372b60 ("DOC: configuration: add
sample fetches for timing events").
In fact, we've had this confusion between log-format tag and log-format
var for more than 10 years now, but in 2.9 it was the first time the
confusion was exposed in the documentation.
Indeed, both 'log-format variable' and 'log-format tag' actually refer
to the same feature (that is: '%B' and friends that can be used for
direct access to some log-oriented predefined fetches instead of using
%[expr] with generic sample expressions).
This feature was first implemented in 723b73ad75 ("MINOR: config: Parse
the string of the log-format config keyword") and later documented in
4894040fa ("DOC: log-format documentation"). At that time, it was clear
that we used to name it 'log-format variable'.
But later the same year, 'log-format tag' naming started to appear in
some commit messages (while still referring to the same feature), for
instance with ffc3fcd6d ("MEDIUM: log: report SSL ciphers and version
in logs using logformat %sslc/%sslv").
Unfortunately in 2.9 when we added (and documented) new log-format
variables we officially started drifting to the misleading 'log-format
tag' naming (perhaps because it was the most recent naming found for
this feature in git log history, or because the confusion has always
been there)
Even worse, in 3.0 this confusion led us to rename all 'var' occurrences
to 'tag' in log-format related code to unify the code with the doc.
Hopefully William quickly noticed that we made a mistake there, but
instead of reverting to historical naming (log-format variable), it was
decided that we must use a different name that is less confusing than
'tags' or 'variables' (tags and variables are keywords that are already
used to designate other features in the code and that are not very
explicit under log-format context today).
Now we refer to '%B' and friends as a logformat alias, which is
essentially a handy way to print some log oriented information in the
log string instead of leveraging '%[expr]' with generic sample expressions
made of fetches and converters. Of course, there are some subtelties, such
as a few log-format aliases that still don't have sample fetch equivalent
for historical reasons, and some aliases that may be a little faster than
their generic sample expression equivalents because most aliases are
pretty much hardcoded in the log building function. But in general
logformat aliases should be simply considered as an alternative to using
expressions (with '%[expr']')
Also, under log-format context, when we want to refer to either an alias
('%alias') or an expression ('%[expr]'), we should use the generic term
'logformat item', which in fact designates a single item within the
logformat string provided by the user. Indeed, a logformat item (whether
is is an alias or an expression) always starts with '%' and may accept
optional flags / arguments
Both the code and the documentation were updated in that sense, hopefully
this will clarify things and prevent future confusions.
2024-05-27 04:18:10 -04:00
/* logformat alias types (internal use) */
enum logformat_alias_type {
MEDIUM: log: carry tag context in logformat node
This is a pretty simple patch despite requiring to make some visible
changes in the code:
When parsing a logformat string, log tags (ie: '%tag', AKA log tags) are
turned into logformat nodes with their type set to the type of the
corresponding logformat_tag element which was matched by name. Thus, when
"compiling" a logformat tag, we only keep a reference to the tag type
from the original logformat_tag.
For example, for "%B" log tag, we have the following logformat_tag
element:
{
.name = "B",
.type = LOG_FMT_BYTES,
.mode = PR_MODE_TCP,
.lw = LW_BYTES,
.config_callback = NULL
}
When parsing "%B" string, we search for a matching logformat tag
inside logformat_tags[] array using the provided name, once we find a
matching element, we craft a logformat node whose type will be
LOG_FMT_BYTES, but from the node itself, we no longer have access to
other informations that are set in the logformat_tag struct element.
Thus from a logformat_node resulting from a log tag, with current
implementation, we cannot easily get back to matching logformat_tag
struct element as it would require us to scan the whole logformat_tags
array at runtime using node->type to find the matching element.
Let's take a simpler path and consider all tag-specific LOG_FMT_*
subtypes as being part of the same logformat node type: LOG_FMT_TAG.
Thanks to that, we're now able to distinguish logformat nodes made
from logformat tag from other logformat nodes, and link them to
their corresponding logformat_tag element from logformat_tags[] array. All
it costs is a simple indirection and an extra pointer in logformat_node
struct.
While at it, all LOG_FMT_* types related to logformat tags were moved
inside log.c as they have no use outside of it since they are simply
lookup indexes for sess_build_logline() and could even be replaced by
function pointers some day...
2024-02-22 14:20:41 -05:00
LOG_FMT_GLOBAL ,
2024-05-06 08:13:11 -04:00
LOG_FMT_ORIGIN ,
MEDIUM: log: carry tag context in logformat node
This is a pretty simple patch despite requiring to make some visible
changes in the code:
When parsing a logformat string, log tags (ie: '%tag', AKA log tags) are
turned into logformat nodes with their type set to the type of the
corresponding logformat_tag element which was matched by name. Thus, when
"compiling" a logformat tag, we only keep a reference to the tag type
from the original logformat_tag.
For example, for "%B" log tag, we have the following logformat_tag
element:
{
.name = "B",
.type = LOG_FMT_BYTES,
.mode = PR_MODE_TCP,
.lw = LW_BYTES,
.config_callback = NULL
}
When parsing "%B" string, we search for a matching logformat tag
inside logformat_tags[] array using the provided name, once we find a
matching element, we craft a logformat node whose type will be
LOG_FMT_BYTES, but from the node itself, we no longer have access to
other informations that are set in the logformat_tag struct element.
Thus from a logformat_node resulting from a log tag, with current
implementation, we cannot easily get back to matching logformat_tag
struct element as it would require us to scan the whole logformat_tags
array at runtime using node->type to find the matching element.
Let's take a simpler path and consider all tag-specific LOG_FMT_*
subtypes as being part of the same logformat node type: LOG_FMT_TAG.
Thanks to that, we're now able to distinguish logformat nodes made
from logformat tag from other logformat nodes, and link them to
their corresponding logformat_tag element from logformat_tags[] array. All
it costs is a simple indirection and an extra pointer in logformat_node
struct.
While at it, all LOG_FMT_* types related to logformat tags were moved
inside log.c as they have no use outside of it since they are simply
lookup indexes for sess_build_logline() and could even be replaced by
function pointers some day...
2024-02-22 14:20:41 -05:00
LOG_FMT_CLIENTIP ,
LOG_FMT_CLIENTPORT ,
LOG_FMT_BACKENDIP ,
LOG_FMT_BACKENDPORT ,
LOG_FMT_FRONTENDIP ,
LOG_FMT_FRONTENDPORT ,
LOG_FMT_SERVERPORT ,
LOG_FMT_SERVERIP ,
LOG_FMT_COUNTER ,
LOG_FMT_LOGCNT ,
LOG_FMT_PID ,
LOG_FMT_DATE ,
LOG_FMT_DATEGMT ,
LOG_FMT_DATELOCAL ,
LOG_FMT_TS ,
LOG_FMT_MS ,
LOG_FMT_FRONTEND ,
LOG_FMT_FRONTEND_XPRT ,
LOG_FMT_BACKEND ,
LOG_FMT_SERVER ,
LOG_FMT_BYTES ,
LOG_FMT_BYTES_UP ,
LOG_FMT_Ta ,
LOG_FMT_Th ,
LOG_FMT_Ti ,
LOG_FMT_TQ ,
LOG_FMT_TW ,
LOG_FMT_TC ,
LOG_FMT_Tr ,
LOG_FMT_tr ,
LOG_FMT_trg ,
LOG_FMT_trl ,
LOG_FMT_TR ,
LOG_FMT_TD ,
LOG_FMT_TT ,
LOG_FMT_TU ,
LOG_FMT_STATUS ,
LOG_FMT_CCLIENT ,
LOG_FMT_CSERVER ,
LOG_FMT_TERMSTATE ,
LOG_FMT_TERMSTATE_CK ,
LOG_FMT_ACTCONN ,
LOG_FMT_FECONN ,
LOG_FMT_BECONN ,
LOG_FMT_SRVCONN ,
LOG_FMT_RETRIES ,
LOG_FMT_SRVQUEUE ,
LOG_FMT_BCKQUEUE ,
LOG_FMT_HDRREQUEST ,
LOG_FMT_HDRRESPONS ,
LOG_FMT_HDRREQUESTLIST ,
LOG_FMT_HDRRESPONSLIST ,
LOG_FMT_REQ ,
LOG_FMT_HTTP_METHOD ,
LOG_FMT_HTTP_URI ,
LOG_FMT_HTTP_PATH ,
LOG_FMT_HTTP_PATH_ONLY ,
LOG_FMT_HTTP_QUERY ,
LOG_FMT_HTTP_VERSION ,
LOG_FMT_HOSTNAME ,
LOG_FMT_UNIQUEID ,
LOG_FMT_SSL_CIPHER ,
LOG_FMT_SSL_VERSION ,
} ;
MINOR: log: rename 'log-format tag' to 'log-format alias'
In 2.9 we started to introduce an ambiguity in the documentation by
referring to historical log-format variables ('%var') as log-format
tags in 739c4e5b1e ("MINOR: sample: accept_date / request_date return
%Ts / %tr timestamp values") and 454c372b60 ("DOC: configuration: add
sample fetches for timing events").
In fact, we've had this confusion between log-format tag and log-format
var for more than 10 years now, but in 2.9 it was the first time the
confusion was exposed in the documentation.
Indeed, both 'log-format variable' and 'log-format tag' actually refer
to the same feature (that is: '%B' and friends that can be used for
direct access to some log-oriented predefined fetches instead of using
%[expr] with generic sample expressions).
This feature was first implemented in 723b73ad75 ("MINOR: config: Parse
the string of the log-format config keyword") and later documented in
4894040fa ("DOC: log-format documentation"). At that time, it was clear
that we used to name it 'log-format variable'.
But later the same year, 'log-format tag' naming started to appear in
some commit messages (while still referring to the same feature), for
instance with ffc3fcd6d ("MEDIUM: log: report SSL ciphers and version
in logs using logformat %sslc/%sslv").
Unfortunately in 2.9 when we added (and documented) new log-format
variables we officially started drifting to the misleading 'log-format
tag' naming (perhaps because it was the most recent naming found for
this feature in git log history, or because the confusion has always
been there)
Even worse, in 3.0 this confusion led us to rename all 'var' occurrences
to 'tag' in log-format related code to unify the code with the doc.
Hopefully William quickly noticed that we made a mistake there, but
instead of reverting to historical naming (log-format variable), it was
decided that we must use a different name that is less confusing than
'tags' or 'variables' (tags and variables are keywords that are already
used to designate other features in the code and that are not very
explicit under log-format context today).
Now we refer to '%B' and friends as a logformat alias, which is
essentially a handy way to print some log oriented information in the
log string instead of leveraging '%[expr]' with generic sample expressions
made of fetches and converters. Of course, there are some subtelties, such
as a few log-format aliases that still don't have sample fetch equivalent
for historical reasons, and some aliases that may be a little faster than
their generic sample expression equivalents because most aliases are
pretty much hardcoded in the log building function. But in general
logformat aliases should be simply considered as an alternative to using
expressions (with '%[expr']')
Also, under log-format context, when we want to refer to either an alias
('%alias') or an expression ('%[expr]'), we should use the generic term
'logformat item', which in fact designates a single item within the
logformat string provided by the user. Indeed, a logformat item (whether
is is an alias or an expression) always starts with '%' and may accept
optional flags / arguments
Both the code and the documentation were updated in that sense, hopefully
this will clarify things and prevent future confusions.
2024-05-27 04:18:10 -04:00
/* log_format alias names */
static const struct logformat_alias logformat_aliases [ ] = {
2012-04-02 10:22:10 -04:00
{ " o " , LOG_FMT_GLOBAL , PR_MODE_TCP , 0 , NULL } , /* global option */
2024-05-06 08:13:11 -04:00
{ " OG " , LOG_FMT_ORIGIN , PR_MODE_TCP , 0 , NULL } , /* human readable log origin */
2012-12-20 11:22:52 -05:00
/* please keep these lines sorted ! */
{ " B " , LOG_FMT_BYTES , PR_MODE_TCP , LW_BYTES , NULL } , /* bytes from server to client */
{ " CC " , LOG_FMT_CCLIENT , PR_MODE_HTTP , LW_REQHDR , NULL } , /* client cookie */
{ " CS " , LOG_FMT_CSERVER , PR_MODE_HTTP , LW_RSPHDR , NULL } , /* server cookie */
{ " H " , LOG_FMT_HOSTNAME , PR_MODE_TCP , LW_INIT , NULL } , /* Hostname */
2020-03-13 07:34:24 -04:00
{ " ID " , LOG_FMT_UNIQUEID , PR_MODE_TCP , LW_BYTES , NULL } , /* Unique ID */
2014-06-13 06:21:40 -04:00
{ " ST " , LOG_FMT_STATUS , PR_MODE_TCP , LW_RESP , NULL } , /* status code */
2012-04-02 10:22:10 -04:00
{ " T " , LOG_FMT_DATEGMT , PR_MODE_TCP , LW_INIT , NULL } , /* date GMT */
MEDIUM: log: Decompose %Tq in %Th %Ti %TR
Tq is the time between the instant the connection is accepted and a
complete valid request is received. This time includes the handshake
(SSL / Proxy-Protocol), the idle when the browser does preconnect and
the request reception.
This patch decomposes %Tq in 3 measurements names %Th, %Ti, and %TR
which returns respectively the handshake time, the idle time and the
duration of valid request reception. It also adds %Ta which reports
the request's active time, which is the total time without %Th nor %Ti.
It replaces %Tt as the total time, reporting accurate measurements for
HTTP persistent connections.
%Th is avalaible for TCP and HTTP sessions, %Ti, %TR and %Ta are only
avalaible for HTTP connections.
In addition to this, we have new timestamps %tr, %trg and %trl, which
log the date of start of receipt of the request, respectively in the
default format, in GMT time and in local time (by analogy with %t, %T
and %Tl). All of them are obviously only available for HTTP. These values
are more relevant as they more accurately represent the request date
without being skewed by a browser's preconnect nor a keep-alive idle
time.
The HTTP log format and the CLF log format have been modified to
use %tr, %TR, and %Ta respectively instead of %t, %Tq and %Tt. This
way the default log formats now produce the expected output for users
who don't want to manually fiddle with the log-format directive.
Example with the following log-format :
log-format "%ci:%cp [%tr] %ft %b/%s h=%Th/i=%Ti/R=%TR/w=%Tw/c=%Tc/r=%Tr/a=%Ta/t=%Tt %ST %B %CC %CS %tsc %ac/%fc/%bc/%sc/%rc %sq/%bq %hr %hs %{+Q}r"
The request was sent by hand using "openssl s_client -connect" :
Aug 23 14:43:20 haproxy[25446]: 127.0.0.1:45636 [23/Aug/2016:14:43:20.221] test~ test/test h=6/i=2375/R=261/w=0/c=1/r=0/a=262/t=2643 200 145 - - ---- 1/1/0/0/0 0/0 "GET / HTTP/1.1"
=> 6 ms of SSL handshake, 2375 waiting before sending the first char (in
fact the time to type the first line), 261 ms before the end of the request,
no time spent in queue, 1 ms spend connecting to the server, immediate
response, total active time for this request = 262ms. Total time from accept
to close : 2643 ms.
The timing now decomposes like this :
first request 2nd request
|<-------------------------------->|<-------------- ...
t tr t tr ...
---|----|----|----|----|----|----|----|----|--
: Th Ti TR Tw Tc Tr Td : Ti ...
:<---- Tq ---->: :
:<-------------- Tt -------------->:
:<--------- Ta --------->:
2016-07-28 11:19:45 -04:00
{ " Ta " , LOG_FMT_Ta , PR_MODE_HTTP , LW_BYTES , NULL } , /* Time active (tr to end) */
2012-12-20 11:22:52 -05:00
{ " Tc " , LOG_FMT_TC , PR_MODE_TCP , LW_BYTES , NULL } , /* Tc */
MEDIUM: log: Decompose %Tq in %Th %Ti %TR
Tq is the time between the instant the connection is accepted and a
complete valid request is received. This time includes the handshake
(SSL / Proxy-Protocol), the idle when the browser does preconnect and
the request reception.
This patch decomposes %Tq in 3 measurements names %Th, %Ti, and %TR
which returns respectively the handshake time, the idle time and the
duration of valid request reception. It also adds %Ta which reports
the request's active time, which is the total time without %Th nor %Ti.
It replaces %Tt as the total time, reporting accurate measurements for
HTTP persistent connections.
%Th is avalaible for TCP and HTTP sessions, %Ti, %TR and %Ta are only
avalaible for HTTP connections.
In addition to this, we have new timestamps %tr, %trg and %trl, which
log the date of start of receipt of the request, respectively in the
default format, in GMT time and in local time (by analogy with %t, %T
and %Tl). All of them are obviously only available for HTTP. These values
are more relevant as they more accurately represent the request date
without being skewed by a browser's preconnect nor a keep-alive idle
time.
The HTTP log format and the CLF log format have been modified to
use %tr, %TR, and %Ta respectively instead of %t, %Tq and %Tt. This
way the default log formats now produce the expected output for users
who don't want to manually fiddle with the log-format directive.
Example with the following log-format :
log-format "%ci:%cp [%tr] %ft %b/%s h=%Th/i=%Ti/R=%TR/w=%Tw/c=%Tc/r=%Tr/a=%Ta/t=%Tt %ST %B %CC %CS %tsc %ac/%fc/%bc/%sc/%rc %sq/%bq %hr %hs %{+Q}r"
The request was sent by hand using "openssl s_client -connect" :
Aug 23 14:43:20 haproxy[25446]: 127.0.0.1:45636 [23/Aug/2016:14:43:20.221] test~ test/test h=6/i=2375/R=261/w=0/c=1/r=0/a=262/t=2643 200 145 - - ---- 1/1/0/0/0 0/0 "GET / HTTP/1.1"
=> 6 ms of SSL handshake, 2375 waiting before sending the first char (in
fact the time to type the first line), 261 ms before the end of the request,
no time spent in queue, 1 ms spend connecting to the server, immediate
response, total active time for this request = 262ms. Total time from accept
to close : 2643 ms.
The timing now decomposes like this :
first request 2nd request
|<-------------------------------->|<-------------- ...
t tr t tr ...
---|----|----|----|----|----|----|----|----|--
: Th Ti TR Tw Tc Tr Td : Ti ...
:<---- Tq ---->: :
:<-------------- Tt -------------->:
:<--------- Ta --------->:
2016-07-28 11:19:45 -04:00
{ " Th " , LOG_FMT_Th , PR_MODE_TCP , LW_BYTES , NULL } , /* Time handshake */
{ " Ti " , LOG_FMT_Ti , PR_MODE_HTTP , LW_BYTES , NULL } , /* Time idle */
{ " Tl " , LOG_FMT_DATELOCAL , PR_MODE_TCP , LW_INIT , NULL } , /* date local timezone */
{ " Tq " , LOG_FMT_TQ , PR_MODE_HTTP , LW_BYTES , NULL } , /* Tq=Th+Ti+TR */
{ " Tr " , LOG_FMT_Tr , PR_MODE_HTTP , LW_BYTES , NULL } , /* Tr */
{ " TR " , LOG_FMT_TR , PR_MODE_HTTP , LW_BYTES , NULL } , /* Time to receive a valid request */
2016-05-17 11:55:27 -04:00
{ " Td " , LOG_FMT_TD , PR_MODE_TCP , LW_BYTES , NULL } , /* Td = Tt - (Tq + Tw + Tc + Tr) */
2012-12-20 11:22:52 -05:00
{ " Ts " , LOG_FMT_TS , PR_MODE_TCP , LW_INIT , NULL } , /* timestamp GMT */
2012-04-02 10:22:10 -04:00
{ " Tt " , LOG_FMT_TT , PR_MODE_TCP , LW_BYTES , NULL } , /* Tt */
2020-04-28 08:09:19 -04:00
{ " Tu " , LOG_FMT_TU , PR_MODE_TCP , LW_BYTES , NULL } , /* Tu = Tt -Ti */
2012-12-20 11:22:52 -05:00
{ " Tw " , LOG_FMT_TW , PR_MODE_TCP , LW_BYTES , NULL } , /* Tw */
{ " U " , LOG_FMT_BYTES_UP , PR_MODE_TCP , LW_BYTES , NULL } , /* bytes from client to server */
2012-04-02 10:22:10 -04:00
{ " ac " , LOG_FMT_ACTCONN , PR_MODE_TCP , LW_BYTES , NULL } , /* actconn */
2012-12-20 11:22:52 -05:00
{ " b " , LOG_FMT_BACKEND , PR_MODE_TCP , LW_INIT , NULL } , /* backend */
2012-04-02 10:22:10 -04:00
{ " bc " , LOG_FMT_BECONN , PR_MODE_TCP , LW_BYTES , NULL } , /* beconn */
2012-12-20 11:22:52 -05:00
{ " bi " , LOG_FMT_BACKENDIP , PR_MODE_TCP , LW_BCKIP , prepare_addrsource } , /* backend source ip */
{ " bp " , LOG_FMT_BACKENDPORT , PR_MODE_TCP , LW_BCKIP , prepare_addrsource } , /* backend source port */
2012-04-02 10:22:10 -04:00
{ " bq " , LOG_FMT_BCKQUEUE , PR_MODE_TCP , LW_BYTES , NULL } , /* backend_queue */
2017-06-23 05:23:43 -04:00
{ " ci " , LOG_FMT_CLIENTIP , PR_MODE_TCP , LW_CLIP | LW_XPRT , NULL } , /* client ip */
{ " cp " , LOG_FMT_CLIENTPORT , PR_MODE_TCP , LW_CLIP | LW_XPRT , NULL } , /* client port */
2012-12-20 11:22:52 -05:00
{ " f " , LOG_FMT_FRONTEND , PR_MODE_TCP , LW_INIT , NULL } , /* frontend */
{ " fc " , LOG_FMT_FECONN , PR_MODE_TCP , LW_BYTES , NULL } , /* feconn */
2017-06-23 05:23:43 -04:00
{ " fi " , LOG_FMT_FRONTENDIP , PR_MODE_TCP , LW_FRTIP | LW_XPRT , NULL } , /* frontend ip */
{ " fp " , LOG_FMT_FRONTENDPORT , PR_MODE_TCP , LW_FRTIP | LW_XPRT , NULL } , /* frontend port */
2012-12-20 11:22:52 -05:00
{ " ft " , LOG_FMT_FRONTEND_XPRT , PR_MODE_TCP , LW_INIT , NULL } , /* frontend with transport mode */
2014-06-13 06:23:06 -04:00
{ " hr " , LOG_FMT_HDRREQUEST , PR_MODE_TCP , LW_REQHDR , NULL } , /* header request */
{ " hrl " , LOG_FMT_HDRREQUESTLIST , PR_MODE_TCP , LW_REQHDR , NULL } , /* header request list */
{ " hs " , LOG_FMT_HDRRESPONS , PR_MODE_TCP , LW_RSPHDR , NULL } , /* header response */
{ " hsl " , LOG_FMT_HDRRESPONSLIST , PR_MODE_TCP , LW_RSPHDR , NULL } , /* header response list */
2015-04-27 17:37:03 -04:00
{ " HM " , LOG_FMT_HTTP_METHOD , PR_MODE_HTTP , LW_REQ , NULL } , /* HTTP method */
2020-11-30 13:27:47 -05:00
{ " HP " , LOG_FMT_HTTP_PATH , PR_MODE_HTTP , LW_REQ , NULL } , /* HTTP relative or absolute path */
{ " HPO " , LOG_FMT_HTTP_PATH_ONLY , PR_MODE_HTTP , LW_REQ , NULL } , /* HTTP path only (without host nor query string) */
2015-07-31 12:14:16 -04:00
{ " HQ " , LOG_FMT_HTTP_QUERY , PR_MODE_HTTP , LW_REQ , NULL } , /* HTTP query */
2015-04-27 17:37:03 -04:00
{ " HU " , LOG_FMT_HTTP_URI , PR_MODE_HTTP , LW_REQ , NULL } , /* HTTP full URI */
{ " HV " , LOG_FMT_HTTP_VERSION , PR_MODE_HTTP , LW_REQ , NULL } , /* HTTP version */
2014-08-28 09:03:15 -04:00
{ " lc " , LOG_FMT_LOGCNT , PR_MODE_TCP , LW_INIT , NULL } , /* log counter */
2012-12-20 11:22:52 -05:00
{ " ms " , LOG_FMT_MS , PR_MODE_TCP , LW_INIT , NULL } , /* accept date millisecond */
2012-04-02 10:22:10 -04:00
{ " pid " , LOG_FMT_PID , PR_MODE_TCP , LW_INIT , NULL } , /* log pid */
2012-12-20 11:22:52 -05:00
{ " r " , LOG_FMT_REQ , PR_MODE_HTTP , LW_REQ , NULL } , /* request */
{ " rc " , LOG_FMT_RETRIES , PR_MODE_TCP , LW_BYTES , NULL } , /* retries */
2014-01-25 05:01:50 -05:00
{ " rt " , LOG_FMT_COUNTER , PR_MODE_TCP , LW_REQ , NULL } , /* request counter (HTTP or TCP session) */
2012-12-20 11:22:52 -05:00
{ " s " , LOG_FMT_SERVER , PR_MODE_TCP , LW_SVID , NULL } , /* server */
{ " sc " , LOG_FMT_SRVCONN , PR_MODE_TCP , LW_BYTES , NULL } , /* srv_conn */
{ " si " , LOG_FMT_SERVERIP , PR_MODE_TCP , LW_SVIP , NULL } , /* server destination ip */
{ " sp " , LOG_FMT_SERVERPORT , PR_MODE_TCP , LW_SVIP , NULL } , /* server destination port */
{ " sq " , LOG_FMT_SRVQUEUE , PR_MODE_TCP , LW_BYTES , NULL } , /* srv_queue */
2012-10-12 14:17:54 -04:00
{ " sslc " , LOG_FMT_SSL_CIPHER , PR_MODE_TCP , LW_XPRT , NULL } , /* client-side SSL ciphers */
{ " sslv " , LOG_FMT_SSL_VERSION , PR_MODE_TCP , LW_XPRT , NULL } , /* client-side SSL protocol version */
2012-12-20 11:22:52 -05:00
{ " t " , LOG_FMT_DATE , PR_MODE_TCP , LW_INIT , NULL } , /* date */
MEDIUM: log: Decompose %Tq in %Th %Ti %TR
Tq is the time between the instant the connection is accepted and a
complete valid request is received. This time includes the handshake
(SSL / Proxy-Protocol), the idle when the browser does preconnect and
the request reception.
This patch decomposes %Tq in 3 measurements names %Th, %Ti, and %TR
which returns respectively the handshake time, the idle time and the
duration of valid request reception. It also adds %Ta which reports
the request's active time, which is the total time without %Th nor %Ti.
It replaces %Tt as the total time, reporting accurate measurements for
HTTP persistent connections.
%Th is avalaible for TCP and HTTP sessions, %Ti, %TR and %Ta are only
avalaible for HTTP connections.
In addition to this, we have new timestamps %tr, %trg and %trl, which
log the date of start of receipt of the request, respectively in the
default format, in GMT time and in local time (by analogy with %t, %T
and %Tl). All of them are obviously only available for HTTP. These values
are more relevant as they more accurately represent the request date
without being skewed by a browser's preconnect nor a keep-alive idle
time.
The HTTP log format and the CLF log format have been modified to
use %tr, %TR, and %Ta respectively instead of %t, %Tq and %Tt. This
way the default log formats now produce the expected output for users
who don't want to manually fiddle with the log-format directive.
Example with the following log-format :
log-format "%ci:%cp [%tr] %ft %b/%s h=%Th/i=%Ti/R=%TR/w=%Tw/c=%Tc/r=%Tr/a=%Ta/t=%Tt %ST %B %CC %CS %tsc %ac/%fc/%bc/%sc/%rc %sq/%bq %hr %hs %{+Q}r"
The request was sent by hand using "openssl s_client -connect" :
Aug 23 14:43:20 haproxy[25446]: 127.0.0.1:45636 [23/Aug/2016:14:43:20.221] test~ test/test h=6/i=2375/R=261/w=0/c=1/r=0/a=262/t=2643 200 145 - - ---- 1/1/0/0/0 0/0 "GET / HTTP/1.1"
=> 6 ms of SSL handshake, 2375 waiting before sending the first char (in
fact the time to type the first line), 261 ms before the end of the request,
no time spent in queue, 1 ms spend connecting to the server, immediate
response, total active time for this request = 262ms. Total time from accept
to close : 2643 ms.
The timing now decomposes like this :
first request 2nd request
|<-------------------------------->|<-------------- ...
t tr t tr ...
---|----|----|----|----|----|----|----|----|--
: Th Ti TR Tw Tc Tr Td : Ti ...
:<---- Tq ---->: :
:<-------------- Tt -------------->:
:<--------- Ta --------->:
2016-07-28 11:19:45 -04:00
{ " tr " , LOG_FMT_tr , PR_MODE_HTTP , LW_INIT , NULL } , /* date of start of request */
{ " trg " , LOG_FMT_trg , PR_MODE_HTTP , LW_INIT , NULL } , /* date of start of request, GMT */
{ " trl " , LOG_FMT_trl , PR_MODE_HTTP , LW_INIT , NULL } , /* date of start of request, local */
2012-12-20 11:22:52 -05:00
{ " ts " , LOG_FMT_TERMSTATE , PR_MODE_TCP , LW_BYTES , NULL } , /* termination state */
{ " tsc " , LOG_FMT_TERMSTATE_CK , PR_MODE_TCP , LW_INIT , NULL } , /* termination state */
2012-04-02 10:22:10 -04:00
{ 0 , 0 , 0 , 0 , NULL }
2012-02-08 10:37:49 -05:00
} ;
2022-12-22 09:37:01 -05:00
char httpclient_log_format [ ] = " %ci:%cp [%tr] %ft -/- %TR/%Tw/%Tc/%Tr/%Ta %ST %B %CC %CS %tsc %ac/%fc/%bc/%sc/%rc %sq/%bq %hr %hs %{+Q}r " ;
MEDIUM: log: Decompose %Tq in %Th %Ti %TR
Tq is the time between the instant the connection is accepted and a
complete valid request is received. This time includes the handshake
(SSL / Proxy-Protocol), the idle when the browser does preconnect and
the request reception.
This patch decomposes %Tq in 3 measurements names %Th, %Ti, and %TR
which returns respectively the handshake time, the idle time and the
duration of valid request reception. It also adds %Ta which reports
the request's active time, which is the total time without %Th nor %Ti.
It replaces %Tt as the total time, reporting accurate measurements for
HTTP persistent connections.
%Th is avalaible for TCP and HTTP sessions, %Ti, %TR and %Ta are only
avalaible for HTTP connections.
In addition to this, we have new timestamps %tr, %trg and %trl, which
log the date of start of receipt of the request, respectively in the
default format, in GMT time and in local time (by analogy with %t, %T
and %Tl). All of them are obviously only available for HTTP. These values
are more relevant as they more accurately represent the request date
without being skewed by a browser's preconnect nor a keep-alive idle
time.
The HTTP log format and the CLF log format have been modified to
use %tr, %TR, and %Ta respectively instead of %t, %Tq and %Tt. This
way the default log formats now produce the expected output for users
who don't want to manually fiddle with the log-format directive.
Example with the following log-format :
log-format "%ci:%cp [%tr] %ft %b/%s h=%Th/i=%Ti/R=%TR/w=%Tw/c=%Tc/r=%Tr/a=%Ta/t=%Tt %ST %B %CC %CS %tsc %ac/%fc/%bc/%sc/%rc %sq/%bq %hr %hs %{+Q}r"
The request was sent by hand using "openssl s_client -connect" :
Aug 23 14:43:20 haproxy[25446]: 127.0.0.1:45636 [23/Aug/2016:14:43:20.221] test~ test/test h=6/i=2375/R=261/w=0/c=1/r=0/a=262/t=2643 200 145 - - ---- 1/1/0/0/0 0/0 "GET / HTTP/1.1"
=> 6 ms of SSL handshake, 2375 waiting before sending the first char (in
fact the time to type the first line), 261 ms before the end of the request,
no time spent in queue, 1 ms spend connecting to the server, immediate
response, total active time for this request = 262ms. Total time from accept
to close : 2643 ms.
The timing now decomposes like this :
first request 2nd request
|<-------------------------------->|<-------------- ...
t tr t tr ...
---|----|----|----|----|----|----|----|----|--
: Th Ti TR Tw Tc Tr Td : Ti ...
:<---- Tq ---->: :
:<-------------- Tt -------------->:
:<--------- Ta --------->:
2016-07-28 11:19:45 -04:00
char 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
2021-11-05 14:14:55 -04:00
char default_https_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 %[fc_err]/%[ssl_fc_err,hex]/%[ssl_c_err]/%[ssl_c_ca_err]/%[ssl_fc_is_resumed] %[ssl_fc_sni]/%sslv/%sslc " ;
MEDIUM: log: Decompose %Tq in %Th %Ti %TR
Tq is the time between the instant the connection is accepted and a
complete valid request is received. This time includes the handshake
(SSL / Proxy-Protocol), the idle when the browser does preconnect and
the request reception.
This patch decomposes %Tq in 3 measurements names %Th, %Ti, and %TR
which returns respectively the handshake time, the idle time and the
duration of valid request reception. It also adds %Ta which reports
the request's active time, which is the total time without %Th nor %Ti.
It replaces %Tt as the total time, reporting accurate measurements for
HTTP persistent connections.
%Th is avalaible for TCP and HTTP sessions, %Ti, %TR and %Ta are only
avalaible for HTTP connections.
In addition to this, we have new timestamps %tr, %trg and %trl, which
log the date of start of receipt of the request, respectively in the
default format, in GMT time and in local time (by analogy with %t, %T
and %Tl). All of them are obviously only available for HTTP. These values
are more relevant as they more accurately represent the request date
without being skewed by a browser's preconnect nor a keep-alive idle
time.
The HTTP log format and the CLF log format have been modified to
use %tr, %TR, and %Ta respectively instead of %t, %Tq and %Tt. This
way the default log formats now produce the expected output for users
who don't want to manually fiddle with the log-format directive.
Example with the following log-format :
log-format "%ci:%cp [%tr] %ft %b/%s h=%Th/i=%Ti/R=%TR/w=%Tw/c=%Tc/r=%Tr/a=%Ta/t=%Tt %ST %B %CC %CS %tsc %ac/%fc/%bc/%sc/%rc %sq/%bq %hr %hs %{+Q}r"
The request was sent by hand using "openssl s_client -connect" :
Aug 23 14:43:20 haproxy[25446]: 127.0.0.1:45636 [23/Aug/2016:14:43:20.221] test~ test/test h=6/i=2375/R=261/w=0/c=1/r=0/a=262/t=2643 200 145 - - ---- 1/1/0/0/0 0/0 "GET / HTTP/1.1"
=> 6 ms of SSL handshake, 2375 waiting before sending the first char (in
fact the time to type the first line), 261 ms before the end of the request,
no time spent in queue, 1 ms spend connecting to the server, immediate
response, total active time for this request = 262ms. Total time from accept
to close : 2643 ms.
The timing now decomposes like this :
first request 2nd request
|<-------------------------------->|<-------------- ...
t tr t tr ...
---|----|----|----|----|----|----|----|----|--
: Th Ti TR Tw Tc Tr Td : Ti ...
:<---- Tq ---->: :
:<-------------- Tt -------------->:
:<--------- Ta --------->:
2016-07-28 11:19:45 -04:00
char 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 " ;
2012-12-20 11:22:52 -05:00
char default_tcp_log_format [ ] = " %ci:%cp [%t] %ft %b/%s %Tw/%Tc/%Tt %B %ts %ac/%fc/%bc/%sc/%rc %sq/%bq " ;
2012-02-08 10:37:49 -05:00
char * log_format = NULL ;
2015-09-25 13:17:44 -04:00
/* Default string used for structured-data part in RFC5424 formatted
* syslog messages .
*/
char default_rfc5424_sd_log_format [ ] = " - " ;
2015-09-22 10:05:32 -04:00
MEDIUM: proxy/log: leverage lf_expr API for logformat preparsing
Currently, the way proxy-oriented logformat directives are handled is way
too complicated. Indeed, "log-format", "log-format-error", "log-format-sd"
and "unique-id-format" all rely on preparsing hints stored inside
proxy->conf member struct. Those preparsing hints include the original
string that should be compiled once the proxy parameters are known plus
the config file and line number where the string was found to generate
precise error messages in case of failure during the compiling process
that happens within check_config_validity().
Now that lf_expr API permits to compile a lf_expr struct that was
previously prepared (with original string and config hints), let's
leverage lf_expr_compile() from check_config_validity() and instead
of relying on individual proxy->conf hints for each logformat expression,
store string and config hints in the lf_expr struct directly and use
lf_expr helpers funcs to handle them when relevant (ie: original
logformat string freeing is now done at a central place inside
lf_expr_deinit(), which allows for some simplifications)
Doing so allows us to greatly simplify the preparsing logic for those 4
proxy directives, and to finally save some space in the proxy struct.
Also, since httpclient proxy has its "logformat" automatically compiled
in check_config_validity(), we now use the file hint from the logformat
expression struct to set an explicit name that will be reported in case
of error ("parsing [httpclient:0] : ...") and remove the extraneous check
in httpclient_precheck() (logformat was parsed twice previously..)
2024-03-05 09:44:43 -05:00
/* returns true if the input logformat string is one of the default ones declared
* above
*/
static inline int logformat_str_isdefault ( const char * str )
{
return str = = httpclient_log_format | |
str = = default_http_log_format | |
str = = default_https_log_format | |
str = = clf_http_log_format | |
str = = default_tcp_log_format | |
str = = default_rfc5424_sd_log_format ;
}
/* free logformat str if it is not a default (static) one */
static inline void logformat_str_free ( char * * str )
{
if ( ! logformat_str_isdefault ( * str ) )
ha_free ( str ) ;
}
/* duplicate and return logformat str if it is not a default (static)
* one , else return the original one
*/
static inline char * logformat_str_dup ( char * str )
{
if ( logformat_str_isdefault ( str ) )
return str ;
return strdup ( str ) ;
}
2018-11-12 01:25:28 -05:00
/* total number of dropped logs */
unsigned int dropped_logs = 0 ;
2015-09-19 16:09:02 -04:00
/* This is a global syslog message buffer, common to all outgoing
* messages . It contains only the data part .
2012-03-19 11:51:53 -04:00
*/
2017-06-02 10:20:16 -04:00
THREAD_LOCAL char * logline = NULL ;
2012-03-19 11:51:53 -04:00
2015-09-25 13:17:44 -04:00
/* A global syslog message buffer, common to all RFC5424 syslog messages.
* Currently , it is used for generating the structured - data part .
*/
2017-06-02 10:20:16 -04:00
THREAD_LOCAL char * logline_rfc5424 = NULL ;
2015-09-25 13:17:44 -04:00
MINOR: log: rename 'log-format tag' to 'log-format alias'
In 2.9 we started to introduce an ambiguity in the documentation by
referring to historical log-format variables ('%var') as log-format
tags in 739c4e5b1e ("MINOR: sample: accept_date / request_date return
%Ts / %tr timestamp values") and 454c372b60 ("DOC: configuration: add
sample fetches for timing events").
In fact, we've had this confusion between log-format tag and log-format
var for more than 10 years now, but in 2.9 it was the first time the
confusion was exposed in the documentation.
Indeed, both 'log-format variable' and 'log-format tag' actually refer
to the same feature (that is: '%B' and friends that can be used for
direct access to some log-oriented predefined fetches instead of using
%[expr] with generic sample expressions).
This feature was first implemented in 723b73ad75 ("MINOR: config: Parse
the string of the log-format config keyword") and later documented in
4894040fa ("DOC: log-format documentation"). At that time, it was clear
that we used to name it 'log-format variable'.
But later the same year, 'log-format tag' naming started to appear in
some commit messages (while still referring to the same feature), for
instance with ffc3fcd6d ("MEDIUM: log: report SSL ciphers and version
in logs using logformat %sslc/%sslv").
Unfortunately in 2.9 when we added (and documented) new log-format
variables we officially started drifting to the misleading 'log-format
tag' naming (perhaps because it was the most recent naming found for
this feature in git log history, or because the confusion has always
been there)
Even worse, in 3.0 this confusion led us to rename all 'var' occurrences
to 'tag' in log-format related code to unify the code with the doc.
Hopefully William quickly noticed that we made a mistake there, but
instead of reverting to historical naming (log-format variable), it was
decided that we must use a different name that is less confusing than
'tags' or 'variables' (tags and variables are keywords that are already
used to designate other features in the code and that are not very
explicit under log-format context today).
Now we refer to '%B' and friends as a logformat alias, which is
essentially a handy way to print some log oriented information in the
log string instead of leveraging '%[expr]' with generic sample expressions
made of fetches and converters. Of course, there are some subtelties, such
as a few log-format aliases that still don't have sample fetch equivalent
for historical reasons, and some aliases that may be a little faster than
their generic sample expression equivalents because most aliases are
pretty much hardcoded in the log building function. But in general
logformat aliases should be simply considered as an alternative to using
expressions (with '%[expr']')
Also, under log-format context, when we want to refer to either an alias
('%alias') or an expression ('%[expr]'), we should use the generic term
'logformat item', which in fact designates a single item within the
logformat string provided by the user. Indeed, a logformat item (whether
is is an alias or an expression) always starts with '%' and may accept
optional flags / arguments
Both the code and the documentation were updated in that sense, hopefully
this will clarify things and prevent future confusions.
2024-05-27 04:18:10 -04:00
struct logformat_node_args {
2012-02-08 10:37:49 -05:00
char * name ;
int mask ;
} ;
MINOR: log: rename 'log-format tag' to 'log-format alias'
In 2.9 we started to introduce an ambiguity in the documentation by
referring to historical log-format variables ('%var') as log-format
tags in 739c4e5b1e ("MINOR: sample: accept_date / request_date return
%Ts / %tr timestamp values") and 454c372b60 ("DOC: configuration: add
sample fetches for timing events").
In fact, we've had this confusion between log-format tag and log-format
var for more than 10 years now, but in 2.9 it was the first time the
confusion was exposed in the documentation.
Indeed, both 'log-format variable' and 'log-format tag' actually refer
to the same feature (that is: '%B' and friends that can be used for
direct access to some log-oriented predefined fetches instead of using
%[expr] with generic sample expressions).
This feature was first implemented in 723b73ad75 ("MINOR: config: Parse
the string of the log-format config keyword") and later documented in
4894040fa ("DOC: log-format documentation"). At that time, it was clear
that we used to name it 'log-format variable'.
But later the same year, 'log-format tag' naming started to appear in
some commit messages (while still referring to the same feature), for
instance with ffc3fcd6d ("MEDIUM: log: report SSL ciphers and version
in logs using logformat %sslc/%sslv").
Unfortunately in 2.9 when we added (and documented) new log-format
variables we officially started drifting to the misleading 'log-format
tag' naming (perhaps because it was the most recent naming found for
this feature in git log history, or because the confusion has always
been there)
Even worse, in 3.0 this confusion led us to rename all 'var' occurrences
to 'tag' in log-format related code to unify the code with the doc.
Hopefully William quickly noticed that we made a mistake there, but
instead of reverting to historical naming (log-format variable), it was
decided that we must use a different name that is less confusing than
'tags' or 'variables' (tags and variables are keywords that are already
used to designate other features in the code and that are not very
explicit under log-format context today).
Now we refer to '%B' and friends as a logformat alias, which is
essentially a handy way to print some log oriented information in the
log string instead of leveraging '%[expr]' with generic sample expressions
made of fetches and converters. Of course, there are some subtelties, such
as a few log-format aliases that still don't have sample fetch equivalent
for historical reasons, and some aliases that may be a little faster than
their generic sample expression equivalents because most aliases are
pretty much hardcoded in the log building function. But in general
logformat aliases should be simply considered as an alternative to using
expressions (with '%[expr']')
Also, under log-format context, when we want to refer to either an alias
('%alias') or an expression ('%[expr]'), we should use the generic term
'logformat item', which in fact designates a single item within the
logformat string provided by the user. Indeed, a logformat item (whether
is is an alias or an expression) always starts with '%' and may accept
optional flags / arguments
Both the code and the documentation were updated in that sense, hopefully
this will clarify things and prevent future confusions.
2024-05-27 04:18:10 -04:00
struct logformat_node_args node_args_list [ ] = {
2012-02-08 10:37:49 -05:00
// global
{ " M " , LOG_OPT_MANDATORY } ,
{ " Q " , LOG_OPT_QUOTE } ,
2012-04-05 12:02:55 -04:00
{ " X " , LOG_OPT_HEXA } ,
2016-02-12 07:23:03 -05:00
{ " E " , LOG_OPT_ESC } ,
2024-04-25 10:29:01 -04:00
{ " bin " , LOG_OPT_BIN } ,
2024-04-22 08:40:04 -04:00
{ " json " , LOG_OPT_ENCODE_JSON } ,
2024-04-23 04:12:46 -04:00
{ " cbor " , LOG_OPT_ENCODE_CBOR } ,
2012-02-08 10:37:49 -05:00
{ 0 , 0 }
} ;
2012-03-02 08:35:21 -05:00
/*
* callback used to configure addr source retrieval
*/
int prepare_addrsource ( struct logformat_node * node , struct proxy * curproxy )
{
MAJOR: log: implement proper postparsing for logformat expressions
This patch tries to address a design flaw with how logformat expressions
are parsed from config. Indeed, some parse_logformat_string() calls are
performed during config parsing when the proxy mode is not yet known.
Here's a config example that illustrates the issue:
defaults
mode tcp
listen test
bind :8888
http-response set-header custom-hdr "%trl" # needs http
mode http
The above config should work, because the effective proxy mode is http,
yet haproxy fails with this error:
[ALERT] (99051) : config : parsing [repro.conf:6] : error detected in proxy 'test' while parsing 'http-response set-header' rule : format tag 'trl' is reserved for HTTP mode.
To fix the issue once and for all, let's implement smart postparsing for
logformat expressions encountered during config parsing:
- split parse_logformat_string() (and subfonctions) in order to create a
new lf_expr_postcheck() function that must be called to finish
preparing and checking the logformat expression once the proxy type is
known.
- save some config hints info during parse_logformat_string() to
generate more precise error messages during lf_expr_postcheck(), if
needed, we rely on curpx->conf.args.{file,line} hints for that because
parse_logformat_string() doesn't know about current file and line
number.
- lf_expr_postcheck() uses PR_FL_CHECKED proxy flag to know if the
function may try to make the proxy compatible with the expression, or
if it should simply fail as soon as an incompatibility is detected.
- if parse_logformat_string() is called from an unchecked proxy, then
schedule the expression for postparsing, else (ie: during runtime),
run the postcheck right away.
This change will also allow for some logformat expression error handling
simplifications in the future.
2024-02-23 11:26:32 -05:00
if ( ( curproxy - > flags & PR_FL_CHECKED ) )
return 0 ;
2012-03-02 08:35:21 -05:00
MAJOR: log: implement proper postparsing for logformat expressions
This patch tries to address a design flaw with how logformat expressions
are parsed from config. Indeed, some parse_logformat_string() calls are
performed during config parsing when the proxy mode is not yet known.
Here's a config example that illustrates the issue:
defaults
mode tcp
listen test
bind :8888
http-response set-header custom-hdr "%trl" # needs http
mode http
The above config should work, because the effective proxy mode is http,
yet haproxy fails with this error:
[ALERT] (99051) : config : parsing [repro.conf:6] : error detected in proxy 'test' while parsing 'http-response set-header' rule : format tag 'trl' is reserved for HTTP mode.
To fix the issue once and for all, let's implement smart postparsing for
logformat expressions encountered during config parsing:
- split parse_logformat_string() (and subfonctions) in order to create a
new lf_expr_postcheck() function that must be called to finish
preparing and checking the logformat expression once the proxy type is
known.
- save some config hints info during parse_logformat_string() to
generate more precise error messages during lf_expr_postcheck(), if
needed, we rely on curpx->conf.args.{file,line} hints for that because
parse_logformat_string() doesn't know about current file and line
number.
- lf_expr_postcheck() uses PR_FL_CHECKED proxy flag to know if the
function may try to make the proxy compatible with the expression, or
if it should simply fail as soon as an incompatibility is detected.
- if parse_logformat_string() is called from an unchecked proxy, then
schedule the expression for postparsing, else (ie: during runtime),
run the postcheck right away.
This change will also allow for some logformat expression error handling
simplifications in the future.
2024-02-23 11:26:32 -05:00
curproxy - > options2 | = PR_O2_SRC_ADDR ;
return 1 ;
2012-03-02 08:35:21 -05:00
}
2012-02-08 10:37:49 -05:00
/*
MINOR: log: rename 'log-format tag' to 'log-format alias'
In 2.9 we started to introduce an ambiguity in the documentation by
referring to historical log-format variables ('%var') as log-format
tags in 739c4e5b1e ("MINOR: sample: accept_date / request_date return
%Ts / %tr timestamp values") and 454c372b60 ("DOC: configuration: add
sample fetches for timing events").
In fact, we've had this confusion between log-format tag and log-format
var for more than 10 years now, but in 2.9 it was the first time the
confusion was exposed in the documentation.
Indeed, both 'log-format variable' and 'log-format tag' actually refer
to the same feature (that is: '%B' and friends that can be used for
direct access to some log-oriented predefined fetches instead of using
%[expr] with generic sample expressions).
This feature was first implemented in 723b73ad75 ("MINOR: config: Parse
the string of the log-format config keyword") and later documented in
4894040fa ("DOC: log-format documentation"). At that time, it was clear
that we used to name it 'log-format variable'.
But later the same year, 'log-format tag' naming started to appear in
some commit messages (while still referring to the same feature), for
instance with ffc3fcd6d ("MEDIUM: log: report SSL ciphers and version
in logs using logformat %sslc/%sslv").
Unfortunately in 2.9 when we added (and documented) new log-format
variables we officially started drifting to the misleading 'log-format
tag' naming (perhaps because it was the most recent naming found for
this feature in git log history, or because the confusion has always
been there)
Even worse, in 3.0 this confusion led us to rename all 'var' occurrences
to 'tag' in log-format related code to unify the code with the doc.
Hopefully William quickly noticed that we made a mistake there, but
instead of reverting to historical naming (log-format variable), it was
decided that we must use a different name that is less confusing than
'tags' or 'variables' (tags and variables are keywords that are already
used to designate other features in the code and that are not very
explicit under log-format context today).
Now we refer to '%B' and friends as a logformat alias, which is
essentially a handy way to print some log oriented information in the
log string instead of leveraging '%[expr]' with generic sample expressions
made of fetches and converters. Of course, there are some subtelties, such
as a few log-format aliases that still don't have sample fetch equivalent
for historical reasons, and some aliases that may be a little faster than
their generic sample expression equivalents because most aliases are
pretty much hardcoded in the log building function. But in general
logformat aliases should be simply considered as an alternative to using
expressions (with '%[expr']')
Also, under log-format context, when we want to refer to either an alias
('%alias') or an expression ('%[expr]'), we should use the generic term
'logformat item', which in fact designates a single item within the
logformat string provided by the user. Indeed, a logformat item (whether
is is an alias or an expression) always starts with '%' and may accept
optional flags / arguments
Both the code and the documentation were updated in that sense, hopefully
this will clarify things and prevent future confusions.
2024-05-27 04:18:10 -04:00
* Parse args in a logformat_node . Returns 0 in error
2016-11-22 17:13:04 -05:00
* case , otherwise , it returns 1.
2012-02-08 10:37:49 -05:00
*/
MINOR: log: rename 'log-format tag' to 'log-format alias'
In 2.9 we started to introduce an ambiguity in the documentation by
referring to historical log-format variables ('%var') as log-format
tags in 739c4e5b1e ("MINOR: sample: accept_date / request_date return
%Ts / %tr timestamp values") and 454c372b60 ("DOC: configuration: add
sample fetches for timing events").
In fact, we've had this confusion between log-format tag and log-format
var for more than 10 years now, but in 2.9 it was the first time the
confusion was exposed in the documentation.
Indeed, both 'log-format variable' and 'log-format tag' actually refer
to the same feature (that is: '%B' and friends that can be used for
direct access to some log-oriented predefined fetches instead of using
%[expr] with generic sample expressions).
This feature was first implemented in 723b73ad75 ("MINOR: config: Parse
the string of the log-format config keyword") and later documented in
4894040fa ("DOC: log-format documentation"). At that time, it was clear
that we used to name it 'log-format variable'.
But later the same year, 'log-format tag' naming started to appear in
some commit messages (while still referring to the same feature), for
instance with ffc3fcd6d ("MEDIUM: log: report SSL ciphers and version
in logs using logformat %sslc/%sslv").
Unfortunately in 2.9 when we added (and documented) new log-format
variables we officially started drifting to the misleading 'log-format
tag' naming (perhaps because it was the most recent naming found for
this feature in git log history, or because the confusion has always
been there)
Even worse, in 3.0 this confusion led us to rename all 'var' occurrences
to 'tag' in log-format related code to unify the code with the doc.
Hopefully William quickly noticed that we made a mistake there, but
instead of reverting to historical naming (log-format variable), it was
decided that we must use a different name that is less confusing than
'tags' or 'variables' (tags and variables are keywords that are already
used to designate other features in the code and that are not very
explicit under log-format context today).
Now we refer to '%B' and friends as a logformat alias, which is
essentially a handy way to print some log oriented information in the
log string instead of leveraging '%[expr]' with generic sample expressions
made of fetches and converters. Of course, there are some subtelties, such
as a few log-format aliases that still don't have sample fetch equivalent
for historical reasons, and some aliases that may be a little faster than
their generic sample expression equivalents because most aliases are
pretty much hardcoded in the log building function. But in general
logformat aliases should be simply considered as an alternative to using
expressions (with '%[expr']')
Also, under log-format context, when we want to refer to either an alias
('%alias') or an expression ('%[expr]'), we should use the generic term
'logformat item', which in fact designates a single item within the
logformat string provided by the user. Indeed, a logformat item (whether
is is an alias or an expression) always starts with '%' and may accept
optional flags / arguments
Both the code and the documentation were updated in that sense, hopefully
this will clarify things and prevent future confusions.
2024-05-27 04:18:10 -04:00
int parse_logformat_node_args ( char * args , struct logformat_node * node , char * * err )
2012-02-08 10:37:49 -05:00
{
int i = 0 ;
int end = 0 ;
int flags = 0 ; // 1 = + 2 = -
char * sp = NULL ; // start pointer
2016-11-22 18:41:28 -05:00
if ( args = = NULL ) {
MINOR: log: rename 'log-format tag' to 'log-format alias'
In 2.9 we started to introduce an ambiguity in the documentation by
referring to historical log-format variables ('%var') as log-format
tags in 739c4e5b1e ("MINOR: sample: accept_date / request_date return
%Ts / %tr timestamp values") and 454c372b60 ("DOC: configuration: add
sample fetches for timing events").
In fact, we've had this confusion between log-format tag and log-format
var for more than 10 years now, but in 2.9 it was the first time the
confusion was exposed in the documentation.
Indeed, both 'log-format variable' and 'log-format tag' actually refer
to the same feature (that is: '%B' and friends that can be used for
direct access to some log-oriented predefined fetches instead of using
%[expr] with generic sample expressions).
This feature was first implemented in 723b73ad75 ("MINOR: config: Parse
the string of the log-format config keyword") and later documented in
4894040fa ("DOC: log-format documentation"). At that time, it was clear
that we used to name it 'log-format variable'.
But later the same year, 'log-format tag' naming started to appear in
some commit messages (while still referring to the same feature), for
instance with ffc3fcd6d ("MEDIUM: log: report SSL ciphers and version
in logs using logformat %sslc/%sslv").
Unfortunately in 2.9 when we added (and documented) new log-format
variables we officially started drifting to the misleading 'log-format
tag' naming (perhaps because it was the most recent naming found for
this feature in git log history, or because the confusion has always
been there)
Even worse, in 3.0 this confusion led us to rename all 'var' occurrences
to 'tag' in log-format related code to unify the code with the doc.
Hopefully William quickly noticed that we made a mistake there, but
instead of reverting to historical naming (log-format variable), it was
decided that we must use a different name that is less confusing than
'tags' or 'variables' (tags and variables are keywords that are already
used to designate other features in the code and that are not very
explicit under log-format context today).
Now we refer to '%B' and friends as a logformat alias, which is
essentially a handy way to print some log oriented information in the
log string instead of leveraging '%[expr]' with generic sample expressions
made of fetches and converters. Of course, there are some subtelties, such
as a few log-format aliases that still don't have sample fetch equivalent
for historical reasons, and some aliases that may be a little faster than
their generic sample expression equivalents because most aliases are
pretty much hardcoded in the log building function. But in general
logformat aliases should be simply considered as an alternative to using
expressions (with '%[expr']')
Also, under log-format context, when we want to refer to either an alias
('%alias') or an expression ('%[expr]'), we should use the generic term
'logformat item', which in fact designates a single item within the
logformat string provided by the user. Indeed, a logformat item (whether
is is an alias or an expression) always starts with '%' and may accept
optional flags / arguments
Both the code and the documentation were updated in that sense, hopefully
this will clarify things and prevent future confusions.
2024-05-27 04:18:10 -04:00
memprintf ( err , " internal error: parse_logformat_node_args() expects non null 'args' " ) ;
2016-11-22 17:13:04 -05:00
return 0 ;
2016-11-22 18:41:28 -05:00
}
2012-02-08 10:37:49 -05:00
while ( 1 ) {
if ( * args = = ' \0 ' )
end = 1 ;
if ( * args = = ' + ' ) {
// add flag
sp = args + 1 ;
flags = 1 ;
}
if ( * args = = ' - ' ) {
// delete flag
sp = args + 1 ;
flags = 2 ;
}
if ( * args = = ' \0 ' | | * args = = ' , ' ) {
* args = ' \0 ' ;
MINOR: log: rename 'log-format tag' to 'log-format alias'
In 2.9 we started to introduce an ambiguity in the documentation by
referring to historical log-format variables ('%var') as log-format
tags in 739c4e5b1e ("MINOR: sample: accept_date / request_date return
%Ts / %tr timestamp values") and 454c372b60 ("DOC: configuration: add
sample fetches for timing events").
In fact, we've had this confusion between log-format tag and log-format
var for more than 10 years now, but in 2.9 it was the first time the
confusion was exposed in the documentation.
Indeed, both 'log-format variable' and 'log-format tag' actually refer
to the same feature (that is: '%B' and friends that can be used for
direct access to some log-oriented predefined fetches instead of using
%[expr] with generic sample expressions).
This feature was first implemented in 723b73ad75 ("MINOR: config: Parse
the string of the log-format config keyword") and later documented in
4894040fa ("DOC: log-format documentation"). At that time, it was clear
that we used to name it 'log-format variable'.
But later the same year, 'log-format tag' naming started to appear in
some commit messages (while still referring to the same feature), for
instance with ffc3fcd6d ("MEDIUM: log: report SSL ciphers and version
in logs using logformat %sslc/%sslv").
Unfortunately in 2.9 when we added (and documented) new log-format
variables we officially started drifting to the misleading 'log-format
tag' naming (perhaps because it was the most recent naming found for
this feature in git log history, or because the confusion has always
been there)
Even worse, in 3.0 this confusion led us to rename all 'var' occurrences
to 'tag' in log-format related code to unify the code with the doc.
Hopefully William quickly noticed that we made a mistake there, but
instead of reverting to historical naming (log-format variable), it was
decided that we must use a different name that is less confusing than
'tags' or 'variables' (tags and variables are keywords that are already
used to designate other features in the code and that are not very
explicit under log-format context today).
Now we refer to '%B' and friends as a logformat alias, which is
essentially a handy way to print some log oriented information in the
log string instead of leveraging '%[expr]' with generic sample expressions
made of fetches and converters. Of course, there are some subtelties, such
as a few log-format aliases that still don't have sample fetch equivalent
for historical reasons, and some aliases that may be a little faster than
their generic sample expression equivalents because most aliases are
pretty much hardcoded in the log building function. But in general
logformat aliases should be simply considered as an alternative to using
expressions (with '%[expr']')
Also, under log-format context, when we want to refer to either an alias
('%alias') or an expression ('%[expr]'), we should use the generic term
'logformat item', which in fact designates a single item within the
logformat string provided by the user. Indeed, a logformat item (whether
is is an alias or an expression) always starts with '%' and may accept
optional flags / arguments
Both the code and the documentation were updated in that sense, hopefully
this will clarify things and prevent future confusions.
2024-05-27 04:18:10 -04:00
for ( i = 0 ; sp & & node_args_list [ i ] . name ; i + + ) {
if ( strcmp ( sp , node_args_list [ i ] . name ) = = 0 ) {
2012-02-08 10:37:49 -05:00
if ( flags = = 1 ) {
2024-04-22 08:40:04 -04:00
/* Ensure we don't mix encoding types, existing
* encoding type prevails over new ones
*/
if ( node - > options & LOG_OPT_ENCODE )
MINOR: log: rename 'log-format tag' to 'log-format alias'
In 2.9 we started to introduce an ambiguity in the documentation by
referring to historical log-format variables ('%var') as log-format
tags in 739c4e5b1e ("MINOR: sample: accept_date / request_date return
%Ts / %tr timestamp values") and 454c372b60 ("DOC: configuration: add
sample fetches for timing events").
In fact, we've had this confusion between log-format tag and log-format
var for more than 10 years now, but in 2.9 it was the first time the
confusion was exposed in the documentation.
Indeed, both 'log-format variable' and 'log-format tag' actually refer
to the same feature (that is: '%B' and friends that can be used for
direct access to some log-oriented predefined fetches instead of using
%[expr] with generic sample expressions).
This feature was first implemented in 723b73ad75 ("MINOR: config: Parse
the string of the log-format config keyword") and later documented in
4894040fa ("DOC: log-format documentation"). At that time, it was clear
that we used to name it 'log-format variable'.
But later the same year, 'log-format tag' naming started to appear in
some commit messages (while still referring to the same feature), for
instance with ffc3fcd6d ("MEDIUM: log: report SSL ciphers and version
in logs using logformat %sslc/%sslv").
Unfortunately in 2.9 when we added (and documented) new log-format
variables we officially started drifting to the misleading 'log-format
tag' naming (perhaps because it was the most recent naming found for
this feature in git log history, or because the confusion has always
been there)
Even worse, in 3.0 this confusion led us to rename all 'var' occurrences
to 'tag' in log-format related code to unify the code with the doc.
Hopefully William quickly noticed that we made a mistake there, but
instead of reverting to historical naming (log-format variable), it was
decided that we must use a different name that is less confusing than
'tags' or 'variables' (tags and variables are keywords that are already
used to designate other features in the code and that are not very
explicit under log-format context today).
Now we refer to '%B' and friends as a logformat alias, which is
essentially a handy way to print some log oriented information in the
log string instead of leveraging '%[expr]' with generic sample expressions
made of fetches and converters. Of course, there are some subtelties, such
as a few log-format aliases that still don't have sample fetch equivalent
for historical reasons, and some aliases that may be a little faster than
their generic sample expression equivalents because most aliases are
pretty much hardcoded in the log building function. But in general
logformat aliases should be simply considered as an alternative to using
expressions (with '%[expr']')
Also, under log-format context, when we want to refer to either an alias
('%alias') or an expression ('%[expr]'), we should use the generic term
'logformat item', which in fact designates a single item within the
logformat string provided by the user. Indeed, a logformat item (whether
is is an alias or an expression) always starts with '%' and may accept
optional flags / arguments
Both the code and the documentation were updated in that sense, hopefully
this will clarify things and prevent future confusions.
2024-05-27 04:18:10 -04:00
node - > options | = ( node_args_list [ i ] . mask & ~ LOG_OPT_ENCODE ) ;
2024-04-22 08:40:04 -04:00
else
MINOR: log: rename 'log-format tag' to 'log-format alias'
In 2.9 we started to introduce an ambiguity in the documentation by
referring to historical log-format variables ('%var') as log-format
tags in 739c4e5b1e ("MINOR: sample: accept_date / request_date return
%Ts / %tr timestamp values") and 454c372b60 ("DOC: configuration: add
sample fetches for timing events").
In fact, we've had this confusion between log-format tag and log-format
var for more than 10 years now, but in 2.9 it was the first time the
confusion was exposed in the documentation.
Indeed, both 'log-format variable' and 'log-format tag' actually refer
to the same feature (that is: '%B' and friends that can be used for
direct access to some log-oriented predefined fetches instead of using
%[expr] with generic sample expressions).
This feature was first implemented in 723b73ad75 ("MINOR: config: Parse
the string of the log-format config keyword") and later documented in
4894040fa ("DOC: log-format documentation"). At that time, it was clear
that we used to name it 'log-format variable'.
But later the same year, 'log-format tag' naming started to appear in
some commit messages (while still referring to the same feature), for
instance with ffc3fcd6d ("MEDIUM: log: report SSL ciphers and version
in logs using logformat %sslc/%sslv").
Unfortunately in 2.9 when we added (and documented) new log-format
variables we officially started drifting to the misleading 'log-format
tag' naming (perhaps because it was the most recent naming found for
this feature in git log history, or because the confusion has always
been there)
Even worse, in 3.0 this confusion led us to rename all 'var' occurrences
to 'tag' in log-format related code to unify the code with the doc.
Hopefully William quickly noticed that we made a mistake there, but
instead of reverting to historical naming (log-format variable), it was
decided that we must use a different name that is less confusing than
'tags' or 'variables' (tags and variables are keywords that are already
used to designate other features in the code and that are not very
explicit under log-format context today).
Now we refer to '%B' and friends as a logformat alias, which is
essentially a handy way to print some log oriented information in the
log string instead of leveraging '%[expr]' with generic sample expressions
made of fetches and converters. Of course, there are some subtelties, such
as a few log-format aliases that still don't have sample fetch equivalent
for historical reasons, and some aliases that may be a little faster than
their generic sample expression equivalents because most aliases are
pretty much hardcoded in the log building function. But in general
logformat aliases should be simply considered as an alternative to using
expressions (with '%[expr']')
Also, under log-format context, when we want to refer to either an alias
('%alias') or an expression ('%[expr]'), we should use the generic term
'logformat item', which in fact designates a single item within the
logformat string provided by the user. Indeed, a logformat item (whether
is is an alias or an expression) always starts with '%' and may accept
optional flags / arguments
Both the code and the documentation were updated in that sense, hopefully
this will clarify things and prevent future confusions.
2024-05-27 04:18:10 -04:00
node - > options | = node_args_list [ i ] . mask ;
2012-02-08 10:37:49 -05:00
break ;
} else if ( flags = = 2 ) {
MINOR: log: rename 'log-format tag' to 'log-format alias'
In 2.9 we started to introduce an ambiguity in the documentation by
referring to historical log-format variables ('%var') as log-format
tags in 739c4e5b1e ("MINOR: sample: accept_date / request_date return
%Ts / %tr timestamp values") and 454c372b60 ("DOC: configuration: add
sample fetches for timing events").
In fact, we've had this confusion between log-format tag and log-format
var for more than 10 years now, but in 2.9 it was the first time the
confusion was exposed in the documentation.
Indeed, both 'log-format variable' and 'log-format tag' actually refer
to the same feature (that is: '%B' and friends that can be used for
direct access to some log-oriented predefined fetches instead of using
%[expr] with generic sample expressions).
This feature was first implemented in 723b73ad75 ("MINOR: config: Parse
the string of the log-format config keyword") and later documented in
4894040fa ("DOC: log-format documentation"). At that time, it was clear
that we used to name it 'log-format variable'.
But later the same year, 'log-format tag' naming started to appear in
some commit messages (while still referring to the same feature), for
instance with ffc3fcd6d ("MEDIUM: log: report SSL ciphers and version
in logs using logformat %sslc/%sslv").
Unfortunately in 2.9 when we added (and documented) new log-format
variables we officially started drifting to the misleading 'log-format
tag' naming (perhaps because it was the most recent naming found for
this feature in git log history, or because the confusion has always
been there)
Even worse, in 3.0 this confusion led us to rename all 'var' occurrences
to 'tag' in log-format related code to unify the code with the doc.
Hopefully William quickly noticed that we made a mistake there, but
instead of reverting to historical naming (log-format variable), it was
decided that we must use a different name that is less confusing than
'tags' or 'variables' (tags and variables are keywords that are already
used to designate other features in the code and that are not very
explicit under log-format context today).
Now we refer to '%B' and friends as a logformat alias, which is
essentially a handy way to print some log oriented information in the
log string instead of leveraging '%[expr]' with generic sample expressions
made of fetches and converters. Of course, there are some subtelties, such
as a few log-format aliases that still don't have sample fetch equivalent
for historical reasons, and some aliases that may be a little faster than
their generic sample expression equivalents because most aliases are
pretty much hardcoded in the log building function. But in general
logformat aliases should be simply considered as an alternative to using
expressions (with '%[expr']')
Also, under log-format context, when we want to refer to either an alias
('%alias') or an expression ('%[expr]'), we should use the generic term
'logformat item', which in fact designates a single item within the
logformat string provided by the user. Indeed, a logformat item (whether
is is an alias or an expression) always starts with '%' and may accept
optional flags / arguments
Both the code and the documentation were updated in that sense, hopefully
this will clarify things and prevent future confusions.
2024-05-27 04:18:10 -04:00
node - > options & = ~ node_args_list [ i ] . mask ;
2012-02-08 10:37:49 -05:00
break ;
}
}
}
sp = NULL ;
if ( end )
break ;
}
2012-12-20 12:19:26 -05:00
args + + ;
2012-02-08 10:37:49 -05:00
}
2016-11-22 17:13:04 -05:00
return 1 ;
2012-02-08 10:37:49 -05:00
}
/*
MINOR: log: rename 'log-format tag' to 'log-format alias'
In 2.9 we started to introduce an ambiguity in the documentation by
referring to historical log-format variables ('%var') as log-format
tags in 739c4e5b1e ("MINOR: sample: accept_date / request_date return
%Ts / %tr timestamp values") and 454c372b60 ("DOC: configuration: add
sample fetches for timing events").
In fact, we've had this confusion between log-format tag and log-format
var for more than 10 years now, but in 2.9 it was the first time the
confusion was exposed in the documentation.
Indeed, both 'log-format variable' and 'log-format tag' actually refer
to the same feature (that is: '%B' and friends that can be used for
direct access to some log-oriented predefined fetches instead of using
%[expr] with generic sample expressions).
This feature was first implemented in 723b73ad75 ("MINOR: config: Parse
the string of the log-format config keyword") and later documented in
4894040fa ("DOC: log-format documentation"). At that time, it was clear
that we used to name it 'log-format variable'.
But later the same year, 'log-format tag' naming started to appear in
some commit messages (while still referring to the same feature), for
instance with ffc3fcd6d ("MEDIUM: log: report SSL ciphers and version
in logs using logformat %sslc/%sslv").
Unfortunately in 2.9 when we added (and documented) new log-format
variables we officially started drifting to the misleading 'log-format
tag' naming (perhaps because it was the most recent naming found for
this feature in git log history, or because the confusion has always
been there)
Even worse, in 3.0 this confusion led us to rename all 'var' occurrences
to 'tag' in log-format related code to unify the code with the doc.
Hopefully William quickly noticed that we made a mistake there, but
instead of reverting to historical naming (log-format variable), it was
decided that we must use a different name that is less confusing than
'tags' or 'variables' (tags and variables are keywords that are already
used to designate other features in the code and that are not very
explicit under log-format context today).
Now we refer to '%B' and friends as a logformat alias, which is
essentially a handy way to print some log oriented information in the
log string instead of leveraging '%[expr]' with generic sample expressions
made of fetches and converters. Of course, there are some subtelties, such
as a few log-format aliases that still don't have sample fetch equivalent
for historical reasons, and some aliases that may be a little faster than
their generic sample expression equivalents because most aliases are
pretty much hardcoded in the log building function. But in general
logformat aliases should be simply considered as an alternative to using
expressions (with '%[expr']')
Also, under log-format context, when we want to refer to either an alias
('%alias') or an expression ('%[expr]'), we should use the generic term
'logformat item', which in fact designates a single item within the
logformat string provided by the user. Indeed, a logformat item (whether
is is an alias or an expression) always starts with '%' and may accept
optional flags / arguments
Both the code and the documentation were updated in that sense, hopefully
this will clarify things and prevent future confusions.
2024-05-27 04:18:10 -04:00
* Parse an alias ' % aliasname ' or ' % { args } aliasname ' in log - format . The caller
2012-12-20 15:23:42 -05:00
* must pass the args part in the < arg > pointer with its length in < arg_len > ,
MINOR: log: rename 'log-format tag' to 'log-format alias'
In 2.9 we started to introduce an ambiguity in the documentation by
referring to historical log-format variables ('%var') as log-format
tags in 739c4e5b1e ("MINOR: sample: accept_date / request_date return
%Ts / %tr timestamp values") and 454c372b60 ("DOC: configuration: add
sample fetches for timing events").
In fact, we've had this confusion between log-format tag and log-format
var for more than 10 years now, but in 2.9 it was the first time the
confusion was exposed in the documentation.
Indeed, both 'log-format variable' and 'log-format tag' actually refer
to the same feature (that is: '%B' and friends that can be used for
direct access to some log-oriented predefined fetches instead of using
%[expr] with generic sample expressions).
This feature was first implemented in 723b73ad75 ("MINOR: config: Parse
the string of the log-format config keyword") and later documented in
4894040fa ("DOC: log-format documentation"). At that time, it was clear
that we used to name it 'log-format variable'.
But later the same year, 'log-format tag' naming started to appear in
some commit messages (while still referring to the same feature), for
instance with ffc3fcd6d ("MEDIUM: log: report SSL ciphers and version
in logs using logformat %sslc/%sslv").
Unfortunately in 2.9 when we added (and documented) new log-format
variables we officially started drifting to the misleading 'log-format
tag' naming (perhaps because it was the most recent naming found for
this feature in git log history, or because the confusion has always
been there)
Even worse, in 3.0 this confusion led us to rename all 'var' occurrences
to 'tag' in log-format related code to unify the code with the doc.
Hopefully William quickly noticed that we made a mistake there, but
instead of reverting to historical naming (log-format variable), it was
decided that we must use a different name that is less confusing than
'tags' or 'variables' (tags and variables are keywords that are already
used to designate other features in the code and that are not very
explicit under log-format context today).
Now we refer to '%B' and friends as a logformat alias, which is
essentially a handy way to print some log oriented information in the
log string instead of leveraging '%[expr]' with generic sample expressions
made of fetches and converters. Of course, there are some subtelties, such
as a few log-format aliases that still don't have sample fetch equivalent
for historical reasons, and some aliases that may be a little faster than
their generic sample expression equivalents because most aliases are
pretty much hardcoded in the log building function. But in general
logformat aliases should be simply considered as an alternative to using
expressions (with '%[expr']')
Also, under log-format context, when we want to refer to either an alias
('%alias') or an expression ('%[expr]'), we should use the generic term
'logformat item', which in fact designates a single item within the
logformat string provided by the user. Indeed, a logformat item (whether
is is an alias or an expression) always starts with '%' and may accept
optional flags / arguments
Both the code and the documentation were updated in that sense, hopefully
this will clarify things and prevent future confusions.
2024-05-27 04:18:10 -04:00
* and aliasname with its length in < alias > and < alias_len > respectively . < arg >
* is ignored when arg_len is 0. Neither < alias > nor < alias_len > may be null .
2016-11-22 16:06:04 -05:00
* Returns false in error case and err is filled , otherwise returns true .
2012-02-08 10:37:49 -05:00
*/
MINOR: log: rename 'log-format tag' to 'log-format alias'
In 2.9 we started to introduce an ambiguity in the documentation by
referring to historical log-format variables ('%var') as log-format
tags in 739c4e5b1e ("MINOR: sample: accept_date / request_date return
%Ts / %tr timestamp values") and 454c372b60 ("DOC: configuration: add
sample fetches for timing events").
In fact, we've had this confusion between log-format tag and log-format
var for more than 10 years now, but in 2.9 it was the first time the
confusion was exposed in the documentation.
Indeed, both 'log-format variable' and 'log-format tag' actually refer
to the same feature (that is: '%B' and friends that can be used for
direct access to some log-oriented predefined fetches instead of using
%[expr] with generic sample expressions).
This feature was first implemented in 723b73ad75 ("MINOR: config: Parse
the string of the log-format config keyword") and later documented in
4894040fa ("DOC: log-format documentation"). At that time, it was clear
that we used to name it 'log-format variable'.
But later the same year, 'log-format tag' naming started to appear in
some commit messages (while still referring to the same feature), for
instance with ffc3fcd6d ("MEDIUM: log: report SSL ciphers and version
in logs using logformat %sslc/%sslv").
Unfortunately in 2.9 when we added (and documented) new log-format
variables we officially started drifting to the misleading 'log-format
tag' naming (perhaps because it was the most recent naming found for
this feature in git log history, or because the confusion has always
been there)
Even worse, in 3.0 this confusion led us to rename all 'var' occurrences
to 'tag' in log-format related code to unify the code with the doc.
Hopefully William quickly noticed that we made a mistake there, but
instead of reverting to historical naming (log-format variable), it was
decided that we must use a different name that is less confusing than
'tags' or 'variables' (tags and variables are keywords that are already
used to designate other features in the code and that are not very
explicit under log-format context today).
Now we refer to '%B' and friends as a logformat alias, which is
essentially a handy way to print some log oriented information in the
log string instead of leveraging '%[expr]' with generic sample expressions
made of fetches and converters. Of course, there are some subtelties, such
as a few log-format aliases that still don't have sample fetch equivalent
for historical reasons, and some aliases that may be a little faster than
their generic sample expression equivalents because most aliases are
pretty much hardcoded in the log building function. But in general
logformat aliases should be simply considered as an alternative to using
expressions (with '%[expr']')
Also, under log-format context, when we want to refer to either an alias
('%alias') or an expression ('%[expr]'), we should use the generic term
'logformat item', which in fact designates a single item within the
logformat string provided by the user. Indeed, a logformat item (whether
is is an alias or an expression) always starts with '%' and may accept
optional flags / arguments
Both the code and the documentation were updated in that sense, hopefully
this will clarify things and prevent future confusions.
2024-05-27 04:18:10 -04:00
static int parse_logformat_alias ( char * arg , int arg_len , char * name , int name_len , int typecast ,
char * alias , int alias_len , struct lf_expr * lf_expr ,
int * defoptions , char * * err )
2012-02-08 10:37:49 -05:00
{
2012-12-20 15:23:42 -05:00
int j ;
2024-03-25 06:29:58 -04:00
struct list * list_format = & lf_expr - > nodes . list ;
2019-04-29 18:40:02 -04:00
struct logformat_node * node = NULL ;
2012-12-20 15:23:42 -05:00
MINOR: log: rename 'log-format tag' to 'log-format alias'
In 2.9 we started to introduce an ambiguity in the documentation by
referring to historical log-format variables ('%var') as log-format
tags in 739c4e5b1e ("MINOR: sample: accept_date / request_date return
%Ts / %tr timestamp values") and 454c372b60 ("DOC: configuration: add
sample fetches for timing events").
In fact, we've had this confusion between log-format tag and log-format
var for more than 10 years now, but in 2.9 it was the first time the
confusion was exposed in the documentation.
Indeed, both 'log-format variable' and 'log-format tag' actually refer
to the same feature (that is: '%B' and friends that can be used for
direct access to some log-oriented predefined fetches instead of using
%[expr] with generic sample expressions).
This feature was first implemented in 723b73ad75 ("MINOR: config: Parse
the string of the log-format config keyword") and later documented in
4894040fa ("DOC: log-format documentation"). At that time, it was clear
that we used to name it 'log-format variable'.
But later the same year, 'log-format tag' naming started to appear in
some commit messages (while still referring to the same feature), for
instance with ffc3fcd6d ("MEDIUM: log: report SSL ciphers and version
in logs using logformat %sslc/%sslv").
Unfortunately in 2.9 when we added (and documented) new log-format
variables we officially started drifting to the misleading 'log-format
tag' naming (perhaps because it was the most recent naming found for
this feature in git log history, or because the confusion has always
been there)
Even worse, in 3.0 this confusion led us to rename all 'var' occurrences
to 'tag' in log-format related code to unify the code with the doc.
Hopefully William quickly noticed that we made a mistake there, but
instead of reverting to historical naming (log-format variable), it was
decided that we must use a different name that is less confusing than
'tags' or 'variables' (tags and variables are keywords that are already
used to designate other features in the code and that are not very
explicit under log-format context today).
Now we refer to '%B' and friends as a logformat alias, which is
essentially a handy way to print some log oriented information in the
log string instead of leveraging '%[expr]' with generic sample expressions
made of fetches and converters. Of course, there are some subtelties, such
as a few log-format aliases that still don't have sample fetch equivalent
for historical reasons, and some aliases that may be a little faster than
their generic sample expression equivalents because most aliases are
pretty much hardcoded in the log building function. But in general
logformat aliases should be simply considered as an alternative to using
expressions (with '%[expr']')
Also, under log-format context, when we want to refer to either an alias
('%alias') or an expression ('%[expr]'), we should use the generic term
'logformat item', which in fact designates a single item within the
logformat string provided by the user. Indeed, a logformat item (whether
is is an alias or an expression) always starts with '%' and may accept
optional flags / arguments
Both the code and the documentation were updated in that sense, hopefully
this will clarify things and prevent future confusions.
2024-05-27 04:18:10 -04:00
for ( j = 0 ; logformat_aliases [ j ] . name ; j + + ) { // search a log type
if ( strlen ( logformat_aliases [ j ] . name ) = = alias_len & &
strncmp ( alias , logformat_aliases [ j ] . name , alias_len ) = = 0 ) {
MAJOR: log: implement proper postparsing for logformat expressions
This patch tries to address a design flaw with how logformat expressions
are parsed from config. Indeed, some parse_logformat_string() calls are
performed during config parsing when the proxy mode is not yet known.
Here's a config example that illustrates the issue:
defaults
mode tcp
listen test
bind :8888
http-response set-header custom-hdr "%trl" # needs http
mode http
The above config should work, because the effective proxy mode is http,
yet haproxy fails with this error:
[ALERT] (99051) : config : parsing [repro.conf:6] : error detected in proxy 'test' while parsing 'http-response set-header' rule : format tag 'trl' is reserved for HTTP mode.
To fix the issue once and for all, let's implement smart postparsing for
logformat expressions encountered during config parsing:
- split parse_logformat_string() (and subfonctions) in order to create a
new lf_expr_postcheck() function that must be called to finish
preparing and checking the logformat expression once the proxy type is
known.
- save some config hints info during parse_logformat_string() to
generate more precise error messages during lf_expr_postcheck(), if
needed, we rely on curpx->conf.args.{file,line} hints for that because
parse_logformat_string() doesn't know about current file and line
number.
- lf_expr_postcheck() uses PR_FL_CHECKED proxy flag to know if the
function may try to make the proxy compatible with the expression, or
if it should simply fail as soon as an incompatibility is detected.
- if parse_logformat_string() is called from an unchecked proxy, then
schedule the expression for postparsing, else (ie: during runtime),
run the postcheck right away.
This change will also allow for some logformat expression error handling
simplifications in the future.
2024-02-23 11:26:32 -05:00
node = calloc ( 1 , sizeof ( * node ) ) ;
if ( ! node ) {
memprintf ( err , " out of memory error " ) ;
goto error_free ;
}
MINOR: log: rename 'log-format tag' to 'log-format alias'
In 2.9 we started to introduce an ambiguity in the documentation by
referring to historical log-format variables ('%var') as log-format
tags in 739c4e5b1e ("MINOR: sample: accept_date / request_date return
%Ts / %tr timestamp values") and 454c372b60 ("DOC: configuration: add
sample fetches for timing events").
In fact, we've had this confusion between log-format tag and log-format
var for more than 10 years now, but in 2.9 it was the first time the
confusion was exposed in the documentation.
Indeed, both 'log-format variable' and 'log-format tag' actually refer
to the same feature (that is: '%B' and friends that can be used for
direct access to some log-oriented predefined fetches instead of using
%[expr] with generic sample expressions).
This feature was first implemented in 723b73ad75 ("MINOR: config: Parse
the string of the log-format config keyword") and later documented in
4894040fa ("DOC: log-format documentation"). At that time, it was clear
that we used to name it 'log-format variable'.
But later the same year, 'log-format tag' naming started to appear in
some commit messages (while still referring to the same feature), for
instance with ffc3fcd6d ("MEDIUM: log: report SSL ciphers and version
in logs using logformat %sslc/%sslv").
Unfortunately in 2.9 when we added (and documented) new log-format
variables we officially started drifting to the misleading 'log-format
tag' naming (perhaps because it was the most recent naming found for
this feature in git log history, or because the confusion has always
been there)
Even worse, in 3.0 this confusion led us to rename all 'var' occurrences
to 'tag' in log-format related code to unify the code with the doc.
Hopefully William quickly noticed that we made a mistake there, but
instead of reverting to historical naming (log-format variable), it was
decided that we must use a different name that is less confusing than
'tags' or 'variables' (tags and variables are keywords that are already
used to designate other features in the code and that are not very
explicit under log-format context today).
Now we refer to '%B' and friends as a logformat alias, which is
essentially a handy way to print some log oriented information in the
log string instead of leveraging '%[expr]' with generic sample expressions
made of fetches and converters. Of course, there are some subtelties, such
as a few log-format aliases that still don't have sample fetch equivalent
for historical reasons, and some aliases that may be a little faster than
their generic sample expression equivalents because most aliases are
pretty much hardcoded in the log building function. But in general
logformat aliases should be simply considered as an alternative to using
expressions (with '%[expr']')
Also, under log-format context, when we want to refer to either an alias
('%alias') or an expression ('%[expr]'), we should use the generic term
'logformat item', which in fact designates a single item within the
logformat string provided by the user. Indeed, a logformat item (whether
is is an alias or an expression) always starts with '%' and may accept
optional flags / arguments
Both the code and the documentation were updated in that sense, hopefully
this will clarify things and prevent future confusions.
2024-05-27 04:18:10 -04:00
node - > type = LOG_FMT_ALIAS ;
node - > alias = & logformat_aliases [ j ] ;
MAJOR: log: implement proper postparsing for logformat expressions
This patch tries to address a design flaw with how logformat expressions
are parsed from config. Indeed, some parse_logformat_string() calls are
performed during config parsing when the proxy mode is not yet known.
Here's a config example that illustrates the issue:
defaults
mode tcp
listen test
bind :8888
http-response set-header custom-hdr "%trl" # needs http
mode http
The above config should work, because the effective proxy mode is http,
yet haproxy fails with this error:
[ALERT] (99051) : config : parsing [repro.conf:6] : error detected in proxy 'test' while parsing 'http-response set-header' rule : format tag 'trl' is reserved for HTTP mode.
To fix the issue once and for all, let's implement smart postparsing for
logformat expressions encountered during config parsing:
- split parse_logformat_string() (and subfonctions) in order to create a
new lf_expr_postcheck() function that must be called to finish
preparing and checking the logformat expression once the proxy type is
known.
- save some config hints info during parse_logformat_string() to
generate more precise error messages during lf_expr_postcheck(), if
needed, we rely on curpx->conf.args.{file,line} hints for that because
parse_logformat_string() doesn't know about current file and line
number.
- lf_expr_postcheck() uses PR_FL_CHECKED proxy flag to know if the
function may try to make the proxy compatible with the expression, or
if it should simply fail as soon as an incompatibility is detected.
- if parse_logformat_string() is called from an unchecked proxy, then
schedule the expression for postparsing, else (ie: during runtime),
run the postcheck right away.
This change will also allow for some logformat expression error handling
simplifications in the future.
2024-02-23 11:26:32 -05:00
node - > typecast = typecast ;
MINOR: log: skip custom logformat_node name if empty
Reminder:
Since 3.0-dev4, we can optionally give a name to logformat nodes:
log-format "%(custom_name1)B %(custom_name2)[str(value)]"
But we may also optionally set the expected node type by appending
':type' after the name, type being either sint,str or bool, like this:
log-format "%(string_as_int:sint)[str(14)]"
However, it is currently not possible to provide a type without providing
a name that is a least 1 char long. But it could be useful to provide a
type without setting a name, like this, for typecasting purposes only:
log-format "%(:sint)[bool(true)]"
Thus in order to allow this usage, don't set node->name if node name is
not at least 1 character long. By doing so, node->name will remain NULL
and will not be considered, but the typecast setting will.
2024-04-25 03:50:14 -04:00
if ( name & & name_len )
MAJOR: log: implement proper postparsing for logformat expressions
This patch tries to address a design flaw with how logformat expressions
are parsed from config. Indeed, some parse_logformat_string() calls are
performed during config parsing when the proxy mode is not yet known.
Here's a config example that illustrates the issue:
defaults
mode tcp
listen test
bind :8888
http-response set-header custom-hdr "%trl" # needs http
mode http
The above config should work, because the effective proxy mode is http,
yet haproxy fails with this error:
[ALERT] (99051) : config : parsing [repro.conf:6] : error detected in proxy 'test' while parsing 'http-response set-header' rule : format tag 'trl' is reserved for HTTP mode.
To fix the issue once and for all, let's implement smart postparsing for
logformat expressions encountered during config parsing:
- split parse_logformat_string() (and subfonctions) in order to create a
new lf_expr_postcheck() function that must be called to finish
preparing and checking the logformat expression once the proxy type is
known.
- save some config hints info during parse_logformat_string() to
generate more precise error messages during lf_expr_postcheck(), if
needed, we rely on curpx->conf.args.{file,line} hints for that because
parse_logformat_string() doesn't know about current file and line
number.
- lf_expr_postcheck() uses PR_FL_CHECKED proxy flag to know if the
function may try to make the proxy compatible with the expression, or
if it should simply fail as soon as an incompatibility is detected.
- if parse_logformat_string() is called from an unchecked proxy, then
schedule the expression for postparsing, else (ie: during runtime),
run the postcheck right away.
This change will also allow for some logformat expression error handling
simplifications in the future.
2024-02-23 11:26:32 -05:00
node - > name = my_strndup ( name , name_len ) ;
BUG/MINOR: log: fix global lf_expr node options behavior
In 507223d5 ("MINOR: log: global lf_expr node options"), a mistake was
made because it was assumed that only the last occurence of %o
(LOG_FMT_GLOBAL) should be kept as global node options.
However, although not documented, it is possible to have multiple %o
within a single logformat expression to change the global settings on the
fly.
For instance, consider this example:
log-format "%{+X}o test1=%ms %{-X}o test2=%ms %{+X}o test3=%ms"
Prior to 3f2e8d0ed ("MEDIUM: log: lf_* build helpers now take a ctx
argument"), this would output something like this:
test1=18B test2=395 test3=18B
This is because global options is properly updated as the lf_expr string
is parsed. But now due to 507223d5 and 3f2e8d0ed, only the last %o
occurence is considered. With the above example, this gives:
test1=18B test2=18B test3=18B
To restore historical behavior, let's partially revert 507223d5: to
compute global node options, we now start with all options enabled and
then for each configurable node in lf_expr_postcheck(), we keep options
common to the current node and previous nodes using AND masking, this way
we really end up with options common to all nodes.
No backport needed.
2024-04-29 05:55:27 -04:00
node - > options = * defoptions ;
MAJOR: log: implement proper postparsing for logformat expressions
This patch tries to address a design flaw with how logformat expressions
are parsed from config. Indeed, some parse_logformat_string() calls are
performed during config parsing when the proxy mode is not yet known.
Here's a config example that illustrates the issue:
defaults
mode tcp
listen test
bind :8888
http-response set-header custom-hdr "%trl" # needs http
mode http
The above config should work, because the effective proxy mode is http,
yet haproxy fails with this error:
[ALERT] (99051) : config : parsing [repro.conf:6] : error detected in proxy 'test' while parsing 'http-response set-header' rule : format tag 'trl' is reserved for HTTP mode.
To fix the issue once and for all, let's implement smart postparsing for
logformat expressions encountered during config parsing:
- split parse_logformat_string() (and subfonctions) in order to create a
new lf_expr_postcheck() function that must be called to finish
preparing and checking the logformat expression once the proxy type is
known.
- save some config hints info during parse_logformat_string() to
generate more precise error messages during lf_expr_postcheck(), if
needed, we rely on curpx->conf.args.{file,line} hints for that because
parse_logformat_string() doesn't know about current file and line
number.
- lf_expr_postcheck() uses PR_FL_CHECKED proxy flag to know if the
function may try to make the proxy compatible with the expression, or
if it should simply fail as soon as an incompatibility is detected.
- if parse_logformat_string() is called from an unchecked proxy, then
schedule the expression for postparsing, else (ie: during runtime),
run the postcheck right away.
This change will also allow for some logformat expression error handling
simplifications in the future.
2024-02-23 11:26:32 -05:00
if ( arg_len ) {
node - > arg = my_strndup ( arg , arg_len ) ;
MINOR: log: rename 'log-format tag' to 'log-format alias'
In 2.9 we started to introduce an ambiguity in the documentation by
referring to historical log-format variables ('%var') as log-format
tags in 739c4e5b1e ("MINOR: sample: accept_date / request_date return
%Ts / %tr timestamp values") and 454c372b60 ("DOC: configuration: add
sample fetches for timing events").
In fact, we've had this confusion between log-format tag and log-format
var for more than 10 years now, but in 2.9 it was the first time the
confusion was exposed in the documentation.
Indeed, both 'log-format variable' and 'log-format tag' actually refer
to the same feature (that is: '%B' and friends that can be used for
direct access to some log-oriented predefined fetches instead of using
%[expr] with generic sample expressions).
This feature was first implemented in 723b73ad75 ("MINOR: config: Parse
the string of the log-format config keyword") and later documented in
4894040fa ("DOC: log-format documentation"). At that time, it was clear
that we used to name it 'log-format variable'.
But later the same year, 'log-format tag' naming started to appear in
some commit messages (while still referring to the same feature), for
instance with ffc3fcd6d ("MEDIUM: log: report SSL ciphers and version
in logs using logformat %sslc/%sslv").
Unfortunately in 2.9 when we added (and documented) new log-format
variables we officially started drifting to the misleading 'log-format
tag' naming (perhaps because it was the most recent naming found for
this feature in git log history, or because the confusion has always
been there)
Even worse, in 3.0 this confusion led us to rename all 'var' occurrences
to 'tag' in log-format related code to unify the code with the doc.
Hopefully William quickly noticed that we made a mistake there, but
instead of reverting to historical naming (log-format variable), it was
decided that we must use a different name that is less confusing than
'tags' or 'variables' (tags and variables are keywords that are already
used to designate other features in the code and that are not very
explicit under log-format context today).
Now we refer to '%B' and friends as a logformat alias, which is
essentially a handy way to print some log oriented information in the
log string instead of leveraging '%[expr]' with generic sample expressions
made of fetches and converters. Of course, there are some subtelties, such
as a few log-format aliases that still don't have sample fetch equivalent
for historical reasons, and some aliases that may be a little faster than
their generic sample expression equivalents because most aliases are
pretty much hardcoded in the log building function. But in general
logformat aliases should be simply considered as an alternative to using
expressions (with '%[expr']')
Also, under log-format context, when we want to refer to either an alias
('%alias') or an expression ('%[expr]'), we should use the generic term
'logformat item', which in fact designates a single item within the
logformat string provided by the user. Indeed, a logformat item (whether
is is an alias or an expression) always starts with '%' and may accept
optional flags / arguments
Both the code and the documentation were updated in that sense, hopefully
this will clarify things and prevent future confusions.
2024-05-27 04:18:10 -04:00
if ( ! parse_logformat_node_args ( node - > arg , node , err ) )
2019-04-29 18:40:02 -04:00
goto error_free ;
MAJOR: log: implement proper postparsing for logformat expressions
This patch tries to address a design flaw with how logformat expressions
are parsed from config. Indeed, some parse_logformat_string() calls are
performed during config parsing when the proxy mode is not yet known.
Here's a config example that illustrates the issue:
defaults
mode tcp
listen test
bind :8888
http-response set-header custom-hdr "%trl" # needs http
mode http
The above config should work, because the effective proxy mode is http,
yet haproxy fails with this error:
[ALERT] (99051) : config : parsing [repro.conf:6] : error detected in proxy 'test' while parsing 'http-response set-header' rule : format tag 'trl' is reserved for HTTP mode.
To fix the issue once and for all, let's implement smart postparsing for
logformat expressions encountered during config parsing:
- split parse_logformat_string() (and subfonctions) in order to create a
new lf_expr_postcheck() function that must be called to finish
preparing and checking the logformat expression once the proxy type is
known.
- save some config hints info during parse_logformat_string() to
generate more precise error messages during lf_expr_postcheck(), if
needed, we rely on curpx->conf.args.{file,line} hints for that because
parse_logformat_string() doesn't know about current file and line
number.
- lf_expr_postcheck() uses PR_FL_CHECKED proxy flag to know if the
function may try to make the proxy compatible with the expression, or
if it should simply fail as soon as an incompatibility is detected.
- if parse_logformat_string() is called from an unchecked proxy, then
schedule the expression for postparsing, else (ie: during runtime),
run the postcheck right away.
This change will also allow for some logformat expression error handling
simplifications in the future.
2024-02-23 11:26:32 -05:00
}
MINOR: log: rename 'log-format tag' to 'log-format alias'
In 2.9 we started to introduce an ambiguity in the documentation by
referring to historical log-format variables ('%var') as log-format
tags in 739c4e5b1e ("MINOR: sample: accept_date / request_date return
%Ts / %tr timestamp values") and 454c372b60 ("DOC: configuration: add
sample fetches for timing events").
In fact, we've had this confusion between log-format tag and log-format
var for more than 10 years now, but in 2.9 it was the first time the
confusion was exposed in the documentation.
Indeed, both 'log-format variable' and 'log-format tag' actually refer
to the same feature (that is: '%B' and friends that can be used for
direct access to some log-oriented predefined fetches instead of using
%[expr] with generic sample expressions).
This feature was first implemented in 723b73ad75 ("MINOR: config: Parse
the string of the log-format config keyword") and later documented in
4894040fa ("DOC: log-format documentation"). At that time, it was clear
that we used to name it 'log-format variable'.
But later the same year, 'log-format tag' naming started to appear in
some commit messages (while still referring to the same feature), for
instance with ffc3fcd6d ("MEDIUM: log: report SSL ciphers and version
in logs using logformat %sslc/%sslv").
Unfortunately in 2.9 when we added (and documented) new log-format
variables we officially started drifting to the misleading 'log-format
tag' naming (perhaps because it was the most recent naming found for
this feature in git log history, or because the confusion has always
been there)
Even worse, in 3.0 this confusion led us to rename all 'var' occurrences
to 'tag' in log-format related code to unify the code with the doc.
Hopefully William quickly noticed that we made a mistake there, but
instead of reverting to historical naming (log-format variable), it was
decided that we must use a different name that is less confusing than
'tags' or 'variables' (tags and variables are keywords that are already
used to designate other features in the code and that are not very
explicit under log-format context today).
Now we refer to '%B' and friends as a logformat alias, which is
essentially a handy way to print some log oriented information in the
log string instead of leveraging '%[expr]' with generic sample expressions
made of fetches and converters. Of course, there are some subtelties, such
as a few log-format aliases that still don't have sample fetch equivalent
for historical reasons, and some aliases that may be a little faster than
their generic sample expression equivalents because most aliases are
pretty much hardcoded in the log building function. But in general
logformat aliases should be simply considered as an alternative to using
expressions (with '%[expr']')
Also, under log-format context, when we want to refer to either an alias
('%alias') or an expression ('%[expr]'), we should use the generic term
'logformat item', which in fact designates a single item within the
logformat string provided by the user. Indeed, a logformat item (whether
is is an alias or an expression) always starts with '%' and may accept
optional flags / arguments
Both the code and the documentation were updated in that sense, hopefully
this will clarify things and prevent future confusions.
2024-05-27 04:18:10 -04:00
if ( node - > alias - > type = = LOG_FMT_GLOBAL ) {
BUG/MINOR: log: fix global lf_expr node options behavior
In 507223d5 ("MINOR: log: global lf_expr node options"), a mistake was
made because it was assumed that only the last occurence of %o
(LOG_FMT_GLOBAL) should be kept as global node options.
However, although not documented, it is possible to have multiple %o
within a single logformat expression to change the global settings on the
fly.
For instance, consider this example:
log-format "%{+X}o test1=%ms %{-X}o test2=%ms %{+X}o test3=%ms"
Prior to 3f2e8d0ed ("MEDIUM: log: lf_* build helpers now take a ctx
argument"), this would output something like this:
test1=18B test2=395 test3=18B
This is because global options is properly updated as the lf_expr string
is parsed. But now due to 507223d5 and 3f2e8d0ed, only the last %o
occurence is considered. With the above example, this gives:
test1=18B test2=18B test3=18B
To restore historical behavior, let's partially revert 507223d5: to
compute global node options, we now start with all options enabled and
then for each configurable node in lf_expr_postcheck(), we keep options
common to the current node and previous nodes using AND masking, this way
we really end up with options common to all nodes.
No backport needed.
2024-04-29 05:55:27 -04:00
* defoptions = node - > options ;
2024-04-29 09:58:36 -04:00
if ( lf_expr - > nodes . options = = LOG_OPT_NONE )
lf_expr - > nodes . options = node - > options ;
else {
/* global options were previously set and were
* overwritten for nodes that appear after the
* current one .
*
* However , for lf_expr - > nodes . options we must
* keep a track of options common to ALL nodes ,
* thus we take previous global options into
* account to compute the new logformat
* expression wide ( global ) node options .
*/
lf_expr - > nodes . options & = node - > options ;
}
MAJOR: log: implement proper postparsing for logformat expressions
This patch tries to address a design flaw with how logformat expressions
are parsed from config. Indeed, some parse_logformat_string() calls are
performed during config parsing when the proxy mode is not yet known.
Here's a config example that illustrates the issue:
defaults
mode tcp
listen test
bind :8888
http-response set-header custom-hdr "%trl" # needs http
mode http
The above config should work, because the effective proxy mode is http,
yet haproxy fails with this error:
[ALERT] (99051) : config : parsing [repro.conf:6] : error detected in proxy 'test' while parsing 'http-response set-header' rule : format tag 'trl' is reserved for HTTP mode.
To fix the issue once and for all, let's implement smart postparsing for
logformat expressions encountered during config parsing:
- split parse_logformat_string() (and subfonctions) in order to create a
new lf_expr_postcheck() function that must be called to finish
preparing and checking the logformat expression once the proxy type is
known.
- save some config hints info during parse_logformat_string() to
generate more precise error messages during lf_expr_postcheck(), if
needed, we rely on curpx->conf.args.{file,line} hints for that because
parse_logformat_string() doesn't know about current file and line
number.
- lf_expr_postcheck() uses PR_FL_CHECKED proxy flag to know if the
function may try to make the proxy compatible with the expression, or
if it should simply fail as soon as an incompatibility is detected.
- if parse_logformat_string() is called from an unchecked proxy, then
schedule the expression for postparsing, else (ie: during runtime),
run the postcheck right away.
This change will also allow for some logformat expression error handling
simplifications in the future.
2024-02-23 11:26:32 -05:00
free_logformat_node ( node ) ;
2012-12-20 15:23:42 -05:00
} else {
MAJOR: log: implement proper postparsing for logformat expressions
This patch tries to address a design flaw with how logformat expressions
are parsed from config. Indeed, some parse_logformat_string() calls are
performed during config parsing when the proxy mode is not yet known.
Here's a config example that illustrates the issue:
defaults
mode tcp
listen test
bind :8888
http-response set-header custom-hdr "%trl" # needs http
mode http
The above config should work, because the effective proxy mode is http,
yet haproxy fails with this error:
[ALERT] (99051) : config : parsing [repro.conf:6] : error detected in proxy 'test' while parsing 'http-response set-header' rule : format tag 'trl' is reserved for HTTP mode.
To fix the issue once and for all, let's implement smart postparsing for
logformat expressions encountered during config parsing:
- split parse_logformat_string() (and subfonctions) in order to create a
new lf_expr_postcheck() function that must be called to finish
preparing and checking the logformat expression once the proxy type is
known.
- save some config hints info during parse_logformat_string() to
generate more precise error messages during lf_expr_postcheck(), if
needed, we rely on curpx->conf.args.{file,line} hints for that because
parse_logformat_string() doesn't know about current file and line
number.
- lf_expr_postcheck() uses PR_FL_CHECKED proxy flag to know if the
function may try to make the proxy compatible with the expression, or
if it should simply fail as soon as an incompatibility is detected.
- if parse_logformat_string() is called from an unchecked proxy, then
schedule the expression for postparsing, else (ie: during runtime),
run the postcheck right away.
This change will also allow for some logformat expression error handling
simplifications in the future.
2024-02-23 11:26:32 -05:00
LIST_APPEND ( list_format , & node - > list ) ;
2012-02-08 10:37:49 -05:00
}
MAJOR: log: implement proper postparsing for logformat expressions
This patch tries to address a design flaw with how logformat expressions
are parsed from config. Indeed, some parse_logformat_string() calls are
performed during config parsing when the proxy mode is not yet known.
Here's a config example that illustrates the issue:
defaults
mode tcp
listen test
bind :8888
http-response set-header custom-hdr "%trl" # needs http
mode http
The above config should work, because the effective proxy mode is http,
yet haproxy fails with this error:
[ALERT] (99051) : config : parsing [repro.conf:6] : error detected in proxy 'test' while parsing 'http-response set-header' rule : format tag 'trl' is reserved for HTTP mode.
To fix the issue once and for all, let's implement smart postparsing for
logformat expressions encountered during config parsing:
- split parse_logformat_string() (and subfonctions) in order to create a
new lf_expr_postcheck() function that must be called to finish
preparing and checking the logformat expression once the proxy type is
known.
- save some config hints info during parse_logformat_string() to
generate more precise error messages during lf_expr_postcheck(), if
needed, we rely on curpx->conf.args.{file,line} hints for that because
parse_logformat_string() doesn't know about current file and line
number.
- lf_expr_postcheck() uses PR_FL_CHECKED proxy flag to know if the
function may try to make the proxy compatible with the expression, or
if it should simply fail as soon as an incompatibility is detected.
- if parse_logformat_string() is called from an unchecked proxy, then
schedule the expression for postparsing, else (ie: during runtime),
run the postcheck right away.
This change will also allow for some logformat expression error handling
simplifications in the future.
2024-02-23 11:26:32 -05:00
return 1 ;
2012-02-08 10:37:49 -05:00
}
}
2012-12-20 15:23:42 -05:00
MINOR: log: rename 'log-format tag' to 'log-format alias'
In 2.9 we started to introduce an ambiguity in the documentation by
referring to historical log-format variables ('%var') as log-format
tags in 739c4e5b1e ("MINOR: sample: accept_date / request_date return
%Ts / %tr timestamp values") and 454c372b60 ("DOC: configuration: add
sample fetches for timing events").
In fact, we've had this confusion between log-format tag and log-format
var for more than 10 years now, but in 2.9 it was the first time the
confusion was exposed in the documentation.
Indeed, both 'log-format variable' and 'log-format tag' actually refer
to the same feature (that is: '%B' and friends that can be used for
direct access to some log-oriented predefined fetches instead of using
%[expr] with generic sample expressions).
This feature was first implemented in 723b73ad75 ("MINOR: config: Parse
the string of the log-format config keyword") and later documented in
4894040fa ("DOC: log-format documentation"). At that time, it was clear
that we used to name it 'log-format variable'.
But later the same year, 'log-format tag' naming started to appear in
some commit messages (while still referring to the same feature), for
instance with ffc3fcd6d ("MEDIUM: log: report SSL ciphers and version
in logs using logformat %sslc/%sslv").
Unfortunately in 2.9 when we added (and documented) new log-format
variables we officially started drifting to the misleading 'log-format
tag' naming (perhaps because it was the most recent naming found for
this feature in git log history, or because the confusion has always
been there)
Even worse, in 3.0 this confusion led us to rename all 'var' occurrences
to 'tag' in log-format related code to unify the code with the doc.
Hopefully William quickly noticed that we made a mistake there, but
instead of reverting to historical naming (log-format variable), it was
decided that we must use a different name that is less confusing than
'tags' or 'variables' (tags and variables are keywords that are already
used to designate other features in the code and that are not very
explicit under log-format context today).
Now we refer to '%B' and friends as a logformat alias, which is
essentially a handy way to print some log oriented information in the
log string instead of leveraging '%[expr]' with generic sample expressions
made of fetches and converters. Of course, there are some subtelties, such
as a few log-format aliases that still don't have sample fetch equivalent
for historical reasons, and some aliases that may be a little faster than
their generic sample expression equivalents because most aliases are
pretty much hardcoded in the log building function. But in general
logformat aliases should be simply considered as an alternative to using
expressions (with '%[expr']')
Also, under log-format context, when we want to refer to either an alias
('%alias') or an expression ('%[expr]'), we should use the generic term
'logformat item', which in fact designates a single item within the
logformat string provided by the user. Indeed, a logformat item (whether
is is an alias or an expression) always starts with '%' and may accept
optional flags / arguments
Both the code and the documentation were updated in that sense, hopefully
this will clarify things and prevent future confusions.
2024-05-27 04:18:10 -04:00
j = alias [ alias_len ] ;
alias [ alias_len ] = 0 ;
memprintf ( err , " no such format alias '%s'. If you wanted to emit the '%%' character verbatim, you need to use '%%%%' " , alias ) ;
alias [ alias_len ] = j ;
2019-04-29 18:40:02 -04:00
error_free :
2024-02-22 09:14:21 -05:00
free_logformat_node ( node ) ;
2016-11-22 16:06:04 -05:00
return 0 ;
2012-02-08 10:37:49 -05:00
}
/*
* push to the logformat linked list
*
* start : start pointer
* end : end text pointer
* type : string type
2024-02-23 09:57:21 -05:00
* lf_expr : destination logformat expr ( list of fmt nodes )
2012-02-08 10:37:49 -05:00
*
* LOG_TEXT : copy chars from start to end excluding end .
*
*/
2024-02-23 09:57:21 -05:00
int add_to_logformat_list ( char * start , char * end , int type , struct lf_expr * lf_expr , char * * err )
2012-02-08 10:37:49 -05:00
{
2024-03-25 06:29:58 -04:00
struct list * list_format = & lf_expr - > nodes . list ;
2012-02-08 10:37:49 -05:00
char * str ;
2012-12-20 15:59:12 -05:00
if ( type = = LF_TEXT ) { /* type text */
2016-04-03 07:48:43 -04:00
struct logformat_node * node = calloc ( 1 , sizeof ( * node ) ) ;
2016-11-22 17:24:10 -05:00
if ( ! node ) {
2016-11-22 18:41:28 -05:00
memprintf ( err , " out of memory error " ) ;
2016-11-22 17:24:10 -05:00
return 0 ;
}
2016-04-03 07:48:43 -04:00
str = calloc ( 1 , end - start + 1 ) ;
2012-02-08 10:37:49 -05:00
strncpy ( str , start , end - start ) ;
str [ end - start ] = ' \0 ' ;
node - > arg = str ;
2012-03-12 07:46:41 -04:00
node - > type = LOG_FMT_TEXT ; // type string
2021-04-21 01:32:39 -04:00
LIST_APPEND ( list_format , & node - > list ) ;
2012-12-20 15:59:12 -05:00
} else if ( type = = LF_SEPARATOR ) {
2016-04-03 07:48:43 -04:00
struct logformat_node * node = calloc ( 1 , sizeof ( * node ) ) ;
2016-11-22 17:24:10 -05:00
if ( ! node ) {
2016-11-22 18:41:28 -05:00
memprintf ( err , " out of memory error " ) ;
2016-11-22 17:24:10 -05:00
return 0 ;
}
2012-03-12 07:46:41 -04:00
node - > type = LOG_FMT_SEPARATOR ;
2021-04-21 01:32:39 -04:00
LIST_APPEND ( list_format , & node - > list ) ;
2012-02-08 10:37:49 -05:00
}
2016-11-22 17:11:21 -05:00
return 1 ;
2012-02-08 10:37:49 -05:00
}
2012-12-20 18:09:23 -05:00
/*
2024-02-23 09:57:21 -05:00
* Parse the sample fetch expression < text > and add a node to < lf_expr > upon
2024-02-22 10:13:13 -05:00
* success . The curpx - > conf . args . ctx must be set by the caller . If an end pointer
2020-02-14 11:33:06 -05:00
* is passed in < endptr > , it will be updated with the pointer to the first character
* not part of the sample expression .
2016-11-22 17:11:21 -05:00
*
* In error case , the function returns 0 , otherwise it returns 1.
2012-12-20 18:09:23 -05:00
*/
2024-02-29 08:54:43 -05:00
static int add_sample_to_logformat_list ( char * text , char * name , int name_len , int typecast ,
char * arg , int arg_len , struct lf_expr * lf_expr ,
BUG/MINOR: log: fix global lf_expr node options behavior
In 507223d5 ("MINOR: log: global lf_expr node options"), a mistake was
made because it was assumed that only the last occurence of %o
(LOG_FMT_GLOBAL) should be kept as global node options.
However, although not documented, it is possible to have multiple %o
within a single logformat expression to change the global settings on the
fly.
For instance, consider this example:
log-format "%{+X}o test1=%ms %{-X}o test2=%ms %{+X}o test3=%ms"
Prior to 3f2e8d0ed ("MEDIUM: log: lf_* build helpers now take a ctx
argument"), this would output something like this:
test1=18B test2=395 test3=18B
This is because global options is properly updated as the lf_expr string
is parsed. But now due to 507223d5 and 3f2e8d0ed, only the last %o
occurence is considered. With the above example, this gives:
test1=18B test2=18B test3=18B
To restore historical behavior, let's partially revert 507223d5: to
compute global node options, we now start with all options enabled and
then for each configurable node in lf_expr_postcheck(), we keep options
common to the current node and previous nodes using AND masking, this way
we really end up with options common to all nodes.
No backport needed.
2024-04-29 05:55:27 -04:00
struct arg_list * al , int options , int cap , char * * err , char * * endptr )
2012-12-20 18:09:23 -05:00
{
char * cmd [ 2 ] ;
2024-03-25 06:29:58 -04:00
struct list * list_format = & lf_expr - > nodes . list ;
2019-04-29 18:40:02 -04:00
struct sample_expr * expr = NULL ;
struct logformat_node * node = NULL ;
2012-12-20 18:09:23 -05:00
int cmd_arg ;
cmd [ 0 ] = text ;
cmd [ 1 ] = " " ;
cmd_arg = 0 ;
2024-02-29 08:54:43 -05:00
expr = sample_parse_expr ( cmd , & cmd_arg , lf_expr - > conf . file , lf_expr - > conf . line , err ,
al , endptr ) ;
2012-12-20 18:09:23 -05:00
if ( ! expr ) {
2016-11-22 18:41:28 -05:00
memprintf ( err , " failed to parse sample expression <%s> : %s " , text , * err ) ;
2019-04-29 18:40:02 -04:00
goto error_free ;
2012-12-20 18:09:23 -05:00
}
2016-04-03 07:48:43 -04:00
node = calloc ( 1 , sizeof ( * node ) ) ;
2016-11-22 17:24:10 -05:00
if ( ! node ) {
2024-05-13 10:24:10 -04:00
release_sample_expr ( expr ) ;
2016-11-22 18:41:28 -05:00
memprintf ( err , " out of memory error " ) ;
2019-04-29 18:40:02 -04:00
goto error_free ;
2016-11-22 17:24:10 -05:00
}
MINOR: log: skip custom logformat_node name if empty
Reminder:
Since 3.0-dev4, we can optionally give a name to logformat nodes:
log-format "%(custom_name1)B %(custom_name2)[str(value)]"
But we may also optionally set the expected node type by appending
':type' after the name, type being either sint,str or bool, like this:
log-format "%(string_as_int:sint)[str(14)]"
However, it is currently not possible to provide a type without providing
a name that is a least 1 char long. But it could be useful to provide a
type without setting a name, like this, for typecasting purposes only:
log-format "%(:sint)[bool(true)]"
Thus in order to allow this usage, don't set node->name if node name is
not at least 1 character long. By doing so, node->name will remain NULL
and will not be considered, but the typecast setting will.
2024-04-25 03:50:14 -04:00
if ( name & & name_len )
2024-01-08 12:38:29 -05:00
node - > name = my_strndup ( name , name_len ) ;
2012-12-20 18:09:23 -05:00
node - > type = LOG_FMT_EXPR ;
2024-02-20 04:29:49 -05:00
node - > typecast = typecast ;
2012-12-20 18:09:23 -05:00
node - > expr = expr ;
BUG/MINOR: log: fix global lf_expr node options behavior
In 507223d5 ("MINOR: log: global lf_expr node options"), a mistake was
made because it was assumed that only the last occurence of %o
(LOG_FMT_GLOBAL) should be kept as global node options.
However, although not documented, it is possible to have multiple %o
within a single logformat expression to change the global settings on the
fly.
For instance, consider this example:
log-format "%{+X}o test1=%ms %{-X}o test2=%ms %{+X}o test3=%ms"
Prior to 3f2e8d0ed ("MEDIUM: log: lf_* build helpers now take a ctx
argument"), this would output something like this:
test1=18B test2=395 test3=18B
This is because global options is properly updated as the lf_expr string
is parsed. But now due to 507223d5 and 3f2e8d0ed, only the last %o
occurence is considered. With the above example, this gives:
test1=18B test2=18B test3=18B
To restore historical behavior, let's partially revert 507223d5: to
compute global node options, we now start with all options enabled and
then for each configurable node in lf_expr_postcheck(), we keep options
common to the current node and previous nodes using AND masking, this way
we really end up with options common to all nodes.
No backport needed.
2024-04-29 05:55:27 -04:00
node - > options = options ;
2012-12-20 18:09:23 -05:00
if ( arg_len ) {
node - > arg = my_strndup ( arg , arg_len ) ;
MINOR: log: rename 'log-format tag' to 'log-format alias'
In 2.9 we started to introduce an ambiguity in the documentation by
referring to historical log-format variables ('%var') as log-format
tags in 739c4e5b1e ("MINOR: sample: accept_date / request_date return
%Ts / %tr timestamp values") and 454c372b60 ("DOC: configuration: add
sample fetches for timing events").
In fact, we've had this confusion between log-format tag and log-format
var for more than 10 years now, but in 2.9 it was the first time the
confusion was exposed in the documentation.
Indeed, both 'log-format variable' and 'log-format tag' actually refer
to the same feature (that is: '%B' and friends that can be used for
direct access to some log-oriented predefined fetches instead of using
%[expr] with generic sample expressions).
This feature was first implemented in 723b73ad75 ("MINOR: config: Parse
the string of the log-format config keyword") and later documented in
4894040fa ("DOC: log-format documentation"). At that time, it was clear
that we used to name it 'log-format variable'.
But later the same year, 'log-format tag' naming started to appear in
some commit messages (while still referring to the same feature), for
instance with ffc3fcd6d ("MEDIUM: log: report SSL ciphers and version
in logs using logformat %sslc/%sslv").
Unfortunately in 2.9 when we added (and documented) new log-format
variables we officially started drifting to the misleading 'log-format
tag' naming (perhaps because it was the most recent naming found for
this feature in git log history, or because the confusion has always
been there)
Even worse, in 3.0 this confusion led us to rename all 'var' occurrences
to 'tag' in log-format related code to unify the code with the doc.
Hopefully William quickly noticed that we made a mistake there, but
instead of reverting to historical naming (log-format variable), it was
decided that we must use a different name that is less confusing than
'tags' or 'variables' (tags and variables are keywords that are already
used to designate other features in the code and that are not very
explicit under log-format context today).
Now we refer to '%B' and friends as a logformat alias, which is
essentially a handy way to print some log oriented information in the
log string instead of leveraging '%[expr]' with generic sample expressions
made of fetches and converters. Of course, there are some subtelties, such
as a few log-format aliases that still don't have sample fetch equivalent
for historical reasons, and some aliases that may be a little faster than
their generic sample expression equivalents because most aliases are
pretty much hardcoded in the log building function. But in general
logformat aliases should be simply considered as an alternative to using
expressions (with '%[expr']')
Also, under log-format context, when we want to refer to either an alias
('%alias') or an expression ('%[expr]'), we should use the generic term
'logformat item', which in fact designates a single item within the
logformat string provided by the user. Indeed, a logformat item (whether
is is an alias or an expression) always starts with '%' and may accept
optional flags / arguments
Both the code and the documentation were updated in that sense, hopefully
this will clarify things and prevent future confusions.
2024-05-27 04:18:10 -04:00
if ( ! parse_logformat_node_args ( node - > arg , node , err ) )
2019-04-29 18:40:02 -04:00
goto error_free ;
2012-12-20 18:09:23 -05:00
}
2013-01-07 19:10:24 -05:00
if ( expr - > fetch - > val & cap & SMP_VAL_REQUEST )
2012-12-20 18:09:23 -05:00
node - > options | = LOG_OPT_REQ_CAP ; /* fetch method is request-compatible */
2013-01-07 19:10:24 -05:00
if ( expr - > fetch - > val & cap & SMP_VAL_RESPONSE )
2012-12-20 18:09:23 -05:00
node - > options | = LOG_OPT_RES_CAP ; /* fetch method is response-compatible */
2016-11-22 17:11:21 -05:00
if ( ! ( expr - > fetch - > val & cap ) ) {
2016-11-22 18:41:28 -05:00
memprintf ( err , " sample fetch <%s> may not be reliably used here because it needs '%s' which is not available here " ,
text , sample_src_names ( expr - > fetch - > use ) ) ;
2019-04-29 18:40:02 -04:00
goto error_free ;
2016-11-22 17:11:21 -05:00
}
2013-01-07 19:10:24 -05:00
BUG/MINOR: log: fix global lf_expr node options behavior
In 507223d5 ("MINOR: log: global lf_expr node options"), a mistake was
made because it was assumed that only the last occurence of %o
(LOG_FMT_GLOBAL) should be kept as global node options.
However, although not documented, it is possible to have multiple %o
within a single logformat expression to change the global settings on the
fly.
For instance, consider this example:
log-format "%{+X}o test1=%ms %{-X}o test2=%ms %{+X}o test3=%ms"
Prior to 3f2e8d0ed ("MEDIUM: log: lf_* build helpers now take a ctx
argument"), this would output something like this:
test1=18B test2=395 test3=18B
This is because global options is properly updated as the lf_expr string
is parsed. But now due to 507223d5 and 3f2e8d0ed, only the last %o
occurence is considered. With the above example, this gives:
test1=18B test2=18B test3=18B
To restore historical behavior, let's partially revert 507223d5: to
compute global node options, we now start with all options enabled and
then for each configurable node in lf_expr_postcheck(), we keep options
common to the current node and previous nodes using AND masking, this way
we really end up with options common to all nodes.
No backport needed.
2024-04-29 05:55:27 -04:00
if ( ( options & LOG_OPT_HTTP ) & & ( expr - > fetch - > use & ( SMP_USE_L6REQ | SMP_USE_L6RES ) ) ) {
2021-03-26 05:02:46 -04:00
ha_warning ( " parsing [%s:%d] : L6 sample fetch <%s> ignored in HTTP log-format string. \n " ,
2024-02-29 08:54:43 -05:00
lf_expr - > conf . file , lf_expr - > conf . line , text ) ;
2021-03-26 05:02:46 -04:00
}
2021-04-21 01:32:39 -04:00
LIST_APPEND ( list_format , & node - > list ) ;
2016-11-22 17:11:21 -05:00
return 1 ;
2019-04-29 18:40:02 -04:00
error_free :
2024-02-22 09:14:21 -05:00
free_logformat_node ( node ) ;
2019-04-29 18:40:02 -04:00
return 0 ;
2012-12-20 18:09:23 -05:00
}
2012-02-08 10:37:49 -05:00
/*
2024-02-29 08:54:43 -05:00
* Compile logformat expression ( from string to list of logformat nodes )
MAJOR: log: implement proper postparsing for logformat expressions
This patch tries to address a design flaw with how logformat expressions
are parsed from config. Indeed, some parse_logformat_string() calls are
performed during config parsing when the proxy mode is not yet known.
Here's a config example that illustrates the issue:
defaults
mode tcp
listen test
bind :8888
http-response set-header custom-hdr "%trl" # needs http
mode http
The above config should work, because the effective proxy mode is http,
yet haproxy fails with this error:
[ALERT] (99051) : config : parsing [repro.conf:6] : error detected in proxy 'test' while parsing 'http-response set-header' rule : format tag 'trl' is reserved for HTTP mode.
To fix the issue once and for all, let's implement smart postparsing for
logformat expressions encountered during config parsing:
- split parse_logformat_string() (and subfonctions) in order to create a
new lf_expr_postcheck() function that must be called to finish
preparing and checking the logformat expression once the proxy type is
known.
- save some config hints info during parse_logformat_string() to
generate more precise error messages during lf_expr_postcheck(), if
needed, we rely on curpx->conf.args.{file,line} hints for that because
parse_logformat_string() doesn't know about current file and line
number.
- lf_expr_postcheck() uses PR_FL_CHECKED proxy flag to know if the
function may try to make the proxy compatible with the expression, or
if it should simply fail as soon as an incompatibility is detected.
- if parse_logformat_string() is called from an unchecked proxy, then
schedule the expression for postparsing, else (ie: during runtime),
run the postcheck right away.
This change will also allow for some logformat expression error handling
simplifications in the future.
2024-02-23 11:26:32 -05:00
*
MINOR: log: rename 'log-format tag' to 'log-format alias'
In 2.9 we started to introduce an ambiguity in the documentation by
referring to historical log-format variables ('%var') as log-format
tags in 739c4e5b1e ("MINOR: sample: accept_date / request_date return
%Ts / %tr timestamp values") and 454c372b60 ("DOC: configuration: add
sample fetches for timing events").
In fact, we've had this confusion between log-format tag and log-format
var for more than 10 years now, but in 2.9 it was the first time the
confusion was exposed in the documentation.
Indeed, both 'log-format variable' and 'log-format tag' actually refer
to the same feature (that is: '%B' and friends that can be used for
direct access to some log-oriented predefined fetches instead of using
%[expr] with generic sample expressions).
This feature was first implemented in 723b73ad75 ("MINOR: config: Parse
the string of the log-format config keyword") and later documented in
4894040fa ("DOC: log-format documentation"). At that time, it was clear
that we used to name it 'log-format variable'.
But later the same year, 'log-format tag' naming started to appear in
some commit messages (while still referring to the same feature), for
instance with ffc3fcd6d ("MEDIUM: log: report SSL ciphers and version
in logs using logformat %sslc/%sslv").
Unfortunately in 2.9 when we added (and documented) new log-format
variables we officially started drifting to the misleading 'log-format
tag' naming (perhaps because it was the most recent naming found for
this feature in git log history, or because the confusion has always
been there)
Even worse, in 3.0 this confusion led us to rename all 'var' occurrences
to 'tag' in log-format related code to unify the code with the doc.
Hopefully William quickly noticed that we made a mistake there, but
instead of reverting to historical naming (log-format variable), it was
decided that we must use a different name that is less confusing than
'tags' or 'variables' (tags and variables are keywords that are already
used to designate other features in the code and that are not very
explicit under log-format context today).
Now we refer to '%B' and friends as a logformat alias, which is
essentially a handy way to print some log oriented information in the
log string instead of leveraging '%[expr]' with generic sample expressions
made of fetches and converters. Of course, there are some subtelties, such
as a few log-format aliases that still don't have sample fetch equivalent
for historical reasons, and some aliases that may be a little faster than
their generic sample expression equivalents because most aliases are
pretty much hardcoded in the log building function. But in general
logformat aliases should be simply considered as an alternative to using
expressions (with '%[expr']')
Also, under log-format context, when we want to refer to either an alias
('%alias') or an expression ('%[expr]'), we should use the generic term
'logformat item', which in fact designates a single item within the
logformat string provided by the user. Indeed, a logformat item (whether
is is an alias or an expression) always starts with '%' and may accept
optional flags / arguments
Both the code and the documentation were updated in that sense, hopefully
this will clarify things and prevent future confusions.
2024-05-27 04:18:10 -04:00
* Aliases are preceded by % and composed by characters [ a - zA - Z0 - 9 ] * : % aliasname
* Expressions are preceded by % and enclosed in square brackets : % [ expr ]
* You can set arguments using { } : % { many arguments } aliasname
* % { many arguments } [ expr ]
2012-03-12 07:46:41 -04:00
*
2024-02-23 09:57:21 -05:00
* lf_expr : the destination logformat expression ( logformat_node list )
2024-02-29 08:54:43 -05:00
* which is supposed to be configured ( str and conf set ) but
2024-04-14 03:23:52 -04:00
* shouldn ' t be compiled ( shouldn ' t contain any nodes )
2024-02-29 08:54:43 -05:00
* al : arg list where sample expr should store arg dependency ( if the logformat
* expression involves sample expressions ) , may be NULL
2013-02-05 12:52:25 -05:00
* options : LOG_OPT_ * to force on every node
2013-01-07 19:10:24 -05:00
* cap : all SMP_VAL_ * flags supported by the consumer
2016-11-22 17:11:21 -05:00
*
2016-11-22 18:41:28 -05:00
* The function returns 1 in success case , otherwise , it returns 0 and err is filled .
2012-02-08 10:37:49 -05:00
*/
2024-02-29 08:54:43 -05:00
int lf_expr_compile ( struct lf_expr * lf_expr ,
struct arg_list * al , int options , int cap , char * * err )
2012-02-08 10:37:49 -05:00
{
MEDIUM: proxy/log: leverage lf_expr API for logformat preparsing
Currently, the way proxy-oriented logformat directives are handled is way
too complicated. Indeed, "log-format", "log-format-error", "log-format-sd"
and "unique-id-format" all rely on preparsing hints stored inside
proxy->conf member struct. Those preparsing hints include the original
string that should be compiled once the proxy parameters are known plus
the config file and line number where the string was found to generate
precise error messages in case of failure during the compiling process
that happens within check_config_validity().
Now that lf_expr API permits to compile a lf_expr struct that was
previously prepared (with original string and config hints), let's
leverage lf_expr_compile() from check_config_validity() and instead
of relying on individual proxy->conf hints for each logformat expression,
store string and config hints in the lf_expr struct directly and use
lf_expr helpers funcs to handle them when relevant (ie: original
logformat string freeing is now done at a central place inside
lf_expr_deinit(), which allows for some simplifications)
Doing so allows us to greatly simplify the preparsing logic for those 4
proxy directives, and to finally save some space in the proxy struct.
Also, since httpclient proxy has its "logformat" automatically compiled
in check_config_validity(), we now use the file hint from the logformat
expression struct to set an explicit name that will be reported in case
of error ("parsing [httpclient:0] : ...") and remove the extraneous check
in httpclient_precheck() (logformat was parsed twice previously..)
2024-03-05 09:44:43 -05:00
char * fmt = lf_expr - > str ; /* will be freed unless default */
2012-12-24 06:36:33 -05:00
char * sp , * str , * backfmt ; /* start pointer for text parts */
2012-12-20 15:23:42 -05:00
char * arg = NULL ; /* start pointer for args */
MINOR: log: rename 'log-format tag' to 'log-format alias'
In 2.9 we started to introduce an ambiguity in the documentation by
referring to historical log-format variables ('%var') as log-format
tags in 739c4e5b1e ("MINOR: sample: accept_date / request_date return
%Ts / %tr timestamp values") and 454c372b60 ("DOC: configuration: add
sample fetches for timing events").
In fact, we've had this confusion between log-format tag and log-format
var for more than 10 years now, but in 2.9 it was the first time the
confusion was exposed in the documentation.
Indeed, both 'log-format variable' and 'log-format tag' actually refer
to the same feature (that is: '%B' and friends that can be used for
direct access to some log-oriented predefined fetches instead of using
%[expr] with generic sample expressions).
This feature was first implemented in 723b73ad75 ("MINOR: config: Parse
the string of the log-format config keyword") and later documented in
4894040fa ("DOC: log-format documentation"). At that time, it was clear
that we used to name it 'log-format variable'.
But later the same year, 'log-format tag' naming started to appear in
some commit messages (while still referring to the same feature), for
instance with ffc3fcd6d ("MEDIUM: log: report SSL ciphers and version
in logs using logformat %sslc/%sslv").
Unfortunately in 2.9 when we added (and documented) new log-format
variables we officially started drifting to the misleading 'log-format
tag' naming (perhaps because it was the most recent naming found for
this feature in git log history, or because the confusion has always
been there)
Even worse, in 3.0 this confusion led us to rename all 'var' occurrences
to 'tag' in log-format related code to unify the code with the doc.
Hopefully William quickly noticed that we made a mistake there, but
instead of reverting to historical naming (log-format variable), it was
decided that we must use a different name that is less confusing than
'tags' or 'variables' (tags and variables are keywords that are already
used to designate other features in the code and that are not very
explicit under log-format context today).
Now we refer to '%B' and friends as a logformat alias, which is
essentially a handy way to print some log oriented information in the
log string instead of leveraging '%[expr]' with generic sample expressions
made of fetches and converters. Of course, there are some subtelties, such
as a few log-format aliases that still don't have sample fetch equivalent
for historical reasons, and some aliases that may be a little faster than
their generic sample expression equivalents because most aliases are
pretty much hardcoded in the log building function. But in general
logformat aliases should be simply considered as an alternative to using
expressions (with '%[expr']')
Also, under log-format context, when we want to refer to either an alias
('%alias') or an expression ('%[expr]'), we should use the generic term
'logformat item', which in fact designates a single item within the
logformat string provided by the user. Indeed, a logformat item (whether
is is an alias or an expression) always starts with '%' and may accept
optional flags / arguments
Both the code and the documentation were updated in that sense, hopefully
this will clarify things and prevent future confusions.
2024-05-27 04:18:10 -04:00
char * alias = NULL ; /* start pointer for aliases */
2024-01-08 12:38:29 -05:00
char * name = NULL ; /* token name (optional) */
2024-02-20 04:29:49 -05:00
char * typecast_str = NULL ; /* token output type (if custom name is set) */
2012-12-20 15:23:42 -05:00
int arg_len = 0 ;
MINOR: log: rename 'log-format tag' to 'log-format alias'
In 2.9 we started to introduce an ambiguity in the documentation by
referring to historical log-format variables ('%var') as log-format
tags in 739c4e5b1e ("MINOR: sample: accept_date / request_date return
%Ts / %tr timestamp values") and 454c372b60 ("DOC: configuration: add
sample fetches for timing events").
In fact, we've had this confusion between log-format tag and log-format
var for more than 10 years now, but in 2.9 it was the first time the
confusion was exposed in the documentation.
Indeed, both 'log-format variable' and 'log-format tag' actually refer
to the same feature (that is: '%B' and friends that can be used for
direct access to some log-oriented predefined fetches instead of using
%[expr] with generic sample expressions).
This feature was first implemented in 723b73ad75 ("MINOR: config: Parse
the string of the log-format config keyword") and later documented in
4894040fa ("DOC: log-format documentation"). At that time, it was clear
that we used to name it 'log-format variable'.
But later the same year, 'log-format tag' naming started to appear in
some commit messages (while still referring to the same feature), for
instance with ffc3fcd6d ("MEDIUM: log: report SSL ciphers and version
in logs using logformat %sslc/%sslv").
Unfortunately in 2.9 when we added (and documented) new log-format
variables we officially started drifting to the misleading 'log-format
tag' naming (perhaps because it was the most recent naming found for
this feature in git log history, or because the confusion has always
been there)
Even worse, in 3.0 this confusion led us to rename all 'var' occurrences
to 'tag' in log-format related code to unify the code with the doc.
Hopefully William quickly noticed that we made a mistake there, but
instead of reverting to historical naming (log-format variable), it was
decided that we must use a different name that is less confusing than
'tags' or 'variables' (tags and variables are keywords that are already
used to designate other features in the code and that are not very
explicit under log-format context today).
Now we refer to '%B' and friends as a logformat alias, which is
essentially a handy way to print some log oriented information in the
log string instead of leveraging '%[expr]' with generic sample expressions
made of fetches and converters. Of course, there are some subtelties, such
as a few log-format aliases that still don't have sample fetch equivalent
for historical reasons, and some aliases that may be a little faster than
their generic sample expression equivalents because most aliases are
pretty much hardcoded in the log building function. But in general
logformat aliases should be simply considered as an alternative to using
expressions (with '%[expr']')
Also, under log-format context, when we want to refer to either an alias
('%alias') or an expression ('%[expr]'), we should use the generic term
'logformat item', which in fact designates a single item within the
logformat string provided by the user. Indeed, a logformat item (whether
is is an alias or an expression) always starts with '%' and may accept
optional flags / arguments
Both the code and the documentation were updated in that sense, hopefully
this will clarify things and prevent future confusions.
2024-05-27 04:18:10 -04:00
int alias_len = 0 ;
2024-01-08 12:38:29 -05:00
int name_len = 0 ;
2024-02-20 04:29:49 -05:00
int typecast = SMP_T_SAME ; /* relaxed by default */
2012-12-20 15:23:42 -05:00
int cformat ; /* current token format */
int pformat ; /* previous token format */
2012-02-08 10:37:49 -05:00
2024-02-29 08:54:43 -05:00
BUG_ON ( ( lf_expr - > flags & LF_FL_COMPILED ) ) ;
if ( ! fmt )
return 1 ; // nothing to do
2012-12-24 06:36:33 -05:00
sp = str = backfmt = strdup ( fmt ) ;
2016-11-22 17:24:10 -05:00
if ( ! str ) {
2016-11-22 18:41:28 -05:00
memprintf ( err , " out of memory error " ) ;
2016-11-22 17:24:10 -05:00
return 0 ;
}
2012-04-02 10:22:10 -04:00
2024-02-29 08:54:43 -05:00
/* Prepare lf_expr nodes, past this lf_expr doesn't know about ->str
* anymore as - > str and - > nodes are part of the same union . - > str has
* been saved as local ' fmt ' string pointer , so we must free it before
* returning .
MAJOR: log: implement proper postparsing for logformat expressions
This patch tries to address a design flaw with how logformat expressions
are parsed from config. Indeed, some parse_logformat_string() calls are
performed during config parsing when the proxy mode is not yet known.
Here's a config example that illustrates the issue:
defaults
mode tcp
listen test
bind :8888
http-response set-header custom-hdr "%trl" # needs http
mode http
The above config should work, because the effective proxy mode is http,
yet haproxy fails with this error:
[ALERT] (99051) : config : parsing [repro.conf:6] : error detected in proxy 'test' while parsing 'http-response set-header' rule : format tag 'trl' is reserved for HTTP mode.
To fix the issue once and for all, let's implement smart postparsing for
logformat expressions encountered during config parsing:
- split parse_logformat_string() (and subfonctions) in order to create a
new lf_expr_postcheck() function that must be called to finish
preparing and checking the logformat expression once the proxy type is
known.
- save some config hints info during parse_logformat_string() to
generate more precise error messages during lf_expr_postcheck(), if
needed, we rely on curpx->conf.args.{file,line} hints for that because
parse_logformat_string() doesn't know about current file and line
number.
- lf_expr_postcheck() uses PR_FL_CHECKED proxy flag to know if the
function may try to make the proxy compatible with the expression, or
if it should simply fail as soon as an incompatibility is detected.
- if parse_logformat_string() is called from an unchecked proxy, then
schedule the expression for postparsing, else (ie: during runtime),
run the postcheck right away.
This change will also allow for some logformat expression error handling
simplifications in the future.
2024-02-23 11:26:32 -05:00
*/
2024-03-25 06:29:58 -04:00
LIST_INIT ( & lf_expr - > nodes . list ) ;
2024-04-29 09:58:36 -04:00
lf_expr - > nodes . options = LOG_OPT_NONE ;
2024-02-29 08:54:43 -05:00
/* we must set the compiled flag now for proper deinit in case of failure */
lf_expr - > flags | = LF_FL_COMPILED ;
MAJOR: log: implement proper postparsing for logformat expressions
This patch tries to address a design flaw with how logformat expressions
are parsed from config. Indeed, some parse_logformat_string() calls are
performed during config parsing when the proxy mode is not yet known.
Here's a config example that illustrates the issue:
defaults
mode tcp
listen test
bind :8888
http-response set-header custom-hdr "%trl" # needs http
mode http
The above config should work, because the effective proxy mode is http,
yet haproxy fails with this error:
[ALERT] (99051) : config : parsing [repro.conf:6] : error detected in proxy 'test' while parsing 'http-response set-header' rule : format tag 'trl' is reserved for HTTP mode.
To fix the issue once and for all, let's implement smart postparsing for
logformat expressions encountered during config parsing:
- split parse_logformat_string() (and subfonctions) in order to create a
new lf_expr_postcheck() function that must be called to finish
preparing and checking the logformat expression once the proxy type is
known.
- save some config hints info during parse_logformat_string() to
generate more precise error messages during lf_expr_postcheck(), if
needed, we rely on curpx->conf.args.{file,line} hints for that because
parse_logformat_string() doesn't know about current file and line
number.
- lf_expr_postcheck() uses PR_FL_CHECKED proxy flag to know if the
function may try to make the proxy compatible with the expression, or
if it should simply fail as soon as an incompatibility is detected.
- if parse_logformat_string() is called from an unchecked proxy, then
schedule the expression for postparsing, else (ie: during runtime),
run the postcheck right away.
This change will also allow for some logformat expression error handling
simplifications in the future.
2024-02-23 11:26:32 -05:00
2012-12-20 15:23:42 -05:00
for ( cformat = LF_INIT ; cformat ! = LF_END ; str + + ) {
2012-02-08 10:37:49 -05:00
pformat = cformat ;
2012-12-20 15:23:42 -05:00
if ( ! * str )
cformat = LF_END ; // preset it to save all states from doing this
2018-11-15 15:10:04 -05:00
/* The principle of the two-step state machine below is to first detect a change, and
2012-12-20 15:23:42 -05:00
* second have all common paths processed at one place . The common paths are the ones
* encountered in text areas ( LF_INIT , LF_TEXT , LF_SEPARATOR ) and at the end ( LF_END ) .
* We use the common LF_INIT state to dispatch to the different final states .
*/
switch ( pformat ) {
MINOR: log: rename 'log-format tag' to 'log-format alias'
In 2.9 we started to introduce an ambiguity in the documentation by
referring to historical log-format variables ('%var') as log-format
tags in 739c4e5b1e ("MINOR: sample: accept_date / request_date return
%Ts / %tr timestamp values") and 454c372b60 ("DOC: configuration: add
sample fetches for timing events").
In fact, we've had this confusion between log-format tag and log-format
var for more than 10 years now, but in 2.9 it was the first time the
confusion was exposed in the documentation.
Indeed, both 'log-format variable' and 'log-format tag' actually refer
to the same feature (that is: '%B' and friends that can be used for
direct access to some log-oriented predefined fetches instead of using
%[expr] with generic sample expressions).
This feature was first implemented in 723b73ad75 ("MINOR: config: Parse
the string of the log-format config keyword") and later documented in
4894040fa ("DOC: log-format documentation"). At that time, it was clear
that we used to name it 'log-format variable'.
But later the same year, 'log-format tag' naming started to appear in
some commit messages (while still referring to the same feature), for
instance with ffc3fcd6d ("MEDIUM: log: report SSL ciphers and version
in logs using logformat %sslc/%sslv").
Unfortunately in 2.9 when we added (and documented) new log-format
variables we officially started drifting to the misleading 'log-format
tag' naming (perhaps because it was the most recent naming found for
this feature in git log history, or because the confusion has always
been there)
Even worse, in 3.0 this confusion led us to rename all 'var' occurrences
to 'tag' in log-format related code to unify the code with the doc.
Hopefully William quickly noticed that we made a mistake there, but
instead of reverting to historical naming (log-format variable), it was
decided that we must use a different name that is less confusing than
'tags' or 'variables' (tags and variables are keywords that are already
used to designate other features in the code and that are not very
explicit under log-format context today).
Now we refer to '%B' and friends as a logformat alias, which is
essentially a handy way to print some log oriented information in the
log string instead of leveraging '%[expr]' with generic sample expressions
made of fetches and converters. Of course, there are some subtelties, such
as a few log-format aliases that still don't have sample fetch equivalent
for historical reasons, and some aliases that may be a little faster than
their generic sample expression equivalents because most aliases are
pretty much hardcoded in the log building function. But in general
logformat aliases should be simply considered as an alternative to using
expressions (with '%[expr']')
Also, under log-format context, when we want to refer to either an alias
('%alias') or an expression ('%[expr]'), we should use the generic term
'logformat item', which in fact designates a single item within the
logformat string provided by the user. Indeed, a logformat item (whether
is is an alias or an expression) always starts with '%' and may accept
optional flags / arguments
Both the code and the documentation were updated in that sense, hopefully
this will clarify things and prevent future confusions.
2024-05-27 04:18:10 -04:00
case LF_STARTALIAS : // text immediately following a '%'
arg = NULL ; alias = NULL ;
2024-01-08 12:38:29 -05:00
name = NULL ;
name_len = 0 ;
2024-02-20 04:29:49 -05:00
typecast = SMP_T_SAME ;
MINOR: log: rename 'log-format tag' to 'log-format alias'
In 2.9 we started to introduce an ambiguity in the documentation by
referring to historical log-format variables ('%var') as log-format
tags in 739c4e5b1e ("MINOR: sample: accept_date / request_date return
%Ts / %tr timestamp values") and 454c372b60 ("DOC: configuration: add
sample fetches for timing events").
In fact, we've had this confusion between log-format tag and log-format
var for more than 10 years now, but in 2.9 it was the first time the
confusion was exposed in the documentation.
Indeed, both 'log-format variable' and 'log-format tag' actually refer
to the same feature (that is: '%B' and friends that can be used for
direct access to some log-oriented predefined fetches instead of using
%[expr] with generic sample expressions).
This feature was first implemented in 723b73ad75 ("MINOR: config: Parse
the string of the log-format config keyword") and later documented in
4894040fa ("DOC: log-format documentation"). At that time, it was clear
that we used to name it 'log-format variable'.
But later the same year, 'log-format tag' naming started to appear in
some commit messages (while still referring to the same feature), for
instance with ffc3fcd6d ("MEDIUM: log: report SSL ciphers and version
in logs using logformat %sslc/%sslv").
Unfortunately in 2.9 when we added (and documented) new log-format
variables we officially started drifting to the misleading 'log-format
tag' naming (perhaps because it was the most recent naming found for
this feature in git log history, or because the confusion has always
been there)
Even worse, in 3.0 this confusion led us to rename all 'var' occurrences
to 'tag' in log-format related code to unify the code with the doc.
Hopefully William quickly noticed that we made a mistake there, but
instead of reverting to historical naming (log-format variable), it was
decided that we must use a different name that is less confusing than
'tags' or 'variables' (tags and variables are keywords that are already
used to designate other features in the code and that are not very
explicit under log-format context today).
Now we refer to '%B' and friends as a logformat alias, which is
essentially a handy way to print some log oriented information in the
log string instead of leveraging '%[expr]' with generic sample expressions
made of fetches and converters. Of course, there are some subtelties, such
as a few log-format aliases that still don't have sample fetch equivalent
for historical reasons, and some aliases that may be a little faster than
their generic sample expression equivalents because most aliases are
pretty much hardcoded in the log building function. But in general
logformat aliases should be simply considered as an alternative to using
expressions (with '%[expr']')
Also, under log-format context, when we want to refer to either an alias
('%alias') or an expression ('%[expr]'), we should use the generic term
'logformat item', which in fact designates a single item within the
logformat string provided by the user. Indeed, a logformat item (whether
is is an alias or an expression) always starts with '%' and may accept
optional flags / arguments
Both the code and the documentation were updated in that sense, hopefully
this will clarify things and prevent future confusions.
2024-05-27 04:18:10 -04:00
arg_len = alias_len = 0 ;
2024-01-08 12:38:29 -05:00
if ( * str = = ' ( ' ) { // custom output name
cformat = LF_STONAME ;
name = str + 1 ;
}
else
MINOR: log: rename 'log-format tag' to 'log-format alias'
In 2.9 we started to introduce an ambiguity in the documentation by
referring to historical log-format variables ('%var') as log-format
tags in 739c4e5b1e ("MINOR: sample: accept_date / request_date return
%Ts / %tr timestamp values") and 454c372b60 ("DOC: configuration: add
sample fetches for timing events").
In fact, we've had this confusion between log-format tag and log-format
var for more than 10 years now, but in 2.9 it was the first time the
confusion was exposed in the documentation.
Indeed, both 'log-format variable' and 'log-format tag' actually refer
to the same feature (that is: '%B' and friends that can be used for
direct access to some log-oriented predefined fetches instead of using
%[expr] with generic sample expressions).
This feature was first implemented in 723b73ad75 ("MINOR: config: Parse
the string of the log-format config keyword") and later documented in
4894040fa ("DOC: log-format documentation"). At that time, it was clear
that we used to name it 'log-format variable'.
But later the same year, 'log-format tag' naming started to appear in
some commit messages (while still referring to the same feature), for
instance with ffc3fcd6d ("MEDIUM: log: report SSL ciphers and version
in logs using logformat %sslc/%sslv").
Unfortunately in 2.9 when we added (and documented) new log-format
variables we officially started drifting to the misleading 'log-format
tag' naming (perhaps because it was the most recent naming found for
this feature in git log history, or because the confusion has always
been there)
Even worse, in 3.0 this confusion led us to rename all 'var' occurrences
to 'tag' in log-format related code to unify the code with the doc.
Hopefully William quickly noticed that we made a mistake there, but
instead of reverting to historical naming (log-format variable), it was
decided that we must use a different name that is less confusing than
'tags' or 'variables' (tags and variables are keywords that are already
used to designate other features in the code and that are not very
explicit under log-format context today).
Now we refer to '%B' and friends as a logformat alias, which is
essentially a handy way to print some log oriented information in the
log string instead of leveraging '%[expr]' with generic sample expressions
made of fetches and converters. Of course, there are some subtelties, such
as a few log-format aliases that still don't have sample fetch equivalent
for historical reasons, and some aliases that may be a little faster than
their generic sample expression equivalents because most aliases are
pretty much hardcoded in the log building function. But in general
logformat aliases should be simply considered as an alternative to using
expressions (with '%[expr']')
Also, under log-format context, when we want to refer to either an alias
('%alias') or an expression ('%[expr]'), we should use the generic term
'logformat item', which in fact designates a single item within the
logformat string provided by the user. Indeed, a logformat item (whether
is is an alias or an expression) always starts with '%' and may accept
optional flags / arguments
Both the code and the documentation were updated in that sense, hopefully
this will clarify things and prevent future confusions.
2024-05-27 04:18:10 -04:00
goto startalias ;
2024-01-08 12:38:29 -05:00
break ;
case LF_STONAME : // text immediately following '%('
2024-02-20 04:29:49 -05:00
case LF_STOTYPE :
if ( cformat = = LF_STONAME & & * str = = ' : ' ) { // start custom output type
cformat = LF_STOTYPE ;
name_len = str - name ;
typecast_str = str + 1 ;
}
else if ( * str = = ' ) ' ) { // end of custom output name
if ( cformat = = LF_STONAME )
name_len = str - name ;
else {
/* custom type */
* str = 0 ; // so that typecast_str is 0 terminated
typecast = type_to_smp ( typecast_str ) ;
if ( typecast ! = SMP_T_STR & & typecast ! = SMP_T_SINT & &
typecast ! = SMP_T_BOOL ) {
memprintf ( err , " unexpected output type '%.*s' at position %d line : '%s'. Supported types are: str, sint, bool " , ( int ) ( str - typecast_str ) , typecast_str , ( int ) ( typecast_str - backfmt ) , fmt ) ;
goto fail ;
}
}
2024-01-08 12:38:29 -05:00
cformat = LF_EDONAME ;
} else if ( ! isalnum ( ( unsigned char ) * str ) & & * str ! = ' _ ' & & * str ! = ' - ' ) {
memprintf ( err , " invalid character in custom name near '%c' at position %d line : '%s' " ,
* str , ( int ) ( str - backfmt ) , fmt ) ;
goto fail ;
}
break ;
case LF_EDONAME : // text immediately following %(name)
MINOR: log: rename 'log-format tag' to 'log-format alias'
In 2.9 we started to introduce an ambiguity in the documentation by
referring to historical log-format variables ('%var') as log-format
tags in 739c4e5b1e ("MINOR: sample: accept_date / request_date return
%Ts / %tr timestamp values") and 454c372b60 ("DOC: configuration: add
sample fetches for timing events").
In fact, we've had this confusion between log-format tag and log-format
var for more than 10 years now, but in 2.9 it was the first time the
confusion was exposed in the documentation.
Indeed, both 'log-format variable' and 'log-format tag' actually refer
to the same feature (that is: '%B' and friends that can be used for
direct access to some log-oriented predefined fetches instead of using
%[expr] with generic sample expressions).
This feature was first implemented in 723b73ad75 ("MINOR: config: Parse
the string of the log-format config keyword") and later documented in
4894040fa ("DOC: log-format documentation"). At that time, it was clear
that we used to name it 'log-format variable'.
But later the same year, 'log-format tag' naming started to appear in
some commit messages (while still referring to the same feature), for
instance with ffc3fcd6d ("MEDIUM: log: report SSL ciphers and version
in logs using logformat %sslc/%sslv").
Unfortunately in 2.9 when we added (and documented) new log-format
variables we officially started drifting to the misleading 'log-format
tag' naming (perhaps because it was the most recent naming found for
this feature in git log history, or because the confusion has always
been there)
Even worse, in 3.0 this confusion led us to rename all 'var' occurrences
to 'tag' in log-format related code to unify the code with the doc.
Hopefully William quickly noticed that we made a mistake there, but
instead of reverting to historical naming (log-format variable), it was
decided that we must use a different name that is less confusing than
'tags' or 'variables' (tags and variables are keywords that are already
used to designate other features in the code and that are not very
explicit under log-format context today).
Now we refer to '%B' and friends as a logformat alias, which is
essentially a handy way to print some log oriented information in the
log string instead of leveraging '%[expr]' with generic sample expressions
made of fetches and converters. Of course, there are some subtelties, such
as a few log-format aliases that still don't have sample fetch equivalent
for historical reasons, and some aliases that may be a little faster than
their generic sample expression equivalents because most aliases are
pretty much hardcoded in the log building function. But in general
logformat aliases should be simply considered as an alternative to using
expressions (with '%[expr']')
Also, under log-format context, when we want to refer to either an alias
('%alias') or an expression ('%[expr]'), we should use the generic term
'logformat item', which in fact designates a single item within the
logformat string provided by the user. Indeed, a logformat item (whether
is is an alias or an expression) always starts with '%' and may accept
optional flags / arguments
Both the code and the documentation were updated in that sense, hopefully
this will clarify things and prevent future confusions.
2024-05-27 04:18:10 -04:00
startalias :
2012-12-20 15:23:42 -05:00
if ( * str = = ' { ' ) { // optional argument
cformat = LF_STARG ;
arg = str + 1 ;
2012-02-08 10:37:49 -05:00
}
2012-12-20 18:09:23 -05:00
else if ( * str = = ' [ ' ) {
cformat = LF_STEXPR ;
MINOR: log: rename 'log-format tag' to 'log-format alias'
In 2.9 we started to introduce an ambiguity in the documentation by
referring to historical log-format variables ('%var') as log-format
tags in 739c4e5b1e ("MINOR: sample: accept_date / request_date return
%Ts / %tr timestamp values") and 454c372b60 ("DOC: configuration: add
sample fetches for timing events").
In fact, we've had this confusion between log-format tag and log-format
var for more than 10 years now, but in 2.9 it was the first time the
confusion was exposed in the documentation.
Indeed, both 'log-format variable' and 'log-format tag' actually refer
to the same feature (that is: '%B' and friends that can be used for
direct access to some log-oriented predefined fetches instead of using
%[expr] with generic sample expressions).
This feature was first implemented in 723b73ad75 ("MINOR: config: Parse
the string of the log-format config keyword") and later documented in
4894040fa ("DOC: log-format documentation"). At that time, it was clear
that we used to name it 'log-format variable'.
But later the same year, 'log-format tag' naming started to appear in
some commit messages (while still referring to the same feature), for
instance with ffc3fcd6d ("MEDIUM: log: report SSL ciphers and version
in logs using logformat %sslc/%sslv").
Unfortunately in 2.9 when we added (and documented) new log-format
variables we officially started drifting to the misleading 'log-format
tag' naming (perhaps because it was the most recent naming found for
this feature in git log history, or because the confusion has always
been there)
Even worse, in 3.0 this confusion led us to rename all 'var' occurrences
to 'tag' in log-format related code to unify the code with the doc.
Hopefully William quickly noticed that we made a mistake there, but
instead of reverting to historical naming (log-format variable), it was
decided that we must use a different name that is less confusing than
'tags' or 'variables' (tags and variables are keywords that are already
used to designate other features in the code and that are not very
explicit under log-format context today).
Now we refer to '%B' and friends as a logformat alias, which is
essentially a handy way to print some log oriented information in the
log string instead of leveraging '%[expr]' with generic sample expressions
made of fetches and converters. Of course, there are some subtelties, such
as a few log-format aliases that still don't have sample fetch equivalent
for historical reasons, and some aliases that may be a little faster than
their generic sample expression equivalents because most aliases are
pretty much hardcoded in the log building function. But in general
logformat aliases should be simply considered as an alternative to using
expressions (with '%[expr']')
Also, under log-format context, when we want to refer to either an alias
('%alias') or an expression ('%[expr]'), we should use the generic term
'logformat item', which in fact designates a single item within the
logformat string provided by the user. Indeed, a logformat item (whether
is is an alias or an expression) always starts with '%' and may accept
optional flags / arguments
Both the code and the documentation were updated in that sense, hopefully
this will clarify things and prevent future confusions.
2024-05-27 04:18:10 -04:00
alias = str + 1 ; // store expr in alias name
2012-12-20 18:09:23 -05:00
}
MINOR: log: rename 'log-format tag' to 'log-format alias'
In 2.9 we started to introduce an ambiguity in the documentation by
referring to historical log-format variables ('%var') as log-format
tags in 739c4e5b1e ("MINOR: sample: accept_date / request_date return
%Ts / %tr timestamp values") and 454c372b60 ("DOC: configuration: add
sample fetches for timing events").
In fact, we've had this confusion between log-format tag and log-format
var for more than 10 years now, but in 2.9 it was the first time the
confusion was exposed in the documentation.
Indeed, both 'log-format variable' and 'log-format tag' actually refer
to the same feature (that is: '%B' and friends that can be used for
direct access to some log-oriented predefined fetches instead of using
%[expr] with generic sample expressions).
This feature was first implemented in 723b73ad75 ("MINOR: config: Parse
the string of the log-format config keyword") and later documented in
4894040fa ("DOC: log-format documentation"). At that time, it was clear
that we used to name it 'log-format variable'.
But later the same year, 'log-format tag' naming started to appear in
some commit messages (while still referring to the same feature), for
instance with ffc3fcd6d ("MEDIUM: log: report SSL ciphers and version
in logs using logformat %sslc/%sslv").
Unfortunately in 2.9 when we added (and documented) new log-format
variables we officially started drifting to the misleading 'log-format
tag' naming (perhaps because it was the most recent naming found for
this feature in git log history, or because the confusion has always
been there)
Even worse, in 3.0 this confusion led us to rename all 'var' occurrences
to 'tag' in log-format related code to unify the code with the doc.
Hopefully William quickly noticed that we made a mistake there, but
instead of reverting to historical naming (log-format variable), it was
decided that we must use a different name that is less confusing than
'tags' or 'variables' (tags and variables are keywords that are already
used to designate other features in the code and that are not very
explicit under log-format context today).
Now we refer to '%B' and friends as a logformat alias, which is
essentially a handy way to print some log oriented information in the
log string instead of leveraging '%[expr]' with generic sample expressions
made of fetches and converters. Of course, there are some subtelties, such
as a few log-format aliases that still don't have sample fetch equivalent
for historical reasons, and some aliases that may be a little faster than
their generic sample expression equivalents because most aliases are
pretty much hardcoded in the log building function. But in general
logformat aliases should be simply considered as an alternative to using
expressions (with '%[expr']')
Also, under log-format context, when we want to refer to either an alias
('%alias') or an expression ('%[expr]'), we should use the generic term
'logformat item', which in fact designates a single item within the
logformat string provided by the user. Indeed, a logformat item (whether
is is an alias or an expression) always starts with '%' and may accept
optional flags / arguments
Both the code and the documentation were updated in that sense, hopefully
this will clarify things and prevent future confusions.
2024-05-27 04:18:10 -04:00
else if ( isalpha ( ( unsigned char ) * str ) ) { // alias name
cformat = LF_ALIAS ;
alias = str ;
2012-02-08 10:37:49 -05:00
}
2012-12-20 15:23:42 -05:00
else if ( * str = = ' % ' )
2020-04-16 14:51:34 -04:00
cformat = LF_TEXT ; // convert this character to a literal (useful for '%')
2013-12-15 19:38:33 -05:00
else if ( isdigit ( ( unsigned char ) * str ) | | * str = = ' ' | | * str = = ' \t ' ) {
2013-12-02 11:45:48 -05:00
/* single '%' followed by blank or digit, send them both */
cformat = LF_TEXT ;
pformat = LF_TEXT ; /* finally we include the previous char as well */
sp = str - 1 ; /* send both the '%' and the current char */
MINOR: log: rename 'log-format tag' to 'log-format alias'
In 2.9 we started to introduce an ambiguity in the documentation by
referring to historical log-format variables ('%var') as log-format
tags in 739c4e5b1e ("MINOR: sample: accept_date / request_date return
%Ts / %tr timestamp values") and 454c372b60 ("DOC: configuration: add
sample fetches for timing events").
In fact, we've had this confusion between log-format tag and log-format
var for more than 10 years now, but in 2.9 it was the first time the
confusion was exposed in the documentation.
Indeed, both 'log-format variable' and 'log-format tag' actually refer
to the same feature (that is: '%B' and friends that can be used for
direct access to some log-oriented predefined fetches instead of using
%[expr] with generic sample expressions).
This feature was first implemented in 723b73ad75 ("MINOR: config: Parse
the string of the log-format config keyword") and later documented in
4894040fa ("DOC: log-format documentation"). At that time, it was clear
that we used to name it 'log-format variable'.
But later the same year, 'log-format tag' naming started to appear in
some commit messages (while still referring to the same feature), for
instance with ffc3fcd6d ("MEDIUM: log: report SSL ciphers and version
in logs using logformat %sslc/%sslv").
Unfortunately in 2.9 when we added (and documented) new log-format
variables we officially started drifting to the misleading 'log-format
tag' naming (perhaps because it was the most recent naming found for
this feature in git log history, or because the confusion has always
been there)
Even worse, in 3.0 this confusion led us to rename all 'var' occurrences
to 'tag' in log-format related code to unify the code with the doc.
Hopefully William quickly noticed that we made a mistake there, but
instead of reverting to historical naming (log-format variable), it was
decided that we must use a different name that is less confusing than
'tags' or 'variables' (tags and variables are keywords that are already
used to designate other features in the code and that are not very
explicit under log-format context today).
Now we refer to '%B' and friends as a logformat alias, which is
essentially a handy way to print some log oriented information in the
log string instead of leveraging '%[expr]' with generic sample expressions
made of fetches and converters. Of course, there are some subtelties, such
as a few log-format aliases that still don't have sample fetch equivalent
for historical reasons, and some aliases that may be a little faster than
their generic sample expression equivalents because most aliases are
pretty much hardcoded in the log building function. But in general
logformat aliases should be simply considered as an alternative to using
expressions (with '%[expr']')
Also, under log-format context, when we want to refer to either an alias
('%alias') or an expression ('%[expr]'), we should use the generic term
'logformat item', which in fact designates a single item within the
logformat string provided by the user. Indeed, a logformat item (whether
is is an alias or an expression) always starts with '%' and may accept
optional flags / arguments
Both the code and the documentation were updated in that sense, hopefully
this will clarify things and prevent future confusions.
2024-05-27 04:18:10 -04:00
memprintf ( err , " unexpected alias name near '%c' at position %d line : '%s'. Maybe you want to write a single '%%', use the syntax '%%%%' " ,
2016-11-22 18:41:28 -05:00
* str , ( int ) ( str - backfmt ) , fmt ) ;
2019-12-11 06:05:39 -05:00
goto fail ;
2013-12-02 11:45:48 -05:00
}
2012-12-20 15:23:42 -05:00
else
2020-04-16 14:51:34 -04:00
cformat = LF_INIT ; // handle other cases of literals
2012-12-20 15:23:42 -05:00
break ;
case LF_STARG : // text immediately following '%{'
if ( * str = = ' } ' ) { // end of arg
2012-02-08 10:37:49 -05:00
cformat = LF_EDARG ;
2012-12-20 15:23:42 -05:00
arg_len = str - arg ;
* str = 0 ; // used for reporting errors
2012-02-08 10:37:49 -05:00
}
2012-12-20 15:23:42 -05:00
break ;
case LF_EDARG : // text immediately following '%{arg}'
2012-12-20 18:09:23 -05:00
if ( * str = = ' [ ' ) {
cformat = LF_STEXPR ;
MINOR: log: rename 'log-format tag' to 'log-format alias'
In 2.9 we started to introduce an ambiguity in the documentation by
referring to historical log-format variables ('%var') as log-format
tags in 739c4e5b1e ("MINOR: sample: accept_date / request_date return
%Ts / %tr timestamp values") and 454c372b60 ("DOC: configuration: add
sample fetches for timing events").
In fact, we've had this confusion between log-format tag and log-format
var for more than 10 years now, but in 2.9 it was the first time the
confusion was exposed in the documentation.
Indeed, both 'log-format variable' and 'log-format tag' actually refer
to the same feature (that is: '%B' and friends that can be used for
direct access to some log-oriented predefined fetches instead of using
%[expr] with generic sample expressions).
This feature was first implemented in 723b73ad75 ("MINOR: config: Parse
the string of the log-format config keyword") and later documented in
4894040fa ("DOC: log-format documentation"). At that time, it was clear
that we used to name it 'log-format variable'.
But later the same year, 'log-format tag' naming started to appear in
some commit messages (while still referring to the same feature), for
instance with ffc3fcd6d ("MEDIUM: log: report SSL ciphers and version
in logs using logformat %sslc/%sslv").
Unfortunately in 2.9 when we added (and documented) new log-format
variables we officially started drifting to the misleading 'log-format
tag' naming (perhaps because it was the most recent naming found for
this feature in git log history, or because the confusion has always
been there)
Even worse, in 3.0 this confusion led us to rename all 'var' occurrences
to 'tag' in log-format related code to unify the code with the doc.
Hopefully William quickly noticed that we made a mistake there, but
instead of reverting to historical naming (log-format variable), it was
decided that we must use a different name that is less confusing than
'tags' or 'variables' (tags and variables are keywords that are already
used to designate other features in the code and that are not very
explicit under log-format context today).
Now we refer to '%B' and friends as a logformat alias, which is
essentially a handy way to print some log oriented information in the
log string instead of leveraging '%[expr]' with generic sample expressions
made of fetches and converters. Of course, there are some subtelties, such
as a few log-format aliases that still don't have sample fetch equivalent
for historical reasons, and some aliases that may be a little faster than
their generic sample expression equivalents because most aliases are
pretty much hardcoded in the log building function. But in general
logformat aliases should be simply considered as an alternative to using
expressions (with '%[expr']')
Also, under log-format context, when we want to refer to either an alias
('%alias') or an expression ('%[expr]'), we should use the generic term
'logformat item', which in fact designates a single item within the
logformat string provided by the user. Indeed, a logformat item (whether
is is an alias or an expression) always starts with '%' and may accept
optional flags / arguments
Both the code and the documentation were updated in that sense, hopefully
this will clarify things and prevent future confusions.
2024-05-27 04:18:10 -04:00
alias = str + 1 ; // store expr in alias name
2012-12-20 18:09:23 -05:00
break ;
}
MINOR: log: rename 'log-format tag' to 'log-format alias'
In 2.9 we started to introduce an ambiguity in the documentation by
referring to historical log-format variables ('%var') as log-format
tags in 739c4e5b1e ("MINOR: sample: accept_date / request_date return
%Ts / %tr timestamp values") and 454c372b60 ("DOC: configuration: add
sample fetches for timing events").
In fact, we've had this confusion between log-format tag and log-format
var for more than 10 years now, but in 2.9 it was the first time the
confusion was exposed in the documentation.
Indeed, both 'log-format variable' and 'log-format tag' actually refer
to the same feature (that is: '%B' and friends that can be used for
direct access to some log-oriented predefined fetches instead of using
%[expr] with generic sample expressions).
This feature was first implemented in 723b73ad75 ("MINOR: config: Parse
the string of the log-format config keyword") and later documented in
4894040fa ("DOC: log-format documentation"). At that time, it was clear
that we used to name it 'log-format variable'.
But later the same year, 'log-format tag' naming started to appear in
some commit messages (while still referring to the same feature), for
instance with ffc3fcd6d ("MEDIUM: log: report SSL ciphers and version
in logs using logformat %sslc/%sslv").
Unfortunately in 2.9 when we added (and documented) new log-format
variables we officially started drifting to the misleading 'log-format
tag' naming (perhaps because it was the most recent naming found for
this feature in git log history, or because the confusion has always
been there)
Even worse, in 3.0 this confusion led us to rename all 'var' occurrences
to 'tag' in log-format related code to unify the code with the doc.
Hopefully William quickly noticed that we made a mistake there, but
instead of reverting to historical naming (log-format variable), it was
decided that we must use a different name that is less confusing than
'tags' or 'variables' (tags and variables are keywords that are already
used to designate other features in the code and that are not very
explicit under log-format context today).
Now we refer to '%B' and friends as a logformat alias, which is
essentially a handy way to print some log oriented information in the
log string instead of leveraging '%[expr]' with generic sample expressions
made of fetches and converters. Of course, there are some subtelties, such
as a few log-format aliases that still don't have sample fetch equivalent
for historical reasons, and some aliases that may be a little faster than
their generic sample expression equivalents because most aliases are
pretty much hardcoded in the log building function. But in general
logformat aliases should be simply considered as an alternative to using
expressions (with '%[expr']')
Also, under log-format context, when we want to refer to either an alias
('%alias') or an expression ('%[expr]'), we should use the generic term
'logformat item', which in fact designates a single item within the
logformat string provided by the user. Indeed, a logformat item (whether
is is an alias or an expression) always starts with '%' and may accept
optional flags / arguments
Both the code and the documentation were updated in that sense, hopefully
this will clarify things and prevent future confusions.
2024-05-27 04:18:10 -04:00
else if ( isalnum ( ( unsigned char ) * str ) ) { // alias name
cformat = LF_ALIAS ;
alias = str ;
2012-12-20 15:23:42 -05:00
break ;
}
MINOR: log: rename 'log-format tag' to 'log-format alias'
In 2.9 we started to introduce an ambiguity in the documentation by
referring to historical log-format variables ('%var') as log-format
tags in 739c4e5b1e ("MINOR: sample: accept_date / request_date return
%Ts / %tr timestamp values") and 454c372b60 ("DOC: configuration: add
sample fetches for timing events").
In fact, we've had this confusion between log-format tag and log-format
var for more than 10 years now, but in 2.9 it was the first time the
confusion was exposed in the documentation.
Indeed, both 'log-format variable' and 'log-format tag' actually refer
to the same feature (that is: '%B' and friends that can be used for
direct access to some log-oriented predefined fetches instead of using
%[expr] with generic sample expressions).
This feature was first implemented in 723b73ad75 ("MINOR: config: Parse
the string of the log-format config keyword") and later documented in
4894040fa ("DOC: log-format documentation"). At that time, it was clear
that we used to name it 'log-format variable'.
But later the same year, 'log-format tag' naming started to appear in
some commit messages (while still referring to the same feature), for
instance with ffc3fcd6d ("MEDIUM: log: report SSL ciphers and version
in logs using logformat %sslc/%sslv").
Unfortunately in 2.9 when we added (and documented) new log-format
variables we officially started drifting to the misleading 'log-format
tag' naming (perhaps because it was the most recent naming found for
this feature in git log history, or because the confusion has always
been there)
Even worse, in 3.0 this confusion led us to rename all 'var' occurrences
to 'tag' in log-format related code to unify the code with the doc.
Hopefully William quickly noticed that we made a mistake there, but
instead of reverting to historical naming (log-format variable), it was
decided that we must use a different name that is less confusing than
'tags' or 'variables' (tags and variables are keywords that are already
used to designate other features in the code and that are not very
explicit under log-format context today).
Now we refer to '%B' and friends as a logformat alias, which is
essentially a handy way to print some log oriented information in the
log string instead of leveraging '%[expr]' with generic sample expressions
made of fetches and converters. Of course, there are some subtelties, such
as a few log-format aliases that still don't have sample fetch equivalent
for historical reasons, and some aliases that may be a little faster than
their generic sample expression equivalents because most aliases are
pretty much hardcoded in the log building function. But in general
logformat aliases should be simply considered as an alternative to using
expressions (with '%[expr']')
Also, under log-format context, when we want to refer to either an alias
('%alias') or an expression ('%[expr]'), we should use the generic term
'logformat item', which in fact designates a single item within the
logformat string provided by the user. Indeed, a logformat item (whether
is is an alias or an expression) always starts with '%' and may accept
optional flags / arguments
Both the code and the documentation were updated in that sense, hopefully
this will clarify things and prevent future confusions.
2024-05-27 04:18:10 -04:00
memprintf ( err , " parse argument modifier without alias name near '%%{%s}' " , arg ) ;
2019-12-11 06:05:39 -05:00
goto fail ;
2012-12-20 15:23:42 -05:00
2012-12-20 18:09:23 -05:00
case LF_STEXPR : // text immediately following '%['
2020-02-14 11:33:06 -05:00
/* the whole sample expression is parsed at once,
* returning the pointer to the first character not
* part of the expression , which MUST be the trailing
* angle bracket .
*/
MINOR: log: rename 'log-format tag' to 'log-format alias'
In 2.9 we started to introduce an ambiguity in the documentation by
referring to historical log-format variables ('%var') as log-format
tags in 739c4e5b1e ("MINOR: sample: accept_date / request_date return
%Ts / %tr timestamp values") and 454c372b60 ("DOC: configuration: add
sample fetches for timing events").
In fact, we've had this confusion between log-format tag and log-format
var for more than 10 years now, but in 2.9 it was the first time the
confusion was exposed in the documentation.
Indeed, both 'log-format variable' and 'log-format tag' actually refer
to the same feature (that is: '%B' and friends that can be used for
direct access to some log-oriented predefined fetches instead of using
%[expr] with generic sample expressions).
This feature was first implemented in 723b73ad75 ("MINOR: config: Parse
the string of the log-format config keyword") and later documented in
4894040fa ("DOC: log-format documentation"). At that time, it was clear
that we used to name it 'log-format variable'.
But later the same year, 'log-format tag' naming started to appear in
some commit messages (while still referring to the same feature), for
instance with ffc3fcd6d ("MEDIUM: log: report SSL ciphers and version
in logs using logformat %sslc/%sslv").
Unfortunately in 2.9 when we added (and documented) new log-format
variables we officially started drifting to the misleading 'log-format
tag' naming (perhaps because it was the most recent naming found for
this feature in git log history, or because the confusion has always
been there)
Even worse, in 3.0 this confusion led us to rename all 'var' occurrences
to 'tag' in log-format related code to unify the code with the doc.
Hopefully William quickly noticed that we made a mistake there, but
instead of reverting to historical naming (log-format variable), it was
decided that we must use a different name that is less confusing than
'tags' or 'variables' (tags and variables are keywords that are already
used to designate other features in the code and that are not very
explicit under log-format context today).
Now we refer to '%B' and friends as a logformat alias, which is
essentially a handy way to print some log oriented information in the
log string instead of leveraging '%[expr]' with generic sample expressions
made of fetches and converters. Of course, there are some subtelties, such
as a few log-format aliases that still don't have sample fetch equivalent
for historical reasons, and some aliases that may be a little faster than
their generic sample expression equivalents because most aliases are
pretty much hardcoded in the log building function. But in general
logformat aliases should be simply considered as an alternative to using
expressions (with '%[expr']')
Also, under log-format context, when we want to refer to either an alias
('%alias') or an expression ('%[expr]'), we should use the generic term
'logformat item', which in fact designates a single item within the
logformat string provided by the user. Indeed, a logformat item (whether
is is an alias or an expression) always starts with '%' and may accept
optional flags / arguments
Both the code and the documentation were updated in that sense, hopefully
this will clarify things and prevent future confusions.
2024-05-27 04:18:10 -04:00
if ( ! add_sample_to_logformat_list ( alias , name , name_len , typecast , arg , arg_len , lf_expr , al , options , cap , err , & str ) )
2020-02-14 11:33:06 -05:00
goto fail ;
if ( * str = = ' ] ' ) {
// end of arg, go on with next state
cformat = pformat = LF_EDEXPR ;
sp = str ;
}
else {
char c = * str ;
* str = 0 ;
2020-02-25 02:16:33 -05:00
if ( isprint ( ( unsigned char ) c ) )
MINOR: log: rename 'log-format tag' to 'log-format alias'
In 2.9 we started to introduce an ambiguity in the documentation by
referring to historical log-format variables ('%var') as log-format
tags in 739c4e5b1e ("MINOR: sample: accept_date / request_date return
%Ts / %tr timestamp values") and 454c372b60 ("DOC: configuration: add
sample fetches for timing events").
In fact, we've had this confusion between log-format tag and log-format
var for more than 10 years now, but in 2.9 it was the first time the
confusion was exposed in the documentation.
Indeed, both 'log-format variable' and 'log-format tag' actually refer
to the same feature (that is: '%B' and friends that can be used for
direct access to some log-oriented predefined fetches instead of using
%[expr] with generic sample expressions).
This feature was first implemented in 723b73ad75 ("MINOR: config: Parse
the string of the log-format config keyword") and later documented in
4894040fa ("DOC: log-format documentation"). At that time, it was clear
that we used to name it 'log-format variable'.
But later the same year, 'log-format tag' naming started to appear in
some commit messages (while still referring to the same feature), for
instance with ffc3fcd6d ("MEDIUM: log: report SSL ciphers and version
in logs using logformat %sslc/%sslv").
Unfortunately in 2.9 when we added (and documented) new log-format
variables we officially started drifting to the misleading 'log-format
tag' naming (perhaps because it was the most recent naming found for
this feature in git log history, or because the confusion has always
been there)
Even worse, in 3.0 this confusion led us to rename all 'var' occurrences
to 'tag' in log-format related code to unify the code with the doc.
Hopefully William quickly noticed that we made a mistake there, but
instead of reverting to historical naming (log-format variable), it was
decided that we must use a different name that is less confusing than
'tags' or 'variables' (tags and variables are keywords that are already
used to designate other features in the code and that are not very
explicit under log-format context today).
Now we refer to '%B' and friends as a logformat alias, which is
essentially a handy way to print some log oriented information in the
log string instead of leveraging '%[expr]' with generic sample expressions
made of fetches and converters. Of course, there are some subtelties, such
as a few log-format aliases that still don't have sample fetch equivalent
for historical reasons, and some aliases that may be a little faster than
their generic sample expression equivalents because most aliases are
pretty much hardcoded in the log building function. But in general
logformat aliases should be simply considered as an alternative to using
expressions (with '%[expr']')
Also, under log-format context, when we want to refer to either an alias
('%alias') or an expression ('%[expr]'), we should use the generic term
'logformat item', which in fact designates a single item within the
logformat string provided by the user. Indeed, a logformat item (whether
is is an alias or an expression) always starts with '%' and may accept
optional flags / arguments
Both the code and the documentation were updated in that sense, hopefully
this will clarify things and prevent future confusions.
2024-05-27 04:18:10 -04:00
memprintf ( err , " expected ']' after '%s', but found '%c' " , alias , c ) ;
2020-02-14 11:33:06 -05:00
else
MINOR: log: rename 'log-format tag' to 'log-format alias'
In 2.9 we started to introduce an ambiguity in the documentation by
referring to historical log-format variables ('%var') as log-format
tags in 739c4e5b1e ("MINOR: sample: accept_date / request_date return
%Ts / %tr timestamp values") and 454c372b60 ("DOC: configuration: add
sample fetches for timing events").
In fact, we've had this confusion between log-format tag and log-format
var for more than 10 years now, but in 2.9 it was the first time the
confusion was exposed in the documentation.
Indeed, both 'log-format variable' and 'log-format tag' actually refer
to the same feature (that is: '%B' and friends that can be used for
direct access to some log-oriented predefined fetches instead of using
%[expr] with generic sample expressions).
This feature was first implemented in 723b73ad75 ("MINOR: config: Parse
the string of the log-format config keyword") and later documented in
4894040fa ("DOC: log-format documentation"). At that time, it was clear
that we used to name it 'log-format variable'.
But later the same year, 'log-format tag' naming started to appear in
some commit messages (while still referring to the same feature), for
instance with ffc3fcd6d ("MEDIUM: log: report SSL ciphers and version
in logs using logformat %sslc/%sslv").
Unfortunately in 2.9 when we added (and documented) new log-format
variables we officially started drifting to the misleading 'log-format
tag' naming (perhaps because it was the most recent naming found for
this feature in git log history, or because the confusion has always
been there)
Even worse, in 3.0 this confusion led us to rename all 'var' occurrences
to 'tag' in log-format related code to unify the code with the doc.
Hopefully William quickly noticed that we made a mistake there, but
instead of reverting to historical naming (log-format variable), it was
decided that we must use a different name that is less confusing than
'tags' or 'variables' (tags and variables are keywords that are already
used to designate other features in the code and that are not very
explicit under log-format context today).
Now we refer to '%B' and friends as a logformat alias, which is
essentially a handy way to print some log oriented information in the
log string instead of leveraging '%[expr]' with generic sample expressions
made of fetches and converters. Of course, there are some subtelties, such
as a few log-format aliases that still don't have sample fetch equivalent
for historical reasons, and some aliases that may be a little faster than
their generic sample expression equivalents because most aliases are
pretty much hardcoded in the log building function. But in general
logformat aliases should be simply considered as an alternative to using
expressions (with '%[expr']')
Also, under log-format context, when we want to refer to either an alias
('%alias') or an expression ('%[expr]'), we should use the generic term
'logformat item', which in fact designates a single item within the
logformat string provided by the user. Indeed, a logformat item (whether
is is an alias or an expression) always starts with '%' and may accept
optional flags / arguments
Both the code and the documentation were updated in that sense, hopefully
this will clarify things and prevent future confusions.
2024-05-27 04:18:10 -04:00
memprintf ( err , " missing ']' after '%s' " , alias ) ;
2020-06-30 15:16:43 -04:00
goto fail ;
2012-12-20 18:09:23 -05:00
}
break ;
MINOR: log: rename 'log-format tag' to 'log-format alias'
In 2.9 we started to introduce an ambiguity in the documentation by
referring to historical log-format variables ('%var') as log-format
tags in 739c4e5b1e ("MINOR: sample: accept_date / request_date return
%Ts / %tr timestamp values") and 454c372b60 ("DOC: configuration: add
sample fetches for timing events").
In fact, we've had this confusion between log-format tag and log-format
var for more than 10 years now, but in 2.9 it was the first time the
confusion was exposed in the documentation.
Indeed, both 'log-format variable' and 'log-format tag' actually refer
to the same feature (that is: '%B' and friends that can be used for
direct access to some log-oriented predefined fetches instead of using
%[expr] with generic sample expressions).
This feature was first implemented in 723b73ad75 ("MINOR: config: Parse
the string of the log-format config keyword") and later documented in
4894040fa ("DOC: log-format documentation"). At that time, it was clear
that we used to name it 'log-format variable'.
But later the same year, 'log-format tag' naming started to appear in
some commit messages (while still referring to the same feature), for
instance with ffc3fcd6d ("MEDIUM: log: report SSL ciphers and version
in logs using logformat %sslc/%sslv").
Unfortunately in 2.9 when we added (and documented) new log-format
variables we officially started drifting to the misleading 'log-format
tag' naming (perhaps because it was the most recent naming found for
this feature in git log history, or because the confusion has always
been there)
Even worse, in 3.0 this confusion led us to rename all 'var' occurrences
to 'tag' in log-format related code to unify the code with the doc.
Hopefully William quickly noticed that we made a mistake there, but
instead of reverting to historical naming (log-format variable), it was
decided that we must use a different name that is less confusing than
'tags' or 'variables' (tags and variables are keywords that are already
used to designate other features in the code and that are not very
explicit under log-format context today).
Now we refer to '%B' and friends as a logformat alias, which is
essentially a handy way to print some log oriented information in the
log string instead of leveraging '%[expr]' with generic sample expressions
made of fetches and converters. Of course, there are some subtelties, such
as a few log-format aliases that still don't have sample fetch equivalent
for historical reasons, and some aliases that may be a little faster than
their generic sample expression equivalents because most aliases are
pretty much hardcoded in the log building function. But in general
logformat aliases should be simply considered as an alternative to using
expressions (with '%[expr']')
Also, under log-format context, when we want to refer to either an alias
('%alias') or an expression ('%[expr]'), we should use the generic term
'logformat item', which in fact designates a single item within the
logformat string provided by the user. Indeed, a logformat item (whether
is is an alias or an expression) always starts with '%' and may accept
optional flags / arguments
Both the code and the documentation were updated in that sense, hopefully
this will clarify things and prevent future confusions.
2024-05-27 04:18:10 -04:00
case LF_ALIAS : // text part of a alias name
alias_len = str - alias ;
2013-12-15 19:38:33 -05:00
if ( ! isalnum ( ( unsigned char ) * str ) )
MINOR: log: rename 'log-format tag' to 'log-format alias'
In 2.9 we started to introduce an ambiguity in the documentation by
referring to historical log-format variables ('%var') as log-format
tags in 739c4e5b1e ("MINOR: sample: accept_date / request_date return
%Ts / %tr timestamp values") and 454c372b60 ("DOC: configuration: add
sample fetches for timing events").
In fact, we've had this confusion between log-format tag and log-format
var for more than 10 years now, but in 2.9 it was the first time the
confusion was exposed in the documentation.
Indeed, both 'log-format variable' and 'log-format tag' actually refer
to the same feature (that is: '%B' and friends that can be used for
direct access to some log-oriented predefined fetches instead of using
%[expr] with generic sample expressions).
This feature was first implemented in 723b73ad75 ("MINOR: config: Parse
the string of the log-format config keyword") and later documented in
4894040fa ("DOC: log-format documentation"). At that time, it was clear
that we used to name it 'log-format variable'.
But later the same year, 'log-format tag' naming started to appear in
some commit messages (while still referring to the same feature), for
instance with ffc3fcd6d ("MEDIUM: log: report SSL ciphers and version
in logs using logformat %sslc/%sslv").
Unfortunately in 2.9 when we added (and documented) new log-format
variables we officially started drifting to the misleading 'log-format
tag' naming (perhaps because it was the most recent naming found for
this feature in git log history, or because the confusion has always
been there)
Even worse, in 3.0 this confusion led us to rename all 'var' occurrences
to 'tag' in log-format related code to unify the code with the doc.
Hopefully William quickly noticed that we made a mistake there, but
instead of reverting to historical naming (log-format variable), it was
decided that we must use a different name that is less confusing than
'tags' or 'variables' (tags and variables are keywords that are already
used to designate other features in the code and that are not very
explicit under log-format context today).
Now we refer to '%B' and friends as a logformat alias, which is
essentially a handy way to print some log oriented information in the
log string instead of leveraging '%[expr]' with generic sample expressions
made of fetches and converters. Of course, there are some subtelties, such
as a few log-format aliases that still don't have sample fetch equivalent
for historical reasons, and some aliases that may be a little faster than
their generic sample expression equivalents because most aliases are
pretty much hardcoded in the log building function. But in general
logformat aliases should be simply considered as an alternative to using
expressions (with '%[expr']')
Also, under log-format context, when we want to refer to either an alias
('%alias') or an expression ('%[expr]'), we should use the generic term
'logformat item', which in fact designates a single item within the
logformat string provided by the user. Indeed, a logformat item (whether
is is an alias or an expression) always starts with '%' and may accept
optional flags / arguments
Both the code and the documentation were updated in that sense, hopefully
this will clarify things and prevent future confusions.
2024-05-27 04:18:10 -04:00
cformat = LF_INIT ; // not alias name anymore
2012-12-20 15:23:42 -05:00
break ;
2012-12-20 18:09:23 -05:00
default : // LF_INIT, LF_TEXT, LF_SEPARATOR, LF_END, LF_EDEXPR
2012-12-20 15:23:42 -05:00
cformat = LF_INIT ;
}
MINOR: log: rename 'log-format tag' to 'log-format alias'
In 2.9 we started to introduce an ambiguity in the documentation by
referring to historical log-format variables ('%var') as log-format
tags in 739c4e5b1e ("MINOR: sample: accept_date / request_date return
%Ts / %tr timestamp values") and 454c372b60 ("DOC: configuration: add
sample fetches for timing events").
In fact, we've had this confusion between log-format tag and log-format
var for more than 10 years now, but in 2.9 it was the first time the
confusion was exposed in the documentation.
Indeed, both 'log-format variable' and 'log-format tag' actually refer
to the same feature (that is: '%B' and friends that can be used for
direct access to some log-oriented predefined fetches instead of using
%[expr] with generic sample expressions).
This feature was first implemented in 723b73ad75 ("MINOR: config: Parse
the string of the log-format config keyword") and later documented in
4894040fa ("DOC: log-format documentation"). At that time, it was clear
that we used to name it 'log-format variable'.
But later the same year, 'log-format tag' naming started to appear in
some commit messages (while still referring to the same feature), for
instance with ffc3fcd6d ("MEDIUM: log: report SSL ciphers and version
in logs using logformat %sslc/%sslv").
Unfortunately in 2.9 when we added (and documented) new log-format
variables we officially started drifting to the misleading 'log-format
tag' naming (perhaps because it was the most recent naming found for
this feature in git log history, or because the confusion has always
been there)
Even worse, in 3.0 this confusion led us to rename all 'var' occurrences
to 'tag' in log-format related code to unify the code with the doc.
Hopefully William quickly noticed that we made a mistake there, but
instead of reverting to historical naming (log-format variable), it was
decided that we must use a different name that is less confusing than
'tags' or 'variables' (tags and variables are keywords that are already
used to designate other features in the code and that are not very
explicit under log-format context today).
Now we refer to '%B' and friends as a logformat alias, which is
essentially a handy way to print some log oriented information in the
log string instead of leveraging '%[expr]' with generic sample expressions
made of fetches and converters. Of course, there are some subtelties, such
as a few log-format aliases that still don't have sample fetch equivalent
for historical reasons, and some aliases that may be a little faster than
their generic sample expression equivalents because most aliases are
pretty much hardcoded in the log building function. But in general
logformat aliases should be simply considered as an alternative to using
expressions (with '%[expr']')
Also, under log-format context, when we want to refer to either an alias
('%alias') or an expression ('%[expr]'), we should use the generic term
'logformat item', which in fact designates a single item within the
logformat string provided by the user. Indeed, a logformat item (whether
is is an alias or an expression) always starts with '%' and may accept
optional flags / arguments
Both the code and the documentation were updated in that sense, hopefully
this will clarify things and prevent future confusions.
2024-05-27 04:18:10 -04:00
if ( cformat = = LF_INIT ) { /* resynchronize state to text/sep/startalias */
2012-12-20 15:23:42 -05:00
switch ( * str ) {
MINOR: log: rename 'log-format tag' to 'log-format alias'
In 2.9 we started to introduce an ambiguity in the documentation by
referring to historical log-format variables ('%var') as log-format
tags in 739c4e5b1e ("MINOR: sample: accept_date / request_date return
%Ts / %tr timestamp values") and 454c372b60 ("DOC: configuration: add
sample fetches for timing events").
In fact, we've had this confusion between log-format tag and log-format
var for more than 10 years now, but in 2.9 it was the first time the
confusion was exposed in the documentation.
Indeed, both 'log-format variable' and 'log-format tag' actually refer
to the same feature (that is: '%B' and friends that can be used for
direct access to some log-oriented predefined fetches instead of using
%[expr] with generic sample expressions).
This feature was first implemented in 723b73ad75 ("MINOR: config: Parse
the string of the log-format config keyword") and later documented in
4894040fa ("DOC: log-format documentation"). At that time, it was clear
that we used to name it 'log-format variable'.
But later the same year, 'log-format tag' naming started to appear in
some commit messages (while still referring to the same feature), for
instance with ffc3fcd6d ("MEDIUM: log: report SSL ciphers and version
in logs using logformat %sslc/%sslv").
Unfortunately in 2.9 when we added (and documented) new log-format
variables we officially started drifting to the misleading 'log-format
tag' naming (perhaps because it was the most recent naming found for
this feature in git log history, or because the confusion has always
been there)
Even worse, in 3.0 this confusion led us to rename all 'var' occurrences
to 'tag' in log-format related code to unify the code with the doc.
Hopefully William quickly noticed that we made a mistake there, but
instead of reverting to historical naming (log-format variable), it was
decided that we must use a different name that is less confusing than
'tags' or 'variables' (tags and variables are keywords that are already
used to designate other features in the code and that are not very
explicit under log-format context today).
Now we refer to '%B' and friends as a logformat alias, which is
essentially a handy way to print some log oriented information in the
log string instead of leveraging '%[expr]' with generic sample expressions
made of fetches and converters. Of course, there are some subtelties, such
as a few log-format aliases that still don't have sample fetch equivalent
for historical reasons, and some aliases that may be a little faster than
their generic sample expression equivalents because most aliases are
pretty much hardcoded in the log building function. But in general
logformat aliases should be simply considered as an alternative to using
expressions (with '%[expr']')
Also, under log-format context, when we want to refer to either an alias
('%alias') or an expression ('%[expr]'), we should use the generic term
'logformat item', which in fact designates a single item within the
logformat string provided by the user. Indeed, a logformat item (whether
is is an alias or an expression) always starts with '%' and may accept
optional flags / arguments
Both the code and the documentation were updated in that sense, hopefully
this will clarify things and prevent future confusions.
2024-05-27 04:18:10 -04:00
case ' % ' : cformat = LF_STARTALIAS ; break ;
2012-12-20 15:23:42 -05:00
case 0 : cformat = LF_END ; break ;
2020-06-23 12:16:44 -04:00
case ' ' :
if ( options & LOG_OPT_MERGE_SPACES ) {
cformat = LF_SEPARATOR ;
break ;
}
2022-11-14 01:22:57 -05:00
__fallthrough ;
2012-12-20 15:23:42 -05:00
default : cformat = LF_TEXT ; break ;
2012-02-08 10:37:49 -05:00
}
}
2012-12-20 15:23:42 -05:00
if ( cformat ! = pformat | | pformat = = LF_SEPARATOR ) {
switch ( pformat ) {
MINOR: log: rename 'log-format tag' to 'log-format alias'
In 2.9 we started to introduce an ambiguity in the documentation by
referring to historical log-format variables ('%var') as log-format
tags in 739c4e5b1e ("MINOR: sample: accept_date / request_date return
%Ts / %tr timestamp values") and 454c372b60 ("DOC: configuration: add
sample fetches for timing events").
In fact, we've had this confusion between log-format tag and log-format
var for more than 10 years now, but in 2.9 it was the first time the
confusion was exposed in the documentation.
Indeed, both 'log-format variable' and 'log-format tag' actually refer
to the same feature (that is: '%B' and friends that can be used for
direct access to some log-oriented predefined fetches instead of using
%[expr] with generic sample expressions).
This feature was first implemented in 723b73ad75 ("MINOR: config: Parse
the string of the log-format config keyword") and later documented in
4894040fa ("DOC: log-format documentation"). At that time, it was clear
that we used to name it 'log-format variable'.
But later the same year, 'log-format tag' naming started to appear in
some commit messages (while still referring to the same feature), for
instance with ffc3fcd6d ("MEDIUM: log: report SSL ciphers and version
in logs using logformat %sslc/%sslv").
Unfortunately in 2.9 when we added (and documented) new log-format
variables we officially started drifting to the misleading 'log-format
tag' naming (perhaps because it was the most recent naming found for
this feature in git log history, or because the confusion has always
been there)
Even worse, in 3.0 this confusion led us to rename all 'var' occurrences
to 'tag' in log-format related code to unify the code with the doc.
Hopefully William quickly noticed that we made a mistake there, but
instead of reverting to historical naming (log-format variable), it was
decided that we must use a different name that is less confusing than
'tags' or 'variables' (tags and variables are keywords that are already
used to designate other features in the code and that are not very
explicit under log-format context today).
Now we refer to '%B' and friends as a logformat alias, which is
essentially a handy way to print some log oriented information in the
log string instead of leveraging '%[expr]' with generic sample expressions
made of fetches and converters. Of course, there are some subtelties, such
as a few log-format aliases that still don't have sample fetch equivalent
for historical reasons, and some aliases that may be a little faster than
their generic sample expression equivalents because most aliases are
pretty much hardcoded in the log building function. But in general
logformat aliases should be simply considered as an alternative to using
expressions (with '%[expr']')
Also, under log-format context, when we want to refer to either an alias
('%alias') or an expression ('%[expr]'), we should use the generic term
'logformat item', which in fact designates a single item within the
logformat string provided by the user. Indeed, a logformat item (whether
is is an alias or an expression) always starts with '%' and may accept
optional flags / arguments
Both the code and the documentation were updated in that sense, hopefully
this will clarify things and prevent future confusions.
2024-05-27 04:18:10 -04:00
case LF_ALIAS :
if ( ! parse_logformat_alias ( arg , arg_len , name , name_len , typecast , alias , alias_len , lf_expr , & options , err ) )
2019-12-11 06:05:39 -05:00
goto fail ;
2012-12-20 15:23:42 -05:00
break ;
case LF_TEXT :
case LF_SEPARATOR :
2024-02-23 09:57:21 -05:00
if ( ! add_to_logformat_list ( sp , str , pformat , lf_expr , err ) )
2019-12-11 06:05:39 -05:00
goto fail ;
2012-12-20 15:23:42 -05:00
break ;
}
sp = str ; /* new start of text at every state switch and at every separator */
2012-02-08 10:37:49 -05:00
}
}
2012-12-20 15:23:42 -05:00
MINOR: log: rename 'log-format tag' to 'log-format alias'
In 2.9 we started to introduce an ambiguity in the documentation by
referring to historical log-format variables ('%var') as log-format
tags in 739c4e5b1e ("MINOR: sample: accept_date / request_date return
%Ts / %tr timestamp values") and 454c372b60 ("DOC: configuration: add
sample fetches for timing events").
In fact, we've had this confusion between log-format tag and log-format
var for more than 10 years now, but in 2.9 it was the first time the
confusion was exposed in the documentation.
Indeed, both 'log-format variable' and 'log-format tag' actually refer
to the same feature (that is: '%B' and friends that can be used for
direct access to some log-oriented predefined fetches instead of using
%[expr] with generic sample expressions).
This feature was first implemented in 723b73ad75 ("MINOR: config: Parse
the string of the log-format config keyword") and later documented in
4894040fa ("DOC: log-format documentation"). At that time, it was clear
that we used to name it 'log-format variable'.
But later the same year, 'log-format tag' naming started to appear in
some commit messages (while still referring to the same feature), for
instance with ffc3fcd6d ("MEDIUM: log: report SSL ciphers and version
in logs using logformat %sslc/%sslv").
Unfortunately in 2.9 when we added (and documented) new log-format
variables we officially started drifting to the misleading 'log-format
tag' naming (perhaps because it was the most recent naming found for
this feature in git log history, or because the confusion has always
been there)
Even worse, in 3.0 this confusion led us to rename all 'var' occurrences
to 'tag' in log-format related code to unify the code with the doc.
Hopefully William quickly noticed that we made a mistake there, but
instead of reverting to historical naming (log-format variable), it was
decided that we must use a different name that is less confusing than
'tags' or 'variables' (tags and variables are keywords that are already
used to designate other features in the code and that are not very
explicit under log-format context today).
Now we refer to '%B' and friends as a logformat alias, which is
essentially a handy way to print some log oriented information in the
log string instead of leveraging '%[expr]' with generic sample expressions
made of fetches and converters. Of course, there are some subtelties, such
as a few log-format aliases that still don't have sample fetch equivalent
for historical reasons, and some aliases that may be a little faster than
their generic sample expression equivalents because most aliases are
pretty much hardcoded in the log building function. But in general
logformat aliases should be simply considered as an alternative to using
expressions (with '%[expr']')
Also, under log-format context, when we want to refer to either an alias
('%alias') or an expression ('%[expr]'), we should use the generic term
'logformat item', which in fact designates a single item within the
logformat string provided by the user. Indeed, a logformat item (whether
is is an alias or an expression) always starts with '%' and may accept
optional flags / arguments
Both the code and the documentation were updated in that sense, hopefully
this will clarify things and prevent future confusions.
2024-05-27 04:18:10 -04:00
if ( pformat = = LF_STARTALIAS | | pformat = = LF_STARG | | pformat = = LF_STEXPR | | pformat = = LF_STONAME | | pformat = = LF_STOTYPE | | pformat = = LF_EDONAME ) {
memprintf ( err , " truncated line after '%s' " , alias ? alias : arg ? arg : " % " ) ;
2019-12-11 06:05:39 -05:00
goto fail ;
2016-11-22 17:11:21 -05:00
}
MEDIUM: proxy/log: leverage lf_expr API for logformat preparsing
Currently, the way proxy-oriented logformat directives are handled is way
too complicated. Indeed, "log-format", "log-format-error", "log-format-sd"
and "unique-id-format" all rely on preparsing hints stored inside
proxy->conf member struct. Those preparsing hints include the original
string that should be compiled once the proxy parameters are known plus
the config file and line number where the string was found to generate
precise error messages in case of failure during the compiling process
that happens within check_config_validity().
Now that lf_expr API permits to compile a lf_expr struct that was
previously prepared (with original string and config hints), let's
leverage lf_expr_compile() from check_config_validity() and instead
of relying on individual proxy->conf hints for each logformat expression,
store string and config hints in the lf_expr struct directly and use
lf_expr helpers funcs to handle them when relevant (ie: original
logformat string freeing is now done at a central place inside
lf_expr_deinit(), which allows for some simplifications)
Doing so allows us to greatly simplify the preparsing logic for those 4
proxy directives, and to finally save some space in the proxy struct.
Also, since httpclient proxy has its "logformat" automatically compiled
in check_config_validity(), we now use the file hint from the logformat
expression struct to set an explicit name that will be reported in case
of error ("parsing [httpclient:0] : ...") and remove the extraneous check
in httpclient_precheck() (logformat was parsed twice previously..)
2024-03-05 09:44:43 -05:00
logformat_str_free ( & fmt ) ;
MAJOR: log: implement proper postparsing for logformat expressions
This patch tries to address a design flaw with how logformat expressions
are parsed from config. Indeed, some parse_logformat_string() calls are
performed during config parsing when the proxy mode is not yet known.
Here's a config example that illustrates the issue:
defaults
mode tcp
listen test
bind :8888
http-response set-header custom-hdr "%trl" # needs http
mode http
The above config should work, because the effective proxy mode is http,
yet haproxy fails with this error:
[ALERT] (99051) : config : parsing [repro.conf:6] : error detected in proxy 'test' while parsing 'http-response set-header' rule : format tag 'trl' is reserved for HTTP mode.
To fix the issue once and for all, let's implement smart postparsing for
logformat expressions encountered during config parsing:
- split parse_logformat_string() (and subfonctions) in order to create a
new lf_expr_postcheck() function that must be called to finish
preparing and checking the logformat expression once the proxy type is
known.
- save some config hints info during parse_logformat_string() to
generate more precise error messages during lf_expr_postcheck(), if
needed, we rely on curpx->conf.args.{file,line} hints for that because
parse_logformat_string() doesn't know about current file and line
number.
- lf_expr_postcheck() uses PR_FL_CHECKED proxy flag to know if the
function may try to make the proxy compatible with the expression, or
if it should simply fail as soon as an incompatibility is detected.
- if parse_logformat_string() is called from an unchecked proxy, then
schedule the expression for postparsing, else (ie: during runtime),
run the postcheck right away.
This change will also allow for some logformat expression error handling
simplifications in the future.
2024-02-23 11:26:32 -05:00
ha_free ( & backfmt ) ;
2024-02-29 08:54:43 -05:00
return 1 ;
fail :
MEDIUM: proxy/log: leverage lf_expr API for logformat preparsing
Currently, the way proxy-oriented logformat directives are handled is way
too complicated. Indeed, "log-format", "log-format-error", "log-format-sd"
and "unique-id-format" all rely on preparsing hints stored inside
proxy->conf member struct. Those preparsing hints include the original
string that should be compiled once the proxy parameters are known plus
the config file and line number where the string was found to generate
precise error messages in case of failure during the compiling process
that happens within check_config_validity().
Now that lf_expr API permits to compile a lf_expr struct that was
previously prepared (with original string and config hints), let's
leverage lf_expr_compile() from check_config_validity() and instead
of relying on individual proxy->conf hints for each logformat expression,
store string and config hints in the lf_expr struct directly and use
lf_expr helpers funcs to handle them when relevant (ie: original
logformat string freeing is now done at a central place inside
lf_expr_deinit(), which allows for some simplifications)
Doing so allows us to greatly simplify the preparsing logic for those 4
proxy directives, and to finally save some space in the proxy struct.
Also, since httpclient proxy has its "logformat" automatically compiled
in check_config_validity(), we now use the file hint from the logformat
expression struct to set an explicit name that will be reported in case
of error ("parsing [httpclient:0] : ...") and remove the extraneous check
in httpclient_precheck() (logformat was parsed twice previously..)
2024-03-05 09:44:43 -05:00
logformat_str_free ( & fmt ) ;
2024-02-29 08:54:43 -05:00
ha_free ( & backfmt ) ;
return 0 ;
}
/* lf_expr_compile() helper: uses <curproxy> to deduce settings and
* simplify function usage , mostly for legacy purpose
*
* curproxy - > conf . args . ctx must be set by the caller .
*
* The logformat expression will be scheduled for postcheck on the proxy unless
* the proxy was already checked , in which case all checks will be performed right
* away .
*
* Returns 1 on success and 0 on failure . On failure : < lf_expr > will be cleaned
* up and < err > will be set .
*/
int parse_logformat_string ( const char * fmt , struct proxy * curproxy ,
struct lf_expr * lf_expr ,
int options , int cap , char * * err )
{
int ret ;
/* reinit lf_expr (if previously set) */
lf_expr_deinit ( lf_expr ) ;
lf_expr - > str = strdup ( fmt ) ;
if ( ! lf_expr - > str ) {
memprintf ( err , " out of memory error " ) ;
goto fail ;
}
/* Save some parsing infos to raise relevant error messages during
* postparsing if needed
*/
if ( curproxy - > conf . args . file ) {
lf_expr - > conf . file = strdup ( curproxy - > conf . args . file ) ;
lf_expr - > conf . line = curproxy - > conf . args . line ;
}
ret = lf_expr_compile ( lf_expr , & curproxy - > conf . args , options , cap , err ) ;
if ( ! ret )
goto fail ;
2024-06-11 04:15:36 -04:00
if ( ! ( curproxy - > cap & PR_CAP_DEF ) & &
! ( curproxy - > flags & PR_FL_CHECKED ) ) {
MAJOR: log: implement proper postparsing for logformat expressions
This patch tries to address a design flaw with how logformat expressions
are parsed from config. Indeed, some parse_logformat_string() calls are
performed during config parsing when the proxy mode is not yet known.
Here's a config example that illustrates the issue:
defaults
mode tcp
listen test
bind :8888
http-response set-header custom-hdr "%trl" # needs http
mode http
The above config should work, because the effective proxy mode is http,
yet haproxy fails with this error:
[ALERT] (99051) : config : parsing [repro.conf:6] : error detected in proxy 'test' while parsing 'http-response set-header' rule : format tag 'trl' is reserved for HTTP mode.
To fix the issue once and for all, let's implement smart postparsing for
logformat expressions encountered during config parsing:
- split parse_logformat_string() (and subfonctions) in order to create a
new lf_expr_postcheck() function that must be called to finish
preparing and checking the logformat expression once the proxy type is
known.
- save some config hints info during parse_logformat_string() to
generate more precise error messages during lf_expr_postcheck(), if
needed, we rely on curpx->conf.args.{file,line} hints for that because
parse_logformat_string() doesn't know about current file and line
number.
- lf_expr_postcheck() uses PR_FL_CHECKED proxy flag to know if the
function may try to make the proxy compatible with the expression, or
if it should simply fail as soon as an incompatibility is detected.
- if parse_logformat_string() is called from an unchecked proxy, then
schedule the expression for postparsing, else (ie: during runtime),
run the postcheck right away.
This change will also allow for some logformat expression error handling
simplifications in the future.
2024-02-23 11:26:32 -05:00
/* add the lf_expr to the proxy checks to delay postparsing
* since config - related proxy properties are not stable yet
*/
LIST_APPEND ( & curproxy - > conf . lf_checks , & lf_expr - > list ) ;
}
else {
2024-06-11 04:15:36 -04:00
/* default proxy, or regular proxy and probably called during
* runtime or with proxy already checked , perform the postcheck
* right away
MAJOR: log: implement proper postparsing for logformat expressions
This patch tries to address a design flaw with how logformat expressions
are parsed from config. Indeed, some parse_logformat_string() calls are
performed during config parsing when the proxy mode is not yet known.
Here's a config example that illustrates the issue:
defaults
mode tcp
listen test
bind :8888
http-response set-header custom-hdr "%trl" # needs http
mode http
The above config should work, because the effective proxy mode is http,
yet haproxy fails with this error:
[ALERT] (99051) : config : parsing [repro.conf:6] : error detected in proxy 'test' while parsing 'http-response set-header' rule : format tag 'trl' is reserved for HTTP mode.
To fix the issue once and for all, let's implement smart postparsing for
logformat expressions encountered during config parsing:
- split parse_logformat_string() (and subfonctions) in order to create a
new lf_expr_postcheck() function that must be called to finish
preparing and checking the logformat expression once the proxy type is
known.
- save some config hints info during parse_logformat_string() to
generate more precise error messages during lf_expr_postcheck(), if
needed, we rely on curpx->conf.args.{file,line} hints for that because
parse_logformat_string() doesn't know about current file and line
number.
- lf_expr_postcheck() uses PR_FL_CHECKED proxy flag to know if the
function may try to make the proxy compatible with the expression, or
if it should simply fail as soon as an incompatibility is detected.
- if parse_logformat_string() is called from an unchecked proxy, then
schedule the expression for postparsing, else (ie: during runtime),
run the postcheck right away.
This change will also allow for some logformat expression error handling
simplifications in the future.
2024-02-23 11:26:32 -05:00
*/
if ( ! lf_expr_postcheck ( lf_expr , curproxy , err ) )
goto fail ;
}
return 1 ;
2024-02-29 08:54:43 -05:00
MAJOR: log: implement proper postparsing for logformat expressions
This patch tries to address a design flaw with how logformat expressions
are parsed from config. Indeed, some parse_logformat_string() calls are
performed during config parsing when the proxy mode is not yet known.
Here's a config example that illustrates the issue:
defaults
mode tcp
listen test
bind :8888
http-response set-header custom-hdr "%trl" # needs http
mode http
The above config should work, because the effective proxy mode is http,
yet haproxy fails with this error:
[ALERT] (99051) : config : parsing [repro.conf:6] : error detected in proxy 'test' while parsing 'http-response set-header' rule : format tag 'trl' is reserved for HTTP mode.
To fix the issue once and for all, let's implement smart postparsing for
logformat expressions encountered during config parsing:
- split parse_logformat_string() (and subfonctions) in order to create a
new lf_expr_postcheck() function that must be called to finish
preparing and checking the logformat expression once the proxy type is
known.
- save some config hints info during parse_logformat_string() to
generate more precise error messages during lf_expr_postcheck(), if
needed, we rely on curpx->conf.args.{file,line} hints for that because
parse_logformat_string() doesn't know about current file and line
number.
- lf_expr_postcheck() uses PR_FL_CHECKED proxy flag to know if the
function may try to make the proxy compatible with the expression, or
if it should simply fail as soon as an incompatibility is detected.
- if parse_logformat_string() is called from an unchecked proxy, then
schedule the expression for postparsing, else (ie: during runtime),
run the postcheck right away.
This change will also allow for some logformat expression error handling
simplifications in the future.
2024-02-23 11:26:32 -05:00
fail :
2024-02-29 08:54:43 -05:00
lf_expr_deinit ( lf_expr ) ;
MAJOR: log: implement proper postparsing for logformat expressions
This patch tries to address a design flaw with how logformat expressions
are parsed from config. Indeed, some parse_logformat_string() calls are
performed during config parsing when the proxy mode is not yet known.
Here's a config example that illustrates the issue:
defaults
mode tcp
listen test
bind :8888
http-response set-header custom-hdr "%trl" # needs http
mode http
The above config should work, because the effective proxy mode is http,
yet haproxy fails with this error:
[ALERT] (99051) : config : parsing [repro.conf:6] : error detected in proxy 'test' while parsing 'http-response set-header' rule : format tag 'trl' is reserved for HTTP mode.
To fix the issue once and for all, let's implement smart postparsing for
logformat expressions encountered during config parsing:
- split parse_logformat_string() (and subfonctions) in order to create a
new lf_expr_postcheck() function that must be called to finish
preparing and checking the logformat expression once the proxy type is
known.
- save some config hints info during parse_logformat_string() to
generate more precise error messages during lf_expr_postcheck(), if
needed, we rely on curpx->conf.args.{file,line} hints for that because
parse_logformat_string() doesn't know about current file and line
number.
- lf_expr_postcheck() uses PR_FL_CHECKED proxy flag to know if the
function may try to make the proxy compatible with the expression, or
if it should simply fail as soon as an incompatibility is detected.
- if parse_logformat_string() is called from an unchecked proxy, then
schedule the expression for postparsing, else (ie: during runtime),
run the postcheck right away.
This change will also allow for some logformat expression error handling
simplifications in the future.
2024-02-23 11:26:32 -05:00
return 0 ;
}
2024-04-30 11:42:00 -04:00
/* automatically resolves incompatible LOG_OPT options by taking into
* account current options and global options
*/
static inline void _lf_expr_postcheck_node_opt ( int * options , int g_options )
{
/* encoding is incompatible with HTTP option, so it is ignored
* if HTTP option is set , unless HTTP option wasn ' t set globally
* and encoding was set globally , which means encoding takes the
* precedence >
*/
if ( * options & LOG_OPT_HTTP ) {
if ( ( g_options & ( LOG_OPT_HTTP | LOG_OPT_ENCODE ) ) = = LOG_OPT_ENCODE ) {
/* global encoding enabled and http enabled individually */
* options & = ~ LOG_OPT_HTTP ;
}
else
* options & = ~ LOG_OPT_ENCODE ;
}
if ( * options & LOG_OPT_ENCODE ) {
/* when encoding is set, ignore +E option */
* options & = ~ LOG_OPT_ESC ;
}
}
/* Performs LOG_OPT postparsing check on logformat node <node> belonging to a
* given logformat expression < lf_expr >
*
* It returns 1 on success and 0 on error , < err > will be set in case of error
*/
static int lf_expr_postcheck_node_opt ( struct lf_expr * lf_expr , struct logformat_node * node , char * * err )
{
/* per-node encoding options cannot be disabled if already
* enabled globally
*
* Also , ensure we don ' t mix encoding types , global setting
* prevails over per - node one .
*
* Finally , ignore LOG_OPT_BIN since it is a global - only option
*/
if ( lf_expr - > nodes . options & LOG_OPT_ENCODE ) {
node - > options & = ~ ( LOG_OPT_BIN | LOG_OPT_ENCODE ) ;
node - > options | = ( lf_expr - > nodes . options & LOG_OPT_ENCODE ) ;
}
else
node - > options & = ~ LOG_OPT_BIN ;
_lf_expr_postcheck_node_opt ( & node - > options , lf_expr - > nodes . options ) ;
return 1 ;
}
MAJOR: log: implement proper postparsing for logformat expressions
This patch tries to address a design flaw with how logformat expressions
are parsed from config. Indeed, some parse_logformat_string() calls are
performed during config parsing when the proxy mode is not yet known.
Here's a config example that illustrates the issue:
defaults
mode tcp
listen test
bind :8888
http-response set-header custom-hdr "%trl" # needs http
mode http
The above config should work, because the effective proxy mode is http,
yet haproxy fails with this error:
[ALERT] (99051) : config : parsing [repro.conf:6] : error detected in proxy 'test' while parsing 'http-response set-header' rule : format tag 'trl' is reserved for HTTP mode.
To fix the issue once and for all, let's implement smart postparsing for
logformat expressions encountered during config parsing:
- split parse_logformat_string() (and subfonctions) in order to create a
new lf_expr_postcheck() function that must be called to finish
preparing and checking the logformat expression once the proxy type is
known.
- save some config hints info during parse_logformat_string() to
generate more precise error messages during lf_expr_postcheck(), if
needed, we rely on curpx->conf.args.{file,line} hints for that because
parse_logformat_string() doesn't know about current file and line
number.
- lf_expr_postcheck() uses PR_FL_CHECKED proxy flag to know if the
function may try to make the proxy compatible with the expression, or
if it should simply fail as soon as an incompatibility is detected.
- if parse_logformat_string() is called from an unchecked proxy, then
schedule the expression for postparsing, else (ie: during runtime),
run the postcheck right away.
This change will also allow for some logformat expression error handling
simplifications in the future.
2024-02-23 11:26:32 -05:00
/* Performs a postparsing check on logformat expression <expr> for a given <px>
* proxy . The function will behave differently depending on the proxy state
* ( during parsing we will try to adapt proxy configuration to make it
* compatible with logformat expression , but once the proxy is checked , we fail
* as soon as we face incompatibilities )
*
2024-06-11 04:15:36 -04:00
* If the proxy is a default section , then allow the postcheck to succeed :
* the logformat expression may or may not work properly depending on the
* actual proxy that effectively runs it during runtime , but we have to stay
* permissive since we cannot assume it won ' t work .
*
MAJOR: log: implement proper postparsing for logformat expressions
This patch tries to address a design flaw with how logformat expressions
are parsed from config. Indeed, some parse_logformat_string() calls are
performed during config parsing when the proxy mode is not yet known.
Here's a config example that illustrates the issue:
defaults
mode tcp
listen test
bind :8888
http-response set-header custom-hdr "%trl" # needs http
mode http
The above config should work, because the effective proxy mode is http,
yet haproxy fails with this error:
[ALERT] (99051) : config : parsing [repro.conf:6] : error detected in proxy 'test' while parsing 'http-response set-header' rule : format tag 'trl' is reserved for HTTP mode.
To fix the issue once and for all, let's implement smart postparsing for
logformat expressions encountered during config parsing:
- split parse_logformat_string() (and subfonctions) in order to create a
new lf_expr_postcheck() function that must be called to finish
preparing and checking the logformat expression once the proxy type is
known.
- save some config hints info during parse_logformat_string() to
generate more precise error messages during lf_expr_postcheck(), if
needed, we rely on curpx->conf.args.{file,line} hints for that because
parse_logformat_string() doesn't know about current file and line
number.
- lf_expr_postcheck() uses PR_FL_CHECKED proxy flag to know if the
function may try to make the proxy compatible with the expression, or
if it should simply fail as soon as an incompatibility is detected.
- if parse_logformat_string() is called from an unchecked proxy, then
schedule the expression for postparsing, else (ie: during runtime),
run the postcheck right away.
This change will also allow for some logformat expression error handling
simplifications in the future.
2024-02-23 11:26:32 -05:00
* It returns 1 on success and 0 on error , < err > will be set in case of error .
*/
int lf_expr_postcheck ( struct lf_expr * lf_expr , struct proxy * px , char * * err )
{
struct logformat_node * lf ;
2024-06-11 04:15:36 -04:00
int default_px = ( px - > cap & PR_CAP_DEF ) ;
MAJOR: log: implement proper postparsing for logformat expressions
This patch tries to address a design flaw with how logformat expressions
are parsed from config. Indeed, some parse_logformat_string() calls are
performed during config parsing when the proxy mode is not yet known.
Here's a config example that illustrates the issue:
defaults
mode tcp
listen test
bind :8888
http-response set-header custom-hdr "%trl" # needs http
mode http
The above config should work, because the effective proxy mode is http,
yet haproxy fails with this error:
[ALERT] (99051) : config : parsing [repro.conf:6] : error detected in proxy 'test' while parsing 'http-response set-header' rule : format tag 'trl' is reserved for HTTP mode.
To fix the issue once and for all, let's implement smart postparsing for
logformat expressions encountered during config parsing:
- split parse_logformat_string() (and subfonctions) in order to create a
new lf_expr_postcheck() function that must be called to finish
preparing and checking the logformat expression once the proxy type is
known.
- save some config hints info during parse_logformat_string() to
generate more precise error messages during lf_expr_postcheck(), if
needed, we rely on curpx->conf.args.{file,line} hints for that because
parse_logformat_string() doesn't know about current file and line
number.
- lf_expr_postcheck() uses PR_FL_CHECKED proxy flag to know if the
function may try to make the proxy compatible with the expression, or
if it should simply fail as soon as an incompatibility is detected.
- if parse_logformat_string() is called from an unchecked proxy, then
schedule the expression for postparsing, else (ie: during runtime),
run the postcheck right away.
This change will also allow for some logformat expression error handling
simplifications in the future.
2024-02-23 11:26:32 -05:00
if ( ! ( px - > flags & PR_FL_CHECKED ) )
px - > to_log | = LW_INIT ;
2024-04-30 11:42:00 -04:00
/* postcheck global node options */
_lf_expr_postcheck_node_opt ( & lf_expr - > nodes . options , LOG_OPT_NONE ) ;
2024-03-25 06:29:58 -04:00
list_for_each_entry ( lf , & lf_expr - > nodes . list , list ) {
MAJOR: log: implement proper postparsing for logformat expressions
This patch tries to address a design flaw with how logformat expressions
are parsed from config. Indeed, some parse_logformat_string() calls are
performed during config parsing when the proxy mode is not yet known.
Here's a config example that illustrates the issue:
defaults
mode tcp
listen test
bind :8888
http-response set-header custom-hdr "%trl" # needs http
mode http
The above config should work, because the effective proxy mode is http,
yet haproxy fails with this error:
[ALERT] (99051) : config : parsing [repro.conf:6] : error detected in proxy 'test' while parsing 'http-response set-header' rule : format tag 'trl' is reserved for HTTP mode.
To fix the issue once and for all, let's implement smart postparsing for
logformat expressions encountered during config parsing:
- split parse_logformat_string() (and subfonctions) in order to create a
new lf_expr_postcheck() function that must be called to finish
preparing and checking the logformat expression once the proxy type is
known.
- save some config hints info during parse_logformat_string() to
generate more precise error messages during lf_expr_postcheck(), if
needed, we rely on curpx->conf.args.{file,line} hints for that because
parse_logformat_string() doesn't know about current file and line
number.
- lf_expr_postcheck() uses PR_FL_CHECKED proxy flag to know if the
function may try to make the proxy compatible with the expression, or
if it should simply fail as soon as an incompatibility is detected.
- if parse_logformat_string() is called from an unchecked proxy, then
schedule the expression for postparsing, else (ie: during runtime),
run the postcheck right away.
This change will also allow for some logformat expression error handling
simplifications in the future.
2024-02-23 11:26:32 -05:00
if ( lf - > type = = LOG_FMT_EXPR ) {
struct sample_expr * expr = lf - > expr ;
uint8_t http_needed = ! ! ( expr - > fetch - > use & SMP_USE_HTTP_ANY ) ;
if ( ( px - > flags & PR_FL_CHECKED ) ) {
/* fail as soon as proxy properties are not compatible */
if ( http_needed & & ! px - > http_needed ) {
memprintf ( err , " sample fetch '%s' requires HTTP enabled proxy which is not available here " ,
expr - > fetch - > kw ) ;
goto fail ;
}
2024-04-30 11:42:00 -04:00
goto next_node ;
MAJOR: log: implement proper postparsing for logformat expressions
This patch tries to address a design flaw with how logformat expressions
are parsed from config. Indeed, some parse_logformat_string() calls are
performed during config parsing when the proxy mode is not yet known.
Here's a config example that illustrates the issue:
defaults
mode tcp
listen test
bind :8888
http-response set-header custom-hdr "%trl" # needs http
mode http
The above config should work, because the effective proxy mode is http,
yet haproxy fails with this error:
[ALERT] (99051) : config : parsing [repro.conf:6] : error detected in proxy 'test' while parsing 'http-response set-header' rule : format tag 'trl' is reserved for HTTP mode.
To fix the issue once and for all, let's implement smart postparsing for
logformat expressions encountered during config parsing:
- split parse_logformat_string() (and subfonctions) in order to create a
new lf_expr_postcheck() function that must be called to finish
preparing and checking the logformat expression once the proxy type is
known.
- save some config hints info during parse_logformat_string() to
generate more precise error messages during lf_expr_postcheck(), if
needed, we rely on curpx->conf.args.{file,line} hints for that because
parse_logformat_string() doesn't know about current file and line
number.
- lf_expr_postcheck() uses PR_FL_CHECKED proxy flag to know if the
function may try to make the proxy compatible with the expression, or
if it should simply fail as soon as an incompatibility is detected.
- if parse_logformat_string() is called from an unchecked proxy, then
schedule the expression for postparsing, else (ie: during runtime),
run the postcheck right away.
This change will also allow for some logformat expression error handling
simplifications in the future.
2024-02-23 11:26:32 -05:00
}
/* check if we need to allocate an http_txn struct for HTTP parsing */
/* Note, we may also need to set curpx->to_log with certain fetches */
px - > http_needed | = http_needed ;
/* FIXME: temporary workaround for missing LW_XPRT and LW_REQ flags
* needed with some sample fetches ( eg : ssl * ) . We always set it for
* now on , but this will leave with sample capabilities soon .
*/
px - > to_log | = LW_XPRT ;
if ( px - > http_needed )
px - > to_log | = LW_REQ ;
}
MINOR: log: rename 'log-format tag' to 'log-format alias'
In 2.9 we started to introduce an ambiguity in the documentation by
referring to historical log-format variables ('%var') as log-format
tags in 739c4e5b1e ("MINOR: sample: accept_date / request_date return
%Ts / %tr timestamp values") and 454c372b60 ("DOC: configuration: add
sample fetches for timing events").
In fact, we've had this confusion between log-format tag and log-format
var for more than 10 years now, but in 2.9 it was the first time the
confusion was exposed in the documentation.
Indeed, both 'log-format variable' and 'log-format tag' actually refer
to the same feature (that is: '%B' and friends that can be used for
direct access to some log-oriented predefined fetches instead of using
%[expr] with generic sample expressions).
This feature was first implemented in 723b73ad75 ("MINOR: config: Parse
the string of the log-format config keyword") and later documented in
4894040fa ("DOC: log-format documentation"). At that time, it was clear
that we used to name it 'log-format variable'.
But later the same year, 'log-format tag' naming started to appear in
some commit messages (while still referring to the same feature), for
instance with ffc3fcd6d ("MEDIUM: log: report SSL ciphers and version
in logs using logformat %sslc/%sslv").
Unfortunately in 2.9 when we added (and documented) new log-format
variables we officially started drifting to the misleading 'log-format
tag' naming (perhaps because it was the most recent naming found for
this feature in git log history, or because the confusion has always
been there)
Even worse, in 3.0 this confusion led us to rename all 'var' occurrences
to 'tag' in log-format related code to unify the code with the doc.
Hopefully William quickly noticed that we made a mistake there, but
instead of reverting to historical naming (log-format variable), it was
decided that we must use a different name that is less confusing than
'tags' or 'variables' (tags and variables are keywords that are already
used to designate other features in the code and that are not very
explicit under log-format context today).
Now we refer to '%B' and friends as a logformat alias, which is
essentially a handy way to print some log oriented information in the
log string instead of leveraging '%[expr]' with generic sample expressions
made of fetches and converters. Of course, there are some subtelties, such
as a few log-format aliases that still don't have sample fetch equivalent
for historical reasons, and some aliases that may be a little faster than
their generic sample expression equivalents because most aliases are
pretty much hardcoded in the log building function. But in general
logformat aliases should be simply considered as an alternative to using
expressions (with '%[expr']')
Also, under log-format context, when we want to refer to either an alias
('%alias') or an expression ('%[expr]'), we should use the generic term
'logformat item', which in fact designates a single item within the
logformat string provided by the user. Indeed, a logformat item (whether
is is an alias or an expression) always starts with '%' and may accept
optional flags / arguments
Both the code and the documentation were updated in that sense, hopefully
this will clarify things and prevent future confusions.
2024-05-27 04:18:10 -04:00
else if ( lf - > type = = LOG_FMT_ALIAS ) {
2024-06-11 04:15:36 -04:00
if ( lf - > alias - > mode = = PR_MODE_HTTP & &
! default_px & & px - > mode ! = PR_MODE_HTTP ) {
MINOR: log: rename 'log-format tag' to 'log-format alias'
In 2.9 we started to introduce an ambiguity in the documentation by
referring to historical log-format variables ('%var') as log-format
tags in 739c4e5b1e ("MINOR: sample: accept_date / request_date return
%Ts / %tr timestamp values") and 454c372b60 ("DOC: configuration: add
sample fetches for timing events").
In fact, we've had this confusion between log-format tag and log-format
var for more than 10 years now, but in 2.9 it was the first time the
confusion was exposed in the documentation.
Indeed, both 'log-format variable' and 'log-format tag' actually refer
to the same feature (that is: '%B' and friends that can be used for
direct access to some log-oriented predefined fetches instead of using
%[expr] with generic sample expressions).
This feature was first implemented in 723b73ad75 ("MINOR: config: Parse
the string of the log-format config keyword") and later documented in
4894040fa ("DOC: log-format documentation"). At that time, it was clear
that we used to name it 'log-format variable'.
But later the same year, 'log-format tag' naming started to appear in
some commit messages (while still referring to the same feature), for
instance with ffc3fcd6d ("MEDIUM: log: report SSL ciphers and version
in logs using logformat %sslc/%sslv").
Unfortunately in 2.9 when we added (and documented) new log-format
variables we officially started drifting to the misleading 'log-format
tag' naming (perhaps because it was the most recent naming found for
this feature in git log history, or because the confusion has always
been there)
Even worse, in 3.0 this confusion led us to rename all 'var' occurrences
to 'tag' in log-format related code to unify the code with the doc.
Hopefully William quickly noticed that we made a mistake there, but
instead of reverting to historical naming (log-format variable), it was
decided that we must use a different name that is less confusing than
'tags' or 'variables' (tags and variables are keywords that are already
used to designate other features in the code and that are not very
explicit under log-format context today).
Now we refer to '%B' and friends as a logformat alias, which is
essentially a handy way to print some log oriented information in the
log string instead of leveraging '%[expr]' with generic sample expressions
made of fetches and converters. Of course, there are some subtelties, such
as a few log-format aliases that still don't have sample fetch equivalent
for historical reasons, and some aliases that may be a little faster than
their generic sample expression equivalents because most aliases are
pretty much hardcoded in the log building function. But in general
logformat aliases should be simply considered as an alternative to using
expressions (with '%[expr']')
Also, under log-format context, when we want to refer to either an alias
('%alias') or an expression ('%[expr]'), we should use the generic term
'logformat item', which in fact designates a single item within the
logformat string provided by the user. Indeed, a logformat item (whether
is is an alias or an expression) always starts with '%' and may accept
optional flags / arguments
Both the code and the documentation were updated in that sense, hopefully
this will clarify things and prevent future confusions.
2024-05-27 04:18:10 -04:00
memprintf ( err , " format alias '%s' is reserved for HTTP mode " ,
lf - > alias - > name ) ;
MAJOR: log: implement proper postparsing for logformat expressions
This patch tries to address a design flaw with how logformat expressions
are parsed from config. Indeed, some parse_logformat_string() calls are
performed during config parsing when the proxy mode is not yet known.
Here's a config example that illustrates the issue:
defaults
mode tcp
listen test
bind :8888
http-response set-header custom-hdr "%trl" # needs http
mode http
The above config should work, because the effective proxy mode is http,
yet haproxy fails with this error:
[ALERT] (99051) : config : parsing [repro.conf:6] : error detected in proxy 'test' while parsing 'http-response set-header' rule : format tag 'trl' is reserved for HTTP mode.
To fix the issue once and for all, let's implement smart postparsing for
logformat expressions encountered during config parsing:
- split parse_logformat_string() (and subfonctions) in order to create a
new lf_expr_postcheck() function that must be called to finish
preparing and checking the logformat expression once the proxy type is
known.
- save some config hints info during parse_logformat_string() to
generate more precise error messages during lf_expr_postcheck(), if
needed, we rely on curpx->conf.args.{file,line} hints for that because
parse_logformat_string() doesn't know about current file and line
number.
- lf_expr_postcheck() uses PR_FL_CHECKED proxy flag to know if the
function may try to make the proxy compatible with the expression, or
if it should simply fail as soon as an incompatibility is detected.
- if parse_logformat_string() is called from an unchecked proxy, then
schedule the expression for postparsing, else (ie: during runtime),
run the postcheck right away.
This change will also allow for some logformat expression error handling
simplifications in the future.
2024-02-23 11:26:32 -05:00
goto fail ;
}
MINOR: log: rename 'log-format tag' to 'log-format alias'
In 2.9 we started to introduce an ambiguity in the documentation by
referring to historical log-format variables ('%var') as log-format
tags in 739c4e5b1e ("MINOR: sample: accept_date / request_date return
%Ts / %tr timestamp values") and 454c372b60 ("DOC: configuration: add
sample fetches for timing events").
In fact, we've had this confusion between log-format tag and log-format
var for more than 10 years now, but in 2.9 it was the first time the
confusion was exposed in the documentation.
Indeed, both 'log-format variable' and 'log-format tag' actually refer
to the same feature (that is: '%B' and friends that can be used for
direct access to some log-oriented predefined fetches instead of using
%[expr] with generic sample expressions).
This feature was first implemented in 723b73ad75 ("MINOR: config: Parse
the string of the log-format config keyword") and later documented in
4894040fa ("DOC: log-format documentation"). At that time, it was clear
that we used to name it 'log-format variable'.
But later the same year, 'log-format tag' naming started to appear in
some commit messages (while still referring to the same feature), for
instance with ffc3fcd6d ("MEDIUM: log: report SSL ciphers and version
in logs using logformat %sslc/%sslv").
Unfortunately in 2.9 when we added (and documented) new log-format
variables we officially started drifting to the misleading 'log-format
tag' naming (perhaps because it was the most recent naming found for
this feature in git log history, or because the confusion has always
been there)
Even worse, in 3.0 this confusion led us to rename all 'var' occurrences
to 'tag' in log-format related code to unify the code with the doc.
Hopefully William quickly noticed that we made a mistake there, but
instead of reverting to historical naming (log-format variable), it was
decided that we must use a different name that is less confusing than
'tags' or 'variables' (tags and variables are keywords that are already
used to designate other features in the code and that are not very
explicit under log-format context today).
Now we refer to '%B' and friends as a logformat alias, which is
essentially a handy way to print some log oriented information in the
log string instead of leveraging '%[expr]' with generic sample expressions
made of fetches and converters. Of course, there are some subtelties, such
as a few log-format aliases that still don't have sample fetch equivalent
for historical reasons, and some aliases that may be a little faster than
their generic sample expression equivalents because most aliases are
pretty much hardcoded in the log building function. But in general
logformat aliases should be simply considered as an alternative to using
expressions (with '%[expr']')
Also, under log-format context, when we want to refer to either an alias
('%alias') or an expression ('%[expr]'), we should use the generic term
'logformat item', which in fact designates a single item within the
logformat string provided by the user. Indeed, a logformat item (whether
is is an alias or an expression) always starts with '%' and may accept
optional flags / arguments
Both the code and the documentation were updated in that sense, hopefully
this will clarify things and prevent future confusions.
2024-05-27 04:18:10 -04:00
if ( lf - > alias - > config_callback & &
! lf - > alias - > config_callback ( lf , px ) ) {
memprintf ( err , " cannot configure format alias '%s' in this context " ,
lf - > alias - > name ) ;
MAJOR: log: implement proper postparsing for logformat expressions
This patch tries to address a design flaw with how logformat expressions
are parsed from config. Indeed, some parse_logformat_string() calls are
performed during config parsing when the proxy mode is not yet known.
Here's a config example that illustrates the issue:
defaults
mode tcp
listen test
bind :8888
http-response set-header custom-hdr "%trl" # needs http
mode http
The above config should work, because the effective proxy mode is http,
yet haproxy fails with this error:
[ALERT] (99051) : config : parsing [repro.conf:6] : error detected in proxy 'test' while parsing 'http-response set-header' rule : format tag 'trl' is reserved for HTTP mode.
To fix the issue once and for all, let's implement smart postparsing for
logformat expressions encountered during config parsing:
- split parse_logformat_string() (and subfonctions) in order to create a
new lf_expr_postcheck() function that must be called to finish
preparing and checking the logformat expression once the proxy type is
known.
- save some config hints info during parse_logformat_string() to
generate more precise error messages during lf_expr_postcheck(), if
needed, we rely on curpx->conf.args.{file,line} hints for that because
parse_logformat_string() doesn't know about current file and line
number.
- lf_expr_postcheck() uses PR_FL_CHECKED proxy flag to know if the
function may try to make the proxy compatible with the expression, or
if it should simply fail as soon as an incompatibility is detected.
- if parse_logformat_string() is called from an unchecked proxy, then
schedule the expression for postparsing, else (ie: during runtime),
run the postcheck right away.
This change will also allow for some logformat expression error handling
simplifications in the future.
2024-02-23 11:26:32 -05:00
goto fail ;
}
if ( ! ( px - > flags & PR_FL_CHECKED ) )
MINOR: log: rename 'log-format tag' to 'log-format alias'
In 2.9 we started to introduce an ambiguity in the documentation by
referring to historical log-format variables ('%var') as log-format
tags in 739c4e5b1e ("MINOR: sample: accept_date / request_date return
%Ts / %tr timestamp values") and 454c372b60 ("DOC: configuration: add
sample fetches for timing events").
In fact, we've had this confusion between log-format tag and log-format
var for more than 10 years now, but in 2.9 it was the first time the
confusion was exposed in the documentation.
Indeed, both 'log-format variable' and 'log-format tag' actually refer
to the same feature (that is: '%B' and friends that can be used for
direct access to some log-oriented predefined fetches instead of using
%[expr] with generic sample expressions).
This feature was first implemented in 723b73ad75 ("MINOR: config: Parse
the string of the log-format config keyword") and later documented in
4894040fa ("DOC: log-format documentation"). At that time, it was clear
that we used to name it 'log-format variable'.
But later the same year, 'log-format tag' naming started to appear in
some commit messages (while still referring to the same feature), for
instance with ffc3fcd6d ("MEDIUM: log: report SSL ciphers and version
in logs using logformat %sslc/%sslv").
Unfortunately in 2.9 when we added (and documented) new log-format
variables we officially started drifting to the misleading 'log-format
tag' naming (perhaps because it was the most recent naming found for
this feature in git log history, or because the confusion has always
been there)
Even worse, in 3.0 this confusion led us to rename all 'var' occurrences
to 'tag' in log-format related code to unify the code with the doc.
Hopefully William quickly noticed that we made a mistake there, but
instead of reverting to historical naming (log-format variable), it was
decided that we must use a different name that is less confusing than
'tags' or 'variables' (tags and variables are keywords that are already
used to designate other features in the code and that are not very
explicit under log-format context today).
Now we refer to '%B' and friends as a logformat alias, which is
essentially a handy way to print some log oriented information in the
log string instead of leveraging '%[expr]' with generic sample expressions
made of fetches and converters. Of course, there are some subtelties, such
as a few log-format aliases that still don't have sample fetch equivalent
for historical reasons, and some aliases that may be a little faster than
their generic sample expression equivalents because most aliases are
pretty much hardcoded in the log building function. But in general
logformat aliases should be simply considered as an alternative to using
expressions (with '%[expr']')
Also, under log-format context, when we want to refer to either an alias
('%alias') or an expression ('%[expr]'), we should use the generic term
'logformat item', which in fact designates a single item within the
logformat string provided by the user. Indeed, a logformat item (whether
is is an alias or an expression) always starts with '%' and may accept
optional flags / arguments
Both the code and the documentation were updated in that sense, hopefully
this will clarify things and prevent future confusions.
2024-05-27 04:18:10 -04:00
px - > to_log | = lf - > alias - > lw ;
MAJOR: log: implement proper postparsing for logformat expressions
This patch tries to address a design flaw with how logformat expressions
are parsed from config. Indeed, some parse_logformat_string() calls are
performed during config parsing when the proxy mode is not yet known.
Here's a config example that illustrates the issue:
defaults
mode tcp
listen test
bind :8888
http-response set-header custom-hdr "%trl" # needs http
mode http
The above config should work, because the effective proxy mode is http,
yet haproxy fails with this error:
[ALERT] (99051) : config : parsing [repro.conf:6] : error detected in proxy 'test' while parsing 'http-response set-header' rule : format tag 'trl' is reserved for HTTP mode.
To fix the issue once and for all, let's implement smart postparsing for
logformat expressions encountered during config parsing:
- split parse_logformat_string() (and subfonctions) in order to create a
new lf_expr_postcheck() function that must be called to finish
preparing and checking the logformat expression once the proxy type is
known.
- save some config hints info during parse_logformat_string() to
generate more precise error messages during lf_expr_postcheck(), if
needed, we rely on curpx->conf.args.{file,line} hints for that because
parse_logformat_string() doesn't know about current file and line
number.
- lf_expr_postcheck() uses PR_FL_CHECKED proxy flag to know if the
function may try to make the proxy compatible with the expression, or
if it should simply fail as soon as an incompatibility is detected.
- if parse_logformat_string() is called from an unchecked proxy, then
schedule the expression for postparsing, else (ie: during runtime),
run the postcheck right away.
This change will also allow for some logformat expression error handling
simplifications in the future.
2024-02-23 11:26:32 -05:00
}
2024-04-30 11:42:00 -04:00
next_node :
/* postcheck individual node's options */
if ( ! lf_expr_postcheck_node_opt ( lf_expr , lf , err ) )
goto fail ;
MAJOR: log: implement proper postparsing for logformat expressions
This patch tries to address a design flaw with how logformat expressions
are parsed from config. Indeed, some parse_logformat_string() calls are
performed during config parsing when the proxy mode is not yet known.
Here's a config example that illustrates the issue:
defaults
mode tcp
listen test
bind :8888
http-response set-header custom-hdr "%trl" # needs http
mode http
The above config should work, because the effective proxy mode is http,
yet haproxy fails with this error:
[ALERT] (99051) : config : parsing [repro.conf:6] : error detected in proxy 'test' while parsing 'http-response set-header' rule : format tag 'trl' is reserved for HTTP mode.
To fix the issue once and for all, let's implement smart postparsing for
logformat expressions encountered during config parsing:
- split parse_logformat_string() (and subfonctions) in order to create a
new lf_expr_postcheck() function that must be called to finish
preparing and checking the logformat expression once the proxy type is
known.
- save some config hints info during parse_logformat_string() to
generate more precise error messages during lf_expr_postcheck(), if
needed, we rely on curpx->conf.args.{file,line} hints for that because
parse_logformat_string() doesn't know about current file and line
number.
- lf_expr_postcheck() uses PR_FL_CHECKED proxy flag to know if the
function may try to make the proxy compatible with the expression, or
if it should simply fail as soon as an incompatibility is detected.
- if parse_logformat_string() is called from an unchecked proxy, then
schedule the expression for postparsing, else (ie: during runtime),
run the postcheck right away.
This change will also allow for some logformat expression error handling
simplifications in the future.
2024-02-23 11:26:32 -05:00
}
2024-06-11 04:15:36 -04:00
if ( ! default_px & & ( px - > to_log & ( LW_REQ | LW_RESP ) ) & &
MAJOR: log: implement proper postparsing for logformat expressions
This patch tries to address a design flaw with how logformat expressions
are parsed from config. Indeed, some parse_logformat_string() calls are
performed during config parsing when the proxy mode is not yet known.
Here's a config example that illustrates the issue:
defaults
mode tcp
listen test
bind :8888
http-response set-header custom-hdr "%trl" # needs http
mode http
The above config should work, because the effective proxy mode is http,
yet haproxy fails with this error:
[ALERT] (99051) : config : parsing [repro.conf:6] : error detected in proxy 'test' while parsing 'http-response set-header' rule : format tag 'trl' is reserved for HTTP mode.
To fix the issue once and for all, let's implement smart postparsing for
logformat expressions encountered during config parsing:
- split parse_logformat_string() (and subfonctions) in order to create a
new lf_expr_postcheck() function that must be called to finish
preparing and checking the logformat expression once the proxy type is
known.
- save some config hints info during parse_logformat_string() to
generate more precise error messages during lf_expr_postcheck(), if
needed, we rely on curpx->conf.args.{file,line} hints for that because
parse_logformat_string() doesn't know about current file and line
number.
- lf_expr_postcheck() uses PR_FL_CHECKED proxy flag to know if the
function may try to make the proxy compatible with the expression, or
if it should simply fail as soon as an incompatibility is detected.
- if parse_logformat_string() is called from an unchecked proxy, then
schedule the expression for postparsing, else (ie: during runtime),
run the postcheck right away.
This change will also allow for some logformat expression error handling
simplifications in the future.
2024-02-23 11:26:32 -05:00
( px - > mode ! = PR_MODE_HTTP & & ! ( px - > options & PR_O_HTTP_UPG ) ) ) {
2024-06-11 03:31:26 -04:00
memprintf ( err , " logformat expression not usable here (at least one item depends on HTTP mode) " ) ;
MAJOR: log: implement proper postparsing for logformat expressions
This patch tries to address a design flaw with how logformat expressions
are parsed from config. Indeed, some parse_logformat_string() calls are
performed during config parsing when the proxy mode is not yet known.
Here's a config example that illustrates the issue:
defaults
mode tcp
listen test
bind :8888
http-response set-header custom-hdr "%trl" # needs http
mode http
The above config should work, because the effective proxy mode is http,
yet haproxy fails with this error:
[ALERT] (99051) : config : parsing [repro.conf:6] : error detected in proxy 'test' while parsing 'http-response set-header' rule : format tag 'trl' is reserved for HTTP mode.
To fix the issue once and for all, let's implement smart postparsing for
logformat expressions encountered during config parsing:
- split parse_logformat_string() (and subfonctions) in order to create a
new lf_expr_postcheck() function that must be called to finish
preparing and checking the logformat expression once the proxy type is
known.
- save some config hints info during parse_logformat_string() to
generate more precise error messages during lf_expr_postcheck(), if
needed, we rely on curpx->conf.args.{file,line} hints for that because
parse_logformat_string() doesn't know about current file and line
number.
- lf_expr_postcheck() uses PR_FL_CHECKED proxy flag to know if the
function may try to make the proxy compatible with the expression, or
if it should simply fail as soon as an incompatibility is detected.
- if parse_logformat_string() is called from an unchecked proxy, then
schedule the expression for postparsing, else (ie: during runtime),
run the postcheck right away.
This change will also allow for some logformat expression error handling
simplifications in the future.
2024-02-23 11:26:32 -05:00
goto fail ;
}
2016-11-22 17:11:21 -05:00
return 1 ;
2019-12-11 06:05:39 -05:00
fail :
return 0 ;
2012-02-08 10:37:49 -05:00
}
MAJOR: log: implement proper postparsing for logformat expressions
This patch tries to address a design flaw with how logformat expressions
are parsed from config. Indeed, some parse_logformat_string() calls are
performed during config parsing when the proxy mode is not yet known.
Here's a config example that illustrates the issue:
defaults
mode tcp
listen test
bind :8888
http-response set-header custom-hdr "%trl" # needs http
mode http
The above config should work, because the effective proxy mode is http,
yet haproxy fails with this error:
[ALERT] (99051) : config : parsing [repro.conf:6] : error detected in proxy 'test' while parsing 'http-response set-header' rule : format tag 'trl' is reserved for HTTP mode.
To fix the issue once and for all, let's implement smart postparsing for
logformat expressions encountered during config parsing:
- split parse_logformat_string() (and subfonctions) in order to create a
new lf_expr_postcheck() function that must be called to finish
preparing and checking the logformat expression once the proxy type is
known.
- save some config hints info during parse_logformat_string() to
generate more precise error messages during lf_expr_postcheck(), if
needed, we rely on curpx->conf.args.{file,line} hints for that because
parse_logformat_string() doesn't know about current file and line
number.
- lf_expr_postcheck() uses PR_FL_CHECKED proxy flag to know if the
function may try to make the proxy compatible with the expression, or
if it should simply fail as soon as an incompatibility is detected.
- if parse_logformat_string() is called from an unchecked proxy, then
schedule the expression for postparsing, else (ie: during runtime),
run the postcheck right away.
This change will also allow for some logformat expression error handling
simplifications in the future.
2024-02-23 11:26:32 -05:00
/* postparse logformats defined at <px> level */
static int postcheck_logformat_proxy ( struct proxy * px )
{
char * err = NULL ;
struct lf_expr * lf_expr , * back_lf ;
int err_code = ERR_NONE ;
list_for_each_entry_safe ( lf_expr , back_lf , & px - > conf . lf_checks , list ) {
2024-02-29 08:54:43 -05:00
BUG_ON ( ! ( lf_expr - > flags & LF_FL_COMPILED ) ) ;
MAJOR: log: implement proper postparsing for logformat expressions
This patch tries to address a design flaw with how logformat expressions
are parsed from config. Indeed, some parse_logformat_string() calls are
performed during config parsing when the proxy mode is not yet known.
Here's a config example that illustrates the issue:
defaults
mode tcp
listen test
bind :8888
http-response set-header custom-hdr "%trl" # needs http
mode http
The above config should work, because the effective proxy mode is http,
yet haproxy fails with this error:
[ALERT] (99051) : config : parsing [repro.conf:6] : error detected in proxy 'test' while parsing 'http-response set-header' rule : format tag 'trl' is reserved for HTTP mode.
To fix the issue once and for all, let's implement smart postparsing for
logformat expressions encountered during config parsing:
- split parse_logformat_string() (and subfonctions) in order to create a
new lf_expr_postcheck() function that must be called to finish
preparing and checking the logformat expression once the proxy type is
known.
- save some config hints info during parse_logformat_string() to
generate more precise error messages during lf_expr_postcheck(), if
needed, we rely on curpx->conf.args.{file,line} hints for that because
parse_logformat_string() doesn't know about current file and line
number.
- lf_expr_postcheck() uses PR_FL_CHECKED proxy flag to know if the
function may try to make the proxy compatible with the expression, or
if it should simply fail as soon as an incompatibility is detected.
- if parse_logformat_string() is called from an unchecked proxy, then
schedule the expression for postparsing, else (ie: during runtime),
run the postcheck right away.
This change will also allow for some logformat expression error handling
simplifications in the future.
2024-02-23 11:26:32 -05:00
if ( ! lf_expr_postcheck ( lf_expr , px , & err ) )
err_code | = ERR_FATAL | ERR_ALERT ;
/* check performed, ensure it doesn't get checked twice */
LIST_DEL_INIT ( & lf_expr - > list ) ;
if ( err_code & ERR_CODE )
break ;
}
if ( err ) {
memprintf ( & err , " error detected while postparsing logformat expression used by %s '%s' : %s " , proxy_type_str ( px ) , px - > id , err ) ;
if ( lf_expr - > conf . file )
memprintf ( & err , " parsing [%s:%d] : %s. \n " , lf_expr - > conf . file , lf_expr - > conf . line , err ) ;
ha_alert ( " %s " , err ) ;
ha_free ( & err ) ;
}
return err_code ;
}
2019-04-24 10:14:33 -04:00
/*
2020-04-16 14:51:34 -04:00
* Parse the first range of indexes from a string made of a list of comma separated
2019-04-24 10:14:33 -04:00
* ranges of indexes . Note that an index may be considered as a particular range
* with a high limit to the low limit .
*/
MEDIUM: tree-wide: logsrv struct becomes logger
When 'log' directive was implemented, the internal representation was
named 'struct logsrv', because the 'log' directive would directly point
to the log target, which used to be a (UDP) log server exclusively at
that time, hence the name.
But things have become more complex, since today 'log' directive can point
to ring targets (implicit, or named) for example.
Indeed, a 'log' directive does no longer reference the "final" server to
which the log will be sent, but instead it describes which log API and
parameters to use for transporting the log messages to the proper log
destination.
So now the term 'logsrv' is rather confusing and prevents us from
introducing a new level of abstraction because they would be mixed
with logsrv.
So in order to better designate this 'log' directive, and make it more
generic, we chose the word 'logger' which now replaces logsrv everywhere
it was used in the code (including related comments).
This is internal rewording, so no functional change should be expected
on user-side.
2023-09-11 09:06:53 -04:00
int get_logger_smp_range ( unsigned int * low , unsigned int * high , char * * arg , char * * err )
2019-04-24 10:14:33 -04:00
{
char * end , * p ;
* low = * high = 0 ;
p = * arg ;
end = strchr ( p , ' , ' ) ;
if ( ! end )
end = p + strlen ( p ) ;
* high = * low = read_uint ( ( const char * * ) & p , end ) ;
if ( ! * low | | ( p ! = end & & * p ! = ' - ' ) )
goto err ;
if ( p = = end )
goto done ;
p + + ;
* high = read_uint ( ( const char * * ) & p , end ) ;
if ( ! * high | | * high < = * low | | p ! = end )
goto err ;
done :
if ( * end = = ' , ' )
end + + ;
* arg = end ;
return 1 ;
err :
memprintf ( err , " wrong sample range '%s' " , * arg ) ;
return 0 ;
}
/*
* Returns 1 if the range defined by < low > and < high > overlaps
* one of them in < rgs > array of ranges with < sz > the size of this
* array , 0 if not .
*/
int smp_log_ranges_overlap ( struct smp_log_range * rgs , size_t sz ,
unsigned int low , unsigned int high , char * * err )
{
size_t i ;
for ( i = 0 ; i < sz ; i + + ) {
if ( ( low > = rgs [ i ] . low & & low < = rgs [ i ] . high ) | |
( high > = rgs [ i ] . low & & high < = rgs [ i ] . high ) ) {
memprintf ( err , " ranges are overlapping " ) ;
return 1 ;
}
}
return 0 ;
}
int smp_log_range_cmp ( const void * a , const void * b )
{
const struct smp_log_range * rg_a = a ;
const struct smp_log_range * rg_b = b ;
if ( rg_a - > high < rg_b - > low )
return - 1 ;
else if ( rg_a - > low > rg_b - > high )
return 1 ;
return 0 ;
}
2023-09-11 10:10:37 -04:00
/* helper func */
static inline void init_log_target ( struct log_target * target )
{
target - > type = 0 ;
target - > flags = LOG_TARGET_FL_NONE ;
target - > addr = NULL ;
2023-09-13 05:52:31 -04:00
target - > resolv_name = NULL ;
2023-09-11 10:10:37 -04:00
}
2023-11-09 10:57:01 -05:00
void deinit_log_target ( struct log_target * target )
2023-09-11 10:10:37 -04:00
{
ha_free ( & target - > addr ) ;
if ( ! ( target - > flags & LOG_TARGET_FL_RESOLVED ) )
2023-09-13 05:52:31 -04:00
ha_free ( & target - > resolv_name ) ;
2023-09-11 10:10:37 -04:00
}
/* returns 0 on failure and positive value on success */
static int dup_log_target ( struct log_target * def , struct log_target * cpy )
{
BUG_ON ( ( def - > flags & LOG_TARGET_FL_RESOLVED ) ) ; /* postparsing already done, invalid use */
init_log_target ( cpy ) ;
2023-09-13 13:28:34 -04:00
if ( def - > addr ) {
cpy - > addr = malloc ( sizeof ( * cpy - > addr ) ) ;
if ( ! cpy - > addr )
goto error ;
* cpy - > addr = * def - > addr ;
}
2023-09-13 05:52:31 -04:00
if ( def - > resolv_name ) {
cpy - > resolv_name = strdup ( def - > resolv_name ) ;
if ( ! cpy - > resolv_name )
2023-09-11 10:10:37 -04:00
goto error ;
}
cpy - > type = def - > type ;
return 1 ;
error :
deinit_log_target ( cpy ) ;
return 0 ;
}
2023-11-16 04:48:34 -05:00
/* check that current configuration is compatible with "mode log" */
static int _postcheck_log_backend_compat ( struct proxy * be )
{
int err_code = ERR_NONE ;
2024-03-28 11:06:58 -04:00
int balance_algo = ( be - > lbprm . algo & BE_LB_ALGO ) ;
2023-11-16 04:48:34 -05:00
if ( ! LIST_ISEMPTY ( & be - > tcp_req . inspect_rules ) | |
! LIST_ISEMPTY ( & be - > tcp_req . l4_rules ) | |
! LIST_ISEMPTY ( & be - > tcp_req . l5_rules ) ) {
ha_warning ( " Cannot use tcp-request rules with 'mode log' in %s '%s'. They will be ignored. \n " ,
proxy_type_str ( be ) , be - > id ) ;
err_code | = ERR_WARN ;
free_act_rules ( & be - > tcp_req . inspect_rules ) ;
free_act_rules ( & be - > tcp_req . l4_rules ) ;
free_act_rules ( & be - > tcp_req . l5_rules ) ;
}
if ( ! LIST_ISEMPTY ( & be - > tcp_rep . inspect_rules ) ) {
ha_warning ( " Cannot use tcp-response rules with 'mode log' in %s '%s'. They will be ignored. \n " ,
proxy_type_str ( be ) , be - > id ) ;
err_code | = ERR_WARN ;
free_act_rules ( & be - > tcp_rep . inspect_rules ) ;
}
2023-11-16 05:29:58 -05:00
if ( be - > table ) {
ha_warning ( " Cannot use stick table with 'mode log' in %s '%s'. It will be ignored. \n " ,
proxy_type_str ( be ) , be - > id ) ;
err_code | = ERR_WARN ;
stktable_deinit ( be - > table ) ;
ha_free ( & be - > table ) ;
}
if ( ! LIST_ISEMPTY ( & be - > storersp_rules ) | |
! LIST_ISEMPTY ( & be - > sticking_rules ) ) {
ha_warning ( " Cannot use sticking rules with 'mode log' in %s '%s'. They will be ignored. \n " ,
proxy_type_str ( be ) , be - > id ) ;
err_code | = ERR_WARN ;
free_stick_rules ( & be - > storersp_rules ) ;
free_stick_rules ( & be - > sticking_rules ) ;
}
2023-11-16 11:11:37 -05:00
if ( isttest ( be - > server_id_hdr_name ) ) {
2024-06-10 12:11:49 -04:00
ha_warning ( " Cannot set \" http-send-name-header \" with 'mode log' in %s '%s'. It will be ignored. \n " ,
2023-11-16 11:11:37 -05:00
proxy_type_str ( be ) , be - > id ) ;
err_code | = ERR_WARN ;
istfree ( & be - > server_id_hdr_name ) ;
}
2023-11-16 11:16:43 -05:00
if ( be - > dyncookie_key ) {
ha_warning ( " Cannot set \" dynamic-cookie-key \" with 'mode log' in %s '%s'. It will be ignored. \n " ,
proxy_type_str ( be ) , be - > id ) ;
err_code | = ERR_WARN ;
ha_free ( & be - > dyncookie_key ) ;
}
2023-11-23 10:40:19 -05:00
if ( ! LIST_ISEMPTY ( & be - > server_rules ) ) {
ha_warning ( " Cannot use \" use-server \" rules with 'mode log' in %s '%s'. They will be ignored. \n " ,
proxy_type_str ( be ) , be - > id ) ;
err_code | = ERR_WARN ;
free_server_rules ( & be - > server_rules ) ;
}
2024-03-28 11:06:58 -04:00
if ( balance_algo ! = BE_LB_ALGO_RR & &
balance_algo ! = BE_LB_ALGO_RND & &
2024-03-28 12:24:53 -04:00
balance_algo ! = BE_LB_ALGO_SS & &
2024-03-28 11:06:58 -04:00
balance_algo ! = BE_LB_ALGO_LH ) {
2024-03-28 10:42:37 -04:00
/* cannot correct the error since lbprm init was already performed
* in cfgparse . c , so fail loudly
*/
2024-03-28 11:06:58 -04:00
ha_alert ( " in %s '%s': \" balance \" only supports 'roundrobin', 'random', 'sticky' and 'log-hash'. \n " , proxy_type_str ( be ) , be - > id ) ;
err_code | = ERR_ALERT | ERR_FATAL ;
}
2023-11-16 04:48:34 -05:00
return err_code ;
}
2023-09-13 05:52:31 -04:00
static int postcheck_log_backend ( struct proxy * be )
{
char * msg = NULL ;
struct server * srv ;
int err_code = ERR_NONE ;
int target_type = - 1 ; // -1 is unused in log_tgt enum
if ( be - > mode ! = PR_MODE_SYSLOG | |
( be - > flags & ( PR_FL_DISABLED | PR_FL_STOPPED ) ) )
return ERR_NONE ; /* nothing to do */
2023-11-16 04:48:34 -05:00
err_code | = _postcheck_log_backend_compat ( be ) ;
if ( err_code & ERR_CODE )
return err_code ;
2023-09-19 04:51:53 -04:00
/* "log-balance hash" needs to compile its expression */
2023-11-15 05:15:50 -05:00
if ( ( be - > lbprm . algo & BE_LB_ALGO ) = = BE_LB_ALGO_LH ) {
2023-09-19 04:51:53 -04:00
struct sample_expr * expr ;
char * expr_str = NULL ;
char * err_str = NULL ;
int idx = 0 ;
/* only map-based hash method is supported for now */
if ( ( be - > lbprm . algo & BE_LB_HASH_TYPE ) ! = BE_LB_HASH_MAP ) {
memprintf ( & msg , " unsupported hash method (from \" hash-type \" ) " ) ;
err_code | = ERR_ALERT | ERR_FATAL ;
goto end ;
}
/* a little bit of explanation about what we're going to do here:
* as the user gave us a list of converters , instead of the fetch + conv list
* tuple as we ' re used to , we need to insert a dummy fetch at the start of
* the converter list so that sample_parse_expr ( ) is able to properly parse
* the expr . We ' re explicitly using str ( ) as dummy fetch , since the input
* sample that will be passed to the converter list at runtime will be a
* string ( the log message about to be sent ) . Doing so allows sample_parse_expr ( )
* to ensure that the provided converters will be compatible with string type .
*/
memprintf ( & expr_str , " str(dummy),%s " , be - > lbprm . arg_str ) ;
if ( ! expr_str ) {
memprintf ( & msg , " memory error during converter list argument parsing (from \" log-balance hash \" ) " ) ;
err_code | = ERR_ALERT | ERR_FATAL ;
goto end ;
}
expr = sample_parse_expr ( ( char * [ ] ) { expr_str , NULL } , & idx ,
be - > conf . file ,
be - > conf . line ,
& err_str , NULL , NULL ) ;
if ( ! expr ) {
memprintf ( & msg , " %s (from converter list argument in \" log-balance hash \" ) " , err_str ) ;
ha_free ( & err_str ) ;
err_code | = ERR_ALERT | ERR_FATAL ;
ha_free ( & expr_str ) ;
goto end ;
}
/* We expect the log_message->conv_list expr to resolve as a binary-compatible
* value because its output will be passed to gen_hash ( ) to compute the hash .
*
* So we check the last converter ' s output type to ensure that it can be
* converted into the expected type . Invalid output type will result in an
* error to prevent unexpected results during runtime .
*/
if ( sample_casts [ smp_expr_output_type ( expr ) ] [ SMP_T_BIN ] = = NULL ) {
memprintf ( & msg , " invalid output type at the end of converter list for \" log-balance hash \" directive " ) ;
err_code | = ERR_ALERT | ERR_FATAL ;
release_sample_expr ( expr ) ;
ha_free ( & expr_str ) ;
goto end ;
}
ha_free ( & expr_str ) ;
be - > lbprm . expr = expr ;
}
2023-09-13 05:52:31 -04:00
/* finish the initialization of proxy's servers */
srv = be - > srv ;
while ( srv ) {
2023-11-09 07:45:03 -05:00
BUG_ON ( srv - > log_target ) ;
BUG_ON ( srv - > addr_type . proto_type ! = PROTO_TYPE_DGRAM & &
srv - > addr_type . proto_type ! = PROTO_TYPE_STREAM ) ;
srv - > log_target = malloc ( sizeof ( * srv - > log_target ) ) ;
if ( ! srv - > log_target ) {
memprintf ( & msg , " memory error when allocating log server '%s' \n " , srv - > id ) ;
err_code | = ERR_ALERT | ERR_FATAL ;
goto end ;
}
2023-11-09 10:57:01 -05:00
init_log_target ( srv - > log_target ) ;
if ( srv - > addr_type . proto_type = = PROTO_TYPE_DGRAM ) {
2023-11-09 07:45:03 -05:00
srv - > log_target - > type = LOG_TARGET_DGRAM ;
2023-11-09 10:57:01 -05:00
/* Try to allocate log target addr (only used in DGRAM mode) */
srv - > log_target - > addr = calloc ( 1 , sizeof ( * srv - > log_target - > addr ) ) ;
if ( ! srv - > log_target - > addr ) {
memprintf ( & msg , " memory error when allocating log server '%s' \n " , srv - > id ) ;
err_code | = ERR_ALERT | ERR_FATAL ;
goto end ;
}
/* We must initialize it with known addr:svc_port, it will then
* be updated automatically by the server API for runtime changes
*/
ipcpy ( & srv - > addr , srv - > log_target - > addr ) ;
set_host_port ( srv - > log_target - > addr , srv - > svc_port ) ;
}
2023-11-09 07:45:03 -05:00
else {
/* for now BUFFER type only supports TCP server to it's almost
2023-11-09 10:57:01 -05:00
* explicit
2023-11-09 07:45:03 -05:00
*/
srv - > log_target - > type = LOG_TARGET_BUFFER ;
2023-11-09 10:57:01 -05:00
srv - > log_target - > sink = sink_new_from_srv ( srv , " log backend " ) ;
if ( ! srv - > log_target - > sink ) {
memprintf ( & msg , " error when creating sink from '%s' log server " , srv - > id ) ;
err_code | = ERR_ALERT | ERR_FATAL ;
goto end ;
}
2023-11-09 07:45:03 -05:00
}
2023-09-13 05:52:31 -04:00
if ( target_type = = - 1 )
target_type = srv - > log_target - > type ;
2023-11-09 07:45:03 -05:00
2023-09-13 05:52:31 -04:00
if ( target_type ! = srv - > log_target - > type ) {
memprintf ( & msg , " cannot mix server types within a log backend, '%s' srv's network type differs from previous server " , srv - > id ) ;
err_code | = ERR_ALERT | ERR_FATAL ;
goto end ;
}
2023-11-09 10:57:01 -05:00
srv - > log_target - > flags | = LOG_TARGET_FL_RESOLVED ;
2023-09-13 05:52:31 -04:00
srv = srv - > next ;
}
end :
if ( err_code & ERR_CODE ) {
ha_alert ( " log backend '%s': failed to initialize: %s. \n " , be - > id , msg ) ;
ha_free ( & msg ) ;
}
return err_code ;
}
MEDIUM: tree-wide: logsrv struct becomes logger
When 'log' directive was implemented, the internal representation was
named 'struct logsrv', because the 'log' directive would directly point
to the log target, which used to be a (UDP) log server exclusively at
that time, hence the name.
But things have become more complex, since today 'log' directive can point
to ring targets (implicit, or named) for example.
Indeed, a 'log' directive does no longer reference the "final" server to
which the log will be sent, but instead it describes which log API and
parameters to use for transporting the log messages to the proper log
destination.
So now the term 'logsrv' is rather confusing and prevents us from
introducing a new level of abstraction because they would be mixed
with logsrv.
So in order to better designate this 'log' directive, and make it more
generic, we chose the word 'logger' which now replaces logsrv everywhere
it was used in the code (including related comments).
This is internal rewording, so no functional change should be expected
on user-side.
2023-09-11 09:06:53 -04:00
/* resolves a single logger entry (it is expected to be called
2023-08-17 11:38:30 -04:00
* at postparsing stage )
*
* Returns err_code which defaults to ERR_NONE and can be set to a combination
* of ERR_WARN , ERR_ALERT , ERR_FATAL and ERR_ABORT in case of errors .
* < msg > could be set at any time ( it will usually be set on error , but
2023-11-21 13:54:16 -05:00
* could also be set when no error occurred to report a diag warning ) , thus is
2023-08-17 11:38:30 -04:00
* up to the caller to check it and to free it .
*/
MEDIUM: tree-wide: logsrv struct becomes logger
When 'log' directive was implemented, the internal representation was
named 'struct logsrv', because the 'log' directive would directly point
to the log target, which used to be a (UDP) log server exclusively at
that time, hence the name.
But things have become more complex, since today 'log' directive can point
to ring targets (implicit, or named) for example.
Indeed, a 'log' directive does no longer reference the "final" server to
which the log will be sent, but instead it describes which log API and
parameters to use for transporting the log messages to the proper log
destination.
So now the term 'logsrv' is rather confusing and prevents us from
introducing a new level of abstraction because they would be mixed
with logsrv.
So in order to better designate this 'log' directive, and make it more
generic, we chose the word 'logger' which now replaces logsrv everywhere
it was used in the code (including related comments).
This is internal rewording, so no functional change should be expected
on user-side.
2023-09-11 09:06:53 -04:00
int resolve_logger ( struct logger * logger , char * * msg )
2023-08-17 11:38:30 -04:00
{
2023-09-11 10:10:37 -04:00
struct log_target * target = & logger - > target ;
2023-08-17 11:38:30 -04:00
int err_code = ERR_NONE ;
2023-09-11 10:10:37 -04:00
if ( target - > type = = LOG_TARGET_BUFFER )
MEDIUM: tree-wide: logsrv struct becomes logger
When 'log' directive was implemented, the internal representation was
named 'struct logsrv', because the 'log' directive would directly point
to the log target, which used to be a (UDP) log server exclusively at
that time, hence the name.
But things have become more complex, since today 'log' directive can point
to ring targets (implicit, or named) for example.
Indeed, a 'log' directive does no longer reference the "final" server to
which the log will be sent, but instead it describes which log API and
parameters to use for transporting the log messages to the proper log
destination.
So now the term 'logsrv' is rather confusing and prevents us from
introducing a new level of abstraction because they would be mixed
with logsrv.
So in order to better designate this 'log' directive, and make it more
generic, we chose the word 'logger' which now replaces logsrv everywhere
it was used in the code (including related comments).
This is internal rewording, so no functional change should be expected
on user-side.
2023-09-11 09:06:53 -04:00
err_code = sink_resolve_logger_buffer ( logger , msg ) ;
2023-09-13 05:52:31 -04:00
else if ( target - > type = = LOG_TARGET_BACKEND ) {
struct proxy * be ;
2023-09-11 10:10:37 -04:00
2023-09-13 05:52:31 -04:00
/* special case */
be = proxy_find_by_name ( target - > be_name , PR_CAP_BE , 0 ) ;
if ( ! be ) {
memprintf ( msg , " uses unknown log backend '%s' " , target - > be_name ) ;
err_code | = ERR_ALERT | ERR_FATAL ;
}
else if ( be - > mode ! = PR_MODE_SYSLOG ) {
memprintf ( msg , " uses incompatible log backend '%s' " , target - > be_name ) ;
err_code | = ERR_ALERT | ERR_FATAL ;
}
ha_free ( & target - > be_name ) ; /* backend is resolved and will replace name hint */
target - > be = be ;
}
2023-09-11 10:10:37 -04:00
target - > flags | = LOG_TARGET_FL_RESOLVED ;
2023-08-17 11:38:30 -04:00
return err_code ;
}
MEDIUM: tree-wide: logsrv struct becomes logger
When 'log' directive was implemented, the internal representation was
named 'struct logsrv', because the 'log' directive would directly point
to the log target, which used to be a (UDP) log server exclusively at
that time, hence the name.
But things have become more complex, since today 'log' directive can point
to ring targets (implicit, or named) for example.
Indeed, a 'log' directive does no longer reference the "final" server to
which the log will be sent, but instead it describes which log API and
parameters to use for transporting the log messages to the proper log
destination.
So now the term 'logsrv' is rather confusing and prevents us from
introducing a new level of abstraction because they would be mixed
with logsrv.
So in order to better designate this 'log' directive, and make it more
generic, we chose the word 'logger' which now replaces logsrv everywhere
it was used in the code (including related comments).
This is internal rewording, so no functional change should be expected
on user-side.
2023-09-11 09:06:53 -04:00
/* tries to duplicate <def> logger
2023-07-05 09:52:19 -04:00
*
MEDIUM: tree-wide: logsrv struct becomes logger
When 'log' directive was implemented, the internal representation was
named 'struct logsrv', because the 'log' directive would directly point
to the log target, which used to be a (UDP) log server exclusively at
that time, hence the name.
But things have become more complex, since today 'log' directive can point
to ring targets (implicit, or named) for example.
Indeed, a 'log' directive does no longer reference the "final" server to
which the log will be sent, but instead it describes which log API and
parameters to use for transporting the log messages to the proper log
destination.
So now the term 'logsrv' is rather confusing and prevents us from
introducing a new level of abstraction because they would be mixed
with logsrv.
So in order to better designate this 'log' directive, and make it more
generic, we chose the word 'logger' which now replaces logsrv everywhere
it was used in the code (including related comments).
This is internal rewording, so no functional change should be expected
on user-side.
2023-09-11 09:06:53 -04:00
* Returns the newly allocated and duplicated logger or NULL
2023-07-05 09:52:19 -04:00
* in case of error .
*/
MEDIUM: tree-wide: logsrv struct becomes logger
When 'log' directive was implemented, the internal representation was
named 'struct logsrv', because the 'log' directive would directly point
to the log target, which used to be a (UDP) log server exclusively at
that time, hence the name.
But things have become more complex, since today 'log' directive can point
to ring targets (implicit, or named) for example.
Indeed, a 'log' directive does no longer reference the "final" server to
which the log will be sent, but instead it describes which log API and
parameters to use for transporting the log messages to the proper log
destination.
So now the term 'logsrv' is rather confusing and prevents us from
introducing a new level of abstraction because they would be mixed
with logsrv.
So in order to better designate this 'log' directive, and make it more
generic, we chose the word 'logger' which now replaces logsrv everywhere
it was used in the code (including related comments).
This is internal rewording, so no functional change should be expected
on user-side.
2023-09-11 09:06:53 -04:00
struct logger * dup_logger ( struct logger * def )
2023-07-05 09:52:19 -04:00
{
MEDIUM: tree-wide: logsrv struct becomes logger
When 'log' directive was implemented, the internal representation was
named 'struct logsrv', because the 'log' directive would directly point
to the log target, which used to be a (UDP) log server exclusively at
that time, hence the name.
But things have become more complex, since today 'log' directive can point
to ring targets (implicit, or named) for example.
Indeed, a 'log' directive does no longer reference the "final" server to
which the log will be sent, but instead it describes which log API and
parameters to use for transporting the log messages to the proper log
destination.
So now the term 'logsrv' is rather confusing and prevents us from
introducing a new level of abstraction because they would be mixed
with logsrv.
So in order to better designate this 'log' directive, and make it more
generic, we chose the word 'logger' which now replaces logsrv everywhere
it was used in the code (including related comments).
This is internal rewording, so no functional change should be expected
on user-side.
2023-09-11 09:06:53 -04:00
struct logger * cpy = malloc ( sizeof ( * cpy ) ) ;
2023-07-05 09:52:19 -04:00
/* copy everything that can be easily copied */
memcpy ( cpy , def , sizeof ( * cpy ) ) ;
/* default values */
cpy - > conf . file = NULL ;
BUG/MINOR: log: smp_rgs array issues with inherited global log directives
When a log directive is defined in the global section, each time we use
"log global" in a proxy section, the global log directives are duplicated
for the current proxy. This works by creating a new proxy logger struct
and duplicating every members for each global one.
However, smp_rgs logger member is a special pointer member that is
allocated when "range" is used on a log directive. Currently, we simply
copy the array pointer (from the global one), instead of creating our own
copy. Because of that, range log sampling may not work properly in some
situations prior to 3f1284560 ("MINOR: log: remove the unused curr_idx in
struct smp_log_range") when used in global log directives, for instance:
global
log 127.0.0.1:5114 format raw sample 1-2,3:4 local0 info # should receive 75% of all proxy logs
log 127.0.0.1:5115 format raw sample 4:4 local0 info # should receive 25% of all proxy logs
listen proxy1
log global
listen proxy2
log global
May not work as expected, because curr_idx was stored within smp_rgs array
member prior to 3f1284560, and due to this bug, it happens to be shared
between every log directive inherited from a "global" one. The result is
that curr_idx counter will not behave properly because the index will be
increased globally instead of per-log directive, and it could even suffer
from concurrent thread accesses under load since we don't own the global
log directive's lock when manipulating it.
Another issue that was revealed because of this bug is that the smp_rgs
array allocated during config parsing is never freed in free_logger(),
resulting in small memory leak during clean exit.
To fix these issues all at once, let's properly duplicate smp_rgs logger
struct member in dup_logger() like we already do for other special members
so that every log directive have its own sms_rgs copy, and then
systematically free it in free_logger().
While this bug affects all stable versions (including 2.4), it's probably
best to not backport this beyond 2.6 because of 211ea252d
("BUG/MINOR: logs: fix logsrv leaks on clean exit") prerequisite that
first appears in 2.6.
[ada: for versions prior to 2.9, 969e212
("MINOR: log: add dup_logsrv() helper function") and 76acde91
("BUG/MINOR: log: keep the ref in dup_logger()") must be backported
first.
Note: Some ctx adjustments should be performed because 'logger' struct
used to be named 'logsrv' in the past and 2.9 introduced logger target
struct member. Thus it's probably easier to manually apply 76acde91 and
the current bugfix by hand directly on top of 969e212.
]
2024-05-14 04:22:19 -04:00
cpy - > lb . smp_rgs = NULL ;
2023-07-05 09:52:19 -04:00
LIST_INIT ( & cpy - > list ) ;
/* special members */
2023-09-11 10:10:37 -04:00
if ( dup_log_target ( & def - > target , & cpy - > target ) = = 0 )
goto error ;
2023-07-05 09:52:19 -04:00
if ( def - > conf . file ) {
cpy - > conf . file = strdup ( def - > conf . file ) ;
if ( ! cpy - > conf . file )
goto error ;
}
BUG/MINOR: log: smp_rgs array issues with inherited global log directives
When a log directive is defined in the global section, each time we use
"log global" in a proxy section, the global log directives are duplicated
for the current proxy. This works by creating a new proxy logger struct
and duplicating every members for each global one.
However, smp_rgs logger member is a special pointer member that is
allocated when "range" is used on a log directive. Currently, we simply
copy the array pointer (from the global one), instead of creating our own
copy. Because of that, range log sampling may not work properly in some
situations prior to 3f1284560 ("MINOR: log: remove the unused curr_idx in
struct smp_log_range") when used in global log directives, for instance:
global
log 127.0.0.1:5114 format raw sample 1-2,3:4 local0 info # should receive 75% of all proxy logs
log 127.0.0.1:5115 format raw sample 4:4 local0 info # should receive 25% of all proxy logs
listen proxy1
log global
listen proxy2
log global
May not work as expected, because curr_idx was stored within smp_rgs array
member prior to 3f1284560, and due to this bug, it happens to be shared
between every log directive inherited from a "global" one. The result is
that curr_idx counter will not behave properly because the index will be
increased globally instead of per-log directive, and it could even suffer
from concurrent thread accesses under load since we don't own the global
log directive's lock when manipulating it.
Another issue that was revealed because of this bug is that the smp_rgs
array allocated during config parsing is never freed in free_logger(),
resulting in small memory leak during clean exit.
To fix these issues all at once, let's properly duplicate smp_rgs logger
struct member in dup_logger() like we already do for other special members
so that every log directive have its own sms_rgs copy, and then
systematically free it in free_logger().
While this bug affects all stable versions (including 2.4), it's probably
best to not backport this beyond 2.6 because of 211ea252d
("BUG/MINOR: logs: fix logsrv leaks on clean exit") prerequisite that
first appears in 2.6.
[ada: for versions prior to 2.9, 969e212
("MINOR: log: add dup_logsrv() helper function") and 76acde91
("BUG/MINOR: log: keep the ref in dup_logger()") must be backported
first.
Note: Some ctx adjustments should be performed because 'logger' struct
used to be named 'logsrv' in the past and 2.9 introduced logger target
struct member. Thus it's probably easier to manually apply 76acde91 and
the current bugfix by hand directly on top of 969e212.
]
2024-05-14 04:22:19 -04:00
if ( def - > lb . smp_rgs ) {
cpy - > lb . smp_rgs = malloc ( sizeof ( * cpy - > lb . smp_rgs ) * def - > lb . smp_rgs_sz ) ;
if ( ! cpy - > lb . smp_rgs )
goto error ;
memcpy ( cpy - > lb . smp_rgs , def - > lb . smp_rgs ,
sizeof ( * cpy - > lb . smp_rgs ) * def - > lb . smp_rgs_sz ) ;
}
2023-11-13 04:19:12 -05:00
/* inherit from original reference if set */
cpy - > ref = ( def - > ref ) ? def - > ref : def ;
2023-07-05 09:52:19 -04:00
return cpy ;
error :
MEDIUM: tree-wide: logsrv struct becomes logger
When 'log' directive was implemented, the internal representation was
named 'struct logsrv', because the 'log' directive would directly point
to the log target, which used to be a (UDP) log server exclusively at
that time, hence the name.
But things have become more complex, since today 'log' directive can point
to ring targets (implicit, or named) for example.
Indeed, a 'log' directive does no longer reference the "final" server to
which the log will be sent, but instead it describes which log API and
parameters to use for transporting the log messages to the proper log
destination.
So now the term 'logsrv' is rather confusing and prevents us from
introducing a new level of abstraction because they would be mixed
with logsrv.
So in order to better designate this 'log' directive, and make it more
generic, we chose the word 'logger' which now replaces logsrv everywhere
it was used in the code (including related comments).
This is internal rewording, so no functional change should be expected
on user-side.
2023-09-11 09:06:53 -04:00
free_logger ( cpy ) ;
2023-07-05 09:52:19 -04:00
return NULL ;
}
MEDIUM: tree-wide: logsrv struct becomes logger
When 'log' directive was implemented, the internal representation was
named 'struct logsrv', because the 'log' directive would directly point
to the log target, which used to be a (UDP) log server exclusively at
that time, hence the name.
But things have become more complex, since today 'log' directive can point
to ring targets (implicit, or named) for example.
Indeed, a 'log' directive does no longer reference the "final" server to
which the log will be sent, but instead it describes which log API and
parameters to use for transporting the log messages to the proper log
destination.
So now the term 'logsrv' is rather confusing and prevents us from
introducing a new level of abstraction because they would be mixed
with logsrv.
So in order to better designate this 'log' directive, and make it more
generic, we chose the word 'logger' which now replaces logsrv everywhere
it was used in the code (including related comments).
This is internal rewording, so no functional change should be expected
on user-side.
2023-09-11 09:06:53 -04:00
/* frees <logger> after freeing all of its allocated fields. The
2022-03-17 14:47:33 -04:00
* server must not belong to a list anymore . Logsrv may be NULL , which is
* silently ignored .
*/
MEDIUM: tree-wide: logsrv struct becomes logger
When 'log' directive was implemented, the internal representation was
named 'struct logsrv', because the 'log' directive would directly point
to the log target, which used to be a (UDP) log server exclusively at
that time, hence the name.
But things have become more complex, since today 'log' directive can point
to ring targets (implicit, or named) for example.
Indeed, a 'log' directive does no longer reference the "final" server to
which the log will be sent, but instead it describes which log API and
parameters to use for transporting the log messages to the proper log
destination.
So now the term 'logsrv' is rather confusing and prevents us from
introducing a new level of abstraction because they would be mixed
with logsrv.
So in order to better designate this 'log' directive, and make it more
generic, we chose the word 'logger' which now replaces logsrv everywhere
it was used in the code (including related comments).
This is internal rewording, so no functional change should be expected
on user-side.
2023-09-11 09:06:53 -04:00
void free_logger ( struct logger * logger )
2022-03-17 14:47:33 -04:00
{
MEDIUM: tree-wide: logsrv struct becomes logger
When 'log' directive was implemented, the internal representation was
named 'struct logsrv', because the 'log' directive would directly point
to the log target, which used to be a (UDP) log server exclusively at
that time, hence the name.
But things have become more complex, since today 'log' directive can point
to ring targets (implicit, or named) for example.
Indeed, a 'log' directive does no longer reference the "final" server to
which the log will be sent, but instead it describes which log API and
parameters to use for transporting the log messages to the proper log
destination.
So now the term 'logsrv' is rather confusing and prevents us from
introducing a new level of abstraction because they would be mixed
with logsrv.
So in order to better designate this 'log' directive, and make it more
generic, we chose the word 'logger' which now replaces logsrv everywhere
it was used in the code (including related comments).
This is internal rewording, so no functional change should be expected
on user-side.
2023-09-11 09:06:53 -04:00
if ( ! logger )
2022-03-17 14:47:33 -04:00
return ;
MEDIUM: tree-wide: logsrv struct becomes logger
When 'log' directive was implemented, the internal representation was
named 'struct logsrv', because the 'log' directive would directly point
to the log target, which used to be a (UDP) log server exclusively at
that time, hence the name.
But things have become more complex, since today 'log' directive can point
to ring targets (implicit, or named) for example.
Indeed, a 'log' directive does no longer reference the "final" server to
which the log will be sent, but instead it describes which log API and
parameters to use for transporting the log messages to the proper log
destination.
So now the term 'logsrv' is rather confusing and prevents us from
introducing a new level of abstraction because they would be mixed
with logsrv.
So in order to better designate this 'log' directive, and make it more
generic, we chose the word 'logger' which now replaces logsrv everywhere
it was used in the code (including related comments).
This is internal rewording, so no functional change should be expected
on user-side.
2023-09-11 09:06:53 -04:00
BUG_ON ( LIST_INLIST ( & logger - > list ) ) ;
ha_free ( & logger - > conf . file ) ;
2023-09-11 10:10:37 -04:00
deinit_log_target ( & logger - > target ) ;
BUG/MINOR: log: smp_rgs array issues with inherited global log directives
When a log directive is defined in the global section, each time we use
"log global" in a proxy section, the global log directives are duplicated
for the current proxy. This works by creating a new proxy logger struct
and duplicating every members for each global one.
However, smp_rgs logger member is a special pointer member that is
allocated when "range" is used on a log directive. Currently, we simply
copy the array pointer (from the global one), instead of creating our own
copy. Because of that, range log sampling may not work properly in some
situations prior to 3f1284560 ("MINOR: log: remove the unused curr_idx in
struct smp_log_range") when used in global log directives, for instance:
global
log 127.0.0.1:5114 format raw sample 1-2,3:4 local0 info # should receive 75% of all proxy logs
log 127.0.0.1:5115 format raw sample 4:4 local0 info # should receive 25% of all proxy logs
listen proxy1
log global
listen proxy2
log global
May not work as expected, because curr_idx was stored within smp_rgs array
member prior to 3f1284560, and due to this bug, it happens to be shared
between every log directive inherited from a "global" one. The result is
that curr_idx counter will not behave properly because the index will be
increased globally instead of per-log directive, and it could even suffer
from concurrent thread accesses under load since we don't own the global
log directive's lock when manipulating it.
Another issue that was revealed because of this bug is that the smp_rgs
array allocated during config parsing is never freed in free_logger(),
resulting in small memory leak during clean exit.
To fix these issues all at once, let's properly duplicate smp_rgs logger
struct member in dup_logger() like we already do for other special members
so that every log directive have its own sms_rgs copy, and then
systematically free it in free_logger().
While this bug affects all stable versions (including 2.4), it's probably
best to not backport this beyond 2.6 because of 211ea252d
("BUG/MINOR: logs: fix logsrv leaks on clean exit") prerequisite that
first appears in 2.6.
[ada: for versions prior to 2.9, 969e212
("MINOR: log: add dup_logsrv() helper function") and 76acde91
("BUG/MINOR: log: keep the ref in dup_logger()") must be backported
first.
Note: Some ctx adjustments should be performed because 'logger' struct
used to be named 'logsrv' in the past and 2.9 introduced logger target
struct member. Thus it's probably easier to manually apply 76acde91 and
the current bugfix by hand directly on top of 969e212.
]
2024-05-14 04:22:19 -04:00
free ( logger - > lb . smp_rgs ) ;
MEDIUM: tree-wide: logsrv struct becomes logger
When 'log' directive was implemented, the internal representation was
named 'struct logsrv', because the 'log' directive would directly point
to the log target, which used to be a (UDP) log server exclusively at
that time, hence the name.
But things have become more complex, since today 'log' directive can point
to ring targets (implicit, or named) for example.
Indeed, a 'log' directive does no longer reference the "final" server to
which the log will be sent, but instead it describes which log API and
parameters to use for transporting the log messages to the proper log
destination.
So now the term 'logsrv' is rather confusing and prevents us from
introducing a new level of abstraction because they would be mixed
with logsrv.
So in order to better designate this 'log' directive, and make it more
generic, we chose the word 'logger' which now replaces logsrv everywhere
it was used in the code (including related comments).
This is internal rewording, so no functional change should be expected
on user-side.
2023-09-11 09:06:53 -04:00
free ( logger ) ;
2022-03-17 14:47:33 -04:00
}
2023-09-11 10:10:37 -04:00
/* Parse single log target
* Returns 0 on failure and positive value on success
*/
static int parse_log_target ( char * raw , struct log_target * target , char * * err )
{
int port1 , port2 , fd ;
struct protocol * proto ;
struct sockaddr_storage * sk ;
init_log_target ( target ) ;
2023-09-13 13:28:34 -04:00
// target addr is NULL at this point
if ( strncmp ( raw , " ring@ " , 5 ) = = 0 ) {
target - > type = LOG_TARGET_BUFFER ;
target - > ring_name = strdup ( raw + 5 ) ;
goto done ;
}
2023-09-13 05:52:31 -04:00
else if ( strncmp ( raw , " backend@ " , 8 ) = = 0 ) {
target - > type = LOG_TARGET_BACKEND ;
target - > be_name = strdup ( raw + 8 ) ;
goto done ;
}
2023-09-11 10:10:37 -04:00
2023-09-13 13:28:34 -04:00
/* try to allocate log target addr */
2023-09-11 10:10:37 -04:00
target - > addr = malloc ( sizeof ( * target - > addr ) ) ;
if ( ! target - > addr ) {
memprintf ( err , " memory error " ) ;
goto error ;
}
2023-09-13 13:28:34 -04:00
target - > type = LOG_TARGET_DGRAM ; // default type
2023-09-11 10:10:37 -04:00
/* parse the target address */
2023-11-09 05:19:24 -05:00
sk = str2sa_range ( raw , NULL , & port1 , & port2 , & fd , & proto , NULL ,
2023-09-11 10:10:37 -04:00
err , NULL , NULL ,
PA_O_RESOLVE | PA_O_PORT_OK | PA_O_RAW_FD | PA_O_DGRAM | PA_O_STREAM | PA_O_DEFAULT_DGRAM ) ;
if ( ! sk )
goto error ;
if ( fd ! = - 1 )
target - > type = LOG_TARGET_FD ;
* target - > addr = * sk ;
if ( sk - > ss_family = = AF_INET | | sk - > ss_family = = AF_INET6 ) {
if ( ! port1 )
set_host_port ( target - > addr , SYSLOG_PORT ) ;
}
if ( proto & & proto - > xprt_type = = PROTO_TYPE_STREAM ) {
static unsigned long ring_ids ;
2023-09-13 13:28:34 -04:00
/* Implicit sink buffer will be initialized in post_check
* ( target - > addr is set in this case )
2023-09-11 10:10:37 -04:00
*/
target - > type = LOG_TARGET_BUFFER ;
/* compute unique name for the ring */
memprintf ( & target - > ring_name , " ring#%lu " , + + ring_ids ) ;
}
done :
return 1 ;
error :
deinit_log_target ( target ) ;
return 0 ;
}
2018-03-26 09:54:32 -04:00
/*
MEDIUM: tree-wide: logsrv struct becomes logger
When 'log' directive was implemented, the internal representation was
named 'struct logsrv', because the 'log' directive would directly point
to the log target, which used to be a (UDP) log server exclusively at
that time, hence the name.
But things have become more complex, since today 'log' directive can point
to ring targets (implicit, or named) for example.
Indeed, a 'log' directive does no longer reference the "final" server to
which the log will be sent, but instead it describes which log API and
parameters to use for transporting the log messages to the proper log
destination.
So now the term 'logsrv' is rather confusing and prevents us from
introducing a new level of abstraction because they would be mixed
with logsrv.
So in order to better designate this 'log' directive, and make it more
generic, we chose the word 'logger' which now replaces logsrv everywhere
it was used in the code (including related comments).
This is internal rewording, so no functional change should be expected
on user-side.
2023-09-11 09:06:53 -04:00
* Parse " log " keyword and update < loggers > list accordingly .
2018-03-26 09:54:32 -04:00
*
* When < do_del > is set , it means the " no log " line was parsed , so all log
MEDIUM: tree-wide: logsrv struct becomes logger
When 'log' directive was implemented, the internal representation was
named 'struct logsrv', because the 'log' directive would directly point
to the log target, which used to be a (UDP) log server exclusively at
that time, hence the name.
But things have become more complex, since today 'log' directive can point
to ring targets (implicit, or named) for example.
Indeed, a 'log' directive does no longer reference the "final" server to
which the log will be sent, but instead it describes which log API and
parameters to use for transporting the log messages to the proper log
destination.
So now the term 'logsrv' is rather confusing and prevents us from
introducing a new level of abstraction because they would be mixed
with logsrv.
So in order to better designate this 'log' directive, and make it more
generic, we chose the word 'logger' which now replaces logsrv everywhere
it was used in the code (including related comments).
This is internal rewording, so no functional change should be expected
on user-side.
2023-09-11 09:06:53 -04:00
* servers in < loggers > are released .
2018-03-26 09:54:32 -04:00
*
* Otherwise , we try to parse the " log " line . First of all , when the list is not
* the global one , we look for the parameter " global " . If we find it ,
MEDIUM: tree-wide: logsrv struct becomes logger
When 'log' directive was implemented, the internal representation was
named 'struct logsrv', because the 'log' directive would directly point
to the log target, which used to be a (UDP) log server exclusively at
that time, hence the name.
But things have become more complex, since today 'log' directive can point
to ring targets (implicit, or named) for example.
Indeed, a 'log' directive does no longer reference the "final" server to
which the log will be sent, but instead it describes which log API and
parameters to use for transporting the log messages to the proper log
destination.
So now the term 'logsrv' is rather confusing and prevents us from
introducing a new level of abstraction because they would be mixed
with logsrv.
So in order to better designate this 'log' directive, and make it more
generic, we chose the word 'logger' which now replaces logsrv everywhere
it was used in the code (including related comments).
This is internal rewording, so no functional change should be expected
on user-side.
2023-09-11 09:06:53 -04:00
* global . loggers is copied . Else we parse each arguments .
2018-03-26 09:54:32 -04:00
*
* The function returns 1 in success case , otherwise , it returns 0 and err is
* filled .
*/
MEDIUM: tree-wide: logsrv struct becomes logger
When 'log' directive was implemented, the internal representation was
named 'struct logsrv', because the 'log' directive would directly point
to the log target, which used to be a (UDP) log server exclusively at
that time, hence the name.
But things have become more complex, since today 'log' directive can point
to ring targets (implicit, or named) for example.
Indeed, a 'log' directive does no longer reference the "final" server to
which the log will be sent, but instead it describes which log API and
parameters to use for transporting the log messages to the proper log
destination.
So now the term 'logsrv' is rather confusing and prevents us from
introducing a new level of abstraction because they would be mixed
with logsrv.
So in order to better designate this 'log' directive, and make it more
generic, we chose the word 'logger' which now replaces logsrv everywhere
it was used in the code (including related comments).
This is internal rewording, so no functional change should be expected
on user-side.
2023-09-11 09:06:53 -04:00
int parse_logger ( char * * args , struct list * loggers , int do_del , const char * file , int linenum , char * * err )
2018-03-26 09:54:32 -04:00
{
2020-10-27 04:51:37 -04:00
struct smp_log_range * smp_rgs = NULL ;
MEDIUM: tree-wide: logsrv struct becomes logger
When 'log' directive was implemented, the internal representation was
named 'struct logsrv', because the 'log' directive would directly point
to the log target, which used to be a (UDP) log server exclusively at
that time, hence the name.
But things have become more complex, since today 'log' directive can point
to ring targets (implicit, or named) for example.
Indeed, a 'log' directive does no longer reference the "final" server to
which the log will be sent, but instead it describes which log API and
parameters to use for transporting the log messages to the proper log
destination.
So now the term 'logsrv' is rather confusing and prevents us from
introducing a new level of abstraction because they would be mixed
with logsrv.
So in order to better designate this 'log' directive, and make it more
generic, we chose the word 'logger' which now replaces logsrv everywhere
it was used in the code (including related comments).
This is internal rewording, so no functional change should be expected
on user-side.
2023-09-11 09:06:53 -04:00
struct logger * logger = NULL ;
2018-03-26 09:54:32 -04:00
int cur_arg ;
/*
* " no log " : delete previous herited or defined syslog
* servers .
*/
if ( do_del ) {
MEDIUM: tree-wide: logsrv struct becomes logger
When 'log' directive was implemented, the internal representation was
named 'struct logsrv', because the 'log' directive would directly point
to the log target, which used to be a (UDP) log server exclusively at
that time, hence the name.
But things have become more complex, since today 'log' directive can point
to ring targets (implicit, or named) for example.
Indeed, a 'log' directive does no longer reference the "final" server to
which the log will be sent, but instead it describes which log API and
parameters to use for transporting the log messages to the proper log
destination.
So now the term 'logsrv' is rather confusing and prevents us from
introducing a new level of abstraction because they would be mixed
with logsrv.
So in order to better designate this 'log' directive, and make it more
generic, we chose the word 'logger' which now replaces logsrv everywhere
it was used in the code (including related comments).
This is internal rewording, so no functional change should be expected
on user-side.
2023-09-11 09:06:53 -04:00
struct logger * back ;
2018-03-26 09:54:32 -04:00
if ( * ( args [ 1 ] ) ! = 0 ) {
memprintf ( err , " 'no log' does not expect arguments " ) ;
goto error ;
}
MEDIUM: tree-wide: logsrv struct becomes logger
When 'log' directive was implemented, the internal representation was
named 'struct logsrv', because the 'log' directive would directly point
to the log target, which used to be a (UDP) log server exclusively at
that time, hence the name.
But things have become more complex, since today 'log' directive can point
to ring targets (implicit, or named) for example.
Indeed, a 'log' directive does no longer reference the "final" server to
which the log will be sent, but instead it describes which log API and
parameters to use for transporting the log messages to the proper log
destination.
So now the term 'logsrv' is rather confusing and prevents us from
introducing a new level of abstraction because they would be mixed
with logsrv.
So in order to better designate this 'log' directive, and make it more
generic, we chose the word 'logger' which now replaces logsrv everywhere
it was used in the code (including related comments).
This is internal rewording, so no functional change should be expected
on user-side.
2023-09-11 09:06:53 -04:00
list_for_each_entry_safe ( logger , back , loggers , list ) {
LIST_DEL_INIT ( & logger - > list ) ;
free_logger ( logger ) ;
2018-03-26 09:54:32 -04:00
}
return 1 ;
}
/*
MEDIUM: tree-wide: logsrv struct becomes logger
When 'log' directive was implemented, the internal representation was
named 'struct logsrv', because the 'log' directive would directly point
to the log target, which used to be a (UDP) log server exclusively at
that time, hence the name.
But things have become more complex, since today 'log' directive can point
to ring targets (implicit, or named) for example.
Indeed, a 'log' directive does no longer reference the "final" server to
which the log will be sent, but instead it describes which log API and
parameters to use for transporting the log messages to the proper log
destination.
So now the term 'logsrv' is rather confusing and prevents us from
introducing a new level of abstraction because they would be mixed
with logsrv.
So in order to better designate this 'log' directive, and make it more
generic, we chose the word 'logger' which now replaces logsrv everywhere
it was used in the code (including related comments).
This is internal rewording, so no functional change should be expected
on user-side.
2023-09-11 09:06:53 -04:00
* " log global " : copy global . loggers linked list to the end of loggers
* list . But first , we check ( loggers ! = global . loggers ) .
2018-03-26 09:54:32 -04:00
*/
CLEANUP: Compare the return value of `XXXcmp()` functions with zero
According to coding-style.txt it is recommended to use:
`strcmp(a, b) == 0` instead of `!strcmp(a, b)`
So let's do this.
The change was performed by running the following (very long) coccinelle patch
on src/:
@@
statement S;
expression E;
expression F;
@@
if (
(
dns_hostname_cmp
|
eb_memcmp
|
memcmp
|
strcasecmp
|
strcmp
|
strncasecmp
|
strncmp
)
- (E, F)
+ (E, F) != 0
)
(
S
|
{ ... }
)
@@
statement S;
expression E;
expression F;
@@
if (
- !
(
dns_hostname_cmp
|
eb_memcmp
|
memcmp
|
strcasecmp
|
strcmp
|
strncasecmp
|
strncmp
)
- (E, F)
+ (E, F) == 0
)
(
S
|
{ ... }
)
@@
expression E;
expression F;
expression G;
@@
(
G &&
(
dns_hostname_cmp
|
eb_memcmp
|
memcmp
|
strcasecmp
|
strcmp
|
strncasecmp
|
strncmp
)
- (E, F)
+ (E, F) != 0
)
@@
expression E;
expression F;
expression G;
@@
(
G ||
(
dns_hostname_cmp
|
eb_memcmp
|
memcmp
|
strcasecmp
|
strcmp
|
strncasecmp
|
strncmp
)
- (E, F)
+ (E, F) != 0
)
@@
expression E;
expression F;
expression G;
@@
(
(
dns_hostname_cmp
|
eb_memcmp
|
memcmp
|
strcasecmp
|
strcmp
|
strncasecmp
|
strncmp
)
- (E, F)
+ (E, F) != 0
&& G
)
@@
expression E;
expression F;
expression G;
@@
(
(
dns_hostname_cmp
|
eb_memcmp
|
memcmp
|
strcasecmp
|
strcmp
|
strncasecmp
|
strncmp
)
- (E, F)
+ (E, F) != 0
|| G
)
@@
expression E;
expression F;
expression G;
@@
(
G &&
- !
(
dns_hostname_cmp
|
eb_memcmp
|
memcmp
|
strcasecmp
|
strcmp
|
strncasecmp
|
strncmp
)
- (E, F)
+ (E, F) == 0
)
@@
expression E;
expression F;
expression G;
@@
(
G ||
- !
(
dns_hostname_cmp
|
eb_memcmp
|
memcmp
|
strcasecmp
|
strcmp
|
strncasecmp
|
strncmp
)
- (E, F)
+ (E, F) == 0
)
@@
expression E;
expression F;
expression G;
@@
(
- !
(
dns_hostname_cmp
|
eb_memcmp
|
memcmp
|
strcasecmp
|
strcmp
|
strncasecmp
|
strncmp
)
- (E, F)
+ (E, F) == 0
&& G
)
@@
expression E;
expression F;
expression G;
@@
(
- !
(
dns_hostname_cmp
|
eb_memcmp
|
memcmp
|
strcasecmp
|
strcmp
|
strncasecmp
|
strncmp
)
- (E, F)
+ (E, F) == 0
|| G
)
@@
expression E;
expression F;
expression G;
@@
(
- !
(
dns_hostname_cmp
|
eb_memcmp
|
memcmp
|
strcasecmp
|
strcmp
|
strncasecmp
|
strncmp
)
- (E, F)
+ (E, F) == 0
)
2021-01-02 16:31:53 -05:00
if ( * ( args [ 1 ] ) & & * ( args [ 2 ] ) = = 0 & & strcmp ( args [ 1 ] , " global " ) = = 0 ) {
MEDIUM: tree-wide: logsrv struct becomes logger
When 'log' directive was implemented, the internal representation was
named 'struct logsrv', because the 'log' directive would directly point
to the log target, which used to be a (UDP) log server exclusively at
that time, hence the name.
But things have become more complex, since today 'log' directive can point
to ring targets (implicit, or named) for example.
Indeed, a 'log' directive does no longer reference the "final" server to
which the log will be sent, but instead it describes which log API and
parameters to use for transporting the log messages to the proper log
destination.
So now the term 'logsrv' is rather confusing and prevents us from
introducing a new level of abstraction because they would be mixed
with logsrv.
So in order to better designate this 'log' directive, and make it more
generic, we chose the word 'logger' which now replaces logsrv everywhere
it was used in the code (including related comments).
This is internal rewording, so no functional change should be expected
on user-side.
2023-09-11 09:06:53 -04:00
if ( loggers = = & global . loggers ) {
2018-03-26 09:54:32 -04:00
memprintf ( err , " 'global' is not supported for a global syslog server " ) ;
goto error ;
}
MEDIUM: tree-wide: logsrv struct becomes logger
When 'log' directive was implemented, the internal representation was
named 'struct logsrv', because the 'log' directive would directly point
to the log target, which used to be a (UDP) log server exclusively at
that time, hence the name.
But things have become more complex, since today 'log' directive can point
to ring targets (implicit, or named) for example.
Indeed, a 'log' directive does no longer reference the "final" server to
which the log will be sent, but instead it describes which log API and
parameters to use for transporting the log messages to the proper log
destination.
So now the term 'logsrv' is rather confusing and prevents us from
introducing a new level of abstraction because they would be mixed
with logsrv.
So in order to better designate this 'log' directive, and make it more
generic, we chose the word 'logger' which now replaces logsrv everywhere
it was used in the code (including related comments).
This is internal rewording, so no functional change should be expected
on user-side.
2023-09-11 09:06:53 -04:00
list_for_each_entry ( logger , & global . loggers , list ) {
struct logger * node ;
2018-03-26 10:09:19 -04:00
MEDIUM: tree-wide: logsrv struct becomes logger
When 'log' directive was implemented, the internal representation was
named 'struct logsrv', because the 'log' directive would directly point
to the log target, which used to be a (UDP) log server exclusively at
that time, hence the name.
But things have become more complex, since today 'log' directive can point
to ring targets (implicit, or named) for example.
Indeed, a 'log' directive does no longer reference the "final" server to
which the log will be sent, but instead it describes which log API and
parameters to use for transporting the log messages to the proper log
destination.
So now the term 'logsrv' is rather confusing and prevents us from
introducing a new level of abstraction because they would be mixed
with logsrv.
So in order to better designate this 'log' directive, and make it more
generic, we chose the word 'logger' which now replaces logsrv everywhere
it was used in the code (including related comments).
This is internal rewording, so no functional change should be expected
on user-side.
2023-09-11 09:06:53 -04:00
list_for_each_entry ( node , loggers , list ) {
if ( node - > ref = = logger )
goto skip_logger ;
2018-03-26 10:09:19 -04:00
}
MEDIUM: tree-wide: logsrv struct becomes logger
When 'log' directive was implemented, the internal representation was
named 'struct logsrv', because the 'log' directive would directly point
to the log target, which used to be a (UDP) log server exclusively at
that time, hence the name.
But things have become more complex, since today 'log' directive can point
to ring targets (implicit, or named) for example.
Indeed, a 'log' directive does no longer reference the "final" server to
which the log will be sent, but instead it describes which log API and
parameters to use for transporting the log messages to the proper log
destination.
So now the term 'logsrv' is rather confusing and prevents us from
introducing a new level of abstraction because they would be mixed
with logsrv.
So in order to better designate this 'log' directive, and make it more
generic, we chose the word 'logger' which now replaces logsrv everywhere
it was used in the code (including related comments).
This is internal rewording, so no functional change should be expected
on user-side.
2023-09-11 09:06:53 -04:00
/* duplicate logger from global */
node = dup_logger ( logger ) ;
2023-05-11 12:57:23 -04:00
if ( ! node ) {
memprintf ( err , " out of memory error " ) ;
goto error ;
}
2023-07-05 09:52:19 -04:00
/* manually override some values */
ha_free ( & node - > conf . file ) ;
2021-04-02 04:13:43 -04:00
node - > conf . file = strdup ( file ) ;
node - > conf . line = linenum ;
2018-03-26 10:09:19 -04:00
2023-07-05 09:52:19 -04:00
/* add to list */
MEDIUM: tree-wide: logsrv struct becomes logger
When 'log' directive was implemented, the internal representation was
named 'struct logsrv', because the 'log' directive would directly point
to the log target, which used to be a (UDP) log server exclusively at
that time, hence the name.
But things have become more complex, since today 'log' directive can point
to ring targets (implicit, or named) for example.
Indeed, a 'log' directive does no longer reference the "final" server to
which the log will be sent, but instead it describes which log API and
parameters to use for transporting the log messages to the proper log
destination.
So now the term 'logsrv' is rather confusing and prevents us from
introducing a new level of abstraction because they would be mixed
with logsrv.
So in order to better designate this 'log' directive, and make it more
generic, we chose the word 'logger' which now replaces logsrv everywhere
it was used in the code (including related comments).
This is internal rewording, so no functional change should be expected
on user-side.
2023-09-11 09:06:53 -04:00
LIST_APPEND ( loggers , & node - > list ) ;
2023-07-05 09:52:19 -04:00
MEDIUM: tree-wide: logsrv struct becomes logger
When 'log' directive was implemented, the internal representation was
named 'struct logsrv', because the 'log' directive would directly point
to the log target, which used to be a (UDP) log server exclusively at
that time, hence the name.
But things have become more complex, since today 'log' directive can point
to ring targets (implicit, or named) for example.
Indeed, a 'log' directive does no longer reference the "final" server to
which the log will be sent, but instead it describes which log API and
parameters to use for transporting the log messages to the proper log
destination.
So now the term 'logsrv' is rather confusing and prevents us from
introducing a new level of abstraction because they would be mixed
with logsrv.
So in order to better designate this 'log' directive, and make it more
generic, we chose the word 'logger' which now replaces logsrv everywhere
it was used in the code (including related comments).
This is internal rewording, so no functional change should be expected
on user-side.
2023-09-11 09:06:53 -04:00
skip_logger :
2018-03-26 10:09:19 -04:00
continue ;
2018-03-26 09:54:32 -04:00
}
return 1 ;
}
/*
* " log <address> ...: parse a syslog server line
*/
if ( * ( args [ 1 ] ) = = 0 | | * ( args [ 2 ] ) = = 0 ) {
memprintf ( err , " expects <address> and <facility> %s as arguments " ,
MEDIUM: tree-wide: logsrv struct becomes logger
When 'log' directive was implemented, the internal representation was
named 'struct logsrv', because the 'log' directive would directly point
to the log target, which used to be a (UDP) log server exclusively at
that time, hence the name.
But things have become more complex, since today 'log' directive can point
to ring targets (implicit, or named) for example.
Indeed, a 'log' directive does no longer reference the "final" server to
which the log will be sent, but instead it describes which log API and
parameters to use for transporting the log messages to the proper log
destination.
So now the term 'logsrv' is rather confusing and prevents us from
introducing a new level of abstraction because they would be mixed
with logsrv.
So in order to better designate this 'log' directive, and make it more
generic, we chose the word 'logger' which now replaces logsrv everywhere
it was used in the code (including related comments).
This is internal rewording, so no functional change should be expected
on user-side.
2023-09-11 09:06:53 -04:00
( ( loggers = = & global . loggers ) ? " " : " or global " ) ) ;
2018-03-26 09:54:32 -04:00
goto error ;
}
2018-11-12 01:34:59 -05:00
/* take care of "stdout" and "stderr" as regular aliases for fd@1 / fd@2 */
if ( strcmp ( args [ 1 ] , " stdout " ) = = 0 )
args [ 1 ] = " fd@1 " ;
else if ( strcmp ( args [ 1 ] , " stderr " ) = = 0 )
args [ 1 ] = " fd@2 " ;
MEDIUM: tree-wide: logsrv struct becomes logger
When 'log' directive was implemented, the internal representation was
named 'struct logsrv', because the 'log' directive would directly point
to the log target, which used to be a (UDP) log server exclusively at
that time, hence the name.
But things have become more complex, since today 'log' directive can point
to ring targets (implicit, or named) for example.
Indeed, a 'log' directive does no longer reference the "final" server to
which the log will be sent, but instead it describes which log API and
parameters to use for transporting the log messages to the proper log
destination.
So now the term 'logsrv' is rather confusing and prevents us from
introducing a new level of abstraction because they would be mixed
with logsrv.
So in order to better designate this 'log' directive, and make it more
generic, we chose the word 'logger' which now replaces logsrv everywhere
it was used in the code (including related comments).
This is internal rewording, so no functional change should be expected
on user-side.
2023-09-11 09:06:53 -04:00
logger = calloc ( 1 , sizeof ( * logger ) ) ;
if ( ! logger ) {
2018-03-26 09:54:32 -04:00
memprintf ( err , " out of memory " ) ;
goto error ;
}
MEDIUM: tree-wide: logsrv struct becomes logger
When 'log' directive was implemented, the internal representation was
named 'struct logsrv', because the 'log' directive would directly point
to the log target, which used to be a (UDP) log server exclusively at
that time, hence the name.
But things have become more complex, since today 'log' directive can point
to ring targets (implicit, or named) for example.
Indeed, a 'log' directive does no longer reference the "final" server to
which the log will be sent, but instead it describes which log API and
parameters to use for transporting the log messages to the proper log
destination.
So now the term 'logsrv' is rather confusing and prevents us from
introducing a new level of abstraction because they would be mixed
with logsrv.
So in order to better designate this 'log' directive, and make it more
generic, we chose the word 'logger' which now replaces logsrv everywhere
it was used in the code (including related comments).
This is internal rewording, so no functional change should be expected
on user-side.
2023-09-11 09:06:53 -04:00
LIST_INIT ( & logger - > list ) ;
logger - > conf . file = strdup ( file ) ;
logger - > conf . line = linenum ;
2021-04-02 04:13:43 -04:00
2018-03-26 09:54:32 -04:00
/* skip address for now, it will be parsed at the end */
cur_arg = 2 ;
/* just after the address, a length may be specified */
MEDIUM: tree-wide: logsrv struct becomes logger
When 'log' directive was implemented, the internal representation was
named 'struct logsrv', because the 'log' directive would directly point
to the log target, which used to be a (UDP) log server exclusively at
that time, hence the name.
But things have become more complex, since today 'log' directive can point
to ring targets (implicit, or named) for example.
Indeed, a 'log' directive does no longer reference the "final" server to
which the log will be sent, but instead it describes which log API and
parameters to use for transporting the log messages to the proper log
destination.
So now the term 'logsrv' is rather confusing and prevents us from
introducing a new level of abstraction because they would be mixed
with logsrv.
So in order to better designate this 'log' directive, and make it more
generic, we chose the word 'logger' which now replaces logsrv everywhere
it was used in the code (including related comments).
This is internal rewording, so no functional change should be expected
on user-side.
2023-09-11 09:06:53 -04:00
logger - > maxlen = MAX_SYSLOG_LEN ;
2018-03-26 09:54:32 -04:00
if ( strcmp ( args [ cur_arg ] , " len " ) = = 0 ) {
int len = atoi ( args [ cur_arg + 1 ] ) ;
if ( len < 80 | | len > 65535 ) {
memprintf ( err , " invalid log length '%s', must be between 80 and 65535 " ,
args [ cur_arg + 1 ] ) ;
goto error ;
}
MEDIUM: tree-wide: logsrv struct becomes logger
When 'log' directive was implemented, the internal representation was
named 'struct logsrv', because the 'log' directive would directly point
to the log target, which used to be a (UDP) log server exclusively at
that time, hence the name.
But things have become more complex, since today 'log' directive can point
to ring targets (implicit, or named) for example.
Indeed, a 'log' directive does no longer reference the "final" server to
which the log will be sent, but instead it describes which log API and
parameters to use for transporting the log messages to the proper log
destination.
So now the term 'logsrv' is rather confusing and prevents us from
introducing a new level of abstraction because they would be mixed
with logsrv.
So in order to better designate this 'log' directive, and make it more
generic, we chose the word 'logger' which now replaces logsrv everywhere
it was used in the code (including related comments).
This is internal rewording, so no functional change should be expected
on user-side.
2023-09-11 09:06:53 -04:00
logger - > maxlen = len ;
2018-03-26 09:54:32 -04:00
cur_arg + = 2 ;
}
MEDIUM: tree-wide: logsrv struct becomes logger
When 'log' directive was implemented, the internal representation was
named 'struct logsrv', because the 'log' directive would directly point
to the log target, which used to be a (UDP) log server exclusively at
that time, hence the name.
But things have become more complex, since today 'log' directive can point
to ring targets (implicit, or named) for example.
Indeed, a 'log' directive does no longer reference the "final" server to
which the log will be sent, but instead it describes which log API and
parameters to use for transporting the log messages to the proper log
destination.
So now the term 'logsrv' is rather confusing and prevents us from
introducing a new level of abstraction because they would be mixed
with logsrv.
So in order to better designate this 'log' directive, and make it more
generic, we chose the word 'logger' which now replaces logsrv everywhere
it was used in the code (including related comments).
This is internal rewording, so no functional change should be expected
on user-side.
2023-09-11 09:06:53 -04:00
if ( logger - > maxlen > global . max_syslog_len )
global . max_syslog_len = logger - > maxlen ;
2018-03-26 09:54:32 -04:00
/* after the length, a format may be specified */
if ( strcmp ( args [ cur_arg ] , " format " ) = = 0 ) {
MEDIUM: tree-wide: logsrv struct becomes logger
When 'log' directive was implemented, the internal representation was
named 'struct logsrv', because the 'log' directive would directly point
to the log target, which used to be a (UDP) log server exclusively at
that time, hence the name.
But things have become more complex, since today 'log' directive can point
to ring targets (implicit, or named) for example.
Indeed, a 'log' directive does no longer reference the "final" server to
which the log will be sent, but instead it describes which log API and
parameters to use for transporting the log messages to the proper log
destination.
So now the term 'logsrv' is rather confusing and prevents us from
introducing a new level of abstraction because they would be mixed
with logsrv.
So in order to better designate this 'log' directive, and make it more
generic, we chose the word 'logger' which now replaces logsrv everywhere
it was used in the code (including related comments).
This is internal rewording, so no functional change should be expected
on user-side.
2023-09-11 09:06:53 -04:00
logger - > format = get_log_format ( args [ cur_arg + 1 ] ) ;
if ( logger - > format = = LOG_FORMAT_UNSPEC ) {
2018-03-26 09:54:32 -04:00
memprintf ( err , " unknown log format '%s' " , args [ cur_arg + 1 ] ) ;
goto error ;
}
cur_arg + = 2 ;
}
2019-04-24 10:14:33 -04:00
if ( strcmp ( args [ cur_arg ] , " sample " ) = = 0 ) {
unsigned low , high ;
char * p , * beg , * end , * smp_sz_str ;
size_t smp_rgs_sz = 0 , smp_sz = 0 , new_smp_sz ;
p = args [ cur_arg + 1 ] ;
smp_sz_str = strchr ( p , ' : ' ) ;
if ( ! smp_sz_str ) {
memprintf ( err , " Missing sample size " ) ;
goto error ;
}
* smp_sz_str + + = ' \0 ' ;
end = p + strlen ( p ) ;
while ( p ! = end ) {
MEDIUM: tree-wide: logsrv struct becomes logger
When 'log' directive was implemented, the internal representation was
named 'struct logsrv', because the 'log' directive would directly point
to the log target, which used to be a (UDP) log server exclusively at
that time, hence the name.
But things have become more complex, since today 'log' directive can point
to ring targets (implicit, or named) for example.
Indeed, a 'log' directive does no longer reference the "final" server to
which the log will be sent, but instead it describes which log API and
parameters to use for transporting the log messages to the proper log
destination.
So now the term 'logsrv' is rather confusing and prevents us from
introducing a new level of abstraction because they would be mixed
with logsrv.
So in order to better designate this 'log' directive, and make it more
generic, we chose the word 'logger' which now replaces logsrv everywhere
it was used in the code (including related comments).
This is internal rewording, so no functional change should be expected
on user-side.
2023-09-11 09:06:53 -04:00
if ( ! get_logger_smp_range ( & low , & high , & p , err ) )
2019-04-24 10:14:33 -04:00
goto error ;
if ( smp_rgs & & smp_log_ranges_overlap ( smp_rgs , smp_rgs_sz , low , high , err ) )
goto error ;
smp_rgs = my_realloc2 ( smp_rgs , ( smp_rgs_sz + 1 ) * sizeof * smp_rgs ) ;
if ( ! smp_rgs ) {
memprintf ( err , " out of memory error " ) ;
goto error ;
}
smp_rgs [ smp_rgs_sz ] . low = low ;
smp_rgs [ smp_rgs_sz ] . high = high ;
smp_rgs [ smp_rgs_sz ] . sz = high - low + 1 ;
if ( smp_rgs [ smp_rgs_sz ] . high > smp_sz )
smp_sz = smp_rgs [ smp_rgs_sz ] . high ;
smp_rgs_sz + + ;
}
2019-06-23 16:10:10 -04:00
if ( smp_rgs = = NULL ) {
memprintf ( err , " no sampling ranges given " ) ;
goto error ;
}
2019-04-24 10:14:33 -04:00
beg = smp_sz_str ;
end = beg + strlen ( beg ) ;
new_smp_sz = read_uint ( ( const char * * ) & beg , end ) ;
if ( ! new_smp_sz | | beg ! = end ) {
memprintf ( err , " wrong sample size '%s' for sample range '%s' " ,
smp_sz_str , args [ cur_arg + 1 ] ) ;
goto error ;
}
if ( new_smp_sz < smp_sz ) {
memprintf ( err , " sample size %zu should be greater or equal to "
" %zu the maximum of the high ranges limits " ,
new_smp_sz , smp_sz ) ;
goto error ;
}
smp_sz = new_smp_sz ;
/* Let's order <smp_rgs> array. */
qsort ( smp_rgs , smp_rgs_sz , sizeof ( struct smp_log_range ) , smp_log_range_cmp ) ;
MEDIUM: tree-wide: logsrv struct becomes logger
When 'log' directive was implemented, the internal representation was
named 'struct logsrv', because the 'log' directive would directly point
to the log target, which used to be a (UDP) log server exclusively at
that time, hence the name.
But things have become more complex, since today 'log' directive can point
to ring targets (implicit, or named) for example.
Indeed, a 'log' directive does no longer reference the "final" server to
which the log will be sent, but instead it describes which log API and
parameters to use for transporting the log messages to the proper log
destination.
So now the term 'logsrv' is rather confusing and prevents us from
introducing a new level of abstraction because they would be mixed
with logsrv.
So in order to better designate this 'log' directive, and make it more
generic, we chose the word 'logger' which now replaces logsrv everywhere
it was used in the code (including related comments).
This is internal rewording, so no functional change should be expected
on user-side.
2023-09-11 09:06:53 -04:00
logger - > lb . smp_rgs = smp_rgs ;
logger - > lb . smp_rgs_sz = smp_rgs_sz ;
logger - > lb . smp_sz = smp_sz ;
2019-04-24 10:14:33 -04:00
cur_arg + = 2 ;
}
MEDIUM: logs: atomically check and update the log sample index
The log server lock is pretty visible in perf top when using log samples
because it's taken for each server in turn while trying to validate and
update the log server's index. Let's change this for a CAS, since we have
the index and the range at hand now. This allow us to remove the logsrv
lock.
The test on 4 servers now shows a 3.7 times improvement thanks to much
lower contention. Without log sampling a test producing 4.4M logs/s
delivers 4.4M logs/s at 21 CPUs used, everything spent in the kernel.
After enabling 4 samples (1:4, 2:4, 3:4 and 4:4), the throughput would
previously drop to 1.13M log/s with 37 CPUs used and 75% spent in
process_send_log(). Now with this change, 4.25M logs/s are emitted,
using 26 CPUs and 22% in process_send_log(). That's a 3.7x throughput
improvement for a 30% global CPU usage reduction, but in practice it
mostly shows that the performance drop caused by having samples is much
less noticeable (each of the 4 servers has its index updated for each
log).
Note that in order to even avoid incrementing an index for each log srv
that is consulted, it would be more convenient to have a single index
per frontend and apply the modulus on each log server in turn to see if
the range has to be updated. It would then only perform one write per
range switch. However the place where this is done doesn't have access
to a frontend, so some changes would need to be performed for this, and
it would require to update the current range independently in each
logsrv, which is not necessarily easier since we don't know yet if we
can commit it.
2023-09-20 14:34:35 -04:00
2018-03-26 09:54:32 -04:00
/* parse the facility */
MEDIUM: tree-wide: logsrv struct becomes logger
When 'log' directive was implemented, the internal representation was
named 'struct logsrv', because the 'log' directive would directly point
to the log target, which used to be a (UDP) log server exclusively at
that time, hence the name.
But things have become more complex, since today 'log' directive can point
to ring targets (implicit, or named) for example.
Indeed, a 'log' directive does no longer reference the "final" server to
which the log will be sent, but instead it describes which log API and
parameters to use for transporting the log messages to the proper log
destination.
So now the term 'logsrv' is rather confusing and prevents us from
introducing a new level of abstraction because they would be mixed
with logsrv.
So in order to better designate this 'log' directive, and make it more
generic, we chose the word 'logger' which now replaces logsrv everywhere
it was used in the code (including related comments).
This is internal rewording, so no functional change should be expected
on user-side.
2023-09-11 09:06:53 -04:00
logger - > facility = get_log_facility ( args [ cur_arg ] ) ;
if ( logger - > facility < 0 ) {
2018-03-26 09:54:32 -04:00
memprintf ( err , " unknown log facility '%s' " , args [ cur_arg ] ) ;
goto error ;
}
cur_arg + + ;
/* parse the max syslog level (default: debug) */
MEDIUM: tree-wide: logsrv struct becomes logger
When 'log' directive was implemented, the internal representation was
named 'struct logsrv', because the 'log' directive would directly point
to the log target, which used to be a (UDP) log server exclusively at
that time, hence the name.
But things have become more complex, since today 'log' directive can point
to ring targets (implicit, or named) for example.
Indeed, a 'log' directive does no longer reference the "final" server to
which the log will be sent, but instead it describes which log API and
parameters to use for transporting the log messages to the proper log
destination.
So now the term 'logsrv' is rather confusing and prevents us from
introducing a new level of abstraction because they would be mixed
with logsrv.
So in order to better designate this 'log' directive, and make it more
generic, we chose the word 'logger' which now replaces logsrv everywhere
it was used in the code (including related comments).
This is internal rewording, so no functional change should be expected
on user-side.
2023-09-11 09:06:53 -04:00
logger - > level = 7 ;
2018-03-26 09:54:32 -04:00
if ( * ( args [ cur_arg ] ) ) {
MEDIUM: tree-wide: logsrv struct becomes logger
When 'log' directive was implemented, the internal representation was
named 'struct logsrv', because the 'log' directive would directly point
to the log target, which used to be a (UDP) log server exclusively at
that time, hence the name.
But things have become more complex, since today 'log' directive can point
to ring targets (implicit, or named) for example.
Indeed, a 'log' directive does no longer reference the "final" server to
which the log will be sent, but instead it describes which log API and
parameters to use for transporting the log messages to the proper log
destination.
So now the term 'logsrv' is rather confusing and prevents us from
introducing a new level of abstraction because they would be mixed
with logsrv.
So in order to better designate this 'log' directive, and make it more
generic, we chose the word 'logger' which now replaces logsrv everywhere
it was used in the code (including related comments).
This is internal rewording, so no functional change should be expected
on user-side.
2023-09-11 09:06:53 -04:00
logger - > level = get_log_level ( args [ cur_arg ] ) ;
if ( logger - > level < 0 ) {
2018-03-26 09:54:32 -04:00
memprintf ( err , " unknown optional log level '%s' " , args [ cur_arg ] ) ;
goto error ;
}
cur_arg + + ;
}
/* parse the limit syslog level (default: emerg) */
MEDIUM: tree-wide: logsrv struct becomes logger
When 'log' directive was implemented, the internal representation was
named 'struct logsrv', because the 'log' directive would directly point
to the log target, which used to be a (UDP) log server exclusively at
that time, hence the name.
But things have become more complex, since today 'log' directive can point
to ring targets (implicit, or named) for example.
Indeed, a 'log' directive does no longer reference the "final" server to
which the log will be sent, but instead it describes which log API and
parameters to use for transporting the log messages to the proper log
destination.
So now the term 'logsrv' is rather confusing and prevents us from
introducing a new level of abstraction because they would be mixed
with logsrv.
So in order to better designate this 'log' directive, and make it more
generic, we chose the word 'logger' which now replaces logsrv everywhere
it was used in the code (including related comments).
This is internal rewording, so no functional change should be expected
on user-side.
2023-09-11 09:06:53 -04:00
logger - > minlvl = 0 ;
2018-03-26 09:54:32 -04:00
if ( * ( args [ cur_arg ] ) ) {
MEDIUM: tree-wide: logsrv struct becomes logger
When 'log' directive was implemented, the internal representation was
named 'struct logsrv', because the 'log' directive would directly point
to the log target, which used to be a (UDP) log server exclusively at
that time, hence the name.
But things have become more complex, since today 'log' directive can point
to ring targets (implicit, or named) for example.
Indeed, a 'log' directive does no longer reference the "final" server to
which the log will be sent, but instead it describes which log API and
parameters to use for transporting the log messages to the proper log
destination.
So now the term 'logsrv' is rather confusing and prevents us from
introducing a new level of abstraction because they would be mixed
with logsrv.
So in order to better designate this 'log' directive, and make it more
generic, we chose the word 'logger' which now replaces logsrv everywhere
it was used in the code (including related comments).
This is internal rewording, so no functional change should be expected
on user-side.
2023-09-11 09:06:53 -04:00
logger - > minlvl = get_log_level ( args [ cur_arg ] ) ;
if ( logger - > minlvl < 0 ) {
2018-03-26 09:54:32 -04:00
memprintf ( err , " unknown optional minimum log level '%s' " , args [ cur_arg ] ) ;
goto error ;
}
cur_arg + + ;
}
/* Too many args */
if ( * ( args [ cur_arg ] ) ) {
memprintf ( err , " cannot handle unexpected argument '%s' " , args [ cur_arg ] ) ;
goto error ;
}
2023-09-11 10:10:37 -04:00
/* now, back to the log target */
if ( ! parse_log_target ( args [ 1 ] , & logger - > target , err ) )
2018-03-26 09:54:32 -04:00
goto error ;
2020-09-15 08:03:26 -04:00
2019-08-30 09:24:59 -04:00
done :
MEDIUM: tree-wide: logsrv struct becomes logger
When 'log' directive was implemented, the internal representation was
named 'struct logsrv', because the 'log' directive would directly point
to the log target, which used to be a (UDP) log server exclusively at
that time, hence the name.
But things have become more complex, since today 'log' directive can point
to ring targets (implicit, or named) for example.
Indeed, a 'log' directive does no longer reference the "final" server to
which the log will be sent, but instead it describes which log API and
parameters to use for transporting the log messages to the proper log
destination.
So now the term 'logsrv' is rather confusing and prevents us from
introducing a new level of abstraction because they would be mixed
with logsrv.
So in order to better designate this 'log' directive, and make it more
generic, we chose the word 'logger' which now replaces logsrv everywhere
it was used in the code (including related comments).
This is internal rewording, so no functional change should be expected
on user-side.
2023-09-11 09:06:53 -04:00
LIST_APPEND ( loggers , & logger - > list ) ;
2018-03-26 09:54:32 -04:00
return 1 ;
error :
2020-10-27 04:51:37 -04:00
free ( smp_rgs ) ;
MEDIUM: tree-wide: logsrv struct becomes logger
When 'log' directive was implemented, the internal representation was
named 'struct logsrv', because the 'log' directive would directly point
to the log target, which used to be a (UDP) log server exclusively at
that time, hence the name.
But things have become more complex, since today 'log' directive can point
to ring targets (implicit, or named) for example.
Indeed, a 'log' directive does no longer reference the "final" server to
which the log will be sent, but instead it describes which log API and
parameters to use for transporting the log messages to the proper log
destination.
So now the term 'logsrv' is rather confusing and prevents us from
introducing a new level of abstraction because they would be mixed
with logsrv.
So in order to better designate this 'log' directive, and make it more
generic, we chose the word 'logger' which now replaces logsrv everywhere
it was used in the code (including related comments).
This is internal rewording, so no functional change should be expected
on user-side.
2023-09-11 09:06:53 -04:00
free_logger ( logger ) ;
2018-03-26 09:54:32 -04:00
return 0 ;
}
2015-09-22 10:05:32 -04:00
/*
2020-07-06 09:54:06 -04:00
* returns log format , LOG_FORMAT_UNSPEC is return if not found .
2015-09-22 10:05:32 -04:00
*/
2020-07-06 09:54:06 -04:00
enum log_fmt get_log_format ( const char * fmt )
2015-09-22 10:05:32 -04:00
{
2020-07-06 09:54:06 -04:00
enum log_fmt format ;
2015-09-22 10:05:32 -04:00
format = LOG_FORMATS - 1 ;
2020-07-06 09:54:06 -04:00
while ( format > 0 & & log_formats [ format ] . name
CLEANUP: Compare the return value of `XXXcmp()` functions with zero
According to coding-style.txt it is recommended to use:
`strcmp(a, b) == 0` instead of `!strcmp(a, b)`
So let's do this.
The change was performed by running the following (very long) coccinelle patch
on src/:
@@
statement S;
expression E;
expression F;
@@
if (
(
dns_hostname_cmp
|
eb_memcmp
|
memcmp
|
strcasecmp
|
strcmp
|
strncasecmp
|
strncmp
)
- (E, F)
+ (E, F) != 0
)
(
S
|
{ ... }
)
@@
statement S;
expression E;
expression F;
@@
if (
- !
(
dns_hostname_cmp
|
eb_memcmp
|
memcmp
|
strcasecmp
|
strcmp
|
strncasecmp
|
strncmp
)
- (E, F)
+ (E, F) == 0
)
(
S
|
{ ... }
)
@@
expression E;
expression F;
expression G;
@@
(
G &&
(
dns_hostname_cmp
|
eb_memcmp
|
memcmp
|
strcasecmp
|
strcmp
|
strncasecmp
|
strncmp
)
- (E, F)
+ (E, F) != 0
)
@@
expression E;
expression F;
expression G;
@@
(
G ||
(
dns_hostname_cmp
|
eb_memcmp
|
memcmp
|
strcasecmp
|
strcmp
|
strncasecmp
|
strncmp
)
- (E, F)
+ (E, F) != 0
)
@@
expression E;
expression F;
expression G;
@@
(
(
dns_hostname_cmp
|
eb_memcmp
|
memcmp
|
strcasecmp
|
strcmp
|
strncasecmp
|
strncmp
)
- (E, F)
+ (E, F) != 0
&& G
)
@@
expression E;
expression F;
expression G;
@@
(
(
dns_hostname_cmp
|
eb_memcmp
|
memcmp
|
strcasecmp
|
strcmp
|
strncasecmp
|
strncmp
)
- (E, F)
+ (E, F) != 0
|| G
)
@@
expression E;
expression F;
expression G;
@@
(
G &&
- !
(
dns_hostname_cmp
|
eb_memcmp
|
memcmp
|
strcasecmp
|
strcmp
|
strncasecmp
|
strncmp
)
- (E, F)
+ (E, F) == 0
)
@@
expression E;
expression F;
expression G;
@@
(
G ||
- !
(
dns_hostname_cmp
|
eb_memcmp
|
memcmp
|
strcasecmp
|
strcmp
|
strncasecmp
|
strncmp
)
- (E, F)
+ (E, F) == 0
)
@@
expression E;
expression F;
expression G;
@@
(
- !
(
dns_hostname_cmp
|
eb_memcmp
|
memcmp
|
strcasecmp
|
strcmp
|
strncasecmp
|
strncmp
)
- (E, F)
+ (E, F) == 0
&& G
)
@@
expression E;
expression F;
expression G;
@@
(
- !
(
dns_hostname_cmp
|
eb_memcmp
|
memcmp
|
strcasecmp
|
strcmp
|
strncasecmp
|
strncmp
)
- (E, F)
+ (E, F) == 0
|| G
)
@@
expression E;
expression F;
expression G;
@@
(
- !
(
dns_hostname_cmp
|
eb_memcmp
|
memcmp
|
strcasecmp
|
strcmp
|
strncasecmp
|
strncmp
)
- (E, F)
+ (E, F) == 0
)
2021-01-02 16:31:53 -05:00
& & strcmp ( log_formats [ format ] . name , fmt ) ! = 0 )
2015-09-22 10:05:32 -04:00
format - - ;
2020-07-06 09:54:06 -04:00
/* Note: 0 is LOG_FORMAT_UNSPEC */
2015-09-22 10:05:32 -04:00
return format ;
}
2006-06-25 20:48:02 -04:00
/*
* returns log level for < lev > or - 1 if not found .
*/
int get_log_level ( const char * lev )
{
int level ;
level = NB_LOG_LEVELS - 1 ;
CLEANUP: Compare the return value of `XXXcmp()` functions with zero
According to coding-style.txt it is recommended to use:
`strcmp(a, b) == 0` instead of `!strcmp(a, b)`
So let's do this.
The change was performed by running the following (very long) coccinelle patch
on src/:
@@
statement S;
expression E;
expression F;
@@
if (
(
dns_hostname_cmp
|
eb_memcmp
|
memcmp
|
strcasecmp
|
strcmp
|
strncasecmp
|
strncmp
)
- (E, F)
+ (E, F) != 0
)
(
S
|
{ ... }
)
@@
statement S;
expression E;
expression F;
@@
if (
- !
(
dns_hostname_cmp
|
eb_memcmp
|
memcmp
|
strcasecmp
|
strcmp
|
strncasecmp
|
strncmp
)
- (E, F)
+ (E, F) == 0
)
(
S
|
{ ... }
)
@@
expression E;
expression F;
expression G;
@@
(
G &&
(
dns_hostname_cmp
|
eb_memcmp
|
memcmp
|
strcasecmp
|
strcmp
|
strncasecmp
|
strncmp
)
- (E, F)
+ (E, F) != 0
)
@@
expression E;
expression F;
expression G;
@@
(
G ||
(
dns_hostname_cmp
|
eb_memcmp
|
memcmp
|
strcasecmp
|
strcmp
|
strncasecmp
|
strncmp
)
- (E, F)
+ (E, F) != 0
)
@@
expression E;
expression F;
expression G;
@@
(
(
dns_hostname_cmp
|
eb_memcmp
|
memcmp
|
strcasecmp
|
strcmp
|
strncasecmp
|
strncmp
)
- (E, F)
+ (E, F) != 0
&& G
)
@@
expression E;
expression F;
expression G;
@@
(
(
dns_hostname_cmp
|
eb_memcmp
|
memcmp
|
strcasecmp
|
strcmp
|
strncasecmp
|
strncmp
)
- (E, F)
+ (E, F) != 0
|| G
)
@@
expression E;
expression F;
expression G;
@@
(
G &&
- !
(
dns_hostname_cmp
|
eb_memcmp
|
memcmp
|
strcasecmp
|
strcmp
|
strncasecmp
|
strncmp
)
- (E, F)
+ (E, F) == 0
)
@@
expression E;
expression F;
expression G;
@@
(
G ||
- !
(
dns_hostname_cmp
|
eb_memcmp
|
memcmp
|
strcasecmp
|
strcmp
|
strncasecmp
|
strncmp
)
- (E, F)
+ (E, F) == 0
)
@@
expression E;
expression F;
expression G;
@@
(
- !
(
dns_hostname_cmp
|
eb_memcmp
|
memcmp
|
strcasecmp
|
strcmp
|
strncasecmp
|
strncmp
)
- (E, F)
+ (E, F) == 0
&& G
)
@@
expression E;
expression F;
expression G;
@@
(
- !
(
dns_hostname_cmp
|
eb_memcmp
|
memcmp
|
strcasecmp
|
strcmp
|
strncasecmp
|
strncmp
)
- (E, F)
+ (E, F) == 0
|| G
)
@@
expression E;
expression F;
expression G;
@@
(
- !
(
dns_hostname_cmp
|
eb_memcmp
|
memcmp
|
strcasecmp
|
strcmp
|
strncasecmp
|
strncmp
)
- (E, F)
+ (E, F) == 0
)
2021-01-02 16:31:53 -05:00
while ( level > = 0 & & strcmp ( log_levels [ level ] , lev ) ! = 0 )
2006-06-25 20:48:02 -04:00
level - - ;
return level ;
}
/*
* returns log facility for < fac > or - 1 if not found .
*/
int get_log_facility ( const char * fac )
{
int facility ;
facility = NB_LOG_FACILITIES - 1 ;
CLEANUP: Compare the return value of `XXXcmp()` functions with zero
According to coding-style.txt it is recommended to use:
`strcmp(a, b) == 0` instead of `!strcmp(a, b)`
So let's do this.
The change was performed by running the following (very long) coccinelle patch
on src/:
@@
statement S;
expression E;
expression F;
@@
if (
(
dns_hostname_cmp
|
eb_memcmp
|
memcmp
|
strcasecmp
|
strcmp
|
strncasecmp
|
strncmp
)
- (E, F)
+ (E, F) != 0
)
(
S
|
{ ... }
)
@@
statement S;
expression E;
expression F;
@@
if (
- !
(
dns_hostname_cmp
|
eb_memcmp
|
memcmp
|
strcasecmp
|
strcmp
|
strncasecmp
|
strncmp
)
- (E, F)
+ (E, F) == 0
)
(
S
|
{ ... }
)
@@
expression E;
expression F;
expression G;
@@
(
G &&
(
dns_hostname_cmp
|
eb_memcmp
|
memcmp
|
strcasecmp
|
strcmp
|
strncasecmp
|
strncmp
)
- (E, F)
+ (E, F) != 0
)
@@
expression E;
expression F;
expression G;
@@
(
G ||
(
dns_hostname_cmp
|
eb_memcmp
|
memcmp
|
strcasecmp
|
strcmp
|
strncasecmp
|
strncmp
)
- (E, F)
+ (E, F) != 0
)
@@
expression E;
expression F;
expression G;
@@
(
(
dns_hostname_cmp
|
eb_memcmp
|
memcmp
|
strcasecmp
|
strcmp
|
strncasecmp
|
strncmp
)
- (E, F)
+ (E, F) != 0
&& G
)
@@
expression E;
expression F;
expression G;
@@
(
(
dns_hostname_cmp
|
eb_memcmp
|
memcmp
|
strcasecmp
|
strcmp
|
strncasecmp
|
strncmp
)
- (E, F)
+ (E, F) != 0
|| G
)
@@
expression E;
expression F;
expression G;
@@
(
G &&
- !
(
dns_hostname_cmp
|
eb_memcmp
|
memcmp
|
strcasecmp
|
strcmp
|
strncasecmp
|
strncmp
)
- (E, F)
+ (E, F) == 0
)
@@
expression E;
expression F;
expression G;
@@
(
G ||
- !
(
dns_hostname_cmp
|
eb_memcmp
|
memcmp
|
strcasecmp
|
strcmp
|
strncasecmp
|
strncmp
)
- (E, F)
+ (E, F) == 0
)
@@
expression E;
expression F;
expression G;
@@
(
- !
(
dns_hostname_cmp
|
eb_memcmp
|
memcmp
|
strcasecmp
|
strcmp
|
strncasecmp
|
strncmp
)
- (E, F)
+ (E, F) == 0
&& G
)
@@
expression E;
expression F;
expression G;
@@
(
- !
(
dns_hostname_cmp
|
eb_memcmp
|
memcmp
|
strcasecmp
|
strcmp
|
strncasecmp
|
strncmp
)
- (E, F)
+ (E, F) == 0
|| G
)
@@
expression E;
expression F;
expression G;
@@
(
- !
(
dns_hostname_cmp
|
eb_memcmp
|
memcmp
|
strcasecmp
|
strcmp
|
strncasecmp
|
strncmp
)
- (E, F)
+ (E, F) == 0
)
2021-01-02 16:31:53 -05:00
while ( facility > = 0 & & strcmp ( log_facilities [ facility ] , fac ) ! = 0 )
2006-06-25 20:48:02 -04:00
facility - - ;
2012-02-06 10:00:33 -05:00
2006-06-25 20:48:02 -04:00
return facility ;
}
2024-04-22 04:12:42 -04:00
struct lf_buildctx {
2024-05-02 10:48:56 -04:00
char _buf [ 256 ] ; /* fixed size buffer for building small strings */
int options ; /* LOG_OPT_* options */
int typecast ; /* same as logformat_node->typecast */
int in_text ; /* inside variable-length text */
2024-04-23 04:12:46 -04:00
union {
struct cbor_encode_ctx cbor ; /* cbor-encode specific ctx */
} encode ;
2024-04-22 04:12:42 -04:00
} ;
2024-05-02 09:30:17 -04:00
static THREAD_LOCAL struct lf_buildctx lf_buildctx ;
2024-04-23 04:12:46 -04:00
/* helper to encode a single byte in hex form
*
* Returns the position of the last written byte on success and NULL on
* error .
*/
static char * _encode_byte_hex ( char * start , char * stop , unsigned char byte )
{
/* hex form requires 2 bytes */
if ( ( stop - start ) < 2 )
return NULL ;
* start + + = hextab [ ( byte > > 4 ) & 15 ] ;
* start + + = hextab [ byte & 15 ] ;
return start ;
}
/* lf cbor function ptr used to encode a single byte according to RFC8949
*
* for now only hex form is supported .
*
2024-04-29 03:46:24 -04:00
* The function may only be called under CBOR context ( that is when
* LOG_OPT_ENCODE_CBOR option is set ) .
*
2024-04-23 04:12:46 -04:00
* Returns the position of the last written byte on success and NULL on
* error .
*/
static char * _lf_cbor_encode_byte ( struct cbor_encode_ctx * cbor_ctx ,
char * start , char * stop , unsigned char byte )
{
2024-04-29 03:46:24 -04:00
struct lf_buildctx * ctx ;
2024-04-30 02:55:13 -04:00
BUG_ON ( ! cbor_ctx | | ! cbor_ctx - > e_fct_ctx ) ;
2024-04-29 03:46:24 -04:00
ctx = cbor_ctx - > e_fct_ctx ;
2024-04-23 13:13:40 -04:00
if ( ctx - > options & LOG_OPT_BIN ) {
/* raw output */
if ( ( stop - start ) < 1 )
return NULL ;
* start + + = byte ;
return start ;
}
2024-04-23 04:12:46 -04:00
return _encode_byte_hex ( start , stop , byte ) ;
}
2024-04-22 04:12:42 -04:00
/* helper function to prepare lf_buildctx struct based on global options
* and current node settings ( may be NULL )
*/
static inline void lf_buildctx_prepare ( struct lf_buildctx * ctx ,
int g_options ,
const struct logformat_node * node )
{
if ( node ) {
2024-04-30 11:42:00 -04:00
/* consider node's options and typecast setting */
ctx - > options = node - > options ;
2024-04-25 12:52:57 -04:00
ctx - > typecast = node - > typecast ;
2024-04-22 04:12:42 -04:00
}
BUG/MEDIUM: log: don't ignore disabled node's options
In 3f2e8d0ed ("MEDIUM: log: lf_* build helpers now take a ctx argument")
I made a mistake, because starting with this commit it is no longer
possible from a node to disable global logformat options.
The result is that when an option is set globally, it cannot be disabled
anymore.
For instance, it is not possible to do this anymore:
log-format "%{+X}o %{-X}Ts"
The original intent was to prevent encoding options from being
disabled once enabled globally, because when encoding is enabled globally
we start the object enumeration right away (ie: in CBOR and JSON we
announce dynamic map, and for each node we announce the key..), thus it
doesn't make sense to mix encoding types there, unless encoding is only
used per-node, in which case only the value gets encoded, thus it remains
possible to print a value in JSON/CBOR-compatible format while the next
one shouldn't be printed as-is.
Thus, to restore the original behavior, slightly change the logic in
lf_buildctx_prepare() so that only global encoding options take the
precedence over node's options (instead of all options).
No backport needed.
2024-04-30 11:52:44 -04:00
else {
ctx - > options = g_options ;
ctx - > typecast = SMP_T_SAME ; /* default */
}
2024-04-22 08:40:04 -04:00
2024-04-30 11:42:00 -04:00
if ( ctx - > options & LOG_OPT_ENCODE_CBOR ) {
/* prepare cbor-specific encode ctx */
ctx - > encode . cbor . e_fct_byte = _lf_cbor_encode_byte ;
ctx - > encode . cbor . e_fct_ctx = ctx ;
2024-04-23 04:12:46 -04:00
}
2024-04-22 04:12:42 -04:00
}
2024-04-26 07:53:15 -04:00
/* helper function for _lf_encode_bytes() to escape a single byte
* with < escape >
*/
static inline char * _lf_escape_byte ( char * start , char * stop ,
char byte , const char escape )
{
if ( start + 3 > = stop )
return NULL ;
* start + + = escape ;
* start + + = hextab [ ( byte > > 4 ) & 15 ] ;
* start + + = hextab [ byte & 15 ] ;
return start ;
}
2024-04-23 04:12:46 -04:00
/* helper function for _lf_encode_bytes() to escape a single byte
* with < escape > and deal with cbor - specific encoding logic
*/
static inline char * _lf_cbor_escape_byte ( char * start , char * stop ,
char byte , const char escape ,
uint8_t cbor_string_prefix ,
struct lf_buildctx * ctx )
{
char escaped_byte [ 3 ] ;
escaped_byte [ 0 ] = escape ;
escaped_byte [ 1 ] = hextab [ ( byte > > 4 ) & 15 ] ;
escaped_byte [ 2 ] = hextab [ byte & 15 ] ;
start = cbor_encode_bytes_prefix ( & ctx - > encode . cbor , start , stop ,
escaped_byte , 3 ,
cbor_string_prefix ) ;
return start ;
}
2024-04-26 07:53:15 -04:00
/* helper function for _lf_encode_bytes() to encode a single byte
* and escape it with < escape > if found in < map >
*
* The function assumes that at least 1 byte is available for writing
*
* Returns the address of the last written byte on success , or NULL
* on error
*/
static inline char * _lf_map_escape_byte ( char * start , char * stop ,
const char * byte ,
const char escape , const long * map ,
2024-04-23 04:12:46 -04:00
const char * * pending , uint8_t cbor_string_prefix ,
2024-04-22 04:12:42 -04:00
struct lf_buildctx * ctx )
2024-04-26 07:53:15 -04:00
{
if ( ! ha_bit_test ( ( unsigned char ) ( * byte ) , map ) )
* start + + = * byte ;
else
start = _lf_escape_byte ( start , stop , * byte , escape ) ;
return start ;
}
2024-04-23 04:12:46 -04:00
/* helper function for _lf_encode_bytes() to encode a single byte
* and escape it with < escape > if found in < map > and deal with
* cbor - specific encoding logic .
*
* The function assumes that at least 1 byte is available for writing
*
* Returns the address of the last written byte on success , or NULL
* on error
*/
static inline char * _lf_cbor_map_escape_byte ( char * start , char * stop ,
const char * byte ,
const char escape , const long * map ,
const char * * pending , uint8_t cbor_string_prefix ,
struct lf_buildctx * ctx )
{
/* We try our best to minimize the number of chunks produced for the
* indefinite - length byte string as each chunk has an extra overhead
* as per RFC8949 .
*
* To achieve that , we try to emit consecutive bytes together
*/
if ( ! ha_bit_test ( ( unsigned char ) ( * byte ) , map ) ) {
/* do nothing and let the caller continue seeking data,
* pending data will be flushed later
*/
} else {
/* first, flush pending unescaped bytes */
start = cbor_encode_bytes_prefix ( & ctx - > encode . cbor , start , stop ,
* pending , ( byte - * pending ) ,
cbor_string_prefix ) ;
if ( start = = NULL )
return NULL ;
* pending = byte + 1 ;
/* escape current matching byte */
start = _lf_cbor_escape_byte ( start , stop , * byte , escape ,
cbor_string_prefix ,
ctx ) ;
}
return start ;
}
2024-04-26 07:53:15 -04:00
/* helper function for _lf_encode_bytes() to encode a single byte
* and escape it with < escape > if found in < map > or escape it with
* ' \ ' if found in rfc5424_escape_map
*
* The function assumes that at least 1 byte is available for writing
*
* Returns the address of the last written byte on success , or NULL
* on error
*/
static inline char * _lf_rfc5424_escape_byte ( char * start , char * stop ,
const char * byte ,
const char escape , const long * map ,
2024-04-23 04:12:46 -04:00
const char * * pending , uint8_t cbor_string_prefix ,
2024-04-22 04:12:42 -04:00
struct lf_buildctx * ctx )
2024-04-26 07:53:15 -04:00
{
if ( ! ha_bit_test ( ( unsigned char ) ( * byte ) , map ) ) {
if ( ! ha_bit_test ( ( unsigned char ) ( * byte ) , rfc5424_escape_map ) )
* start + + = * byte ;
else {
if ( start + 2 > = stop )
return NULL ;
* start + + = ' \\ ' ;
* start + + = * byte ;
}
}
else
start = _lf_escape_byte ( start , stop , * byte , escape ) ;
return start ;
}
2024-04-22 08:40:04 -04:00
/* helper function for _lf_encode_bytes() to encode a single byte
* and escape it with < escape > if found in < map > or escape it with
* ' \ ' if found in json_escape_map
*
* The function assumes that at least 1 byte is available for writing
*
* Returns the address of the last written byte on success , or NULL
* on error
*/
static inline char * _lf_json_escape_byte ( char * start , char * stop ,
const char * byte ,
const char escape , const long * map ,
2024-04-23 04:12:46 -04:00
const char * * pending , uint8_t cbor_string_prefix ,
2024-04-22 08:40:04 -04:00
struct lf_buildctx * ctx )
{
if ( ! ha_bit_test ( ( unsigned char ) ( * byte ) , map ) ) {
if ( ! ha_bit_test ( ( unsigned char ) ( * byte ) , json_escape_map ) )
* start + + = * byte ;
else {
if ( start + 2 > = stop )
return NULL ;
* start + + = ' \\ ' ;
* start + + = * byte ;
}
}
else
start = _lf_escape_byte ( start , stop , * byte , escape ) ;
return start ;
}
2016-02-12 07:23:03 -05:00
/*
2024-04-26 07:53:15 -04:00
* helper for lf_encode_ { string , chunk } :
* encode the input bytes , input < bytes > is processed until < bytes_stop >
* is reached . If < bytes_stop > is NULL , < bytes > is expected to be NULL
* terminated .
2016-02-12 07:23:03 -05:00
*
* When using the + E log format option , it will try to escape ' " \ ]'
* characters with ' \ ' as prefix . The same prefix should not be used as
* < escape > .
BUG/MINOR: tools/log: invalid encode_{chunk,string} usage
encode_{chunk,string}() is often found to be used this way:
ret = encode_{chunk,string}(start, stop...)
if (ret == NULL || *ret != '\0') {
//error
}
//success
Indeed, encode_{chunk,string} will always try to add terminating NULL byte
to the output string, unless no space is available for even 1 byte.
However, it means that for the caller to be able to spot an error, then it
must provide a buffer (here: start) which is already initialized.
But this is wrong: not only this is very tricky to use, but since those
functions don't return NULL on failure, then if the output buffer was not
properly initialized prior to calling the function, the caller will
perform invalid reads when checking for failure this way. Moreover, even
if the buffer is initialized, we cannot reliably tell if the function
actually failed this way because if the buffer was previously initialized
with NULL byte, then the caller might think that the call actually
succeeded (since the function didn't return NULL and didn't update the
buffer).
Also, sess_build_logline() relies lf_encode_{chunk,string}() functions
which are in fact wrappers for encode_{chunk,string}() functions and thus
exhibit the same error handling mechanism. It turns out that
sess_build_logline() makes unsafe use of those functions because it uses
the error-checking logic mentionned above while buffer (tmplog) is not
guaranteed to be initialized when entering the function. This may
ultimately cause malfunctions or invalid reads if the output buffer is
lacking space.
To fix the issue once and for all and prevent similar bugs from being
introduced, we make it so encode_{string, chunk} and escape_string()
(based on encode_string()) now explicitly return NULL on failure
(when the function failed to write at least the ending NULL byte)
lf_encode_{string,chunk}() helpers had to be patched as well due to code
duplication.
This should be backported to all stable versions.
[ada: for 2.4 and 2.6 the patch won't apply as-is, it might be helpful to
backport ae1e14d65 ("CLEANUP: tools: removing escape_chunk() function")
first, considering it's not very relevant to maintain a dead function]
2024-04-09 05:44:54 -04:00
*
2024-04-22 08:40:04 -04:00
* When using json encoding , string will be escaped according to
* json escape map
*
2024-04-23 04:12:46 -04:00
* When using cbor encoding , escape option is ignored . However bytes found
* in < map > will still be escaped with < escape > .
*
BUG/MINOR: tools/log: invalid encode_{chunk,string} usage
encode_{chunk,string}() is often found to be used this way:
ret = encode_{chunk,string}(start, stop...)
if (ret == NULL || *ret != '\0') {
//error
}
//success
Indeed, encode_{chunk,string} will always try to add terminating NULL byte
to the output string, unless no space is available for even 1 byte.
However, it means that for the caller to be able to spot an error, then it
must provide a buffer (here: start) which is already initialized.
But this is wrong: not only this is very tricky to use, but since those
functions don't return NULL on failure, then if the output buffer was not
properly initialized prior to calling the function, the caller will
perform invalid reads when checking for failure this way. Moreover, even
if the buffer is initialized, we cannot reliably tell if the function
actually failed this way because if the buffer was previously initialized
with NULL byte, then the caller might think that the call actually
succeeded (since the function didn't return NULL and didn't update the
buffer).
Also, sess_build_logline() relies lf_encode_{chunk,string}() functions
which are in fact wrappers for encode_{chunk,string}() functions and thus
exhibit the same error handling mechanism. It turns out that
sess_build_logline() makes unsafe use of those functions because it uses
the error-checking logic mentionned above while buffer (tmplog) is not
guaranteed to be initialized when entering the function. This may
ultimately cause malfunctions or invalid reads if the output buffer is
lacking space.
To fix the issue once and for all and prevent similar bugs from being
introduced, we make it so encode_{string, chunk} and escape_string()
(based on encode_string()) now explicitly return NULL on failure
(when the function failed to write at least the ending NULL byte)
lf_encode_{string,chunk}() helpers had to be patched as well due to code
duplication.
This should be backported to all stable versions.
[ada: for 2.4 and 2.6 the patch won't apply as-is, it might be helpful to
backport ae1e14d65 ("CLEANUP: tools: removing escape_chunk() function")
first, considering it's not very relevant to maintain a dead function]
2024-04-09 05:44:54 -04:00
* Return the address of the \ 0 character , or NULL on error
2016-02-12 07:23:03 -05:00
*/
2024-04-26 07:53:15 -04:00
static char * _lf_encode_bytes ( char * start , char * stop ,
2019-06-07 05:10:07 -04:00
const char escape , const long * map ,
2024-04-26 07:53:15 -04:00
const char * bytes , const char * bytes_stop ,
2024-04-22 04:12:42 -04:00
struct lf_buildctx * ctx )
2016-02-12 07:23:03 -05:00
{
2024-04-26 07:53:15 -04:00
char * ret ;
2024-04-23 04:12:46 -04:00
const char * pending ;
uint8_t cbor_string_prefix = 0 ;
2024-04-26 07:53:15 -04:00
char * ( * encode_byte ) ( char * start , char * stop ,
const char * byte ,
const char escape , const long * map ,
2024-04-23 04:12:46 -04:00
const char * * pending , uint8_t cbor_string_prefix ,
2024-04-22 04:12:42 -04:00
struct lf_buildctx * ctx ) ;
2024-04-26 07:53:15 -04:00
2024-04-22 08:40:04 -04:00
if ( ctx - > options & LOG_OPT_ENCODE_JSON )
encode_byte = _lf_json_escape_byte ;
2024-04-23 04:12:46 -04:00
else if ( ctx - > options & LOG_OPT_ENCODE_CBOR )
encode_byte = _lf_cbor_map_escape_byte ;
2024-04-22 08:40:04 -04:00
else if ( ctx - > options & LOG_OPT_ESC )
2024-04-26 07:53:15 -04:00
encode_byte = _lf_rfc5424_escape_byte ;
else
encode_byte = _lf_map_escape_byte ;
2024-04-23 04:12:46 -04:00
if ( ctx - > options & LOG_OPT_ENCODE_CBOR ) {
if ( ! bytes_stop ) {
/* printable chars: use cbor text */
cbor_string_prefix = 0x60 ;
}
else {
/* non printable chars: use cbor byte string */
cbor_string_prefix = 0x40 ;
}
}
2024-04-26 07:53:15 -04:00
if ( start < stop ) {
stop - - ; /* reserve one byte for the final '\0' */
2024-04-23 04:12:46 -04:00
if ( ( ctx - > options & LOG_OPT_ENCODE_CBOR ) & & ! ctx - > in_text ) {
/* start indefinite-length cbor byte string or text */
start = _lf_cbor_encode_byte ( & ctx - > encode . cbor , start , stop ,
( cbor_string_prefix | 0x1F ) ) ;
if ( start = = NULL )
return NULL ;
}
pending = bytes ;
2024-04-26 07:53:15 -04:00
/* we have 2 distinct loops to keep checks outside of the loop
* for better performance
*/
if ( bytes & & ! bytes_stop ) {
while ( start < stop & & * bytes ! = ' \0 ' ) {
2024-04-23 04:12:46 -04:00
ret = encode_byte ( start , stop , bytes , escape , map ,
& pending , cbor_string_prefix ,
ctx ) ;
2024-04-26 07:53:15 -04:00
if ( ret = = NULL )
break ;
start = ret ;
bytes + + ;
}
} else if ( bytes ) {
while ( start < stop & & bytes < bytes_stop ) {
2024-04-23 04:12:46 -04:00
ret = encode_byte ( start , stop , bytes , escape , map ,
& pending , cbor_string_prefix ,
ctx ) ;
2024-04-26 07:53:15 -04:00
if ( ret = = NULL )
break ;
start = ret ;
bytes + + ;
2016-02-12 07:23:03 -05:00
}
}
2024-04-23 04:12:46 -04:00
if ( ctx - > options & LOG_OPT_ENCODE_CBOR ) {
if ( pending ! = bytes ) {
/* flush pending unescaped bytes */
start = cbor_encode_bytes_prefix ( & ctx - > encode . cbor , start , stop ,
pending , ( bytes - pending ) ,
cbor_string_prefix ) ;
if ( start = = NULL )
return NULL ;
}
if ( ! ctx - > in_text ) {
/* cbor break (to end indefinite-length text or byte string) */
start = _lf_cbor_encode_byte ( & ctx - > encode . cbor , start , stop , 0xFF ) ;
if ( start = = NULL )
return NULL ;
}
}
2024-04-26 07:53:15 -04:00
* start = ' \0 ' ;
return start ;
2016-02-12 07:23:03 -05:00
}
BUG/MINOR: tools/log: invalid encode_{chunk,string} usage
encode_{chunk,string}() is often found to be used this way:
ret = encode_{chunk,string}(start, stop...)
if (ret == NULL || *ret != '\0') {
//error
}
//success
Indeed, encode_{chunk,string} will always try to add terminating NULL byte
to the output string, unless no space is available for even 1 byte.
However, it means that for the caller to be able to spot an error, then it
must provide a buffer (here: start) which is already initialized.
But this is wrong: not only this is very tricky to use, but since those
functions don't return NULL on failure, then if the output buffer was not
properly initialized prior to calling the function, the caller will
perform invalid reads when checking for failure this way. Moreover, even
if the buffer is initialized, we cannot reliably tell if the function
actually failed this way because if the buffer was previously initialized
with NULL byte, then the caller might think that the call actually
succeeded (since the function didn't return NULL and didn't update the
buffer).
Also, sess_build_logline() relies lf_encode_{chunk,string}() functions
which are in fact wrappers for encode_{chunk,string}() functions and thus
exhibit the same error handling mechanism. It turns out that
sess_build_logline() makes unsafe use of those functions because it uses
the error-checking logic mentionned above while buffer (tmplog) is not
guaranteed to be initialized when entering the function. This may
ultimately cause malfunctions or invalid reads if the output buffer is
lacking space.
To fix the issue once and for all and prevent similar bugs from being
introduced, we make it so encode_{string, chunk} and escape_string()
(based on encode_string()) now explicitly return NULL on failure
(when the function failed to write at least the ending NULL byte)
lf_encode_{string,chunk}() helpers had to be patched as well due to code
duplication.
This should be backported to all stable versions.
[ada: for 2.4 and 2.6 the patch won't apply as-is, it might be helpful to
backport ae1e14d65 ("CLEANUP: tools: removing escape_chunk() function")
first, considering it's not very relevant to maintain a dead function]
2024-04-09 05:44:54 -04:00
return NULL ;
2016-02-12 07:23:03 -05:00
}
2024-04-26 07:53:15 -04:00
/*
* Encode the string .
*/
static char * lf_encode_string ( char * start , char * stop ,
const char escape , const long * map ,
const char * string ,
2024-04-22 04:12:42 -04:00
struct lf_buildctx * ctx )
2024-04-26 07:53:15 -04:00
{
return _lf_encode_bytes ( start , stop , escape , map ,
2024-04-22 04:12:42 -04:00
string , NULL , ctx ) ;
2024-04-26 07:53:15 -04:00
}
2016-02-12 07:23:03 -05:00
/*
* Encode the chunk .
*/
static char * lf_encode_chunk ( char * start , char * stop ,
2019-06-07 05:10:07 -04:00
const char escape , const long * map ,
2018-07-13 05:56:34 -04:00
const struct buffer * chunk ,
2024-04-22 04:12:42 -04:00
struct lf_buildctx * ctx )
2016-02-12 07:23:03 -05:00
{
2024-04-26 07:53:15 -04:00
return _lf_encode_bytes ( start , stop , escape , map ,
chunk - > area , chunk - > area + chunk - > data ,
2024-04-22 04:12:42 -04:00
ctx ) ;
2016-02-12 07:23:03 -05:00
}
2012-02-08 10:38:44 -05:00
/*
2024-04-10 06:07:26 -04:00
* Write a raw string in the log string
* Take care of escape option
2012-02-08 10:38:44 -05:00
*
2024-04-22 08:40:04 -04:00
* When using json encoding , string will be escaped according
* to json escape map
*
2024-04-23 04:12:46 -04:00
* When using cbor encoding , escape option is ignored .
*
2018-11-15 15:10:04 -05:00
* Return the address of the \ 0 character , or NULL on error
2012-02-08 10:38:44 -05:00
*/
2024-04-10 06:07:26 -04:00
static inline char * _lf_text_len ( char * dst , const char * src ,
2024-04-22 04:12:42 -04:00
size_t len , size_t size , struct lf_buildctx * ctx )
2012-02-08 10:38:44 -05:00
{
2024-04-22 08:40:04 -04:00
const long * escape_map = NULL ;
2024-04-23 04:12:46 -04:00
char * ret ;
2024-04-22 08:40:04 -04:00
if ( ctx - > options & LOG_OPT_ENCODE_JSON )
escape_map = json_escape_map ;
else if ( ctx - > options & LOG_OPT_ESC )
escape_map = rfc5424_escape_map ;
2013-02-05 12:52:25 -05:00
if ( src & & len ) {
2024-04-23 04:12:46 -04:00
if ( ctx - > options & LOG_OPT_ENCODE_CBOR ) {
/* it's actually less costly to compute the actual text size to
* write a single fixed length text at once rather than emitting
* indefinite length text in cbor , because indefinite - length text
* has to be made of multiple chunks of known size as per RFC8949 . . .
*/
2024-05-17 04:24:33 -04:00
{
int _len ;
/* strnlen(src, len) portable equivalent: */
for ( _len = 0 ; _len < len & & src [ _len ] ; _len + + )
;
len = _len ;
}
2024-04-23 04:12:46 -04:00
ret = cbor_encode_text ( & ctx - > encode . cbor , dst , dst + size , src , len ) ;
if ( ret = = NULL )
return NULL ;
len = ret - dst ;
}
2022-09-20 08:33:18 -04:00
/* escape_string and strlcpy2 will both try to add terminating NULL-byte
2024-04-09 05:15:23 -04:00
* to dst
2022-09-20 08:33:18 -04:00
*/
2024-04-23 04:12:46 -04:00
else if ( escape_map ) {
2016-02-12 07:23:03 -05:00
char * ret ;
2024-04-22 08:40:04 -04:00
ret = escape_string ( dst , dst + size , ' \\ ' , escape_map , src , src + len ) ;
2024-04-09 11:54:41 -04:00
if ( ret = = NULL )
2016-02-12 07:23:03 -05:00
return NULL ;
len = ret - dst ;
}
else {
2022-09-20 08:33:18 -04:00
if ( + + len > size )
len = size ;
2016-02-12 07:23:03 -05:00
len = strlcpy2 ( dst , src , len ) ;
2024-04-10 06:07:26 -04:00
if ( len = = 0 )
return NULL ;
2016-02-12 07:23:03 -05:00
}
2012-12-21 13:23:44 -05:00
dst + = len ;
2024-04-10 06:07:26 -04:00
size - = len ;
2012-12-21 13:23:44 -05:00
}
2024-04-10 06:07:26 -04:00
if ( size < 1 )
return NULL ;
* dst = ' \0 ' ;
return dst ;
}
/*
* Quote a string , then leverage _lf_text_len ( ) to write it
*/
static inline char * _lf_quotetext_len ( char * dst , const char * src ,
2024-04-22 04:12:42 -04:00
size_t len , size_t size , struct lf_buildctx * ctx )
2024-04-10 06:07:26 -04:00
{
if ( size < 2 )
return NULL ;
* ( dst + + ) = ' " ' ;
size - - ;
if ( src & & len ) {
char * ret ;
2024-04-22 04:12:42 -04:00
ret = _lf_text_len ( dst , src , len , size , ctx ) ;
2024-04-10 06:07:26 -04:00
if ( ret = = NULL )
2012-12-21 13:23:44 -05:00
return NULL ;
2024-04-10 06:07:26 -04:00
size - = ( ret - dst ) ;
dst + = ( ret - dst ) ;
2012-12-21 13:23:44 -05:00
}
2024-04-10 06:07:26 -04:00
if ( size < 2 )
return NULL ;
* ( dst + + ) = ' " ' ;
* dst = ' \0 ' ;
return dst ;
}
/*
* Write a string in the log string
2024-04-22 08:40:04 -04:00
* Take care of quote , mandatory and escape and encoding options
2024-04-10 06:07:26 -04:00
*
* Return the address of the \ 0 character , or NULL on error
*/
2024-04-22 04:12:42 -04:00
static char * lf_text_len ( char * dst , const char * src , size_t len , size_t size , struct lf_buildctx * ctx )
2024-04-10 06:07:26 -04:00
{
2024-04-22 08:40:04 -04:00
if ( ( ctx - > options & ( LOG_OPT_QUOTE | LOG_OPT_ENCODE_JSON ) ) )
2024-04-22 04:12:42 -04:00
return _lf_quotetext_len ( dst , src , len , size , ctx ) ;
2024-04-23 04:12:46 -04:00
else if ( ( ctx - > options & LOG_OPT_ENCODE_CBOR ) | |
( src & & len ) )
2024-04-22 04:12:42 -04:00
return _lf_text_len ( dst , src , len , size , ctx ) ;
2024-04-10 06:07:26 -04:00
if ( size < 2 )
return NULL ;
2024-04-22 04:12:42 -04:00
if ( ( ctx - > options & LOG_OPT_MANDATORY ) )
return _lf_text_len ( dst , " - " , 1 , size , ctx ) ;
2024-04-10 06:07:26 -04:00
2012-12-21 13:23:44 -05:00
* dst = ' \0 ' ;
2024-04-10 06:07:26 -04:00
2012-02-27 05:23:10 -05:00
return dst ;
2012-02-08 10:38:44 -05:00
}
2024-04-10 06:07:26 -04:00
/*
* Same as lf_text_len ( ) except that it ignores mandatory and quoting options .
* Quoting is only performed when strictly required by the encoding method .
*/
2024-04-22 04:12:42 -04:00
static char * lf_rawtext_len ( char * dst , const char * src , size_t len , size_t size , struct lf_buildctx * ctx )
2024-04-10 06:07:26 -04:00
{
2024-04-22 08:40:04 -04:00
if ( ! ctx - > in_text & &
( ctx - > options & LOG_OPT_ENCODE_JSON ) )
return _lf_quotetext_len ( dst , src , len , size , ctx ) ;
2024-04-22 04:12:42 -04:00
return _lf_text_len ( dst , src , len , size , ctx ) ;
2024-04-10 06:07:26 -04:00
}
/* lf_text_len() helper when <src> is null-byte terminated */
2024-04-22 04:12:42 -04:00
static inline char * lf_text ( char * dst , const char * src , size_t size , struct lf_buildctx * ctx )
2012-12-21 13:23:44 -05:00
{
2024-04-22 04:12:42 -04:00
return lf_text_len ( dst , src , size , size , ctx ) ;
2012-12-21 13:23:44 -05:00
}
2024-04-10 06:07:26 -04:00
/* lf_rawtext_len() helper when <src> is null-byte terminated */
2024-04-22 04:12:42 -04:00
static inline char * lf_rawtext ( char * dst , const char * src , size_t size , struct lf_buildctx * ctx )
2024-04-10 06:07:26 -04:00
{
2024-04-22 04:12:42 -04:00
return lf_rawtext_len ( dst , src , size , size , ctx ) ;
2024-04-10 06:07:26 -04:00
}
2012-04-05 12:02:55 -04:00
/*
2018-11-15 15:10:04 -05:00
* Write a IP address to the log string
2020-04-16 14:51:34 -04:00
* + X option write in hexadecimal notation , most significant byte on the left
2012-04-05 12:02:55 -04:00
*/
2024-04-22 04:12:42 -04:00
static char * lf_ip ( char * dst , const struct sockaddr * sockaddr , size_t size , struct lf_buildctx * ctx )
2012-04-05 12:02:55 -04:00
{
char * ret = dst ;
int iret ;
char pn [ INET6_ADDRSTRLEN ] ;
2024-04-22 04:12:42 -04:00
if ( ctx - > options & LOG_OPT_HEXA ) {
BUG/MINOR: log: properly format IPv6 address when LOG_OPT_HEXA modifier is used.
In lf_ip(), when LOG_OPT_HEXA modifier is used, there is a code to format the
IP address as a hexadecimal string. This code does not properly handle cases
when the IP address is IPv6. In such case, the code only prints `00000000`.
This patch adds support for IPv6. For legacy IPv4, the format remains
unchanged. If IPv6 socket is used to accept IPv6 connection, the full IPv6
address is returned. For example, IPv6 localhost, ::1, is printed as
00000000000000000000000000000001.
If IPv6 socket accepts IPv4 connection, the IPv4 address is mapped by the
kernel into the IPv4-mapped-IPv6 address space (RFC4291, section 2.5.5.2)
and is formatted as such. For example, 127.0.0.1 becomes ::ffff:127.0.0.1,
which is printed as 00000000000000000000FFFF7F000001.
This should be backported to 1.9.
2019-03-22 06:21:54 -04:00
unsigned char * addr = NULL ;
switch ( sockaddr - > sa_family ) {
case AF_INET :
2024-04-03 09:42:35 -04:00
{
BUG/MINOR: log: properly format IPv6 address when LOG_OPT_HEXA modifier is used.
In lf_ip(), when LOG_OPT_HEXA modifier is used, there is a code to format the
IP address as a hexadecimal string. This code does not properly handle cases
when the IP address is IPv6. In such case, the code only prints `00000000`.
This patch adds support for IPv6. For legacy IPv4, the format remains
unchanged. If IPv6 socket is used to accept IPv6 connection, the full IPv6
address is returned. For example, IPv6 localhost, ::1, is printed as
00000000000000000000000000000001.
If IPv6 socket accepts IPv4 connection, the IPv4 address is mapped by the
kernel into the IPv4-mapped-IPv6 address space (RFC4291, section 2.5.5.2)
and is formatted as such. For example, 127.0.0.1 becomes ::ffff:127.0.0.1,
which is printed as 00000000000000000000FFFF7F000001.
This should be backported to 1.9.
2019-03-22 06:21:54 -04:00
addr = ( unsigned char * ) & ( ( struct sockaddr_in * ) sockaddr ) - > sin_addr . s_addr ;
2024-05-02 10:48:56 -04:00
iret = snprintf ( ctx - > _buf , sizeof ( ctx - > _buf ) , " %02X%02X%02X%02X " ,
2024-04-03 09:42:35 -04:00
addr [ 0 ] , addr [ 1 ] , addr [ 2 ] , addr [ 3 ] ) ;
if ( iret < 0 | | iret > = size )
return NULL ;
2024-05-02 10:48:56 -04:00
ret = lf_rawtext ( dst , ctx - > _buf , size , ctx ) ;
2024-04-03 09:42:35 -04:00
BUG/MINOR: log: properly format IPv6 address when LOG_OPT_HEXA modifier is used.
In lf_ip(), when LOG_OPT_HEXA modifier is used, there is a code to format the
IP address as a hexadecimal string. This code does not properly handle cases
when the IP address is IPv6. In such case, the code only prints `00000000`.
This patch adds support for IPv6. For legacy IPv4, the format remains
unchanged. If IPv6 socket is used to accept IPv6 connection, the full IPv6
address is returned. For example, IPv6 localhost, ::1, is printed as
00000000000000000000000000000001.
If IPv6 socket accepts IPv4 connection, the IPv4 address is mapped by the
kernel into the IPv4-mapped-IPv6 address space (RFC4291, section 2.5.5.2)
and is formatted as such. For example, 127.0.0.1 becomes ::ffff:127.0.0.1,
which is printed as 00000000000000000000FFFF7F000001.
This should be backported to 1.9.
2019-03-22 06:21:54 -04:00
break ;
2024-04-03 09:42:35 -04:00
}
BUG/MINOR: log: properly format IPv6 address when LOG_OPT_HEXA modifier is used.
In lf_ip(), when LOG_OPT_HEXA modifier is used, there is a code to format the
IP address as a hexadecimal string. This code does not properly handle cases
when the IP address is IPv6. In such case, the code only prints `00000000`.
This patch adds support for IPv6. For legacy IPv4, the format remains
unchanged. If IPv6 socket is used to accept IPv6 connection, the full IPv6
address is returned. For example, IPv6 localhost, ::1, is printed as
00000000000000000000000000000001.
If IPv6 socket accepts IPv4 connection, the IPv4 address is mapped by the
kernel into the IPv4-mapped-IPv6 address space (RFC4291, section 2.5.5.2)
and is formatted as such. For example, 127.0.0.1 becomes ::ffff:127.0.0.1,
which is printed as 00000000000000000000FFFF7F000001.
This should be backported to 1.9.
2019-03-22 06:21:54 -04:00
case AF_INET6 :
2024-04-03 09:42:35 -04:00
{
BUG/MINOR: log: properly format IPv6 address when LOG_OPT_HEXA modifier is used.
In lf_ip(), when LOG_OPT_HEXA modifier is used, there is a code to format the
IP address as a hexadecimal string. This code does not properly handle cases
when the IP address is IPv6. In such case, the code only prints `00000000`.
This patch adds support for IPv6. For legacy IPv4, the format remains
unchanged. If IPv6 socket is used to accept IPv6 connection, the full IPv6
address is returned. For example, IPv6 localhost, ::1, is printed as
00000000000000000000000000000001.
If IPv6 socket accepts IPv4 connection, the IPv4 address is mapped by the
kernel into the IPv4-mapped-IPv6 address space (RFC4291, section 2.5.5.2)
and is formatted as such. For example, 127.0.0.1 becomes ::ffff:127.0.0.1,
which is printed as 00000000000000000000FFFF7F000001.
This should be backported to 1.9.
2019-03-22 06:21:54 -04:00
addr = ( unsigned char * ) & ( ( struct sockaddr_in6 * ) sockaddr ) - > sin6_addr . s6_addr ;
2024-05-02 10:48:56 -04:00
iret = snprintf ( ctx - > _buf , sizeof ( ctx - > _buf ) ,
2024-04-03 09:42:35 -04:00
" %02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X " ,
addr [ 0 ] , addr [ 1 ] , addr [ 2 ] , addr [ 3 ] ,
addr [ 4 ] , addr [ 5 ] , addr [ 6 ] , addr [ 7 ] ,
addr [ 8 ] , addr [ 9 ] , addr [ 10 ] , addr [ 11 ] ,
addr [ 12 ] , addr [ 13 ] , addr [ 14 ] , addr [ 15 ] ) ;
if ( iret < 0 | | iret > = size )
return NULL ;
2024-05-02 10:48:56 -04:00
ret = lf_rawtext ( dst , ctx - > _buf , size , ctx ) ;
2024-04-03 09:42:35 -04:00
BUG/MINOR: log: properly format IPv6 address when LOG_OPT_HEXA modifier is used.
In lf_ip(), when LOG_OPT_HEXA modifier is used, there is a code to format the
IP address as a hexadecimal string. This code does not properly handle cases
when the IP address is IPv6. In such case, the code only prints `00000000`.
This patch adds support for IPv6. For legacy IPv4, the format remains
unchanged. If IPv6 socket is used to accept IPv6 connection, the full IPv6
address is returned. For example, IPv6 localhost, ::1, is printed as
00000000000000000000000000000001.
If IPv6 socket accepts IPv4 connection, the IPv4 address is mapped by the
kernel into the IPv4-mapped-IPv6 address space (RFC4291, section 2.5.5.2)
and is formatted as such. For example, 127.0.0.1 becomes ::ffff:127.0.0.1,
which is printed as 00000000000000000000FFFF7F000001.
This should be backported to 1.9.
2019-03-22 06:21:54 -04:00
break ;
2024-04-03 09:42:35 -04:00
}
BUG/MINOR: log: properly format IPv6 address when LOG_OPT_HEXA modifier is used.
In lf_ip(), when LOG_OPT_HEXA modifier is used, there is a code to format the
IP address as a hexadecimal string. This code does not properly handle cases
when the IP address is IPv6. In such case, the code only prints `00000000`.
This patch adds support for IPv6. For legacy IPv4, the format remains
unchanged. If IPv6 socket is used to accept IPv6 connection, the full IPv6
address is returned. For example, IPv6 localhost, ::1, is printed as
00000000000000000000000000000001.
If IPv6 socket accepts IPv4 connection, the IPv4 address is mapped by the
kernel into the IPv4-mapped-IPv6 address space (RFC4291, section 2.5.5.2)
and is formatted as such. For example, 127.0.0.1 becomes ::ffff:127.0.0.1,
which is printed as 00000000000000000000FFFF7F000001.
This should be backported to 1.9.
2019-03-22 06:21:54 -04:00
default :
return NULL ;
}
2012-04-05 12:02:55 -04:00
} else {
addr_to_str ( ( struct sockaddr_storage * ) sockaddr , pn , sizeof ( pn ) ) ;
2024-04-22 04:12:42 -04:00
ret = lf_text ( dst , pn , size , ctx ) ;
2012-04-05 12:02:55 -04:00
}
return ret ;
}
2024-04-22 08:40:04 -04:00
/* Logformat expr wrapper to write a boolean according to node
* encoding settings
*/
static char * lf_bool_encode ( char * dst , size_t size , uint8_t value ,
struct lf_buildctx * ctx )
{
/* encode as a regular bool value */
if ( ctx - > options & LOG_OPT_ENCODE_JSON ) {
char * ret = dst ;
int iret ;
if ( value )
iret = snprintf ( dst , size , " true " ) ;
else
iret = snprintf ( dst , size , " false " ) ;
if ( iret < 0 | | iret > = size )
return NULL ;
ret + = iret ;
return ret ;
}
2024-04-23 04:12:46 -04:00
if ( ctx - > options & LOG_OPT_ENCODE_CBOR ) {
if ( value )
return _lf_cbor_encode_byte ( & ctx - > encode . cbor , dst , dst + size , 0xF5 ) ;
return _lf_cbor_encode_byte ( & ctx - > encode . cbor , dst , dst + size , 0xF4 ) ;
}
2024-04-22 08:40:04 -04:00
return NULL ; /* not supported */
}
/* Logformat expr wrapper to write an integer according to node
* encoding settings and typecast settings .
*/
static char * lf_int_encode ( char * dst , size_t size , int64_t value ,
struct lf_buildctx * ctx )
{
if ( ctx - > typecast = = SMP_T_BOOL ) {
/* either true or false */
return lf_bool_encode ( dst , size , ! ! value , ctx ) ;
}
if ( ctx - > options & LOG_OPT_ENCODE_JSON ) {
char * ret = dst ;
int iret = 0 ;
if ( ctx - > typecast = = SMP_T_STR ) {
/* encode as a string number (base10 with "quotes"):
* may be useful to work around the limited resolution
* of JS number types for instance
*/
iret = snprintf ( dst , size , " \" %lld \" " , ( long long int ) value ) ;
}
else {
/* encode as a regular int64 number (base10) */
iret = snprintf ( dst , size , " %lld " , ( long long int ) value ) ;
}
if ( iret < 0 | | iret > = size )
return NULL ;
ret + = iret ;
return ret ;
}
2024-04-23 04:12:46 -04:00
else if ( ctx - > options & LOG_OPT_ENCODE_CBOR ) {
/* Always print as a regular int64 number (STR typecast isn't
* supported )
*/
return cbor_encode_int64 ( & ctx - > encode . cbor , dst , dst + size , value ) ;
}
2024-04-22 08:40:04 -04:00
return NULL ; /* not supported */
}
2024-03-27 05:17:11 -04:00
enum lf_int_hdl {
LF_INT_LTOA = 0 ,
LF_INT_LLTOA ,
LF_INT_ULTOA ,
LF_INT_UTOA_PAD_4 ,
} ;
/*
* Logformat expr wrapper to write an integer , uses < dft_hdl > to know
2024-04-22 08:40:04 -04:00
* how to encode the value by default ( if no encoding is used )
2024-03-27 05:17:11 -04:00
*/
static inline char * lf_int ( char * dst , size_t size , int64_t value ,
2024-04-22 04:12:42 -04:00
struct lf_buildctx * ctx ,
2024-03-27 05:17:11 -04:00
enum lf_int_hdl dft_hdl )
{
2024-04-22 08:40:04 -04:00
if ( ctx - > options & LOG_OPT_ENCODE )
return lf_int_encode ( dst , size , value , ctx ) ;
2024-03-27 05:17:11 -04:00
switch ( dft_hdl ) {
case LF_INT_LTOA :
return ltoa_o ( value , dst , size ) ;
case LF_INT_LLTOA :
return lltoa ( value , dst , size ) ;
case LF_INT_ULTOA :
return ultoa_o ( value , dst , size ) ;
case LF_INT_UTOA_PAD_4 :
{
if ( size < 4 )
return NULL ;
return utoa_pad ( value , dst , 4 ) ;
}
}
return NULL ;
}
2012-04-05 12:02:55 -04:00
/*
* Write a port to the log
2020-04-16 14:51:34 -04:00
* + X option write in hexadecimal notation , most significant byte on the left
2012-04-05 12:02:55 -04:00
*/
2024-04-22 04:12:42 -04:00
static char * lf_port ( char * dst , const struct sockaddr * sockaddr , size_t size , struct lf_buildctx * ctx )
2012-04-05 12:02:55 -04:00
{
char * ret = dst ;
int iret ;
2024-04-22 04:12:42 -04:00
if ( ctx - > options & LOG_OPT_HEXA ) {
2012-04-05 12:02:55 -04:00
const unsigned char * port = ( const unsigned char * ) & ( ( struct sockaddr_in * ) sockaddr ) - > sin_port ;
2024-04-03 09:42:35 -04:00
2024-05-02 10:48:56 -04:00
iret = snprintf ( ctx - > _buf , sizeof ( ctx - > _buf ) , " %02X%02X " , port [ 0 ] , port [ 1 ] ) ;
BUG/MINOR: log: invalid snprintf() usage in sess_build_logline()
According to snprintf() man page:
The functions snprintf() and vsnprintf() do not write more than
size bytes (including the terminating null byte ('\0')). If the
output was truncated due to this limit, then the return value is
the number of characters (excluding the terminating null byte)
which would have been written to the final string if enough space
had been available. Thus, a return value of size or more means
that the output was truncated.
However, in sess_build_logline(), each time we need to check the return
value of snprintf(), here is how we proceed:
iret = snprintf(tmplog, max, ...);
if (iret < 0 || iret > max)
// error
// success
tmplog += iret;
Here is the issue: if snprintf() lacks 1 byte space to write the
terminating NULL byte, it will return max. Which means in this case
that we fail to know that snprintf() truncated the output in reality,
and we still add iret to tmplog pointer. Considering sess_build_logline()
should NOT write more than <maxsize> bytes (including the terminating NULL
byte) as per the function description, in this case the function would
write <maxsize>+1 byte (to write the terminating NULL byte upon return),
which may lead to invalid write if <dst> was meant to hold <maxsize> bytes
at maximum.
Hopefully, this bug wasn't triggered so far because sess_build_logline()
is called with logline as <dst> argument and <global.max_syslog_len> as
<maxsize> argument, logline being initialized with 1 extra byte upon
startup.
But we better fix this to comply with the function description and prevent
any side-effect since some sess_build_logline() helpers may assume that
'tmplog-dst < maxsize' is always true. Also sess_build_logline() users
probably don't expect NULL-byte to be accounted for in the produced
logline length.
This should be backported to all stable versions.
[ada: for backports, the patch needs to be applied manually because of
c6a713842 ("MINOR: log: simplify last_isspace in sess_build_logline()")]
2024-04-09 09:59:42 -04:00
if ( iret < 0 | | iret > = size )
2012-04-05 12:02:55 -04:00
return NULL ;
2024-05-02 10:48:56 -04:00
ret = lf_rawtext ( dst , ctx - > _buf , size , ctx ) ;
2012-04-05 12:02:55 -04:00
} else {
2024-03-27 05:17:11 -04:00
ret = lf_int ( dst , size , get_host_port ( ( struct sockaddr_storage * ) sockaddr ) ,
2024-04-22 04:12:42 -04:00
ctx , LF_INT_LTOA ) ;
2012-04-05 12:02:55 -04:00
}
return ret ;
}
2020-07-06 09:54:06 -04:00
/*
2024-05-22 09:19:32 -04:00
* This function sends a syslog message .
* < target > is the actual log target where log will be sent ,
2023-08-24 14:46:12 -04:00
*
2024-05-22 09:19:32 -04:00
* Message will be prefixed by header according to < hdr > setting .
* Final message will be truncated < maxlen > parameter and will be
* terminated with an LF character .
2023-08-24 14:46:12 -04:00
*
2024-05-22 09:19:32 -04:00
* Does not return any error
2020-07-06 09:54:06 -04:00
*/
2024-05-22 09:19:32 -04:00
static inline void __do_send_log ( struct log_target * target , struct log_header hdr ,
int nblogger , size_t maxlen ,
char * message , size_t size )
2020-07-06 09:54:06 -04:00
{
2024-05-22 09:19:32 -04:00
static THREAD_LOCAL struct iovec iovec [ NB_LOG_HDR_MAX_ELEMENTS + 1 + 1 ] = { } ; /* header elements + message + LF */
static THREAD_LOCAL struct msghdr msghdr = {
//.msg_iov = iovec,
. msg_iovlen = NB_LOG_HDR_MAX_ELEMENTS + 2
} ;
static THREAD_LOCAL int logfdunix = - 1 ; /* syslog to AF_UNIX socket */
static THREAD_LOCAL int logfdinet = - 1 ; /* syslog to AF_INET socket */
int * plogfd ;
int sent ;
size_t nbelem ;
struct ist * msg_header = NULL ;
2020-07-06 09:54:06 -04:00
2024-05-22 09:19:32 -04:00
msghdr . msg_iov = iovec ;
2020-07-06 09:54:06 -04:00
2024-05-22 09:19:32 -04:00
/* historically some messages used to already contain the trailing LF
* or Zero . Let ' s remove all trailing LF or Zero
*/
while ( size & & ( message [ size - 1 ] = = ' \n ' | | ( message [ size - 1 ] = = 0 ) ) )
size - - ;
2020-07-06 09:54:06 -04:00
2024-05-22 09:19:32 -04:00
if ( target - > type = = LOG_TARGET_BUFFER ) {
plogfd = NULL ;
goto send ;
}
else if ( target - > addr - > ss_family = = AF_CUST_EXISTING_FD ) {
/* the socket's address is a file descriptor */
plogfd = ( int * ) & ( ( struct sockaddr_in * ) target - > addr ) - > sin_addr . s_addr ;
}
else if ( target - > addr - > ss_family = = AF_UNIX )
plogfd = & logfdunix ;
else
plogfd = & logfdinet ;
2020-07-06 09:54:06 -04:00
2024-05-22 09:19:32 -04:00
if ( plogfd & & unlikely ( * plogfd < 0 ) ) {
/* socket not successfully initialized yet */
if ( ( * plogfd = socket ( target - > addr - > ss_family , SOCK_DGRAM ,
( target - > addr - > ss_family = = AF_UNIX ) ? 0 : IPPROTO_UDP ) ) < 0 ) {
static char once ;
if ( ! once ) {
once = 1 ; /* note: no need for atomic ops here */
ha_alert ( " socket() failed in logger #%d: %s (errno=%d) \n " ,
nblogger , strerror ( errno ) , errno ) ;
2020-07-06 09:54:06 -04:00
}
2024-05-22 09:19:32 -04:00
return ;
} else {
/* we don't want to receive anything on this socket */
setsockopt ( * plogfd , SOL_SOCKET , SO_RCVBUF , & zero , sizeof ( zero ) ) ;
/* we may want to adjust the output buffer (tune.sndbuf.backend) */
if ( global . tune . backend_sndbuf )
setsockopt ( * plogfd , SOL_SOCKET , SO_SNDBUF , & global . tune . backend_sndbuf , sizeof ( global . tune . backend_sndbuf ) ) ;
/* does nothing under Linux, maybe needed for others */
shutdown ( * plogfd , SHUT_RD ) ;
fd_set_cloexec ( * plogfd ) ;
2020-07-06 09:54:06 -04:00
}
}
2024-05-22 09:19:32 -04:00
msg_header = build_log_header ( hdr , & nbelem ) ;
send :
if ( target - > type = = LOG_TARGET_BUFFER ) {
struct ist msg ;
size_t e_maxlen = maxlen ;
msg = ist2 ( message , size ) ;
/* make room for the final '\n' which may be forcefully inserted
* by tcp forwarder applet ( sink_forward_io_handler )
*/
e_maxlen - = 1 ;
sent = sink_write ( target - > sink , hdr , e_maxlen , & msg , 1 ) ;
2020-07-06 09:54:06 -04:00
}
2024-05-22 09:19:32 -04:00
else if ( target - > addr - > ss_family = = AF_CUST_EXISTING_FD ) {
struct ist msg ;
2020-07-06 09:54:06 -04:00
2024-05-22 09:19:32 -04:00
msg = ist2 ( message , size ) ;
2020-07-06 09:54:06 -04:00
2024-05-22 09:19:32 -04:00
sent = fd_write_frag_line ( * plogfd , maxlen , msg_header , nbelem , & msg , 1 , 1 ) ;
}
else {
int i = 0 ;
int totlen = maxlen - 1 ; /* save space for the final '\n' */
for ( i = 0 ; i < nbelem ; i + + ) {
iovec [ i ] . iov_base = msg_header [ i ] . ptr ;
iovec [ i ] . iov_len = msg_header [ i ] . len ;
if ( totlen < = iovec [ i ] . iov_len ) {
iovec [ i ] . iov_len = totlen ;
totlen = 0 ;
2020-07-06 09:54:06 -04:00
break ;
}
2024-05-22 09:19:32 -04:00
totlen - = iovec [ i ] . iov_len ;
}
if ( totlen ) {
iovec [ i ] . iov_base = message ;
iovec [ i ] . iov_len = size ;
if ( totlen < = iovec [ i ] . iov_len )
iovec [ i ] . iov_len = totlen ;
i + + ;
}
iovec [ i ] . iov_base = " \n " ; /* insert a \n at the end of the message */
iovec [ i ] . iov_len = 1 ;
i + + ;
2020-07-06 09:54:06 -04:00
2024-05-22 09:19:32 -04:00
msghdr . msg_iovlen = i ;
msghdr . msg_name = ( struct sockaddr * ) target - > addr ;
msghdr . msg_namelen = get_addr_len ( target - > addr ) ;
2020-07-06 09:54:06 -04:00
2024-05-22 09:19:32 -04:00
sent = sendmsg ( * plogfd , & msghdr , MSG_DONTWAIT | MSG_NOSIGNAL ) ;
}
2020-07-06 09:54:06 -04:00
2024-05-22 09:19:32 -04:00
if ( sent < 0 ) {
static char once ;
2020-07-06 09:54:06 -04:00
2024-05-22 09:19:32 -04:00
if ( errno = = EAGAIN | | errno = = EWOULDBLOCK )
_HA_ATOMIC_INC ( & dropped_logs ) ;
else if ( ! once ) {
once = 1 ; /* note: no need for atomic ops here */
ha_alert ( " sendmsg()/writev() failed in logger #%d: %s (errno=%d) \n " ,
nblogger , strerror ( errno ) , errno ) ;
}
}
}
2020-07-06 09:54:06 -04:00
2024-05-22 09:19:32 -04:00
/* does the same as __do_send_log() does for a single target, but here the log
* will be sent according to the log backend ' s lb settings . The function will
* leverage __do_send_log ( ) function to actually send the log messages .
*/
static inline void __do_send_log_backend ( struct proxy * be , struct log_header hdr ,
int nblogger , size_t maxlen ,
char * message , size_t size )
{
struct server * srv = NULL ;
2020-07-06 09:54:06 -04:00
2024-05-22 09:19:32 -04:00
/* log-balancing logic: */
2020-07-06 09:54:06 -04:00
2024-05-22 09:19:32 -04:00
if ( ( be - > lbprm . algo & BE_LB_ALGO ) = = BE_LB_ALGO_RR ) {
srv = fwrr_get_next_server ( be , NULL ) ;
2020-07-06 09:54:06 -04:00
}
2024-05-22 09:19:32 -04:00
else if ( ( be - > lbprm . algo & BE_LB_ALGO ) = = BE_LB_ALGO_SS ) {
/* sticky mode: use first server in the pool, which will always stay
* first during dequeuing and requeuing , unless it becomes unavailable
* and will be replaced by another one
*/
srv = ss_get_server ( be ) ;
}
else if ( ( be - > lbprm . algo & BE_LB_ALGO ) = = BE_LB_ALGO_RND ) {
unsigned int hash ;
2020-07-06 09:54:06 -04:00
2024-05-22 09:19:32 -04:00
hash = statistical_prng ( ) ; /* random */
srv = chash_get_server_hash ( be , hash , NULL ) ;
}
else if ( ( be - > lbprm . algo & BE_LB_ALGO ) = = BE_LB_ALGO_LH ) {
struct sample result ;
2020-07-06 09:54:06 -04:00
2024-05-22 09:19:32 -04:00
/* log-balance hash */
memset ( & result , 0 , sizeof ( result ) ) ;
result . data . type = SMP_T_STR ;
result . flags = SMP_F_CONST ;
result . data . u . str . area = message ;
result . data . u . str . data = size ;
result . data . u . str . size = size + 1 ; /* with terminating NULL byte */
if ( sample_process_cnv ( be - > lbprm . expr , & result ) ) {
/* gen_hash takes binary input, ensure that we provide such value to it */
if ( result . data . type = = SMP_T_BIN | | sample_casts [ result . data . type ] [ SMP_T_BIN ] ) {
unsigned int hash ;
2020-07-06 09:54:06 -04:00
2024-05-22 09:19:32 -04:00
sample_casts [ result . data . type ] [ SMP_T_BIN ] ( & result ) ;
hash = gen_hash ( be , result . data . u . str . area , result . data . u . str . data ) ;
srv = map_get_server_hash ( be , hash ) ;
2020-07-06 09:54:06 -04:00
}
2024-05-22 09:19:32 -04:00
}
}
2020-07-06 09:54:06 -04:00
2024-05-22 09:19:32 -04:00
if ( ! srv ) {
/* no srv available, can't log */
goto drop ;
2020-07-06 09:54:06 -04:00
}
2024-05-22 09:19:32 -04:00
__do_send_log ( srv - > log_target , hdr , nblogger , maxlen , message , size ) ;
return ;
drop :
_HA_ATOMIC_INC ( & dropped_logs ) ;
2020-07-06 09:54:06 -04:00
}
2012-02-06 10:00:33 -05:00
2024-02-22 05:29:20 -05:00
/* provided to low-level process_send_log() helper, may be NULL */
struct process_send_log_ctx {
struct session * sess ;
struct stream * stream ;
enum log_orig origin ;
} ;
2012-02-06 10:00:33 -05:00
/*
2023-08-17 07:45:19 -04:00
* This function sends a syslog message .
2024-05-22 09:19:32 -04:00
* It doesn ' t care about errors nor does it report them .
* The argument < metadata > MUST be an array of size
* LOG_META_FIELDS * sizeof ( struct ist ) containing
* data to build the header .
2012-02-06 10:00:33 -05:00
*/
2024-02-22 05:29:20 -05:00
static void process_send_log ( struct process_send_log_ctx * ctx ,
struct list * loggers , int level , int facility ,
2024-05-22 09:19:32 -04:00
struct ist * metadata , char * message , size_t size )
2012-02-06 10:00:33 -05:00
{
2024-05-22 09:19:32 -04:00
struct logger * logger ;
int nblogger ;
2017-06-02 10:20:16 -04:00
2024-05-22 09:19:32 -04:00
/* Send log messages to syslog server. */
nblogger = 0 ;
list_for_each_entry ( logger , loggers , list ) {
int in_range = 1 ;
2012-02-06 10:00:33 -05:00
2024-05-22 09:19:32 -04:00
/* we can filter the level of the messages that are sent to each logger */
if ( level > logger - > level )
continue ;
2020-05-12 13:33:15 -04:00
2024-05-22 09:19:32 -04:00
if ( logger - > lb . smp_rgs ) {
struct smp_log_range * smp_rg ;
uint next_idx , curr_rg ;
ullong curr_rg_idx , next_rg_idx ;
2019-04-10 02:22:17 -04:00
2024-05-22 09:19:32 -04:00
curr_rg_idx = _HA_ATOMIC_LOAD ( & logger - > lb . curr_rg_idx ) ;
do {
next_idx = ( curr_rg_idx & 0xFFFFFFFFU ) + 1 ;
curr_rg = curr_rg_idx > > 32 ;
smp_rg = & logger - > lb . smp_rgs [ curr_rg ] ;
2019-04-10 02:22:17 -04:00
2024-05-22 09:19:32 -04:00
/* check if the index we're going to take is within range */
in_range = smp_rg - > low < = next_idx & & next_idx < = smp_rg - > high ;
if ( in_range ) {
/* Let's consume this range. */
if ( next_idx = = smp_rg - > high ) {
/* If consumed, let's select the next range. */
curr_rg = ( curr_rg + 1 ) % logger - > lb . smp_rgs_sz ;
}
}
next_idx = next_idx % logger - > lb . smp_sz ;
next_rg_idx = ( ( ullong ) curr_rg < < 32 ) + next_idx ;
} while ( ! _HA_ATOMIC_CAS ( & logger - > lb . curr_rg_idx , & curr_rg_idx , next_rg_idx ) & &
__ha_cpu_relax ( ) ) ;
}
if ( in_range ) {
struct log_header hdr ;
hdr . level = MAX ( level , logger - > minlvl ) ;
hdr . facility = ( facility = = - 1 ) ? logger - > facility : facility ;
hdr . format = logger - > format ;
hdr . metadata = metadata ;
nblogger + = 1 ;
if ( logger - > target . type = = LOG_TARGET_BACKEND ) {
__do_send_log_backend ( logger - > target . be , hdr , nblogger , logger - > maxlen , message , size ) ;
2019-04-10 02:22:17 -04:00
}
2024-05-22 09:19:32 -04:00
else {
/* normal target */
__do_send_log ( & logger - > target , hdr , nblogger , logger - > maxlen , message , size ) ;
}
}
}
}
/*
* This function sends a syslog message .
* It doesn ' t care about errors nor does it report them .
* The arguments < sd > and < sd_size > are used for the structured - data part
* in RFC5424 formatted syslog messages .
*/
2024-02-22 05:29:20 -05:00
static void __send_log ( struct process_send_log_ctx * ctx ,
struct list * loggers , struct buffer * tagb , int level ,
2024-05-22 09:19:32 -04:00
char * message , size_t size , char * sd , size_t sd_size )
{
static THREAD_LOCAL pid_t curr_pid ;
static THREAD_LOCAL char pidstr [ 16 ] ;
static THREAD_LOCAL struct ist metadata [ LOG_META_FIELDS ] ;
if ( loggers = = NULL ) {
if ( ! LIST_ISEMPTY ( & global . loggers ) ) {
loggers = & global . loggers ;
2015-10-01 07:18:13 -04:00
}
2006-06-25 20:48:02 -04:00
}
2024-05-22 09:19:32 -04:00
if ( ! loggers | | LIST_ISEMPTY ( loggers ) )
return ;
if ( ! metadata [ LOG_META_HOST ] . len ) {
if ( global . log_send_hostname )
metadata [ LOG_META_HOST ] = ist ( global . log_send_hostname ) ;
}
2006-06-25 20:48:02 -04:00
2024-05-22 09:19:32 -04:00
if ( ! tagb | | ! tagb - > area )
tagb = & global . log_tag ;
2020-07-06 09:54:06 -04:00
2024-05-22 09:19:32 -04:00
if ( tagb )
metadata [ LOG_META_TAG ] = ist2 ( tagb - > area , tagb - > data ) ;
2019-08-30 08:05:35 -04:00
2024-05-22 09:19:32 -04:00
if ( unlikely ( curr_pid ! = getpid ( ) ) )
metadata [ LOG_META_PID ] . len = 0 ;
BUG/MEDIUM: log: improper use of logsrv->maxlen for buffer targets
In e709e1e ("MEDIUM: logs: buffer targets now rely on new sink_write")
we started using the sink API instead of using the ring_write function
directly.
But as indicated in the commit message, the maxlen parameter of the log
directive now only applies to the message part and not the complete
payload. I don't know what the original intent was (maybe minimizing code
changes) but it seems wrong, because the doc doesn't mention this special
case, and the result is that the ring->buffer output can differ from all
other log output types, making it very confusing.
One last issue with this is that log messages can end up being dropped at
runtime, only for the buffer target, and even if logsrv->maxlen is
correctly set (including default: 1024) because depending on the generated
header size the payload can grow bigger than the accepted sink size (sink
maxlen is not mandatory) and we have no simple way to detect this at
configuration time.
First, we partially revert e709e1e:
TARGET_BUFFER still leverages the proper sink API, but thanks to
"MINOR: sink: pass explicit maxlen parameter to sink_write()" we now
explicitly pass the logsrv->maxlen to the sink_write function in order
to stop writing as soon as either sink->maxlen or logsrv->maxlen is
reached.
This restores pre-e709e1e behavior with the added benefit from using the
high-level API, which includes automatically announcing dropped message
events.
Then, we also need to take the ending '\n' into account: it is not
explicitly set when generating the logline for TARGET_BUFFER, but it will
be forcefully added by the sink_forward_io_handler function from the tcp
handler applet when log messages from the buffer are forwarded to tcp
endpoints.
In current form, because the '\n' is added later in the chain, maxlen is
not being considered anymore, so the final log message could exceed maxlen
by 1 byte, which could make receiving servers unhappy in logging context.
To prevent this, we sacrifice 1 byte from the logsrv->maxlen to ensure
that the final message will never exceed log->maxlen, even if the '\n'
char is automatically appended later by the forwarding applet.
Thanks to this change TCP (over RING/BUFFER) target now behaves like
FD and UDP targets.
This commit depends on:
- "MINOR: sink: pass explicit maxlen parameter to sink_write()"
It may be backported as far as 2.2
[For 2.2 and 2.4 the patch does not apply automatically, the sink_write()
call must be updated by hand]
2023-06-26 11:15:48 -04:00
2024-05-22 09:19:32 -04:00
if ( ! metadata [ LOG_META_PID ] . len ) {
curr_pid = getpid ( ) ;
ltoa_o ( curr_pid , pidstr , sizeof ( pidstr ) ) ;
metadata [ LOG_META_PID ] = ist2 ( pidstr , strlen ( pidstr ) ) ;
2020-09-04 10:44:20 -04:00
}
2024-05-22 09:19:32 -04:00
metadata [ LOG_META_STDATA ] = ist2 ( sd , sd_size ) ;
2020-09-04 10:44:20 -04:00
2024-05-22 09:19:32 -04:00
/* Remove trailing space of structured data */
while ( metadata [ LOG_META_STDATA ] . len & & metadata [ LOG_META_STDATA ] . ptr [ metadata [ LOG_META_STDATA ] . len - 1 ] = = ' ' )
metadata [ LOG_META_STDATA ] . len - - ;
2020-07-06 09:54:06 -04:00
2024-02-22 05:29:20 -05:00
return process_send_log ( ctx , loggers , level , - 1 , metadata , message , size ) ;
2024-05-22 09:19:32 -04:00
}
2019-08-30 08:05:35 -04:00
2024-05-22 09:19:32 -04:00
/*
* This function sends the syslog message using a printf format string . It
* expects an LF - terminated message .
*/
void send_log ( struct proxy * p , int level , const char * format , . . . )
{
va_list argp ;
int data_len ;
2015-10-01 07:18:13 -04:00
2024-05-22 09:19:32 -04:00
if ( level < 0 | | format = = NULL | | logline = = NULL )
return ;
2015-10-01 07:18:13 -04:00
2024-05-22 09:19:32 -04:00
va_start ( argp , format ) ;
data_len = vsnprintf ( logline , global . max_syslog_len , format , argp ) ;
if ( data_len < 0 | | data_len > global . max_syslog_len )
data_len = global . max_syslog_len ;
va_end ( argp ) ;
2015-10-01 07:18:13 -04:00
2024-02-22 05:29:20 -05:00
__send_log ( NULL , ( p ? & p - > loggers : NULL ) ,
( p ? & p - > log_tag : NULL ) , level ,
2024-05-22 09:19:32 -04:00
logline , data_len , default_rfc5424_sd_log_format , 2 ) ;
2019-04-10 02:22:17 -04:00
}
2015-09-19 16:35:44 -04:00
2024-05-22 09:19:32 -04:00
/*
* This function builds a log header according to < hdr > settings .
*
* If hdr . format is set to LOG_FORMAT_UNSPEC , it tries to determine
* format based on hdr . metadata . It is useful for log - forwarding to be
* able to forward any format without settings .
*
* This function returns a struct ist array of elements of the header
* nbelem is set to the number of available elements .
* This function returns currently a maximum of NB_LOG_HDR_IST_ELEMENTS
* elements .
2023-09-13 05:52:31 -04:00
*/
2024-05-22 09:19:32 -04:00
struct ist * build_log_header ( struct log_header hdr , size_t * nbelem )
2023-09-13 05:52:31 -04:00
{
2024-05-22 09:19:32 -04:00
static THREAD_LOCAL struct {
struct ist ist_vector [ NB_LOG_HDR_MAX_ELEMENTS ] ;
char timestamp_buffer [ LOG_LEGACYTIME_LEN + 1 + 1 ] ;
time_t cur_legacy_time ;
char priority_buffer [ 6 ] ;
} hdr_ctx = { . priority_buffer = " <<<<> " } ;
2023-09-13 05:52:31 -04:00
2024-05-22 09:19:32 -04:00
struct tm logtime ;
int len ;
int fac_level = 0 ;
time_t time = date . tv_sec ;
struct ist * metadata = hdr . metadata ;
enum log_fmt format = hdr . format ;
int facility = hdr . facility ;
int level = hdr . level ;
2023-09-13 05:52:31 -04:00
2024-05-22 09:19:32 -04:00
* nbelem = 0 ;
if ( format = = LOG_FORMAT_UNSPEC ) {
format = LOG_FORMAT_RAW ;
if ( metadata ) {
/* If a hostname is set, it appears we want to perform syslog
* because only rfc5427 or rfc3164 support an hostname .
*/
if ( metadata [ LOG_META_HOST ] . len ) {
/* If a rfc5424 compliant timestamp is used we consider
* that output format is rfc5424 , else legacy format
* is used as specified default for local logs
* in documentation .
*/
if ( ( metadata [ LOG_META_TIME ] . len = = 1 & & metadata [ LOG_META_TIME ] . ptr [ 0 ] = = ' - ' )
| | ( metadata [ LOG_META_TIME ] . len > = LOG_ISOTIME_MINLEN ) )
format = LOG_FORMAT_RFC5424 ;
else
format = LOG_FORMAT_RFC3164 ;
}
else if ( metadata [ LOG_META_TAG ] . len ) {
/* Tag is present but no hostname, we should
* consider we try to emit a local log
* in legacy format ( analog to RFC3164 but
* with stripped hostname ) .
*/
format = LOG_FORMAT_LOCAL ;
}
else if ( metadata [ LOG_META_PRIO ] . len ) {
/* the source seems a parsed message
* offering a valid level / prio prefix
* so we consider this format .
*/
format = LOG_FORMAT_PRIO ;
}
}
2023-09-21 14:24:14 -04:00
}
2024-03-28 10:42:37 -04:00
2024-05-22 09:19:32 -04:00
/* prepare priority, stored into 1 single elem */
switch ( format ) {
case LOG_FORMAT_LOCAL :
case LOG_FORMAT_RFC3164 :
case LOG_FORMAT_RFC5424 :
case LOG_FORMAT_PRIO :
fac_level = facility < < 3 ;
/* further format ignore the facility */
__fallthrough ;
case LOG_FORMAT_TIMED :
case LOG_FORMAT_SHORT :
fac_level + = level ;
hdr_ctx . ist_vector [ * nbelem ] . ptr = & hdr_ctx . priority_buffer [ 3 ] ; /* last digit of the log level */
do {
* hdr_ctx . ist_vector [ * nbelem ] . ptr = ' 0 ' + fac_level % 10 ;
fac_level / = 10 ;
hdr_ctx . ist_vector [ * nbelem ] . ptr - - ;
} while ( fac_level & & hdr_ctx . ist_vector [ * nbelem ] . ptr > & hdr_ctx . priority_buffer [ 0 ] ) ;
* hdr_ctx . ist_vector [ * nbelem ] . ptr = ' < ' ;
hdr_ctx . ist_vector [ ( * nbelem ) + + ] . len = & hdr_ctx . priority_buffer [ 5 ] - hdr_ctx . ist_vector [ 0 ] . ptr ;
break ;
case LOG_FORMAT_ISO :
case LOG_FORMAT_RAW :
break ;
case LOG_FORMAT_UNSPEC :
case LOG_FORMATS :
ABORT_NOW ( ) ;
2023-10-04 11:30:02 -04:00
}
2023-09-19 04:51:53 -04:00
2024-03-28 10:42:37 -04:00
2024-05-22 09:19:32 -04:00
/* prepare timestamp, stored into a max of 4 elems */
switch ( format ) {
case LOG_FORMAT_LOCAL :
case LOG_FORMAT_RFC3164 :
/* rfc3164 ex: 'Jan 1 00:00:00 ' */
if ( metadata & & metadata [ LOG_META_TIME ] . len = = LOG_LEGACYTIME_LEN ) {
hdr_ctx . ist_vector [ ( * nbelem ) + + ] = metadata [ LOG_META_TIME ] ;
hdr_ctx . ist_vector [ ( * nbelem ) + + ] = ist2 ( " " , 1 ) ;
/* time is set, break immediately */
break ;
}
else if ( metadata & & metadata [ LOG_META_TIME ] . len > = LOG_ISOTIME_MINLEN ) {
int month ;
char * timestamp = metadata [ LOG_META_TIME ] . ptr ;
/* iso time always begins like this: '1970-01-01T00:00:00' */
/* compute month */
month = 10 * ( timestamp [ 5 ] - ' 0 ' ) + ( timestamp [ 6 ] - ' 0 ' ) ;
if ( month )
month - - ;
if ( month < = 11 ) {
/* builds log prefix ex: 'Jan 1 ' */
len = snprintf ( hdr_ctx . timestamp_buffer , sizeof ( hdr_ctx . timestamp_buffer ) ,
" %s %c%c " , monthname [ month ] ,
timestamp [ 8 ] ! = ' 0 ' ? timestamp [ 8 ] : ' ' ,
timestamp [ 9 ] ) ;
/* we reused the timestamp_buffer, signal that it does not
* contain local time anymore
*/
hdr_ctx . cur_legacy_time = 0 ;
if ( len = = 7 ) {
hdr_ctx . ist_vector [ ( * nbelem ) + + ] = ist2 ( & hdr_ctx . timestamp_buffer [ 0 ] , len ) ;
/* adds 'HH:MM:SS' from iso time */
hdr_ctx . ist_vector [ ( * nbelem ) + + ] = ist2 ( & timestamp [ 11 ] , 8 ) ;
hdr_ctx . ist_vector [ ( * nbelem ) + + ] = ist2 ( " " , 1 ) ;
/* we successfully reuse iso time, we can break */
break ;
}
}
/* Failed to reuse isotime time, fallback to local legacy time */
2023-09-19 04:51:53 -04:00
}
2023-09-13 05:52:31 -04:00
2024-05-22 09:19:32 -04:00
if ( unlikely ( time ! = hdr_ctx . cur_legacy_time ) ) {
/* re-builds timestamp from the current local time */
get_localtime ( time , & logtime ) ;
2023-09-13 05:52:31 -04:00
2024-05-22 09:19:32 -04:00
len = snprintf ( hdr_ctx . timestamp_buffer , sizeof ( hdr_ctx . timestamp_buffer ) ,
" %s %2d %02d:%02d:%02d " ,
monthname [ logtime . tm_mon ] ,
logtime . tm_mday , logtime . tm_hour , logtime . tm_min , logtime . tm_sec ) ;
if ( len ! = LOG_LEGACYTIME_LEN + 1 )
hdr_ctx . cur_legacy_time = 0 ;
else
hdr_ctx . cur_legacy_time = time ;
}
if ( likely ( hdr_ctx . cur_legacy_time ) )
hdr_ctx . ist_vector [ ( * nbelem ) + + ] = ist2 ( & hdr_ctx . timestamp_buffer [ 0 ] , LOG_LEGACYTIME_LEN + 1 ) ;
else
hdr_ctx . ist_vector [ ( * nbelem ) + + ] = ist2 ( " Jan 1 00:00:00 " , LOG_LEGACYTIME_LEN + 1 ) ;
break ;
case LOG_FORMAT_RFC5424 :
/* adds rfc5425 version prefix */
hdr_ctx . ist_vector [ ( * nbelem ) + + ] = ist2 ( " 1 " , 2 ) ;
if ( metadata & & metadata [ LOG_META_TIME ] . len = = 1 & & metadata [ LOG_META_TIME ] . ptr [ 0 ] = = ' - ' ) {
/* submitted len is NILVALUE, it is a valid timestamp for rfc5425 */
hdr_ctx . ist_vector [ ( * nbelem ) + + ] = metadata [ LOG_META_TIME ] ;
hdr_ctx . ist_vector [ ( * nbelem ) + + ] = ist2 ( " " , 1 ) ;
break ;
}
/* let continue as 'timed' and 'iso' format for usual timestamp */
__fallthrough ;
case LOG_FORMAT_TIMED :
case LOG_FORMAT_ISO :
/* ISO format ex: '1900:01:01T12:00:00.123456Z'
* ' 1900 : 01 : 01 T14 : 00 : 00 + 02 : 00 '
* ' 1900 : 01 : 01 T10 : 00 : 00.123456 - 02 : 00 '
*/
if ( metadata & & metadata [ LOG_META_TIME ] . len > = LOG_ISOTIME_MINLEN ) {
hdr_ctx . ist_vector [ ( * nbelem ) + + ] = metadata [ LOG_META_TIME ] ;
hdr_ctx . ist_vector [ ( * nbelem ) + + ] = ist2 ( " " , 1 ) ;
/* time is set, break immediately */
break ;
}
else if ( metadata & & metadata [ LOG_META_TIME ] . len = = LOG_LEGACYTIME_LEN ) {
int month ;
char * timestamp = metadata [ LOG_META_TIME ] . ptr ;
2023-09-13 05:52:31 -04:00
2024-05-22 09:19:32 -04:00
for ( month = 0 ; month < 12 ; month + + )
if ( ! memcmp ( monthname [ month ] , timestamp , 3 ) )
break ;
2019-04-10 02:22:17 -04:00
2024-05-22 09:19:32 -04:00
if ( month < 12 ) {
2019-04-25 01:42:09 -04:00
2024-05-22 09:19:32 -04:00
/* get local time to retrieve year */
get_localtime ( time , & logtime ) ;
2019-04-10 02:22:17 -04:00
2024-05-22 09:19:32 -04:00
/* year seems changed since log */
if ( logtime . tm_mon < month )
logtime . tm_year - - ;
MEDIUM: logs: atomically check and update the log sample index
The log server lock is pretty visible in perf top when using log samples
because it's taken for each server in turn while trying to validate and
update the log server's index. Let's change this for a CAS, since we have
the index and the range at hand now. This allow us to remove the logsrv
lock.
The test on 4 servers now shows a 3.7 times improvement thanks to much
lower contention. Without log sampling a test producing 4.4M logs/s
delivers 4.4M logs/s at 21 CPUs used, everything spent in the kernel.
After enabling 4 samples (1:4, 2:4, 3:4 and 4:4), the throughput would
previously drop to 1.13M log/s with 37 CPUs used and 75% spent in
process_send_log(). Now with this change, 4.25M logs/s are emitted,
using 26 CPUs and 22% in process_send_log(). That's a 3.7x throughput
improvement for a 30% global CPU usage reduction, but in practice it
mostly shows that the performance drop caused by having samples is much
less noticeable (each of the 4 servers has its index updated for each
log).
Note that in order to even avoid incrementing an index for each log srv
that is consulted, it would be more convenient to have a single index
per frontend and apply the modulus on each log server in turn to see if
the range has to be updated. It would then only perform one write per
range switch. However the place where this is done doesn't have access
to a frontend, so some changes would need to be performed for this, and
it would require to update the current range independently in each
logsrv, which is not necessarily easier since we don't know yet if we
can commit it.
2023-09-20 14:34:35 -04:00
2024-05-22 09:19:32 -04:00
/* builds rfc5424 prefix ex: '1900-01-01T' */
len = snprintf ( hdr_ctx . timestamp_buffer , sizeof ( hdr_ctx . timestamp_buffer ) ,
" %4d-%02d-%c%cT " ,
logtime . tm_year + 1900 , month + 1 ,
timestamp [ 4 ] ! = ' ' ? timestamp [ 4 ] : ' 0 ' ,
timestamp [ 5 ] ) ;
MEDIUM: logs: atomically check and update the log sample index
The log server lock is pretty visible in perf top when using log samples
because it's taken for each server in turn while trying to validate and
update the log server's index. Let's change this for a CAS, since we have
the index and the range at hand now. This allow us to remove the logsrv
lock.
The test on 4 servers now shows a 3.7 times improvement thanks to much
lower contention. Without log sampling a test producing 4.4M logs/s
delivers 4.4M logs/s at 21 CPUs used, everything spent in the kernel.
After enabling 4 samples (1:4, 2:4, 3:4 and 4:4), the throughput would
previously drop to 1.13M log/s with 37 CPUs used and 75% spent in
process_send_log(). Now with this change, 4.25M logs/s are emitted,
using 26 CPUs and 22% in process_send_log(). That's a 3.7x throughput
improvement for a 30% global CPU usage reduction, but in practice it
mostly shows that the performance drop caused by having samples is much
less noticeable (each of the 4 servers has its index updated for each
log).
Note that in order to even avoid incrementing an index for each log srv
that is consulted, it would be more convenient to have a single index
per frontend and apply the modulus on each log server in turn to see if
the range has to be updated. It would then only perform one write per
range switch. However the place where this is done doesn't have access
to a frontend, so some changes would need to be performed for this, and
it would require to update the current range independently in each
logsrv, which is not necessarily easier since we don't know yet if we
can commit it.
2023-09-20 14:34:35 -04:00
2024-05-22 09:19:32 -04:00
/* we reused the timestamp_buffer, signal that it does not
* contain local time anymore
*/
hdr_ctx . cur_legacy_time = 0 ;
if ( len = = 11 ) {
hdr_ctx . ist_vector [ ( * nbelem ) + + ] = ist2 ( & hdr_ctx . timestamp_buffer [ 0 ] , len ) ;
/* adds HH:MM:SS from legacy timestamp */
hdr_ctx . ist_vector [ ( * nbelem ) + + ] = ist2 ( & timestamp [ 7 ] , 8 ) ;
/* skip secfraq because it is optional */
/* according to rfc: -00:00 means we don't know the timezone */
hdr_ctx . ist_vector [ ( * nbelem ) + + ] = ist2 ( " -00:00 " , 7 ) ;
/* we successfully reuse legacy time, we can break */
break ;
MEDIUM: logs: atomically check and update the log sample index
The log server lock is pretty visible in perf top when using log samples
because it's taken for each server in turn while trying to validate and
update the log server's index. Let's change this for a CAS, since we have
the index and the range at hand now. This allow us to remove the logsrv
lock.
The test on 4 servers now shows a 3.7 times improvement thanks to much
lower contention. Without log sampling a test producing 4.4M logs/s
delivers 4.4M logs/s at 21 CPUs used, everything spent in the kernel.
After enabling 4 samples (1:4, 2:4, 3:4 and 4:4), the throughput would
previously drop to 1.13M log/s with 37 CPUs used and 75% spent in
process_send_log(). Now with this change, 4.25M logs/s are emitted,
using 26 CPUs and 22% in process_send_log(). That's a 3.7x throughput
improvement for a 30% global CPU usage reduction, but in practice it
mostly shows that the performance drop caused by having samples is much
less noticeable (each of the 4 servers has its index updated for each
log).
Note that in order to even avoid incrementing an index for each log srv
that is consulted, it would be more convenient to have a single index
per frontend and apply the modulus on each log server in turn to see if
the range has to be updated. It would then only perform one write per
range switch. However the place where this is done doesn't have access
to a frontend, so some changes would need to be performed for this, and
it would require to update the current range independently in each
logsrv, which is not necessarily easier since we don't know yet if we
can commit it.
2023-09-20 14:34:35 -04:00
}
2019-04-25 01:42:09 -04:00
}
2024-05-22 09:19:32 -04:00
/* Failed to reuse legacy time, fallback to local iso time */
2023-09-13 05:52:31 -04:00
}
2024-05-22 09:19:32 -04:00
hdr_ctx . ist_vector [ ( * nbelem ) + + ] = ist2 ( timeofday_as_iso_us ( 1 ) , LOG_ISOTIME_MAXLEN + 1 ) ;
break ;
case LOG_FORMAT_PRIO :
case LOG_FORMAT_SHORT :
case LOG_FORMAT_RAW :
break ;
case LOG_FORMAT_UNSPEC :
case LOG_FORMATS :
ABORT_NOW ( ) ;
2006-06-25 20:48:02 -04:00
}
2020-07-06 09:54:06 -04:00
2024-05-22 09:19:32 -04:00
/* prepare other meta data, stored into a max of 10 elems */
switch ( format ) {
case LOG_FORMAT_RFC3164 :
if ( metadata & & metadata [ LOG_META_HOST ] . len ) {
hdr_ctx . ist_vector [ ( * nbelem ) + + ] = metadata [ LOG_META_HOST ] ;
hdr_ctx . ist_vector [ ( * nbelem ) + + ] = ist2 ( " " , 1 ) ;
}
else /* the caller MUST fill the hostname, this field is mandatory */
hdr_ctx . ist_vector [ ( * nbelem ) + + ] = ist2 ( " localhost " , 10 ) ;
__fallthrough ;
case LOG_FORMAT_LOCAL :
if ( ! metadata | | ! metadata [ LOG_META_TAG ] . len )
break ;
2020-07-06 09:54:06 -04:00
2024-05-22 09:19:32 -04:00
hdr_ctx . ist_vector [ ( * nbelem ) + + ] = metadata [ LOG_META_TAG ] ;
if ( metadata [ LOG_META_PID ] . len ) {
hdr_ctx . ist_vector [ ( * nbelem ) + + ] = ist2 ( " [ " , 1 ) ;
hdr_ctx . ist_vector [ ( * nbelem ) + + ] = metadata [ LOG_META_PID ] ;
hdr_ctx . ist_vector [ ( * nbelem ) + + ] = ist2 ( " ] " , 1 ) ;
}
hdr_ctx . ist_vector [ ( * nbelem ) + + ] = ist2 ( " : " , 2 ) ;
break ;
case LOG_FORMAT_RFC5424 :
if ( metadata & & metadata [ LOG_META_HOST ] . len ) {
hdr_ctx . ist_vector [ ( * nbelem ) + + ] = metadata [ LOG_META_HOST ] ;
hdr_ctx . ist_vector [ ( * nbelem ) + + ] = ist2 ( " " , 1 ) ;
}
else
hdr_ctx . ist_vector [ ( * nbelem ) + + ] = ist2 ( " - " , 2 ) ;
2020-07-06 09:54:06 -04:00
2024-05-22 09:19:32 -04:00
if ( metadata & & metadata [ LOG_META_TAG ] . len ) {
hdr_ctx . ist_vector [ ( * nbelem ) + + ] = metadata [ LOG_META_TAG ] ;
hdr_ctx . ist_vector [ ( * nbelem ) + + ] = ist2 ( " " , 1 ) ;
}
else
hdr_ctx . ist_vector [ ( * nbelem ) + + ] = ist2 ( " - " , 2 ) ;
2020-07-06 09:54:06 -04:00
2024-05-22 09:19:32 -04:00
if ( metadata & & metadata [ LOG_META_PID ] . len ) {
hdr_ctx . ist_vector [ ( * nbelem ) + + ] = metadata [ LOG_META_PID ] ;
hdr_ctx . ist_vector [ ( * nbelem ) + + ] = ist2 ( " " , 1 ) ;
}
else
hdr_ctx . ist_vector [ ( * nbelem ) + + ] = ist2 ( " - " , 2 ) ;
2020-07-06 09:54:06 -04:00
2024-05-22 09:19:32 -04:00
if ( metadata & & metadata [ LOG_META_MSGID ] . len ) {
hdr_ctx . ist_vector [ ( * nbelem ) + + ] = metadata [ LOG_META_MSGID ] ;
hdr_ctx . ist_vector [ ( * nbelem ) + + ] = ist2 ( " " , 1 ) ;
}
else
hdr_ctx . ist_vector [ ( * nbelem ) + + ] = ist2 ( " - " , 2 ) ;
2020-07-06 09:54:06 -04:00
2024-05-22 09:19:32 -04:00
if ( metadata & & metadata [ LOG_META_STDATA ] . len ) {
hdr_ctx . ist_vector [ ( * nbelem ) + + ] = metadata [ LOG_META_STDATA ] ;
hdr_ctx . ist_vector [ ( * nbelem ) + + ] = ist2 ( " " , 1 ) ;
}
else
hdr_ctx . ist_vector [ ( * nbelem ) + + ] = ist2 ( " - " , 2 ) ;
break ;
case LOG_FORMAT_PRIO :
case LOG_FORMAT_SHORT :
case LOG_FORMAT_TIMED :
case LOG_FORMAT_ISO :
case LOG_FORMAT_RAW :
break ;
case LOG_FORMAT_UNSPEC :
case LOG_FORMATS :
ABORT_NOW ( ) ;
2020-07-06 09:54:06 -04:00
}
2024-05-22 09:19:32 -04:00
return hdr_ctx . ist_vector ;
2020-07-06 09:54:06 -04:00
}
2012-02-27 05:23:10 -05:00
2012-04-05 15:18:22 -04:00
const char sess_cookie [ 8 ] = " NIDVEOU7 " ; /* No cookie, Invalid cookie, cookie for a Down server, Valid cookie, Expired cookie, Old cookie, Unused, unknown */
2012-02-27 05:23:10 -05:00
const char sess_set_cookie [ 8 ] = " NPDIRU67 " ; /* No set-cookie, Set-cookie found and left unchanged (passive),
Set - cookie Deleted , Set - Cookie Inserted , Set - cookie Rewritten ,
Set - cookie Updated , unknown , unknown */
2024-04-23 04:12:46 -04:00
/*
* try to write a cbor byte if there is enough space , or goto out
*/
# define LOG_CBOR_BYTE(x) do { \
2024-05-02 09:30:17 -04:00
ret = _lf_cbor_encode_byte ( & ctx - > encode . cbor , \
2024-04-23 04:12:46 -04:00
tmplog , \
dst + maxsize , \
( x ) ) ; \
if ( ret = = NULL ) \
goto out ; \
tmplog = ret ; \
} while ( 0 )
2012-03-12 07:46:41 -04:00
/*
* try to write a character if there is enough space , or goto out
*/
2012-02-27 05:23:10 -05:00
# define LOGCHAR(x) do { \
2024-05-02 09:30:17 -04:00
if ( ( ctx - > options & LOG_OPT_ENCODE_CBOR ) & & \
ctx - > in_text ) { \
2024-04-23 04:12:46 -04:00
char _x [ 1 ] ; \
/* encode the char as text chunk since we \
* cannot just throw random bytes and expect \
* cbor decoder to know how to handle them \
*/ \
_x [ 0 ] = ( x ) ; \
2024-05-02 09:30:17 -04:00
ret = cbor_encode_text ( & ctx - > encode . cbor , \
2024-04-23 04:12:46 -04:00
tmplog , \
dst + maxsize , \
_x , sizeof ( _x ) ) ; \
2024-04-29 14:19:05 -04:00
if ( ret = = NULL ) \
goto out ; \
2024-04-23 04:12:46 -04:00
tmplog = ret ; \
break ; \
} \
if ( tmplog < dst + maxsize - 1 ) { \
* ( tmplog + + ) = ( x ) ; \
} else { \
goto out ; \
} \
2012-02-27 05:23:10 -05:00
} while ( 0 )
2006-06-25 20:48:02 -04:00
2024-04-16 05:17:55 -04:00
/* indicate that a new variable-length text is starting, sets in_text
* variable to indicate that a var text was started and deals with
* encoding and options to know if some special treatment is needed .
2024-01-10 13:14:25 -05:00
*/
2024-04-23 04:12:46 -04:00
# define LOG_VARTEXT_START() do { \
2024-05-02 09:30:17 -04:00
ctx - > in_text = 1 ; \
if ( ctx - > options & LOG_OPT_ENCODE_CBOR ) { \
2024-04-23 04:12:46 -04:00
/* start indefinite-length cbor text */ \
LOG_CBOR_BYTE ( 0x7F ) ; \
break ; \
} \
/* put the text within quotes if JSON encoding \
* is used or quoting is enabled \
*/ \
2024-05-02 09:30:17 -04:00
if ( ctx - > options & \
2024-04-23 04:12:46 -04:00
( LOG_OPT_QUOTE | LOG_OPT_ENCODE_JSON ) ) { \
LOGCHAR ( ' " ' ) ; \
} \
2024-01-10 13:14:25 -05:00
} while ( 0 )
2024-04-16 05:17:55 -04:00
/* properly finish a variable text that was started using LOG_VARTEXT_START
* checks the in_text variable to know if a text was started or not , and
* deals with encoding and options to know if some special treatment is
* needed .
*/
2024-04-23 04:12:46 -04:00
# define LOG_VARTEXT_END() do { \
2024-05-02 09:30:17 -04:00
if ( ! ctx - > in_text ) \
2024-04-23 04:12:46 -04:00
break ; \
2024-05-02 09:30:17 -04:00
ctx - > in_text = 0 ; \
if ( ctx - > options & LOG_OPT_ENCODE_CBOR ) { \
2024-04-23 04:12:46 -04:00
/* end indefinite-length cbor text with break*/ \
LOG_CBOR_BYTE ( 0xFF ) ; \
break ; \
} \
/* add the ending quote if JSON encoding is \
* used or quoting is enabled \
*/ \
2024-05-02 09:30:17 -04:00
if ( ctx - > options & \
2024-04-23 04:12:46 -04:00
( LOG_OPT_QUOTE | LOG_OPT_ENCODE_JSON ) ) { \
LOGCHAR ( ' " ' ) ; \
} \
2024-01-10 13:14:25 -05:00
} while ( 0 )
2012-03-12 07:46:41 -04:00
2024-01-30 12:01:15 -05:00
/* Prints additional logvalue hint represented by <chr>.
* It is useful to express that < chr > is not part of the " raw " value and
* should be considered as optional metadata instead .
*/
# define LOGMETACHAR(chr) do { \
2024-04-22 08:40:04 -04:00
/* ignored when encoding is used */ \
2024-05-02 09:30:17 -04:00
if ( ctx - > options & LOG_OPT_ENCODE ) \
2024-04-22 08:40:04 -04:00
break ; \
2024-01-30 12:01:15 -05:00
LOGCHAR ( chr ) ; \
} while ( 0 )
2024-01-31 08:37:07 -05:00
/* indicate the start of a string array */
# define LOG_STRARRAY_START() do { \
2024-05-02 09:30:17 -04:00
if ( ctx - > options & LOG_OPT_ENCODE_JSON ) \
2024-04-22 08:40:04 -04:00
LOGCHAR ( ' [ ' ) ; \
2024-05-02 09:30:17 -04:00
if ( ctx - > options & LOG_OPT_ENCODE_CBOR ) { \
2024-04-23 04:12:46 -04:00
/* start indefinite-length array */ \
LOG_CBOR_BYTE ( 0x9F ) ; \
} \
2024-01-31 08:37:07 -05:00
} while ( 0 )
/* indicate that a new element is added to the string array */
# define LOG_STRARRAY_NEXT() do { \
2024-05-02 09:30:17 -04:00
if ( ctx - > options & LOG_OPT_ENCODE_CBOR ) \
2024-04-23 04:12:46 -04:00
break ; \
2024-05-02 09:30:17 -04:00
if ( ctx - > options & LOG_OPT_ENCODE_JSON ) { \
2024-04-22 08:40:04 -04:00
LOGCHAR ( ' , ' ) ; \
LOGCHAR ( ' ' ) ; \
} \
else \
LOGCHAR ( ' ' ) ; \
2024-01-31 08:37:07 -05:00
} while ( 0 )
/* indicate the end of a string array */
# define LOG_STRARRAY_END() do { \
2024-05-02 09:30:17 -04:00
if ( ctx - > options & LOG_OPT_ENCODE_JSON ) \
2024-04-22 08:40:04 -04:00
LOGCHAR ( ' ] ' ) ; \
2024-05-02 09:30:17 -04:00
if ( ctx - > options & LOG_OPT_ENCODE_CBOR ) { \
2024-04-23 04:12:46 -04:00
/* cbor break */ \
LOG_CBOR_BYTE ( 0xFF ) ; \
} \
2024-01-31 08:37:07 -05:00
} while ( 0 )
2018-11-26 10:31:20 -05:00
/* Initializes some log data at boot */
static void init_log ( )
2016-02-12 07:23:03 -05:00
{
char * tmp ;
2018-09-10 12:16:53 -04:00
int i ;
2016-02-12 07:23:03 -05:00
2024-04-26 08:23:43 -04:00
/* Initialize the no escape map, which may be used to bypass escaping */
memset ( no_escape_map , 0 , sizeof ( no_escape_map ) ) ;
2016-02-12 07:23:03 -05:00
/* Initialize the escape map for the RFC5424 structured-data : '"\]'
* inside PARAM - VALUE should be escaped with ' \ ' as prefix .
* See https : //tools.ietf.org/html/rfc5424#section-6.3.3 for more
* details .
*/
memset ( rfc5424_escape_map , 0 , sizeof ( rfc5424_escape_map ) ) ;
tmp = " \" \\ ] " ;
while ( * tmp ) {
2019-06-07 05:10:07 -04:00
ha_bit_set ( * tmp , rfc5424_escape_map ) ;
2016-02-12 07:23:03 -05:00
tmp + + ;
}
2018-09-10 12:16:53 -04:00
2024-04-22 08:40:04 -04:00
/* Initialize the escape map for JSON strings : '"\' */
memset ( json_escape_map , 0 , sizeof ( json_escape_map ) ) ;
tmp = " \" \\ " ;
while ( * tmp ) {
ha_bit_set ( * tmp , json_escape_map ) ;
tmp + + ;
}
2018-09-10 12:16:53 -04:00
/* initialize the log header encoding map : '{|}"#' should be encoded with
* ' # ' as prefix , as well as non - printable characters ( < 32 or > = 127 ) .
* URL encoding only requires ' " ' , ' # ' to be encoded as well as non -
* printable characters above .
*/
memset ( hdr_encode_map , 0 , sizeof ( hdr_encode_map ) ) ;
memset ( url_encode_map , 0 , sizeof ( url_encode_map ) ) ;
for ( i = 0 ; i < 32 ; i + + ) {
2019-06-07 05:10:07 -04:00
ha_bit_set ( i , hdr_encode_map ) ;
ha_bit_set ( i , url_encode_map ) ;
2018-09-10 12:16:53 -04:00
}
for ( i = 127 ; i < 256 ; i + + ) {
2019-06-07 05:10:07 -04:00
ha_bit_set ( i , hdr_encode_map ) ;
ha_bit_set ( i , url_encode_map ) ;
2018-09-10 12:16:53 -04:00
}
tmp = " \" #{|} " ;
while ( * tmp ) {
2019-06-07 05:10:07 -04:00
ha_bit_set ( * tmp , hdr_encode_map ) ;
2018-09-10 12:16:53 -04:00
tmp + + ;
}
tmp = " \" # " ;
while ( * tmp ) {
2019-06-07 05:10:07 -04:00
ha_bit_set ( * tmp , url_encode_map ) ;
2018-09-10 12:16:53 -04:00
tmp + + ;
}
/* initialize the http header encoding map. The draft httpbis define the
* header content as :
*
* HTTP - message = start - line
* * ( header - field CRLF )
* CRLF
* [ message - body ]
* header - field = field - name " : " OWS field - value OWS
* field - value = * ( field - content / obs - fold )
* field - content = field - vchar [ 1 * ( SP / HTAB ) field - vchar ]
* obs - fold = CRLF 1 * ( SP / HTAB )
* field - vchar = VCHAR / obs - text
* VCHAR = % x21 - 7 E
* obs - text = % x80 - FF
*
* All the chars are encoded except " VCHAR " , " obs-text " , SP and HTAB .
* The encoded chars are form 0x00 to 0x08 , 0x0a to 0x1f and 0x7f . The
2018-11-15 15:10:04 -05:00
* " obs-fold " is voluntarily forgotten because haproxy remove this .
2018-09-10 12:16:53 -04:00
*/
memset ( http_encode_map , 0 , sizeof ( http_encode_map ) ) ;
for ( i = 0x00 ; i < = 0x08 ; i + + )
2019-06-07 05:10:07 -04:00
ha_bit_set ( i , http_encode_map ) ;
2018-09-10 12:16:53 -04:00
for ( i = 0x0a ; i < = 0x1f ; i + + )
2019-06-07 05:10:07 -04:00
ha_bit_set ( i , http_encode_map ) ;
ha_bit_set ( 0x7f , http_encode_map ) ;
2016-02-12 07:23:03 -05:00
}
2018-11-26 10:31:20 -05:00
INITCALL0 ( STG_PREPARE , init_log ) ;
2017-07-26 09:33:35 -04:00
/* Initialize log buffers used for syslog messages */
int init_log_buffers ( )
{
logline = my_realloc2 ( logline , global . max_syslog_len + 1 ) ;
logline_rfc5424 = my_realloc2 ( logline_rfc5424 , global . max_syslog_len + 1 ) ;
2020-07-06 09:54:06 -04:00
if ( ! logline | | ! logline_rfc5424 )
2017-07-26 09:33:35 -04:00
return 0 ;
return 1 ;
}
/* Deinitialize log buffers used for syslog messages */
void deinit_log_buffers ( )
{
free ( logline ) ;
free ( logline_rfc5424 ) ;
logline = NULL ;
logline_rfc5424 = NULL ;
}
2023-07-03 12:07:30 -04:00
/* Deinitialize log forwarder proxies used for syslog messages */
void deinit_log_forward ( )
{
struct proxy * p , * p0 ;
p = cfg_log_forward ;
/* we need to manually clean cfg_log_forward proxy list */
while ( p ) {
p0 = p ;
p = p - > next ;
free_proxy ( p0 ) ;
}
}
2024-02-22 09:03:29 -05:00
/* Releases memory for a single log-format node */
void free_logformat_node ( struct logformat_node * node )
{
if ( ! node )
return ;
release_sample_expr ( node - > expr ) ;
node - > expr = NULL ;
ha_free ( & node - > name ) ;
ha_free ( & node - > arg ) ;
ha_free ( & node ) ;
}
2024-01-29 21:14:09 -05:00
/* Releases memory allocated for a log-format string */
void free_logformat_list ( struct list * fmt )
{
struct logformat_node * lf , * lfb ;
if ( ( fmt = = NULL ) | | LIST_ISEMPTY ( fmt ) )
return ;
list_for_each_entry_safe ( lf , lfb , fmt , list ) {
LIST_DELETE ( & lf - > list ) ;
2024-02-22 09:03:29 -05:00
free_logformat_node ( lf ) ;
2024-01-29 21:14:09 -05:00
}
}
2024-02-23 09:57:21 -05:00
/* Prepares log-format expression struct */
void lf_expr_init ( struct lf_expr * expr )
{
MAJOR: log: implement proper postparsing for logformat expressions
This patch tries to address a design flaw with how logformat expressions
are parsed from config. Indeed, some parse_logformat_string() calls are
performed during config parsing when the proxy mode is not yet known.
Here's a config example that illustrates the issue:
defaults
mode tcp
listen test
bind :8888
http-response set-header custom-hdr "%trl" # needs http
mode http
The above config should work, because the effective proxy mode is http,
yet haproxy fails with this error:
[ALERT] (99051) : config : parsing [repro.conf:6] : error detected in proxy 'test' while parsing 'http-response set-header' rule : format tag 'trl' is reserved for HTTP mode.
To fix the issue once and for all, let's implement smart postparsing for
logformat expressions encountered during config parsing:
- split parse_logformat_string() (and subfonctions) in order to create a
new lf_expr_postcheck() function that must be called to finish
preparing and checking the logformat expression once the proxy type is
known.
- save some config hints info during parse_logformat_string() to
generate more precise error messages during lf_expr_postcheck(), if
needed, we rely on curpx->conf.args.{file,line} hints for that because
parse_logformat_string() doesn't know about current file and line
number.
- lf_expr_postcheck() uses PR_FL_CHECKED proxy flag to know if the
function may try to make the proxy compatible with the expression, or
if it should simply fail as soon as an incompatibility is detected.
- if parse_logformat_string() is called from an unchecked proxy, then
schedule the expression for postparsing, else (ie: during runtime),
run the postcheck right away.
This change will also allow for some logformat expression error handling
simplifications in the future.
2024-02-23 11:26:32 -05:00
LIST_INIT ( & expr - > list ) ;
2024-02-29 08:54:43 -05:00
expr - > flags = LF_FL_NONE ;
expr - > str = NULL ;
MAJOR: log: implement proper postparsing for logformat expressions
This patch tries to address a design flaw with how logformat expressions
are parsed from config. Indeed, some parse_logformat_string() calls are
performed during config parsing when the proxy mode is not yet known.
Here's a config example that illustrates the issue:
defaults
mode tcp
listen test
bind :8888
http-response set-header custom-hdr "%trl" # needs http
mode http
The above config should work, because the effective proxy mode is http,
yet haproxy fails with this error:
[ALERT] (99051) : config : parsing [repro.conf:6] : error detected in proxy 'test' while parsing 'http-response set-header' rule : format tag 'trl' is reserved for HTTP mode.
To fix the issue once and for all, let's implement smart postparsing for
logformat expressions encountered during config parsing:
- split parse_logformat_string() (and subfonctions) in order to create a
new lf_expr_postcheck() function that must be called to finish
preparing and checking the logformat expression once the proxy type is
known.
- save some config hints info during parse_logformat_string() to
generate more precise error messages during lf_expr_postcheck(), if
needed, we rely on curpx->conf.args.{file,line} hints for that because
parse_logformat_string() doesn't know about current file and line
number.
- lf_expr_postcheck() uses PR_FL_CHECKED proxy flag to know if the
function may try to make the proxy compatible with the expression, or
if it should simply fail as soon as an incompatibility is detected.
- if parse_logformat_string() is called from an unchecked proxy, then
schedule the expression for postparsing, else (ie: during runtime),
run the postcheck right away.
This change will also allow for some logformat expression error handling
simplifications in the future.
2024-02-23 11:26:32 -05:00
expr - > conf . file = NULL ;
expr - > conf . line = 0 ;
2024-02-23 09:57:21 -05:00
}
/* Releases and resets a log-format expression */
void lf_expr_deinit ( struct lf_expr * expr )
{
2024-02-29 08:54:43 -05:00
if ( ( expr - > flags & LF_FL_COMPILED ) )
2024-03-25 06:29:58 -04:00
free_logformat_list ( & expr - > nodes . list ) ;
2024-02-29 08:54:43 -05:00
else
MEDIUM: proxy/log: leverage lf_expr API for logformat preparsing
Currently, the way proxy-oriented logformat directives are handled is way
too complicated. Indeed, "log-format", "log-format-error", "log-format-sd"
and "unique-id-format" all rely on preparsing hints stored inside
proxy->conf member struct. Those preparsing hints include the original
string that should be compiled once the proxy parameters are known plus
the config file and line number where the string was found to generate
precise error messages in case of failure during the compiling process
that happens within check_config_validity().
Now that lf_expr API permits to compile a lf_expr struct that was
previously prepared (with original string and config hints), let's
leverage lf_expr_compile() from check_config_validity() and instead
of relying on individual proxy->conf hints for each logformat expression,
store string and config hints in the lf_expr struct directly and use
lf_expr helpers funcs to handle them when relevant (ie: original
logformat string freeing is now done at a central place inside
lf_expr_deinit(), which allows for some simplifications)
Doing so allows us to greatly simplify the preparsing logic for those 4
proxy directives, and to finally save some space in the proxy struct.
Also, since httpclient proxy has its "logformat" automatically compiled
in check_config_validity(), we now use the file hint from the logformat
expression struct to set an explicit name that will be reported in case
of error ("parsing [httpclient:0] : ...") and remove the extraneous check
in httpclient_precheck() (logformat was parsed twice previously..)
2024-03-05 09:44:43 -05:00
logformat_str_free ( & expr - > str ) ;
MAJOR: log: implement proper postparsing for logformat expressions
This patch tries to address a design flaw with how logformat expressions
are parsed from config. Indeed, some parse_logformat_string() calls are
performed during config parsing when the proxy mode is not yet known.
Here's a config example that illustrates the issue:
defaults
mode tcp
listen test
bind :8888
http-response set-header custom-hdr "%trl" # needs http
mode http
The above config should work, because the effective proxy mode is http,
yet haproxy fails with this error:
[ALERT] (99051) : config : parsing [repro.conf:6] : error detected in proxy 'test' while parsing 'http-response set-header' rule : format tag 'trl' is reserved for HTTP mode.
To fix the issue once and for all, let's implement smart postparsing for
logformat expressions encountered during config parsing:
- split parse_logformat_string() (and subfonctions) in order to create a
new lf_expr_postcheck() function that must be called to finish
preparing and checking the logformat expression once the proxy type is
known.
- save some config hints info during parse_logformat_string() to
generate more precise error messages during lf_expr_postcheck(), if
needed, we rely on curpx->conf.args.{file,line} hints for that because
parse_logformat_string() doesn't know about current file and line
number.
- lf_expr_postcheck() uses PR_FL_CHECKED proxy flag to know if the
function may try to make the proxy compatible with the expression, or
if it should simply fail as soon as an incompatibility is detected.
- if parse_logformat_string() is called from an unchecked proxy, then
schedule the expression for postparsing, else (ie: during runtime),
run the postcheck right away.
This change will also allow for some logformat expression error handling
simplifications in the future.
2024-02-23 11:26:32 -05:00
free ( expr - > conf . file ) ;
/* remove from parent list (if any) */
LIST_DEL_INIT ( & expr - > list ) ;
2024-02-23 09:57:21 -05:00
lf_expr_init ( expr ) ;
}
2024-02-29 08:54:43 -05:00
/* Transfer a compiled log-format expression from <src> to <dst>
2024-02-23 09:57:21 -05:00
* at the end of the operation , < src > is reset
*/
void lf_expr_xfer ( struct lf_expr * src , struct lf_expr * dst )
{
struct logformat_node * lf , * lfb ;
/* first, reset any existing expr */
lf_expr_deinit ( dst ) ;
2024-02-29 08:54:43 -05:00
BUG_ON ( ! ( src - > flags & LF_FL_COMPILED ) ) ;
2024-02-23 09:57:21 -05:00
/* then proceed with transfer between <src> and <dst> */
MAJOR: log: implement proper postparsing for logformat expressions
This patch tries to address a design flaw with how logformat expressions
are parsed from config. Indeed, some parse_logformat_string() calls are
performed during config parsing when the proxy mode is not yet known.
Here's a config example that illustrates the issue:
defaults
mode tcp
listen test
bind :8888
http-response set-header custom-hdr "%trl" # needs http
mode http
The above config should work, because the effective proxy mode is http,
yet haproxy fails with this error:
[ALERT] (99051) : config : parsing [repro.conf:6] : error detected in proxy 'test' while parsing 'http-response set-header' rule : format tag 'trl' is reserved for HTTP mode.
To fix the issue once and for all, let's implement smart postparsing for
logformat expressions encountered during config parsing:
- split parse_logformat_string() (and subfonctions) in order to create a
new lf_expr_postcheck() function that must be called to finish
preparing and checking the logformat expression once the proxy type is
known.
- save some config hints info during parse_logformat_string() to
generate more precise error messages during lf_expr_postcheck(), if
needed, we rely on curpx->conf.args.{file,line} hints for that because
parse_logformat_string() doesn't know about current file and line
number.
- lf_expr_postcheck() uses PR_FL_CHECKED proxy flag to know if the
function may try to make the proxy compatible with the expression, or
if it should simply fail as soon as an incompatibility is detected.
- if parse_logformat_string() is called from an unchecked proxy, then
schedule the expression for postparsing, else (ie: during runtime),
run the postcheck right away.
This change will also allow for some logformat expression error handling
simplifications in the future.
2024-02-23 11:26:32 -05:00
dst - > conf . file = src - > conf . file ;
dst - > conf . line = src - > conf . line ;
2024-02-29 08:54:43 -05:00
dst - > flags | = LF_FL_COMPILED ;
2024-03-25 06:29:58 -04:00
LIST_INIT ( & dst - > nodes . list ) ;
2024-02-29 08:54:43 -05:00
2024-03-25 06:29:58 -04:00
list_for_each_entry_safe ( lf , lfb , & src - > nodes . list , list ) {
2024-02-23 09:57:21 -05:00
LIST_DELETE ( & lf - > list ) ;
2024-03-25 06:29:58 -04:00
LIST_APPEND ( & dst - > nodes . list , & lf - > list ) ;
2024-02-23 09:57:21 -05:00
}
MAJOR: log: implement proper postparsing for logformat expressions
This patch tries to address a design flaw with how logformat expressions
are parsed from config. Indeed, some parse_logformat_string() calls are
performed during config parsing when the proxy mode is not yet known.
Here's a config example that illustrates the issue:
defaults
mode tcp
listen test
bind :8888
http-response set-header custom-hdr "%trl" # needs http
mode http
The above config should work, because the effective proxy mode is http,
yet haproxy fails with this error:
[ALERT] (99051) : config : parsing [repro.conf:6] : error detected in proxy 'test' while parsing 'http-response set-header' rule : format tag 'trl' is reserved for HTTP mode.
To fix the issue once and for all, let's implement smart postparsing for
logformat expressions encountered during config parsing:
- split parse_logformat_string() (and subfonctions) in order to create a
new lf_expr_postcheck() function that must be called to finish
preparing and checking the logformat expression once the proxy type is
known.
- save some config hints info during parse_logformat_string() to
generate more precise error messages during lf_expr_postcheck(), if
needed, we rely on curpx->conf.args.{file,line} hints for that because
parse_logformat_string() doesn't know about current file and line
number.
- lf_expr_postcheck() uses PR_FL_CHECKED proxy flag to know if the
function may try to make the proxy compatible with the expression, or
if it should simply fail as soon as an incompatibility is detected.
- if parse_logformat_string() is called from an unchecked proxy, then
schedule the expression for postparsing, else (ie: during runtime),
run the postcheck right away.
This change will also allow for some logformat expression error handling
simplifications in the future.
2024-02-23 11:26:32 -05:00
/* replace <src> with <dst> in <src>'s list by first adding
* < dst > after < src > , then removing < src > . . .
*/
LIST_INSERT ( & src - > list , & dst - > list ) ;
LIST_DEL_INIT ( & src - > list ) ;
2024-02-23 09:57:21 -05:00
/* src is now empty, perform an explicit reset */
lf_expr_init ( src ) ;
}
2024-02-29 08:54:43 -05:00
/* tries to duplicate an uncompiled logformat expression from <orig> to <dest>
*
* Returns 1 on success and 0 on failure .
*/
int lf_expr_dup ( const struct lf_expr * orig , struct lf_expr * dest )
{
BUG_ON ( ( orig - > flags & LF_FL_COMPILED ) ) ;
lf_expr_deinit ( dest ) ;
if ( orig - > str ) {
MEDIUM: proxy/log: leverage lf_expr API for logformat preparsing
Currently, the way proxy-oriented logformat directives are handled is way
too complicated. Indeed, "log-format", "log-format-error", "log-format-sd"
and "unique-id-format" all rely on preparsing hints stored inside
proxy->conf member struct. Those preparsing hints include the original
string that should be compiled once the proxy parameters are known plus
the config file and line number where the string was found to generate
precise error messages in case of failure during the compiling process
that happens within check_config_validity().
Now that lf_expr API permits to compile a lf_expr struct that was
previously prepared (with original string and config hints), let's
leverage lf_expr_compile() from check_config_validity() and instead
of relying on individual proxy->conf hints for each logformat expression,
store string and config hints in the lf_expr struct directly and use
lf_expr helpers funcs to handle them when relevant (ie: original
logformat string freeing is now done at a central place inside
lf_expr_deinit(), which allows for some simplifications)
Doing so allows us to greatly simplify the preparsing logic for those 4
proxy directives, and to finally save some space in the proxy struct.
Also, since httpclient proxy has its "logformat" automatically compiled
in check_config_validity(), we now use the file hint from the logformat
expression struct to set an explicit name that will be reported in case
of error ("parsing [httpclient:0] : ...") and remove the extraneous check
in httpclient_precheck() (logformat was parsed twice previously..)
2024-03-05 09:44:43 -05:00
dest - > str = logformat_str_dup ( orig - > str ) ;
2024-02-29 08:54:43 -05:00
if ( ! dest - > str )
goto error ;
}
if ( orig - > conf . file ) {
dest - > conf . file = strdup ( orig - > conf . file ) ;
if ( ! dest - > conf . file )
goto error ;
}
dest - > conf . line = orig - > conf . line ;
return 1 ;
error :
lf_expr_deinit ( dest ) ;
return 0 ;
}
2024-02-23 09:57:21 -05:00
/* Builds a log line in <dst> based on <lf_expr>, and stops before reaching
2012-12-27 20:44:01 -05:00
* < maxsize > characters . Returns the size of the output string in characters ,
* not counting the trailing zero which is always added if the resulting size
2018-09-05 10:55:15 -04:00
* is not zero . It requires a valid session and optionally a stream . If the
* stream is NULL , default values will be assumed for the stream part .
2012-12-27 20:44:01 -05:00
*/
2024-05-06 08:13:11 -04:00
int sess_build_logline_orig ( struct session * sess , struct stream * s ,
char * dst , size_t maxsize , struct lf_expr * lf_expr ,
enum log_orig log_orig )
2006-06-25 20:48:02 -04:00
{
2024-05-02 09:30:17 -04:00
struct lf_buildctx * ctx = & lf_buildctx ;
2015-04-03 09:40:56 -04:00
struct proxy * fe = sess - > fe ;
2018-09-05 10:55:15 -04:00
struct proxy * be ;
struct http_txn * txn ;
const struct strm_logs * logs ;
2020-10-06 09:11:43 -04:00
struct connection * fe_conn , * be_conn ;
2024-03-25 06:29:58 -04:00
struct list * list_format = & lf_expr - > nodes . list ;
2018-09-05 10:55:15 -04:00
unsigned int s_flags ;
unsigned int uniq_id ;
2018-07-13 05:56:34 -04:00
struct buffer chunk ;
2012-02-27 05:23:10 -05:00
char * uri ;
2015-04-27 17:37:03 -04:00
char * spc ;
2015-07-31 12:14:16 -04:00
char * qmark ;
2015-04-27 17:37:03 -04:00
char * end ;
2007-10-25 04:34:16 -04:00
struct tm tm ;
2012-02-27 05:23:10 -05:00
int t_request ;
int hdr ;
int last_isspace = 1 ;
2015-04-27 17:37:03 -04:00
int nspaces = 0 ;
2012-03-19 11:51:53 -04:00
char * tmplog ;
2012-03-12 07:46:41 -04:00
char * ret ;
int iret ;
2020-10-06 09:11:43 -04:00
int status ;
2012-02-27 05:23:10 -05:00
struct logformat_node * tmp ;
MEDIUM: log: Decompose %Tq in %Th %Ti %TR
Tq is the time between the instant the connection is accepted and a
complete valid request is received. This time includes the handshake
(SSL / Proxy-Protocol), the idle when the browser does preconnect and
the request reception.
This patch decomposes %Tq in 3 measurements names %Th, %Ti, and %TR
which returns respectively the handshake time, the idle time and the
duration of valid request reception. It also adds %Ta which reports
the request's active time, which is the total time without %Th nor %Ti.
It replaces %Tt as the total time, reporting accurate measurements for
HTTP persistent connections.
%Th is avalaible for TCP and HTTP sessions, %Ti, %TR and %Ta are only
avalaible for HTTP connections.
In addition to this, we have new timestamps %tr, %trg and %trl, which
log the date of start of receipt of the request, respectively in the
default format, in GMT time and in local time (by analogy with %t, %T
and %Tl). All of them are obviously only available for HTTP. These values
are more relevant as they more accurately represent the request date
without being skewed by a browser's preconnect nor a keep-alive idle
time.
The HTTP log format and the CLF log format have been modified to
use %tr, %TR, and %Ta respectively instead of %t, %Tq and %Tt. This
way the default log formats now produce the expected output for users
who don't want to manually fiddle with the log-format directive.
Example with the following log-format :
log-format "%ci:%cp [%tr] %ft %b/%s h=%Th/i=%Ti/R=%TR/w=%Tw/c=%Tc/r=%Tr/a=%Ta/t=%Tt %ST %B %CC %CS %tsc %ac/%fc/%bc/%sc/%rc %sq/%bq %hr %hs %{+Q}r"
The request was sent by hand using "openssl s_client -connect" :
Aug 23 14:43:20 haproxy[25446]: 127.0.0.1:45636 [23/Aug/2016:14:43:20.221] test~ test/test h=6/i=2375/R=261/w=0/c=1/r=0/a=262/t=2643 200 145 - - ---- 1/1/0/0/0 0/0 "GET / HTTP/1.1"
=> 6 ms of SSL handshake, 2375 waiting before sending the first char (in
fact the time to type the first line), 261 ms before the end of the request,
no time spent in queue, 1 ms spend connecting to the server, immediate
response, total active time for this request = 262ms. Total time from accept
to close : 2643 ms.
The timing now decomposes like this :
first request 2nd request
|<-------------------------------->|<-------------- ...
t tr t tr ...
---|----|----|----|----|----|----|----|----|--
: Th Ti TR Tw Tc Tr Td : Ti ...
:<---- Tq ---->: :
:<-------------- Tt -------------->:
:<--------- Ta --------->:
2016-07-28 11:19:45 -04:00
struct timeval tv ;
2018-09-05 10:55:15 -04:00
struct strm_logs tmp_strm_log ;
2020-11-30 13:27:47 -05:00
struct ist path ;
2021-07-06 05:40:12 -04:00
struct http_uri_parser parser ;
2024-04-22 04:12:42 -04:00
int g_options = lf_expr - > nodes . options ; /* global */
2024-04-22 08:40:04 -04:00
int first_node = 1 ;
2006-06-25 20:48:02 -04:00
2012-02-27 05:23:10 -05:00
/* FIXME: let's limit ourselves to frontend logging for now. */
2007-03-31 19:30:43 -04:00
2018-09-05 10:55:15 -04:00
if ( likely ( s ) ) {
be = s - > be ;
txn = s - > txn ;
2022-05-18 10:23:22 -04:00
be_conn = sc_conn ( s - > scb ) ;
2020-10-06 09:11:43 -04:00
status = ( txn ? txn - > status : 0 ) ;
2018-09-05 10:55:15 -04:00
s_flags = s - > flags ;
uniq_id = s - > uniq_id ;
logs = & s - > logs ;
} else {
/* we have no stream so we first need to initialize a few
* things that are needed later . We do increment the request
* ID so that it ' s uniquely assigned to this request just as
* if the request had reached the point of being processed .
* A request error is reported as it ' s the only element we have
* here and which justifies emitting such a log .
*/
MINOR: logs: Add support of checks as session origin to format lf strings
When a log-format string is built from an health-check, the session origin
is the health-check itself and not a connection. In addition, there is no
stream. It means for now some formats are not supported: %s, %sc, %b, %bi,
%bp, %si and %sp.
Thanks to this patch, the session origin is converted to a check. So it is
possible to retrieve the backend and the backend connection. Note this
session have no listener, thus %ft format must be guarded.
This patch is light and standalone, thus it may be backported as far as 2.2
if required. However, because the error is human, it is probably better to
wait a bit to be sure everything is properly protected.
2021-04-14 08:01:41 -04:00
be = ( ( obj_type ( sess - > origin ) = = OBJ_TYPE_CHECK ) ? __objt_check ( sess - > origin ) - > proxy : fe ) ;
2018-09-05 10:55:15 -04:00
txn = NULL ;
2020-10-06 09:11:43 -04:00
fe_conn = objt_conn ( sess - > origin ) ;
2022-05-27 04:04:04 -04:00
be_conn = ( ( obj_type ( sess - > origin ) = = OBJ_TYPE_CHECK ) ? sc_conn ( __objt_check ( sess - > origin ) - > sc ) : NULL ) ;
2020-10-06 09:11:43 -04:00
status = 0 ;
2018-09-05 10:55:15 -04:00
s_flags = SF_ERR_PRXCOND | SF_FINST_R ;
2021-04-06 05:57:41 -04:00
uniq_id = _HA_ATOMIC_FETCH_ADD ( & global . req_count , 1 ) ;
2018-09-05 10:55:15 -04:00
/* prepare a valid log structure */
2023-04-27 03:46:02 -04:00
tmp_strm_log . accept_ts = sess - > accept_ts ;
2018-09-05 10:55:15 -04:00
tmp_strm_log . accept_date = sess - > accept_date ;
tmp_strm_log . t_handshake = sess - > t_handshake ;
2020-09-30 09:10:07 -04:00
tmp_strm_log . t_idle = ( sess - > t_idle > = 0 ? sess - > t_idle : 0 ) ;
2023-04-27 03:46:02 -04:00
tmp_strm_log . request_ts = 0 ;
2018-09-05 10:55:15 -04:00
tmp_strm_log . t_queue = - 1 ;
tmp_strm_log . t_connect = - 1 ;
tmp_strm_log . t_data = - 1 ;
2023-04-28 03:16:15 -04:00
tmp_strm_log . t_close = ns_to_ms ( now_ns - sess - > accept_ts ) ;
2018-09-05 10:55:15 -04:00
tmp_strm_log . bytes_in = 0 ;
tmp_strm_log . bytes_out = 0 ;
tmp_strm_log . prx_queue_pos = 0 ;
tmp_strm_log . srv_queue_pos = 0 ;
logs = & tmp_strm_log ;
2020-10-06 09:11:43 -04:00
if ( ( fe - > mode = = PR_MODE_HTTP ) & & fe_conn & & fe_conn - > mux & & fe_conn - > mux - > ctl ) {
2023-11-28 08:27:51 -05:00
enum mux_exit_status es = fe_conn - > mux - > ctl ( fe_conn , MUX_CTL_EXIT_STATUS , & status ) ;
2020-10-06 09:11:43 -04:00
switch ( es ) {
case MUX_ES_SUCCESS :
break ;
case MUX_ES_INVALID_ERR :
2021-09-28 05:36:28 -04:00
status = ( status ? status : 400 ) ;
2020-10-06 09:11:43 -04:00
if ( ( fe_conn - > flags & CO_FL_ERROR ) | | conn_xprt_read0_pending ( fe_conn ) )
s_flags = SF_ERR_CLICL | SF_FINST_R ;
else
s_flags = SF_ERR_PRXCOND | SF_FINST_R ;
break ;
case MUX_ES_TOUT_ERR :
2021-09-28 05:36:28 -04:00
status = ( status ? status : 408 ) ;
2020-10-06 09:11:43 -04:00
s_flags = SF_ERR_CLITO | SF_FINST_R ;
break ;
2020-12-07 05:24:37 -05:00
case MUX_ES_NOTIMPL_ERR :
2021-09-28 05:36:28 -04:00
status = ( status ? status : 501 ) ;
2020-12-07 05:24:37 -05:00
s_flags = SF_ERR_PRXCOND | SF_FINST_R ;
break ;
2020-10-06 09:11:43 -04:00
case MUX_ES_INTERNAL_ERR :
2021-09-28 05:36:28 -04:00
status = ( status ? status : 500 ) ;
2020-10-06 09:11:43 -04:00
s_flags = SF_ERR_INTERNAL | SF_FINST_R ;
break ;
default :
break ;
}
}
2018-09-05 10:55:15 -04:00
}
2012-02-27 05:23:10 -05:00
t_request = - 1 ;
2023-04-27 03:46:02 -04:00
if ( ( llong ) ( logs - > request_ts - logs - > accept_ts ) > = 0 )
t_request = ns_to_ms ( logs - > request_ts - logs - > accept_ts ) ;
2012-02-27 05:23:10 -05:00
2012-03-12 07:46:41 -04:00
tmplog = dst ;
2009-05-10 05:57:02 -04:00
2024-05-02 09:30:17 -04:00
/* reset static ctx struct */
ctx - > in_text = 0 ;
2024-04-22 04:12:42 -04:00
/* start with global ctx by default */
2024-05-02 09:30:17 -04:00
lf_buildctx_prepare ( ctx , g_options , NULL ) ;
2024-04-22 04:12:42 -04:00
2012-02-27 05:23:10 -05:00
/* fill logbuffer */
2024-05-02 09:30:17 -04:00
if ( ! ( ctx - > options & LOG_OPT_ENCODE ) & & lf_expr_isempty ( lf_expr ) )
2012-03-12 07:46:41 -04:00
return 0 ;
2012-02-27 05:23:10 -05:00
2024-05-02 09:30:17 -04:00
if ( ctx - > options & LOG_OPT_ENCODE_JSON )
2024-04-22 08:40:04 -04:00
LOGCHAR ( ' { ' ) ;
2024-05-02 09:30:17 -04:00
else if ( ctx - > options & LOG_OPT_ENCODE_CBOR ) {
2024-04-23 04:12:46 -04:00
/* start indefinite-length map */
LOG_CBOR_BYTE ( 0xBF ) ;
}
2024-04-22 08:40:04 -04:00
2012-03-12 07:46:41 -04:00
list_for_each_entry ( tmp , list_format , list ) {
2021-10-27 05:58:05 -04:00
# ifdef USE_OPENSSL
2013-10-01 04:45:07 -04:00
struct connection * conn ;
2021-10-27 05:58:05 -04:00
# endif
2021-10-22 11:43:22 -04:00
const struct sockaddr_storage * addr ;
2012-10-12 13:48:16 -04:00
const char * src = NULL ;
2024-04-22 08:40:04 -04:00
const char * value_beg = NULL ;
2012-12-20 18:09:23 -05:00
struct sample * key ;
2024-04-22 04:12:42 -04:00
2024-04-30 09:52:57 -04:00
/* first start with basic types (use continue statement to skip
* the current node )
*/
if ( tmp - > type = = LOG_FMT_SEPARATOR ) {
if ( g_options & LOG_OPT_ENCODE ) {
/* ignored when global encoding is set */
continue ;
}
if ( ! last_isspace ) {
LOGCHAR ( ' ' ) ;
last_isspace = 1 ;
}
continue ;
}
else if ( tmp - > type = = LOG_FMT_TEXT ) {
/* text */
if ( g_options & LOG_OPT_ENCODE ) {
/* ignored when global encoding is set */
continue ;
}
src = tmp - > arg ;
iret = strlcpy2 ( tmplog , src , dst + maxsize - tmplog ) ;
if ( iret = = 0 )
goto out ;
tmplog + = iret ;
last_isspace = 0 ; /* data was written */
continue ;
}
/* dynamic types handling (use "goto next_fmt" statement to skip
* the current node )
*/
2024-04-29 09:31:17 -04:00
if ( g_options & LOG_OPT_ENCODE ) {
2024-04-22 08:40:04 -04:00
/* only consider global ctx for key encoding */
2024-05-02 09:30:17 -04:00
lf_buildctx_prepare ( ctx , g_options , NULL ) ;
2024-04-22 08:40:04 -04:00
if ( ! tmp - > name )
goto next_fmt ; /* cannot represent anonymous field, ignore */
if ( ! first_node ) {
2024-05-02 09:30:17 -04:00
if ( ctx - > options & LOG_OPT_ENCODE_JSON ) {
2024-04-22 08:40:04 -04:00
LOGCHAR ( ' , ' ) ;
LOGCHAR ( ' ' ) ;
}
}
2024-05-02 09:30:17 -04:00
if ( ctx - > options & LOG_OPT_ENCODE_JSON ) {
2024-04-22 08:40:04 -04:00
LOGCHAR ( ' " ' ) ;
iret = strlcpy2 ( tmplog , tmp - > name , dst + maxsize - tmplog ) ;
if ( iret = = 0 )
goto out ;
tmplog + = iret ;
LOGCHAR ( ' " ' ) ;
LOGCHAR ( ' : ' ) ;
LOGCHAR ( ' ' ) ;
}
2024-05-02 09:30:17 -04:00
else if ( ctx - > options & LOG_OPT_ENCODE_CBOR ) {
ret = cbor_encode_text ( & ctx - > encode . cbor , tmplog ,
2024-04-23 04:12:46 -04:00
dst + maxsize , tmp - > name ,
strlen ( tmp - > name ) ) ;
if ( ret = = NULL )
goto out ;
tmplog = ret ;
}
2024-04-22 08:40:04 -04:00
first_node = 0 ;
}
value_beg = tmplog ;
2024-04-22 04:12:42 -04:00
/* get the chance to consider per-node options (if not already
* set globally ) for printing the value
*/
2024-05-02 09:30:17 -04:00
lf_buildctx_prepare ( ctx , g_options , tmp ) ;
2012-02-27 05:23:10 -05:00
2024-04-30 09:52:57 -04:00
if ( tmp - > type = = LOG_FMT_EXPR ) {
/* sample expression, may be request or response */
int type ;
2012-02-27 05:23:10 -05:00
2024-04-30 09:52:57 -04:00
key = NULL ;
2024-05-02 09:30:17 -04:00
if ( ctx - > options & LOG_OPT_REQ_CAP )
2024-04-30 09:52:57 -04:00
key = sample_process ( be , sess , s , SMP_OPT_DIR_REQ | SMP_OPT_FINAL , tmp - > expr , NULL ) ;
2012-02-27 05:23:10 -05:00
2024-05-02 09:30:17 -04:00
if ( ! key & & ( ctx - > options & LOG_OPT_RES_CAP ) )
2024-04-30 09:52:57 -04:00
key = sample_process ( be , sess , s , SMP_OPT_DIR_RES | SMP_OPT_FINAL , tmp - > expr , NULL ) ;
2024-04-25 10:20:11 -04:00
2024-05-02 09:30:17 -04:00
if ( ! key & & ! ( ctx - > options & ( LOG_OPT_REQ_CAP | LOG_OPT_RES_CAP ) ) ) // cfg, cli
2024-04-30 09:52:57 -04:00
key = sample_process ( be , sess , s , SMP_OPT_FINAL , tmp - > expr , NULL ) ;
2021-09-03 02:53:29 -04:00
2024-04-30 09:52:57 -04:00
type = SMP_T_STR ; // default
2021-09-03 02:53:29 -04:00
2024-04-30 09:52:57 -04:00
if ( key & & key - > data . type = = SMP_T_BIN & &
2024-05-02 09:30:17 -04:00
( ctx - > options & LOG_OPT_BIN ) ) {
2024-04-30 09:52:57 -04:00
/* output type is binary, and binary option is set:
* preserve output type unless typecast is set to
* force output type to string
*/
2024-05-02 09:30:17 -04:00
if ( ctx - > typecast ! = SMP_T_STR )
2024-04-30 09:52:57 -04:00
type = SMP_T_BIN ;
}
2024-04-25 10:20:11 -04:00
2024-04-30 09:52:57 -04:00
/* if encoding is set, try to preserve output type
* with respect to typecast settings
* ( ie : str , sint , bool )
*
* Special case for cbor encoding : we also try to
* preserve bin output type since cbor encoders
* know how to deal with binary data .
*/
2024-05-02 09:30:17 -04:00
if ( ctx - > options & LOG_OPT_ENCODE ) {
if ( ctx - > typecast = = SMP_T_STR | |
ctx - > typecast = = SMP_T_SINT | |
ctx - > typecast = = SMP_T_BOOL ) {
2024-04-30 09:52:57 -04:00
/* enforce type */
2024-05-02 09:30:17 -04:00
type = ctx - > typecast ;
2024-04-25 10:29:01 -04:00
}
2024-04-30 09:52:57 -04:00
else if ( key & &
( key - > data . type = = SMP_T_SINT | |
key - > data . type = = SMP_T_BOOL | |
2024-05-02 09:30:17 -04:00
( ( ctx - > options & LOG_OPT_ENCODE_CBOR ) & &
2024-04-30 09:52:57 -04:00
key - > data . type = = SMP_T_BIN ) ) ) {
/* preserve type */
type = key - > data . type ;
2024-04-22 08:40:04 -04:00
}
2024-04-30 09:52:57 -04:00
}
2024-04-22 08:40:04 -04:00
2024-04-30 09:52:57 -04:00
if ( key & & ! sample_convert ( key , type ) )
key = NULL ;
2024-05-02 09:30:17 -04:00
if ( ctx - > options & LOG_OPT_HTTP )
2024-04-30 09:52:57 -04:00
ret = lf_encode_chunk ( tmplog , dst + maxsize ,
2024-05-02 09:30:17 -04:00
' % ' , http_encode_map , key ? & key - > data . u . str : & empty , ctx ) ;
2024-04-30 09:52:57 -04:00
else {
if ( key & & type = = SMP_T_BIN )
2016-02-12 07:23:03 -05:00
ret = lf_encode_chunk ( tmplog , dst + maxsize ,
2024-04-30 09:52:57 -04:00
0 , no_escape_map ,
& key - > data . u . str ,
2024-05-02 09:30:17 -04:00
ctx ) ;
2024-04-30 09:52:57 -04:00
else if ( key & & type = = SMP_T_SINT )
ret = lf_int_encode ( tmplog , dst + maxsize - tmplog ,
2024-05-02 09:30:17 -04:00
key - > data . u . sint , ctx ) ;
2024-04-30 09:52:57 -04:00
else if ( key & & type = = SMP_T_BOOL )
ret = lf_bool_encode ( tmplog , dst + maxsize - tmplog ,
2024-05-02 09:30:17 -04:00
key - > data . u . sint , ctx ) ;
2024-04-30 09:52:57 -04:00
else
ret = lf_text_len ( tmplog ,
key ? key - > data . u . str . area : NULL ,
key ? key - > data . u . str . data : 0 ,
dst + maxsize - tmplog ,
2024-05-02 09:30:17 -04:00
ctx ) ;
2024-04-25 10:20:11 -04:00
}
2024-04-30 09:52:57 -04:00
if ( ret = = NULL )
goto out ;
tmplog = ret ;
BUG/MINOR: log: prevent double spaces emission in sess_build_logline()
Christian reported in GH #2556 that since 3.0-dev double spaces may be
found in log messages on some cases where it was not the case before.
As we were able to easily reproduce, a quick bisect led us to c6a7138
("MINOR: log: simplify last_isspace in sess_build_logline()"). While
it is true that all switch cases set the last_isspace variable to 0,
there was a subtelty for some fields such as '%hr', '%hrl', '%hs' or
'%hsl' and I overlooked it. Indeed, for '%hr', last_isspace was only set
to 0 if data was emitted, else the assignment didn't occur.
But with c6a7138, last_isspace is always set to 0 as long as the current
node type is not a separator. Because of that, if no data is emitted for
the current node value, and a space was already emitted prior to the
current node, then an extra space could be emitted after the node,
resulting in two spaces being emitted.
Note that while c6a7138 introduces a slight behavior regression regarding
last_isspace logic with the specific fields mentionned above, this
behavior could already be triggered with a failing or empty logformat
node sample expression. Consider this logformat expression:
log-format "%{-M}o | %[str()] |"
str() will not print anything, and since we disabled mandatory option with
'-M', nothing gets printed for the node sample expression. As a result, we
have the following output:
"| |"
Instead of (when mandatory option is enabled):
"| - |"
Thus in order to stick to the historical behavior, systematically set
last_isspace to 0 for EXPR nodes, and only set last_isspace to 0 when
data was written for TAG nodes. This way, '%hr', '%hrl', '%hs' or
'%hsl' should behave as before.
No backport needed.
2024-05-02 03:30:28 -04:00
last_isspace = 0 ; /* consider that data was written */
2024-04-30 09:52:57 -04:00
goto next_fmt ;
MEDIUM: log: carry tag context in logformat node
This is a pretty simple patch despite requiring to make some visible
changes in the code:
When parsing a logformat string, log tags (ie: '%tag', AKA log tags) are
turned into logformat nodes with their type set to the type of the
corresponding logformat_tag element which was matched by name. Thus, when
"compiling" a logformat tag, we only keep a reference to the tag type
from the original logformat_tag.
For example, for "%B" log tag, we have the following logformat_tag
element:
{
.name = "B",
.type = LOG_FMT_BYTES,
.mode = PR_MODE_TCP,
.lw = LW_BYTES,
.config_callback = NULL
}
When parsing "%B" string, we search for a matching logformat tag
inside logformat_tags[] array using the provided name, once we find a
matching element, we craft a logformat node whose type will be
LOG_FMT_BYTES, but from the node itself, we no longer have access to
other informations that are set in the logformat_tag struct element.
Thus from a logformat_node resulting from a log tag, with current
implementation, we cannot easily get back to matching logformat_tag
struct element as it would require us to scan the whole logformat_tags
array at runtime using node->type to find the matching element.
Let's take a simpler path and consider all tag-specific LOG_FMT_*
subtypes as being part of the same logformat node type: LOG_FMT_TAG.
Thanks to that, we're now able to distinguish logformat nodes made
from logformat tag from other logformat nodes, and link them to
their corresponding logformat_tag element from logformat_tags[] array. All
it costs is a simple indirection and an extra pointer in logformat_node
struct.
While at it, all LOG_FMT_* types related to logformat tags were moved
inside log.c as they have no use outside of it since they are simply
lookup indexes for sess_build_logline() and could even be replaced by
function pointers some day...
2024-02-22 14:20:41 -05:00
}
MINOR: log: rename 'log-format tag' to 'log-format alias'
In 2.9 we started to introduce an ambiguity in the documentation by
referring to historical log-format variables ('%var') as log-format
tags in 739c4e5b1e ("MINOR: sample: accept_date / request_date return
%Ts / %tr timestamp values") and 454c372b60 ("DOC: configuration: add
sample fetches for timing events").
In fact, we've had this confusion between log-format tag and log-format
var for more than 10 years now, but in 2.9 it was the first time the
confusion was exposed in the documentation.
Indeed, both 'log-format variable' and 'log-format tag' actually refer
to the same feature (that is: '%B' and friends that can be used for
direct access to some log-oriented predefined fetches instead of using
%[expr] with generic sample expressions).
This feature was first implemented in 723b73ad75 ("MINOR: config: Parse
the string of the log-format config keyword") and later documented in
4894040fa ("DOC: log-format documentation"). At that time, it was clear
that we used to name it 'log-format variable'.
But later the same year, 'log-format tag' naming started to appear in
some commit messages (while still referring to the same feature), for
instance with ffc3fcd6d ("MEDIUM: log: report SSL ciphers and version
in logs using logformat %sslc/%sslv").
Unfortunately in 2.9 when we added (and documented) new log-format
variables we officially started drifting to the misleading 'log-format
tag' naming (perhaps because it was the most recent naming found for
this feature in git log history, or because the confusion has always
been there)
Even worse, in 3.0 this confusion led us to rename all 'var' occurrences
to 'tag' in log-format related code to unify the code with the doc.
Hopefully William quickly noticed that we made a mistake there, but
instead of reverting to historical naming (log-format variable), it was
decided that we must use a different name that is less confusing than
'tags' or 'variables' (tags and variables are keywords that are already
used to designate other features in the code and that are not very
explicit under log-format context today).
Now we refer to '%B' and friends as a logformat alias, which is
essentially a handy way to print some log oriented information in the
log string instead of leveraging '%[expr]' with generic sample expressions
made of fetches and converters. Of course, there are some subtelties, such
as a few log-format aliases that still don't have sample fetch equivalent
for historical reasons, and some aliases that may be a little faster than
their generic sample expression equivalents because most aliases are
pretty much hardcoded in the log building function. But in general
logformat aliases should be simply considered as an alternative to using
expressions (with '%[expr']')
Also, under log-format context, when we want to refer to either an alias
('%alias') or an expression ('%[expr]'), we should use the generic term
'logformat item', which in fact designates a single item within the
logformat string provided by the user. Indeed, a logformat item (whether
is is an alias or an expression) always starts with '%' and may accept
optional flags / arguments
Both the code and the documentation were updated in that sense, hopefully
this will clarify things and prevent future confusions.
2024-05-27 04:18:10 -04:00
BUG_ON ( tmp - > type ! = LOG_FMT_ALIAS ) ;
2012-12-20 18:09:23 -05:00
MINOR: log: rename 'log-format tag' to 'log-format alias'
In 2.9 we started to introduce an ambiguity in the documentation by
referring to historical log-format variables ('%var') as log-format
tags in 739c4e5b1e ("MINOR: sample: accept_date / request_date return
%Ts / %tr timestamp values") and 454c372b60 ("DOC: configuration: add
sample fetches for timing events").
In fact, we've had this confusion between log-format tag and log-format
var for more than 10 years now, but in 2.9 it was the first time the
confusion was exposed in the documentation.
Indeed, both 'log-format variable' and 'log-format tag' actually refer
to the same feature (that is: '%B' and friends that can be used for
direct access to some log-oriented predefined fetches instead of using
%[expr] with generic sample expressions).
This feature was first implemented in 723b73ad75 ("MINOR: config: Parse
the string of the log-format config keyword") and later documented in
4894040fa ("DOC: log-format documentation"). At that time, it was clear
that we used to name it 'log-format variable'.
But later the same year, 'log-format tag' naming started to appear in
some commit messages (while still referring to the same feature), for
instance with ffc3fcd6d ("MEDIUM: log: report SSL ciphers and version
in logs using logformat %sslc/%sslv").
Unfortunately in 2.9 when we added (and documented) new log-format
variables we officially started drifting to the misleading 'log-format
tag' naming (perhaps because it was the most recent naming found for
this feature in git log history, or because the confusion has always
been there)
Even worse, in 3.0 this confusion led us to rename all 'var' occurrences
to 'tag' in log-format related code to unify the code with the doc.
Hopefully William quickly noticed that we made a mistake there, but
instead of reverting to historical naming (log-format variable), it was
decided that we must use a different name that is less confusing than
'tags' or 'variables' (tags and variables are keywords that are already
used to designate other features in the code and that are not very
explicit under log-format context today).
Now we refer to '%B' and friends as a logformat alias, which is
essentially a handy way to print some log oriented information in the
log string instead of leveraging '%[expr]' with generic sample expressions
made of fetches and converters. Of course, there are some subtelties, such
as a few log-format aliases that still don't have sample fetch equivalent
for historical reasons, and some aliases that may be a little faster than
their generic sample expression equivalents because most aliases are
pretty much hardcoded in the log building function. But in general
logformat aliases should be simply considered as an alternative to using
expressions (with '%[expr']')
Also, under log-format context, when we want to refer to either an alias
('%alias') or an expression ('%[expr]'), we should use the generic term
'logformat item', which in fact designates a single item within the
logformat string provided by the user. Indeed, a logformat item (whether
is is an alias or an expression) always starts with '%' and may accept
optional flags / arguments
Both the code and the documentation were updated in that sense, hopefully
this will clarify things and prevent future confusions.
2024-05-27 04:18:10 -04:00
/* logformat alias */
switch ( tmp - > alias - > type ) {
2012-12-20 11:22:52 -05:00
case LOG_FMT_CLIENTIP : // %ci
2022-05-27 02:57:21 -04:00
addr = ( s ? sc_src ( s - > scf ) : sess_src ( sess ) ) ;
2021-10-22 11:43:22 -04:00
if ( addr )
2024-05-02 09:30:17 -04:00
ret = lf_ip ( tmplog , ( struct sockaddr * ) addr , dst + maxsize - tmplog , ctx ) ;
2013-10-01 04:45:07 -04:00
else
2024-05-02 09:30:17 -04:00
ret = lf_text_len ( tmplog , NULL , 0 , dst + maxsize - tmplog , ctx ) ;
2021-10-22 11:43:22 -04:00
2012-03-12 07:46:41 -04:00
if ( ret = = NULL )
2012-02-27 05:23:10 -05:00
goto out ;
2012-03-12 07:46:41 -04:00
tmplog = ret ;
2012-02-27 05:23:10 -05:00
break ;
2012-12-20 11:22:52 -05:00
case LOG_FMT_CLIENTPORT : // %cp
2022-05-27 02:57:21 -04:00
addr = ( s ? sc_src ( s - > scf ) : sess_src ( sess ) ) ;
2021-10-22 11:43:22 -04:00
if ( addr ) {
2021-11-15 05:31:08 -05:00
/* sess->listener is always defined when the session's owner is an inbound connections */
2021-10-22 11:43:22 -04:00
if ( addr - > ss_family = = AF_UNIX )
2024-03-27 05:17:11 -04:00
ret = lf_int ( tmplog , dst + maxsize - tmplog ,
2024-05-02 09:30:17 -04:00
sess - > listener - > luid , ctx , LF_INT_LTOA ) ;
2021-10-22 11:43:22 -04:00
else
2024-05-02 09:30:17 -04:00
ret = lf_port ( tmplog , ( struct sockaddr * ) addr , dst + maxsize - tmplog , ctx ) ;
2012-04-05 12:02:55 -04:00
}
2013-10-01 04:45:07 -04:00
else
2024-05-02 09:30:17 -04:00
ret = lf_text_len ( tmplog , NULL , 0 , dst + maxsize - tmplog , ctx ) ;
2013-10-01 04:45:07 -04:00
2012-04-05 12:02:55 -04:00
if ( ret = = NULL )
goto out ;
tmplog = ret ;
break ;
2012-12-20 11:22:52 -05:00
case LOG_FMT_FRONTENDIP : // %fi
2022-05-27 02:57:21 -04:00
addr = ( s ? sc_dst ( s - > scf ) : sess_dst ( sess ) ) ;
2021-10-22 11:43:22 -04:00
if ( addr )
2024-05-02 09:30:17 -04:00
ret = lf_ip ( tmplog , ( struct sockaddr * ) addr , dst + maxsize - tmplog , ctx ) ;
2013-10-01 04:45:07 -04:00
else
2024-05-02 09:30:17 -04:00
ret = lf_text_len ( tmplog , NULL , 0 , dst + maxsize - tmplog , ctx ) ;
2013-10-01 04:45:07 -04:00
2012-04-05 12:02:55 -04:00
if ( ret = = NULL )
goto out ;
tmplog = ret ;
break ;
2012-12-20 11:22:52 -05:00
case LOG_FMT_FRONTENDPORT : // %fp
2022-05-27 02:57:21 -04:00
addr = ( s ? sc_dst ( s - > scf ) : sess_dst ( sess ) ) ;
2021-10-22 11:43:22 -04:00
if ( addr ) {
2021-11-15 05:31:08 -05:00
/* sess->listener is always defined when the session's owner is an inbound connections */
2021-10-22 11:43:22 -04:00
if ( addr - > ss_family = = AF_UNIX )
2024-03-27 05:17:11 -04:00
ret = lf_int ( tmplog , dst + maxsize - tmplog ,
2024-05-02 09:30:17 -04:00
sess - > listener - > luid , ctx , LF_INT_LTOA ) ;
2013-10-01 04:45:07 -04:00
else
2024-05-02 09:30:17 -04:00
ret = lf_port ( tmplog , ( struct sockaddr * ) addr , dst + maxsize - tmplog , ctx ) ;
2012-04-05 12:02:55 -04:00
}
2013-10-01 04:45:07 -04:00
else
2024-05-02 09:30:17 -04:00
ret = lf_text_len ( tmplog , NULL , 0 , dst + maxsize - tmplog , ctx ) ;
2013-10-01 04:45:07 -04:00
2012-03-12 07:46:41 -04:00
if ( ret = = NULL )
2012-02-27 05:23:10 -05:00
goto out ;
2012-03-12 07:46:41 -04:00
tmplog = ret ;
2012-02-27 05:23:10 -05:00
break ;
2012-12-20 11:22:52 -05:00
case LOG_FMT_BACKENDIP : // %bi
2019-07-17 05:47:11 -04:00
if ( be_conn & & conn_get_src ( be_conn ) )
2024-05-02 09:30:17 -04:00
ret = lf_ip ( tmplog , ( const struct sockaddr * ) be_conn - > src , dst + maxsize - tmplog , ctx ) ;
2013-10-01 04:45:07 -04:00
else
2024-05-02 09:30:17 -04:00
ret = lf_text_len ( tmplog , NULL , 0 , dst + maxsize - tmplog , ctx ) ;
2013-10-01 04:45:07 -04:00
2012-03-12 07:46:41 -04:00
if ( ret = = NULL )
2012-03-02 08:35:21 -05:00
goto out ;
2012-03-12 07:46:41 -04:00
tmplog = ret ;
2012-03-02 08:35:21 -05:00
break ;
2012-12-20 11:22:52 -05:00
case LOG_FMT_BACKENDPORT : // %bp
2019-07-17 05:47:11 -04:00
if ( be_conn & & conn_get_src ( be_conn ) )
2024-05-02 09:30:17 -04:00
ret = lf_port ( tmplog , ( struct sockaddr * ) be_conn - > src , dst + maxsize - tmplog , ctx ) ;
2013-10-01 04:45:07 -04:00
else
2024-05-02 09:30:17 -04:00
ret = lf_text_len ( tmplog , NULL , 0 , dst + maxsize - tmplog , ctx ) ;
2013-10-01 04:45:07 -04:00
2012-04-05 12:02:55 -04:00
if ( ret = = NULL )
goto out ;
tmplog = ret ;
break ;
2012-12-20 11:22:52 -05:00
case LOG_FMT_SERVERIP : // %si
2019-07-17 05:47:11 -04:00
if ( be_conn & & conn_get_dst ( be_conn ) )
2024-05-02 09:30:17 -04:00
ret = lf_ip ( tmplog , ( struct sockaddr * ) be_conn - > dst , dst + maxsize - tmplog , ctx ) ;
2013-10-01 04:45:07 -04:00
else
2024-05-02 09:30:17 -04:00
ret = lf_text_len ( tmplog , NULL , 0 , dst + maxsize - tmplog , ctx ) ;
2013-10-01 04:45:07 -04:00
2012-04-05 12:02:55 -04:00
if ( ret = = NULL )
goto out ;
tmplog = ret ;
break ;
2012-12-20 11:22:52 -05:00
case LOG_FMT_SERVERPORT : // %sp
2019-07-17 05:47:11 -04:00
if ( be_conn & & conn_get_dst ( be_conn ) )
2024-05-02 09:30:17 -04:00
ret = lf_port ( tmplog , ( struct sockaddr * ) be_conn - > dst , dst + maxsize - tmplog , ctx ) ;
2013-10-01 04:45:07 -04:00
else
2024-05-02 09:30:17 -04:00
ret = lf_text_len ( tmplog , NULL , 0 , dst + maxsize - tmplog , ctx ) ;
2013-10-01 04:45:07 -04:00
2012-03-12 07:46:41 -04:00
if ( ret = = NULL )
2012-03-02 08:35:21 -05:00
goto out ;
2012-03-12 07:46:41 -04:00
tmplog = ret ;
2012-03-02 08:35:21 -05:00
break ;
MEDIUM: log: Decompose %Tq in %Th %Ti %TR
Tq is the time between the instant the connection is accepted and a
complete valid request is received. This time includes the handshake
(SSL / Proxy-Protocol), the idle when the browser does preconnect and
the request reception.
This patch decomposes %Tq in 3 measurements names %Th, %Ti, and %TR
which returns respectively the handshake time, the idle time and the
duration of valid request reception. It also adds %Ta which reports
the request's active time, which is the total time without %Th nor %Ti.
It replaces %Tt as the total time, reporting accurate measurements for
HTTP persistent connections.
%Th is avalaible for TCP and HTTP sessions, %Ti, %TR and %Ta are only
avalaible for HTTP connections.
In addition to this, we have new timestamps %tr, %trg and %trl, which
log the date of start of receipt of the request, respectively in the
default format, in GMT time and in local time (by analogy with %t, %T
and %Tl). All of them are obviously only available for HTTP. These values
are more relevant as they more accurately represent the request date
without being skewed by a browser's preconnect nor a keep-alive idle
time.
The HTTP log format and the CLF log format have been modified to
use %tr, %TR, and %Ta respectively instead of %t, %Tq and %Tt. This
way the default log formats now produce the expected output for users
who don't want to manually fiddle with the log-format directive.
Example with the following log-format :
log-format "%ci:%cp [%tr] %ft %b/%s h=%Th/i=%Ti/R=%TR/w=%Tw/c=%Tc/r=%Tr/a=%Ta/t=%Tt %ST %B %CC %CS %tsc %ac/%fc/%bc/%sc/%rc %sq/%bq %hr %hs %{+Q}r"
The request was sent by hand using "openssl s_client -connect" :
Aug 23 14:43:20 haproxy[25446]: 127.0.0.1:45636 [23/Aug/2016:14:43:20.221] test~ test/test h=6/i=2375/R=261/w=0/c=1/r=0/a=262/t=2643 200 145 - - ---- 1/1/0/0/0 0/0 "GET / HTTP/1.1"
=> 6 ms of SSL handshake, 2375 waiting before sending the first char (in
fact the time to type the first line), 261 ms before the end of the request,
no time spent in queue, 1 ms spend connecting to the server, immediate
response, total active time for this request = 262ms. Total time from accept
to close : 2643 ms.
The timing now decomposes like this :
first request 2nd request
|<-------------------------------->|<-------------- ...
t tr t tr ...
---|----|----|----|----|----|----|----|----|--
: Th Ti TR Tw Tc Tr Td : Ti ...
:<---- Tq ---->: :
:<-------------- Tt -------------->:
:<--------- Ta --------->:
2016-07-28 11:19:45 -04:00
case LOG_FMT_DATE : // %t = accept date
2024-04-03 05:08:15 -04:00
{
2024-05-02 10:48:56 -04:00
// "26/Apr/2024:09:39:58.774"
2024-04-03 05:08:15 -04:00
2018-09-05 09:16:23 -04:00
get_localtime ( logs - > accept_date . tv_sec , & tm ) ;
2024-05-02 11:04:28 -04:00
if ( ctx - > options & LOG_OPT_ENCODE ) {
if ( ! date2str_log ( ctx - > _buf , & tm , & logs - > accept_date , sizeof ( ctx - > _buf ) ) )
goto out ;
ret = lf_rawtext ( tmplog , ctx - > _buf , dst + maxsize - tmplog , ctx ) ;
}
else // speedup
ret = date2str_log ( tmplog , & tm , & logs - > accept_date , dst + maxsize - tmplog ) ;
2012-03-12 07:46:41 -04:00
if ( ret = = NULL )
2012-02-27 05:23:10 -05:00
goto out ;
2012-03-12 07:46:41 -04:00
tmplog = ret ;
2012-02-27 05:23:10 -05:00
break ;
2024-04-03 05:08:15 -04:00
}
2012-02-27 05:23:10 -05:00
MEDIUM: log: Decompose %Tq in %Th %Ti %TR
Tq is the time between the instant the connection is accepted and a
complete valid request is received. This time includes the handshake
(SSL / Proxy-Protocol), the idle when the browser does preconnect and
the request reception.
This patch decomposes %Tq in 3 measurements names %Th, %Ti, and %TR
which returns respectively the handshake time, the idle time and the
duration of valid request reception. It also adds %Ta which reports
the request's active time, which is the total time without %Th nor %Ti.
It replaces %Tt as the total time, reporting accurate measurements for
HTTP persistent connections.
%Th is avalaible for TCP and HTTP sessions, %Ti, %TR and %Ta are only
avalaible for HTTP connections.
In addition to this, we have new timestamps %tr, %trg and %trl, which
log the date of start of receipt of the request, respectively in the
default format, in GMT time and in local time (by analogy with %t, %T
and %Tl). All of them are obviously only available for HTTP. These values
are more relevant as they more accurately represent the request date
without being skewed by a browser's preconnect nor a keep-alive idle
time.
The HTTP log format and the CLF log format have been modified to
use %tr, %TR, and %Ta respectively instead of %t, %Tq and %Tt. This
way the default log formats now produce the expected output for users
who don't want to manually fiddle with the log-format directive.
Example with the following log-format :
log-format "%ci:%cp [%tr] %ft %b/%s h=%Th/i=%Ti/R=%TR/w=%Tw/c=%Tc/r=%Tr/a=%Ta/t=%Tt %ST %B %CC %CS %tsc %ac/%fc/%bc/%sc/%rc %sq/%bq %hr %hs %{+Q}r"
The request was sent by hand using "openssl s_client -connect" :
Aug 23 14:43:20 haproxy[25446]: 127.0.0.1:45636 [23/Aug/2016:14:43:20.221] test~ test/test h=6/i=2375/R=261/w=0/c=1/r=0/a=262/t=2643 200 145 - - ---- 1/1/0/0/0 0/0 "GET / HTTP/1.1"
=> 6 ms of SSL handshake, 2375 waiting before sending the first char (in
fact the time to type the first line), 261 ms before the end of the request,
no time spent in queue, 1 ms spend connecting to the server, immediate
response, total active time for this request = 262ms. Total time from accept
to close : 2643 ms.
The timing now decomposes like this :
first request 2nd request
|<-------------------------------->|<-------------- ...
t tr t tr ...
---|----|----|----|----|----|----|----|----|--
: Th Ti TR Tw Tc Tr Td : Ti ...
:<---- Tq ---->: :
:<-------------- Tt -------------->:
:<--------- Ta --------->:
2016-07-28 11:19:45 -04:00
case LOG_FMT_tr : // %tr = start of request date
2024-04-03 05:08:15 -04:00
{
2024-05-02 10:48:56 -04:00
// "26/Apr/2024:09:39:58.774"
2024-04-03 05:08:15 -04:00
MEDIUM: log: Decompose %Tq in %Th %Ti %TR
Tq is the time between the instant the connection is accepted and a
complete valid request is received. This time includes the handshake
(SSL / Proxy-Protocol), the idle when the browser does preconnect and
the request reception.
This patch decomposes %Tq in 3 measurements names %Th, %Ti, and %TR
which returns respectively the handshake time, the idle time and the
duration of valid request reception. It also adds %Ta which reports
the request's active time, which is the total time without %Th nor %Ti.
It replaces %Tt as the total time, reporting accurate measurements for
HTTP persistent connections.
%Th is avalaible for TCP and HTTP sessions, %Ti, %TR and %Ta are only
avalaible for HTTP connections.
In addition to this, we have new timestamps %tr, %trg and %trl, which
log the date of start of receipt of the request, respectively in the
default format, in GMT time and in local time (by analogy with %t, %T
and %Tl). All of them are obviously only available for HTTP. These values
are more relevant as they more accurately represent the request date
without being skewed by a browser's preconnect nor a keep-alive idle
time.
The HTTP log format and the CLF log format have been modified to
use %tr, %TR, and %Ta respectively instead of %t, %Tq and %Tt. This
way the default log formats now produce the expected output for users
who don't want to manually fiddle with the log-format directive.
Example with the following log-format :
log-format "%ci:%cp [%tr] %ft %b/%s h=%Th/i=%Ti/R=%TR/w=%Tw/c=%Tc/r=%Tr/a=%Ta/t=%Tt %ST %B %CC %CS %tsc %ac/%fc/%bc/%sc/%rc %sq/%bq %hr %hs %{+Q}r"
The request was sent by hand using "openssl s_client -connect" :
Aug 23 14:43:20 haproxy[25446]: 127.0.0.1:45636 [23/Aug/2016:14:43:20.221] test~ test/test h=6/i=2375/R=261/w=0/c=1/r=0/a=262/t=2643 200 145 - - ---- 1/1/0/0/0 0/0 "GET / HTTP/1.1"
=> 6 ms of SSL handshake, 2375 waiting before sending the first char (in
fact the time to type the first line), 261 ms before the end of the request,
no time spent in queue, 1 ms spend connecting to the server, immediate
response, total active time for this request = 262ms. Total time from accept
to close : 2643 ms.
The timing now decomposes like this :
first request 2nd request
|<-------------------------------->|<-------------- ...
t tr t tr ...
---|----|----|----|----|----|----|----|----|--
: Th Ti TR Tw Tc Tr Td : Ti ...
:<---- Tq ---->: :
:<-------------- Tt -------------->:
:<--------- Ta --------->:
2016-07-28 11:19:45 -04:00
/* Note that the timers are valid if we get here */
2018-09-05 09:16:23 -04:00
tv_ms_add ( & tv , & logs - > accept_date , logs - > t_idle > = 0 ? logs - > t_idle + logs - > t_handshake : 0 ) ;
MEDIUM: log: Decompose %Tq in %Th %Ti %TR
Tq is the time between the instant the connection is accepted and a
complete valid request is received. This time includes the handshake
(SSL / Proxy-Protocol), the idle when the browser does preconnect and
the request reception.
This patch decomposes %Tq in 3 measurements names %Th, %Ti, and %TR
which returns respectively the handshake time, the idle time and the
duration of valid request reception. It also adds %Ta which reports
the request's active time, which is the total time without %Th nor %Ti.
It replaces %Tt as the total time, reporting accurate measurements for
HTTP persistent connections.
%Th is avalaible for TCP and HTTP sessions, %Ti, %TR and %Ta are only
avalaible for HTTP connections.
In addition to this, we have new timestamps %tr, %trg and %trl, which
log the date of start of receipt of the request, respectively in the
default format, in GMT time and in local time (by analogy with %t, %T
and %Tl). All of them are obviously only available for HTTP. These values
are more relevant as they more accurately represent the request date
without being skewed by a browser's preconnect nor a keep-alive idle
time.
The HTTP log format and the CLF log format have been modified to
use %tr, %TR, and %Ta respectively instead of %t, %Tq and %Tt. This
way the default log formats now produce the expected output for users
who don't want to manually fiddle with the log-format directive.
Example with the following log-format :
log-format "%ci:%cp [%tr] %ft %b/%s h=%Th/i=%Ti/R=%TR/w=%Tw/c=%Tc/r=%Tr/a=%Ta/t=%Tt %ST %B %CC %CS %tsc %ac/%fc/%bc/%sc/%rc %sq/%bq %hr %hs %{+Q}r"
The request was sent by hand using "openssl s_client -connect" :
Aug 23 14:43:20 haproxy[25446]: 127.0.0.1:45636 [23/Aug/2016:14:43:20.221] test~ test/test h=6/i=2375/R=261/w=0/c=1/r=0/a=262/t=2643 200 145 - - ---- 1/1/0/0/0 0/0 "GET / HTTP/1.1"
=> 6 ms of SSL handshake, 2375 waiting before sending the first char (in
fact the time to type the first line), 261 ms before the end of the request,
no time spent in queue, 1 ms spend connecting to the server, immediate
response, total active time for this request = 262ms. Total time from accept
to close : 2643 ms.
The timing now decomposes like this :
first request 2nd request
|<-------------------------------->|<-------------- ...
t tr t tr ...
---|----|----|----|----|----|----|----|----|--
: Th Ti TR Tw Tc Tr Td : Ti ...
:<---- Tq ---->: :
:<-------------- Tt -------------->:
:<--------- Ta --------->:
2016-07-28 11:19:45 -04:00
get_localtime ( tv . tv_sec , & tm ) ;
2024-05-02 11:04:28 -04:00
if ( ctx - > options & LOG_OPT_ENCODE ) {
if ( ! date2str_log ( ctx - > _buf , & tm , & tv , sizeof ( ctx - > _buf ) ) )
goto out ;
ret = lf_rawtext ( tmplog , ctx - > _buf , dst + maxsize - tmplog , ctx ) ;
}
else // speedup
ret = date2str_log ( tmplog , & tm , & tv , dst + maxsize - tmplog ) ;
MEDIUM: log: Decompose %Tq in %Th %Ti %TR
Tq is the time between the instant the connection is accepted and a
complete valid request is received. This time includes the handshake
(SSL / Proxy-Protocol), the idle when the browser does preconnect and
the request reception.
This patch decomposes %Tq in 3 measurements names %Th, %Ti, and %TR
which returns respectively the handshake time, the idle time and the
duration of valid request reception. It also adds %Ta which reports
the request's active time, which is the total time without %Th nor %Ti.
It replaces %Tt as the total time, reporting accurate measurements for
HTTP persistent connections.
%Th is avalaible for TCP and HTTP sessions, %Ti, %TR and %Ta are only
avalaible for HTTP connections.
In addition to this, we have new timestamps %tr, %trg and %trl, which
log the date of start of receipt of the request, respectively in the
default format, in GMT time and in local time (by analogy with %t, %T
and %Tl). All of them are obviously only available for HTTP. These values
are more relevant as they more accurately represent the request date
without being skewed by a browser's preconnect nor a keep-alive idle
time.
The HTTP log format and the CLF log format have been modified to
use %tr, %TR, and %Ta respectively instead of %t, %Tq and %Tt. This
way the default log formats now produce the expected output for users
who don't want to manually fiddle with the log-format directive.
Example with the following log-format :
log-format "%ci:%cp [%tr] %ft %b/%s h=%Th/i=%Ti/R=%TR/w=%Tw/c=%Tc/r=%Tr/a=%Ta/t=%Tt %ST %B %CC %CS %tsc %ac/%fc/%bc/%sc/%rc %sq/%bq %hr %hs %{+Q}r"
The request was sent by hand using "openssl s_client -connect" :
Aug 23 14:43:20 haproxy[25446]: 127.0.0.1:45636 [23/Aug/2016:14:43:20.221] test~ test/test h=6/i=2375/R=261/w=0/c=1/r=0/a=262/t=2643 200 145 - - ---- 1/1/0/0/0 0/0 "GET / HTTP/1.1"
=> 6 ms of SSL handshake, 2375 waiting before sending the first char (in
fact the time to type the first line), 261 ms before the end of the request,
no time spent in queue, 1 ms spend connecting to the server, immediate
response, total active time for this request = 262ms. Total time from accept
to close : 2643 ms.
The timing now decomposes like this :
first request 2nd request
|<-------------------------------->|<-------------- ...
t tr t tr ...
---|----|----|----|----|----|----|----|----|--
: Th Ti TR Tw Tc Tr Td : Ti ...
:<---- Tq ---->: :
:<-------------- Tt -------------->:
:<--------- Ta --------->:
2016-07-28 11:19:45 -04:00
if ( ret = = NULL )
goto out ;
tmplog = ret ;
break ;
2024-04-03 05:08:15 -04:00
}
MEDIUM: log: Decompose %Tq in %Th %Ti %TR
Tq is the time between the instant the connection is accepted and a
complete valid request is received. This time includes the handshake
(SSL / Proxy-Protocol), the idle when the browser does preconnect and
the request reception.
This patch decomposes %Tq in 3 measurements names %Th, %Ti, and %TR
which returns respectively the handshake time, the idle time and the
duration of valid request reception. It also adds %Ta which reports
the request's active time, which is the total time without %Th nor %Ti.
It replaces %Tt as the total time, reporting accurate measurements for
HTTP persistent connections.
%Th is avalaible for TCP and HTTP sessions, %Ti, %TR and %Ta are only
avalaible for HTTP connections.
In addition to this, we have new timestamps %tr, %trg and %trl, which
log the date of start of receipt of the request, respectively in the
default format, in GMT time and in local time (by analogy with %t, %T
and %Tl). All of them are obviously only available for HTTP. These values
are more relevant as they more accurately represent the request date
without being skewed by a browser's preconnect nor a keep-alive idle
time.
The HTTP log format and the CLF log format have been modified to
use %tr, %TR, and %Ta respectively instead of %t, %Tq and %Tt. This
way the default log formats now produce the expected output for users
who don't want to manually fiddle with the log-format directive.
Example with the following log-format :
log-format "%ci:%cp [%tr] %ft %b/%s h=%Th/i=%Ti/R=%TR/w=%Tw/c=%Tc/r=%Tr/a=%Ta/t=%Tt %ST %B %CC %CS %tsc %ac/%fc/%bc/%sc/%rc %sq/%bq %hr %hs %{+Q}r"
The request was sent by hand using "openssl s_client -connect" :
Aug 23 14:43:20 haproxy[25446]: 127.0.0.1:45636 [23/Aug/2016:14:43:20.221] test~ test/test h=6/i=2375/R=261/w=0/c=1/r=0/a=262/t=2643 200 145 - - ---- 1/1/0/0/0 0/0 "GET / HTTP/1.1"
=> 6 ms of SSL handshake, 2375 waiting before sending the first char (in
fact the time to type the first line), 261 ms before the end of the request,
no time spent in queue, 1 ms spend connecting to the server, immediate
response, total active time for this request = 262ms. Total time from accept
to close : 2643 ms.
The timing now decomposes like this :
first request 2nd request
|<-------------------------------->|<-------------- ...
t tr t tr ...
---|----|----|----|----|----|----|----|----|--
: Th Ti TR Tw Tc Tr Td : Ti ...
:<---- Tq ---->: :
:<-------------- Tt -------------->:
:<--------- Ta --------->:
2016-07-28 11:19:45 -04:00
case LOG_FMT_DATEGMT : // %T = accept date, GMT
2024-04-03 05:08:15 -04:00
{
2024-05-02 10:48:56 -04:00
// "26/Apr/2024:07:41:11 +0000"
2024-04-03 05:08:15 -04:00
2018-09-05 09:16:23 -04:00
get_gmtime ( logs - > accept_date . tv_sec , & tm ) ;
2024-05-02 11:04:28 -04:00
if ( ctx - > options & LOG_OPT_ENCODE ) {
if ( ! gmt2str_log ( ctx - > _buf , & tm , sizeof ( ctx - > _buf ) ) )
goto out ;
ret = lf_rawtext ( tmplog , ctx - > _buf , dst + maxsize - tmplog , ctx ) ;
}
else // speedup
ret = gmt2str_log ( tmplog , & tm , dst + maxsize - tmplog ) ;
2012-03-12 07:46:41 -04:00
if ( ret = = NULL )
2012-02-27 05:23:10 -05:00
goto out ;
2012-03-12 07:46:41 -04:00
tmplog = ret ;
2012-10-18 22:36:09 -04:00
break ;
2024-04-03 05:08:15 -04:00
}
2012-10-18 22:36:09 -04:00
MEDIUM: log: Decompose %Tq in %Th %Ti %TR
Tq is the time between the instant the connection is accepted and a
complete valid request is received. This time includes the handshake
(SSL / Proxy-Protocol), the idle when the browser does preconnect and
the request reception.
This patch decomposes %Tq in 3 measurements names %Th, %Ti, and %TR
which returns respectively the handshake time, the idle time and the
duration of valid request reception. It also adds %Ta which reports
the request's active time, which is the total time without %Th nor %Ti.
It replaces %Tt as the total time, reporting accurate measurements for
HTTP persistent connections.
%Th is avalaible for TCP and HTTP sessions, %Ti, %TR and %Ta are only
avalaible for HTTP connections.
In addition to this, we have new timestamps %tr, %trg and %trl, which
log the date of start of receipt of the request, respectively in the
default format, in GMT time and in local time (by analogy with %t, %T
and %Tl). All of them are obviously only available for HTTP. These values
are more relevant as they more accurately represent the request date
without being skewed by a browser's preconnect nor a keep-alive idle
time.
The HTTP log format and the CLF log format have been modified to
use %tr, %TR, and %Ta respectively instead of %t, %Tq and %Tt. This
way the default log formats now produce the expected output for users
who don't want to manually fiddle with the log-format directive.
Example with the following log-format :
log-format "%ci:%cp [%tr] %ft %b/%s h=%Th/i=%Ti/R=%TR/w=%Tw/c=%Tc/r=%Tr/a=%Ta/t=%Tt %ST %B %CC %CS %tsc %ac/%fc/%bc/%sc/%rc %sq/%bq %hr %hs %{+Q}r"
The request was sent by hand using "openssl s_client -connect" :
Aug 23 14:43:20 haproxy[25446]: 127.0.0.1:45636 [23/Aug/2016:14:43:20.221] test~ test/test h=6/i=2375/R=261/w=0/c=1/r=0/a=262/t=2643 200 145 - - ---- 1/1/0/0/0 0/0 "GET / HTTP/1.1"
=> 6 ms of SSL handshake, 2375 waiting before sending the first char (in
fact the time to type the first line), 261 ms before the end of the request,
no time spent in queue, 1 ms spend connecting to the server, immediate
response, total active time for this request = 262ms. Total time from accept
to close : 2643 ms.
The timing now decomposes like this :
first request 2nd request
|<-------------------------------->|<-------------- ...
t tr t tr ...
---|----|----|----|----|----|----|----|----|--
: Th Ti TR Tw Tc Tr Td : Ti ...
:<---- Tq ---->: :
:<-------------- Tt -------------->:
:<--------- Ta --------->:
2016-07-28 11:19:45 -04:00
case LOG_FMT_trg : // %trg = start of request date, GMT
2024-04-03 05:08:15 -04:00
{
2024-05-02 10:48:56 -04:00
// "26/Apr/2024:07:41:11 +0000"
2024-04-03 05:08:15 -04:00
2018-09-05 09:16:23 -04:00
tv_ms_add ( & tv , & logs - > accept_date , logs - > t_idle > = 0 ? logs - > t_idle + logs - > t_handshake : 0 ) ;
MEDIUM: log: Decompose %Tq in %Th %Ti %TR
Tq is the time between the instant the connection is accepted and a
complete valid request is received. This time includes the handshake
(SSL / Proxy-Protocol), the idle when the browser does preconnect and
the request reception.
This patch decomposes %Tq in 3 measurements names %Th, %Ti, and %TR
which returns respectively the handshake time, the idle time and the
duration of valid request reception. It also adds %Ta which reports
the request's active time, which is the total time without %Th nor %Ti.
It replaces %Tt as the total time, reporting accurate measurements for
HTTP persistent connections.
%Th is avalaible for TCP and HTTP sessions, %Ti, %TR and %Ta are only
avalaible for HTTP connections.
In addition to this, we have new timestamps %tr, %trg and %trl, which
log the date of start of receipt of the request, respectively in the
default format, in GMT time and in local time (by analogy with %t, %T
and %Tl). All of them are obviously only available for HTTP. These values
are more relevant as they more accurately represent the request date
without being skewed by a browser's preconnect nor a keep-alive idle
time.
The HTTP log format and the CLF log format have been modified to
use %tr, %TR, and %Ta respectively instead of %t, %Tq and %Tt. This
way the default log formats now produce the expected output for users
who don't want to manually fiddle with the log-format directive.
Example with the following log-format :
log-format "%ci:%cp [%tr] %ft %b/%s h=%Th/i=%Ti/R=%TR/w=%Tw/c=%Tc/r=%Tr/a=%Ta/t=%Tt %ST %B %CC %CS %tsc %ac/%fc/%bc/%sc/%rc %sq/%bq %hr %hs %{+Q}r"
The request was sent by hand using "openssl s_client -connect" :
Aug 23 14:43:20 haproxy[25446]: 127.0.0.1:45636 [23/Aug/2016:14:43:20.221] test~ test/test h=6/i=2375/R=261/w=0/c=1/r=0/a=262/t=2643 200 145 - - ---- 1/1/0/0/0 0/0 "GET / HTTP/1.1"
=> 6 ms of SSL handshake, 2375 waiting before sending the first char (in
fact the time to type the first line), 261 ms before the end of the request,
no time spent in queue, 1 ms spend connecting to the server, immediate
response, total active time for this request = 262ms. Total time from accept
to close : 2643 ms.
The timing now decomposes like this :
first request 2nd request
|<-------------------------------->|<-------------- ...
t tr t tr ...
---|----|----|----|----|----|----|----|----|--
: Th Ti TR Tw Tc Tr Td : Ti ...
:<---- Tq ---->: :
:<-------------- Tt -------------->:
:<--------- Ta --------->:
2016-07-28 11:19:45 -04:00
get_gmtime ( tv . tv_sec , & tm ) ;
2024-05-02 11:04:28 -04:00
if ( ctx - > options & LOG_OPT_ENCODE ) {
if ( ! gmt2str_log ( ctx - > _buf , & tm , sizeof ( ctx - > _buf ) ) )
goto out ;
ret = lf_rawtext ( tmplog , ctx - > _buf , dst + maxsize - tmplog , ctx ) ;
}
else // speedup
ret = gmt2str_log ( tmplog , & tm , dst + maxsize - tmplog ) ;
MEDIUM: log: Decompose %Tq in %Th %Ti %TR
Tq is the time between the instant the connection is accepted and a
complete valid request is received. This time includes the handshake
(SSL / Proxy-Protocol), the idle when the browser does preconnect and
the request reception.
This patch decomposes %Tq in 3 measurements names %Th, %Ti, and %TR
which returns respectively the handshake time, the idle time and the
duration of valid request reception. It also adds %Ta which reports
the request's active time, which is the total time without %Th nor %Ti.
It replaces %Tt as the total time, reporting accurate measurements for
HTTP persistent connections.
%Th is avalaible for TCP and HTTP sessions, %Ti, %TR and %Ta are only
avalaible for HTTP connections.
In addition to this, we have new timestamps %tr, %trg and %trl, which
log the date of start of receipt of the request, respectively in the
default format, in GMT time and in local time (by analogy with %t, %T
and %Tl). All of them are obviously only available for HTTP. These values
are more relevant as they more accurately represent the request date
without being skewed by a browser's preconnect nor a keep-alive idle
time.
The HTTP log format and the CLF log format have been modified to
use %tr, %TR, and %Ta respectively instead of %t, %Tq and %Tt. This
way the default log formats now produce the expected output for users
who don't want to manually fiddle with the log-format directive.
Example with the following log-format :
log-format "%ci:%cp [%tr] %ft %b/%s h=%Th/i=%Ti/R=%TR/w=%Tw/c=%Tc/r=%Tr/a=%Ta/t=%Tt %ST %B %CC %CS %tsc %ac/%fc/%bc/%sc/%rc %sq/%bq %hr %hs %{+Q}r"
The request was sent by hand using "openssl s_client -connect" :
Aug 23 14:43:20 haproxy[25446]: 127.0.0.1:45636 [23/Aug/2016:14:43:20.221] test~ test/test h=6/i=2375/R=261/w=0/c=1/r=0/a=262/t=2643 200 145 - - ---- 1/1/0/0/0 0/0 "GET / HTTP/1.1"
=> 6 ms of SSL handshake, 2375 waiting before sending the first char (in
fact the time to type the first line), 261 ms before the end of the request,
no time spent in queue, 1 ms spend connecting to the server, immediate
response, total active time for this request = 262ms. Total time from accept
to close : 2643 ms.
The timing now decomposes like this :
first request 2nd request
|<-------------------------------->|<-------------- ...
t tr t tr ...
---|----|----|----|----|----|----|----|----|--
: Th Ti TR Tw Tc Tr Td : Ti ...
:<---- Tq ---->: :
:<-------------- Tt -------------->:
:<--------- Ta --------->:
2016-07-28 11:19:45 -04:00
if ( ret = = NULL )
goto out ;
tmplog = ret ;
break ;
2024-04-03 05:08:15 -04:00
}
MEDIUM: log: Decompose %Tq in %Th %Ti %TR
Tq is the time between the instant the connection is accepted and a
complete valid request is received. This time includes the handshake
(SSL / Proxy-Protocol), the idle when the browser does preconnect and
the request reception.
This patch decomposes %Tq in 3 measurements names %Th, %Ti, and %TR
which returns respectively the handshake time, the idle time and the
duration of valid request reception. It also adds %Ta which reports
the request's active time, which is the total time without %Th nor %Ti.
It replaces %Tt as the total time, reporting accurate measurements for
HTTP persistent connections.
%Th is avalaible for TCP and HTTP sessions, %Ti, %TR and %Ta are only
avalaible for HTTP connections.
In addition to this, we have new timestamps %tr, %trg and %trl, which
log the date of start of receipt of the request, respectively in the
default format, in GMT time and in local time (by analogy with %t, %T
and %Tl). All of them are obviously only available for HTTP. These values
are more relevant as they more accurately represent the request date
without being skewed by a browser's preconnect nor a keep-alive idle
time.
The HTTP log format and the CLF log format have been modified to
use %tr, %TR, and %Ta respectively instead of %t, %Tq and %Tt. This
way the default log formats now produce the expected output for users
who don't want to manually fiddle with the log-format directive.
Example with the following log-format :
log-format "%ci:%cp [%tr] %ft %b/%s h=%Th/i=%Ti/R=%TR/w=%Tw/c=%Tc/r=%Tr/a=%Ta/t=%Tt %ST %B %CC %CS %tsc %ac/%fc/%bc/%sc/%rc %sq/%bq %hr %hs %{+Q}r"
The request was sent by hand using "openssl s_client -connect" :
Aug 23 14:43:20 haproxy[25446]: 127.0.0.1:45636 [23/Aug/2016:14:43:20.221] test~ test/test h=6/i=2375/R=261/w=0/c=1/r=0/a=262/t=2643 200 145 - - ---- 1/1/0/0/0 0/0 "GET / HTTP/1.1"
=> 6 ms of SSL handshake, 2375 waiting before sending the first char (in
fact the time to type the first line), 261 ms before the end of the request,
no time spent in queue, 1 ms spend connecting to the server, immediate
response, total active time for this request = 262ms. Total time from accept
to close : 2643 ms.
The timing now decomposes like this :
first request 2nd request
|<-------------------------------->|<-------------- ...
t tr t tr ...
---|----|----|----|----|----|----|----|----|--
: Th Ti TR Tw Tc Tr Td : Ti ...
:<---- Tq ---->: :
:<-------------- Tt -------------->:
:<--------- Ta --------->:
2016-07-28 11:19:45 -04:00
case LOG_FMT_DATELOCAL : // %Tl = accept date, local
2024-04-03 05:08:15 -04:00
{
2024-05-02 10:48:56 -04:00
// "26/Apr/2024:09:42:32 +0200"
2024-04-03 05:08:15 -04:00
2018-09-05 09:16:23 -04:00
get_localtime ( logs - > accept_date . tv_sec , & tm ) ;
2024-05-02 11:04:28 -04:00
if ( ctx - > options & LOG_OPT_ENCODE ) {
if ( ! localdate2str_log ( ctx - > _buf , logs - > accept_date . tv_sec ,
& tm , sizeof ( ctx - > _buf ) ) )
goto out ;
ret = lf_rawtext ( tmplog , ctx - > _buf , dst + maxsize - tmplog , ctx ) ;
}
else // speedup
ret = localdate2str_log ( tmplog , logs - > accept_date . tv_sec ,
& tm , dst + maxsize - tmplog ) ;
2012-10-18 22:36:09 -04:00
if ( ret = = NULL )
goto out ;
tmplog = ret ;
2012-02-27 05:23:10 -05:00
break ;
2024-04-03 05:08:15 -04:00
}
2012-02-27 05:23:10 -05:00
MEDIUM: log: Decompose %Tq in %Th %Ti %TR
Tq is the time between the instant the connection is accepted and a
complete valid request is received. This time includes the handshake
(SSL / Proxy-Protocol), the idle when the browser does preconnect and
the request reception.
This patch decomposes %Tq in 3 measurements names %Th, %Ti, and %TR
which returns respectively the handshake time, the idle time and the
duration of valid request reception. It also adds %Ta which reports
the request's active time, which is the total time without %Th nor %Ti.
It replaces %Tt as the total time, reporting accurate measurements for
HTTP persistent connections.
%Th is avalaible for TCP and HTTP sessions, %Ti, %TR and %Ta are only
avalaible for HTTP connections.
In addition to this, we have new timestamps %tr, %trg and %trl, which
log the date of start of receipt of the request, respectively in the
default format, in GMT time and in local time (by analogy with %t, %T
and %Tl). All of them are obviously only available for HTTP. These values
are more relevant as they more accurately represent the request date
without being skewed by a browser's preconnect nor a keep-alive idle
time.
The HTTP log format and the CLF log format have been modified to
use %tr, %TR, and %Ta respectively instead of %t, %Tq and %Tt. This
way the default log formats now produce the expected output for users
who don't want to manually fiddle with the log-format directive.
Example with the following log-format :
log-format "%ci:%cp [%tr] %ft %b/%s h=%Th/i=%Ti/R=%TR/w=%Tw/c=%Tc/r=%Tr/a=%Ta/t=%Tt %ST %B %CC %CS %tsc %ac/%fc/%bc/%sc/%rc %sq/%bq %hr %hs %{+Q}r"
The request was sent by hand using "openssl s_client -connect" :
Aug 23 14:43:20 haproxy[25446]: 127.0.0.1:45636 [23/Aug/2016:14:43:20.221] test~ test/test h=6/i=2375/R=261/w=0/c=1/r=0/a=262/t=2643 200 145 - - ---- 1/1/0/0/0 0/0 "GET / HTTP/1.1"
=> 6 ms of SSL handshake, 2375 waiting before sending the first char (in
fact the time to type the first line), 261 ms before the end of the request,
no time spent in queue, 1 ms spend connecting to the server, immediate
response, total active time for this request = 262ms. Total time from accept
to close : 2643 ms.
The timing now decomposes like this :
first request 2nd request
|<-------------------------------->|<-------------- ...
t tr t tr ...
---|----|----|----|----|----|----|----|----|--
: Th Ti TR Tw Tc Tr Td : Ti ...
:<---- Tq ---->: :
:<-------------- Tt -------------->:
:<--------- Ta --------->:
2016-07-28 11:19:45 -04:00
case LOG_FMT_trl : // %trl = start of request date, local
2024-04-03 05:08:15 -04:00
{
2024-05-02 10:48:56 -04:00
// "26/Apr/2024:09:42:32 +0200"
2024-04-03 05:08:15 -04:00
2018-09-05 09:16:23 -04:00
tv_ms_add ( & tv , & logs - > accept_date , logs - > t_idle > = 0 ? logs - > t_idle + logs - > t_handshake : 0 ) ;
MEDIUM: log: Decompose %Tq in %Th %Ti %TR
Tq is the time between the instant the connection is accepted and a
complete valid request is received. This time includes the handshake
(SSL / Proxy-Protocol), the idle when the browser does preconnect and
the request reception.
This patch decomposes %Tq in 3 measurements names %Th, %Ti, and %TR
which returns respectively the handshake time, the idle time and the
duration of valid request reception. It also adds %Ta which reports
the request's active time, which is the total time without %Th nor %Ti.
It replaces %Tt as the total time, reporting accurate measurements for
HTTP persistent connections.
%Th is avalaible for TCP and HTTP sessions, %Ti, %TR and %Ta are only
avalaible for HTTP connections.
In addition to this, we have new timestamps %tr, %trg and %trl, which
log the date of start of receipt of the request, respectively in the
default format, in GMT time and in local time (by analogy with %t, %T
and %Tl). All of them are obviously only available for HTTP. These values
are more relevant as they more accurately represent the request date
without being skewed by a browser's preconnect nor a keep-alive idle
time.
The HTTP log format and the CLF log format have been modified to
use %tr, %TR, and %Ta respectively instead of %t, %Tq and %Tt. This
way the default log formats now produce the expected output for users
who don't want to manually fiddle with the log-format directive.
Example with the following log-format :
log-format "%ci:%cp [%tr] %ft %b/%s h=%Th/i=%Ti/R=%TR/w=%Tw/c=%Tc/r=%Tr/a=%Ta/t=%Tt %ST %B %CC %CS %tsc %ac/%fc/%bc/%sc/%rc %sq/%bq %hr %hs %{+Q}r"
The request was sent by hand using "openssl s_client -connect" :
Aug 23 14:43:20 haproxy[25446]: 127.0.0.1:45636 [23/Aug/2016:14:43:20.221] test~ test/test h=6/i=2375/R=261/w=0/c=1/r=0/a=262/t=2643 200 145 - - ---- 1/1/0/0/0 0/0 "GET / HTTP/1.1"
=> 6 ms of SSL handshake, 2375 waiting before sending the first char (in
fact the time to type the first line), 261 ms before the end of the request,
no time spent in queue, 1 ms spend connecting to the server, immediate
response, total active time for this request = 262ms. Total time from accept
to close : 2643 ms.
The timing now decomposes like this :
first request 2nd request
|<-------------------------------->|<-------------- ...
t tr t tr ...
---|----|----|----|----|----|----|----|----|--
: Th Ti TR Tw Tc Tr Td : Ti ...
:<---- Tq ---->: :
:<-------------- Tt -------------->:
:<--------- Ta --------->:
2016-07-28 11:19:45 -04:00
get_localtime ( tv . tv_sec , & tm ) ;
2024-05-02 11:04:28 -04:00
if ( ctx - > options & LOG_OPT_ENCODE ) {
if ( ! localdate2str_log ( ctx - > _buf , tv . tv_sec , & tm , sizeof ( ctx - > _buf ) ) )
goto out ;
ret = lf_rawtext ( tmplog , ctx - > _buf , dst + maxsize - tmplog , ctx ) ;
}
else // speedup
ret = localdate2str_log ( tmplog , tv . tv_sec , & tm , dst + maxsize - tmplog ) ;
MEDIUM: log: Decompose %Tq in %Th %Ti %TR
Tq is the time between the instant the connection is accepted and a
complete valid request is received. This time includes the handshake
(SSL / Proxy-Protocol), the idle when the browser does preconnect and
the request reception.
This patch decomposes %Tq in 3 measurements names %Th, %Ti, and %TR
which returns respectively the handshake time, the idle time and the
duration of valid request reception. It also adds %Ta which reports
the request's active time, which is the total time without %Th nor %Ti.
It replaces %Tt as the total time, reporting accurate measurements for
HTTP persistent connections.
%Th is avalaible for TCP and HTTP sessions, %Ti, %TR and %Ta are only
avalaible for HTTP connections.
In addition to this, we have new timestamps %tr, %trg and %trl, which
log the date of start of receipt of the request, respectively in the
default format, in GMT time and in local time (by analogy with %t, %T
and %Tl). All of them are obviously only available for HTTP. These values
are more relevant as they more accurately represent the request date
without being skewed by a browser's preconnect nor a keep-alive idle
time.
The HTTP log format and the CLF log format have been modified to
use %tr, %TR, and %Ta respectively instead of %t, %Tq and %Tt. This
way the default log formats now produce the expected output for users
who don't want to manually fiddle with the log-format directive.
Example with the following log-format :
log-format "%ci:%cp [%tr] %ft %b/%s h=%Th/i=%Ti/R=%TR/w=%Tw/c=%Tc/r=%Tr/a=%Ta/t=%Tt %ST %B %CC %CS %tsc %ac/%fc/%bc/%sc/%rc %sq/%bq %hr %hs %{+Q}r"
The request was sent by hand using "openssl s_client -connect" :
Aug 23 14:43:20 haproxy[25446]: 127.0.0.1:45636 [23/Aug/2016:14:43:20.221] test~ test/test h=6/i=2375/R=261/w=0/c=1/r=0/a=262/t=2643 200 145 - - ---- 1/1/0/0/0 0/0 "GET / HTTP/1.1"
=> 6 ms of SSL handshake, 2375 waiting before sending the first char (in
fact the time to type the first line), 261 ms before the end of the request,
no time spent in queue, 1 ms spend connecting to the server, immediate
response, total active time for this request = 262ms. Total time from accept
to close : 2643 ms.
The timing now decomposes like this :
first request 2nd request
|<-------------------------------->|<-------------- ...
t tr t tr ...
---|----|----|----|----|----|----|----|----|--
: Th Ti TR Tw Tc Tr Td : Ti ...
:<---- Tq ---->: :
:<-------------- Tt -------------->:
:<--------- Ta --------->:
2016-07-28 11:19:45 -04:00
if ( ret = = NULL )
goto out ;
tmplog = ret ;
break ;
2024-04-03 05:08:15 -04:00
}
MEDIUM: log: Decompose %Tq in %Th %Ti %TR
Tq is the time between the instant the connection is accepted and a
complete valid request is received. This time includes the handshake
(SSL / Proxy-Protocol), the idle when the browser does preconnect and
the request reception.
This patch decomposes %Tq in 3 measurements names %Th, %Ti, and %TR
which returns respectively the handshake time, the idle time and the
duration of valid request reception. It also adds %Ta which reports
the request's active time, which is the total time without %Th nor %Ti.
It replaces %Tt as the total time, reporting accurate measurements for
HTTP persistent connections.
%Th is avalaible for TCP and HTTP sessions, %Ti, %TR and %Ta are only
avalaible for HTTP connections.
In addition to this, we have new timestamps %tr, %trg and %trl, which
log the date of start of receipt of the request, respectively in the
default format, in GMT time and in local time (by analogy with %t, %T
and %Tl). All of them are obviously only available for HTTP. These values
are more relevant as they more accurately represent the request date
without being skewed by a browser's preconnect nor a keep-alive idle
time.
The HTTP log format and the CLF log format have been modified to
use %tr, %TR, and %Ta respectively instead of %t, %Tq and %Tt. This
way the default log formats now produce the expected output for users
who don't want to manually fiddle with the log-format directive.
Example with the following log-format :
log-format "%ci:%cp [%tr] %ft %b/%s h=%Th/i=%Ti/R=%TR/w=%Tw/c=%Tc/r=%Tr/a=%Ta/t=%Tt %ST %B %CC %CS %tsc %ac/%fc/%bc/%sc/%rc %sq/%bq %hr %hs %{+Q}r"
The request was sent by hand using "openssl s_client -connect" :
Aug 23 14:43:20 haproxy[25446]: 127.0.0.1:45636 [23/Aug/2016:14:43:20.221] test~ test/test h=6/i=2375/R=261/w=0/c=1/r=0/a=262/t=2643 200 145 - - ---- 1/1/0/0/0 0/0 "GET / HTTP/1.1"
=> 6 ms of SSL handshake, 2375 waiting before sending the first char (in
fact the time to type the first line), 261 ms before the end of the request,
no time spent in queue, 1 ms spend connecting to the server, immediate
response, total active time for this request = 262ms. Total time from accept
to close : 2643 ms.
The timing now decomposes like this :
first request 2nd request
|<-------------------------------->|<-------------- ...
t tr t tr ...
---|----|----|----|----|----|----|----|----|--
: Th Ti TR Tw Tc Tr Td : Ti ...
:<---- Tq ---->: :
:<-------------- Tt -------------->:
:<--------- Ta --------->:
2016-07-28 11:19:45 -04:00
2012-04-05 12:02:55 -04:00
case LOG_FMT_TS : // %Ts
2024-03-26 06:50:50 -04:00
{
unsigned long value = logs - > accept_date . tv_sec ;
2024-05-02 09:30:17 -04:00
if ( ctx - > options & LOG_OPT_HEXA ) {
2024-05-02 10:48:56 -04:00
iret = snprintf ( ctx - > _buf , sizeof ( ctx - > _buf ) , " %04X " , ( unsigned int ) value ) ;
BUG/MINOR: log: invalid snprintf() usage in sess_build_logline()
According to snprintf() man page:
The functions snprintf() and vsnprintf() do not write more than
size bytes (including the terminating null byte ('\0')). If the
output was truncated due to this limit, then the return value is
the number of characters (excluding the terminating null byte)
which would have been written to the final string if enough space
had been available. Thus, a return value of size or more means
that the output was truncated.
However, in sess_build_logline(), each time we need to check the return
value of snprintf(), here is how we proceed:
iret = snprintf(tmplog, max, ...);
if (iret < 0 || iret > max)
// error
// success
tmplog += iret;
Here is the issue: if snprintf() lacks 1 byte space to write the
terminating NULL byte, it will return max. Which means in this case
that we fail to know that snprintf() truncated the output in reality,
and we still add iret to tmplog pointer. Considering sess_build_logline()
should NOT write more than <maxsize> bytes (including the terminating NULL
byte) as per the function description, in this case the function would
write <maxsize>+1 byte (to write the terminating NULL byte upon return),
which may lead to invalid write if <dst> was meant to hold <maxsize> bytes
at maximum.
Hopefully, this bug wasn't triggered so far because sess_build_logline()
is called with logline as <dst> argument and <global.max_syslog_len> as
<maxsize> argument, logline being initialized with 1 extra byte upon
startup.
But we better fix this to comply with the function description and prevent
any side-effect since some sess_build_logline() helpers may assume that
'tmplog-dst < maxsize' is always true. Also sess_build_logline() users
probably don't expect NULL-byte to be accounted for in the produced
logline length.
This should be backported to all stable versions.
[ada: for backports, the patch needs to be applied manually because of
c6a713842 ("MINOR: log: simplify last_isspace in sess_build_logline()")]
2024-04-09 09:59:42 -04:00
if ( iret < 0 | | iret > = dst + maxsize - tmplog )
2012-04-05 12:02:55 -04:00
goto out ;
2024-05-02 10:48:56 -04:00
ret = lf_rawtext ( tmplog , ctx - > _buf , dst + maxsize - tmplog , ctx ) ;
2012-04-05 12:02:55 -04:00
} else {
2024-05-02 09:30:17 -04:00
ret = lf_int ( tmplog , dst + maxsize - tmplog , value , ctx , LF_INT_LTOA ) ;
2012-04-05 12:02:55 -04:00
}
2024-03-27 05:28:59 -04:00
if ( ret = = NULL )
goto out ;
tmplog = ret ;
2024-03-26 06:50:50 -04:00
break ;
}
2012-04-05 12:02:55 -04:00
2012-03-12 07:46:41 -04:00
case LOG_FMT_MS : // %ms
2024-03-26 06:50:50 -04:00
{
unsigned int value = ( unsigned int ) logs - > accept_date . tv_usec / 1000 ;
2024-05-02 09:30:17 -04:00
if ( ctx - > options & LOG_OPT_HEXA ) {
2024-05-02 10:48:56 -04:00
iret = snprintf ( ctx - > _buf , sizeof ( ctx - > _buf ) , " %02X " , value ) ;
BUG/MINOR: log: invalid snprintf() usage in sess_build_logline()
According to snprintf() man page:
The functions snprintf() and vsnprintf() do not write more than
size bytes (including the terminating null byte ('\0')). If the
output was truncated due to this limit, then the return value is
the number of characters (excluding the terminating null byte)
which would have been written to the final string if enough space
had been available. Thus, a return value of size or more means
that the output was truncated.
However, in sess_build_logline(), each time we need to check the return
value of snprintf(), here is how we proceed:
iret = snprintf(tmplog, max, ...);
if (iret < 0 || iret > max)
// error
// success
tmplog += iret;
Here is the issue: if snprintf() lacks 1 byte space to write the
terminating NULL byte, it will return max. Which means in this case
that we fail to know that snprintf() truncated the output in reality,
and we still add iret to tmplog pointer. Considering sess_build_logline()
should NOT write more than <maxsize> bytes (including the terminating NULL
byte) as per the function description, in this case the function would
write <maxsize>+1 byte (to write the terminating NULL byte upon return),
which may lead to invalid write if <dst> was meant to hold <maxsize> bytes
at maximum.
Hopefully, this bug wasn't triggered so far because sess_build_logline()
is called with logline as <dst> argument and <global.max_syslog_len> as
<maxsize> argument, logline being initialized with 1 extra byte upon
startup.
But we better fix this to comply with the function description and prevent
any side-effect since some sess_build_logline() helpers may assume that
'tmplog-dst < maxsize' is always true. Also sess_build_logline() users
probably don't expect NULL-byte to be accounted for in the produced
logline length.
This should be backported to all stable versions.
[ada: for backports, the patch needs to be applied manually because of
c6a713842 ("MINOR: log: simplify last_isspace in sess_build_logline()")]
2024-04-09 09:59:42 -04:00
if ( iret < 0 | | iret > = dst + maxsize - tmplog )
2012-04-05 12:02:55 -04:00
goto out ;
2024-05-02 10:48:56 -04:00
ret = lf_rawtext ( tmplog , ctx - > _buf , dst + maxsize - tmplog , ctx ) ;
2024-03-26 06:50:50 -04:00
} else {
2024-03-27 05:17:11 -04:00
ret = lf_int ( tmplog , dst + maxsize - tmplog , value ,
2024-05-02 09:30:17 -04:00
ctx , LF_INT_UTOA_PAD_4 ) ;
2024-03-26 06:50:50 -04:00
}
2024-03-27 05:28:59 -04:00
if ( ret = = NULL )
goto out ;
tmplog = ret ;
2024-03-26 06:50:50 -04:00
break ;
2012-04-05 12:02:55 -04:00
}
2012-02-27 05:23:10 -05:00
2012-03-12 07:46:41 -04:00
case LOG_FMT_FRONTEND : // %f
2012-02-27 05:23:10 -05:00
src = fe - > id ;
2024-05-02 09:30:17 -04:00
ret = lf_text ( tmplog , src , dst + maxsize - tmplog , ctx ) ;
2012-03-12 07:46:41 -04:00
if ( ret = = NULL )
2012-02-27 05:23:10 -05:00
goto out ;
2012-03-12 07:46:41 -04:00
tmplog = ret ;
2012-02-27 05:23:10 -05:00
break ;
2012-10-12 08:56:11 -04:00
case LOG_FMT_FRONTEND_XPRT : // %ft
src = fe - > id ;
2024-04-16 05:17:55 -04:00
LOG_VARTEXT_START ( ) ;
2024-05-02 09:30:17 -04:00
ret = lf_rawtext ( tmplog , src , dst + maxsize - tmplog , ctx ) ;
2024-03-27 05:28:59 -04:00
if ( ret = = NULL )
2012-10-12 08:56:11 -04:00
goto out ;
2024-03-27 05:28:59 -04:00
tmplog = ret ;
2021-11-15 05:31:08 -05:00
/* sess->listener may be undefined if the session's owner is a health-check */
2022-04-12 02:08:33 -04:00
if ( sess - > listener & & sess - > listener - > bind_conf - > xprt - > get_ssl_sock_ctx )
2012-10-12 08:56:11 -04:00
LOGCHAR ( ' ~ ' ) ;
break ;
2012-10-12 14:17:54 -04:00
# ifdef USE_OPENSSL
case LOG_FMT_SSL_CIPHER : // %sslc
src = NULL ;
2015-04-03 13:19:59 -04:00
conn = objt_conn ( sess - > origin ) ;
2013-10-01 04:45:07 -04:00
if ( conn ) {
2017-10-13 10:59:49 -04:00
src = ssl_sock_get_cipher_name ( conn ) ;
2013-10-01 04:45:07 -04:00
}
2024-05-02 09:30:17 -04:00
ret = lf_text ( tmplog , src , dst + maxsize - tmplog , ctx ) ;
2012-10-12 14:17:54 -04:00
if ( ret = = NULL )
goto out ;
tmplog = ret ;
break ;
2012-10-12 08:56:11 -04:00
2012-10-12 14:17:54 -04:00
case LOG_FMT_SSL_VERSION : // %sslv
src = NULL ;
2015-04-03 13:19:59 -04:00
conn = objt_conn ( sess - > origin ) ;
2013-10-01 04:45:07 -04:00
if ( conn ) {
2017-10-13 10:59:49 -04:00
src = ssl_sock_get_proto_version ( conn ) ;
2013-10-01 04:45:07 -04:00
}
2024-05-02 09:30:17 -04:00
ret = lf_text ( tmplog , src , dst + maxsize - tmplog , ctx ) ;
2012-10-12 14:17:54 -04:00
if ( ret = = NULL )
goto out ;
tmplog = ret ;
break ;
# endif
2012-03-12 07:46:41 -04:00
case LOG_FMT_BACKEND : // %b
2012-02-27 05:23:10 -05:00
src = be - > id ;
2024-05-02 09:30:17 -04:00
ret = lf_text ( tmplog , src , dst + maxsize - tmplog , ctx ) ;
2012-03-12 07:46:41 -04:00
if ( ret = = NULL )
2012-02-27 05:23:10 -05:00
goto out ;
2012-03-12 07:46:41 -04:00
tmplog = ret ;
2012-02-27 05:23:10 -05:00
break ;
2012-03-12 07:46:41 -04:00
case LOG_FMT_SERVER : // %s
MINOR: logs: Add support of checks as session origin to format lf strings
When a log-format string is built from an health-check, the session origin
is the health-check itself and not a connection. In addition, there is no
stream. It means for now some formats are not supported: %s, %sc, %b, %bi,
%bp, %si and %sp.
Thanks to this patch, the session origin is converted to a check. So it is
possible to retrieve the backend and the backend connection. Note this
session have no listener, thus %ft format must be guarded.
This patch is light and standalone, thus it may be backported as far as 2.2
if required. However, because the error is human, it is probably better to
wait a bit to be sure everything is properly protected.
2021-04-14 08:01:41 -04:00
switch ( obj_type ( s ? s - > target : sess - > origin ) ) {
BUG/MINOR: log: make log-format, unique-id-format and add-header more independant
It happens that all of them call parse_logformat_line() which sets
proxy->to_log with a number of flags affecting the line format for
all three users. For example, having a unique-id specified disables
the default log-format since fe->to_log is tested when the session
is established.
Similarly, having "option logasap" will cause "+" to be inserted in
unique-id or headers referencing some of the fields depending on
LW_BYTES.
This patch first removes most of the dependency on fe->to_log whenever
possible. The first possible cleanup is to stop checking fe->to_log
for being null, considering that it always contains at least LW_INIT
when any such usage is made of the log-format!
Also, some checks are wrong. s->logs.logwait cannot be nulled by
"logwait &= ~LW_*" since LW_INIT is always there. This results in
getting the wrong log at the end of a request or session when a
unique-id or add-header is set, because logwait is still not null
but the log-format is not checked.
Further cleanups are required. Most LW_* flags should be removed or at
least replaced with what they really mean (eg: depend on client-side
connection, depend on server-side connection, etc...) and this should
only affect logging, not other mechanisms.
This patch fixes the default log-format and tries to limit interferences
between the log formats, but does not pretend to do more for the moment,
since it's the most visible breakage.
2012-12-28 03:40:16 -05:00
case OBJ_TYPE_SERVER :
2018-09-20 05:13:58 -04:00
src = __objt_server ( s - > target ) - > id ;
BUG/MINOR: log: make log-format, unique-id-format and add-header more independant
It happens that all of them call parse_logformat_line() which sets
proxy->to_log with a number of flags affecting the line format for
all three users. For example, having a unique-id specified disables
the default log-format since fe->to_log is tested when the session
is established.
Similarly, having "option logasap" will cause "+" to be inserted in
unique-id or headers referencing some of the fields depending on
LW_BYTES.
This patch first removes most of the dependency on fe->to_log whenever
possible. The first possible cleanup is to stop checking fe->to_log
for being null, considering that it always contains at least LW_INIT
when any such usage is made of the log-format!
Also, some checks are wrong. s->logs.logwait cannot be nulled by
"logwait &= ~LW_*" since LW_INIT is always there. This results in
getting the wrong log at the end of a request or session when a
unique-id or add-header is set, because logwait is still not null
but the log-format is not checked.
Further cleanups are required. Most LW_* flags should be removed or at
least replaced with what they really mean (eg: depend on client-side
connection, depend on server-side connection, etc...) and this should
only affect logging, not other mechanisms.
This patch fixes the default log-format and tries to limit interferences
between the log formats, but does not pretend to do more for the moment,
since it's the most visible breakage.
2012-12-28 03:40:16 -05:00
break ;
case OBJ_TYPE_APPLET :
2018-09-20 05:13:58 -04:00
src = __objt_applet ( s - > target ) - > name ;
BUG/MINOR: log: make log-format, unique-id-format and add-header more independant
It happens that all of them call parse_logformat_line() which sets
proxy->to_log with a number of flags affecting the line format for
all three users. For example, having a unique-id specified disables
the default log-format since fe->to_log is tested when the session
is established.
Similarly, having "option logasap" will cause "+" to be inserted in
unique-id or headers referencing some of the fields depending on
LW_BYTES.
This patch first removes most of the dependency on fe->to_log whenever
possible. The first possible cleanup is to stop checking fe->to_log
for being null, considering that it always contains at least LW_INIT
when any such usage is made of the log-format!
Also, some checks are wrong. s->logs.logwait cannot be nulled by
"logwait &= ~LW_*" since LW_INIT is always there. This results in
getting the wrong log at the end of a request or session when a
unique-id or add-header is set, because logwait is still not null
but the log-format is not checked.
Further cleanups are required. Most LW_* flags should be removed or at
least replaced with what they really mean (eg: depend on client-side
connection, depend on server-side connection, etc...) and this should
only affect logging, not other mechanisms.
This patch fixes the default log-format and tries to limit interferences
between the log formats, but does not pretend to do more for the moment,
since it's the most visible breakage.
2012-12-28 03:40:16 -05:00
break ;
MINOR: logs: Add support of checks as session origin to format lf strings
When a log-format string is built from an health-check, the session origin
is the health-check itself and not a connection. In addition, there is no
stream. It means for now some formats are not supported: %s, %sc, %b, %bi,
%bp, %si and %sp.
Thanks to this patch, the session origin is converted to a check. So it is
possible to retrieve the backend and the backend connection. Note this
session have no listener, thus %ft format must be guarded.
This patch is light and standalone, thus it may be backported as far as 2.2
if required. However, because the error is human, it is probably better to
wait a bit to be sure everything is properly protected.
2021-04-14 08:01:41 -04:00
case OBJ_TYPE_CHECK :
src = ( __objt_check ( sess - > origin ) - > server
? __objt_check ( sess - > origin ) - > server - > id
: " <NOSRV> " ) ;
break ;
BUG/MINOR: log: make log-format, unique-id-format and add-header more independant
It happens that all of them call parse_logformat_line() which sets
proxy->to_log with a number of flags affecting the line format for
all three users. For example, having a unique-id specified disables
the default log-format since fe->to_log is tested when the session
is established.
Similarly, having "option logasap" will cause "+" to be inserted in
unique-id or headers referencing some of the fields depending on
LW_BYTES.
This patch first removes most of the dependency on fe->to_log whenever
possible. The first possible cleanup is to stop checking fe->to_log
for being null, considering that it always contains at least LW_INIT
when any such usage is made of the log-format!
Also, some checks are wrong. s->logs.logwait cannot be nulled by
"logwait &= ~LW_*" since LW_INIT is always there. This results in
getting the wrong log at the end of a request or session when a
unique-id or add-header is set, because logwait is still not null
but the log-format is not checked.
Further cleanups are required. Most LW_* flags should be removed or at
least replaced with what they really mean (eg: depend on client-side
connection, depend on server-side connection, etc...) and this should
only affect logging, not other mechanisms.
This patch fixes the default log-format and tries to limit interferences
between the log formats, but does not pretend to do more for the moment,
since it's the most visible breakage.
2012-12-28 03:40:16 -05:00
default :
src = " <NOSRV> " ;
break ;
}
2024-05-02 09:30:17 -04:00
ret = lf_text ( tmplog , src , dst + maxsize - tmplog , ctx ) ;
2012-03-12 07:46:41 -04:00
if ( ret = = NULL )
2012-02-27 05:23:10 -05:00
goto out ;
2012-03-12 07:46:41 -04:00
tmplog = ret ;
2012-02-27 05:23:10 -05:00
break ;
MEDIUM: log: Decompose %Tq in %Th %Ti %TR
Tq is the time between the instant the connection is accepted and a
complete valid request is received. This time includes the handshake
(SSL / Proxy-Protocol), the idle when the browser does preconnect and
the request reception.
This patch decomposes %Tq in 3 measurements names %Th, %Ti, and %TR
which returns respectively the handshake time, the idle time and the
duration of valid request reception. It also adds %Ta which reports
the request's active time, which is the total time without %Th nor %Ti.
It replaces %Tt as the total time, reporting accurate measurements for
HTTP persistent connections.
%Th is avalaible for TCP and HTTP sessions, %Ti, %TR and %Ta are only
avalaible for HTTP connections.
In addition to this, we have new timestamps %tr, %trg and %trl, which
log the date of start of receipt of the request, respectively in the
default format, in GMT time and in local time (by analogy with %t, %T
and %Tl). All of them are obviously only available for HTTP. These values
are more relevant as they more accurately represent the request date
without being skewed by a browser's preconnect nor a keep-alive idle
time.
The HTTP log format and the CLF log format have been modified to
use %tr, %TR, and %Ta respectively instead of %t, %Tq and %Tt. This
way the default log formats now produce the expected output for users
who don't want to manually fiddle with the log-format directive.
Example with the following log-format :
log-format "%ci:%cp [%tr] %ft %b/%s h=%Th/i=%Ti/R=%TR/w=%Tw/c=%Tc/r=%Tr/a=%Ta/t=%Tt %ST %B %CC %CS %tsc %ac/%fc/%bc/%sc/%rc %sq/%bq %hr %hs %{+Q}r"
The request was sent by hand using "openssl s_client -connect" :
Aug 23 14:43:20 haproxy[25446]: 127.0.0.1:45636 [23/Aug/2016:14:43:20.221] test~ test/test h=6/i=2375/R=261/w=0/c=1/r=0/a=262/t=2643 200 145 - - ---- 1/1/0/0/0 0/0 "GET / HTTP/1.1"
=> 6 ms of SSL handshake, 2375 waiting before sending the first char (in
fact the time to type the first line), 261 ms before the end of the request,
no time spent in queue, 1 ms spend connecting to the server, immediate
response, total active time for this request = 262ms. Total time from accept
to close : 2643 ms.
The timing now decomposes like this :
first request 2nd request
|<-------------------------------->|<-------------- ...
t tr t tr ...
---|----|----|----|----|----|----|----|----|--
: Th Ti TR Tw Tc Tr Td : Ti ...
:<---- Tq ---->: :
:<-------------- Tt -------------->:
:<--------- Ta --------->:
2016-07-28 11:19:45 -04:00
case LOG_FMT_Th : // %Th = handshake time
2024-05-02 09:30:17 -04:00
ret = lf_int ( tmplog , dst + maxsize - tmplog , logs - > t_handshake , ctx , LF_INT_LTOA ) ;
MEDIUM: log: Decompose %Tq in %Th %Ti %TR
Tq is the time between the instant the connection is accepted and a
complete valid request is received. This time includes the handshake
(SSL / Proxy-Protocol), the idle when the browser does preconnect and
the request reception.
This patch decomposes %Tq in 3 measurements names %Th, %Ti, and %TR
which returns respectively the handshake time, the idle time and the
duration of valid request reception. It also adds %Ta which reports
the request's active time, which is the total time without %Th nor %Ti.
It replaces %Tt as the total time, reporting accurate measurements for
HTTP persistent connections.
%Th is avalaible for TCP and HTTP sessions, %Ti, %TR and %Ta are only
avalaible for HTTP connections.
In addition to this, we have new timestamps %tr, %trg and %trl, which
log the date of start of receipt of the request, respectively in the
default format, in GMT time and in local time (by analogy with %t, %T
and %Tl). All of them are obviously only available for HTTP. These values
are more relevant as they more accurately represent the request date
without being skewed by a browser's preconnect nor a keep-alive idle
time.
The HTTP log format and the CLF log format have been modified to
use %tr, %TR, and %Ta respectively instead of %t, %Tq and %Tt. This
way the default log formats now produce the expected output for users
who don't want to manually fiddle with the log-format directive.
Example with the following log-format :
log-format "%ci:%cp [%tr] %ft %b/%s h=%Th/i=%Ti/R=%TR/w=%Tw/c=%Tc/r=%Tr/a=%Ta/t=%Tt %ST %B %CC %CS %tsc %ac/%fc/%bc/%sc/%rc %sq/%bq %hr %hs %{+Q}r"
The request was sent by hand using "openssl s_client -connect" :
Aug 23 14:43:20 haproxy[25446]: 127.0.0.1:45636 [23/Aug/2016:14:43:20.221] test~ test/test h=6/i=2375/R=261/w=0/c=1/r=0/a=262/t=2643 200 145 - - ---- 1/1/0/0/0 0/0 "GET / HTTP/1.1"
=> 6 ms of SSL handshake, 2375 waiting before sending the first char (in
fact the time to type the first line), 261 ms before the end of the request,
no time spent in queue, 1 ms spend connecting to the server, immediate
response, total active time for this request = 262ms. Total time from accept
to close : 2643 ms.
The timing now decomposes like this :
first request 2nd request
|<-------------------------------->|<-------------- ...
t tr t tr ...
---|----|----|----|----|----|----|----|----|--
: Th Ti TR Tw Tc Tr Td : Ti ...
:<---- Tq ---->: :
:<-------------- Tt -------------->:
:<--------- Ta --------->:
2016-07-28 11:19:45 -04:00
if ( ret = = NULL )
goto out ;
tmplog = ret ;
break ;
case LOG_FMT_Ti : // %Ti = HTTP idle time
2024-05-02 09:30:17 -04:00
ret = lf_int ( tmplog , dst + maxsize - tmplog , logs - > t_idle , ctx , LF_INT_LTOA ) ;
MEDIUM: log: Decompose %Tq in %Th %Ti %TR
Tq is the time between the instant the connection is accepted and a
complete valid request is received. This time includes the handshake
(SSL / Proxy-Protocol), the idle when the browser does preconnect and
the request reception.
This patch decomposes %Tq in 3 measurements names %Th, %Ti, and %TR
which returns respectively the handshake time, the idle time and the
duration of valid request reception. It also adds %Ta which reports
the request's active time, which is the total time without %Th nor %Ti.
It replaces %Tt as the total time, reporting accurate measurements for
HTTP persistent connections.
%Th is avalaible for TCP and HTTP sessions, %Ti, %TR and %Ta are only
avalaible for HTTP connections.
In addition to this, we have new timestamps %tr, %trg and %trl, which
log the date of start of receipt of the request, respectively in the
default format, in GMT time and in local time (by analogy with %t, %T
and %Tl). All of them are obviously only available for HTTP. These values
are more relevant as they more accurately represent the request date
without being skewed by a browser's preconnect nor a keep-alive idle
time.
The HTTP log format and the CLF log format have been modified to
use %tr, %TR, and %Ta respectively instead of %t, %Tq and %Tt. This
way the default log formats now produce the expected output for users
who don't want to manually fiddle with the log-format directive.
Example with the following log-format :
log-format "%ci:%cp [%tr] %ft %b/%s h=%Th/i=%Ti/R=%TR/w=%Tw/c=%Tc/r=%Tr/a=%Ta/t=%Tt %ST %B %CC %CS %tsc %ac/%fc/%bc/%sc/%rc %sq/%bq %hr %hs %{+Q}r"
The request was sent by hand using "openssl s_client -connect" :
Aug 23 14:43:20 haproxy[25446]: 127.0.0.1:45636 [23/Aug/2016:14:43:20.221] test~ test/test h=6/i=2375/R=261/w=0/c=1/r=0/a=262/t=2643 200 145 - - ---- 1/1/0/0/0 0/0 "GET / HTTP/1.1"
=> 6 ms of SSL handshake, 2375 waiting before sending the first char (in
fact the time to type the first line), 261 ms before the end of the request,
no time spent in queue, 1 ms spend connecting to the server, immediate
response, total active time for this request = 262ms. Total time from accept
to close : 2643 ms.
The timing now decomposes like this :
first request 2nd request
|<-------------------------------->|<-------------- ...
t tr t tr ...
---|----|----|----|----|----|----|----|----|--
: Th Ti TR Tw Tc Tr Td : Ti ...
:<---- Tq ---->: :
:<-------------- Tt -------------->:
:<--------- Ta --------->:
2016-07-28 11:19:45 -04:00
if ( ret = = NULL )
goto out ;
tmplog = ret ;
break ;
case LOG_FMT_TR : // %TR = HTTP request time
2024-03-26 06:50:50 -04:00
{
long value = ( t_request > = 0 ) ? t_request - logs - > t_idle - logs - > t_handshake : - 1 ;
2024-05-02 09:30:17 -04:00
ret = lf_int ( tmplog , dst + maxsize - tmplog , value , ctx , LF_INT_LTOA ) ;
MEDIUM: log: Decompose %Tq in %Th %Ti %TR
Tq is the time between the instant the connection is accepted and a
complete valid request is received. This time includes the handshake
(SSL / Proxy-Protocol), the idle when the browser does preconnect and
the request reception.
This patch decomposes %Tq in 3 measurements names %Th, %Ti, and %TR
which returns respectively the handshake time, the idle time and the
duration of valid request reception. It also adds %Ta which reports
the request's active time, which is the total time without %Th nor %Ti.
It replaces %Tt as the total time, reporting accurate measurements for
HTTP persistent connections.
%Th is avalaible for TCP and HTTP sessions, %Ti, %TR and %Ta are only
avalaible for HTTP connections.
In addition to this, we have new timestamps %tr, %trg and %trl, which
log the date of start of receipt of the request, respectively in the
default format, in GMT time and in local time (by analogy with %t, %T
and %Tl). All of them are obviously only available for HTTP. These values
are more relevant as they more accurately represent the request date
without being skewed by a browser's preconnect nor a keep-alive idle
time.
The HTTP log format and the CLF log format have been modified to
use %tr, %TR, and %Ta respectively instead of %t, %Tq and %Tt. This
way the default log formats now produce the expected output for users
who don't want to manually fiddle with the log-format directive.
Example with the following log-format :
log-format "%ci:%cp [%tr] %ft %b/%s h=%Th/i=%Ti/R=%TR/w=%Tw/c=%Tc/r=%Tr/a=%Ta/t=%Tt %ST %B %CC %CS %tsc %ac/%fc/%bc/%sc/%rc %sq/%bq %hr %hs %{+Q}r"
The request was sent by hand using "openssl s_client -connect" :
Aug 23 14:43:20 haproxy[25446]: 127.0.0.1:45636 [23/Aug/2016:14:43:20.221] test~ test/test h=6/i=2375/R=261/w=0/c=1/r=0/a=262/t=2643 200 145 - - ---- 1/1/0/0/0 0/0 "GET / HTTP/1.1"
=> 6 ms of SSL handshake, 2375 waiting before sending the first char (in
fact the time to type the first line), 261 ms before the end of the request,
no time spent in queue, 1 ms spend connecting to the server, immediate
response, total active time for this request = 262ms. Total time from accept
to close : 2643 ms.
The timing now decomposes like this :
first request 2nd request
|<-------------------------------->|<-------------- ...
t tr t tr ...
---|----|----|----|----|----|----|----|----|--
: Th Ti TR Tw Tc Tr Td : Ti ...
:<---- Tq ---->: :
:<-------------- Tt -------------->:
:<--------- Ta --------->:
2016-07-28 11:19:45 -04:00
if ( ret = = NULL )
goto out ;
tmplog = ret ;
break ;
2024-03-26 06:50:50 -04:00
}
MEDIUM: log: Decompose %Tq in %Th %Ti %TR
Tq is the time between the instant the connection is accepted and a
complete valid request is received. This time includes the handshake
(SSL / Proxy-Protocol), the idle when the browser does preconnect and
the request reception.
This patch decomposes %Tq in 3 measurements names %Th, %Ti, and %TR
which returns respectively the handshake time, the idle time and the
duration of valid request reception. It also adds %Ta which reports
the request's active time, which is the total time without %Th nor %Ti.
It replaces %Tt as the total time, reporting accurate measurements for
HTTP persistent connections.
%Th is avalaible for TCP and HTTP sessions, %Ti, %TR and %Ta are only
avalaible for HTTP connections.
In addition to this, we have new timestamps %tr, %trg and %trl, which
log the date of start of receipt of the request, respectively in the
default format, in GMT time and in local time (by analogy with %t, %T
and %Tl). All of them are obviously only available for HTTP. These values
are more relevant as they more accurately represent the request date
without being skewed by a browser's preconnect nor a keep-alive idle
time.
The HTTP log format and the CLF log format have been modified to
use %tr, %TR, and %Ta respectively instead of %t, %Tq and %Tt. This
way the default log formats now produce the expected output for users
who don't want to manually fiddle with the log-format directive.
Example with the following log-format :
log-format "%ci:%cp [%tr] %ft %b/%s h=%Th/i=%Ti/R=%TR/w=%Tw/c=%Tc/r=%Tr/a=%Ta/t=%Tt %ST %B %CC %CS %tsc %ac/%fc/%bc/%sc/%rc %sq/%bq %hr %hs %{+Q}r"
The request was sent by hand using "openssl s_client -connect" :
Aug 23 14:43:20 haproxy[25446]: 127.0.0.1:45636 [23/Aug/2016:14:43:20.221] test~ test/test h=6/i=2375/R=261/w=0/c=1/r=0/a=262/t=2643 200 145 - - ---- 1/1/0/0/0 0/0 "GET / HTTP/1.1"
=> 6 ms of SSL handshake, 2375 waiting before sending the first char (in
fact the time to type the first line), 261 ms before the end of the request,
no time spent in queue, 1 ms spend connecting to the server, immediate
response, total active time for this request = 262ms. Total time from accept
to close : 2643 ms.
The timing now decomposes like this :
first request 2nd request
|<-------------------------------->|<-------------- ...
t tr t tr ...
---|----|----|----|----|----|----|----|----|--
: Th Ti TR Tw Tc Tr Td : Ti ...
:<---- Tq ---->: :
:<-------------- Tt -------------->:
:<--------- Ta --------->:
2016-07-28 11:19:45 -04:00
case LOG_FMT_TQ : // %Tq = Th + Ti + TR
2024-05-02 09:30:17 -04:00
ret = lf_int ( tmplog , dst + maxsize - tmplog , t_request , ctx , LF_INT_LTOA ) ;
2012-03-12 07:46:41 -04:00
if ( ret = = NULL )
2012-02-27 05:23:10 -05:00
goto out ;
2012-03-12 07:46:41 -04:00
tmplog = ret ;
2012-02-27 05:23:10 -05:00
break ;
2012-03-12 07:46:41 -04:00
case LOG_FMT_TW : // %Tw
2024-03-26 06:50:50 -04:00
{
long value = ( logs - > t_queue > = 0 ) ? logs - > t_queue - t_request : - 1 ;
2024-05-02 09:30:17 -04:00
ret = lf_int ( tmplog , dst + maxsize - tmplog , value , ctx , LF_INT_LTOA ) ;
2012-03-12 07:46:41 -04:00
if ( ret = = NULL )
2012-02-27 05:23:10 -05:00
goto out ;
2012-03-12 07:46:41 -04:00
tmplog = ret ;
2012-02-27 05:23:10 -05:00
break ;
2024-03-26 06:50:50 -04:00
}
2012-02-27 05:23:10 -05:00
2012-03-12 07:46:41 -04:00
case LOG_FMT_TC : // %Tc
2024-03-26 06:50:50 -04:00
{
long value = ( logs - > t_connect > = 0 ) ? logs - > t_connect - logs - > t_queue : - 1 ;
2024-05-02 09:30:17 -04:00
ret = lf_int ( tmplog , dst + maxsize - tmplog , value , ctx , LF_INT_LTOA ) ;
2012-03-12 07:46:41 -04:00
if ( ret = = NULL )
2012-02-27 05:23:10 -05:00
goto out ;
2012-03-12 07:46:41 -04:00
tmplog = ret ;
2012-02-27 05:23:10 -05:00
break ;
2024-03-26 06:50:50 -04:00
}
2012-02-27 05:23:10 -05:00
MEDIUM: log: Decompose %Tq in %Th %Ti %TR
Tq is the time between the instant the connection is accepted and a
complete valid request is received. This time includes the handshake
(SSL / Proxy-Protocol), the idle when the browser does preconnect and
the request reception.
This patch decomposes %Tq in 3 measurements names %Th, %Ti, and %TR
which returns respectively the handshake time, the idle time and the
duration of valid request reception. It also adds %Ta which reports
the request's active time, which is the total time without %Th nor %Ti.
It replaces %Tt as the total time, reporting accurate measurements for
HTTP persistent connections.
%Th is avalaible for TCP and HTTP sessions, %Ti, %TR and %Ta are only
avalaible for HTTP connections.
In addition to this, we have new timestamps %tr, %trg and %trl, which
log the date of start of receipt of the request, respectively in the
default format, in GMT time and in local time (by analogy with %t, %T
and %Tl). All of them are obviously only available for HTTP. These values
are more relevant as they more accurately represent the request date
without being skewed by a browser's preconnect nor a keep-alive idle
time.
The HTTP log format and the CLF log format have been modified to
use %tr, %TR, and %Ta respectively instead of %t, %Tq and %Tt. This
way the default log formats now produce the expected output for users
who don't want to manually fiddle with the log-format directive.
Example with the following log-format :
log-format "%ci:%cp [%tr] %ft %b/%s h=%Th/i=%Ti/R=%TR/w=%Tw/c=%Tc/r=%Tr/a=%Ta/t=%Tt %ST %B %CC %CS %tsc %ac/%fc/%bc/%sc/%rc %sq/%bq %hr %hs %{+Q}r"
The request was sent by hand using "openssl s_client -connect" :
Aug 23 14:43:20 haproxy[25446]: 127.0.0.1:45636 [23/Aug/2016:14:43:20.221] test~ test/test h=6/i=2375/R=261/w=0/c=1/r=0/a=262/t=2643 200 145 - - ---- 1/1/0/0/0 0/0 "GET / HTTP/1.1"
=> 6 ms of SSL handshake, 2375 waiting before sending the first char (in
fact the time to type the first line), 261 ms before the end of the request,
no time spent in queue, 1 ms spend connecting to the server, immediate
response, total active time for this request = 262ms. Total time from accept
to close : 2643 ms.
The timing now decomposes like this :
first request 2nd request
|<-------------------------------->|<-------------- ...
t tr t tr ...
---|----|----|----|----|----|----|----|----|--
: Th Ti TR Tw Tc Tr Td : Ti ...
:<---- Tq ---->: :
:<-------------- Tt -------------->:
:<--------- Ta --------->:
2016-07-28 11:19:45 -04:00
case LOG_FMT_Tr : // %Tr
2024-03-26 06:50:50 -04:00
{
long value = ( logs - > t_data > = 0 ) ? logs - > t_data - logs - > t_connect : - 1 ;
2024-05-02 09:30:17 -04:00
ret = lf_int ( tmplog , dst + maxsize - tmplog , value , ctx , LF_INT_LTOA ) ;
2012-03-12 07:46:41 -04:00
if ( ret = = NULL )
2012-02-27 05:23:10 -05:00
goto out ;
2012-03-12 07:46:41 -04:00
tmplog = ret ;
2012-02-27 05:23:10 -05:00
break ;
2024-03-26 06:50:50 -04:00
}
2012-02-27 05:23:10 -05:00
2016-05-17 11:55:27 -04:00
case LOG_FMT_TD : // %Td
2024-03-26 06:50:50 -04:00
{
long value ;
2018-09-05 09:07:15 -04:00
if ( be - > mode = = PR_MODE_HTTP )
2024-03-26 06:50:50 -04:00
value = ( logs - > t_data > = 0 ) ? logs - > t_close - logs - > t_data : - 1 ;
2016-05-17 11:55:27 -04:00
else
2024-03-26 06:50:50 -04:00
value = ( logs - > t_connect > = 0 ) ? logs - > t_close - logs - > t_connect : - 1 ;
2024-05-02 09:30:17 -04:00
ret = lf_int ( tmplog , dst + maxsize - tmplog , value , ctx , LF_INT_LTOA ) ;
2024-03-26 06:50:50 -04:00
2016-05-17 11:55:27 -04:00
if ( ret = = NULL )
goto out ;
tmplog = ret ;
break ;
2024-03-26 06:50:50 -04:00
}
2016-05-17 11:55:27 -04:00
MEDIUM: log: Decompose %Tq in %Th %Ti %TR
Tq is the time between the instant the connection is accepted and a
complete valid request is received. This time includes the handshake
(SSL / Proxy-Protocol), the idle when the browser does preconnect and
the request reception.
This patch decomposes %Tq in 3 measurements names %Th, %Ti, and %TR
which returns respectively the handshake time, the idle time and the
duration of valid request reception. It also adds %Ta which reports
the request's active time, which is the total time without %Th nor %Ti.
It replaces %Tt as the total time, reporting accurate measurements for
HTTP persistent connections.
%Th is avalaible for TCP and HTTP sessions, %Ti, %TR and %Ta are only
avalaible for HTTP connections.
In addition to this, we have new timestamps %tr, %trg and %trl, which
log the date of start of receipt of the request, respectively in the
default format, in GMT time and in local time (by analogy with %t, %T
and %Tl). All of them are obviously only available for HTTP. These values
are more relevant as they more accurately represent the request date
without being skewed by a browser's preconnect nor a keep-alive idle
time.
The HTTP log format and the CLF log format have been modified to
use %tr, %TR, and %Ta respectively instead of %t, %Tq and %Tt. This
way the default log formats now produce the expected output for users
who don't want to manually fiddle with the log-format directive.
Example with the following log-format :
log-format "%ci:%cp [%tr] %ft %b/%s h=%Th/i=%Ti/R=%TR/w=%Tw/c=%Tc/r=%Tr/a=%Ta/t=%Tt %ST %B %CC %CS %tsc %ac/%fc/%bc/%sc/%rc %sq/%bq %hr %hs %{+Q}r"
The request was sent by hand using "openssl s_client -connect" :
Aug 23 14:43:20 haproxy[25446]: 127.0.0.1:45636 [23/Aug/2016:14:43:20.221] test~ test/test h=6/i=2375/R=261/w=0/c=1/r=0/a=262/t=2643 200 145 - - ---- 1/1/0/0/0 0/0 "GET / HTTP/1.1"
=> 6 ms of SSL handshake, 2375 waiting before sending the first char (in
fact the time to type the first line), 261 ms before the end of the request,
no time spent in queue, 1 ms spend connecting to the server, immediate
response, total active time for this request = 262ms. Total time from accept
to close : 2643 ms.
The timing now decomposes like this :
first request 2nd request
|<-------------------------------->|<-------------- ...
t tr t tr ...
---|----|----|----|----|----|----|----|----|--
: Th Ti TR Tw Tc Tr Td : Ti ...
:<---- Tq ---->: :
:<-------------- Tt -------------->:
:<--------- Ta --------->:
2016-07-28 11:19:45 -04:00
case LOG_FMT_Ta : // %Ta = active time = Tt - Th - Ti
2024-03-26 06:50:50 -04:00
{
long value = logs - > t_close - ( logs - > t_idle > = 0 ? logs - > t_idle + logs - > t_handshake : 0 ) ;
MEDIUM: log: Decompose %Tq in %Th %Ti %TR
Tq is the time between the instant the connection is accepted and a
complete valid request is received. This time includes the handshake
(SSL / Proxy-Protocol), the idle when the browser does preconnect and
the request reception.
This patch decomposes %Tq in 3 measurements names %Th, %Ti, and %TR
which returns respectively the handshake time, the idle time and the
duration of valid request reception. It also adds %Ta which reports
the request's active time, which is the total time without %Th nor %Ti.
It replaces %Tt as the total time, reporting accurate measurements for
HTTP persistent connections.
%Th is avalaible for TCP and HTTP sessions, %Ti, %TR and %Ta are only
avalaible for HTTP connections.
In addition to this, we have new timestamps %tr, %trg and %trl, which
log the date of start of receipt of the request, respectively in the
default format, in GMT time and in local time (by analogy with %t, %T
and %Tl). All of them are obviously only available for HTTP. These values
are more relevant as they more accurately represent the request date
without being skewed by a browser's preconnect nor a keep-alive idle
time.
The HTTP log format and the CLF log format have been modified to
use %tr, %TR, and %Ta respectively instead of %t, %Tq and %Tt. This
way the default log formats now produce the expected output for users
who don't want to manually fiddle with the log-format directive.
Example with the following log-format :
log-format "%ci:%cp [%tr] %ft %b/%s h=%Th/i=%Ti/R=%TR/w=%Tw/c=%Tc/r=%Tr/a=%Ta/t=%Tt %ST %B %CC %CS %tsc %ac/%fc/%bc/%sc/%rc %sq/%bq %hr %hs %{+Q}r"
The request was sent by hand using "openssl s_client -connect" :
Aug 23 14:43:20 haproxy[25446]: 127.0.0.1:45636 [23/Aug/2016:14:43:20.221] test~ test/test h=6/i=2375/R=261/w=0/c=1/r=0/a=262/t=2643 200 145 - - ---- 1/1/0/0/0 0/0 "GET / HTTP/1.1"
=> 6 ms of SSL handshake, 2375 waiting before sending the first char (in
fact the time to type the first line), 261 ms before the end of the request,
no time spent in queue, 1 ms spend connecting to the server, immediate
response, total active time for this request = 262ms. Total time from accept
to close : 2643 ms.
The timing now decomposes like this :
first request 2nd request
|<-------------------------------->|<-------------- ...
t tr t tr ...
---|----|----|----|----|----|----|----|----|--
: Th Ti TR Tw Tc Tr Td : Ti ...
:<---- Tq ---->: :
:<-------------- Tt -------------->:
:<--------- Ta --------->:
2016-07-28 11:19:45 -04:00
if ( ! ( fe - > to_log & LW_BYTES ) )
2024-01-30 12:01:15 -05:00
LOGMETACHAR ( ' + ' ) ;
2024-05-02 09:30:17 -04:00
ret = lf_int ( tmplog , dst + maxsize - tmplog , value , ctx , LF_INT_LTOA ) ;
MEDIUM: log: Decompose %Tq in %Th %Ti %TR
Tq is the time between the instant the connection is accepted and a
complete valid request is received. This time includes the handshake
(SSL / Proxy-Protocol), the idle when the browser does preconnect and
the request reception.
This patch decomposes %Tq in 3 measurements names %Th, %Ti, and %TR
which returns respectively the handshake time, the idle time and the
duration of valid request reception. It also adds %Ta which reports
the request's active time, which is the total time without %Th nor %Ti.
It replaces %Tt as the total time, reporting accurate measurements for
HTTP persistent connections.
%Th is avalaible for TCP and HTTP sessions, %Ti, %TR and %Ta are only
avalaible for HTTP connections.
In addition to this, we have new timestamps %tr, %trg and %trl, which
log the date of start of receipt of the request, respectively in the
default format, in GMT time and in local time (by analogy with %t, %T
and %Tl). All of them are obviously only available for HTTP. These values
are more relevant as they more accurately represent the request date
without being skewed by a browser's preconnect nor a keep-alive idle
time.
The HTTP log format and the CLF log format have been modified to
use %tr, %TR, and %Ta respectively instead of %t, %Tq and %Tt. This
way the default log formats now produce the expected output for users
who don't want to manually fiddle with the log-format directive.
Example with the following log-format :
log-format "%ci:%cp [%tr] %ft %b/%s h=%Th/i=%Ti/R=%TR/w=%Tw/c=%Tc/r=%Tr/a=%Ta/t=%Tt %ST %B %CC %CS %tsc %ac/%fc/%bc/%sc/%rc %sq/%bq %hr %hs %{+Q}r"
The request was sent by hand using "openssl s_client -connect" :
Aug 23 14:43:20 haproxy[25446]: 127.0.0.1:45636 [23/Aug/2016:14:43:20.221] test~ test/test h=6/i=2375/R=261/w=0/c=1/r=0/a=262/t=2643 200 145 - - ---- 1/1/0/0/0 0/0 "GET / HTTP/1.1"
=> 6 ms of SSL handshake, 2375 waiting before sending the first char (in
fact the time to type the first line), 261 ms before the end of the request,
no time spent in queue, 1 ms spend connecting to the server, immediate
response, total active time for this request = 262ms. Total time from accept
to close : 2643 ms.
The timing now decomposes like this :
first request 2nd request
|<-------------------------------->|<-------------- ...
t tr t tr ...
---|----|----|----|----|----|----|----|----|--
: Th Ti TR Tw Tc Tr Td : Ti ...
:<---- Tq ---->: :
:<-------------- Tt -------------->:
:<--------- Ta --------->:
2016-07-28 11:19:45 -04:00
if ( ret = = NULL )
goto out ;
tmplog = ret ;
break ;
2024-03-26 06:50:50 -04:00
}
MEDIUM: log: Decompose %Tq in %Th %Ti %TR
Tq is the time between the instant the connection is accepted and a
complete valid request is received. This time includes the handshake
(SSL / Proxy-Protocol), the idle when the browser does preconnect and
the request reception.
This patch decomposes %Tq in 3 measurements names %Th, %Ti, and %TR
which returns respectively the handshake time, the idle time and the
duration of valid request reception. It also adds %Ta which reports
the request's active time, which is the total time without %Th nor %Ti.
It replaces %Tt as the total time, reporting accurate measurements for
HTTP persistent connections.
%Th is avalaible for TCP and HTTP sessions, %Ti, %TR and %Ta are only
avalaible for HTTP connections.
In addition to this, we have new timestamps %tr, %trg and %trl, which
log the date of start of receipt of the request, respectively in the
default format, in GMT time and in local time (by analogy with %t, %T
and %Tl). All of them are obviously only available for HTTP. These values
are more relevant as they more accurately represent the request date
without being skewed by a browser's preconnect nor a keep-alive idle
time.
The HTTP log format and the CLF log format have been modified to
use %tr, %TR, and %Ta respectively instead of %t, %Tq and %Tt. This
way the default log formats now produce the expected output for users
who don't want to manually fiddle with the log-format directive.
Example with the following log-format :
log-format "%ci:%cp [%tr] %ft %b/%s h=%Th/i=%Ti/R=%TR/w=%Tw/c=%Tc/r=%Tr/a=%Ta/t=%Tt %ST %B %CC %CS %tsc %ac/%fc/%bc/%sc/%rc %sq/%bq %hr %hs %{+Q}r"
The request was sent by hand using "openssl s_client -connect" :
Aug 23 14:43:20 haproxy[25446]: 127.0.0.1:45636 [23/Aug/2016:14:43:20.221] test~ test/test h=6/i=2375/R=261/w=0/c=1/r=0/a=262/t=2643 200 145 - - ---- 1/1/0/0/0 0/0 "GET / HTTP/1.1"
=> 6 ms of SSL handshake, 2375 waiting before sending the first char (in
fact the time to type the first line), 261 ms before the end of the request,
no time spent in queue, 1 ms spend connecting to the server, immediate
response, total active time for this request = 262ms. Total time from accept
to close : 2643 ms.
The timing now decomposes like this :
first request 2nd request
|<-------------------------------->|<-------------- ...
t tr t tr ...
---|----|----|----|----|----|----|----|----|--
: Th Ti TR Tw Tc Tr Td : Ti ...
:<---- Tq ---->: :
:<-------------- Tt -------------->:
:<--------- Ta --------->:
2016-07-28 11:19:45 -04:00
case LOG_FMT_TT : // %Tt = total time
BUG/MINOR: log: make log-format, unique-id-format and add-header more independant
It happens that all of them call parse_logformat_line() which sets
proxy->to_log with a number of flags affecting the line format for
all three users. For example, having a unique-id specified disables
the default log-format since fe->to_log is tested when the session
is established.
Similarly, having "option logasap" will cause "+" to be inserted in
unique-id or headers referencing some of the fields depending on
LW_BYTES.
This patch first removes most of the dependency on fe->to_log whenever
possible. The first possible cleanup is to stop checking fe->to_log
for being null, considering that it always contains at least LW_INIT
when any such usage is made of the log-format!
Also, some checks are wrong. s->logs.logwait cannot be nulled by
"logwait &= ~LW_*" since LW_INIT is always there. This results in
getting the wrong log at the end of a request or session when a
unique-id or add-header is set, because logwait is still not null
but the log-format is not checked.
Further cleanups are required. Most LW_* flags should be removed or at
least replaced with what they really mean (eg: depend on client-side
connection, depend on server-side connection, etc...) and this should
only affect logging, not other mechanisms.
This patch fixes the default log-format and tries to limit interferences
between the log formats, but does not pretend to do more for the moment,
since it's the most visible breakage.
2012-12-28 03:40:16 -05:00
if ( ! ( fe - > to_log & LW_BYTES ) )
2024-01-30 12:01:15 -05:00
LOGMETACHAR ( ' + ' ) ;
2024-05-02 09:30:17 -04:00
ret = lf_int ( tmplog , dst + maxsize - tmplog , logs - > t_close , ctx , LF_INT_LTOA ) ;
2012-03-12 07:46:41 -04:00
if ( ret = = NULL )
2012-02-27 05:23:10 -05:00
goto out ;
2012-03-12 07:46:41 -04:00
tmplog = ret ;
2012-02-27 05:23:10 -05:00
break ;
2020-04-28 08:09:19 -04:00
case LOG_FMT_TU : // %Tu = total time seen by user = Tt - Ti
2024-03-26 06:50:50 -04:00
{
long value = logs - > t_close - ( logs - > t_idle > = 0 ? logs - > t_idle : 0 ) ;
2020-04-28 08:09:19 -04:00
if ( ! ( fe - > to_log & LW_BYTES ) )
2024-01-30 12:01:15 -05:00
LOGMETACHAR ( ' + ' ) ;
2024-05-02 09:30:17 -04:00
ret = lf_int ( tmplog , dst + maxsize - tmplog , value , ctx , LF_INT_LTOA ) ;
2020-04-28 08:09:19 -04:00
if ( ret = = NULL )
goto out ;
tmplog = ret ;
break ;
2024-03-26 06:50:50 -04:00
}
2020-04-28 08:09:19 -04:00
2012-12-20 11:22:52 -05:00
case LOG_FMT_STATUS : // %ST
2024-05-02 09:30:17 -04:00
ret = lf_int ( tmplog , dst + maxsize - tmplog , status , ctx , LF_INT_LTOA ) ;
2012-03-12 07:46:41 -04:00
if ( ret = = NULL )
2012-02-27 05:23:10 -05:00
goto out ;
2012-03-12 07:46:41 -04:00
tmplog = ret ;
2012-02-27 05:23:10 -05:00
break ;
2012-03-12 07:46:41 -04:00
case LOG_FMT_BYTES : // %B
BUG/MINOR: log: make log-format, unique-id-format and add-header more independant
It happens that all of them call parse_logformat_line() which sets
proxy->to_log with a number of flags affecting the line format for
all three users. For example, having a unique-id specified disables
the default log-format since fe->to_log is tested when the session
is established.
Similarly, having "option logasap" will cause "+" to be inserted in
unique-id or headers referencing some of the fields depending on
LW_BYTES.
This patch first removes most of the dependency on fe->to_log whenever
possible. The first possible cleanup is to stop checking fe->to_log
for being null, considering that it always contains at least LW_INIT
when any such usage is made of the log-format!
Also, some checks are wrong. s->logs.logwait cannot be nulled by
"logwait &= ~LW_*" since LW_INIT is always there. This results in
getting the wrong log at the end of a request or session when a
unique-id or add-header is set, because logwait is still not null
but the log-format is not checked.
Further cleanups are required. Most LW_* flags should be removed or at
least replaced with what they really mean (eg: depend on client-side
connection, depend on server-side connection, etc...) and this should
only affect logging, not other mechanisms.
This patch fixes the default log-format and tries to limit interferences
between the log formats, but does not pretend to do more for the moment,
since it's the most visible breakage.
2012-12-28 03:40:16 -05:00
if ( ! ( fe - > to_log & LW_BYTES ) )
2024-01-30 12:01:15 -05:00
LOGMETACHAR ( ' + ' ) ;
2024-05-02 09:30:17 -04:00
ret = lf_int ( tmplog , dst + maxsize - tmplog , logs - > bytes_out , ctx , LF_INT_LLTOA ) ;
2012-12-20 09:38:04 -05:00
if ( ret = = NULL )
goto out ;
tmplog = ret ;
break ;
case LOG_FMT_BYTES_UP : // %U
2024-05-02 09:30:17 -04:00
ret = lf_int ( tmplog , dst + maxsize - tmplog , logs - > bytes_in , ctx , LF_INT_LLTOA ) ;
2012-03-12 07:46:41 -04:00
if ( ret = = NULL )
2012-02-27 05:23:10 -05:00
goto out ;
2012-03-12 07:46:41 -04:00
tmplog = ret ;
2012-02-27 05:23:10 -05:00
break ;
2012-12-20 11:22:52 -05:00
case LOG_FMT_CCLIENT : // %CC
2016-04-25 11:09:40 -04:00
src = txn ? txn - > cli_cookie : NULL ;
2024-05-02 09:30:17 -04:00
ret = lf_text ( tmplog , src , dst + maxsize - tmplog , ctx ) ;
2012-03-12 07:46:41 -04:00
if ( ret = = NULL )
2012-03-26 11:52:55 -04:00
goto out ;
2012-03-12 07:46:41 -04:00
tmplog = ret ;
2012-02-27 05:23:10 -05:00
break ;
2012-12-20 11:22:52 -05:00
case LOG_FMT_CSERVER : // %CS
2016-04-25 11:09:40 -04:00
src = txn ? txn - > srv_cookie : NULL ;
2024-05-02 09:30:17 -04:00
ret = lf_text ( tmplog , src , dst + maxsize - tmplog , ctx ) ;
2012-03-12 07:46:41 -04:00
if ( ret = = NULL )
2012-03-26 11:52:55 -04:00
goto out ;
2012-03-12 07:46:41 -04:00
tmplog = ret ;
2012-02-27 05:23:10 -05:00
break ;
2012-03-12 07:46:41 -04:00
case LOG_FMT_TERMSTATE : // %ts
2024-04-23 12:25:32 -04:00
{
2024-05-02 10:48:56 -04:00
ctx - > _buf [ 0 ] = sess_term_cond [ ( s_flags & SF_ERR_MASK ) > > SF_ERR_SHIFT ] ;
ctx - > _buf [ 1 ] = sess_fin_state [ ( s_flags & SF_FINST_MASK ) > > SF_FINST_SHIFT ] ;
ret = lf_rawtext_len ( tmplog , ctx - > _buf , 2 , maxsize - ( tmplog - dst ) , ctx ) ;
2024-04-23 12:25:32 -04:00
if ( ret = = NULL )
goto out ;
tmplog = ret ;
2012-03-12 10:09:42 -04:00
break ;
2024-04-23 12:25:32 -04:00
}
2012-02-27 05:23:10 -05:00
2012-03-12 07:46:41 -04:00
case LOG_FMT_TERMSTATE_CK : // %tsc, same as TS with cookie state (for mode HTTP)
2024-04-23 12:25:32 -04:00
{
2024-05-02 10:48:56 -04:00
ctx - > _buf [ 0 ] = sess_term_cond [ ( s_flags & SF_ERR_MASK ) > > SF_ERR_SHIFT ] ;
ctx - > _buf [ 1 ] = sess_fin_state [ ( s_flags & SF_FINST_MASK ) > > SF_FINST_SHIFT ] ;
ctx - > _buf [ 2 ] = ( txn & & ( be - > ck_opts & PR_CK_ANY ) ) ? sess_cookie [ ( txn - > flags & TX_CK_MASK ) > > TX_CK_SHIFT ] : ' - ' ;
ctx - > _buf [ 3 ] = ( txn & & ( be - > ck_opts & PR_CK_ANY ) ) ? sess_set_cookie [ ( txn - > flags & TX_SCK_MASK ) > > TX_SCK_SHIFT ] : ' - ' ;
ret = lf_rawtext_len ( tmplog , ctx - > _buf , 4 , maxsize - ( tmplog - dst ) , ctx ) ;
2024-04-23 12:25:32 -04:00
if ( ret = = NULL )
goto out ;
tmplog = ret ;
2012-02-27 05:23:10 -05:00
break ;
2024-04-23 12:25:32 -04:00
}
2012-02-27 05:23:10 -05:00
2012-03-12 07:46:41 -04:00
case LOG_FMT_ACTCONN : // %ac
2024-05-02 09:30:17 -04:00
ret = lf_int ( tmplog , dst + maxsize - tmplog , actconn , ctx , LF_INT_LTOA ) ;
2012-03-12 07:46:41 -04:00
if ( ret = = NULL )
2012-02-27 05:23:10 -05:00
goto out ;
2012-03-12 07:46:41 -04:00
tmplog = ret ;
2012-02-27 05:23:10 -05:00
break ;
2012-03-12 07:46:41 -04:00
case LOG_FMT_FECONN : // %fc
2024-05-02 09:30:17 -04:00
ret = lf_int ( tmplog , dst + maxsize - tmplog , fe - > feconn , ctx , LF_INT_LTOA ) ;
2012-03-12 07:46:41 -04:00
if ( ret = = NULL )
2012-02-27 05:23:10 -05:00
goto out ;
2012-03-12 07:46:41 -04:00
tmplog = ret ;
2012-02-27 05:23:10 -05:00
break ;
2012-03-12 07:46:41 -04:00
case LOG_FMT_BECONN : // %bc
2024-05-02 09:30:17 -04:00
ret = lf_int ( tmplog , dst + maxsize - tmplog , be - > beconn , ctx , LF_INT_LTOA ) ;
2012-03-12 07:46:41 -04:00
if ( ret = = NULL )
2012-02-27 05:23:10 -05:00
goto out ;
2012-03-12 07:46:41 -04:00
tmplog = ret ;
2012-02-27 05:23:10 -05:00
break ;
2012-03-12 07:46:41 -04:00
case LOG_FMT_SRVCONN : // %sc
2024-03-26 06:50:50 -04:00
{
unsigned long value ;
MINOR: logs: Add support of checks as session origin to format lf strings
When a log-format string is built from an health-check, the session origin
is the health-check itself and not a connection. In addition, there is no
stream. It means for now some formats are not supported: %s, %sc, %b, %bi,
%bp, %si and %sp.
Thanks to this patch, the session origin is converted to a check. So it is
possible to retrieve the backend and the backend connection. Note this
session have no listener, thus %ft format must be guarded.
This patch is light and standalone, thus it may be backported as far as 2.2
if required. However, because the error is human, it is probably better to
wait a bit to be sure everything is properly protected.
2021-04-14 08:01:41 -04:00
switch ( obj_type ( s ? s - > target : sess - > origin ) ) {
case OBJ_TYPE_SERVER :
2024-03-26 06:50:50 -04:00
value = __objt_server ( s - > target ) - > cur_sess ;
MINOR: logs: Add support of checks as session origin to format lf strings
When a log-format string is built from an health-check, the session origin
is the health-check itself and not a connection. In addition, there is no
stream. It means for now some formats are not supported: %s, %sc, %b, %bi,
%bp, %si and %sp.
Thanks to this patch, the session origin is converted to a check. So it is
possible to retrieve the backend and the backend connection. Note this
session have no listener, thus %ft format must be guarded.
This patch is light and standalone, thus it may be backported as far as 2.2
if required. However, because the error is human, it is probably better to
wait a bit to be sure everything is properly protected.
2021-04-14 08:01:41 -04:00
break ;
case OBJ_TYPE_CHECK :
2024-03-26 06:50:50 -04:00
value = ( __objt_check ( sess - > origin ) - > server
? __objt_check ( sess - > origin ) - > server - > cur_sess
: 0 ) ;
MINOR: logs: Add support of checks as session origin to format lf strings
When a log-format string is built from an health-check, the session origin
is the health-check itself and not a connection. In addition, there is no
stream. It means for now some formats are not supported: %s, %sc, %b, %bi,
%bp, %si and %sp.
Thanks to this patch, the session origin is converted to a check. So it is
possible to retrieve the backend and the backend connection. Note this
session have no listener, thus %ft format must be guarded.
This patch is light and standalone, thus it may be backported as far as 2.2
if required. However, because the error is human, it is probably better to
wait a bit to be sure everything is properly protected.
2021-04-14 08:01:41 -04:00
break ;
default :
2024-03-26 06:50:50 -04:00
value = 0 ;
MINOR: logs: Add support of checks as session origin to format lf strings
When a log-format string is built from an health-check, the session origin
is the health-check itself and not a connection. In addition, there is no
stream. It means for now some formats are not supported: %s, %sc, %b, %bi,
%bp, %si and %sp.
Thanks to this patch, the session origin is converted to a check. So it is
possible to retrieve the backend and the backend connection. Note this
session have no listener, thus %ft format must be guarded.
This patch is light and standalone, thus it may be backported as far as 2.2
if required. However, because the error is human, it is probably better to
wait a bit to be sure everything is properly protected.
2021-04-14 08:01:41 -04:00
break ;
}
2024-05-02 09:30:17 -04:00
ret = lf_int ( tmplog , dst + maxsize - tmplog , value , ctx , LF_INT_ULTOA ) ;
2024-03-26 06:50:50 -04:00
2012-03-12 07:46:41 -04:00
if ( ret = = NULL )
2012-02-27 05:23:10 -05:00
goto out ;
2012-03-12 07:46:41 -04:00
tmplog = ret ;
2012-02-27 05:23:10 -05:00
break ;
2024-03-26 06:50:50 -04:00
}
2012-02-27 05:23:10 -05:00
2023-11-28 05:21:40 -05:00
case LOG_FMT_RETRIES : // %rc
2024-03-26 06:50:50 -04:00
{
long int value = ( s ? s - > conn_retries : 0 ) ;
2018-09-05 09:51:28 -04:00
if ( s_flags & SF_REDISP )
2024-01-30 12:01:15 -05:00
LOGMETACHAR ( ' + ' ) ;
2024-05-02 09:30:17 -04:00
ret = lf_int ( tmplog , dst + maxsize - tmplog , value , ctx , LF_INT_LTOA ) ;
2012-03-12 07:46:41 -04:00
if ( ret = = NULL )
2012-03-26 11:52:55 -04:00
goto out ;
2012-03-12 07:46:41 -04:00
tmplog = ret ;
2012-02-27 05:23:10 -05:00
break ;
2024-03-26 06:50:50 -04:00
}
2012-02-27 05:23:10 -05:00
2012-03-12 07:46:41 -04:00
case LOG_FMT_SRVQUEUE : // %sq
2024-03-27 05:17:11 -04:00
ret = lf_int ( tmplog , dst + maxsize - tmplog , logs - > srv_queue_pos ,
2024-05-02 09:30:17 -04:00
ctx , LF_INT_LTOA ) ;
2012-03-12 07:46:41 -04:00
if ( ret = = NULL )
2012-02-27 05:23:10 -05:00
goto out ;
2012-03-12 07:46:41 -04:00
tmplog = ret ;
2012-02-27 05:23:10 -05:00
break ;
2012-03-12 07:46:41 -04:00
case LOG_FMT_BCKQUEUE : // %bq
2024-03-27 05:17:11 -04:00
ret = lf_int ( tmplog , dst + maxsize - tmplog , logs - > prx_queue_pos ,
2024-05-02 09:30:17 -04:00
ctx , LF_INT_LTOA ) ;
2012-03-12 07:46:41 -04:00
if ( ret = = NULL )
2012-02-27 05:23:10 -05:00
goto out ;
2012-03-12 07:46:41 -04:00
tmplog = ret ;
2012-02-27 05:23:10 -05:00
break ;
2012-03-12 07:46:41 -04:00
case LOG_FMT_HDRREQUEST : // %hr
2012-02-27 05:23:10 -05:00
/* request header */
2018-09-05 09:28:07 -04:00
if ( fe - > nb_req_cap & & s & & s - > req_cap ) {
2024-04-16 05:17:55 -04:00
LOG_VARTEXT_START ( ) ;
2012-02-27 05:23:10 -05:00
LOGCHAR ( ' { ' ) ;
for ( hdr = 0 ; hdr < fe - > nb_req_cap ; hdr + + ) {
if ( hdr )
LOGCHAR ( ' | ' ) ;
2015-04-03 16:16:32 -04:00
if ( s - > req_cap [ hdr ] ! = NULL ) {
2016-02-12 07:23:03 -05:00
ret = lf_encode_string ( tmplog , dst + maxsize ,
2024-05-02 09:30:17 -04:00
' # ' , hdr_encode_map , s - > req_cap [ hdr ] , ctx ) ;
2024-04-09 11:54:41 -04:00
if ( ret = = NULL )
2012-03-26 11:52:55 -04:00
goto out ;
2012-03-12 07:46:41 -04:00
tmplog = ret ;
2012-03-26 11:52:55 -04:00
}
2012-02-27 05:23:10 -05:00
}
LOGCHAR ( ' } ' ) ;
}
break ;
2012-03-12 07:46:41 -04:00
case LOG_FMT_HDRREQUESTLIST : // %hrl
2012-02-27 05:23:10 -05:00
/* request header list */
2018-09-05 09:28:07 -04:00
if ( fe - > nb_req_cap & & s & & s - > req_cap ) {
2024-01-31 08:37:07 -05:00
LOG_STRARRAY_START ( ) ;
2012-02-27 05:23:10 -05:00
for ( hdr = 0 ; hdr < fe - > nb_req_cap ; hdr + + ) {
if ( hdr > 0 )
2024-01-31 08:37:07 -05:00
LOG_STRARRAY_NEXT ( ) ;
2024-04-16 05:17:55 -04:00
LOG_VARTEXT_START ( ) ;
2015-04-03 16:16:32 -04:00
if ( s - > req_cap [ hdr ] ! = NULL ) {
2016-02-12 07:23:03 -05:00
ret = lf_encode_string ( tmplog , dst + maxsize ,
2024-05-02 09:30:17 -04:00
' # ' , hdr_encode_map , s - > req_cap [ hdr ] , ctx ) ;
2024-04-09 11:54:41 -04:00
if ( ret = = NULL )
2012-03-26 11:52:55 -04:00
goto out ;
2012-03-12 07:46:41 -04:00
tmplog = ret ;
2024-05-02 09:30:17 -04:00
} else if ( ! ( ctx - > options & LOG_OPT_QUOTE ) )
2012-02-27 05:23:10 -05:00
LOGCHAR ( ' - ' ) ;
2024-04-16 05:17:55 -04:00
/* Manually end variable text as we're emitting multiple
* texts at once
2024-01-10 13:14:25 -05:00
*/
2024-04-16 05:17:55 -04:00
LOG_VARTEXT_END ( ) ;
2012-02-27 05:23:10 -05:00
}
2024-01-31 08:37:07 -05:00
LOG_STRARRAY_END ( ) ;
2012-02-27 05:23:10 -05:00
}
break ;
2006-06-25 20:48:02 -04:00
2012-03-12 07:46:41 -04:00
case LOG_FMT_HDRRESPONS : // %hs
2012-02-27 05:23:10 -05:00
/* response header */
2018-09-05 09:28:07 -04:00
if ( fe - > nb_rsp_cap & & s & & s - > res_cap ) {
2024-04-16 05:17:55 -04:00
LOG_VARTEXT_START ( ) ;
2012-02-27 05:23:10 -05:00
LOGCHAR ( ' { ' ) ;
for ( hdr = 0 ; hdr < fe - > nb_rsp_cap ; hdr + + ) {
if ( hdr )
LOGCHAR ( ' | ' ) ;
2015-04-03 16:16:32 -04:00
if ( s - > res_cap [ hdr ] ! = NULL ) {
2016-02-12 07:23:03 -05:00
ret = lf_encode_string ( tmplog , dst + maxsize ,
2024-05-02 09:30:17 -04:00
' # ' , hdr_encode_map , s - > res_cap [ hdr ] , ctx ) ;
2024-04-09 11:54:41 -04:00
if ( ret = = NULL )
2012-03-26 11:52:55 -04:00
goto out ;
2012-03-12 07:46:41 -04:00
tmplog = ret ;
2012-03-26 11:52:55 -04:00
}
2012-02-27 05:23:10 -05:00
}
LOGCHAR ( ' } ' ) ;
}
break ;
2012-03-12 07:46:41 -04:00
case LOG_FMT_HDRRESPONSLIST : // %hsl
2012-02-27 05:23:10 -05:00
/* response header list */
2018-09-05 09:28:07 -04:00
if ( fe - > nb_rsp_cap & & s & & s - > res_cap ) {
2024-01-31 08:37:07 -05:00
LOG_STRARRAY_START ( ) ;
2012-02-27 05:23:10 -05:00
for ( hdr = 0 ; hdr < fe - > nb_rsp_cap ; hdr + + ) {
if ( hdr > 0 )
2024-01-31 08:37:07 -05:00
LOG_STRARRAY_NEXT ( ) ;
2024-04-16 05:17:55 -04:00
LOG_VARTEXT_START ( ) ;
2015-04-03 16:16:32 -04:00
if ( s - > res_cap [ hdr ] ! = NULL ) {
2016-02-12 07:23:03 -05:00
ret = lf_encode_string ( tmplog , dst + maxsize ,
2024-05-02 09:30:17 -04:00
' # ' , hdr_encode_map , s - > res_cap [ hdr ] , ctx ) ;
2024-04-09 11:54:41 -04:00
if ( ret = = NULL )
2012-03-26 11:52:55 -04:00
goto out ;
2012-03-12 07:46:41 -04:00
tmplog = ret ;
2024-05-02 09:30:17 -04:00
} else if ( ! ( ctx - > options & LOG_OPT_QUOTE ) )
2012-02-27 05:23:10 -05:00
LOGCHAR ( ' - ' ) ;
2024-04-16 05:17:55 -04:00
/* Manually end variable text as we're emitting multiple
* texts at once
2024-01-10 13:14:25 -05:00
*/
2024-04-16 05:17:55 -04:00
LOG_VARTEXT_END ( ) ;
2012-02-27 05:23:10 -05:00
}
2024-01-31 08:37:07 -05:00
LOG_STRARRAY_END ( ) ;
2012-02-27 05:23:10 -05:00
}
break ;
2012-03-12 07:46:41 -04:00
case LOG_FMT_REQ : // %r
2012-02-27 05:23:10 -05:00
/* Request */
2024-04-16 05:17:55 -04:00
LOG_VARTEXT_START ( ) ;
2016-04-25 11:09:40 -04:00
uri = txn & & txn - > uri ? txn - > uri : " <BADREQ> " ;
2016-02-12 07:23:03 -05:00
ret = lf_encode_string ( tmplog , dst + maxsize ,
2024-05-02 09:30:17 -04:00
' # ' , url_encode_map , uri , ctx ) ;
2024-04-09 11:54:41 -04:00
if ( ret = = NULL )
2012-03-26 11:52:55 -04:00
goto out ;
2012-03-12 07:46:41 -04:00
tmplog = ret ;
2012-02-27 05:23:10 -05:00
break ;
2012-04-05 12:02:55 -04:00
2015-04-27 17:37:03 -04:00
case LOG_FMT_HTTP_PATH : // %HP
2016-04-25 11:09:40 -04:00
uri = txn & & txn - > uri ? txn - > uri : " <BADREQ> " ;
2015-04-27 17:37:03 -04:00
2024-04-16 05:17:55 -04:00
LOG_VARTEXT_START ( ) ;
2015-04-27 17:37:03 -04:00
end = uri + strlen ( uri ) ;
// look for the first whitespace character
while ( uri < end & & ! HTTP_IS_SPHT ( * uri ) )
uri + + ;
// keep advancing past multiple spaces
while ( uri < end & & HTTP_IS_SPHT ( * uri ) ) {
uri + + ; nspaces + + ;
}
// look for first space or question mark after url
spc = uri ;
while ( spc < end & & * spc ! = ' ? ' & & ! HTTP_IS_SPHT ( * spc ) )
spc + + ;
2016-04-25 19:39:02 -04:00
if ( ! txn | | ! txn - > uri | | nspaces = = 0 ) {
2018-07-13 04:54:26 -04:00
chunk . area = " <BADREQ> " ;
chunk . data = strlen ( " <BADREQ> " ) ;
2015-04-27 17:37:03 -04:00
} else {
2018-07-13 04:54:26 -04:00
chunk . area = uri ;
chunk . data = spc - uri ;
2015-04-27 17:37:03 -04:00
}
2024-05-02 09:30:17 -04:00
ret = lf_encode_chunk ( tmplog , dst + maxsize , ' # ' , url_encode_map , & chunk , ctx ) ;
2024-04-09 11:54:41 -04:00
if ( ret = = NULL )
2015-04-27 17:37:03 -04:00
goto out ;
tmplog = ret ;
break ;
2020-11-30 13:27:47 -05:00
case LOG_FMT_HTTP_PATH_ONLY : // %HPO
uri = txn & & txn - > uri ? txn - > uri : " <BADREQ> " ;
2024-04-16 05:17:55 -04:00
LOG_VARTEXT_START ( ) ;
2020-11-30 13:27:47 -05:00
end = uri + strlen ( uri ) ;
// look for the first whitespace character
while ( uri < end & & ! HTTP_IS_SPHT ( * uri ) )
uri + + ;
// keep advancing past multiple spaces
while ( uri < end & & HTTP_IS_SPHT ( * uri ) ) {
uri + + ; nspaces + + ;
}
// look for first space after url
spc = uri ;
while ( spc < end & & ! HTTP_IS_SPHT ( * spc ) )
spc + + ;
2021-02-28 10:11:36 -05:00
path = ist2 ( uri , spc - uri ) ;
2020-11-30 13:27:47 -05:00
// extract relative path without query params from url
2021-07-06 05:40:12 -04:00
parser = http_uri_parser_init ( path ) ;
path = iststop ( http_parse_path ( & parser ) , ' ? ' ) ;
2020-11-30 13:27:47 -05:00
if ( ! txn | | ! txn - > uri | | nspaces = = 0 ) {
chunk . area = " <BADREQ> " ;
chunk . data = strlen ( " <BADREQ> " ) ;
} else {
chunk . area = path . ptr ;
chunk . data = path . len ;
}
2024-05-02 09:30:17 -04:00
ret = lf_encode_chunk ( tmplog , dst + maxsize , ' # ' , url_encode_map , & chunk , ctx ) ;
2024-04-09 11:54:41 -04:00
if ( ret = = NULL )
2020-11-30 13:27:47 -05:00
goto out ;
tmplog = ret ;
break ;
2015-07-31 12:14:16 -04:00
case LOG_FMT_HTTP_QUERY : // %HQ
2024-04-16 05:17:55 -04:00
LOG_VARTEXT_START ( ) ;
2015-07-31 12:14:16 -04:00
2016-04-25 11:09:40 -04:00
if ( ! txn | | ! txn - > uri ) {
2018-07-13 04:54:26 -04:00
chunk . area = " <BADREQ> " ;
chunk . data = strlen ( " <BADREQ> " ) ;
2015-07-31 12:14:16 -04:00
} else {
uri = txn - > uri ;
end = uri + strlen ( uri ) ;
// look for the first question mark
while ( uri < end & & * uri ! = ' ? ' )
uri + + ;
qmark = uri ;
// look for first space or question mark after url
while ( uri < end & & ! HTTP_IS_SPHT ( * uri ) )
uri + + ;
2018-07-13 04:54:26 -04:00
chunk . area = qmark ;
chunk . data = uri - qmark ;
2015-07-31 12:14:16 -04:00
}
2024-05-02 09:30:17 -04:00
ret = lf_encode_chunk ( tmplog , dst + maxsize , ' # ' , url_encode_map , & chunk , ctx ) ;
2024-04-09 11:54:41 -04:00
if ( ret = = NULL )
2015-07-31 12:14:16 -04:00
goto out ;
tmplog = ret ;
break ;
2015-04-27 17:37:03 -04:00
case LOG_FMT_HTTP_URI : // %HU
2016-04-25 11:09:40 -04:00
uri = txn & & txn - > uri ? txn - > uri : " <BADREQ> " ;
2015-04-27 17:37:03 -04:00
2024-04-16 05:17:55 -04:00
LOG_VARTEXT_START ( ) ;
2015-04-27 17:37:03 -04:00
end = uri + strlen ( uri ) ;
// look for the first whitespace character
while ( uri < end & & ! HTTP_IS_SPHT ( * uri ) )
uri + + ;
// keep advancing past multiple spaces
while ( uri < end & & HTTP_IS_SPHT ( * uri ) ) {
uri + + ; nspaces + + ;
}
// look for first space after url
spc = uri ;
while ( spc < end & & ! HTTP_IS_SPHT ( * spc ) )
spc + + ;
2016-04-25 11:09:40 -04:00
if ( ! txn | | ! txn - > uri | | nspaces = = 0 ) {
2018-07-13 04:54:26 -04:00
chunk . area = " <BADREQ> " ;
chunk . data = strlen ( " <BADREQ> " ) ;
2015-04-27 17:37:03 -04:00
} else {
2018-07-13 04:54:26 -04:00
chunk . area = uri ;
chunk . data = spc - uri ;
2015-04-27 17:37:03 -04:00
}
2024-05-02 09:30:17 -04:00
ret = lf_encode_chunk ( tmplog , dst + maxsize , ' # ' , url_encode_map , & chunk , ctx ) ;
2024-04-09 11:54:41 -04:00
if ( ret = = NULL )
2015-04-27 17:37:03 -04:00
goto out ;
tmplog = ret ;
break ;
case LOG_FMT_HTTP_METHOD : // %HM
2016-04-25 11:09:40 -04:00
uri = txn & & txn - > uri ? txn - > uri : " <BADREQ> " ;
2024-04-16 05:17:55 -04:00
LOG_VARTEXT_START ( ) ;
2015-04-27 17:37:03 -04:00
end = uri + strlen ( uri ) ;
// look for the first whitespace character
spc = uri ;
while ( spc < end & & ! HTTP_IS_SPHT ( * spc ) )
spc + + ;
if ( spc = = end ) { // odd case, we have txn->uri, but we only got a verb
2018-07-13 04:54:26 -04:00
chunk . area = " <BADREQ> " ;
chunk . data = strlen ( " <BADREQ> " ) ;
2015-04-27 17:37:03 -04:00
} else {
2018-07-13 04:54:26 -04:00
chunk . area = uri ;
chunk . data = spc - uri ;
2015-04-27 17:37:03 -04:00
}
2024-05-02 09:30:17 -04:00
ret = lf_encode_chunk ( tmplog , dst + maxsize , ' # ' , url_encode_map , & chunk , ctx ) ;
2024-04-09 11:54:41 -04:00
if ( ret = = NULL )
2015-04-27 17:37:03 -04:00
goto out ;
tmplog = ret ;
break ;
case LOG_FMT_HTTP_VERSION : // %HV
2016-04-25 11:09:40 -04:00
uri = txn & & txn - > uri ? txn - > uri : " <BADREQ> " ;
2024-04-16 05:17:55 -04:00
LOG_VARTEXT_START ( ) ;
2015-04-27 17:37:03 -04:00
end = uri + strlen ( uri ) ;
// look for the first whitespace character
while ( uri < end & & ! HTTP_IS_SPHT ( * uri ) )
uri + + ;
// keep advancing past multiple spaces
while ( uri < end & & HTTP_IS_SPHT ( * uri ) ) {
uri + + ; nspaces + + ;
}
// look for the next whitespace character
while ( uri < end & & ! HTTP_IS_SPHT ( * uri ) )
uri + + ;
// keep advancing past multiple spaces
while ( uri < end & & HTTP_IS_SPHT ( * uri ) )
uri + + ;
2016-04-25 11:09:40 -04:00
if ( ! txn | | ! txn - > uri | | nspaces = = 0 ) {
2018-07-13 04:54:26 -04:00
chunk . area = " <BADREQ> " ;
chunk . data = strlen ( " <BADREQ> " ) ;
2015-04-27 17:37:03 -04:00
} else if ( uri = = end ) {
2018-07-13 04:54:26 -04:00
chunk . area = " HTTP/0.9 " ;
chunk . data = strlen ( " HTTP/0.9 " ) ;
2015-04-27 17:37:03 -04:00
} else {
2018-07-13 04:54:26 -04:00
chunk . area = uri ;
chunk . data = end - uri ;
2015-04-27 17:37:03 -04:00
}
2024-05-02 09:30:17 -04:00
ret = lf_encode_chunk ( tmplog , dst + maxsize , ' # ' , url_encode_map , & chunk , ctx ) ;
2024-04-09 11:54:41 -04:00
if ( ret = = NULL )
2015-04-27 17:37:03 -04:00
goto out ;
tmplog = ret ;
break ;
2012-04-05 12:02:55 -04:00
case LOG_FMT_COUNTER : // %rt
2024-05-02 09:30:17 -04:00
if ( ctx - > options & LOG_OPT_HEXA ) {
2024-05-02 10:48:56 -04:00
iret = snprintf ( ctx - > _buf , sizeof ( ctx - > _buf ) , " %04X " , uniq_id ) ;
BUG/MINOR: log: invalid snprintf() usage in sess_build_logline()
According to snprintf() man page:
The functions snprintf() and vsnprintf() do not write more than
size bytes (including the terminating null byte ('\0')). If the
output was truncated due to this limit, then the return value is
the number of characters (excluding the terminating null byte)
which would have been written to the final string if enough space
had been available. Thus, a return value of size or more means
that the output was truncated.
However, in sess_build_logline(), each time we need to check the return
value of snprintf(), here is how we proceed:
iret = snprintf(tmplog, max, ...);
if (iret < 0 || iret > max)
// error
// success
tmplog += iret;
Here is the issue: if snprintf() lacks 1 byte space to write the
terminating NULL byte, it will return max. Which means in this case
that we fail to know that snprintf() truncated the output in reality,
and we still add iret to tmplog pointer. Considering sess_build_logline()
should NOT write more than <maxsize> bytes (including the terminating NULL
byte) as per the function description, in this case the function would
write <maxsize>+1 byte (to write the terminating NULL byte upon return),
which may lead to invalid write if <dst> was meant to hold <maxsize> bytes
at maximum.
Hopefully, this bug wasn't triggered so far because sess_build_logline()
is called with logline as <dst> argument and <global.max_syslog_len> as
<maxsize> argument, logline being initialized with 1 extra byte upon
startup.
But we better fix this to comply with the function description and prevent
any side-effect since some sess_build_logline() helpers may assume that
'tmplog-dst < maxsize' is always true. Also sess_build_logline() users
probably don't expect NULL-byte to be accounted for in the produced
logline length.
This should be backported to all stable versions.
[ada: for backports, the patch needs to be applied manually because of
c6a713842 ("MINOR: log: simplify last_isspace in sess_build_logline()")]
2024-04-09 09:59:42 -04:00
if ( iret < 0 | | iret > = dst + maxsize - tmplog )
2012-04-05 12:02:55 -04:00
goto out ;
2024-05-02 10:48:56 -04:00
ret = lf_rawtext ( tmplog , ctx - > _buf , dst + maxsize - tmplog , ctx ) ;
2012-04-05 12:02:55 -04:00
} else {
2024-05-02 09:30:17 -04:00
ret = lf_int ( tmplog , dst + maxsize - tmplog , uniq_id , ctx , LF_INT_LTOA ) ;
2012-04-05 12:02:55 -04:00
}
2024-03-27 05:28:59 -04:00
if ( ret = = NULL )
goto out ;
tmplog = ret ;
2012-04-05 12:02:55 -04:00
break ;
2014-08-28 09:03:15 -04:00
case LOG_FMT_LOGCNT : // %lc
2024-05-02 09:30:17 -04:00
if ( ctx - > options & LOG_OPT_HEXA ) {
2024-05-02 10:48:56 -04:00
iret = snprintf ( ctx - > _buf , sizeof ( ctx - > _buf ) , " %04X " , fe - > log_count ) ;
BUG/MINOR: log: invalid snprintf() usage in sess_build_logline()
According to snprintf() man page:
The functions snprintf() and vsnprintf() do not write more than
size bytes (including the terminating null byte ('\0')). If the
output was truncated due to this limit, then the return value is
the number of characters (excluding the terminating null byte)
which would have been written to the final string if enough space
had been available. Thus, a return value of size or more means
that the output was truncated.
However, in sess_build_logline(), each time we need to check the return
value of snprintf(), here is how we proceed:
iret = snprintf(tmplog, max, ...);
if (iret < 0 || iret > max)
// error
// success
tmplog += iret;
Here is the issue: if snprintf() lacks 1 byte space to write the
terminating NULL byte, it will return max. Which means in this case
that we fail to know that snprintf() truncated the output in reality,
and we still add iret to tmplog pointer. Considering sess_build_logline()
should NOT write more than <maxsize> bytes (including the terminating NULL
byte) as per the function description, in this case the function would
write <maxsize>+1 byte (to write the terminating NULL byte upon return),
which may lead to invalid write if <dst> was meant to hold <maxsize> bytes
at maximum.
Hopefully, this bug wasn't triggered so far because sess_build_logline()
is called with logline as <dst> argument and <global.max_syslog_len> as
<maxsize> argument, logline being initialized with 1 extra byte upon
startup.
But we better fix this to comply with the function description and prevent
any side-effect since some sess_build_logline() helpers may assume that
'tmplog-dst < maxsize' is always true. Also sess_build_logline() users
probably don't expect NULL-byte to be accounted for in the produced
logline length.
This should be backported to all stable versions.
[ada: for backports, the patch needs to be applied manually because of
c6a713842 ("MINOR: log: simplify last_isspace in sess_build_logline()")]
2024-04-09 09:59:42 -04:00
if ( iret < 0 | | iret > = dst + maxsize - tmplog )
2014-08-28 09:03:15 -04:00
goto out ;
2024-05-02 10:48:56 -04:00
ret = lf_rawtext ( tmplog , ctx - > _buf , dst + maxsize - tmplog , ctx ) ;
2014-08-28 09:03:15 -04:00
} else {
2024-03-27 05:17:11 -04:00
ret = lf_int ( tmplog , dst + maxsize - tmplog , fe - > log_count ,
2024-05-02 09:30:17 -04:00
ctx , LF_INT_ULTOA ) ;
2014-08-28 09:03:15 -04:00
}
2024-03-27 05:28:59 -04:00
if ( ret = = NULL )
goto out ;
tmplog = ret ;
2014-08-28 09:03:15 -04:00
break ;
2012-04-05 12:02:55 -04:00
case LOG_FMT_HOSTNAME : // %H
src = hostname ;
2024-05-02 09:30:17 -04:00
ret = lf_text ( tmplog , src , dst + maxsize - tmplog , ctx ) ;
2012-04-05 12:02:55 -04:00
if ( ret = = NULL )
goto out ;
tmplog = ret ;
break ;
case LOG_FMT_PID : // %pid
2024-05-02 09:30:17 -04:00
if ( ctx - > options & LOG_OPT_HEXA ) {
2024-05-02 10:48:56 -04:00
iret = snprintf ( ctx - > _buf , sizeof ( ctx - > _buf ) , " %04X " , pid ) ;
BUG/MINOR: log: invalid snprintf() usage in sess_build_logline()
According to snprintf() man page:
The functions snprintf() and vsnprintf() do not write more than
size bytes (including the terminating null byte ('\0')). If the
output was truncated due to this limit, then the return value is
the number of characters (excluding the terminating null byte)
which would have been written to the final string if enough space
had been available. Thus, a return value of size or more means
that the output was truncated.
However, in sess_build_logline(), each time we need to check the return
value of snprintf(), here is how we proceed:
iret = snprintf(tmplog, max, ...);
if (iret < 0 || iret > max)
// error
// success
tmplog += iret;
Here is the issue: if snprintf() lacks 1 byte space to write the
terminating NULL byte, it will return max. Which means in this case
that we fail to know that snprintf() truncated the output in reality,
and we still add iret to tmplog pointer. Considering sess_build_logline()
should NOT write more than <maxsize> bytes (including the terminating NULL
byte) as per the function description, in this case the function would
write <maxsize>+1 byte (to write the terminating NULL byte upon return),
which may lead to invalid write if <dst> was meant to hold <maxsize> bytes
at maximum.
Hopefully, this bug wasn't triggered so far because sess_build_logline()
is called with logline as <dst> argument and <global.max_syslog_len> as
<maxsize> argument, logline being initialized with 1 extra byte upon
startup.
But we better fix this to comply with the function description and prevent
any side-effect since some sess_build_logline() helpers may assume that
'tmplog-dst < maxsize' is always true. Also sess_build_logline() users
probably don't expect NULL-byte to be accounted for in the produced
logline length.
This should be backported to all stable versions.
[ada: for backports, the patch needs to be applied manually because of
c6a713842 ("MINOR: log: simplify last_isspace in sess_build_logline()")]
2024-04-09 09:59:42 -04:00
if ( iret < 0 | | iret > = dst + maxsize - tmplog )
2012-04-05 12:02:55 -04:00
goto out ;
2024-05-02 10:48:56 -04:00
ret = lf_rawtext ( tmplog , ctx - > _buf , dst + maxsize - tmplog , ctx ) ;
2012-04-05 12:02:55 -04:00
} else {
2024-05-02 09:30:17 -04:00
ret = lf_int ( tmplog , dst + maxsize - tmplog , pid , ctx , LF_INT_LTOA ) ;
2012-04-05 12:02:55 -04:00
}
2024-03-27 05:28:59 -04:00
if ( ret = = NULL )
goto out ;
tmplog = ret ;
2012-04-05 12:02:55 -04:00
break ;
2012-03-12 07:48:57 -04:00
case LOG_FMT_UNIQUEID : // %ID
2013-08-28 09:44:19 -04:00
ret = NULL ;
2020-03-05 14:19:02 -05:00
if ( s )
2024-05-02 09:30:17 -04:00
ret = lf_text_len ( tmplog , s - > unique_id . ptr , s - > unique_id . len , maxsize - ( tmplog - dst ) , ctx ) ;
2020-03-05 14:19:02 -05:00
else
2024-05-02 09:30:17 -04:00
ret = lf_text_len ( tmplog , NULL , 0 , maxsize - ( tmplog - dst ) , ctx ) ;
2012-03-12 07:48:57 -04:00
if ( ret = = NULL )
goto out ;
tmplog = ret ;
break ;
2024-05-06 08:13:11 -04:00
case LOG_FMT_ORIGIN : // %OG
ret = lf_text ( tmplog , log_orig_to_str ( log_orig ) ,
dst + maxsize - tmplog , ctx ) ;
if ( ret = = NULL )
goto out ;
tmplog = ret ;
break ;
2012-02-27 05:23:10 -05:00
}
MEDIUM: log: carry tag context in logformat node
This is a pretty simple patch despite requiring to make some visible
changes in the code:
When parsing a logformat string, log tags (ie: '%tag', AKA log tags) are
turned into logformat nodes with their type set to the type of the
corresponding logformat_tag element which was matched by name. Thus, when
"compiling" a logformat tag, we only keep a reference to the tag type
from the original logformat_tag.
For example, for "%B" log tag, we have the following logformat_tag
element:
{
.name = "B",
.type = LOG_FMT_BYTES,
.mode = PR_MODE_TCP,
.lw = LW_BYTES,
.config_callback = NULL
}
When parsing "%B" string, we search for a matching logformat tag
inside logformat_tags[] array using the provided name, once we find a
matching element, we craft a logformat node whose type will be
LOG_FMT_BYTES, but from the node itself, we no longer have access to
other informations that are set in the logformat_tag struct element.
Thus from a logformat_node resulting from a log tag, with current
implementation, we cannot easily get back to matching logformat_tag
struct element as it would require us to scan the whole logformat_tags
array at runtime using node->type to find the matching element.
Let's take a simpler path and consider all tag-specific LOG_FMT_*
subtypes as being part of the same logformat node type: LOG_FMT_TAG.
Thanks to that, we're now able to distinguish logformat nodes made
from logformat tag from other logformat nodes, and link them to
their corresponding logformat_tag element from logformat_tags[] array. All
it costs is a simple indirection and an extra pointer in logformat_node
struct.
While at it, all LOG_FMT_* types related to logformat tags were moved
inside log.c as they have no use outside of it since they are simply
lookup indexes for sess_build_logline() and could even be replaced by
function pointers some day...
2024-02-22 14:20:41 -05:00
next_fmt :
2024-04-22 08:40:04 -04:00
if ( value_beg = = tmplog ) {
/* handle the case where no data was generated for the value after
* the key was already announced
*/
2024-05-02 09:30:17 -04:00
if ( ctx - > options & LOG_OPT_ENCODE_JSON ) {
2024-04-22 08:40:04 -04:00
/* for JSON, we simply output 'null' */
iret = snprintf ( tmplog , dst + maxsize - tmplog , " null " ) ;
if ( iret < 0 | | iret > = dst + maxsize - tmplog )
goto out ;
tmplog + = iret ;
}
2024-05-02 09:30:17 -04:00
if ( ctx - > options & LOG_OPT_ENCODE_CBOR ) {
2024-04-23 04:12:46 -04:00
/* for CBOR, we have the '22' primitive which is known as
* NULL
*/
LOG_CBOR_BYTE ( 0xF6 ) ;
}
2024-04-22 08:40:04 -04:00
}
2024-04-16 05:17:55 -04:00
/* if variable text was started for the current node data, we need
* to end it
2024-01-10 13:14:25 -05:00
*/
2024-04-16 05:17:55 -04:00
LOG_VARTEXT_END ( ) ;
BUG/MINOR: log: prevent double spaces emission in sess_build_logline()
Christian reported in GH #2556 that since 3.0-dev double spaces may be
found in log messages on some cases where it was not the case before.
As we were able to easily reproduce, a quick bisect led us to c6a7138
("MINOR: log: simplify last_isspace in sess_build_logline()"). While
it is true that all switch cases set the last_isspace variable to 0,
there was a subtelty for some fields such as '%hr', '%hrl', '%hs' or
'%hsl' and I overlooked it. Indeed, for '%hr', last_isspace was only set
to 0 if data was emitted, else the assignment didn't occur.
But with c6a7138, last_isspace is always set to 0 as long as the current
node type is not a separator. Because of that, if no data is emitted for
the current node value, and a space was already emitted prior to the
current node, then an extra space could be emitted after the node,
resulting in two spaces being emitted.
Note that while c6a7138 introduces a slight behavior regression regarding
last_isspace logic with the specific fields mentionned above, this
behavior could already be triggered with a failing or empty logformat
node sample expression. Consider this logformat expression:
log-format "%{-M}o | %[str()] |"
str() will not print anything, and since we disabled mandatory option with
'-M', nothing gets printed for the node sample expression. As a result, we
have the following output:
"| |"
Instead of (when mandatory option is enabled):
"| - |"
Thus in order to stick to the historical behavior, systematically set
last_isspace to 0 for EXPR nodes, and only set last_isspace to 0 when
data was written for TAG nodes. This way, '%hr', '%hrl', '%hs' or
'%hsl' should behave as before.
No backport needed.
2024-05-02 03:30:28 -04:00
if ( tmplog ! = value_beg ) {
/* data was actually generated for the current dynamic
* node , reset the space hint so that a new space may
* now be emitted when relevant .
*/
last_isspace = 0 ;
}
2012-02-27 05:23:10 -05:00
}
2024-04-22 08:40:04 -04:00
/* back to global ctx (some encoding types may need to output
* ending closure )
*/
2024-05-02 09:30:17 -04:00
lf_buildctx_prepare ( ctx , g_options , NULL ) ;
2024-04-22 08:40:04 -04:00
2024-05-02 09:30:17 -04:00
if ( ctx - > options & LOG_OPT_ENCODE_JSON )
2024-04-22 08:40:04 -04:00
LOGCHAR ( ' } ' ) ;
2024-05-02 09:30:17 -04:00
else if ( ctx - > options & LOG_OPT_ENCODE_CBOR ) {
2024-04-23 04:12:46 -04:00
/* end indefinite-length map */
LOG_CBOR_BYTE ( 0xFF ) ;
}
2024-04-22 08:40:04 -04:00
2012-02-27 05:23:10 -05:00
out :
2012-03-12 07:46:41 -04:00
/* *tmplog is a unused character */
* tmplog = ' \0 ' ;
2012-12-27 20:44:01 -05:00
return tmplog - dst ;
2012-02-27 05:23:10 -05:00
2006-06-25 20:48:02 -04:00
}
2012-03-12 07:46:41 -04:00
/*
REORG/MAJOR: session: rename the "session" entity to "stream"
With HTTP/2, we'll have to support multiplexed streams. A stream is in
fact the largest part of what we currently call a session, it has buffers,
logs, etc.
In order to catch any error, this commit removes any reference to the
struct session and tries to rename most "session" occurrences in function
names to "stream" and "sess" to "strm" when that's related to a session.
The files stream.{c,h} were added and session.{c,h} removed.
The session will be reintroduced later and a few parts of the stream
will progressively be moved overthere. It will more or less contain
only what we need in an embryonic session.
Sample fetch functions and converters will have to change a bit so
that they'll use an L5 (session) instead of what's currently called
"L4" which is in fact L6 for now.
Once all changes are completed, we should see approximately this :
L7 - http_txn
L6 - stream
L5 - session
L4 - connection | applet
There will be at most one http_txn per stream, and a same session will
possibly be referenced by multiple streams. A connection will point to
a session and to a stream. The session will hold all the information
we need to keep even when we don't yet have a stream.
Some more cleanup is needed because some code was already far from
being clean. The server queue management still refers to sessions at
many places while comments talk about connections. This will have to
be cleaned up once we have a server-side connection pool manager.
Stream flags "SN_*" still need to be renamed, it doesn't seem like
any of them will need to move to the session.
2015-04-02 18:22:06 -04:00
* send a log for the stream when we have enough info about it .
2012-03-12 07:46:41 -04:00
* Will not log if the frontend has no log defined .
*/
2024-02-22 05:29:20 -05:00
void strm_log ( struct stream * s , int origin )
2012-03-12 07:46:41 -04:00
{
2015-04-03 09:40:56 -04:00
struct session * sess = s - > sess ;
2012-03-12 07:46:41 -04:00
int size , err , level ;
2015-09-25 13:17:44 -04:00
int sd_size = 0 ;
2012-03-12 07:46:41 -04:00
/* if we don't want to log normal traffic, return now */
2015-04-02 19:14:29 -04:00
err = ( s - > flags & SF_REDISP ) | |
( ( s - > flags & SF_ERR_MASK ) > SF_ERR_LOCAL ) | |
2022-06-17 08:53:20 -04:00
( ( ( s - > flags & SF_ERR_MASK ) = = SF_ERR_NONE ) & & s - > conn_retries ) | |
2015-04-03 17:46:31 -04:00
( ( sess - > fe - > mode = = PR_MODE_HTTP ) & & s - > txn & & s - > txn - > status > = 500 ) ;
2006-06-25 20:48:02 -04:00
2015-04-03 09:40:56 -04:00
if ( ! err & & ( sess - > fe - > options2 & PR_O2_NOLOGNORM ) )
2012-03-12 07:46:41 -04:00
return ;
2012-02-27 05:23:10 -05:00
MEDIUM: tree-wide: logsrv struct becomes logger
When 'log' directive was implemented, the internal representation was
named 'struct logsrv', because the 'log' directive would directly point
to the log target, which used to be a (UDP) log server exclusively at
that time, hence the name.
But things have become more complex, since today 'log' directive can point
to ring targets (implicit, or named) for example.
Indeed, a 'log' directive does no longer reference the "final" server to
which the log will be sent, but instead it describes which log API and
parameters to use for transporting the log messages to the proper log
destination.
So now the term 'logsrv' is rather confusing and prevents us from
introducing a new level of abstraction because they would be mixed
with logsrv.
So in order to better designate this 'log' directive, and make it more
generic, we chose the word 'logger' which now replaces logsrv everywhere
it was used in the code (including related comments).
This is internal rewording, so no functional change should be expected
on user-side.
2023-09-11 09:06:53 -04:00
if ( LIST_ISEMPTY ( & sess - > fe - > loggers ) )
2012-03-12 07:46:41 -04:00
return ;
2012-02-27 05:23:10 -05:00
2013-06-11 11:18:02 -04:00
if ( s - > logs . level ) { /* loglevel was overridden */
if ( s - > logs . level = = - 1 ) {
s - > logs . logwait = 0 ; /* logs disabled */
return ;
}
level = s - > logs . level - 1 ;
}
else {
level = LOG_INFO ;
2015-04-03 09:40:56 -04:00
if ( err & & ( sess - > fe - > options2 & PR_O2_LOGERRORS ) )
2013-06-11 11:18:02 -04:00
level = LOG_ERR ;
}
2012-03-12 07:46:41 -04:00
2013-08-28 09:44:19 -04:00
/* if unique-id was not generated */
2024-02-23 09:57:21 -05:00
if ( ! isttest ( s - > unique_id ) & & ! lf_expr_isempty ( & sess - > fe - > format_unique_id ) ) {
2020-02-28 09:13:34 -05:00
stream_generate_unique_id ( s , & sess - > fe - > format_unique_id ) ;
2013-08-28 09:44:19 -04:00
}
2024-02-23 09:57:21 -05:00
if ( ! lf_expr_isempty ( & sess - > fe - > logformat_sd ) ) {
2024-05-06 08:13:11 -04:00
sd_size = build_logline_orig ( s , logline_rfc5424 , global . max_syslog_len ,
& sess - > fe - > logformat_sd , origin ) ;
2015-09-25 13:17:44 -04:00
}
2024-05-06 08:13:11 -04:00
size = build_logline_orig ( s , logline , global . max_syslog_len , & sess - > fe - > logformat , origin ) ;
2012-03-12 07:46:41 -04:00
if ( size > 0 ) {
2024-02-22 05:29:20 -05:00
struct process_send_log_ctx ctx ;
2021-04-06 07:53:36 -04:00
_HA_ATOMIC_INC ( & sess - > fe - > log_count ) ;
2024-02-22 05:29:20 -05:00
ctx . origin = origin ;
ctx . sess = sess ;
ctx . stream = s ;
__send_log ( & ctx , & sess - > fe - > loggers , & sess - > fe - > log_tag , level ,
2019-08-11 13:40:12 -04:00
logline , size + 1 , logline_rfc5424 , sd_size ) ;
2012-03-12 07:46:41 -04:00
s - > logs . logwait = 0 ;
}
}
2012-02-27 05:23:10 -05:00
2018-09-05 13:51:10 -04:00
/*
* send a minimalist log for the session . Will not log if the frontend has no
* log defined . It is assumed that this is only used to report anomalies that
* cannot lead to the creation of a regular stream . Because of this the log
* level is LOG_INFO or LOG_ERR depending on the " log-separate-error " setting
* in the frontend . The caller must simply know that it should not call this
2018-10-05 04:22:27 -04:00
* function to report unimportant events . It is safe to call this function with
* sess = = NULL ( will not do anything ) .
2024-02-21 11:26:52 -05:00
*
* if < embryonic > is set , then legacy error log payload will be generated unless
* logformat_error is specified ( ie : normal logformat is ignored in this case ) .
*
2018-09-05 13:51:10 -04:00
*/
2024-02-21 11:26:52 -05:00
void _sess_log ( struct session * sess , int embryonic )
2018-09-05 13:51:10 -04:00
{
int size , level ;
int sd_size = 0 ;
2024-05-06 08:13:11 -04:00
int orig = ( embryonic ) ? LOG_ORIG_SESS_KILL : LOG_ORIG_SESS_ERROR ;
2018-09-05 13:51:10 -04:00
2018-10-05 04:22:27 -04:00
if ( ! sess )
return ;
MEDIUM: tree-wide: logsrv struct becomes logger
When 'log' directive was implemented, the internal representation was
named 'struct logsrv', because the 'log' directive would directly point
to the log target, which used to be a (UDP) log server exclusively at
that time, hence the name.
But things have become more complex, since today 'log' directive can point
to ring targets (implicit, or named) for example.
Indeed, a 'log' directive does no longer reference the "final" server to
which the log will be sent, but instead it describes which log API and
parameters to use for transporting the log messages to the proper log
destination.
So now the term 'logsrv' is rather confusing and prevents us from
introducing a new level of abstraction because they would be mixed
with logsrv.
So in order to better designate this 'log' directive, and make it more
generic, we chose the word 'logger' which now replaces logsrv everywhere
it was used in the code (including related comments).
This is internal rewording, so no functional change should be expected
on user-side.
2023-09-11 09:06:53 -04:00
if ( LIST_ISEMPTY ( & sess - > fe - > loggers ) )
2018-09-05 13:51:10 -04:00
return ;
level = LOG_INFO ;
if ( sess - > fe - > options2 & PR_O2_LOGERRORS )
level = LOG_ERR ;
2024-02-23 09:57:21 -05:00
if ( ! lf_expr_isempty ( & sess - > fe - > logformat_sd ) ) {
2024-05-06 08:13:11 -04:00
sd_size = sess_build_logline_orig ( sess , NULL ,
logline_rfc5424 , global . max_syslog_len ,
& sess - > fe - > logformat_sd ,
orig ) ;
2018-09-05 13:51:10 -04:00
}
2024-02-23 09:57:21 -05:00
if ( ! lf_expr_isempty ( & sess - > fe - > logformat_error ) )
2024-05-06 08:13:11 -04:00
size = sess_build_logline_orig ( sess , NULL , logline ,
global . max_syslog_len , & sess - > fe - > logformat_error ,
orig ) ;
2024-02-21 11:26:52 -05:00
else if ( ! embryonic )
2024-05-06 08:13:11 -04:00
size = sess_build_logline_orig ( sess , NULL , logline ,
global . max_syslog_len , & sess - > fe - > logformat ,
orig ) ;
2024-02-21 11:26:52 -05:00
else { /* no logformat_error and embryonic==1 */
struct buffer buf ;
buf = b_make ( logline , global . max_syslog_len , 0 , 0 ) ;
session_embryonic_build_legacy_err ( sess , & buf ) ;
size = buf . data ;
}
2018-09-05 13:51:10 -04:00
if ( size > 0 ) {
2024-02-22 05:29:20 -05:00
struct process_send_log_ctx ctx ;
2021-04-06 07:53:36 -04:00
_HA_ATOMIC_INC ( & sess - > fe - > log_count ) ;
2024-05-06 08:13:11 -04:00
ctx . origin = orig ;
2024-02-22 05:29:20 -05:00
ctx . sess = sess ;
ctx . stream = NULL ;
__send_log ( & ctx , & sess - > fe - > loggers ,
& sess - > fe - > log_tag , level ,
2019-08-11 13:40:12 -04:00
logline , size + 1 , logline_rfc5424 , sd_size ) ;
2018-09-05 13:51:10 -04:00
}
}
MEDIUM: tree-wide: logsrv struct becomes logger
When 'log' directive was implemented, the internal representation was
named 'struct logsrv', because the 'log' directive would directly point
to the log target, which used to be a (UDP) log server exclusively at
that time, hence the name.
But things have become more complex, since today 'log' directive can point
to ring targets (implicit, or named) for example.
Indeed, a 'log' directive does no longer reference the "final" server to
which the log will be sent, but instead it describes which log API and
parameters to use for transporting the log messages to the proper log
destination.
So now the term 'logsrv' is rather confusing and prevents us from
introducing a new level of abstraction because they would be mixed
with logsrv.
So in order to better designate this 'log' directive, and make it more
generic, we chose the word 'logger' which now replaces logsrv everywhere
it was used in the code (including related comments).
This is internal rewording, so no functional change should be expected
on user-side.
2023-09-11 09:06:53 -04:00
void app_log ( struct list * loggers , struct buffer * tag , int level , const char * format , . . . )
2019-08-11 13:40:12 -04:00
{
va_list argp ;
int data_len ;
if ( level < 0 | | format = = NULL | | logline = = NULL )
return ;
va_start ( argp , format ) ;
data_len = vsnprintf ( logline , global . max_syslog_len , format , argp ) ;
if ( data_len < 0 | | data_len > global . max_syslog_len )
data_len = global . max_syslog_len ;
va_end ( argp ) ;
2024-02-22 05:29:20 -05:00
__send_log ( NULL , loggers , tag , level , logline , data_len , default_rfc5424_sd_log_format , 2 ) ;
2019-08-11 13:40:12 -04:00
}
2020-07-07 03:43:24 -04:00
/*
* This function parse a received log message < buf > , of size < buflen >
* it fills < level > , < facility > and < metadata > depending of the detected
* header format and message will point on remaining payload of < size >
*
* < metadata > must point on a preallocated array of LOG_META_FIELDS * sizeof ( struct ist )
* struct ist len will be set to 0 if field is not found
* < level > and < facility > will be set to - 1 if not found .
*/
void parse_log_message ( char * buf , size_t buflen , int * level , int * facility ,
struct ist * metadata , char * * message , size_t * size )
{
char * p ;
int fac_level = 0 ;
* level = * facility = - 1 ;
* message = buf ;
* size = buflen ;
memset ( metadata , 0 , LOG_META_FIELDS * sizeof ( struct ist ) ) ;
p = buf ;
if ( * size < 2 | | * p ! = ' < ' )
return ;
p + + ;
while ( * p ! = ' > ' ) {
if ( * p > ' 9 ' | | * p < ' 0 ' )
return ;
fac_level = 10 * fac_level + ( * p - ' 0 ' ) ;
p + + ;
if ( ( p - buf ) > buflen )
return ;
}
* facility = fac_level > > 3 ;
* level = fac_level & 0x7 ;
p + + ;
metadata [ LOG_META_PRIO ] = ist2 ( buf , p - buf ) ;
buflen - = p - buf ;
buf = p ;
* size = buflen ;
* message = buf ;
/* for rfc5424, prio is always followed by '1' and ' ' */
if ( ( * size > 2 ) & & ( p [ 0 ] = = ' 1 ' ) & & ( p [ 1 ] = = ' ' ) ) {
/* format is always '1 TIMESTAMP HOSTNAME TAG PID MSGID STDATA '
* followed by message .
* Each header field can present NILVALUE : ' - '
*/
p + = 2 ;
2022-11-22 05:17:11 -05:00
* size - = 2 ;
2020-07-07 03:43:24 -04:00
/* timestamp is NILVALUE '-' */
if ( * size > 2 & & ( p [ 0 ] = = ' - ' ) & & p [ 1 ] = = ' ' ) {
metadata [ LOG_META_TIME ] = ist2 ( p , 1 ) ;
p + + ;
}
else if ( * size > LOG_ISOTIME_MINLEN ) {
metadata [ LOG_META_TIME ] . ptr = p ;
2020-07-22 15:32:55 -04:00
/* check if optional secfrac is present
2020-07-07 03:43:24 -04:00
* in timestamp .
* possible format are :
* ex : ' 1970 - 01 - 01 T00 : 00 : 00.000000 Z '
* ' 1970 - 01 - 01 T00 : 00 : 00.000000 + 00 : 00 '
* ' 1970 - 01 - 01 T00 : 00 : 00.000000 - 00 : 00 '
* ' 1970 - 01 - 01 T00 : 00 : 00 Z '
* ' 1970 - 01 - 01 T00 : 00 : 00 + 00 : 00 '
* ' 1970 - 01 - 01 T00 : 00 : 00 - 00 : 00 '
*/
p + = 19 ;
if ( * p = = ' . ' ) {
p + + ;
if ( ( p - buf ) > = buflen )
goto bad_format ;
while ( * p ! = ' Z ' & & * p ! = ' + ' & & * p ! = ' - ' ) {
if ( ( unsigned char ) ( * p - ' 0 ' ) > 9 )
goto bad_format ;
p + + ;
if ( ( p - buf ) > = buflen )
goto bad_format ;
}
}
if ( * p = = ' Z ' )
p + + ;
else
p + = 6 ; /* case of '+00:00 or '-00:00' */
if ( ( p - buf ) > = buflen | | * p ! = ' ' )
goto bad_format ;
metadata [ LOG_META_TIME ] . len = p - metadata [ LOG_META_TIME ] . ptr ;
}
else
goto bad_format ;
p + + ;
if ( ( p - buf ) > = buflen | | * p = = ' ' )
goto bad_format ;
metadata [ LOG_META_HOST ] . ptr = p ;
while ( * p ! = ' ' ) {
p + + ;
if ( ( p - buf ) > = buflen )
goto bad_format ;
}
metadata [ LOG_META_HOST ] . len = p - metadata [ LOG_META_HOST ] . ptr ;
if ( metadata [ LOG_META_HOST ] . len = = 1 & & metadata [ LOG_META_HOST ] . ptr [ 0 ] = = ' - ' )
metadata [ LOG_META_HOST ] . len = 0 ;
p + + ;
if ( ( p - buf ) > = buflen | | * p = = ' ' )
goto bad_format ;
metadata [ LOG_META_TAG ] . ptr = p ;
while ( * p ! = ' ' ) {
p + + ;
if ( ( p - buf ) > = buflen )
goto bad_format ;
}
metadata [ LOG_META_TAG ] . len = p - metadata [ LOG_META_TAG ] . ptr ;
if ( metadata [ LOG_META_TAG ] . len = = 1 & & metadata [ LOG_META_TAG ] . ptr [ 0 ] = = ' - ' )
metadata [ LOG_META_TAG ] . len = 0 ;
p + + ;
if ( ( p - buf ) > = buflen | | * p = = ' ' )
goto bad_format ;
metadata [ LOG_META_PID ] . ptr = p ;
while ( * p ! = ' ' ) {
p + + ;
if ( ( p - buf ) > = buflen )
goto bad_format ;
}
metadata [ LOG_META_PID ] . len = p - metadata [ LOG_META_PID ] . ptr ;
if ( metadata [ LOG_META_PID ] . len = = 1 & & metadata [ LOG_META_PID ] . ptr [ 0 ] = = ' - ' )
metadata [ LOG_META_PID ] . len = 0 ;
p + + ;
if ( ( p - buf ) > = buflen | | * p = = ' ' )
goto bad_format ;
metadata [ LOG_META_MSGID ] . ptr = p ;
while ( * p ! = ' ' ) {
p + + ;
if ( ( p - buf ) > = buflen )
goto bad_format ;
}
metadata [ LOG_META_MSGID ] . len = p - metadata [ LOG_META_MSGID ] . ptr ;
if ( metadata [ LOG_META_MSGID ] . len = = 1 & & metadata [ LOG_META_MSGID ] . ptr [ 0 ] = = ' - ' )
metadata [ LOG_META_MSGID ] . len = 0 ;
p + + ;
if ( ( p - buf ) > = buflen | | * p = = ' ' )
goto bad_format ;
/* structured data format is:
* ex :
* ' [ key1 = value1 key2 = value2 ] [ key3 = value3 ] '
*
* space is invalid outside [ ] because
* considered as the end of structured data field
*/
metadata [ LOG_META_STDATA ] . ptr = p ;
if ( * p = = ' [ ' ) {
int elem = 0 ;
while ( 1 ) {
if ( elem ) {
/* according to rfc this char is escaped in param values */
if ( * p = = ' ] ' & & * ( p - 1 ) ! = ' \\ ' )
elem = 0 ;
}
else {
if ( * p = = ' [ ' )
elem = 1 ;
else if ( * p = = ' ' )
break ;
else
goto bad_format ;
}
p + + ;
if ( ( p - buf ) > = buflen )
goto bad_format ;
}
}
else if ( * p = = ' - ' ) {
/* case of NILVALUE */
p + + ;
if ( ( p - buf ) > = buflen | | * p ! = ' ' )
goto bad_format ;
}
else
goto bad_format ;
metadata [ LOG_META_STDATA ] . len = p - metadata [ LOG_META_STDATA ] . ptr ;
if ( metadata [ LOG_META_STDATA ] . len = = 1 & & metadata [ LOG_META_STDATA ] . ptr [ 0 ] = = ' - ' )
metadata [ LOG_META_STDATA ] . len = 0 ;
p + + ;
buflen - = p - buf ;
buf = p ;
* size = buflen ;
* message = p ;
}
else if ( * size > LOG_LEGACYTIME_LEN ) {
int m ;
/* supported header format according to rfc3164.
* ex :
* ' Jan 1 00 : 00 : 00 HOSTNAME TAG [ PID ] : '
* or ' Jan 1 00 : 00 : 00 HOSTNAME TAG : '
* or ' Jan 1 00 : 00 : 00 HOSTNAME '
* Note : HOSTNAME is mandatory , and day
* of month uses a single space prefix if
* less than 10 to ensure hour offset is
* always the same .
*/
/* Check month to see if it correspond to a rfc3164
* header ex ' Jan 1 00 : 00 : 00 ' */
for ( m = 0 ; m < 12 ; m + + )
if ( ! memcmp ( monthname [ m ] , p , 3 ) )
break ;
/* Month not found */
if ( m = = 12 )
goto bad_format ;
metadata [ LOG_META_TIME ] = ist2 ( p , LOG_LEGACYTIME_LEN ) ;
p + = LOG_LEGACYTIME_LEN ;
if ( ( p - buf ) > = buflen | | * p ! = ' ' )
goto bad_format ;
p + + ;
if ( ( p - buf ) > = buflen | | * p = = ' ' )
goto bad_format ;
metadata [ LOG_META_HOST ] . ptr = p ;
while ( * p ! = ' ' ) {
p + + ;
if ( ( p - buf ) > = buflen )
goto bad_format ;
}
metadata [ LOG_META_HOST ] . len = p - metadata [ LOG_META_HOST ] . ptr ;
/* TAG seems to no be mandatory */
p + + ;
buflen - = p - buf ;
buf = p ;
* size = buflen ;
* message = buf ;
if ( ! buflen )
return ;
while ( ( ( p - buf ) < buflen ) & & * p ! = ' ' & & * p ! = ' : ' )
p + + ;
/* a tag must present a trailing ':' */
if ( ( ( p - buf ) > = buflen ) | | * p ! = ' : ' )
return ;
p + + ;
/* followed by a space */
if ( ( ( p - buf ) > = buflen ) | | * p ! = ' ' )
return ;
/* rewind to parse tag and pid */
p = buf ;
metadata [ LOG_META_TAG ] . ptr = p ;
/* we have the guarantee that ':' will be reach before size limit */
while ( * p ! = ' : ' ) {
if ( * p = = ' [ ' ) {
metadata [ LOG_META_TAG ] . len = p - metadata [ LOG_META_TAG ] . ptr ;
metadata [ LOG_META_PID ] . ptr = p + 1 ;
}
2021-03-02 12:57:28 -05:00
else if ( * p = = ' ] ' & & isttest ( metadata [ LOG_META_PID ] ) ) {
2020-07-07 03:43:24 -04:00
if ( p [ 1 ] ! = ' : ' )
return ;
metadata [ LOG_META_PID ] . len = p - metadata [ LOG_META_PID ] . ptr ;
}
p + + ;
}
if ( ! metadata [ LOG_META_TAG ] . len )
metadata [ LOG_META_TAG ] . len = p - metadata [ LOG_META_TAG ] . ptr ;
2020-07-22 15:32:55 -04:00
/* let pass ':' and ' ', we still have warranty size is large enough */
2020-07-07 03:43:24 -04:00
p + = 2 ;
buflen - = p - buf ;
buf = p ;
* size = buflen ;
* message = buf ;
}
return ;
bad_format :
/* bad syslog format, we reset all parsed syslog fields
* but priority is kept because we are able to re - build
* this message using LOF_FORMAT_PRIO .
*/
metadata [ LOG_META_TIME ] . len = 0 ;
metadata [ LOG_META_HOST ] . len = 0 ;
metadata [ LOG_META_TAG ] . len = 0 ;
metadata [ LOG_META_PID ] . len = 0 ;
metadata [ LOG_META_MSGID ] . len = 0 ;
metadata [ LOG_META_STDATA ] . len = 0 ;
return ;
}
/*
* UDP syslog fd handler
*/
void syslog_fd_handler ( int fd )
{
static THREAD_LOCAL struct ist metadata [ LOG_META_FIELDS ] ;
ssize_t ret = 0 ;
struct buffer * buf = get_trash_chunk ( ) ;
size_t size ;
char * message ;
int level ;
int facility ;
struct listener * l = objt_listener ( fdtab [ fd ] . owner ) ;
int max_accept ;
2021-09-15 07:58:49 -04:00
BUG_ON ( ! l ) ;
2020-07-07 03:43:24 -04:00
2021-04-06 11:23:40 -04:00
if ( fdtab [ fd ] . state & FD_POLL_IN ) {
2020-07-07 03:43:24 -04:00
if ( ! fd_recv_ready ( fd ) )
return ;
2023-01-12 12:52:23 -05:00
max_accept = l - > bind_conf - > maxaccept ? l - > bind_conf - > maxaccept : 1 ;
2020-07-07 03:43:24 -04:00
do {
/* Source address */
struct sockaddr_storage saddr = { 0 } ;
socklen_t saddrlen ;
saddrlen = sizeof ( saddr ) ;
ret = recvfrom ( fd , buf - > area , buf - > size , 0 , ( struct sockaddr * ) & saddr , & saddrlen ) ;
if ( ret < 0 ) {
if ( errno = = EINTR )
continue ;
2022-04-25 14:32:15 -04:00
if ( errno = = EAGAIN | | errno = = EWOULDBLOCK )
2020-07-07 03:43:24 -04:00
fd_cant_recv ( fd ) ;
goto out ;
}
buf - > data = ret ;
2020-07-09 17:23:34 -04:00
/* update counters */
2021-04-06 07:53:36 -04:00
_HA_ATOMIC_INC ( & cum_log_messages ) ;
2023-01-18 05:52:21 -05:00
proxy_inc_fe_req_ctr ( l , l - > bind_conf - > frontend , 0 ) ;
2020-07-09 17:23:34 -04:00
2020-07-07 03:43:24 -04:00
parse_log_message ( buf - > area , buf - > data , & level , & facility , metadata , & message , & size ) ;
2024-02-22 05:29:20 -05:00
process_send_log ( NULL , & l - > bind_conf - > frontend - > loggers , level , facility , metadata , message , size ) ;
2020-07-07 03:43:24 -04:00
} while ( - - max_accept ) ;
}
out :
return ;
}
2019-08-11 13:40:12 -04:00
2020-10-05 08:39:35 -04:00
/*
* IO Handler to handle message exchange with a syslog tcp client
*/
static void syslog_io_handler ( struct appctx * appctx )
{
static THREAD_LOCAL struct ist metadata [ LOG_META_FIELDS ] ;
2022-05-27 05:08:15 -04:00
struct stconn * sc = appctx_sc ( appctx ) ;
2022-05-27 04:36:36 -04:00
struct stream * s = __sc_strm ( sc ) ;
2020-10-05 08:39:35 -04:00
struct proxy * frontend = strm_fe ( s ) ;
struct listener * l = strm_li ( s ) ;
struct buffer * buf = get_trash_chunk ( ) ;
int max_accept ;
int to_skip ;
int facility ;
int level ;
char * message ;
size_t size ;
2024-02-14 01:56:50 -05:00
if ( unlikely ( se_fl_test ( appctx - > sedesc , ( SE_FL_EOS | SE_FL_ERROR ) ) ) ) {
2023-04-11 01:56:50 -04:00
co_skip ( sc_oc ( sc ) , co_data ( sc_oc ( sc ) ) ) ;
2023-03-31 05:17:13 -04:00
goto out ;
2023-04-11 01:56:50 -04:00
}
2023-03-31 05:17:13 -04:00
2023-01-12 12:52:23 -05:00
max_accept = l - > bind_conf - > maxaccept ? l - > bind_conf - > maxaccept : 1 ;
2023-04-17 10:34:29 -04:00
while ( 1 ) {
2020-10-05 08:39:35 -04:00
char c ;
if ( max_accept < = 0 )
goto missing_budget ;
max_accept - - ;
2022-05-27 04:36:36 -04:00
to_skip = co_getchar ( sc_oc ( sc ) , & c ) ;
2020-10-05 08:39:35 -04:00
if ( ! to_skip )
goto missing_data ;
else if ( to_skip < 0 )
goto cli_abort ;
if ( c = = ' < ' ) {
/* rfc-6587, Non-Transparent-Framing: messages separated by
* a trailing LF or CR LF
*/
2022-05-27 04:36:36 -04:00
to_skip = co_getline ( sc_oc ( sc ) , buf - > area , buf - > size ) ;
2020-10-05 08:39:35 -04:00
if ( ! to_skip )
goto missing_data ;
else if ( to_skip < 0 )
goto cli_abort ;
if ( buf - > area [ to_skip - 1 ] ! = ' \n ' )
goto parse_error ;
buf - > data = to_skip - 1 ;
/* according to rfc-6587, some devices adds CR before LF */
if ( buf - > data & & buf - > area [ buf - > data - 1 ] = = ' \r ' )
buf - > data - - ;
}
else if ( ( unsigned char ) ( c - ' 1 ' ) < = 8 ) {
/* rfc-6587, Octet-Counting: message length in ASCII
* ( first digit can not be ZERO ) , followed by a space
* and message length
*/
char * p = NULL ;
int msglen ;
2022-05-27 04:36:36 -04:00
to_skip = co_getword ( sc_oc ( sc ) , buf - > area , buf - > size , ' ' ) ;
2020-10-05 08:39:35 -04:00
if ( ! to_skip )
goto missing_data ;
else if ( to_skip < 0 )
goto cli_abort ;
if ( buf - > area [ to_skip - 1 ] ! = ' ' )
goto parse_error ;
2022-10-26 17:40:08 -04:00
msglen = strtol ( buf - > area , & p , 10 ) ;
2020-10-05 08:39:35 -04:00
if ( ! msglen | | p ! = & buf - > area [ to_skip - 1 ] )
goto parse_error ;
/* message seems too large */
if ( msglen > buf - > size )
goto parse_error ;
2022-05-27 04:36:36 -04:00
msglen = co_getblk ( sc_oc ( sc ) , buf - > area , msglen , to_skip ) ;
2020-10-05 08:39:35 -04:00
if ( ! msglen )
goto missing_data ;
else if ( msglen < 0 )
goto cli_abort ;
buf - > data = msglen ;
to_skip + = msglen ;
}
else
goto parse_error ;
2022-05-27 04:36:36 -04:00
co_skip ( sc_oc ( sc ) , to_skip ) ;
2020-10-05 08:39:35 -04:00
/* update counters */
2021-04-06 07:53:36 -04:00
_HA_ATOMIC_INC ( & cum_log_messages ) ;
2023-01-18 05:52:21 -05:00
proxy_inc_fe_req_ctr ( l , frontend , 0 ) ;
2020-10-05 08:39:35 -04:00
parse_log_message ( buf - > area , buf - > data , & level , & facility , metadata , & message , & size ) ;
2024-02-22 05:29:20 -05:00
process_send_log ( NULL , & frontend - > loggers , level , facility , metadata , message , size ) ;
2020-10-05 08:39:35 -04:00
}
missing_data :
/* we need more data to read */
2023-03-16 09:27:29 -04:00
applet_need_more_data ( appctx ) ;
2020-10-05 08:39:35 -04:00
return ;
missing_budget :
/* it may remain some stuff to do, let's retry later */
appctx_wakeup ( appctx ) ;
return ;
parse_error :
if ( l - > counters )
2021-04-06 07:53:36 -04:00
_HA_ATOMIC_INC ( & l - > counters - > failed_req ) ;
_HA_ATOMIC_INC ( & frontend - > fe_counters . failed_req ) ;
2020-10-05 08:39:35 -04:00
2023-03-31 05:17:13 -04:00
goto error ;
2020-10-05 08:39:35 -04:00
cli_abort :
if ( l - > counters )
2021-04-06 07:53:36 -04:00
_HA_ATOMIC_INC ( & l - > counters - > cli_aborts ) ;
_HA_ATOMIC_INC ( & frontend - > fe_counters . cli_aborts ) ;
2020-10-05 08:39:35 -04:00
2023-03-31 05:17:13 -04:00
error :
se_fl_set ( appctx - > sedesc , SE_FL_ERROR ) ;
out :
2020-10-05 08:39:35 -04:00
return ;
}
static struct applet syslog_applet = {
. obj_type = OBJ_TYPE_APPLET ,
. name = " <SYSLOG> " , /* used for logging */
. fct = syslog_io_handler ,
. release = NULL ,
} ;
2024-02-27 10:17:42 -05:00
/* Atomically append an event to applet >ctx>'s output, prepending it with its
2024-02-27 01:58:26 -05:00
* size in decimal followed by a space . The line is read from vectors < v1 > and
* < v2 > at offset < ofs > relative to the area ' s origin , for < len > bytes . It
* returns the number of bytes consumed from the input vectors on success , - 1
* if it temporarily cannot ( buffer full ) , - 2 if it will never be able to ( too
* large msg ) . The input vectors are not modified . The caller is responsible for
* making sure that there are at least ofs + len bytes in the input buffer .
2024-02-27 10:17:42 -05:00
*/
2024-02-27 01:58:26 -05:00
ssize_t syslog_applet_append_event ( void * ctx , struct ist v1 , struct ist v2 , size_t ofs , size_t len )
2024-02-27 10:17:42 -05:00
{
struct appctx * appctx = ctx ;
char * p ;
/* first, encode the message's size */
chunk_reset ( & trash ) ;
p = ulltoa ( len , trash . area , b_size ( & trash ) ) ;
if ( p ) {
trash . data = p - trash . area ;
trash . area [ trash . data + + ] = ' ' ;
}
/* check if the message has a chance to fit */
if ( unlikely ( ! p | | trash . data + len > b_size ( & trash ) ) )
return - 2 ;
/* try to transfer it or report full */
2024-05-07 10:46:35 -04:00
trash . data + = vp_peek_ofs ( v1 , v2 , ofs , trash . area + trash . data , len ) ;
2024-02-27 10:17:42 -05:00
if ( applet_putchk ( appctx , & trash ) = = - 1 )
return - 1 ;
/* OK done */
return len ;
}
2020-07-07 08:19:42 -04:00
/*
* Parse " log-forward " section and create corresponding sink buffer .
*
* The function returns 0 in success case , otherwise , it returns error
* flags .
*/
int cfg_parse_log_forward ( const char * file , int linenum , char * * args , int kwm )
{
2023-07-03 12:33:18 -04:00
int err_code = ERR_NONE ;
2020-07-07 08:19:42 -04:00
struct proxy * px ;
char * errmsg = NULL ;
const char * err = NULL ;
if ( strcmp ( args [ 0 ] , " log-forward " ) = = 0 ) {
if ( ! * args [ 1 ] ) {
2023-07-03 11:35:54 -04:00
ha_alert ( " parsing [%s:%d] : missing name for log-forward section. \n " , file , linenum ) ;
2020-07-07 08:19:42 -04:00
err_code | = ERR_ALERT | ERR_ABORT ;
goto out ;
}
if ( alertif_too_many_args ( 1 , file , linenum , args , & err_code ) )
goto out ;
err = invalid_char ( args [ 1 ] ) ;
if ( err ) {
ha_alert ( " parsing [%s:%d] : character '%c' is not permitted in '%s' name '%s'. \n " ,
file , linenum , * err , args [ 0 ] , args [ 1 ] ) ;
err_code | = ERR_ALERT | ERR_ABORT ;
goto out ;
}
2020-10-07 11:05:59 -04:00
px = log_forward_by_name ( args [ 1 ] ) ;
if ( px ) {
ha_alert ( " Parsing [%s:%d]: log-forward section '%s' has the same name as another log-forward section declared at %s:%d. \n " ,
file , linenum , args [ 1 ] , px - > conf . file , px - > conf . line ) ;
err_code | = ERR_ALERT | ERR_FATAL ;
2023-07-03 12:33:18 -04:00
goto out ;
2020-10-07 11:05:59 -04:00
}
px = proxy_find_by_name ( args [ 1 ] , 0 , 0 ) ;
if ( px ) {
ha_alert ( " Parsing [%s:%d]: log forward section '%s' has the same name as %s '%s' declared at %s:%d. \n " ,
file , linenum , args [ 1 ] , proxy_type_str ( px ) ,
px - > id , px - > conf . file , px - > conf . line ) ;
err_code | = ERR_ALERT | ERR_FATAL ;
2023-07-03 12:33:18 -04:00
goto out ;
2020-07-07 08:19:42 -04:00
}
px = calloc ( 1 , sizeof * px ) ;
if ( ! px ) {
err_code | = ERR_ALERT | ERR_FATAL ;
goto out ;
}
2021-12-01 06:08:42 -05:00
init_new_proxy ( px ) ;
2020-07-07 08:19:42 -04:00
px - > next = cfg_log_forward ;
cfg_log_forward = px ;
px - > conf . file = strdup ( file ) ;
px - > conf . line = linenum ;
px - > mode = PR_MODE_SYSLOG ;
2024-04-30 06:04:57 -04:00
px - > fe_counters . last_change = ns_to_sec ( now_ns ) ;
2020-10-05 08:39:35 -04:00
px - > cap = PR_CAP_FE ;
px - > maxconn = 10 ;
px - > timeout . client = TICK_ETERNITY ;
px - > accept = frontend_accept ;
px - > default_target = & syslog_applet . obj_type ;
2020-07-07 08:19:42 -04:00
px - > id = strdup ( args [ 1 ] ) ;
}
CLEANUP: Compare the return value of `XXXcmp()` functions with zero
According to coding-style.txt it is recommended to use:
`strcmp(a, b) == 0` instead of `!strcmp(a, b)`
So let's do this.
The change was performed by running the following (very long) coccinelle patch
on src/:
@@
statement S;
expression E;
expression F;
@@
if (
(
dns_hostname_cmp
|
eb_memcmp
|
memcmp
|
strcasecmp
|
strcmp
|
strncasecmp
|
strncmp
)
- (E, F)
+ (E, F) != 0
)
(
S
|
{ ... }
)
@@
statement S;
expression E;
expression F;
@@
if (
- !
(
dns_hostname_cmp
|
eb_memcmp
|
memcmp
|
strcasecmp
|
strcmp
|
strncasecmp
|
strncmp
)
- (E, F)
+ (E, F) == 0
)
(
S
|
{ ... }
)
@@
expression E;
expression F;
expression G;
@@
(
G &&
(
dns_hostname_cmp
|
eb_memcmp
|
memcmp
|
strcasecmp
|
strcmp
|
strncasecmp
|
strncmp
)
- (E, F)
+ (E, F) != 0
)
@@
expression E;
expression F;
expression G;
@@
(
G ||
(
dns_hostname_cmp
|
eb_memcmp
|
memcmp
|
strcasecmp
|
strcmp
|
strncasecmp
|
strncmp
)
- (E, F)
+ (E, F) != 0
)
@@
expression E;
expression F;
expression G;
@@
(
(
dns_hostname_cmp
|
eb_memcmp
|
memcmp
|
strcasecmp
|
strcmp
|
strncasecmp
|
strncmp
)
- (E, F)
+ (E, F) != 0
&& G
)
@@
expression E;
expression F;
expression G;
@@
(
(
dns_hostname_cmp
|
eb_memcmp
|
memcmp
|
strcasecmp
|
strcmp
|
strncasecmp
|
strncmp
)
- (E, F)
+ (E, F) != 0
|| G
)
@@
expression E;
expression F;
expression G;
@@
(
G &&
- !
(
dns_hostname_cmp
|
eb_memcmp
|
memcmp
|
strcasecmp
|
strcmp
|
strncasecmp
|
strncmp
)
- (E, F)
+ (E, F) == 0
)
@@
expression E;
expression F;
expression G;
@@
(
G ||
- !
(
dns_hostname_cmp
|
eb_memcmp
|
memcmp
|
strcasecmp
|
strcmp
|
strncasecmp
|
strncmp
)
- (E, F)
+ (E, F) == 0
)
@@
expression E;
expression F;
expression G;
@@
(
- !
(
dns_hostname_cmp
|
eb_memcmp
|
memcmp
|
strcasecmp
|
strcmp
|
strncasecmp
|
strncmp
)
- (E, F)
+ (E, F) == 0
&& G
)
@@
expression E;
expression F;
expression G;
@@
(
- !
(
dns_hostname_cmp
|
eb_memcmp
|
memcmp
|
strcasecmp
|
strcmp
|
strncasecmp
|
strncmp
)
- (E, F)
+ (E, F) == 0
|| G
)
@@
expression E;
expression F;
expression G;
@@
(
- !
(
dns_hostname_cmp
|
eb_memcmp
|
memcmp
|
strcasecmp
|
strcmp
|
strncasecmp
|
strncmp
)
- (E, F)
+ (E, F) == 0
)
2021-01-02 16:31:53 -05:00
else if ( strcmp ( args [ 0 ] , " maxconn " ) = = 0 ) { /* maxconn */
2020-10-05 08:39:35 -04:00
if ( warnifnotcap ( cfg_log_forward , PR_CAP_FE , file , linenum , args [ 0 ] , " Maybe you want 'fullconn' instead ? " ) )
err_code | = ERR_WARN ;
if ( * ( args [ 1 ] ) = = 0 ) {
ha_alert ( " parsing [%s:%d] : '%s' expects an integer argument. \n " , file , linenum , args [ 0 ] ) ;
err_code | = ERR_ALERT | ERR_FATAL ;
goto out ;
}
cfg_log_forward - > maxconn = atol ( args [ 1 ] ) ;
if ( alertif_too_many_args ( 1 , file , linenum , args , & err_code ) )
goto out ;
}
CLEANUP: Compare the return value of `XXXcmp()` functions with zero
According to coding-style.txt it is recommended to use:
`strcmp(a, b) == 0` instead of `!strcmp(a, b)`
So let's do this.
The change was performed by running the following (very long) coccinelle patch
on src/:
@@
statement S;
expression E;
expression F;
@@
if (
(
dns_hostname_cmp
|
eb_memcmp
|
memcmp
|
strcasecmp
|
strcmp
|
strncasecmp
|
strncmp
)
- (E, F)
+ (E, F) != 0
)
(
S
|
{ ... }
)
@@
statement S;
expression E;
expression F;
@@
if (
- !
(
dns_hostname_cmp
|
eb_memcmp
|
memcmp
|
strcasecmp
|
strcmp
|
strncasecmp
|
strncmp
)
- (E, F)
+ (E, F) == 0
)
(
S
|
{ ... }
)
@@
expression E;
expression F;
expression G;
@@
(
G &&
(
dns_hostname_cmp
|
eb_memcmp
|
memcmp
|
strcasecmp
|
strcmp
|
strncasecmp
|
strncmp
)
- (E, F)
+ (E, F) != 0
)
@@
expression E;
expression F;
expression G;
@@
(
G ||
(
dns_hostname_cmp
|
eb_memcmp
|
memcmp
|
strcasecmp
|
strcmp
|
strncasecmp
|
strncmp
)
- (E, F)
+ (E, F) != 0
)
@@
expression E;
expression F;
expression G;
@@
(
(
dns_hostname_cmp
|
eb_memcmp
|
memcmp
|
strcasecmp
|
strcmp
|
strncasecmp
|
strncmp
)
- (E, F)
+ (E, F) != 0
&& G
)
@@
expression E;
expression F;
expression G;
@@
(
(
dns_hostname_cmp
|
eb_memcmp
|
memcmp
|
strcasecmp
|
strcmp
|
strncasecmp
|
strncmp
)
- (E, F)
+ (E, F) != 0
|| G
)
@@
expression E;
expression F;
expression G;
@@
(
G &&
- !
(
dns_hostname_cmp
|
eb_memcmp
|
memcmp
|
strcasecmp
|
strcmp
|
strncasecmp
|
strncmp
)
- (E, F)
+ (E, F) == 0
)
@@
expression E;
expression F;
expression G;
@@
(
G ||
- !
(
dns_hostname_cmp
|
eb_memcmp
|
memcmp
|
strcasecmp
|
strcmp
|
strncasecmp
|
strncmp
)
- (E, F)
+ (E, F) == 0
)
@@
expression E;
expression F;
expression G;
@@
(
- !
(
dns_hostname_cmp
|
eb_memcmp
|
memcmp
|
strcasecmp
|
strcmp
|
strncasecmp
|
strncmp
)
- (E, F)
+ (E, F) == 0
&& G
)
@@
expression E;
expression F;
expression G;
@@
(
- !
(
dns_hostname_cmp
|
eb_memcmp
|
memcmp
|
strcasecmp
|
strcmp
|
strncasecmp
|
strncmp
)
- (E, F)
+ (E, F) == 0
|| G
)
@@
expression E;
expression F;
expression G;
@@
(
- !
(
dns_hostname_cmp
|
eb_memcmp
|
memcmp
|
strcasecmp
|
strcmp
|
strncasecmp
|
strncmp
)
- (E, F)
+ (E, F) == 0
)
2021-01-02 16:31:53 -05:00
else if ( strcmp ( args [ 0 ] , " backlog " ) = = 0 ) { /* backlog */
2020-10-05 08:39:35 -04:00
if ( warnifnotcap ( cfg_log_forward , PR_CAP_FE , file , linenum , args [ 0 ] , NULL ) )
err_code | = ERR_WARN ;
if ( * ( args [ 1 ] ) = = 0 ) {
ha_alert ( " parsing [%s:%d] : '%s' expects an integer argument. \n " , file , linenum , args [ 0 ] ) ;
err_code | = ERR_ALERT | ERR_FATAL ;
goto out ;
}
cfg_log_forward - > backlog = atol ( args [ 1 ] ) ;
if ( alertif_too_many_args ( 1 , file , linenum , args , & err_code ) )
goto out ;
}
else if ( strcmp ( args [ 0 ] , " bind " ) = = 0 ) {
int cur_arg ;
struct bind_conf * bind_conf ;
struct listener * l ;
2022-08-19 09:16:26 -04:00
int ret ;
2020-10-05 08:39:35 -04:00
cur_arg = 1 ;
bind_conf = bind_conf_alloc ( cfg_log_forward , file , linenum ,
NULL , xprt_get ( XPRT_RAW ) ) ;
if ( ! bind_conf ) {
ha_alert ( " parsing [%s:%d] : out of memory error. " , file , linenum ) ;
err_code | = ERR_ALERT | ERR_FATAL ;
goto out ;
}
2023-01-12 12:52:23 -05:00
bind_conf - > maxaccept = global . tune . maxaccept ? global . tune . maxaccept : MAX_ACCEPT ;
2023-01-12 13:10:17 -05:00
bind_conf - > accept = session_accept_fd ;
2023-01-12 12:52:23 -05:00
2020-10-05 08:39:35 -04:00
if ( ! str2listener ( args [ 1 ] , cfg_log_forward , bind_conf , file , linenum , & errmsg ) ) {
if ( errmsg & & * errmsg ) {
indent_msg ( & errmsg , 2 ) ;
ha_alert ( " parsing [%s:%d] : '%s %s' : %s \n " , file , linenum , args [ 0 ] , args [ 1 ] , errmsg ) ;
}
else {
ha_alert ( " parsing [%s:%d] : '%s %s' : error encountered while parsing listening address %s. \n " ,
file , linenum , args [ 0 ] , args [ 1 ] , args [ 2 ] ) ;
}
2023-07-03 12:33:18 -04:00
err_code | = ERR_ALERT | ERR_FATAL ;
goto out ;
2020-10-05 08:39:35 -04:00
}
list_for_each_entry ( l , & bind_conf - > listeners , by_bind ) {
global . maxsock + + ;
}
cur_arg + + ;
2022-08-19 09:16:26 -04:00
ret = bind_parse_args_list ( bind_conf , args , cur_arg , cursection , file , linenum ) ;
err_code | = ret ;
if ( ret ! = 0 ) {
2020-10-05 08:39:35 -04:00
err_code | = ERR_ALERT | ERR_FATAL ;
goto out ;
}
}
2020-09-16 09:07:22 -04:00
else if ( strcmp ( args [ 0 ] , " dgram-bind " ) = = 0 ) {
2020-07-07 08:19:42 -04:00
int cur_arg ;
struct bind_conf * bind_conf ;
struct bind_kw * kw ;
struct listener * l ;
cur_arg = 1 ;
bind_conf = bind_conf_alloc ( cfg_log_forward , file , linenum ,
NULL , xprt_get ( XPRT_RAW ) ) ;
2021-04-12 10:56:37 -04:00
if ( ! bind_conf ) {
ha_alert ( " parsing [%s:%d] : out of memory error. " , file , linenum ) ;
err_code | = ERR_ALERT | ERR_FATAL ;
goto out ;
}
2020-07-07 08:19:42 -04:00
2023-01-12 12:52:23 -05:00
bind_conf - > maxaccept = global . tune . maxaccept ? global . tune . maxaccept : MAX_ACCEPT ;
2020-09-16 09:22:19 -04:00
if ( ! str2receiver ( args [ 1 ] , cfg_log_forward , bind_conf , file , linenum , & errmsg ) ) {
2020-07-07 08:19:42 -04:00
if ( errmsg & & * errmsg ) {
indent_msg ( & errmsg , 2 ) ;
ha_alert ( " parsing [%s:%d] : '%s %s' : %s \n " , file , linenum , args [ 0 ] , args [ 1 ] , errmsg ) ;
}
else {
ha_alert ( " parsing [%s:%d] : '%s %s' : error encountered while parsing listening address %s. \n " ,
file , linenum , args [ 0 ] , args [ 1 ] , args [ 2 ] ) ;
}
2020-09-16 10:24:14 -04:00
err_code | = ERR_ALERT | ERR_FATAL ;
goto out ;
2020-07-07 08:19:42 -04:00
}
list_for_each_entry ( l , & bind_conf - > listeners , by_bind ) {
2020-09-16 09:22:19 -04:00
/* the fact that the sockets are of type dgram is guaranteed by str2receiver() */
2020-10-15 15:25:32 -04:00
l - > rx . iocb = syslog_fd_handler ;
2020-07-07 08:19:42 -04:00
global . maxsock + + ;
}
cur_arg + + ;
while ( * args [ cur_arg ] & & ( kw = bind_find_kw ( args [ cur_arg ] ) ) ) {
int ret ;
ret = kw - > parse ( args , cur_arg , cfg_log_forward , bind_conf , & errmsg ) ;
err_code | = ret ;
if ( ret ) {
if ( errmsg & & * errmsg ) {
indent_msg ( & errmsg , 2 ) ;
ha_alert ( " parsing [%s:%d] : %s \n " , file , linenum , errmsg ) ;
}
else
ha_alert ( " parsing [%s:%d]: error encountered while processing '%s' \n " ,
file , linenum , args [ cur_arg ] ) ;
if ( ret & ERR_FATAL )
goto out ;
}
cur_arg + = 1 + kw - > skip ;
}
if ( * args [ cur_arg ] ! = 0 ) {
2021-03-12 04:14:07 -05:00
const char * best = bind_find_best_kw ( args [ cur_arg ] ) ;
if ( best )
ha_alert ( " parsing [%s:%d] : unknown keyword '%s' in '%s' section; did you mean '%s' maybe ? \n " ,
file , linenum , args [ cur_arg ] , cursection , best ) ;
else
ha_alert ( " parsing [%s:%d] : unknown keyword '%s' in '%s' section. \n " ,
file , linenum , args [ cur_arg ] , cursection ) ;
2020-07-07 08:19:42 -04:00
err_code | = ERR_ALERT | ERR_FATAL ;
goto out ;
}
}
else if ( strcmp ( args [ 0 ] , " log " ) = = 0 ) {
MEDIUM: tree-wide: logsrv struct becomes logger
When 'log' directive was implemented, the internal representation was
named 'struct logsrv', because the 'log' directive would directly point
to the log target, which used to be a (UDP) log server exclusively at
that time, hence the name.
But things have become more complex, since today 'log' directive can point
to ring targets (implicit, or named) for example.
Indeed, a 'log' directive does no longer reference the "final" server to
which the log will be sent, but instead it describes which log API and
parameters to use for transporting the log messages to the proper log
destination.
So now the term 'logsrv' is rather confusing and prevents us from
introducing a new level of abstraction because they would be mixed
with logsrv.
So in order to better designate this 'log' directive, and make it more
generic, we chose the word 'logger' which now replaces logsrv everywhere
it was used in the code (including related comments).
This is internal rewording, so no functional change should be expected
on user-side.
2023-09-11 09:06:53 -04:00
if ( ! parse_logger ( args , & cfg_log_forward - > loggers , ( kwm = = KWM_NO ) , file , linenum , & errmsg ) ) {
2020-07-07 08:19:42 -04:00
ha_alert ( " parsing [%s:%d] : %s : %s \n " , file , linenum , args [ 0 ] , errmsg ) ;
err_code | = ERR_ALERT | ERR_FATAL ;
goto out ;
}
}
2020-10-05 08:39:35 -04:00
else if ( strcmp ( args [ 0 ] , " timeout " ) = = 0 ) {
const char * res ;
unsigned timeout ;
if ( strcmp ( args [ 1 ] , " client " ) ! = 0 ) {
ha_alert ( " parsing [%s:%d] : unknown keyword '%s %s' in log-forward section. \n " , file , linenum , args [ 0 ] , args [ 1 ] ) ;
err_code | = ERR_ALERT | ERR_FATAL ;
goto out ;
}
if ( * args [ 2 ] = = 0 ) {
ha_alert ( " parsing [%s:%d] : missing timeout client value. \n " , file , linenum ) ;
err_code | = ERR_ALERT | ERR_FATAL ;
goto out ;
}
res = parse_time_err ( args [ 2 ] , & timeout , TIME_UNIT_MS ) ;
if ( res = = PARSE_TIME_OVER ) {
memprintf ( & errmsg , " timer overflow in argument '%s' to 'timeout client' (maximum value is 2147483647 ms or ~24.8 days) " , args [ 2 ] ) ;
}
else if ( res = = PARSE_TIME_UNDER ) {
memprintf ( & errmsg , " timer underflow in argument '%s' to 'timeout client' (minimum non-null value is 1 ms) " , args [ 2 ] ) ;
}
else if ( res ) {
memprintf ( & errmsg , " unexpected character '%c' in 'timeout client' " , * res ) ;
}
if ( res ) {
ha_alert ( " parsing [%s:%d] : %s : %s \n " , file , linenum , args [ 0 ] , errmsg ) ;
err_code | = ERR_ALERT | ERR_FATAL ;
goto out ;
}
cfg_log_forward - > timeout . client = MS_TO_TICKS ( timeout ) ;
}
2020-09-16 09:04:33 -04:00
else {
ha_alert ( " parsing [%s:%d] : unknown keyword '%s' in log-forward section. \n " , file , linenum , args [ 0 ] ) ;
err_code | = ERR_ALERT | ERR_ABORT ;
goto out ;
}
2020-07-07 08:19:42 -04:00
out :
2023-07-04 09:36:45 -04:00
ha_free ( & errmsg ) ;
2020-07-07 08:19:42 -04:00
return err_code ;
}
MEDIUM: tree-wide: logsrv struct becomes logger
When 'log' directive was implemented, the internal representation was
named 'struct logsrv', because the 'log' directive would directly point
to the log target, which used to be a (UDP) log server exclusively at
that time, hence the name.
But things have become more complex, since today 'log' directive can point
to ring targets (implicit, or named) for example.
Indeed, a 'log' directive does no longer reference the "final" server to
which the log will be sent, but instead it describes which log API and
parameters to use for transporting the log messages to the proper log
destination.
So now the term 'logsrv' is rather confusing and prevents us from
introducing a new level of abstraction because they would be mixed
with logsrv.
So in order to better designate this 'log' directive, and make it more
generic, we chose the word 'logger' which now replaces logsrv everywhere
it was used in the code (including related comments).
This is internal rewording, so no functional change should be expected
on user-side.
2023-09-11 09:06:53 -04:00
/* function: post-resolve a single list of loggers
2023-08-17 11:38:30 -04:00
*
* Returns err_code which defaults to ERR_NONE and can be set to a combination
* of ERR_WARN , ERR_ALERT , ERR_FATAL and ERR_ABORT in case of errors .
*/
MEDIUM: tree-wide: logsrv struct becomes logger
When 'log' directive was implemented, the internal representation was
named 'struct logsrv', because the 'log' directive would directly point
to the log target, which used to be a (UDP) log server exclusively at
that time, hence the name.
But things have become more complex, since today 'log' directive can point
to ring targets (implicit, or named) for example.
Indeed, a 'log' directive does no longer reference the "final" server to
which the log will be sent, but instead it describes which log API and
parameters to use for transporting the log messages to the proper log
destination.
So now the term 'logsrv' is rather confusing and prevents us from
introducing a new level of abstraction because they would be mixed
with logsrv.
So in order to better designate this 'log' directive, and make it more
generic, we chose the word 'logger' which now replaces logsrv everywhere
it was used in the code (including related comments).
This is internal rewording, so no functional change should be expected
on user-side.
2023-09-11 09:06:53 -04:00
int postresolve_logger_list ( struct list * loggers , const char * section , const char * section_name )
2023-08-17 11:38:30 -04:00
{
int err_code = ERR_NONE ;
MEDIUM: tree-wide: logsrv struct becomes logger
When 'log' directive was implemented, the internal representation was
named 'struct logsrv', because the 'log' directive would directly point
to the log target, which used to be a (UDP) log server exclusively at
that time, hence the name.
But things have become more complex, since today 'log' directive can point
to ring targets (implicit, or named) for example.
Indeed, a 'log' directive does no longer reference the "final" server to
which the log will be sent, but instead it describes which log API and
parameters to use for transporting the log messages to the proper log
destination.
So now the term 'logsrv' is rather confusing and prevents us from
introducing a new level of abstraction because they would be mixed
with logsrv.
So in order to better designate this 'log' directive, and make it more
generic, we chose the word 'logger' which now replaces logsrv everywhere
it was used in the code (including related comments).
This is internal rewording, so no functional change should be expected
on user-side.
2023-09-11 09:06:53 -04:00
struct logger * logger ;
2023-08-17 11:38:30 -04:00
MEDIUM: tree-wide: logsrv struct becomes logger
When 'log' directive was implemented, the internal representation was
named 'struct logsrv', because the 'log' directive would directly point
to the log target, which used to be a (UDP) log server exclusively at
that time, hence the name.
But things have become more complex, since today 'log' directive can point
to ring targets (implicit, or named) for example.
Indeed, a 'log' directive does no longer reference the "final" server to
which the log will be sent, but instead it describes which log API and
parameters to use for transporting the log messages to the proper log
destination.
So now the term 'logsrv' is rather confusing and prevents us from
introducing a new level of abstraction because they would be mixed
with logsrv.
So in order to better designate this 'log' directive, and make it more
generic, we chose the word 'logger' which now replaces logsrv everywhere
it was used in the code (including related comments).
This is internal rewording, so no functional change should be expected
on user-side.
2023-09-11 09:06:53 -04:00
list_for_each_entry ( logger , loggers , list ) {
2023-08-17 11:38:30 -04:00
int cur_code ;
char * msg = NULL ;
MEDIUM: tree-wide: logsrv struct becomes logger
When 'log' directive was implemented, the internal representation was
named 'struct logsrv', because the 'log' directive would directly point
to the log target, which used to be a (UDP) log server exclusively at
that time, hence the name.
But things have become more complex, since today 'log' directive can point
to ring targets (implicit, or named) for example.
Indeed, a 'log' directive does no longer reference the "final" server to
which the log will be sent, but instead it describes which log API and
parameters to use for transporting the log messages to the proper log
destination.
So now the term 'logsrv' is rather confusing and prevents us from
introducing a new level of abstraction because they would be mixed
with logsrv.
So in order to better designate this 'log' directive, and make it more
generic, we chose the word 'logger' which now replaces logsrv everywhere
it was used in the code (including related comments).
This is internal rewording, so no functional change should be expected
on user-side.
2023-09-11 09:06:53 -04:00
cur_code = resolve_logger ( logger , & msg ) ;
2023-08-17 11:38:30 -04:00
if ( msg ) {
void ( * e_func ) ( const char * fmt , . . . ) = NULL ;
if ( cur_code & ERR_ALERT )
e_func = ha_alert ;
else if ( cur_code & ERR_WARN )
e_func = ha_warning ;
else
e_func = ha_diag_warning ;
if ( ! section )
MEDIUM: tree-wide: logsrv struct becomes logger
When 'log' directive was implemented, the internal representation was
named 'struct logsrv', because the 'log' directive would directly point
to the log target, which used to be a (UDP) log server exclusively at
that time, hence the name.
But things have become more complex, since today 'log' directive can point
to ring targets (implicit, or named) for example.
Indeed, a 'log' directive does no longer reference the "final" server to
which the log will be sent, but instead it describes which log API and
parameters to use for transporting the log messages to the proper log
destination.
So now the term 'logsrv' is rather confusing and prevents us from
introducing a new level of abstraction because they would be mixed
with logsrv.
So in order to better designate this 'log' directive, and make it more
generic, we chose the word 'logger' which now replaces logsrv everywhere
it was used in the code (including related comments).
This is internal rewording, so no functional change should be expected
on user-side.
2023-09-11 09:06:53 -04:00
e_func ( " global log directive declared in file %s at line '%d' %s. \n " ,
logger - > conf . file , logger - > conf . line , msg ) ;
2023-08-17 11:38:30 -04:00
else
MEDIUM: tree-wide: logsrv struct becomes logger
When 'log' directive was implemented, the internal representation was
named 'struct logsrv', because the 'log' directive would directly point
to the log target, which used to be a (UDP) log server exclusively at
that time, hence the name.
But things have become more complex, since today 'log' directive can point
to ring targets (implicit, or named) for example.
Indeed, a 'log' directive does no longer reference the "final" server to
which the log will be sent, but instead it describes which log API and
parameters to use for transporting the log messages to the proper log
destination.
So now the term 'logsrv' is rather confusing and prevents us from
introducing a new level of abstraction because they would be mixed
with logsrv.
So in order to better designate this 'log' directive, and make it more
generic, we chose the word 'logger' which now replaces logsrv everywhere
it was used in the code (including related comments).
This is internal rewording, so no functional change should be expected
on user-side.
2023-09-11 09:06:53 -04:00
e_func ( " log directive declared in %s section '%s' in file '%s' at line %d %s. \n " ,
section , section_name , logger - > conf . file , logger - > conf . line , msg ) ;
2023-08-17 11:38:30 -04:00
ha_free ( & msg ) ;
}
err_code | = cur_code ;
}
return err_code ;
}
/* resolve default log directives at end of config. Returns 0 on success
* otherwise error flags .
*/
MEDIUM: tree-wide: logsrv struct becomes logger
When 'log' directive was implemented, the internal representation was
named 'struct logsrv', because the 'log' directive would directly point
to the log target, which used to be a (UDP) log server exclusively at
that time, hence the name.
But things have become more complex, since today 'log' directive can point
to ring targets (implicit, or named) for example.
Indeed, a 'log' directive does no longer reference the "final" server to
which the log will be sent, but instead it describes which log API and
parameters to use for transporting the log messages to the proper log
destination.
So now the term 'logsrv' is rather confusing and prevents us from
introducing a new level of abstraction because they would be mixed
with logsrv.
So in order to better designate this 'log' directive, and make it more
generic, we chose the word 'logger' which now replaces logsrv everywhere
it was used in the code (including related comments).
This is internal rewording, so no functional change should be expected
on user-side.
2023-09-11 09:06:53 -04:00
static int postresolve_loggers ( )
2023-08-17 11:38:30 -04:00
{
struct proxy * px ;
int err_code = ERR_NONE ;
/* global log directives */
MEDIUM: tree-wide: logsrv struct becomes logger
When 'log' directive was implemented, the internal representation was
named 'struct logsrv', because the 'log' directive would directly point
to the log target, which used to be a (UDP) log server exclusively at
that time, hence the name.
But things have become more complex, since today 'log' directive can point
to ring targets (implicit, or named) for example.
Indeed, a 'log' directive does no longer reference the "final" server to
which the log will be sent, but instead it describes which log API and
parameters to use for transporting the log messages to the proper log
destination.
So now the term 'logsrv' is rather confusing and prevents us from
introducing a new level of abstraction because they would be mixed
with logsrv.
So in order to better designate this 'log' directive, and make it more
generic, we chose the word 'logger' which now replaces logsrv everywhere
it was used in the code (including related comments).
This is internal rewording, so no functional change should be expected
on user-side.
2023-09-11 09:06:53 -04:00
err_code | = postresolve_logger_list ( & global . loggers , NULL , NULL ) ;
2023-08-17 11:38:30 -04:00
/* proxy log directives */
for ( px = proxies_list ; px ; px = px - > next )
MEDIUM: tree-wide: logsrv struct becomes logger
When 'log' directive was implemented, the internal representation was
named 'struct logsrv', because the 'log' directive would directly point
to the log target, which used to be a (UDP) log server exclusively at
that time, hence the name.
But things have become more complex, since today 'log' directive can point
to ring targets (implicit, or named) for example.
Indeed, a 'log' directive does no longer reference the "final" server to
which the log will be sent, but instead it describes which log API and
parameters to use for transporting the log messages to the proper log
destination.
So now the term 'logsrv' is rather confusing and prevents us from
introducing a new level of abstraction because they would be mixed
with logsrv.
So in order to better designate this 'log' directive, and make it more
generic, we chose the word 'logger' which now replaces logsrv everywhere
it was used in the code (including related comments).
This is internal rewording, so no functional change should be expected
on user-side.
2023-09-11 09:06:53 -04:00
err_code | = postresolve_logger_list ( & px - > loggers , " proxy " , px - > id ) ;
2023-08-17 11:38:30 -04:00
/* log-forward log directives */
for ( px = cfg_log_forward ; px ; px = px - > next )
MEDIUM: tree-wide: logsrv struct becomes logger
When 'log' directive was implemented, the internal representation was
named 'struct logsrv', because the 'log' directive would directly point
to the log target, which used to be a (UDP) log server exclusively at
that time, hence the name.
But things have become more complex, since today 'log' directive can point
to ring targets (implicit, or named) for example.
Indeed, a 'log' directive does no longer reference the "final" server to
which the log will be sent, but instead it describes which log API and
parameters to use for transporting the log messages to the proper log
destination.
So now the term 'logsrv' is rather confusing and prevents us from
introducing a new level of abstraction because they would be mixed
with logsrv.
So in order to better designate this 'log' directive, and make it more
generic, we chose the word 'logger' which now replaces logsrv everywhere
it was used in the code (including related comments).
This is internal rewording, so no functional change should be expected
on user-side.
2023-09-11 09:06:53 -04:00
err_code | = postresolve_logger_list ( & px - > loggers , " log-forward " , px - > id ) ;
2023-08-17 11:38:30 -04:00
return err_code ;
}
2020-07-07 08:19:42 -04:00
/* config parsers for this section */
REGISTER_CONFIG_SECTION ( " log-forward " , cfg_parse_log_forward , NULL ) ;
MEDIUM: tree-wide: logsrv struct becomes logger
When 'log' directive was implemented, the internal representation was
named 'struct logsrv', because the 'log' directive would directly point
to the log target, which used to be a (UDP) log server exclusively at
that time, hence the name.
But things have become more complex, since today 'log' directive can point
to ring targets (implicit, or named) for example.
Indeed, a 'log' directive does no longer reference the "final" server to
which the log will be sent, but instead it describes which log API and
parameters to use for transporting the log messages to the proper log
destination.
So now the term 'logsrv' is rather confusing and prevents us from
introducing a new level of abstraction because they would be mixed
with logsrv.
So in order to better designate this 'log' directive, and make it more
generic, we chose the word 'logger' which now replaces logsrv everywhere
it was used in the code (including related comments).
This is internal rewording, so no functional change should be expected
on user-side.
2023-09-11 09:06:53 -04:00
REGISTER_POST_CHECK ( postresolve_loggers ) ;
2023-09-13 05:52:31 -04:00
REGISTER_POST_PROXY_CHECK ( postcheck_log_backend ) ;
MAJOR: log: implement proper postparsing for logformat expressions
This patch tries to address a design flaw with how logformat expressions
are parsed from config. Indeed, some parse_logformat_string() calls are
performed during config parsing when the proxy mode is not yet known.
Here's a config example that illustrates the issue:
defaults
mode tcp
listen test
bind :8888
http-response set-header custom-hdr "%trl" # needs http
mode http
The above config should work, because the effective proxy mode is http,
yet haproxy fails with this error:
[ALERT] (99051) : config : parsing [repro.conf:6] : error detected in proxy 'test' while parsing 'http-response set-header' rule : format tag 'trl' is reserved for HTTP mode.
To fix the issue once and for all, let's implement smart postparsing for
logformat expressions encountered during config parsing:
- split parse_logformat_string() (and subfonctions) in order to create a
new lf_expr_postcheck() function that must be called to finish
preparing and checking the logformat expression once the proxy type is
known.
- save some config hints info during parse_logformat_string() to
generate more precise error messages during lf_expr_postcheck(), if
needed, we rely on curpx->conf.args.{file,line} hints for that because
parse_logformat_string() doesn't know about current file and line
number.
- lf_expr_postcheck() uses PR_FL_CHECKED proxy flag to know if the
function may try to make the proxy compatible with the expression, or
if it should simply fail as soon as an incompatibility is detected.
- if parse_logformat_string() is called from an unchecked proxy, then
schedule the expression for postparsing, else (ie: during runtime),
run the postcheck right away.
This change will also allow for some logformat expression error handling
simplifications in the future.
2024-02-23 11:26:32 -05:00
REGISTER_POST_PROXY_CHECK ( postcheck_logformat_proxy ) ;
2020-07-07 08:19:42 -04:00
2019-05-22 08:42:12 -04:00
REGISTER_PER_THREAD_ALLOC ( init_log_buffers ) ;
REGISTER_PER_THREAD_FREE ( deinit_log_buffers ) ;
2018-11-26 05:21:50 -05:00
2023-07-03 12:07:30 -04:00
REGISTER_POST_DEINIT ( deinit_log_forward ) ;
2006-06-25 20:48:02 -04:00
/*
* Local variables :
* c - indent - level : 8
* c - basic - offset : 8
* End :
*/