CONTRIB: opentracing: add the OpenTracing filter

This commit adds the OpenTracing filter (hereinafter we will use the
abbreviated name 'the OT filter') to the contrib tree.

The OT filter adds native support for using distributed tracing in HAProxy.
This is enabled by sending an OpenTracing compliant request to one of the
supported tracers; such as Datadog, Jaeger, Lightstep and Zipkin tracers.
Please note: tracers are not listed by any preference, but alphabetically.

The OT filter is a standard HAProxy filter, so what applies to others also
applies to this one (of course, by that I mean what is described in the
documentation, more precisely in the doc/internals/filters.txt file).

The OT filter activation is done explicitly by specifying it in the HAProxy
configuration.  If this is not done, the OT filter in no way participates
in the work of HAProxy.

As for the impact on HAProxy speed, this is documented with several tests
located in the test directory, and the result is found in the README-speed-*
files.  In short, the speed of operation depends on the way it is used and
the complexity of the configuration, from an almost immeasurable impact to
a significant deceleration (5x and more).  I think that in some normal use
the speed of HAProxy with the filter on will be quite satisfactory with a
slowdown of less than 4%.

The OT filter allows intensive use of ACLs, which can be defined anywhere in
the configuration.  Thus, it is possible to use the filter only for those
connections that are of interest to us.

More detailed documentation related to the operation, configuration and use
of the filter can be found in the contrib/opentracing directory.

To make the OpenTracing filter easier to configure and compile, several
entries have been added to the Makefile.  When running the make utility,
it is possible to use several new arguments:

  USE_OT=1     : enable the OpenTracing filter
  OT_DEBUG=1   : compile the OpenTracing filter in debug mode
  OT_INC=path  : force the include path to libopentracing-c-wrapper
  OT_LIB=path  : force the lib path to libopentracing-c-wrapper
  OT_RUNPATH=1 : add libopentracing-c-wrapper RUNPATH to haproxy executable

If USE_OT is set, then an additional Makefile from the contrib/opentracing
directory is included in the compilation process.
This commit is contained in:
Miroslav Zagorac 2020-12-09 16:54:31 +01:00 committed by Willy Tarreau
parent 7f8314c8d1
commit 70230c6484
77 changed files with 12136 additions and 1 deletions

View file

@ -53,6 +53,7 @@
# USE_SYSTEMD : enable sd_notify() support.
# USE_OBSOLETE_LINKER : use when the linker fails to emit __start_init/__stop_init
# USE_THREAD_DUMP : use the more advanced thread state dump system. Automatic.
# USE_OT : enable the OpenTracing filter
#
# Options can be forced by specifying "USE_xxx=1" or can be disabled by using
# "USE_xxx=" (empty string). The list of enabled and disabled options for a
@ -102,6 +103,10 @@
# LUA_INC : force the include path to lua
# LUA_LIB_NAME : force the lib name (or automatically evaluated, by order of
# priority : lua5.3, lua53, lua).
# OT_DEBUG : compile the OpenTracing filter in debug mode
# OT_INC : force the include path to libopentracing-c-wrapper
# OT_LIB : force the lib path to libopentracing-c-wrapper
# OT_RUNPATH : add RUNPATH for libopentracing-c-wrapper to haproxy executable
# IGNOREGIT : ignore GIT commit versions if set.
# VERSION : force haproxy version reporting.
# SUBVERS : add a sub-version (eg: platform, model, ...).
@ -296,7 +301,7 @@ use_opts = USE_EPOLL USE_KQUEUE USE_NETFILTER \
USE_GETADDRINFO USE_OPENSSL USE_LUA USE_FUTEX USE_ACCEPT4 \
USE_CLOSEFROM USE_ZLIB USE_SLZ USE_CPU_AFFINITY USE_TFO USE_NS \
USE_DL USE_RT USE_DEVICEATLAS USE_51DEGREES USE_WURFL USE_SYSTEMD \
USE_OBSOLETE_LINKER USE_PRCTL USE_THREAD_DUMP USE_EVPORTS
USE_OBSOLETE_LINKER USE_PRCTL USE_THREAD_DUMP USE_EVPORTS USE_OT
#### Target system options
# Depending on the target platform, some options are set, as well as some
@ -759,6 +764,10 @@ ifneq ($(USE_NS),)
OPTIONS_OBJS += src/namespace.o
endif
ifneq ($(USE_OT),)
include contrib/opentracing/Makefile
endif
#### Global link options
# These options are added at the end of the "ld" command line. Use LDFLAGS to
# add options at the beginning of the "ld" command line if needed.

View file

@ -0,0 +1 @@
Miroslav Zagorac <mzagorac@haproxy.com>

View file

@ -0,0 +1 @@
Miroslav Zagorac <mzagorac@haproxy.com>

View file

@ -0,0 +1,61 @@
# USE_OT : enable the OpenTracing filter
# OT_DEBUG : compile the OpenTracing filter in debug mode
# OT_INC : force the include path to libopentracing-c-wrapper
# OT_LIB : force the lib path to libopentracing-c-wrapper
# OT_RUNPATH : add libopentracing-c-wrapper RUNPATH to haproxy executable
OT_DEFINE =
OT_CFLAGS =
OT_LDFLAGS =
OT_DEBUG_EXT =
OTC_WRAPPER = opentracing-c-wrapper
ifneq ($(OT_DEBUG),)
OT_DEBUG_EXT = _dbg
OT_DEFINE = -DDEBUG_OT
endif
ifeq ($(OT_INC),)
OT_CFLAGS = $(shell pkg-config --silence-errors --cflags $(OTC_WRAPPER)$(OT_DEBUG_EXT))
else
ifneq ($(wildcard $(OT_INC)/$(OTC_WRAPPER)/.*),)
OT_CFLAGS = -I$(OT_INC) $(if $(OT_DEBUG),-DOTC_DBG_MEM)
endif
endif
ifeq ($(OT_CFLAGS),)
$(error OpenTracing C wrapper : can't find headers)
endif
ifeq ($(OT_LIB),)
OT_LDFLAGS = $(shell pkg-config --silence-errors --libs $(OTC_WRAPPER)$(OT_DEBUG_EXT))
else
ifneq ($(wildcard $(OT_LIB)/lib$(OTC_WRAPPER).*),)
OT_LDFLAGS = -L$(OT_LIB) -l$(OTC_WRAPPER)$(OT_DEBUG_EXT)
ifneq ($(OT_RUNPATH),)
OT_LDFLAGS += -Wl,--rpath,$(OT_LIB)
endif
endif
endif
ifeq ($(OT_LDFLAGS),)
$(error OpenTracing C wrapper : can't find library)
endif
OPTIONS_OBJS += \
contrib/opentracing/src/cli.o \
contrib/opentracing/src/conf.o \
contrib/opentracing/src/event.o \
contrib/opentracing/src/filter.o \
contrib/opentracing/src/group.o \
contrib/opentracing/src/http.o \
contrib/opentracing/src/opentracing.o \
contrib/opentracing/src/parser.o \
contrib/opentracing/src/pool.o \
contrib/opentracing/src/scope.o \
contrib/opentracing/src/util.o \
contrib/opentracing/src/vars.o
OPTIONS_CFLAGS += $(OT_CFLAGS) -Icontrib/opentracing/include
OPTIONS_LDFLAGS += $(OT_LDFLAGS)
OPTIONS_CFLAGS += $(OT_DEFINE)

794
contrib/opentracing/README Normal file
View file

@ -0,0 +1,794 @@
-----------------------------------------
The HAProxy OpenTracing filter (OT)
Version 1.0
( Last update: 2020-12-10 )
-----------------------------------------
Author : Miroslav Zagorac
Contact : mzagorac at haproxy dot com
SUMMARY
--------
0. Terms
1. Introduction
2. Build instructions
3. Basic concepts in OpenTracing
4. OT configuration
4.1. OT scope
4.2. "ot-tracer" section
4.3. "ot-scope" section
4.4. "ot-group" section
5. Examples
5.1 Benchmarking results
6. OT CLI
7. Known bugs and limitations
0. Terms
---------
* OT: The HAProxy OpenTracing filter
OT is the HAProxy filter that allows you to send data to distributed
tracing systems via the OpenTracing API.
1. Introduction
----------------
Nowadays there is a growing need to divide a process into microservices and
there is a problem of monitoring the work of the same process. One way to
solve this problem is to use distributed tracing service in a central location,
the so-called tracer.
OT is a feature introduced in HAProxy 2.4. This filter enables communication
via the OpenTracing API with OpenTracing compatible servers (tracers).
Currently, tracers that support this API include Datadog, Jaeger, LightStep
and Zipkin.
The OT filter was primarily tested with the Jaeger tracer, while configurations
for both Datadog and Zipkin tracers were also set in the test directory.
The OT filter is a standard HAProxy filter, so what applies to others also
applies to this one (of course, by that I mean what is described in the
documentation, more precisely in the doc/internals/filters.txt file).
The OT filter activation is done explicitly by specifying it in the HAProxy
configuration. If this is not done, the OT filter in no way participates
in the work of HAProxy.
As for the impact on HAProxy speed, this is documented with several tests
located in the test directory, and the result is found in the README-speed-*
files. In short, the speed of operation depends on the way it is used and
the complexity of the configuration, from an almost immeasurable impact to
a significant deceleration (5x and more). I think that in some normal use
the speed of HAProxy with the filter on will be quite satisfactory with a
slowdown of less than 4% (provided that no more than 10% of requests are
sent to the tracer, which is determined by the keyword 'rate-limit').
The OT filter allows intensive use of ACLs, which can be defined anywhere in
the configuration. Thus, it is possible to use the filter only for those
connections that are of interest to us.
2. Build instructions
----------------------
OT is the HAProxy filter and as such is compiled together with HAProxy.
To communicate with some OpenTracing compatible tracer, the OT filter uses the
OpenTracing C Wrapper library (which again uses the OpenTracing CPP library).
This means that we must have both libraries installed on the system on which
we want to compile or use HAProxy.
Instructions for compiling and installing both required libraries can be
found at https://github.com/haproxytech/opentracing-c-wrapper .
Also, to use the OT filter when running HAProxy we need to have an OpenTracing
plugin for the tracer we want to use. We will return to this later, in
section 5.
The OT filter can be more easily compiled using the pkg-config tool, if we
have the OpenTracing C Wrapper library installed so that it contains pkg-config
files (which have the .pc extension). If the pkg-config tool cannot be used,
then the path to the directory where the include files and libraries are
located can be explicitly specified.
Below are examples of the two ways to compile HAProxy with the OT filter, the
first using the pkg-congfig tool and the second explicitly specifying the path
to the OpenTracing C Wrapper include and library.
Note: prompt '%' indicates that the command is executed under a unprivileged
user, while prompt '#' indicates that the command is executed under the
root user.
Example of compiling HAProxy using the pkg-congfig tool (assuming the
OpenTracing C Wrapper library is installed in the /opt directory):
% PKG_CONFIG_PATH=/opt/lib/pkgconfig make USE_OT=1 TARGET=linux-glibc
The OT filter can also be compiled in debug mode as follows:
% PKG_CONFIG_PATH=/opt/lib/pkgconfig make USE_OT=1 OT_DEBUG=1 TARGET=linux-glibc
HAProxy compilation example explicitly specifying path to the OpenTracing C
Wrapper include and library:
% make USE_OT=1 OT_INC=/opt/include OT_LIB=/opt/lib TARGET=linux-glibc
In case we want to use debug mode, then it looks like this:
% make USE_OT=1 OT_DEBUG=1 OT_INC=/opt/include OT_LIB=/opt/lib TARGET=linux-glibc
If the library we want to use is not installed on a unix system, then a locally
installed library can be used (say, which is compiled and installed in the user
home directory). In this case instead of /opt/include and /opt/lib the
equivalent paths to the local installation should be specified. Of course,
in that case the pkg-config tool can also be used if we have a complete
installation (with .pc files).
last but not least, if the pkg-config tool is not used when compiling, then
HAProxy executable may not be able to find the OpenTracing C Wrapper library
at startup. This can be solved in several ways, for example using the
LD_LIBRARY_PATH environment variable which should be set to the path where the
library is located before starting the HAProxy.
% LD_LIBRARY_PATH=/opt/lib /path-to/haproxy ...
Another way is to add RUNPATH to HAProxy executable that contains the path to
the library in question.
% make USE_OT=1 OT_RUNPATH=1 OT_INC=/opt/include OT_LIB=/opt/lib TARGET=linux-glibc
After HAProxy is compiled, we can check if the OT filter is enabled:
% ./haproxy -vv | grep opentracing
--- command output ----------
[ OT] opentracing
--- command output ----------
3. Basic concepts in OpenTracing
---------------------------------
Basic concepts of OpenTracing can be read on the OpenTracing documentation
website https://opentracing.io/docs/overview/.
Here we will list only the most important elements of distributed tracing and
these are 'trace', 'span' and 'span context'. Trace is a description of the
complete transaction we want to record in the tracing system. A span is an
operation that represents a unit of work that is recorded in a tracing system.
Span context is a group of information related to a particular span that is
passed on to the system (from service to service). Using this context, we can
add new spans to already open trace (or supplement data in already open spans).
An individual span may contain one or more tags, logs and baggage items.
The tag is a key-value element that is valid for the entire span. Log is a
key-value element that allows you to write some data at a certain time, it
can be used for debugging. A baggage item is a key-value data pair that can
be used for the duration of an entire trace, from the moment it is added to
the span.
4. OT configuration
--------------------
In order for the OT filter to be used, it must be included in the HAProxy
configuration, in the proxy section (frontend / listen / backend):
frontend ot-test
...
filter opentracing [id <id>] config <file>
...
If no filter id is specified, 'ot-filter' is used as default. The 'config'
parameter must be specified and it contains the path of the file used to
configure the OT filter.
4.1 OT scope
-------------
If the filter id is defined for the OT filter, then the OT scope with
the same name should be defined in the configuration file. In the same
configuration file we can have several defined OT scopes.
Each OT scope must have a defined (only one) "ot-tracer" section that is
used to configure the operation of the OT filter and define the used groups
and scopes.
OT scope starts with the id of the filter specified in square brackets and
ends with the end of the file or when a new OT scope is defined.
For example, this defines two OT scopes in the same configuration file:
[my-first-ot-filter]
ot-tracer tracer1
...
ot-group group1
...
ot-scope scope1
...
[my-second-ot-filter]
...
4.2. "ot-tracer" section
-------------------------
Only one "ot-tracer" section must be defined for each OT scope.
There are several keywords that must be defined for the OT filter to work.
These are 'config' which defines the configuration file for the OpenTracing
API, and 'plugin' which defines the OpenTracing plugin used.
Through optional keywords can be defined ACLs, logging, rate limit, and groups
and scopes that define the tracing model.
ot-tracer <name>
A new OT with the name <name> is created.
Arguments :
name - the name of the tracer section
The following keywords are supported in this section:
- mandatory keywords:
- config
- plugin
- optional keywords:
- acl
- debug-level
- groups
- [no] log
- [no] option disabled
- [no] option dontlog-normal
- [no] option hard-errors
- rate-limit
- scopes
acl <aclname> <criterion> [flags] [operator] <value> ...
Declare or complete an access list.
To configure and use the ACL, see section 7 of the HAProxy Configuration
Manual.
config <file>
'config' is one of the two mandatory keywords associated with the OT tracer
configuration. This keyword sets the path of the configuration file for the
OpenTracing tracer plugin. To set the contents of this configuration file,
it is best to look at the documentation related to the OpenTracing tracer we
want to use.
Arguments :
file - the path of the configuration file
debug-level <value>
This keyword sets the value of the debug level related to the display of
debug messages in the OT filter. The 'debug-level' value is binary, ie
a single value bit enables or disables the display of the corresponding
debug message that uses that bit. The default value is set via the
FLT_OT_DEBUG_LEVEL macro in the include/config.h file. Debug level value
is used only if the OT filter is compiled with the debug mode enabled,
otherwise it is ignored.
Arguments :
value - binary value ranging from 0 to 255 (8 bits)
groups <name> ...
A list of "ot-group" groups used for the currently defined tracer is declared.
Several groups can be specified in one line.
Arguments :
name - the name of the OT group
log global
log <addr> [len <len>] [format <fmt>] <facility> [<level> [<minlevel>]]
no log
Enable per-instance logging of events and traffic.
To configure and use the logging system, see section 4.2 of the HAProxy
Configuration Manual.
option disabled
no option disabled
Keyword which turns the operation of the OT filter on or off. By default
the filter is on.
option dontlog-normal
no option dontlog-normal
Enable or disable logging of normal, successful processing. By default,
this option is disabled. For this option to be considered, logging must
be turned on.
See also: 'log' keyword description.
option hard-errors
no option hard-errors
During the operation of the filter, some errors may occur, caused by
incorrect configuration of the tracer or some error related to the operation
of HAProxy. By default, such an error will not interrupt the filter
operation for the stream in which the error occurred. If the 'hard-error'
option is enabled, the operation error prohibits all further processing of
events and groups in the stream in which the error occurred.
plugin <file>
'plugin' is one of the two mandatory keywords associated with the OT tracer
configuration. This keyword sets the path of the OpenTracing tracer plugin.
Arguments :
file - the name of the plugin used
rate-limit <value>
This option allows limiting the use of the OT filter, ie it can be influenced
whether the OT filter is activated for a stream or not. Determining whether
or not a filter is activated depends on the value of this option that is
compared to a randomly selected value when attaching the filter to the stream.
By default, the value of this option is set to 100.0, ie the OT filter is
activated for each stream.
Arguments :
value - floating point value ranging from 0.0 to 100.0
scopes <name> ...
This keyword declares a list of "ot-scope" definitions used for the currently
defined tracer. Multiple scopes can be specified in the same line.
Arguments :
name - the name of the OT scope
4.3. "ot-scope" section
------------------------
Stream processing begins with filter attachment, then continues with the
processing of a number of defined events and groups, and ends with filter
detachment. The "ot-scope" section is used to define actions related to
individual events. However, this section may be part of a group, so the
event does not have to be part of the definition.
ot-scope <name>
Creates a new OT scope definition named <name>.
Arguments :
name - the name of the OT scope
The following keywords are supported in this section:
- acl
- baggage
- event
- extract
- finish
- inject
- log
- span
- tag
acl <aclname> <criterion> [flags] [operator] <value> ...
Declare or complete an access list.
To configure and use the ACL, see section 7 of the HAProxy Configuration
Manual.
baggage <name> <sample> ...
Baggage items allow the propagation of data between spans, ie allow the
assignment of metadata that is propagated to future children spans.
This data is formatted in the style of key-value pairs and is part of
the context that can be transferred between processes that are part of
a server architecture.
This kewyord allows setting the baggage for the currently active span. The
data type is always a string, ie any sample type is converted to a string.
The exception is a binary value that is not supported by the OT filter.
See the 'tag' keyword description for the data type conversion table.
Arguments :
name - key part of a data pair
sample - sample expression (value part of a data pair), at least one
sample must be present
event <name> [{ if | unless } <condition>]
Set the event that triggers the 'ot-scope' to which it is assigned.
Optionally, it can be followed by an ACL-based condition, in which case it
will only be evaluated if the condition is true.
ACL-based conditions are executed in the context of a stream that processes
the client and server connections. To configure and use the ACL, see
section 7 of the HAProxy Configuration Manual.
Arguments :
name - the event name
condition - a standard ACL-based condition
Supported events are (the table gives the names of the events in the OT
filter and the corresponding equivalent in the SPOE filter):
-------------------------------------|------------------------------
the OT filter | the SPOE filter
-------------------------------------|------------------------------
on-client-session-start | on-client-session
on-frontend-tcp-request | on-frontend-tcp-request
on-http-wait-request | -
on-http-body-request | -
on-frontend-http-request | on-frontend-http-request
on-switching-rules-request | -
on-backend-tcp-request | on-backend-tcp-request
on-backend-http-request | on-backend-http-request
on-process-server-rules-request | -
on-http-process-request | -
on-tcp-rdp-cookie-request | -
on-process-sticking-rules-request | -
on-client-session-end | -
on-server-unavailable | -
-------------------------------------|------------------------------
on-server-session-start | on-server-session
on-tcp-response | on-tcp-response
on-http-wait-response | -
on-process-store-rules-response | -
on-http-response | on-http-response
on-server-session-end | -
-------------------------------------|------------------------------
extract <name-prefix> [use-vars | use-headers]
For a more detailed description of the propagation process of the span
context, see the description of the keyword 'inject'. Only the process
of extracting data from the carrier is described here.
Arguments :
name-prefix - data name prefix (ie key element prefix)
use-vars - data is extracted from HAProxy variables
use-headers - data is extracted from the HTTP header
Below is an example of using HAProxy variables to transfer span context data:
--- test/ctx/ot.cfg --------------------------------------------------------
...
ot-scope client_session_start_2
extract "ot_ctx_1" use-vars
span "Client session" child-of "ot_ctx_1"
...
----------------------------------------------------------------------------
finish <name> ...
Closing a particular span or span context. Instead of the name of the span,
there are several specially predefined names with which we can finish certain
groups of spans. So it can be used as the name '*req*' for all open spans
related to the request channel, '*res*' for all open spans related to the
response channel and '*' for all open spans regardless of which channel they
are related to. Several spans and/or span contexts can be specified in one
line.
Arguments :
name - the name of the span or context context
inject <name-prefix> [use-vars] [use-headers]
In OpenTracing, the transfer of data related to the tracing process between
microservices that are part of a larger service is done through the
propagation of the span context. The basic operations that allow us to
access and transfer this data are 'inject' and 'extract'.
'inject' allows us to extract span context so that the obtained data can
be forwarded to another process (microservice) via the selected carrier.
'inject' in the name actually means inject data into carrier. Carrier is
an interface here (ie a data structure) that allows us to transfer tracing
state from one process to another.
Data transfer can take place via one of two selected storage methods, the
first is by adding data to the HTTP header and the second is by using HAProxy
variables. Only data transfer via HTTP header can be used to transfer data
to another process (ie microservice). All data is organized in the form of
key-value data pairs.
No matter which data transfer method you use, we need to specify a prefix
for the key element. All alphanumerics (lowercase only) and underline
character can be used to construct the data name prefix. Uppercase letters
can actually be used, but they will be converted to lowercase when creating
the prefix.
Arguments :
name-prefix - data name prefix (ie key element prefix)
use-vars - HAProxy variables are used to store and transfer data
use-headers - HTTP headers are used to store and transfer data
Below is an example of using HTTP headers and variables, and how this is
reflected in the internal data of the HAProxy process.
--- test/ctx/ot.cfg --------------------------------------------------------
...
ot-scope client_session_start_1
span "HAProxy session" root
inject "ot_ctx_1" use-headers use-vars
...
----------------------------------------------------------------------------
- generated HAProxy variable (key -> value):
txn.ot_ctx_1.uberDtraceDid -> 8f1a05a3518d2283:8f1a05a3518d2283:0:1
- generated HTTP header (key: value):
ot_ctx_1-uber-trace-id: 8f1a05a3518d2283:8f1a05a3518d2283:0:1
Because HAProxy does not allow the '-' character in the variable name (which
is automatically generated by the OpenTracing API and on which we have no
influence), it is converted to the letter 'D'. We can see that there is no
such conversion in the name of the HTTP header because the '-' sign is allowed
there. Due to this conversion, initially all uppercase letters are converted
to lowercase because otherwise we would not be able to distinguish whether
the disputed sign '-' is used or not.
Thus created HTTP headers and variables are deleted when executing the
'finish' keyword or when detaching the stream from the filter.
log <name> <sample> ...
This kewyord allows setting the log for the currently active span. The
data type is always a string, ie any sample type is converted to a string.
The exception is a binary value that is not supported by the OT filter.
See the 'tag' keyword description for the data type conversion table.
Arguments :
name - key part of a data pair
sample - sample expression (value part of a data pair), at least one
sample must be present
span <name> [<reference>]
Creating a new span (or referencing an already opened one). If a new span
is created, it can be a child of the referenced span, follow from the
referenced span, or be root 'span'. In case we did not specify a reference
to the previously created span, the new span will become the root span.
We need to pay attention to the fact that in one trace there can be only
one root span. In case we have specified a non-existent span as a reference,
a new span will not be created.
Arguments :
name - the name of the span being created or referenced (operation
name)
reference - span or span context to which the created span is referenced
tag <name> <sample> ...
This kewyord allows setting a tag for the currently active span. The first
argument is the name of the tag (tag ID) and the second its value. A value
can consist of one or more data. If the value is only one data, then the
type of that data depends on the type of the HAProxy sample. If the value
contains more data, then the data type is string. The data conversion table
is below:
HAProxy sample data type | the OpenTracing data type
--------------------------+---------------------------
NULL | NULL
BOOL | BOOL
INT32 | INT64
UINT32 | UINT64
INT64 | INT64
UINT64 | UINT64
IPV4 | STRING
IPV6 | STRING
STRING | STRING
BINARY | UNSUPPORTED
--------------------------+---------------------------
Arguments :
name - key part of a data pair
sample - sample expression (value part of a data pair), at least one
sample must be present
4.4. "ot-group" section
------------------------
This section allows us to define a group of OT scopes, that is not activated
via an event but is triggered from TCP or HTTP rules. More precisely, these
are the following rules: 'tcp-request', 'tcp-response', 'http-request',
'http-response' and 'http-after-response'. These rules can be defined in the
HAProxy configuration file.
ot-group <name>
Creates a new OT group definition named <name>.
Arguments :
name - the name of the OT group
The following keywords are supported in this section:
- scopes
scopes <name> ...
'ot-scope' sections that are part of the specified group are defined. If
the mentioned 'ot-scope' sections are used only in some OT group, they do
not have to have defined events. Several 'ot-scope' sections can be
specified in one line.
Arguments :
name - the name of the 'ot-scope' section
5. Examples
------------
Several examples of the OT filter configuration can be found in the test
directory. A brief description of the prepared configurations follows:
cmp - the configuration very similar to that of the spoa-opentracing project.
It was made to compare the speed of the OT filter with the
implementation of distributed tracing via spoa-opentracing application.
sa - the configuration in which all possible events are used.
ctx - the configuration is very similar to the previous one, with the only
difference that the spans are opened using the span context as a span
reference.
fe be - a slightly more complicated example of the OT filter configuration
that uses two cascaded HAProxy services. The span context between
HAProxy processes is transmitted via the HTTP header.
empty - the empty configuration in which the OT filter is initialized but
no event is triggered. It is not very usable, except to check the
behavior of the OT filter in the case of a similar configuration.
In order to be able to collect data (and view results via the web interface)
we need to install some of the supported tracers. We will use the Jaeger
tracer as an example. Installation instructions can be found on the website
https://www.jaegertracing.io/download/. For the impatient, here we will list
how the image to test the operation of the tracer system can be installed
without much reading of the documentation.
# docker pull jaegertracing/all-in-one:latest
# docker run -d --name jaeger -e COLLECTOR_ZIPKIN_HTTP_PORT=9411 \
-p 5775:5775/udp -p 6831:6831/udp -p 6832:6832/udp -p 5778:5778 \
-p 16686:16686 -p 14268:14268 -p 9411:9411 jaegertracing/all-in-one:latest
The last command will also initialize and run the Jaeger container. If we
want to use that container later, it can be started and stopped in the classic
way, using the 'docker container start/stop' commands.
In order to be able to use any of the configurations from the test directory,
we must also have a tracer plugin in that directory (all examples use the
Jaeger tracer plugin). The simplest way is to download the tracer plugin
using the already prepared shell script get-opentracing-plugins.sh.
The script accepts one argument, the directory in which the download is made.
If run without an argument, the script downloads all plugins to the current
directory.
% ./get-opentracing-plugins.sh
After that, we can run one of the pre-configured configurations using the
provided script run-xxx.sh (where xxx is the name of the configuration being
tested). For example:
% ./run-sa.sh
The script will create a new log file each time it is run (because part of the
log file name is the start time of the script).
Eh, someone will surely notice that all test configurations use the Jaeger
tracing plugin that cannot be downloaded using the get-opentracing-plugins.sh
script. Unfortunately, the latest precompiled version that can be downloaded
is 0.4.2, for newer ones only the source code can be found. Version 0.4.2 has
a bug that can cause the operation of the OT filter to get stuck, so it is
better not to use this version. Here is the procedure by which we can compile
a newer version of the plugin (in our example it is 0.5.0).
Important note: the GCC version must be at least 4.9 or later.
% wget https://github.com/jaegertracing/jaeger-client-cpp/archive/v0.5.0.tar.gz
% tar xf v0.5.0.tar.gz
% cd jaeger-client-cpp-0.5.0
% mkdir build
% cd build
% cmake -DCMAKE_INSTALL_PREFIX=/opt -DJAEGERTRACING_PLUGIN=ON -DHUNTER_CONFIGURATION_TYPES=Release -DHUNTER_BUILD_SHARED_LIBS=OFF ..
% make
After the plugin is compiled, it will be in the current directory. The name
of the plugin is libjaegertracing_plugin.so.
5.1. Benchmarking results
--------------------------
To check the operation of the OT filter, several different test configurations
have been made which are located in the test directory. The test results of
the same configurations (with the names README-speed-xxx, where xxx is the name
of the configuration being tested) are also in the directory of the same name.
All tests were performed on the same debian 9.13 system, CPU i7-4770, 32 GB RAM.
For the purpose of testing, the thttpd web server on port 8000 was used.
Testing was done with the wrk utility running via run-xxx.sh scripts; that is,
via the test-speed.sh script that is run as follows:
% ./test-speed.sh all
The above mentioned thttpd web server is run from that script and it should be
noted that we need to have the same installed on the system (or change the path
to the thttpd server in that script if it is installed elsewhere).
Each test is performed several times over a period of 5 minutes per individual
test. The only difference when running the tests for the same configuration
was in changing the 'rate-limit' parameter (and the 'option disabled' option),
which is set to the following values: 100.0, 50.0, 10.0, 2.5 and 0.0 percent.
Then a test is performed with the OT filter active but disabled for request
processing ('option disabled' is included in the ot.cfg configuration). In
the last test, the OT filter is not used at all, ie it is not active and does
not affect the operation of HAProxy in any way.
6. OT CLI
----------
Via the HAProxy CLI interface we can find out the current status of the OT
filter and change several of its settings.
All supported CLI commands can be found in the following way, using the
socat utility with the assumption that the HAProxy CLI socket path is set
to /tmp/haproxy.sock (of course, instead of socat, nc or other utility can
be used with a change in arguments when running the same):
% echo "help" | socat - UNIX-CONNECT:/tmp/haproxy.sock | grep flt-ot
--- command output ----------
flt-ot debug [level] : set the OT filter debug level (default: get current debug level)
flt-ot disable : disable the OT filter
flt-ot enable : enable the OT filter
flt-ot soft-errors : turning off hard-errors mode
flt-ot hard-errors : enabling hard-errors mode
flt-ot logging [state] : set logging state (default: get current logging state)
flt-ot rate [value] : set the rate limit (default: get current rate value)
flt-ot status : show the OT filter status
--- command output ----------
'flt-ot debug' can only be used in case the OT filter is compiled with the
debug mode enabled.
7. Known bugs and limitations
------------------------------
The name of the span context definition can contain only letters, numbers and
characters '_' and '-'. Also, all uppercase letters in the name are converted
to lowercase. The character '-' is converted internally to the 'D' character,
and since a HAProxy variable is generated from that name, this should be taken
into account if we want to use it somewhere in the HAProxy configuration.
The above mentioned span context is used in the 'inject' and 'extract' keywords.
Let's look a little at the example test/fe-be (configurations are in the
test/fe and test/be directories, 'fe' is here the abbreviation for frontend
and 'be' for backend). In case we have the 'rate-limit' set to a value less
than 100.0, then distributed tracing will not be started with each new HTTP
request. It also means that the span context will not be delivered (via the
HTTP header) to the backend HAProxy process. The 'rate-limit' on the backend
HAProxy must be set to 100.0, but because the frontend HAProxy does not send
a span context every time, all such cases will cause an error to be reported
on the backend server. Therefore, the 'hard-errors' option must be set on the
backend server, so that processing on that stream is stopped as soon as the
first error occurs. Such cases will slow down the backend server's response
a bit (in the example in question it is about 3%).

View file

@ -0,0 +1,298 @@
Here I will write down some specifics of certain parts of the source, these are
just some of my thoughts and clues and they are probably not too important for
a wider audience.
src/parser.c
------------------------------------------------------------------------------
The first thing to run when starting the HAProxy is the flt_ot_parse() function
which actually parses the filter configuration.
In case of correct configuration, the function returns ERR_NONE (or 0), while
in case of incorrect configuration it returns the combination of ERR_* flags
(ERR_NONE here does not belong to that bit combination because its value is 0).
One of the parameters of the function is <char **err> in which an error message
can be returned, if it exists. In that case the return value of the function
should have some of the ERR_* flags set.
Let's look at an example of the following filter configuration what the function
call sequence looks like.
Filter configuration line:
filter opentracing [id <id>] config <file>
Function call sequence:
flt_ot_parse(<err>) {
/* Initialization of the filter configuration data. */
flt_ot_conf_init() {
}
/* Setting the filter name. */
flt_ot_parse_keyword(<err>) {
flt_ot_parse_strdup(<err>) {
}
}
/* Setting the filter configuration file name. */
flt_ot_parse_keyword(<err>) {
flt_ot_parse_strdup(<err>) {
}
}
/* Checking the configuration of the filter. */
flt_ot_parse_cfg(<err>) {
flt_ot_parse_cfg_tracer() {
}
...
flt_ot_post_parse_cfg_tracer() {
}
flt_ot_parse_cfg_group() {
}
...
flt_ot_post_parse_cfg_group() {
}
flt_ot_parse_cfg_scope() {
}
...
flt_ot_post_parse_cfg_scope() {
}
}
}
Checking the filter configuration is actually much more complicated, only the
name of the main function flt_ot_parse_cfg() that does it is listed here.
All functions that use the <err> parameter should set the error status using
that pointer. All other functions (actually these are all functions called
by the flt_ot_parse_cfg() function) should set the error message using the
ha_warning()/ha_alert() HAProxy functions. Of course, the return value (the
mentioned combination of ERR_* bits) is set in all these functions and it
indicates whether the filter configuration is correct or not.
src/group.c
------------------------------------------------------------------------------
The OT filter allows the use of groups within which one or more 'ot-scope'
declarations can be found. These groups can be used using several HAProxy
rules, more precisely 'http-request', 'http-response', 'tcp-request',
'tcp-response' and 'http-after-response' rules.
Configuration example for the specified rules:
<rule> ot-group <filter-id> <group-name> [ { if | unless } <condition> ]
Parsing each of these rules is performed by the flt_ot_group_parse() function.
After parsing the configuration, its verification is performed via the
flt_ot_group_check() function. One parsing function and one configuration
check function are called for each defined rule.
flt_ot_group_parse(<err>) {
}
...
flt_ot_group_check() {
}
...
When deinitializing the module, the function flt_ot_group_release() is called
(which is actually an release_ptr callback function from one of the above
rules). One callback function is called for each defined rule.
flt_ot_group_release() {
}
...
src/filter.c
------------------------------------------------------------------------------
After parsing and checking the configuration, the flt_ot_check() function is
called which associates the 'ot-group' and 'ot-scope' definitions with their
declarations. This procedure concludes the configuration of the OT filter and
after that its initialization is possible.
flt_ops.check = flt_ot_check;
flt_ot_check() {
}
The initialization of the OT filter is done via the flt_ot_init() callback
function. In this function the OpenTracing API library is also initialized.
It is also possible to initialize for each thread individually, but nothing
is being done here for now.
flt_ops.init = flt_ot_init;
flt_ot_init() {
flt_ot_cli_init() {
}
/* Initialization of the OpenTracing API. */
ot_init(<err>) {
}
}
flt_ops.init_per_thread = flt_ot_init_per_thread;
flt_ot_init_per_thread() {
}
...
After the filter instance is created and attached to the stream, the
flt_ot_attach() function is called. In this function a new OT runtime
context is created, and flags are set that define which analyzers are used.
flt_ops.attach = flt_ot_attach;
flt_ot_attach() {
/* In case OT is disabled, nothing is done on this stream further. */
flt_ot_runtime_context_init(<err>) {
flt_ot_pool_alloc() {
}
/* Initializing and setting the variable 'sess.ot.uuid'. */
if (flt_ot_var_register(<err>) != -1) {
flt_ot_var_set(<err>) {
}
}
}
}
When a stream is started, this function is called. At the moment, nothing
is being done in it.
flt_ops.stream_start = flt_ot_stream_start;
flt_ot_stream_start() {
}
Channel analyzers are called when executing individual filter events.
For each of the four analyzer functions, the events associated with them
are listed.
Events:
- 1 'on-client-session-start'
- 15 'on-server-session-start'
------------------------------------------------------------------------
flt_ops.channel_start_analyze = flt_ot_channel_start_analyze;
flt_ot_channel_start_analyze() {
flt_ot_event_run() {
/* Run event. */
flt_ot_scope_run() {
/* Processing of all ot-scopes defined for the current event. */
}
}
}
Events:
- 2 'on-frontend-tcp-request'
- 4 'on-http-body-request'
- 5 'on-frontend-http-request'
- 6 'on-switching-rules-request'
- 7 'on-backend-tcp-request'
- 8 'on-backend-http-request'
- 9 'on-process-server-rules-request'
- 10 'on-http-process-request'
- 11 'on-tcp-rdp-cookie-request'
- 12 'on-process-sticking-rules-request
- 16 'on-tcp-response'
- 18 'on-process-store-rules-response'
- 19 'on-http-response'
------------------------------------------------------------------------
flt_ops.channel_pre_analyze = flt_ot_channel_pre_analyze;
flt_ot_channel_pre_analyze() {
flt_ot_event_run() {
/* Run event. */
flt_ot_scope_run() {
/* Processing of all ot-scopes defined for the current event. */
}
}
}
Events:
- 3 'on-http-wait-request'
- 17 'on-http-wait-response'
------------------------------------------------------------------------
flt_ops.channel_post_analyze = flt_ot_channel_post_analyze;
flt_ot_channel_post_analyze() {
flt_ot_event_run() {
/* Run event. */
flt_ot_scope_run() {
/* Processing of all ot-scopes defined for the current event. */
}
}
}
Events:
- 13 'on-client-session-end'
- 14 'on-server-unavailable'
- 20 'on-server-session-end'
------------------------------------------------------------------------
flt_ops.channel_end_analyze = flt_ot_channel_end_analyze;
flt_ot_channel_end_analyze() {
flt_ot_event_run() {
/* Run event. */
flt_ot_scope_run() {
/* Processing of all ot-scopes defined for the current event. */
}
}
/* In case the backend server does not work, event 'on-server-unavailable'
is called here before event 'on-client-session-end'. */
if ('on-server-unavailable') {
flt_ot_event_run() {
/* Run event. */
flt_ot_scope_run() {
/* Processing of all ot-scopes defined for the current event. */
}
}
}
}
After the stream has stopped, this function is called. At the moment, nothing
is being done in it.
flt_ops.stream_stop = flt_ot_stream_stop;
flt_ot_stream_stop() {
}
Then, before the instance filter is detached from the stream, the following
function is called. It deallocates the runtime context of the OT filter.
flt_ops.detach = flt_ot_detach;
flt_ot_detach() {
flt_ot_runtime_context_free() {
flt_ot_pool_free() {
}
}
}
Module deinitialization begins with deinitialization of individual threads
(as many threads as configured for the HAProxy process). Because nothing
special is connected to the process threads, nothing is done in this function.
flt_ops.deinit_per_thread = flt_ot_deinit_per_thread;
flt_ot_deinit_per_thread() {
}
...
For this function see the above description related to the src/group.c file.
flt_ot_group_release() {
}
...
Module deinitialization ends with the flt_ot_deinit() function, in which all
memory occupied by module operation (and OpenTracing API operation, of course)
is freed.
flt_ops.deinit = flt_ot_deinit;
flt_ot_deinit() {
ot_close() {
}
flt_ot_conf_free() {
}
}

View file

@ -0,0 +1,25 @@
Used pools:
-------------------------------+-----------------------------+-----------------------------
head / name | size | define
-------------------------------+-----------------------------+-----------------------------
pool_head_ buffer | global.tune.bufsize = 16384 | USE_POOL_BUFFER
pool_head_ trash | 32 + 16384 | USE_TRASH_CHUNK
-------------------------------+-----------------------------+-----------------------------
pool_head_ ot_scope_span | 96 | USE_POOL_OT_SCOPE_SPAN
pool_head_ ot_scope_context | 64 | USE_POOL_OT_SCOPE_CONTEXT
pool_head_ ot_runtime_context | 128 | USE_POOL_OT_RUNTIME_CONTEXT
pool_head_ ot_span_context | 96 | USE_POOL_OT_SPAN_CONTEXT
-------------------------------+-----------------------------+-----------------------------
By defining individual definitions in file include/config.h, it is possible to
switch individual pools on / off. If a particular pool is not used, memory is
used in a 'normal' way instead, using malloc()/free() functions.
This is made only from the aspect of debuging the program, i.e. comparing the
speed of operation using different methods of working with memory.
In general, it would be better to use memory pools, due to less fragmentation
of memory space after long operation of the program. The speed of operation
is similar to when using standard allocation functions (when testing it was
shown that pool use was fast by about 1%).

View file

@ -0,0 +1,50 @@
/***
* Copyright 2020 HAProxy Technologies
*
* This file is part of the HAProxy OpenTracing filter.
*
* 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.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#ifndef _OPENTRACING_CLI_H_
#define _OPENTRACING_CLI_H_
#define FLT_OT_CLI_CMD "flt-ot"
#define FLT_OT_CLI_LOGGING_OFF "off"
#define FLT_OT_CLI_LOGGING_ON "on"
#define FLT_OT_CLI_LOGGING_NOLOGNORM "dontlog-normal"
#define FLT_OT_CLI_LOGGING_STATE(a) ((a) & FLT_OT_LOGGING_ON) ? (((a) & FLT_OT_LOGGING_NOLOGNORM) ? "enabled, " FLT_OT_CLI_LOGGING_NOLOGNORM : "enabled") : "disabled"
#define FLT_OT_CLI_MSG_CAT(a) ((a) == NULL) ? "" : (a), ((a) == NULL) ? "" : "\n"
enum FLT_OT_LOGGING_enum {
FLT_OT_LOGGING_OFF = 0,
FLT_OT_LOGGING_ON = 1 << 0,
FLT_OT_LOGGING_NOLOGNORM = 1 << 1,
};
void flt_ot_cli_init(void);
#endif /* _OPENTRACING_CLI_H_ */
/*
* Local variables:
* c-indent-level: 8
* c-basic-offset: 8
* End:
*
* vi: noexpandtab shiftwidth=8 tabstop=8
*/

View file

@ -0,0 +1,227 @@
/***
* Copyright 2020 HAProxy Technologies
*
* This file is part of the HAProxy OpenTracing filter.
*
* 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.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#ifndef _OPENTRACING_CONF_H_
#define _OPENTRACING_CONF_H_
#define FLT_OT_CONF(f) ((struct flt_ot_conf *)FLT_CONF(f))
#define FLT_OT_CONF_HDR_FMT "%p:{ { '%.*s' %zu %d } "
#define FLT_OT_CONF_HDR_ARGS(a,b) (a), (int)(a)->b##_len, (a)->b, (a)->b##_len, (a)->cfg_line
#define FLT_OT_STR_HDR_ARGS(a,b) (a)->b, (a)->b##_len
#define FLT_OT_DBG_CONF_SAMPLE_EXPR(f,a) \
FLT_OT_DBG(3, "%s%p:{ '%s' %p }", (f), (a), (a)->value, (a)->expr)
#define FLT_OT_DBG_CONF_SAMPLE(f,a) \
FLT_OT_DBG(3, "%s%p:{ '%s' '%s' %s %d }", \
(f), (a), (a)->key, (a)->value, flt_ot_list_debug(&((a)->exprs)), (a)->num_exprs)
#define FLT_OT_DBG_CONF_STR(f,a) \
FLT_OT_DBG(3, f FLT_OT_CONF_HDR_FMT "}", FLT_OT_CONF_HDR_ARGS(a, str))
#define FLT_OT_DBG_CONF_CONTEXT(f,a) \
FLT_OT_DBG(3, f FLT_OT_CONF_HDR_FMT "0x%02hhx }", FLT_OT_CONF_HDR_ARGS(a, id), (a)->flags)
#define FLT_OT_DBG_CONF_SPAN(f,a) \
FLT_OT_DBG(3, f FLT_OT_CONF_HDR_FMT "'%s' %zu %d '%s' %zu %hhu 0x%02hhx %s %s %s }", \
FLT_OT_CONF_HDR_ARGS(a, id), FLT_OT_STR_HDR_ARGS(a, ref_id), (a)->ref_type, \
FLT_OT_STR_HDR_ARGS(a, ctx_id), (a)->flag_root, (a)->ctx_flags, flt_ot_list_debug(&((a)->tags)), \
flt_ot_list_debug(&((a)->logs)), flt_ot_list_debug(&((a)->baggages)))
#define FLT_OT_DBG_CONF_SCOPE(f,a) \
FLT_OT_DBG(3, f FLT_OT_CONF_HDR_FMT "%hhu %d %s %p %s %s %s }", \
FLT_OT_CONF_HDR_ARGS(a, id), (a)->flag_used, (a)->event, flt_ot_list_debug(&((a)->acls)), \
(a)->cond, flt_ot_list_debug(&((a)->contexts)), flt_ot_list_debug(&((a)->spans)), \
flt_ot_list_debug(&((a)->finish)))
#define FLT_OT_DBG_CONF_GROUP(f,a) \
FLT_OT_DBG(3, f FLT_OT_CONF_HDR_FMT "%hhu %s }", \
FLT_OT_CONF_HDR_ARGS(a, id), (a)->flag_used, flt_ot_list_debug(&((a)->ph_scopes)))
#define FLT_OT_DBG_CONF_PH(f,a) \
FLT_OT_DBG(3, f FLT_OT_CONF_HDR_FMT "%p }", FLT_OT_CONF_HDR_ARGS(a, id), (a)->ptr)
#define FLT_OT_DBG_CONF_TRACER(f,a) \
FLT_OT_DBG(3, f FLT_OT_CONF_HDR_FMT "'%s' '%s' %p %u %hhu %hhu 0x%02hhx %p:%s 0x%08x %s %s %s }", \
FLT_OT_CONF_HDR_ARGS(a, id), (a)->config, (a)->plugin, (a)->tracer, (a)->rate_limit, (a)->flag_harderr, \
(a)->flag_disabled, (a)->logging, &((a)->proxy_log), flt_ot_list_debug(&((a)->proxy_log.logsrvs)), (a)->analyzers, \
flt_ot_list_debug(&((a)->acls)), flt_ot_list_debug(&((a)->ph_groups)), flt_ot_list_debug(&((a)->ph_scopes)))
#define FLT_OT_DBG_CONF(f,a) \
FLT_OT_DBG(3, "%s%p:{ %p '%s' '%s' %p %s %s }", \
(f), (a), (a)->proxy, (a)->id, (a)->cfg_file, (a)->tracer, \
flt_ot_list_debug(&((a)->groups)), flt_ot_list_debug(&((a)->scopes)))
#define FLT_OT_STR_HDR(a) \
struct { \
char *a; \
size_t a##_len; \
}
#define FLT_OT_CONF_HDR(a) \
struct { \
FLT_OT_STR_HDR(a); \
int cfg_line; \
struct list list; \
}
struct flt_ot_conf_hdr {
FLT_OT_CONF_HDR(id);
};
/* flt_ot_conf_sample->exprs */
struct flt_ot_conf_sample_expr {
FLT_OT_CONF_HDR(value); /* The sample value. */
struct sample_expr *expr; /* The sample expression. */
};
/*
* flt_ot_conf_span->tags
* flt_ot_conf_span->logs
* flt_ot_conf_span->baggages
*/
struct flt_ot_conf_sample {
FLT_OT_CONF_HDR(key); /* The sample name. */
char *value; /* The sample content. */
struct list exprs; /* Used to chain sample expressions. */
int num_exprs; /* Number of defined expressions. */
};
/* flt_ot_conf_scope->finish */
struct flt_ot_conf_str {
FLT_OT_CONF_HDR(str); /* String content/length. */
};
/* flt_ot_conf_scope->contexts */
struct flt_ot_conf_context {
FLT_OT_CONF_HDR(id); /* The name of the context. */
uint8_t flags; /* The type of storage from which the span context is extracted. */
};
/* flt_ot_conf_scope->spans */
struct flt_ot_conf_span {
FLT_OT_CONF_HDR(id); /* The name of the span. */
FLT_OT_STR_HDR(ref_id); /* The reference name, if used. */
int ref_type; /* The reference type. */
FLT_OT_STR_HDR(ctx_id); /* The span context name, if used. */
uint8_t ctx_flags; /* The type of storage used for the span context. */
bool flag_root; /* Whether this is a root span. */
struct list tags; /* The set of key:value tags. */
struct list logs; /* The set of key:value logs. */
struct list baggages; /* The set of key:value baggage items. */
};
struct flt_ot_conf_scope {
FLT_OT_CONF_HDR(id); /* The scope name. */
bool flag_used; /* The indication that the scope is being used. */
int event; /* FLT_OT_EVENT_* */
struct list acls; /* ACLs declared on this scope. */
struct acl_cond *cond; /* ACL condition to meet. */
struct list contexts; /* Declared contexts. */
struct list spans; /* Declared spans. */
struct list finish; /* The list of spans to be finished. */
};
struct flt_ot_conf_group {
FLT_OT_CONF_HDR(id); /* The group name. */
bool flag_used; /* The indication that the group is being used. */
struct list ph_scopes; /* List of all used scopes. */
};
struct flt_ot_conf_ph {
FLT_OT_CONF_HDR(id); /* The scope/group name. */
void *ptr; /* Pointer to real placeholder structure. */
};
#define flt_ot_conf_ph_group flt_ot_conf_ph
#define flt_ot_conf_ph_scope flt_ot_conf_ph
struct flt_ot_conf_tracer {
FLT_OT_CONF_HDR(id); /* The tracer name. */
char *config; /* The OpenTracing configuration file name. */
char *plugin; /* The OpenTracing plugin library file name. */
struct otc_tracer *tracer; /* The OpenTracing tracer handle. */
uint32_t rate_limit; /* [0 2^32-1] <-> [0.0 100.0] */
bool flag_harderr; /* [0 1] */
bool flag_disabled; /* [0 1] */
uint8_t logging; /* [0 1 3] */
struct proxy proxy_log; /* The log server list. */
uint analyzers; /* Defined channel analyzers. */
struct list acls; /* ACLs declared on this tracer. */
struct list ph_groups; /* List of all used groups. */
struct list ph_scopes; /* List of all used scopes. */
};
struct flt_ot_counters {
#ifdef DEBUG_OT
struct {
bool flag_used; /* Whether this event is used. */
uint64_t htx[2]; /* htx_is_empty() function result counter. */
} event[FLT_OT_EVENT_MAX];
#endif
uint64_t disabled[2]; /* How many times stream processing is disabled. */
};
/* The OpenTracing filter configuration. */
struct flt_ot_conf {
struct proxy *proxy; /* Proxy owning the filter. */
char *id; /* The OpenTracing filter id. */
char *cfg_file; /* The OpenTracing filter configuration file name. */
struct flt_ot_conf_tracer *tracer; /* There can only be one tracer. */
struct list groups; /* List of all available groups. */
struct list scopes; /* List of all available scopes. */
struct flt_ot_counters cnt; /* Various counters related to filter operation. */
};
#define flt_ot_conf_ph_group_free flt_ot_conf_ph_free
#define flt_ot_conf_ph_scope_free flt_ot_conf_ph_free
struct flt_ot_conf_ph *flt_ot_conf_ph_init(const char *id, int linenum, struct list *head, char **err);
void flt_ot_conf_ph_free(struct flt_ot_conf_ph **ptr);
struct flt_ot_conf_sample_expr *flt_ot_conf_sample_expr_init(const char *id, int linenum, struct list *head, char **err);
void flt_ot_conf_sample_expr_free(struct flt_ot_conf_sample_expr **ptr);
struct flt_ot_conf_sample *flt_ot_conf_sample_init(char **args, int linenum, struct list *head, char **err);
void flt_ot_conf_sample_free(struct flt_ot_conf_sample **ptr);
struct flt_ot_conf_str *flt_ot_conf_str_init(const char *id, int linenum, struct list *head, char **err);
void flt_ot_conf_str_free(struct flt_ot_conf_str **ptr);
struct flt_ot_conf_context *flt_ot_conf_context_init(const char *id, int linenum, struct list *head, char **err);
void flt_ot_conf_context_free(struct flt_ot_conf_context **ptr);
struct flt_ot_conf_span *flt_ot_conf_span_init(const char *id, int linenum, struct list *head, char **err);
void flt_ot_conf_span_free(struct flt_ot_conf_span **ptr);
struct flt_ot_conf_scope *flt_ot_conf_scope_init(const char *id, int linenum, struct list *head, char **err);
void flt_ot_conf_scope_free(struct flt_ot_conf_scope **ptr);
struct flt_ot_conf_group *flt_ot_conf_group_init(const char *id, int linenum, struct list *head, char **err);
void flt_ot_conf_group_free(struct flt_ot_conf_group **ptr);
struct flt_ot_conf_tracer *flt_ot_conf_tracer_init(const char *id, int linenum, char **err);
void flt_ot_conf_tracer_free(struct flt_ot_conf_tracer **ptr);
struct flt_ot_conf *flt_ot_conf_init(struct proxy *px);
void flt_ot_conf_free(struct flt_ot_conf **ptr);
#endif /* _OPENTRACING_CONF_H_ */
/*
* Local variables:
* c-indent-level: 8
* c-basic-offset: 8
* End:
*
* vi: noexpandtab shiftwidth=8 tabstop=8
*/

View file

@ -0,0 +1,46 @@
/***
* Copyright 2020 HAProxy Technologies
*
* This file is part of the HAProxy OpenTracing filter.
*
* 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.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#ifndef _OPENTRACING_CONFIG_H_
#define _OPENTRACING_CONFIG_H_
#undef DEBUG_OT_SYSTIME
#define USE_POOL_BUFFER
#define USE_POOL_OT_SPAN_CONTEXT
#define USE_POOL_OT_SCOPE_SPAN
#define USE_POOL_OT_SCOPE_CONTEXT
#define USE_POOL_OT_RUNTIME_CONTEXT
#define USE_TRASH_CHUNK
#define FLT_OT_ID_MAXLEN 64
#define FLT_OT_MAXTAGS 8
#define FLT_OT_MAXBAGGAGES 8
#define FLT_OT_RATE_LIMIT_MAX 100.0
#define FLT_OT_DEBUG_LEVEL 0b00001111
#endif /* _OPENTRACING_CONFIG_H_ */
/*
* Local variables:
* c-indent-level: 8
* c-basic-offset: 8
* End:
*
* vi: noexpandtab shiftwidth=8 tabstop=8
*/

View file

@ -0,0 +1,96 @@
/***
* Copyright 2020 HAProxy Technologies
*
* This file is part of the HAProxy OpenTracing filter.
*
* 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.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#ifndef _OPENTRACING_DEBUG_H_
#define _OPENTRACING_DEBUG_H_
#ifdef DEBUG_FULL
# define DEBUG_OT
#endif
#ifdef DEBUG_OT
# ifdef DEBUG_OT_SYSTIME
# define FLT_OT_DBG_FMT(f) "[% 2d] %ld.%06ld [" FLT_OT_SCOPE "]: " f, tid, now.tv_sec, now.tv_usec
# else
# define FLT_OT_DBG_FMT(f) "[% 2d] %11.6f [" FLT_OT_SCOPE "]: " f, tid, FLT_OT_TV_UDIFF(&(flt_ot_debug.start), &now) / 1e6
# endif
# define FLT_OT_DBG_INDENT " "
# define FLT_OT_DBG(l,f, ...) \
do { \
if (!(l) || (flt_ot_debug.level & (1 << (l)))) \
(void)fprintf(stderr, FLT_OT_DBG_FMT("%.*s" f "\n"), \
dbg_indent_level, FLT_OT_DBG_INDENT, ##__VA_ARGS__); \
} while (0)
# define FLT_OT_FUNC(f, ...) do { FLT_OT_DBG(1, "%s(" f ") {", __func__, ##__VA_ARGS__); dbg_indent_level += 3; } while (0)
# define FLT_OT_RETURN(a) do { dbg_indent_level -= 3; FLT_OT_DBG(1, "}"); return a; } while (0)
# define FLT_OT_DBG_IFDEF(a,b) a
# define FLT_OT_DBG_ARGS(a, ...) a, ##__VA_ARGS__
struct flt_ot_debug {
#ifndef DEBUG_OT_SYSTIME
struct timeval start;
#endif
uint8_t level;
};
extern THREAD_LOCAL int dbg_indent_level;
extern struct flt_ot_debug flt_ot_debug;
#else
# define FLT_OT_DBG(...) while (0)
# define FLT_OT_FUNC(...) while (0)
# define FLT_OT_RETURN(a) return a
# define FLT_OT_DBG_IFDEF(a,b) b
# define FLT_OT_DBG_ARGS(...)
#endif /* DEBUG_OT */
/*
* ON | NOLOGNORM |
* -----+-----------+-------------
* 0 | 0 | no log
* 0 | 1 | no log
* 1 | 0 | log all
* 1 | 1 | log errors
* -----+-----------+-------------
*/
#define FLT_OT_LOG(l,f, ...) \
do { \
if (!(conf->tracer->logging & FLT_OT_LOGGING_ON)) \
FLT_OT_DBG(3, "NOLOG[%d]: [" FLT_OT_SCOPE "]: [%s] " f, (l), conf->id, ##__VA_ARGS__); \
else if ((conf->tracer->logging & FLT_OT_LOGGING_NOLOGNORM) && ((l) > LOG_ERR)) \
FLT_OT_DBG(2, "NOLOG[%d]: [" FLT_OT_SCOPE "]: [%s] " f, (l), conf->id, ##__VA_ARGS__); \
else { \
send_log(&(conf->tracer->proxy_log), (l), "[" FLT_OT_SCOPE "]: [%s] " f "\n", conf->id, ##__VA_ARGS__); \
\
FLT_OT_DBG(1, "LOG[%d]: %s", (l), logline); \
} \
} while (0)
#endif /* _OPENTRACING_DEBUG_H_ */
/*
* Local variables:
* c-indent-level: 8
* c-basic-offset: 8
* End:
*
* vi: noexpandtab shiftwidth=8 tabstop=8
*/

View file

@ -0,0 +1,104 @@
/***
* Copyright 2020 HAProxy Technologies
*
* This file is part of the HAProxy OpenTracing filter.
*
* 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.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#ifndef _OPENTRACING_DEFINE_H_
#define _OPENTRACING_DEFINE_H_
#define FLT_OT_DEREF(a,m,v) (((a) != NULL) ? (a)->m : (v))
#define FLT_OT_DDEREF(a,m,v) ((((a) != NULL) && (*(a) != NULL)) ? (*(a))->m : (v))
#define FLT_OT_TABLESIZE(a) (sizeof(a) / sizeof((a)[0]))
#define FLT_OT_IN_RANGE(v,a,b) (((v) >= (a)) && ((v) <= (b)))
#define FLT_OT_DPTR_ARGS(a) (a), ((a) == NULL) ? NULL : *(a)
#define FLT_OT_ARG_ISVALID(n) ((args[n] != NULL) && *args[n])
#define FLT_OT_TV_UDIFF(a,b) (((b)->tv_sec - (a)->tv_sec) * 1000000 + (b)->tv_usec - (a)->tv_usec)
#define FLT_OT_U32_FLOAT(a,b) ((a) * (double)(b) / UINT32_MAX)
#define FLT_OT_FLOAT_U32(a,b) ((uint32_t)((a) / (double)(b) * UINT32_MAX + 0.5))
#define FLT_OT_STR_DASH_72 "------------------------------------------------------------------------"
#define FLT_OT_STR_DASH_78 FLT_OT_STR_DASH_72 "------"
#define FLT_OT_STR_FLAG_YN(a) (a) ? "yes" : "no"
#define FLT_OT_STR_SIZE(a) (sizeof(a) - 1)
#define FLT_OT_STR_ADDRSIZE(a) (a), FLT_OT_STR_SIZE(a)
#define FLT_OT_STR_ISVALID(a) (((a) != NULL) && (*(a) != '\0'))
#define FLT_OT_STR_CMP(S,s,l) (((l) == FLT_OT_STR_SIZE(S)) && (memcmp((s), FLT_OT_STR_ADDRSIZE(S)) == 0))
#define FLT_OT_STR_ELLIPSIS(a,n) do { if ((a) != NULL) { if ((n) > 0) (a)[(n) - 1] = '\0'; if ((n) > 3) (a)[(n) - 2] = (a)[(n) - 3] = (a)[(n) - 4] = '.'; } } while (0)
#define FLT_OT_NIBBLE_TO_HEX(a) ((a) + (((a) < 10) ? '0' : ('a' - 10)))
#define FLT_OT_FREE(a) do { if ((a) != NULL) OTC_DBG_FREE(a); } while (0)
#define FLT_OT_FREE_VOID(a) do { if ((a) != NULL) OTC_DBG_FREE((void *)(a)); } while (0)
#define FLT_OT_FREE_CLEAR(a) do { if ((a) != NULL) { OTC_DBG_FREE(a); (a) = NULL; } } while (0)
#define FLT_OT_STRDUP(s) OTC_DBG_STRDUP(s)
#define FLT_OT_STRNDUP(s,n) OTC_DBG_STRNDUP((s), (n))
#define FLT_OT_CALLOC(n,e) OTC_DBG_CALLOC((n), (e))
#define FLT_OT_MALLOC(s) OTC_DBG_MALLOC((s))
#define FLT_OT_MEMINFO() OTC_DBG_MEMINFO()
#define FLT_OT_RUN_ONCE(f) do { static bool __f = 1; if (__f) { __f = 0; f; } } while (0)
#define FLT_OT_LIST_ISVALID(a) (((a) != NULL) && ((a)->n != NULL) && ((a)->p != NULL))
#define FLT_OT_LIST_DEL(a) do { if (FLT_OT_LIST_ISVALID(a)) LIST_DEL(a); } while (0)
#define FLT_OT_LIST_DESTROY(t,h) \
do { \
struct flt_ot_conf_##t *_ptr, *_back; \
\
if (!FLT_OT_LIST_ISVALID(h) || LIST_ISEMPTY(h)) \
break; \
\
FLT_OT_DBG(2, "- deleting " #t " list %s", flt_ot_list_debug(h)); \
\
list_for_each_entry_safe(_ptr, _back, (h), list) \
flt_ot_conf_##t##_free(&_ptr); \
} while (0)
#define FLT_OT_BUFFER_THR(b,m,n,p) \
static THREAD_LOCAL char b[m][n]; \
static THREAD_LOCAL size_t __idx = 0; \
char *p = b[__idx]; \
__idx = (__idx + 1) % (m)
#define FLT_OT_ERR(f, ...) \
do { \
if ((err != NULL) && (*err == NULL)) \
(void)memprintf(err, f, ##__VA_ARGS__); \
} while (0)
#define FLT_OT_ERR_APPEND(f, ...) \
do { \
if (err != NULL) \
(void)memprintf(err, f, ##__VA_ARGS__); \
} while (0)
#define FLT_OT_ERR_FREE(p) \
do { \
if ((p) == NULL) \
break; \
\
FLT_OT_DBG(0, "%s:%d: ERROR: %s", __func__, __LINE__, (p)); \
FLT_OT_FREE_CLEAR(p); \
} while (0)
#endif /* _OPENTRACING_DEFINE_H_ */
/*
* Local variables:
* c-indent-level: 8
* c-basic-offset: 8
* End:
*
* vi: noexpandtab shiftwidth=8 tabstop=8
*/

View file

@ -0,0 +1,120 @@
/***
* Copyright 2020 HAProxy Technologies
*
* This file is part of the HAProxy OpenTracing filter.
*
* 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.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#ifndef _OPENTRACING_EVENT_H_
#define _OPENTRACING_EVENT_H_
/*
* This must be defined in order for macro FLT_OT_EVENT_DEFINES
* and structure flt_ot_event_data to have the correct contents.
*/
#define AN_REQ_NONE 0
#define AN_REQ_CLIENT_SESS_START 0
#define AN_REQ_SERVER_UNAVAILABLE 0
#define AN_REQ_CLIENT_SESS_END 0
#define AN_RES_SERVER_SESS_START 0
#define AN_RES_SERVER_SESS_END 0
#define SMP_VAL_FE_ 0
#define SMP_VAL_BE_ 0
/*
* Event names are selected to be somewhat compatible with the SPOE filter,
* from which the following names are taken:
* - on-client-session -> on-client-session-start
* - on-frontend-tcp-request
* - on-frontend-http-request
* - on-backend-tcp-request
* - on-backend-http-request
* - on-server-session -> on-server-session-start
* - on-tcp-response
* - on-http-response
*
* FLT_OT_EVENT_NONE is used as an index for 'ot-scope' sections that do not
* have an event defined. The 'ot-scope' sections thus defined can be used
* within the 'ot-group' section.
*
* A description of the macro arguments can be found in the structure
* flt_ot_event_data definition
*/
#define FLT_OT_EVENT_DEFINES \
FLT_OT_EVENT_DEF( NONE, REQ, , , 0, "") \
FLT_OT_EVENT_DEF( CLIENT_SESS_START, REQ, CON_ACC, , 1, "on-client-session-start") \
FLT_OT_EVENT_DEF( INSPECT_FE, REQ, REQ_CNT, , 1, "on-frontend-tcp-request") \
FLT_OT_EVENT_DEF( WAIT_HTTP, REQ, , , 1, "on-http-wait-request") \
FLT_OT_EVENT_DEF( HTTP_BODY, REQ, , , 1, "on-http-body-request") \
FLT_OT_EVENT_DEF( HTTP_PROCESS_FE, REQ, HRQ_HDR, , 1, "on-frontend-http-request") \
FLT_OT_EVENT_DEF( SWITCHING_RULES, REQ, , , 1, "on-switching-rules-request") \
FLT_OT_EVENT_DEF( INSPECT_BE, REQ, REQ_CNT, REQ_CNT, 1, "on-backend-tcp-request") \
FLT_OT_EVENT_DEF( HTTP_PROCESS_BE, REQ, HRQ_HDR, HRQ_HDR, 1, "on-backend-http-request") \
/* FLT_OT_EVENT_DEF( HTTP_TARPIT, REQ, , , 1, "on-http-tarpit-request") */ \
FLT_OT_EVENT_DEF( SRV_RULES, REQ, , , 1, "on-process-server-rules-request") \
FLT_OT_EVENT_DEF( HTTP_INNER, REQ, , , 1, "on-http-process-request") \
FLT_OT_EVENT_DEF( PRST_RDP_COOKIE, REQ, , , 1, "on-tcp-rdp-cookie-request") \
FLT_OT_EVENT_DEF( STICKING_RULES, REQ, , , 1, "on-process-sticking-rules-request") \
FLT_OT_EVENT_DEF( CLIENT_SESS_END, REQ, , , 0, "on-client-session-end") \
FLT_OT_EVENT_DEF(SERVER_UNAVAILABLE, REQ, , , 0, "on-server-unavailable") \
\
FLT_OT_EVENT_DEF( SERVER_SESS_START, RES, , SRV_CON, 0, "on-server-session-start") \
FLT_OT_EVENT_DEF( INSPECT, RES, RES_CNT, RES_CNT, 0, "on-tcp-response") \
FLT_OT_EVENT_DEF( WAIT_HTTP, RES, , , 1, "on-http-wait-response") \
FLT_OT_EVENT_DEF( STORE_RULES, RES, , , 1, "on-process-store-rules-response") \
FLT_OT_EVENT_DEF( HTTP_PROCESS_BE, RES, HRS_HDR, HRS_HDR, 1, "on-http-response") \
FLT_OT_EVENT_DEF( SERVER_SESS_END, RES, , , 0, "on-server-session-end")
enum FLT_OT_EVENT_enum {
#define FLT_OT_EVENT_DEF(a,b,c,d,e,f) FLT_OT_EVENT_##b##_##a,
FLT_OT_EVENT_DEFINES
FLT_OT_EVENT_MAX
#undef FLT_OT_EVENT_DEF
};
enum FLT_OT_EVENT_SAMPLE_enum {
FLT_OT_EVENT_SAMPLE_TAG = 0,
FLT_OT_EVENT_SAMPLE_LOG,
FLT_OT_EVENT_SAMPLE_BAGGAGE,
};
struct flt_ot_event_data {
uint an_bit; /* Used channel analyser. */
uint smp_opt_dir; /* Fetch direction (request/response). */
uint smp_val_fe; /* Valid FE fetch location. */
uint smp_val_be; /* Valid BE fetch location. */
bool flag_http_inject; /* Span context injection allowed. */
const char *name; /* Filter event name. */
};
struct flt_ot_conf_scope;
extern const struct flt_ot_event_data flt_ot_event_data[FLT_OT_EVENT_MAX];
int flt_ot_scope_run(struct stream *s, struct filter *f, struct channel *chn, struct flt_ot_conf_scope *conf_scope, const struct timespec *ts, uint dir, char **err);
int flt_ot_event_run(struct stream *s, struct filter *f, struct channel *chn, int event, char **err);
#endif /* _OPENTRACING_EVENT_H_ */
/*
* Local variables:
* c-indent-level: 8
* c-basic-offset: 8
* End:
*
* vi: noexpandtab shiftwidth=8 tabstop=8
*/

View file

@ -0,0 +1,68 @@
/***
* Copyright 2020 HAProxy Technologies
*
* This file is part of the HAProxy OpenTracing filter.
*
* 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.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#ifndef _OPENTRACING_FILTER_H_
#define _OPENTRACING_FILTER_H_
#define FLT_OT_FMT_NAME "'" FLT_OT_OPT_NAME "' : "
#define FLT_OT_FMT_TYPE "'filter' : "
#define FTL_OT_VAR_UUID "sess", "ot", "uuid"
#define FLT_OT_ALERT(f, ...) ha_alert(FLT_OT_FMT_TYPE FLT_OT_FMT_NAME f "\n", ##__VA_ARGS__)
#define FLT_OT_CONDITION_IF "if"
#define FLT_OT_CONDITION_UNLESS "unless"
enum FLT_OT_RET_enum {
FLT_OT_RET_ERROR = -1,
FLT_OT_RET_WAIT = 0,
FLT_OT_RET_IGNORE = 0,
FLT_OT_RET_OK = 1,
};
#define FLT_OT_DBG_LIST(d,m,p,t,v,f) \
do { \
if (LIST_ISEMPTY(&((d)->m##s))) { \
FLT_OT_DBG(3, p "- no " #m "s " t); \
} else { \
const struct flt_ot_conf_##m *v; \
\
FLT_OT_DBG(3, p "- " t " " #m "s: %s", \
flt_ot_list_debug(&((d)->m##s))); \
list_for_each_entry(v, &((d)->m##s), list) \
do { f; } while (0); \
} \
} while (0)
extern const char *ot_flt_id;
extern struct flt_ops flt_ot_ops;
bool flt_ot_is_disabled(const struct filter *f FLT_OT_DBG_ARGS(, int event));
#endif /* _OPENTRACING_FILTER_H_ */
/*
* Local variables:
* c-indent-level: 8
* c-basic-offset: 8
* End:
*
* vi: noexpandtab shiftwidth=8 tabstop=8
*/

View file

@ -0,0 +1,61 @@
/***
* Copyright 2020 HAProxy Technologies
*
* This file is part of the HAProxy OpenTracing filter.
*
* 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.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#ifndef _OPENTRACING_GROUP_H_
#define _OPENTRACING_GROUP_H_
#define FLT_OT_ACTION_GROUP "ot-group"
enum FLT_OT_ARG_enum {
FLT_OT_ARG_FILTER_ID = 0,
FLT_OT_ARG_GROUP_ID,
FLT_OT_ARG_FLT_CONF = 0,
FLT_OT_ARG_CONF,
FLT_OT_ARG_GROUP,
};
/*
* A description of the macro arguments can be found in the structure
* flt_ot_group_data definition
*/
#define FLT_OT_GROUP_DEFINES \
FLT_OT_GROUP_DEF(ACT_F_TCP_REQ_CON, SMP_VAL_FE_CON_ACC, SMP_OPT_DIR_REQ) \
FLT_OT_GROUP_DEF(ACT_F_TCP_REQ_SES, SMP_VAL_FE_SES_ACC, SMP_OPT_DIR_REQ) \
FLT_OT_GROUP_DEF(ACT_F_TCP_REQ_CNT, SMP_VAL_FE_REQ_CNT, SMP_OPT_DIR_REQ) \
FLT_OT_GROUP_DEF(ACT_F_TCP_RES_CNT, SMP_VAL_BE_RES_CNT, SMP_OPT_DIR_RES) \
FLT_OT_GROUP_DEF(ACT_F_HTTP_REQ, SMP_VAL_FE_HRQ_HDR, SMP_OPT_DIR_REQ) \
FLT_OT_GROUP_DEF(ACT_F_HTTP_RES, SMP_VAL_BE_HRS_HDR, SMP_OPT_DIR_RES)
struct flt_ot_group_data {
enum act_from act_from; /* ACT_F_* */
uint smp_val; /* Valid FE/BE fetch location. */
uint smp_opt_dir; /* Fetch direction (request/response). */
};
#endif /* _OPENTRACING_GROUP_H_ */
/*
* Local variables:
* c-indent-level: 8
* c-basic-offset: 8
* End:
*
* vi: noexpandtab shiftwidth=8 tabstop=8
*/

View file

@ -0,0 +1,41 @@
/***
* Copyright 2020 HAProxy Technologies
*
* This file is part of the HAProxy OpenTracing filter.
*
* 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.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#ifndef _OPENTRACING_HTTP_H_
#define _OPENTRACING_HTTP_H_
#ifndef DEBUG_OT
# define flt_ot_http_headers_dump(...) while (0)
#else
void flt_ot_http_headers_dump(const struct channel *chn);
#endif
struct otc_text_map *flt_ot_http_headers_get(struct channel *chn, const char *prefix, size_t len, char **err);
int flt_ot_http_header_set(struct channel *chn, const char *prefix, const char *name, const char *value, char **err);
int flt_ot_http_headers_remove(struct channel *chn, const char *prefix, char **err);
#endif /* _OPENTRACING_HTTP_H_ */
/*
* Local variables:
* c-indent-level: 8
* c-basic-offset: 8
* End:
*
* vi: noexpandtab shiftwidth=8 tabstop=8
*/

View file

@ -0,0 +1,63 @@
/***
* Copyright 2020 HAProxy Technologies
*
* This file is part of the HAProxy OpenTracing filter.
*
* 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.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#ifndef _OPENTRACING_INCLUDE_H_
#define _OPENTRACING_INCLUDE_H_
#include <errno.h>
#include <stdbool.h>
#include <haproxy/api.h>
#include <haproxy/cfgparse.h>
#include <haproxy/acl.h>
#include <haproxy/cli.h>
#include <haproxy/filters.h>
#include <haproxy/http_htx.h>
#include <haproxy/http_rules.h>
#include <haproxy/log.h>
#include <haproxy/sample.h>
#include <haproxy/tcp_rules.h>
#include <haproxy/vars.h>
#include "config.h"
#include "debug.h"
#include "define.h"
#include "cli.h"
#include "event.h"
#include "conf.h"
#include "filter.h"
#include "group.h"
#include "http.h"
#include "opentracing.h"
#include "parser.h"
#include "pool.h"
#include "scope.h"
#include "util.h"
#include "vars.h"
#endif /* _OPENTRACING_INCLUDE_H_ */
/*
* Local variables:
* c-indent-level: 8
* c-basic-offset: 8
* End:
*
* vi: noexpandtab shiftwidth=8 tabstop=8
*/

View file

@ -0,0 +1,85 @@
/***
* Copyright 2020 HAProxy Technologies
*
* This file is part of the HAProxy OpenTracing filter.
*
* 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.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#ifndef _OPENTRACING_OT_H_
#define _OPENTRACING_OT_H_
#include <opentracing-c-wrapper/include.h>
#define FLT_OT_VSET(p,t,v) \
do { (p)->type = otc_value_##t; (p)->value.t##_value = (v); } while (0)
#define FLT_OT_DBG_TEXT_MAP(a) \
FLT_OT_DBG(3, "%p:{ %p %p %zu/%zu %hhu }", \
(a), (a)->key, (a)->value, (a)->count, (a)->size, (a)->is_dynamic)
#define FLT_OT_DBG_TEXT_CARRIER(a,f) \
FLT_OT_DBG(3, "%p:{ { %p %p %zu/%zu %hhu } %p }", \
(a), (a)->text_map.key, (a)->text_map.value, (a)->text_map.count, \
(a)->text_map.size, (a)->text_map.is_dynamic, (a)->f)
#define FLT_OT_DBG_CUSTOM_CARRIER(a,f) \
FLT_OT_DBG(3, "%p:{ { %p %zu %hhu } %p }", \
(a), (a)->binary_data.data, (a)->binary_data.size, \
(a)->binary_data.is_dynamic, (a)->f)
#define FLT_OT_DBG_SPAN_CONTEXT(a) \
FLT_OT_DBG(3, "%p:{ %" PRId64 " %p %p }", (a), (a)->idx, (a)->span, (a)->destroy)
#ifndef DEBUG_OT
# define ot_debug() while (0)
# define ot_text_map_show(...) while (0)
#else
void ot_text_map_show(const struct otc_text_map *text_map);
void ot_debug(void);
#endif
int ot_init(struct otc_tracer **tracer, const char *config, const char *plugin, char **err);
struct otc_span *ot_span_init(struct otc_tracer *tracer, const char *operation_name, const struct timespec *ts_steady, const struct timespec *ts_system, int ref_type, int ref_ctx_idx, const struct otc_span *ref_span, const struct otc_tag *tags, int num_tags, char **err);
int ot_span_tag(struct otc_span *span, const struct otc_tag *tags, int num_tags);
int ot_span_log(struct otc_span *span, const struct otc_log_field *log_fields, int num_fields);
int ot_span_set_baggage(struct otc_span *span, const struct otc_text_map *baggage);
struct otc_span_context *ot_inject_http_headers(struct otc_tracer *tracer, const struct otc_span *span, struct otc_http_headers_writer *carrier, char **err);
struct otc_span_context *ot_extract_http_headers(struct otc_tracer *tracer, struct otc_http_headers_reader *carrier, const struct otc_text_map *text_map, char **err);
void ot_span_finish(struct otc_span **span, const struct timespec *ts_finish, const struct timespec *log_ts, const char *log_key, const char *log_value, ...);
void ot_close(struct otc_tracer **tracer);
/* Unused code. */
struct otc_span *ot_span_init_va(struct otc_tracer *tracer, const char *operation_name, const struct timespec *ts_steady, const struct timespec *ts_system, int ref_type, int ref_ctx_idx, const struct otc_span *ref_span, char **err, const char *tag_key, const char *tag_value, ...);
int ot_span_tag_va(struct otc_span *span, const char *key, int type, ...);
int ot_span_log_va(struct otc_span *span, const char *key, const char *value, ...);
int ot_span_log_fmt(struct otc_span *span, const char *key, const char *format, ...) __attribute__ ((format(printf, 3, 4)));
int ot_span_set_baggage_va(struct otc_span *span, const char *key, const char *value, ...);
struct otc_text_map *ot_span_baggage_va(const struct otc_span *span, const char *key, ...);
struct otc_span_context *ot_inject_text_map(struct otc_tracer *tracer, const struct otc_span *span, struct otc_text_map_writer *carrier);
struct otc_span_context *ot_inject_binary(struct otc_tracer *tracer, const struct otc_span *span, struct otc_custom_carrier_writer *carrier);
struct otc_span_context *ot_extract_text_map(struct otc_tracer *tracer, struct otc_text_map_reader *carrier, const struct otc_text_map *text_map);
struct otc_span_context *ot_extract_binary(struct otc_tracer *tracer, struct otc_custom_carrier_reader *carrier, const struct otc_binary_data *binary_data);
#endif /* _OPENTRACING_OT_H_ */
/*
* Local variables:
* c-indent-level: 8
* c-basic-offset: 8
* End:
*
* vi: noexpandtab shiftwidth=8 tabstop=8
*/

View file

@ -0,0 +1,148 @@
/***
* Copyright 2020 HAProxy Technologies
*
* This file is part of the HAProxy OpenTracing filter.
*
* 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.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#ifndef _OPENTRACING_PARSER_H_
#define _OPENTRACING_PARSER_H_
#define FLT_OT_SCOPE "OT"
/*
* filter FLT_OT_OPT_NAME FLT_OT_OPT_FILTER_ID <FLT_OT_OPT_FILTER_ID_DEFAULT> FLT_OT_OPT_CONFIG <file>
*/
#define FLT_OT_OPT_NAME "opentracing"
#define FLT_OT_OPT_FILTER_ID "id"
#define FLT_OT_OPT_FILTER_ID_DEFAULT "ot-filter"
#define FLT_OT_OPT_CONFIG "config"
#define FLT_OT_PARSE_SECTION_TRACER_ID "ot-tracer"
#define FLT_OT_PARSE_SECTION_GROUP_ID "ot-group"
#define FLT_OT_PARSE_SECTION_SCOPE_ID "ot-scope"
#define FLT_OT_PARSE_SPAN_ROOT "root"
#define FLT_OT_PARSE_SPAN_REF_CHILD "child-of"
#define FLT_OT_PARSE_SPAN_REF_FOLLOWS "follows-from"
#define FLT_OT_PARSE_CTX_AUTONAME "-"
#define FLT_OT_PARSE_CTX_USE_HEADERS "use-headers"
#define FLT_OT_PARSE_CTX_USE_VARS "use-vars"
#define FLT_OT_PARSE_OPTION_HARDERR "hard-errors"
#define FLT_OT_PARSE_OPTION_DISABLED "disabled"
#define FLT_OT_PARSE_OPTION_NOLOGNORM "dontlog-normal"
/*
* A description of the macro arguments can be found in the structure
* flt_ot_parse_data definition
*/
#define FLT_OT_PARSE_TRACER_DEFINES \
FLT_OT_PARSE_TRACER_DEF( ID, 0, 1, 2, 2, "ot-tracer", " <name>") \
FLT_OT_PARSE_TRACER_DEF( ACL, 0, 1, 3, 0, "acl", " <name> <criterion> [flags] [operator] <value> ...") \
FLT_OT_PARSE_TRACER_DEF( LOG, 0, 1, 2, 0, "log", " { global | <addr> [len <len>] [format <fmt>] <facility> [<level> [<minlevel>]] }") \
FLT_OT_PARSE_TRACER_DEF( CONFIG, 0, 0, 2, 2, "config", " <file>") \
FLT_OT_PARSE_TRACER_DEF( PLUGIN, 0, 0, 2, 2, "plugin", " <file>") \
FLT_OT_PARSE_TRACER_DEF( GROUPS, 0, 0, 2, 0, "groups", " <name> ...") \
FLT_OT_PARSE_TRACER_DEF( SCOPES, 0, 0, 2, 0, "scopes", " <name> ...") \
FLT_OT_PARSE_TRACER_DEF( RATE_LIMIT, 0, 0, 2, 2, "rate-limit", " <value>") \
FLT_OT_PARSE_TRACER_DEF( OPTION, 0, 0, 2, 2, "option", " { disabled | dontlog-normal | hard-errors }") \
FLT_OT_PARSE_TRACER_DEF(DEBUG_LEVEL, 0, 0, 2, 2, "debug-level", " <value>")
#define FLT_OT_PARSE_GROUP_DEFINES \
FLT_OT_PARSE_GROUP_DEF( ID, 0, 1, 2, 2, "ot-group", " <name>") \
FLT_OT_PARSE_GROUP_DEF(SCOPES, 0, 0, 2, 0, "scopes", " <name> ...")
#define FLT_OT_PARSE_SCOPE_DEFINES \
FLT_OT_PARSE_SCOPE_DEF( ID, 0, 1, 2, 2, "ot-scope", " <name>") \
FLT_OT_PARSE_SCOPE_DEF( SPAN, 0, 0, 2, 5, "span", " <name> [<reference>] [root]") \
FLT_OT_PARSE_SCOPE_DEF( TAG, 1, 0, 3, 0, "tag", " <name> <sample> ...") \
FLT_OT_PARSE_SCOPE_DEF( LOG, 1, 0, 3, 0, "log", " <name> <sample> ...") \
FLT_OT_PARSE_SCOPE_DEF(BAGGAGE, 1, 4, 3, 0, "baggage", " <name> <sample> ...") \
FLT_OT_PARSE_SCOPE_DEF( INJECT, 1, 3, 2, 4, "inject", " <name-prefix> [use-vars] [use-headers]") \
FLT_OT_PARSE_SCOPE_DEF(EXTRACT, 0, 3, 2, 3, "extract", " <name-prefix> [use-vars | use-headers]") \
FLT_OT_PARSE_SCOPE_DEF( FINISH, 0, 0, 2, 0, "finish", " <name> ...") \
FLT_OT_PARSE_SCOPE_DEF( ACL, 0, 1, 3, 0, "acl", " <name> <criterion> [flags] [operator] <value> ...") \
FLT_OT_PARSE_SCOPE_DEF( EVENT, 0, 0, 2, 0, "event", " <name> [{ if | unless } <condition>]")
enum FLT_OT_PARSE_TRACER_enum {
#define FLT_OT_PARSE_TRACER_DEF(a,b,c,d,e,f,g) FLT_OT_PARSE_TRACER_##a,
FLT_OT_PARSE_TRACER_DEFINES
#undef FLT_OT_PARSE_TRACER_DEF
};
enum FLT_OT_PARSE_GROUP_enum {
#define FLT_OT_PARSE_GROUP_DEF(a,b,c,d,e,f,g) FLT_OT_PARSE_GROUP_##a,
FLT_OT_PARSE_GROUP_DEFINES
#undef FLT_OT_PARSE_GROUP_DEF
};
enum FLT_OT_PARSE_SCOPE_enum {
#define FLT_OT_PARSE_SCOPE_DEF(a,b,c,d,e,f,g) FLT_OT_PARSE_SCOPE_##a,
FLT_OT_PARSE_SCOPE_DEFINES
#undef FLT_OT_PARSE_SCOPE_DEF
};
enum FLT_OT_CTX_USE_enum {
FLT_OT_CTX_USE_VARS = 1 << 0,
FLT_OT_CTX_USE_HEADERS = 1 << 1,
};
struct flt_ot_parse_data {
int keyword; /* Keyword index. */
bool flag_check_id; /* Whether the group ID must be defined for the keyword. */
int check_name; /* Checking allowed characters in the name. */
int args_min; /* The minimum number of arguments required. */
int args_max; /* The maximum number of arguments allowed. */
const char *name; /* Keyword name. */
const char *usage; /* Usage text to be printed in case of an error. */
};
#define FLT_OT_PARSE_WARNING(f, ...) \
ha_warning("parsing [%s:%d] : " FLT_OT_FMT_TYPE FLT_OT_FMT_NAME "'" f "'\n", ##__VA_ARGS__);
#define FLT_OT_PARSE_ALERT(f, ...) \
do { \
ha_alert("parsing [%s:%d] : " FLT_OT_FMT_TYPE FLT_OT_FMT_NAME "'" f "'\n", ##__VA_ARGS__); \
\
retval |= ERR_ABORT | ERR_ALERT; \
} while (0)
#define FLT_OT_POST_PARSE_ALERT(f, ...) \
FLT_OT_PARSE_ALERT(f, flt_ot_current_config->cfg_file, ##__VA_ARGS__)
#define FLT_OT_PARSE_ERR(e,f, ...) \
do { \
if (*(e) == NULL) \
(void)memprintf((e), f, ##__VA_ARGS__); \
\
retval |= ERR_ABORT | ERR_ALERT; \
} while (0)
#define FLT_OT_PARSE_IFERR_ALERT() \
do { \
if (err == NULL) \
break; \
\
FLT_OT_PARSE_ALERT("%s", file, linenum, err); \
FLT_OT_ERR_FREE(err); \
} while (0)
#endif /* _OPENTRACING_PARSER_H_ */
/*
* Local variables:
* c-indent-level: 8
* c-basic-offset: 8
* End:
*
* vi: noexpandtab shiftwidth=8 tabstop=8
*/

View file

@ -0,0 +1,39 @@
/***
* Copyright 2020 HAProxy Technologies
*
* This file is part of the HAProxy OpenTracing filter.
*
* 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.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#ifndef _OPENTRACING_POOL_H_
#define _OPENTRACING_POOL_H_
void *flt_ot_pool_alloc(struct pool_head *pool, size_t size, bool flag_clear, char **err);
void *flt_ot_pool_strndup(struct pool_head *pool, const char *s, size_t size, char **err);
void flt_ot_pool_free(struct pool_head *pool, void **ptr);
struct buffer *flt_ot_trash_alloc(bool flag_clear, char **err);
void flt_ot_trash_free(struct buffer **ptr);
#endif /* _OPENTRACING_POOL_H_ */
/*
* Local variables:
* c-indent-level: 8
* c-basic-offset: 8
* End:
*
* vi: noexpandtab shiftwidth=8 tabstop=8
*/

View file

@ -0,0 +1,141 @@
/***
* Copyright 2020 HAProxy Technologies
*
* This file is part of the HAProxy OpenTracing filter.
*
* 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.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#ifndef _OPENTRACING_SCOPE_H_
#define _OPENTRACING_SCOPE_H_
#define FLT_OT_SCOPE_SPAN_FINISH_REQ "*req*"
#define FLT_OT_SCOPE_SPAN_FINISH_RES "*res*"
#define FLT_OT_SCOPE_SPAN_FINISH_ALL "*"
#define FLT_OT_RT_CTX(a) ((struct flt_ot_runtime_context *)(a))
#define FLT_OT_DBG_SCOPE_SPAN(f,a) \
FLT_OT_DBG(3, "%s%p:{ '%s' %zu %u %hhu %p %d %p %p }", \
(f), (a), FLT_OT_STR_HDR_ARGS(a, id), (a)->smp_opt_dir, \
(a)->flag_finish, (a)->span, (a)->ref_type, (a)->ref_span, (a)->ref_ctx)
#define FLT_OT_DBG_SCOPE_CONTEXT(f,a) \
FLT_OT_DBG(3, "%s%p:{ '%s' %zu %u %hhu %p }", \
(f), (a), FLT_OT_STR_HDR_ARGS(a, id), (a)->smp_opt_dir, \
(a)->flag_finish, (a)->context)
#define FLT_OT_DBG_SCOPE_DATA(f,a) \
FLT_OT_DBG(3, "%s%p:{ %p %d %p %p %d }", \
(f), (a), (a)->tags, (a)->num_tags, (a)->baggage, (a)->log_fields, (a)->num_log_fields)
#define FLT_OT_DBG_RUNTIME_CONTEXT(f,a) \
FLT_OT_DBG(3, "%s%p:{ %p %p { %016" PRIx64 " %016" PRIx64 " '%s' } %hhu %hhu 0x%02hhx 0x%08x %s %s }", \
(f), (a), (a)->stream, (a)->filter, (a)->uuid.u64[0], (a)->uuid.u64[1], (a)->uuid.s, (a)->flag_harderr, \
(a)->flag_disabled, (a)->logging, (a)->analyzers, flt_ot_list_debug(&((a)->spans)), \
flt_ot_list_debug(&((a)->contexts)))
#define FLT_OT_CONST_STR_HDR(a) \
struct { \
const char *a; \
size_t a##_len; \
}
struct flt_ot_scope_data {
struct otc_tag tags[FLT_OT_MAXTAGS]; /* Defined tags. */
int num_tags; /* The number of tags used. */
struct otc_text_map *baggage; /* Defined baggage. */
struct otc_log_field log_fields[OTC_MAXLOGFIELDS]; /* Defined logs. */
int num_log_fields; /* The number of log fields used. */
};
/* flt_ot_runtime_context->spans */
struct flt_ot_scope_span {
FLT_OT_CONST_STR_HDR(id); /* The span operation name/len. */
uint smp_opt_dir; /* SMP_OPT_DIR_RE(Q|S) */
bool flag_finish; /* Whether the span is marked for completion. */
struct otc_span *span; /* The current span. */
otc_span_reference_type_t ref_type; /* Span reference type. */
struct otc_span *ref_span; /* Span to which the current span refers. */
struct otc_span_context *ref_ctx; /* Span context to which the current span refers. */
struct list list; /* Used to chain this structure. */
};
/* flt_ot_runtime_context->contexts */
struct flt_ot_scope_context {
FLT_OT_CONST_STR_HDR(id); /* The span context name/len. */
uint smp_opt_dir; /* SMP_OPT_DIR_RE(Q|S) */
bool flag_finish; /* Whether the span context is marked for completion. */
struct otc_span_context *context; /* The current span context. */
struct list list; /* Used to chain this structure. */
};
struct flt_ot_uuid {
union {
uint64_t u64[2];
uint8_t u8[16];
struct {
uint32_t time_low;
uint16_t time_mid;
uint16_t time_hi_and_version;
uint16_t clock_seq;
uint64_t node : 48;
} __attribute__((packed));
};
char s[40];
};
/* The runtime filter context attached to a stream. */
struct flt_ot_runtime_context {
struct stream *stream; /* The stream to which the filter is attached. */
struct filter *filter; /* The OpenTracing filter. */
struct flt_ot_uuid uuid; /* Randomly generated UUID. */
bool flag_harderr; /* [0 1] */
bool flag_disabled; /* [0 1] */
uint8_t logging; /* [0 1 3] */
uint analyzers; /* Executed channel analyzers. */
struct list spans; /* The scope spans. */
struct list contexts; /* The scope contexts. */
};
#ifndef DEBUG_OT
# define flt_ot_pools_info() while (0)
#else
void flt_ot_pools_info(void);
#endif
struct flt_ot_runtime_context *flt_ot_runtime_context_init(struct stream *s, struct filter *f, char **err);
void flt_ot_runtime_context_free(struct filter *f);
struct flt_ot_scope_span *flt_ot_scope_span_init(struct flt_ot_runtime_context *rt_ctx, const char *id, size_t id_len, otc_span_reference_type_t ref_type, const char *ref_id, size_t ref_id_len, uint dir, char **err);
void flt_ot_scope_span_free(struct flt_ot_scope_span **ptr);
struct flt_ot_scope_context *flt_ot_scope_context_init(struct flt_ot_runtime_context *rt_ctx, struct otc_tracer *tracer, const char *id, size_t id_len, const struct otc_text_map *text_map, uint dir, char **err);
void flt_ot_scope_context_free(struct flt_ot_scope_context **ptr);
void flt_ot_scope_data_free(struct flt_ot_scope_data *ptr);
int flt_ot_scope_finish_mark(const struct flt_ot_runtime_context *rt_ctx, const char *id, size_t id_len);
void flt_ot_scope_finish_marked(const struct flt_ot_runtime_context *rt_ctx, const struct timespec *ts_finish);
void flt_ot_scope_free_unused(struct flt_ot_runtime_context *rt_ctx, struct channel *chn);
#endif /* _OPENTRACING_SCOPE_H_ */
/*
* Local variables:
* c-indent-level: 8
* c-basic-offset: 8
* End:
*
* vi: noexpandtab shiftwidth=8 tabstop=8
*/

View file

@ -0,0 +1,109 @@
/***
* Copyright 2020 HAProxy Technologies
*
* This file is part of the HAProxy OpenTracing filter.
*
* 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.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#ifndef _OPENTRACING_UTIL_H_
#define _OPENTRACING_UTIL_H_
#define HTTP_METH_STR_OPTIONS "OPTIONS"
#define HTTP_METH_STR_GET "GET"
#define HTTP_METH_STR_HEAD "HEAD"
#define HTTP_METH_STR_POST "POST"
#define HTTP_METH_STR_PUT "PUT"
#define HTTP_METH_STR_DELETE "DELETE"
#define HTTP_METH_STR_TRACE "TRACE"
#define HTTP_METH_STR_CONNECT "CONNECT"
/* Defined in include/haproxy/channel-t.h. */
#define FLT_OT_AN_DEFINES \
FLT_OT_AN_DEF(AN_REQ_INSPECT_FE) \
FLT_OT_AN_DEF(AN_REQ_WAIT_HTTP) \
FLT_OT_AN_DEF(AN_REQ_HTTP_BODY) \
FLT_OT_AN_DEF(AN_REQ_HTTP_PROCESS_FE) \
FLT_OT_AN_DEF(AN_REQ_SWITCHING_RULES) \
FLT_OT_AN_DEF(AN_REQ_INSPECT_BE) \
FLT_OT_AN_DEF(AN_REQ_HTTP_PROCESS_BE) \
FLT_OT_AN_DEF(AN_REQ_HTTP_TARPIT) \
FLT_OT_AN_DEF(AN_REQ_SRV_RULES) \
FLT_OT_AN_DEF(AN_REQ_HTTP_INNER) \
FLT_OT_AN_DEF(AN_REQ_PRST_RDP_COOKIE) \
FLT_OT_AN_DEF(AN_REQ_STICKING_RULES) \
FLT_OT_AN_DEF(AN_REQ_HTTP_XFER_BODY) \
FLT_OT_AN_DEF(AN_REQ_WAIT_CLI) \
FLT_OT_AN_DEF(AN_RES_INSPECT) \
FLT_OT_AN_DEF(AN_RES_WAIT_HTTP) \
FLT_OT_AN_DEF(AN_RES_STORE_RULES) \
FLT_OT_AN_DEF(AN_RES_HTTP_PROCESS_BE) \
FLT_OT_AN_DEF(AN_RES_HTTP_PROCESS_FE) \
FLT_OT_AN_DEF(AN_RES_HTTP_XFER_BODY) \
FLT_OT_AN_DEF(AN_RES_WAIT_CLI)
#define FLT_OT_PROXIES_LIST_START() \
do { \
struct flt_conf *fconf; \
struct proxy *px; \
\
for (px = proxies_list; px != NULL; px = px->next) \
list_for_each_entry(fconf, &(px->filter_configs), list) \
if (fconf->id == ot_flt_id) { \
struct flt_ot_conf *conf = fconf->conf;
#define FLT_OT_PROXIES_LIST_END() \
} \
} while (0)
#ifdef DEBUG_OT
# define FLT_OT_ARGS_DUMP() do { if (flt_ot_debug.level & (1 << 2)) flt_ot_args_dump(args); } while (0)
#else
# define FLT_OT_ARGS_DUMP() while (0)
#endif
#ifndef DEBUG_OT
# define flt_ot_filters_dump() while (0)
#else
void flt_ot_args_dump(char **args);
void flt_ot_filters_dump(void);
const char *flt_ot_chn_label(const struct channel *chn);
const char *flt_ot_pr_mode(const struct stream *s);
const char *flt_ot_stream_pos(const struct stream *s);
const char *flt_ot_type(const struct filter *f);
const char *flt_ot_analyzer(uint an_bit);
const char *flt_ot_str_hex(const void *data, size_t size);
const char *flt_ot_str_ctrl(const void *data, size_t size);
const char *flt_ot_list_debug(const struct list *head);
#endif
ssize_t flt_ot_chunk_add(struct buffer *chk, const void *src, size_t n, char **err);
int flt_ot_args_count(char **args);
void flt_ot_args_to_str(char **args, int idx, char **str);
double flt_ot_strtod(const char *nptr, double limit_min, double limit_max, char **err);
int64_t flt_ot_strtoll(const char *nptr, int64_t limit_min, int64_t limit_max, char **err);
int flt_ot_sample_to_str(const struct sample_data *data, char *value, size_t size, char **err);
int flt_ot_sample_to_value(const char *key, const struct sample_data *data, struct otc_value *value, char **err);
int flt_ot_sample_add(struct stream *s, uint dir, struct flt_ot_conf_sample *sample, struct flt_ot_scope_data *data, int type, char **err);
#endif /* _OPENTRACING_UTIL_H_ */
/*
* Local variables:
* c-indent-level: 8
* c-basic-offset: 8
* End:
*
* vi: noexpandtab shiftwidth=8 tabstop=8
*/

View file

@ -0,0 +1,49 @@
/***
* Copyright 2020 HAProxy Technologies
*
* This file is part of the HAProxy OpenTracing filter.
*
* 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.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#ifndef _OPENTRACING_VARS_H_
#define _OPENTRACING_VARS_H_
#define FLT_OT_VARS_SCOPE "txn"
#define FLT_OT_VAR_CHAR_DASH 'D'
#define FLT_OT_VAR_CHAR_SPACE 'S'
#ifndef DEBUG_OT
# define flt_ot_vars_dump(...) while (0)
#else
void flt_ot_vars_dump(struct stream *s);
#endif
int flt_ot_var_register(const char *scope, const char *prefix, const char *name, char **err);
int flt_ot_var_set(struct stream *s, const char *scope, const char *prefix, const char *name, const char *value, uint opt, char **err);
int flt_ot_var_unset(struct stream *s, const char *scope, const char *prefix, const char *name, uint opt, char **err);
int flt_ot_vars_unset(struct stream *s, const char *scope, const char *prefix, uint opt, char **err);
int flt_ot_var_get(struct stream *s, const char *scope, const char *prefix, const char *name, char **value, uint opt, char **err);
struct otc_text_map *flt_ot_vars_get(struct stream *s, const char *scope, const char *prefix, uint opt, char **err);
#endif /* _OPENTRACING_VARS_H_ */
/*
* Local variables:
* c-indent-level: 8
* c-basic-offset: 8
* End:
*
* vi: noexpandtab shiftwidth=8 tabstop=8
*/

View file

@ -0,0 +1,395 @@
/***
* Copyright 2020 HAProxy Technologies
*
* This file is part of the HAProxy OpenTracing filter.
*
* 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.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include "include.h"
/***
* NAME
* flt_ot_cli_set_msg -
*
* ARGUMENTS
* appctx -
* err -
* msg -
* cli_state -
*
* DESCRIPTION
* -
*
* RETURN VALUE
* This function does not return a value.
*/
static void cmn_cli_set_msg(struct appctx *appctx, char *err, char *msg, int cli_state)
{
FLT_OT_FUNC("%p, %p, %p, %d", appctx, err, msg, cli_state);
if ((appctx == NULL) || ((err == NULL) && (msg == NULL)))
FLT_OT_RETURN();
appctx->ctx.cli.err = (err == NULL) ? msg : err;
appctx->st0 = (appctx->ctx.cli.err == NULL) ? CLI_ST_PROMPT : cli_state;
FLT_OT_DBG(1, "err(%d): \"%s\"", appctx->st0, appctx->ctx.cli.err);
FLT_OT_RETURN();
}
#ifdef DEBUG_OT
/***
* NAME
* flt_ot_cli_parse_debug -
*
* ARGUMENTS
* args -
* payload -
* appctx -
* private -
*
* DESCRIPTION
* -
*
* RETURN VALUE
* -
*/
static int flt_ot_cli_parse_debug(char **args, char *payload, struct appctx *appctx, void *private)
{
char *err = NULL, *msg = NULL;
uint8_t value;
int retval = 0;
FLT_OT_FUNC("%p, \"%s\", %p, %p", args, payload, appctx, private);
FLT_OT_ARGS_DUMP();
if (FLT_OT_ARG_ISVALID(2)) {
value = flt_ot_strtoll(args[2], 0, 255, &err);
if (err == NULL) {
_HA_ATOMIC_STORE(&(flt_ot_debug.level), value);
(void)memprintf(&msg, FLT_OT_CLI_CMD " : debug level set to %hhu", value);
} else {
retval = 1;
}
} else {
value = _HA_ATOMIC_LOAD(&(flt_ot_debug.level));
(void)memprintf(&msg, FLT_OT_CLI_CMD " : current debug level is %hhu", value);
}
cmn_cli_set_msg(appctx, err, msg, CLI_ST_PRINT_FREE);
FLT_OT_RETURN(retval);
}
#endif /* DEBUG_OT */
/***
* NAME
* flt_ot_cli_parse_disabled -
*
* ARGUMENTS
* args -
* payload -
* appctx -
* private -
*
* DESCRIPTION
* -
*
* RETURN VALUE
* -
*/
static int flt_ot_cli_parse_disabled(char **args, char *payload, struct appctx *appctx, void *private)
{
char *msg = NULL;
bool value = (uintptr_t)private;
int retval = 0;
FLT_OT_FUNC("%p, \"%s\", %p, %p", args, payload, appctx, private);
FLT_OT_ARGS_DUMP();
FLT_OT_PROXIES_LIST_START() {
_HA_ATOMIC_STORE(&(conf->tracer->flag_disabled), value);
(void)memprintf(&msg, "%s%s" FLT_OT_CLI_CMD " : filter %sabled", FLT_OT_CLI_MSG_CAT(msg), value ? "dis" : "en");
} FLT_OT_PROXIES_LIST_END();
cmn_cli_set_msg(appctx, NULL, msg, CLI_ST_PRINT_FREE);
FLT_OT_RETURN(retval);
}
/***
* NAME
* flt_ot_cli_parse_option -
*
* ARGUMENTS
* args -
* payload -
* appctx -
* private -
*
* DESCRIPTION
* -
*
* RETURN VALUE
* -
*/
static int flt_ot_cli_parse_option(char **args, char *payload, struct appctx *appctx, void *private)
{
char *msg = NULL;
bool value = (uintptr_t)private;
int retval = 0;
FLT_OT_FUNC("%p, \"%s\", %p, %p", args, payload, appctx, private);
FLT_OT_ARGS_DUMP();
FLT_OT_PROXIES_LIST_START() {
_HA_ATOMIC_STORE(&(conf->tracer->flag_harderr), value);
(void)memprintf(&msg, "%s%s" FLT_OT_CLI_CMD " : filter set %s-errors", FLT_OT_CLI_MSG_CAT(msg), value ? "hard" : "soft");
} FLT_OT_PROXIES_LIST_END();
cmn_cli_set_msg(appctx, NULL, msg, CLI_ST_PRINT_FREE);
FLT_OT_RETURN(retval);
}
/***
* NAME
* flt_ot_cli_parse_logging -
*
* ARGUMENTS
* args -
* payload -
* appctx -
* private -
*
* DESCRIPTION
* -
*
* RETURN VALUE
* -
*/
static int flt_ot_cli_parse_logging(char **args, char *payload, struct appctx *appctx, void *private)
{
char *err = NULL, *msg = NULL;
uint8_t value;
int retval = 0;
FLT_OT_FUNC("%p, \"%s\", %p, %p", args, payload, appctx, private);
FLT_OT_ARGS_DUMP();
if (FLT_OT_ARG_ISVALID(2)) {
if (strcasecmp(args[2], FLT_OT_CLI_LOGGING_OFF) == 0) {
value = FLT_OT_LOGGING_OFF;
}
else if (strcasecmp(args[2], FLT_OT_CLI_LOGGING_ON) == 0) {
value = FLT_OT_LOGGING_ON;
}
else if (strcasecmp(args[2], FLT_OT_CLI_LOGGING_NOLOGNORM) == 0) {
value = FLT_OT_LOGGING_ON | FLT_OT_LOGGING_NOLOGNORM;
}
else {
(void)memprintf(&err, "'%s' : invalid value, use <" FLT_OT_CLI_LOGGING_OFF " | " FLT_OT_CLI_LOGGING_ON " | " FLT_OT_CLI_LOGGING_NOLOGNORM ">", args[2]);
retval = 1;
}
if (retval == 0) {
FLT_OT_PROXIES_LIST_START() {
_HA_ATOMIC_STORE(&(conf->tracer->logging), value);
(void)memprintf(&msg, "%s%s" FLT_OT_CLI_CMD " : logging is %s", FLT_OT_CLI_MSG_CAT(msg), FLT_OT_CLI_LOGGING_STATE(value));
} FLT_OT_PROXIES_LIST_END();
}
} else {
FLT_OT_PROXIES_LIST_START() {
value = _HA_ATOMIC_LOAD(&(conf->tracer->logging));
(void)memprintf(&msg, "%s%s" FLT_OT_CLI_CMD " : logging is currently %s", FLT_OT_CLI_MSG_CAT(msg), FLT_OT_CLI_LOGGING_STATE(value));
} FLT_OT_PROXIES_LIST_END();
}
cmn_cli_set_msg(appctx, err, msg, CLI_ST_PRINT_FREE);
FLT_OT_RETURN(retval);
}
/***
* NAME
* flt_ot_cli_parse_rate -
*
* ARGUMENTS
* args -
* payload -
* appctx -
* private -
*
* DESCRIPTION
* -
*
* RETURN VALUE
* -
*/
static int flt_ot_cli_parse_rate(char **args, char *payload, struct appctx *appctx, void *private)
{
char *err = NULL, *msg = NULL;
uint32_t value;
int retval = 0;
FLT_OT_FUNC("%p, \"%s\", %p, %p", args, payload, appctx, private);
FLT_OT_ARGS_DUMP();
if (FLT_OT_ARG_ISVALID(2)) {
value = FLT_OT_FLOAT_U32(flt_ot_strtod(args[2], 0.0, FLT_OT_RATE_LIMIT_MAX, &err), FLT_OT_RATE_LIMIT_MAX);
if (err == NULL) {
FLT_OT_PROXIES_LIST_START() {
_HA_ATOMIC_STORE(&(conf->tracer->rate_limit), value);
(void)memprintf(&msg, "%s%s" FLT_OT_CLI_CMD " : rate limit set to %.2f", FLT_OT_CLI_MSG_CAT(msg), FLT_OT_U32_FLOAT(value, FLT_OT_RATE_LIMIT_MAX));
} FLT_OT_PROXIES_LIST_END();
} else {
retval = 1;
}
} else {
FLT_OT_PROXIES_LIST_START() {
value = _HA_ATOMIC_LOAD(&(conf->tracer->rate_limit));
(void)memprintf(&msg, "%s%s" FLT_OT_CLI_CMD " : current rate limit is %.2f", FLT_OT_CLI_MSG_CAT(msg), FLT_OT_U32_FLOAT(value, FLT_OT_RATE_LIMIT_MAX));
} FLT_OT_PROXIES_LIST_END();
}
cmn_cli_set_msg(appctx, err, msg, CLI_ST_PRINT_FREE);
FLT_OT_RETURN(retval);
}
/***
* NAME
* flt_ot_cli_parse_status -
*
* ARGUMENTS
* args -
* payload -
* appctx -
* private -
*
* DESCRIPTION
* -
*
* RETURN VALUE
* -
*/
static int flt_ot_cli_parse_status(char **args, char *payload, struct appctx *appctx, void *private)
{
const char *nl = "";
char *msg = NULL;
int retval = 0;
FLT_OT_FUNC("%p, \"%s\", %p, %p", args, payload, appctx, private);
FLT_OT_ARGS_DUMP();
flt_ot_filters_dump();
(void)memprintf(&msg, " " FLT_OT_OPT_NAME " filter status\n" FLT_OT_STR_DASH_78);
#ifdef DEBUG_OT
(void)memprintf(&msg, "%s\n debug level: 0x%02hhx\n", msg, flt_ot_debug.level);
#endif
FLT_OT_PROXIES_LIST_START() {
(void)memprintf(&msg, "%s\n%s filter %s\n", msg, nl, conf->id);
(void)memprintf(&msg, "%s configuration: %s\n", msg, conf->cfg_file);
(void)memprintf(&msg, "%s disable count: %" PRIu64 " %" PRIu64 "\n\n", msg, conf->cnt.disabled[0], conf->cnt.disabled[1]);
(void)memprintf(&msg, "%s tracer %s\n", msg, conf->tracer->id);
(void)memprintf(&msg, "%s configuration: %s\n", msg, conf->tracer->config);
(void)memprintf(&msg, "%s plugin: %s\n", msg, conf->tracer->plugin);
(void)memprintf(&msg, "%s rate limit: %.2f %%\n", msg, FLT_OT_U32_FLOAT(conf->tracer->rate_limit, FLT_OT_RATE_LIMIT_MAX));
(void)memprintf(&msg, "%s hard errors: %s\n", msg, FLT_OT_STR_FLAG_YN(conf->tracer->flag_harderr));
(void)memprintf(&msg, "%s disabled: %s\n", msg, FLT_OT_STR_FLAG_YN(conf->tracer->flag_disabled));
(void)memprintf(&msg, "%s logging: %s\n", msg, FLT_OT_CLI_LOGGING_STATE(conf->tracer->logging));
(void)memprintf(&msg, "%s analyzers: %08x", msg, conf->tracer->analyzers);
nl = "\n";
} FLT_OT_PROXIES_LIST_END();
cmn_cli_set_msg(appctx, NULL, msg, CLI_ST_PRINT_FREE);
FLT_OT_RETURN(retval);
}
static struct cli_kw_list cli_kws = { { }, {
#ifdef DEBUG_OT
{ { FLT_OT_CLI_CMD, "debug", NULL }, FLT_OT_CLI_CMD " debug [level] : set the OT filter debug level (default: get current debug level)", flt_ot_cli_parse_debug, NULL, NULL, NULL, 0 },
#endif
{ { FLT_OT_CLI_CMD, "disable", NULL }, FLT_OT_CLI_CMD " disable : disable the OT filter", flt_ot_cli_parse_disabled, NULL, NULL, (void *)1, 0 },
{ { FLT_OT_CLI_CMD, "enable", NULL }, FLT_OT_CLI_CMD " enable : enable the OT filter", flt_ot_cli_parse_disabled, NULL, NULL, (void *)0, 0 },
{ { FLT_OT_CLI_CMD, "soft-errors", NULL }, FLT_OT_CLI_CMD " soft-errors : turning off hard-errors mode", flt_ot_cli_parse_option, NULL, NULL, (void *)0, 0 },
{ { FLT_OT_CLI_CMD, "hard-errors", NULL }, FLT_OT_CLI_CMD " hard-errors : enabling hard-errors mode", flt_ot_cli_parse_option, NULL, NULL, (void *)1, 0 },
{ { FLT_OT_CLI_CMD, "logging", NULL }, FLT_OT_CLI_CMD " logging [state] : set logging state (default: get current logging state)", flt_ot_cli_parse_logging, NULL, NULL, NULL, 0 },
{ { FLT_OT_CLI_CMD, "rate", NULL }, FLT_OT_CLI_CMD " rate [value] : set the rate limit (default: get current rate value)", flt_ot_cli_parse_rate, NULL, NULL, NULL, 0 },
{ { FLT_OT_CLI_CMD, "status", NULL }, FLT_OT_CLI_CMD " status : show the OT filter status", flt_ot_cli_parse_status, NULL, NULL, NULL, 0 },
{ /* END */ }
}};
/***
* NAME
* flt_ot_cli_init -
*
* ARGUMENTS
* This function takes no arguments.
*
* DESCRIPTION
* -
*
* RETURN VALUE
* This function does not return a value.
*/
void flt_ot_cli_init(void)
{
FLT_OT_FUNC("");
/* Register CLI keywords. */
cli_register_kw(&cli_kws);
FLT_OT_RETURN();
}
/*
* Local variables:
* c-indent-level: 8
* c-basic-offset: 8
* End:
*
* vi: noexpandtab shiftwidth=8 tabstop=8
*/

View file

@ -0,0 +1,766 @@
/***
* Copyright 2020 HAProxy Technologies
*
* This file is part of the HAProxy OpenTracing filter.
*
* 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.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include "include.h"
/***
* NAME
* flt_ot_conf_hdr_init -
*
* ARGUMENTS
* size -
* id -
* linenum -
* head -
* err -
*
* DESCRIPTION
* -
*
* RETURN VALUE
* -
*/
static void *flt_ot_conf_hdr_init(size_t size, const char *id, int linenum, struct list *head, char **err)
{
struct flt_ot_conf_hdr *retptr = NULL, *ptr;
FLT_OT_FUNC("%zu, \"%s\", %d, %p, %p:%p", size, id, linenum, head, FLT_OT_DPTR_ARGS(err));
if (head != NULL)
list_for_each_entry(ptr, head, list)
if (strcmp(ptr->id, id) == 0) {
FLT_OT_ERR("'%s' : already defined", id);
FLT_OT_RETURN(retptr);
}
retptr = FLT_OT_CALLOC(1, size);
if (retptr != NULL) {
retptr->id_len = strlen(id);
if (retptr->id_len >= FLT_OT_ID_MAXLEN)
FLT_OT_ERR("'%s' : name too long", id);
else
retptr->id = FLT_OT_STRDUP(id);
if (retptr->id == NULL)
FLT_OT_FREE_CLEAR(retptr);
}
if (retptr != NULL) {
retptr->cfg_line = linenum;
if (head != NULL)
LIST_ADDQ(head, &(retptr->list));
} else {
FLT_OT_ERR("out of memory");
}
FLT_OT_RETURN(retptr);
}
/***
* NAME
* flt_ot_conf_ph_init -
*
* ARGUMENTS
* id -
* linenum -
* head -
* err -
*
* DESCRIPTION
* -
*
* RETURN VALUE
* -
*/
struct flt_ot_conf_ph *flt_ot_conf_ph_init(const char *id, int linenum, struct list *head, char **err)
{
struct flt_ot_conf_ph *retptr;
FLT_OT_FUNC("\"%s\", %d, %p, %p:%p", id, linenum, head, FLT_OT_DPTR_ARGS(err));
retptr = flt_ot_conf_hdr_init(sizeof(*retptr), id, linenum, head, err);
if (retptr != NULL)
FLT_OT_DBG_CONF_PH("- init ", retptr);
FLT_OT_RETURN(retptr);
}
/***
* NAME
* flt_ot_conf_ph_free -
*
* ARGUMENTS
* ptr -
*
* DESCRIPTION
* -
*
* RETURN VALUE
* This function does not return a value.
*/
void flt_ot_conf_ph_free(struct flt_ot_conf_ph **ptr)
{
FLT_OT_FUNC("%p:%p", FLT_OT_DPTR_ARGS(ptr));
if ((ptr == NULL) || (*ptr == NULL))
FLT_OT_RETURN();
FLT_OT_DBG_CONF_PH("- free ", *ptr);
FLT_OT_FREE((*ptr)->id);
FLT_OT_LIST_DEL(&((*ptr)->list));
FLT_OT_FREE_CLEAR(*ptr);
FLT_OT_RETURN();
}
/***
* NAME
* flt_ot_conf_sample_expr_init -
*
* ARGUMENTS
* id -
* linenum -
* head -
* err -
*
* DESCRIPTION
* -
*
* RETURN VALUE
* -
*/
struct flt_ot_conf_sample_expr *flt_ot_conf_sample_expr_init(const char *id, int linenum, struct list *head, char **err)
{
struct flt_ot_conf_sample_expr *retptr;
FLT_OT_FUNC("\"%s\", %d, %p, %p:%p", id, linenum, head, FLT_OT_DPTR_ARGS(err));
retptr = flt_ot_conf_hdr_init(sizeof(*retptr), id, linenum, head, err);
if (retptr != NULL)
FLT_OT_DBG_CONF_SAMPLE_EXPR("- init ", retptr);
FLT_OT_RETURN(retptr);
}
/***
* NAME
* flt_ot_conf_sample_expr_free -
*
* ARGUMENTS
* ptr -
*
* DESCRIPTION
* -
*
* RETURN VALUE
* This function does not return a value.
*/
void flt_ot_conf_sample_expr_free(struct flt_ot_conf_sample_expr **ptr)
{
FLT_OT_FUNC("%p:%p", FLT_OT_DPTR_ARGS(ptr));
if ((ptr == NULL) || (*ptr == NULL))
FLT_OT_RETURN();
FLT_OT_DBG_CONF_SAMPLE_EXPR("- free ", *ptr);
FLT_OT_FREE((*ptr)->value);
release_sample_expr((*ptr)->expr);
FLT_OT_LIST_DEL(&((*ptr)->list));
FLT_OT_FREE_CLEAR(*ptr);
FLT_OT_RETURN();
}
/***
* NAME
* flt_ot_conf_sample_init -
*
* ARGUMENTS
* args -
* linenum -
* head -
* err -
*
* DESCRIPTION
* -
*
* RETURN VALUE
* -
*/
struct flt_ot_conf_sample *flt_ot_conf_sample_init(char **args, int linenum, struct list *head, char **err)
{
struct flt_ot_conf_sample *retptr;
FLT_OT_FUNC("%p, %d, %p, %p:%p", args, linenum, head, FLT_OT_DPTR_ARGS(err));
retptr = flt_ot_conf_hdr_init(sizeof(*retptr), args[1], linenum, head, err);
if (retptr == NULL)
FLT_OT_RETURN(retptr);
flt_ot_args_to_str(args, 2, &(retptr->value));
if (retptr->value == NULL) {
FLT_OT_FREE_CLEAR(retptr);
FLT_OT_RETURN(retptr);
}
retptr->num_exprs = flt_ot_args_count(args) - 2;
LIST_INIT(&(retptr->exprs));
FLT_OT_DBG_CONF_SAMPLE("- init ", retptr);
FLT_OT_RETURN(retptr);
}
/***
* NAME
* flt_ot_conf_sample_free -
*
* ARGUMENTS
* ptr -
*
* DESCRIPTION
* -
*
* RETURN VALUE
* This function does not return a value.
*/
void flt_ot_conf_sample_free(struct flt_ot_conf_sample **ptr)
{
FLT_OT_FUNC("%p:%p", FLT_OT_DPTR_ARGS(ptr));
if ((ptr == NULL) || (*ptr == NULL))
FLT_OT_RETURN();
FLT_OT_DBG_CONF_SAMPLE("- free ", *ptr);
FLT_OT_FREE((*ptr)->key);
FLT_OT_FREE((*ptr)->value);
FLT_OT_LIST_DESTROY(sample_expr, &((*ptr)->exprs));
FLT_OT_LIST_DEL(&((*ptr)->list));
FLT_OT_FREE_CLEAR(*ptr);
FLT_OT_RETURN();
}
/***
* NAME
* flt_ot_conf_str_init -
*
* ARGUMENTS
* id -
* linenum -
* head -
* err -
*
* DESCRIPTION
* -
*
* RETURN VALUE
* -
*/
struct flt_ot_conf_str *flt_ot_conf_str_init(const char *id, int linenum, struct list *head, char **err)
{
struct flt_ot_conf_str *retptr;
FLT_OT_FUNC("\"%s\", %d, %p, %p:%p", id, linenum, head, FLT_OT_DPTR_ARGS(err));
retptr = flt_ot_conf_hdr_init(sizeof(*retptr), id, linenum, head, err);
if (retptr != NULL)
FLT_OT_DBG_CONF_STR("- init ", retptr);
FLT_OT_RETURN(retptr);
}
/***
* NAME
* flt_ot_conf_str_free -
*
* ARGUMENTS
* ptr -
*
* DESCRIPTION
* -
*
* RETURN VALUE
* This function does not return a value.
*/
void flt_ot_conf_str_free(struct flt_ot_conf_str **ptr)
{
FLT_OT_FUNC("%p:%p", FLT_OT_DPTR_ARGS(ptr));
if ((ptr == NULL) || (*ptr == NULL))
FLT_OT_RETURN();
FLT_OT_DBG_CONF_STR("- free ", *ptr);
FLT_OT_FREE((*ptr)->str);
FLT_OT_LIST_DEL(&((*ptr)->list));
FLT_OT_FREE_CLEAR(*ptr);
FLT_OT_RETURN();
}
/***
* NAME
* flt_ot_conf_context_init -
*
* ARGUMENTS
* id -
* linenum -
* head -
* err -
*
* DESCRIPTION
* -
*
* RETURN VALUE
* -
*/
struct flt_ot_conf_context *flt_ot_conf_context_init(const char *id, int linenum, struct list *head, char **err)
{
struct flt_ot_conf_context *retptr;
FLT_OT_FUNC("\"%s\", %d, %p, %p:%p", id, linenum, head, FLT_OT_DPTR_ARGS(err));
retptr = flt_ot_conf_hdr_init(sizeof(*retptr), id, linenum, head, err);
if (retptr != NULL)
FLT_OT_DBG_CONF_CONTEXT("- init ", retptr);
FLT_OT_RETURN(retptr);
}
/***
* NAME
* flt_ot_conf_context_free -
*
* ARGUMENTS
* ptr -
*
* DESCRIPTION
* -
*
* RETURN VALUE
* This function does not return a value.
*/
void flt_ot_conf_context_free(struct flt_ot_conf_context **ptr)
{
FLT_OT_FUNC("%p:%p", FLT_OT_DPTR_ARGS(ptr));
if ((ptr == NULL) || (*ptr == NULL))
FLT_OT_RETURN();
FLT_OT_DBG_CONF_CONTEXT("- free ", *ptr);
FLT_OT_FREE((*ptr)->id);
FLT_OT_LIST_DEL(&((*ptr)->list));
FLT_OT_FREE_CLEAR(*ptr);
FLT_OT_RETURN();
}
/***
* NAME
* flt_ot_conf_span_init -
*
* ARGUMENTS
* id -
* linenum -
* head -
* err -
*
* DESCRIPTION
* -
*
* RETURN VALUE
* -
*/
struct flt_ot_conf_span *flt_ot_conf_span_init(const char *id, int linenum, struct list *head, char **err)
{
struct flt_ot_conf_span *retptr;
FLT_OT_FUNC("\"%s\", %d, %p, %p:%p", id, linenum, head, FLT_OT_DPTR_ARGS(err));
retptr = flt_ot_conf_hdr_init(sizeof(*retptr), id, linenum, head, err);
if (retptr == NULL)
FLT_OT_RETURN(retptr);
LIST_INIT(&(retptr->tags));
LIST_INIT(&(retptr->logs));
LIST_INIT(&(retptr->baggages));
FLT_OT_DBG_CONF_SPAN("- init ", retptr);
FLT_OT_RETURN(retptr);
}
/***
* NAME
* flt_ot_conf_span_free -
*
* ARGUMENTS
* ptr -
*
* DESCRIPTION
* -
*
* RETURN VALUE
* This function does not return a value.
*/
void flt_ot_conf_span_free(struct flt_ot_conf_span **ptr)
{
FLT_OT_FUNC("%p:%p", FLT_OT_DPTR_ARGS(ptr));
if ((ptr == NULL) || (*ptr == NULL))
FLT_OT_RETURN();
FLT_OT_DBG_CONF_SPAN("- free ", *ptr);
FLT_OT_FREE((*ptr)->id);
FLT_OT_FREE((*ptr)->ref_id);
FLT_OT_FREE((*ptr)->ctx_id);
FLT_OT_LIST_DESTROY(sample, &((*ptr)->tags));
FLT_OT_LIST_DESTROY(sample, &((*ptr)->logs));
FLT_OT_LIST_DESTROY(sample, &((*ptr)->baggages));
FLT_OT_LIST_DEL(&((*ptr)->list));
FLT_OT_FREE_CLEAR(*ptr);
FLT_OT_RETURN();
}
/***
* NAME
* flt_ot_conf_scope_init -
*
* ARGUMENTS
* id -
* linenum -
* head -
* err -
*
* DESCRIPTION
* -
*
* RETURN VALUE
* -
*/
struct flt_ot_conf_scope *flt_ot_conf_scope_init(const char *id, int linenum, struct list *head, char **err)
{
struct flt_ot_conf_scope *retptr = NULL;
FLT_OT_FUNC("\"%s\", %d, %p, %p:%p", id, linenum, head, FLT_OT_DPTR_ARGS(err));
retptr = flt_ot_conf_hdr_init(sizeof(*retptr), id, linenum, head, err);
if (retptr == NULL)
FLT_OT_RETURN(retptr);
LIST_INIT(&(retptr->acls));
LIST_INIT(&(retptr->contexts));
LIST_INIT(&(retptr->spans));
LIST_INIT(&(retptr->finish));
FLT_OT_DBG_CONF_SCOPE("- init ", retptr);
FLT_OT_RETURN(retptr);
}
/***
* NAME
* flt_ot_conf_scope_free -
*
* ARGUMENTS
* ptr -
*
* DESCRIPTION
* -
*
* RETURN VALUE
* This function does not return a value.
*/
void flt_ot_conf_scope_free(struct flt_ot_conf_scope **ptr)
{
struct acl *acl, *aclback;
FLT_OT_FUNC("%p:%p", FLT_OT_DPTR_ARGS(ptr));
if ((ptr == NULL) || (*ptr == NULL))
FLT_OT_RETURN();
FLT_OT_DBG_CONF_SCOPE("- free ", *ptr);
FLT_OT_FREE((*ptr)->id);
list_for_each_entry_safe(acl, aclback, &((*ptr)->acls), list) {
prune_acl(acl);
FLT_OT_LIST_DEL(&(acl->list));
FLT_OT_FREE(acl);
}
if ((*ptr)->cond != NULL) {
prune_acl_cond((*ptr)->cond);
FLT_OT_FREE((*ptr)->cond);
}
FLT_OT_LIST_DESTROY(context, &((*ptr)->contexts));
FLT_OT_LIST_DESTROY(span, &((*ptr)->spans));
FLT_OT_LIST_DESTROY(str, &((*ptr)->finish));
FLT_OT_LIST_DEL(&((*ptr)->list));
FLT_OT_FREE_CLEAR(*ptr);
FLT_OT_RETURN();
}
/***
* NAME
* flt_ot_conf_group_init -
*
* ARGUMENTS
* id -
* linenum -
* head -
* err -
*
* DESCRIPTION
* -
*
* RETURN VALUE
* -
*/
struct flt_ot_conf_group *flt_ot_conf_group_init(const char *id, int linenum, struct list *head, char **err)
{
struct flt_ot_conf_group *retptr;
FLT_OT_FUNC("\"%s\", %d, %p, %p:%p", id, linenum, head, FLT_OT_DPTR_ARGS(err));
retptr = flt_ot_conf_hdr_init(sizeof(*retptr), id, linenum, head, err);
if (retptr == NULL)
FLT_OT_RETURN(retptr);
LIST_INIT(&(retptr->ph_scopes));
FLT_OT_DBG_CONF_GROUP("- init ", retptr);
FLT_OT_RETURN(retptr);
}
/***
* NAME
* flt_ot_conf_group_free -
*
* ARGUMENTS
* ptr -
*
* DESCRIPTION
* -
*
* RETURN VALUE
* This function does not return a value.
*/
void flt_ot_conf_group_free(struct flt_ot_conf_group **ptr)
{
FLT_OT_FUNC("%p:%p", FLT_OT_DPTR_ARGS(ptr));
if ((ptr == NULL) || (*ptr == NULL))
FLT_OT_RETURN();
FLT_OT_DBG_CONF_GROUP("- free ", *ptr);
FLT_OT_FREE((*ptr)->id);
FLT_OT_LIST_DESTROY(ph_scope, &((*ptr)->ph_scopes));
FLT_OT_LIST_DEL(&((*ptr)->list));
FLT_OT_FREE_CLEAR(*ptr);
FLT_OT_RETURN();
}
/***
* NAME
* flt_ot_conf_tracer_init -
*
* ARGUMENTS
* id -
* linenum -
* err -
*
* DESCRIPTION
* -
*
* RETURN VALUE
* -
*/
struct flt_ot_conf_tracer *flt_ot_conf_tracer_init(const char *id, int linenum, char **err)
{
struct flt_ot_conf_tracer *retptr;
FLT_OT_FUNC("\"%s\", %d, %p:%p", id, linenum, FLT_OT_DPTR_ARGS(err));
retptr = flt_ot_conf_hdr_init(sizeof(*retptr), id, linenum, NULL, err);
if (retptr == NULL)
FLT_OT_RETURN(retptr);
retptr->rate_limit = FLT_OT_FLOAT_U32(FLT_OT_RATE_LIMIT_MAX, FLT_OT_RATE_LIMIT_MAX);
init_new_proxy(&(retptr->proxy_log));
LIST_INIT(&(retptr->acls));
LIST_INIT(&(retptr->ph_groups));
LIST_INIT(&(retptr->ph_scopes));
FLT_OT_DBG_CONF_TRACER("- init ", retptr);
FLT_OT_RETURN(retptr);
}
/***
* NAME
* flt_ot_conf_tracer_free -
*
* ARGUMENTS
* ptr -
*
* DESCRIPTION
* -
*
* RETURN VALUE
* This function does not return a value.
*/
void flt_ot_conf_tracer_free(struct flt_ot_conf_tracer **ptr)
{
struct acl *acl, *aclback;
struct logsrv *logsrv, *logsrvback;
FLT_OT_FUNC("%p:%p", FLT_OT_DPTR_ARGS(ptr));
if ((ptr == NULL) || (*ptr == NULL))
FLT_OT_RETURN();
FLT_OT_DBG_CONF_TRACER("- free ", *ptr);
FLT_OT_FREE((*ptr)->id);
FLT_OT_FREE((*ptr)->config);
FLT_OT_FREE((*ptr)->plugin);
FLT_OT_DBG(2, "- deleting acls list %s", flt_ot_list_debug(&((*ptr)->acls)));
list_for_each_entry_safe(acl, aclback, &((*ptr)->acls), list) {
prune_acl(acl);
FLT_OT_LIST_DEL(&(acl->list));
FLT_OT_FREE(acl);
}
FLT_OT_DBG(2, "- deleting proxy_log.logsrvs list %s", flt_ot_list_debug(&((*ptr)->proxy_log.logsrvs)));
list_for_each_entry_safe(logsrv, logsrvback, &((*ptr)->proxy_log.logsrvs), list) {
LIST_DEL(&(logsrv->list));
FLT_OT_FREE(logsrv);
}
FLT_OT_LIST_DESTROY(ph_group, &((*ptr)->ph_groups));
FLT_OT_LIST_DESTROY(ph_scope, &((*ptr)->ph_scopes));
FLT_OT_FREE_CLEAR(*ptr);
FLT_OT_RETURN();
}
/***
* NAME
* flt_ot_conf_init -
*
* ARGUMENTS
* px -
*
* DESCRIPTION
* -
*
* RETURN VALUE
* -
*/
struct flt_ot_conf *flt_ot_conf_init(struct proxy *px)
{
struct flt_ot_conf *retptr;
FLT_OT_FUNC("%p", px);
retptr = FLT_OT_CALLOC(1, sizeof(*retptr));
if (retptr == NULL)
FLT_OT_RETURN(retptr);
retptr->proxy = px;
LIST_INIT(&(retptr->groups));
LIST_INIT(&(retptr->scopes));
FLT_OT_DBG_CONF("- init ", retptr);
FLT_OT_RETURN(retptr);
}
/***
* NAME
* flt_ot_conf_free -
*
* ARGUMENTS
* ptr -
*
* DESCRIPTION
* -
*
* RETURN VALUE
* This function does not return a value.
*/
void flt_ot_conf_free(struct flt_ot_conf **ptr)
{
FLT_OT_FUNC("%p:%p", FLT_OT_DPTR_ARGS(ptr));
if ((ptr == NULL) || (*ptr == NULL))
FLT_OT_RETURN();
FLT_OT_DBG_CONF("- free ", *ptr);
FLT_OT_FREE((*ptr)->id);
FLT_OT_FREE((*ptr)->cfg_file);
flt_ot_conf_tracer_free(&((*ptr)->tracer));
FLT_OT_LIST_DESTROY(group, &((*ptr)->groups));
FLT_OT_LIST_DESTROY(scope, &((*ptr)->scopes));
FLT_OT_FREE_CLEAR(*ptr);
FLT_OT_RETURN();
}
/*
* Local variables:
* c-indent-level: 8
* c-basic-offset: 8
* End:
*
* vi: noexpandtab shiftwidth=8 tabstop=8
*/

View file

@ -0,0 +1,332 @@
/***
* Copyright 2020 HAProxy Technologies
*
* This file is part of the HAProxy OpenTracing filter.
*
* 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.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include "include.h"
#define FLT_OT_EVENT_DEF(a,b,c,d,e,f) { AN_##b##_##a, SMP_OPT_DIR_##b, SMP_VAL_FE_##c, SMP_VAL_BE_##d, e, f },
const struct flt_ot_event_data flt_ot_event_data[FLT_OT_EVENT_MAX] = { FLT_OT_EVENT_DEFINES };
#undef FLT_OT_EVENT_DEF
/***
* NAME
* flt_ot_scope_run_span -
*
* ARGUMENTS
* s -
* f -
* chn -
* dir -
* span -
* data -
* conf_span -
* ts -
* err -
*
* DESCRIPTION
* -
*
* RETURN VALUE
* Returns a negative value if an error occurs, 0 if it needs to wait,
* any other value otherwise.
*/
static int flt_ot_scope_run_span(struct stream *s, struct filter *f, struct channel *chn, uint dir, struct flt_ot_scope_span *span, struct flt_ot_scope_data *data, const struct flt_ot_conf_span *conf_span, const struct timespec *ts, char **err)
{
struct flt_ot_conf *conf = FLT_OT_CONF(f);
int retval = FLT_OT_RET_OK;
FLT_OT_FUNC("%p, %p, %p, %u, %p, %p, %p, %p, %p:%p", s, f, chn, dir, span, data, conf_span, ts, FLT_OT_DPTR_ARGS(err));
if (span == NULL)
FLT_OT_RETURN(retval);
if (span->span == NULL) {
span->span = ot_span_init(conf->tracer->tracer, span->id, ts, NULL, span->ref_type, FLT_OT_DEREF(span->ref_ctx, idx, -1), span->ref_span, data->tags, data->num_tags, err);
if (span->span == NULL)
retval = FLT_OT_RET_ERROR;
}
else if (data->num_tags > 0)
if (ot_span_tag(span->span, data->tags, data->num_tags) == -1)
retval = FLT_OT_RET_ERROR;
if ((span->span != NULL) && (data->baggage != NULL))
if (ot_span_set_baggage(span->span, data->baggage) == -1)
retval = FLT_OT_RET_ERROR;
if ((span->span != NULL) && (data->num_log_fields > 0))
if (ot_span_log(span->span, data->log_fields, data->num_log_fields) == -1)
retval = FLT_OT_RET_ERROR;
if ((span->span != NULL) && (conf_span->ctx_id != NULL)) {
struct otc_http_headers_writer writer;
struct otc_text_map *text_map = NULL;
struct otc_span_context *span_ctx;
span_ctx = ot_inject_http_headers(conf->tracer->tracer, span->span, &writer, err);
if (span_ctx != NULL) {
int i = 0;
if (conf_span->ctx_flags & (FLT_OT_CTX_USE_VARS | FLT_OT_CTX_USE_HEADERS)) {
for (text_map = &(writer.text_map); i < text_map->count; i++) {
if (!(conf_span->ctx_flags & FLT_OT_CTX_USE_VARS))
/* Do nothing. */;
else if (flt_ot_var_register(FLT_OT_VARS_SCOPE, conf_span->ctx_id, text_map->key[i], err) == -1)
retval = FLT_OT_RET_ERROR;
else if (flt_ot_var_set(s, FLT_OT_VARS_SCOPE, conf_span->ctx_id, text_map->key[i], text_map->value[i], dir, err) == -1)
retval = FLT_OT_RET_ERROR;
if (!(conf_span->ctx_flags & FLT_OT_CTX_USE_HEADERS))
/* Do nothing. */;
else if (flt_ot_http_header_set(chn, conf_span->ctx_id, text_map->key[i], text_map->value[i], err) == -1)
retval = FLT_OT_RET_ERROR;
}
}
span_ctx->destroy(&span_ctx);
otc_text_map_destroy(&text_map, OTC_TEXT_MAP_FREE_KEY | OTC_TEXT_MAP_FREE_VALUE);
}
}
FLT_OT_RETURN(retval);
}
/***
* NAME
* flt_ot_scope_run -
*
* ARGUMENTS
* s -
* f -
* chn -
* conf_scope -
* ts -
* dir -
* err -
*
* DESCRIPTION
* -
*
* RETURN VALUE
* Returns a negative value if an error occurs, 0 if it needs to wait,
* any other value otherwise.
*/
int flt_ot_scope_run(struct stream *s, struct filter *f, struct channel *chn, struct flt_ot_conf_scope *conf_scope, const struct timespec *ts, uint dir, char **err)
{
struct flt_ot_conf *conf = FLT_OT_CONF(f);
struct flt_ot_conf_context *conf_ctx;
struct flt_ot_conf_span *conf_span;
struct flt_ot_conf_str *finish;
struct timespec ts_now;
int retval = FLT_OT_RET_OK;
FLT_OT_FUNC("%p, %p, %p, %p, %p, %u, %p:%p", s, f, chn, conf_scope, ts, dir, FLT_OT_DPTR_ARGS(err));
FLT_OT_DBG(3, "channel: %s, mode: %s (%s)", flt_ot_chn_label(chn), flt_ot_pr_mode(s), flt_ot_stream_pos(s));
FLT_OT_DBG(3, "run scope '%s' %d", conf_scope->id, conf_scope->event);
FLT_OT_DBG_CONF_SCOPE("run scope ", conf_scope);
if (ts == NULL) {
(void)clock_gettime(CLOCK_MONOTONIC, &ts_now);
ts = &ts_now;
}
if (conf_scope->cond != NULL) {
enum acl_test_res res;
int rc;
res = acl_exec_cond(conf_scope->cond, s->be, s->sess, s, dir | SMP_OPT_FINAL);
rc = acl_pass(res);
if (conf_scope->cond->pol == ACL_COND_UNLESS)
rc = !rc;
FLT_OT_DBG(3, "the ACL rule %s", rc ? "matches" : "does not match");
/*
* If the rule does not match, the current scope is skipped.
*
* If it is a root span, further processing of the session is
* disabled. As soon as the first span is encountered which
* is marked as root, further search is interrupted.
*/
if (!rc) {
list_for_each_entry(conf_span, &(conf_scope->spans), list)
if (conf_span->flag_root) {
FLT_OT_DBG(0, "session disabled");
FLT_OT_RT_CTX(f->ctx)->flag_disabled = 1;
_HA_ATOMIC_ADD(conf->cnt.disabled + 0, 1);
break;
}
FLT_OT_RETURN(retval);
}
}
list_for_each_entry(conf_ctx, &(conf_scope->contexts), list) {
struct otc_text_map *text_map;
FLT_OT_DBG(3, "run context '%s' -> '%s'", conf_scope->id, conf_ctx->id);
FLT_OT_DBG_CONF_CONTEXT("run context ", conf_ctx);
/*
* The OpenTracing context is read from the HTTP header
* or from HAProxy variables.
*/
if (conf_ctx->flags & FLT_OT_CTX_USE_HEADERS)
text_map = flt_ot_http_headers_get(chn, conf_ctx->id, conf_ctx->id_len, err);
else
text_map = flt_ot_vars_get(s, FLT_OT_VARS_SCOPE, conf_ctx->id, dir, err);
if (text_map != NULL) {
if (flt_ot_scope_context_init(f->ctx, conf->tracer->tracer, conf_ctx->id, conf_ctx->id_len, text_map, dir, err) == NULL)
retval = FLT_OT_RET_ERROR;
otc_text_map_destroy(&text_map, OTC_TEXT_MAP_FREE_KEY | OTC_TEXT_MAP_FREE_VALUE);
} else {
retval = FLT_OT_RET_ERROR;
}
}
list_for_each_entry(conf_span, &(conf_scope->spans), list) {
struct flt_ot_scope_data data;
struct flt_ot_scope_span *span;
struct flt_ot_conf_sample *sample;
FLT_OT_DBG(3, "run span '%s' -> '%s'", conf_scope->id, conf_span->id);
FLT_OT_DBG_CONF_SPAN("run span ", conf_span);
(void)memset(&data, 0, sizeof(data));
span = flt_ot_scope_span_init(f->ctx, conf_span->id, conf_span->id_len, conf_span->ref_type, conf_span->ref_id, conf_span->ref_id_len, dir, err);
if (span == NULL)
retval = FLT_OT_RET_ERROR;
list_for_each_entry(sample, &(conf_span->tags), list) {
FLT_OT_DBG(3, "adding tag '%s' -> '%s'", sample->key, sample->value);
if (flt_ot_sample_add(s, dir, sample, &data, FLT_OT_EVENT_SAMPLE_TAG, err) == FLT_OT_RET_ERROR)
retval = FLT_OT_RET_ERROR;
}
list_for_each_entry(sample, &(conf_span->logs), list) {
FLT_OT_DBG(3, "adding log '%s' -> '%s'", sample->key, sample->value);
if (flt_ot_sample_add(s, dir, sample, &data, FLT_OT_EVENT_SAMPLE_LOG, err) == FLT_OT_RET_ERROR)
retval = FLT_OT_RET_ERROR;
}
list_for_each_entry(sample, &(conf_span->baggages), list) {
FLT_OT_DBG(3, "adding baggage '%s' -> '%s'", sample->key, sample->value);
if (flt_ot_sample_add(s, dir, sample, &data, FLT_OT_EVENT_SAMPLE_BAGGAGE, err) == FLT_OT_RET_ERROR)
retval = FLT_OT_RET_ERROR;
}
if (retval != FLT_OT_RET_ERROR)
if (flt_ot_scope_run_span(s, f, chn, dir, span, &data, conf_span, ts, err) == FLT_OT_RET_ERROR)
retval = FLT_OT_RET_ERROR;
flt_ot_scope_data_free(&data);
}
list_for_each_entry(finish, &(conf_scope->finish), list)
if (flt_ot_scope_finish_mark(f->ctx, finish->str, finish->str_len) == -1)
retval = FLT_OT_RET_ERROR;
flt_ot_scope_finish_marked(f->ctx, ts);
flt_ot_scope_free_unused(f->ctx, chn);
FLT_OT_RETURN(retval);
}
/***
* NAME
* flt_ot_event_run -
*
* ARGUMENTS
* s -
* f -
* chn -
* event -
* err -
*
* DESCRIPTION
* -
*
* RETURN VALUE
* Returns a negative value if an error occurs, 0 if it needs to wait,
* any other value otherwise.
*/
int flt_ot_event_run(struct stream *s, struct filter *f, struct channel *chn, int event, char **err)
{
struct flt_ot_conf *conf = FLT_OT_CONF(f);
struct flt_ot_conf_scope *conf_scope;
struct timespec ts;
int retval = FLT_OT_RET_OK;
FLT_OT_FUNC("%p, %p, %p, %d, %p:%p", s, f, chn, event, FLT_OT_DPTR_ARGS(err));
FLT_OT_DBG(3, "channel: %s, mode: %s (%s)", flt_ot_chn_label(chn), flt_ot_pr_mode(s), flt_ot_stream_pos(s));
FLT_OT_DBG(3, "run event '%s' %d", flt_ot_event_data[event].name, event);
#ifdef DEBUG_OT
_HA_ATOMIC_ADD(conf->cnt.event[event].htx + (htx_is_empty(htxbuf(&(chn->buf))) ? 1 : 0), 1);
#endif
FLT_OT_RT_CTX(f->ctx)->analyzers |= flt_ot_event_data[event].an_bit;
/* All spans should be created/completed at the same time. */
(void)clock_gettime(CLOCK_MONOTONIC, &ts);
/*
* It is possible that there are defined multiple scopes that use the
* same event. Therefore, there must not be a 'break' here, ie an
* exit from the 'for' loop.
*/
list_for_each_entry(conf_scope, &(conf->scopes), list) {
if (conf_scope->event != event)
/* Do nothing. */;
else if (!conf_scope->flag_used)
FLT_OT_DBG(3, "scope '%s' %d not used", conf_scope->id, conf_scope->event);
else if (flt_ot_scope_run(s, f, chn, conf_scope, &ts, flt_ot_event_data[event].smp_opt_dir, err) == FLT_OT_RET_ERROR)
retval = FLT_OT_RET_ERROR;
}
flt_ot_vars_dump(s);
flt_ot_http_headers_dump(chn);
FLT_OT_DBG(3, "event = %d, chn = %p, s->req = %p, s->res = %p", event, chn, &(s->req), &(s->res));
FLT_OT_RETURN(retval);
}
/*
* Local variables:
* c-indent-level: 8
* c-basic-offset: 8
* End:
*
* vi: noexpandtab shiftwidth=8 tabstop=8
*/

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,354 @@
/***
* Copyright 2020 HAProxy Technologies
*
* This file is part of the HAProxy OpenTracing filter.
*
* 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.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include "include.h"
#define FLT_OT_GROUP_DEF(a,b,c) { a, b, c },
const struct flt_ot_group_data flt_ot_group_data[] = { FLT_OT_GROUP_DEFINES };
#undef FLT_OT_GROUP_DEF
/***
* NAME
* flt_ot_group_action -
*
* ARGUMENTS
* rule -
* px -
* sess -
* s -
* opts -
*
* DESCRIPTION
* This is the action_ptr callback of a rule associated to the
* FLT_OT_ACTION_GROUP action.
*
* RETURN VALUE
* The function returns ACT_RET_CONT if processing is finished (with error or
* not), otherwise, it returns ACT_RET_YIELD if the action is in progress.
*/
static enum act_return flt_ot_group_action(struct act_rule *rule, struct proxy *px, struct session *sess, struct stream *s, int opts)
{
const struct filter *filter;
const struct flt_conf *fconf;
const struct flt_ot_conf *conf;
const struct flt_ot_conf_group *conf_group;
const struct flt_ot_runtime_context *rt_ctx = NULL;
const struct flt_ot_conf_ph *ph_scope;
char *err = NULL;
int i, rc;
FLT_OT_FUNC("%p, %p, %p, %p, %d", rule, px, sess, s, opts);
FLT_OT_DBG(3, "from: %d, arg.act %p:{ %p %p %p %p }", rule->from, &(rule->arg.act), rule->arg.act.p[0], rule->arg.act.p[1], rule->arg.act.p[2], rule->arg.act.p[3]);
fconf = rule->arg.act.p[FLT_OT_ARG_FLT_CONF];
conf = rule->arg.act.p[FLT_OT_ARG_CONF];
conf_group = ((const struct flt_ot_conf_ph *)(rule->arg.act.p[FLT_OT_ARG_GROUP]))->ptr;
if ((fconf == NULL) || (conf == NULL) || (conf_group == NULL)) {
FLT_OT_LOG(LOG_ERR, FLT_OT_ACTION_GROUP ": internal error, invalid group action");
FLT_OT_RETURN(ACT_RET_CONT);
}
if (conf->tracer->flag_disabled) {
FLT_OT_DBG(1, "filter '%s' disabled, group action '%s' ignored", conf->id, conf_group->id);
FLT_OT_RETURN(ACT_RET_CONT);
}
/* Find the OpenTracing filter instance from the current stream. */
list_for_each_entry(filter, &(s->strm_flt.filters), list)
if (filter->config == fconf) {
rt_ctx = filter->ctx;
break;
}
if (rt_ctx == NULL) {
FLT_OT_DBG(1, "cannot find filter, probably not attached to the stream");
FLT_OT_RETURN(ACT_RET_CONT);
}
else if (flt_ot_is_disabled(filter FLT_OT_DBG_ARGS(, -1))) {
FLT_OT_RETURN(ACT_RET_CONT);
}
else {
FLT_OT_DBG(3, "run group '%s'", conf_group->id);
FLT_OT_DBG_CONF_GROUP("run group ", conf_group);
}
/*
* Check the value of rule->from; in case it is incorrect,
* report an error.
*/
for (i = 0; i < FLT_OT_TABLESIZE(flt_ot_group_data); i++)
if (flt_ot_group_data[i].act_from == rule->from)
break;
if (i >= FLT_OT_TABLESIZE(flt_ot_group_data)) {
FLT_OT_LOG(LOG_ERR, FLT_OT_ACTION_GROUP ": internal error, invalid rule->from=%d", rule->from);
FLT_OT_RETURN(ACT_RET_CONT);
}
list_for_each_entry(ph_scope, &(conf_group->ph_scopes), list) {
rc = flt_ot_scope_run(s, rt_ctx->filter, &(s->res), ph_scope->ptr, NULL, SMP_OPT_DIR_RES, &err);
if ((rc == FLT_OT_RET_ERROR) && (opts & ACT_OPT_FINAL)) {
/* XXX */
}
}
FLT_OT_RETURN(ACT_RET_CONT);
}
/***
* NAME
* flt_ot_group_check -
*
* ARGUMENTS
* rule -
* px -
* err -
*
* DESCRIPTION
* This is the check_ptr callback of a rule associated to the
* FLT_OT_ACTION_GROUP action.
*
* RETURN VALUE
* The function returns 1 in success case, otherwise,
* it returns 0 and err is filled.
*/
static int flt_ot_group_check(struct act_rule *rule, struct proxy *px, char **err)
{
struct flt_conf *fconf_tmp, *fconf = NULL;
struct flt_ot_conf *conf;
struct flt_ot_conf_ph *ph_group;
const char *filter_id;
const char *group_id;
bool flag_found = 0;
int i;
FLT_OT_FUNC("%p, %p, %p:%p", rule, px, FLT_OT_DPTR_ARGS(err));
filter_id = rule->arg.act.p[FLT_OT_ARG_FILTER_ID];
group_id = rule->arg.act.p[FLT_OT_ARG_GROUP_ID];
FLT_OT_DBG(2, "checking filter_id='%s', group_id='%s'", filter_id, group_id);
/*
* Check the value of rule->from; in case it is incorrect,
* report an error.
*/
for (i = 0; i < FLT_OT_TABLESIZE(flt_ot_group_data); i++)
if (flt_ot_group_data[i].act_from == rule->from)
break;
if (i >= FLT_OT_TABLESIZE(flt_ot_group_data)) {
FLT_OT_ERR("internal error, unexpected rule->from=%d, please report this bug!", rule->from);
FLT_OT_RETURN(0);
}
/*
* Try to find the OpenTracing filter by checking all filters
* for the proxy <px>.
*/
list_for_each_entry(fconf_tmp, &(px->filter_configs), list) {
conf = fconf_tmp->conf;
if (fconf_tmp->id != ot_flt_id) {
/* This is not an OpenTracing filter. */
continue;
}
else if (strcmp(conf->id, filter_id) == 0) {
/* This is the good filter ID. */
fconf = fconf_tmp;
break;
}
}
if (fconf == NULL) {
FLT_OT_ERR("unable to find the OpenTracing filter '%s' used by the " FLT_OT_ACTION_GROUP " '%s'", filter_id, group_id);
FLT_OT_RETURN(0);
}
/*
* Attempt to find if the group is defined in the OpenTracing filter
* configuration.
*/
list_for_each_entry(ph_group, &(conf->tracer->ph_groups), list)
if (strcmp(ph_group->id, group_id) == 0) {
flag_found = 1;
break;
}
if (!flag_found) {
FLT_OT_ERR("unable to find group '%s' in the OpenTracing filter '%s' configuration", group_id, filter_id);
FLT_OT_RETURN(0);
}
FLT_OT_FREE_CLEAR(rule->arg.act.p[FLT_OT_ARG_FILTER_ID]);
FLT_OT_FREE_CLEAR(rule->arg.act.p[FLT_OT_ARG_GROUP_ID]);
rule->arg.act.p[FLT_OT_ARG_FLT_CONF] = fconf;
rule->arg.act.p[FLT_OT_ARG_CONF] = conf;
rule->arg.act.p[FLT_OT_ARG_GROUP] = ph_group;
FLT_OT_RETURN(1);
}
/***
* NAME
* flt_ot_group_release -
*
* ARGUMENTS
* rule -
*
* DESCRIPTION
* This is the release_ptr callback of a rule associated to the
* FLT_OT_ACTION_GROUP action.
*
* RETURN VALUE
* This function does not return a value.
*/
static void flt_ot_group_release(struct act_rule *rule)
{
FLT_OT_FUNC("%p", rule);
FLT_OT_RETURN();
}
/***
* NAME
* flt_ot_group_parse -
*
* ARGUMENTS
* args -
* cur_arg -
* px -
* rule -
* err -
*
* DESCRIPTION
* -
*
* RETURN VALUE
* Returns ACT_RET_PRS_ERR if an error occurs, ACT_RET_PRS_OK otherwise.
*/
static enum act_parse_ret flt_ot_group_parse(const char **args, int *cur_arg, struct proxy *px, struct act_rule *rule, char **err)
{
FLT_OT_FUNC("%p, %p, %p, %p, %p:%p", args, cur_arg, px, rule, FLT_OT_DPTR_ARGS(err));
if (!FLT_OT_ARG_ISVALID(*cur_arg) ||
!FLT_OT_ARG_ISVALID(*cur_arg + 1) ||
(FLT_OT_ARG_ISVALID(*cur_arg + 2) &&
(strcmp(args[*cur_arg + 2], FLT_OT_CONDITION_IF) != 0) &&
(strcmp(args[*cur_arg + 2], FLT_OT_CONDITION_UNLESS) != 0))) {
FLT_OT_ERR("expects: <filter-id> <group-id> [{ if | unless } ...]");
FLT_OT_RETURN(ACT_RET_PRS_ERR);
}
/* Copy the OpenTracing filter id. */
rule->arg.act.p[FLT_OT_ARG_FILTER_ID] = FLT_OT_STRDUP(args[*cur_arg]);
if (rule->arg.act.p[FLT_OT_ARG_FILTER_ID] == NULL) {
FLT_OT_ERR("%s : out of memory", args[*cur_arg]);
FLT_OT_RETURN(ACT_RET_PRS_ERR);
}
/* Copy the OpenTracing group id. */
rule->arg.act.p[FLT_OT_ARG_GROUP_ID] = FLT_OT_STRDUP(args[*cur_arg + 1]);
if (rule->arg.act.p[FLT_OT_ARG_GROUP_ID] == NULL) {
FLT_OT_ERR("%s : out of memory", args[*cur_arg + 1]);
FLT_OT_FREE_CLEAR(rule->arg.act.p[FLT_OT_ARG_FILTER_ID]);
FLT_OT_RETURN(ACT_RET_PRS_ERR);
}
rule->action = ACT_CUSTOM;
rule->action_ptr = flt_ot_group_action;
rule->check_ptr = flt_ot_group_check;
rule->release_ptr = flt_ot_group_release;
*cur_arg += 2;
FLT_OT_RETURN(ACT_RET_PRS_OK);
}
static struct action_kw_list tcp_req_action_kws = { ILH, {
{ FLT_OT_ACTION_GROUP, flt_ot_group_parse },
{ /* END */ },
}
};
INITCALL1(STG_REGISTER, tcp_req_cont_keywords_register, &tcp_req_action_kws);
static struct action_kw_list tcp_res_action_kws = { ILH, {
{ FLT_OT_ACTION_GROUP, flt_ot_group_parse },
{ /* END */ },
}
};
INITCALL1(STG_REGISTER, tcp_res_cont_keywords_register, &tcp_res_action_kws);
static struct action_kw_list http_req_action_kws = { ILH, {
{ FLT_OT_ACTION_GROUP, flt_ot_group_parse },
{ /* END */ },
}
};
INITCALL1(STG_REGISTER, http_req_keywords_register, &http_req_action_kws);
static struct action_kw_list http_res_action_kws = { ILH, {
{ FLT_OT_ACTION_GROUP, flt_ot_group_parse },
{ /* END */ },
}
};
INITCALL1(STG_REGISTER, http_res_keywords_register, &http_res_action_kws);
static struct action_kw_list http_after_res_actions_kws = { ILH, {
{ FLT_OT_ACTION_GROUP, flt_ot_group_parse },
{ /* END */ },
}
};
INITCALL1(STG_REGISTER, http_after_res_keywords_register, &http_after_res_actions_kws);
/*
* Local variables:
* c-indent-level: 8
* c-basic-offset: 8
* End:
*
* vi: noexpandtab shiftwidth=8 tabstop=8
*/

View file

@ -0,0 +1,291 @@
/***
* Copyright 2020 HAProxy Technologies
*
* This file is part of the HAProxy OpenTracing filter.
*
* 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.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include "include.h"
#ifdef DEBUG_OT
/***
* NAME
* flt_ot_http_headers_dump -
*
* ARGUMENTS
* chn -
*
* DESCRIPTION
* -
*
* RETURN VALUE
* This function does not return a value.
*/
void flt_ot_http_headers_dump(const struct channel *chn)
{
const struct htx *htx;
int32_t pos;
FLT_OT_FUNC("%p", chn);
if (chn == NULL)
FLT_OT_RETURN();
htx = htxbuf(&(chn->buf));
if (htx_is_empty(htx))
FLT_OT_RETURN();
for (pos = htx_get_first(htx); pos != -1; pos = htx_get_next(htx, pos)) {
struct htx_blk *blk = htx_get_blk(htx, pos);
enum htx_blk_type type = htx_get_blk_type(blk);
if (type == HTX_BLK_HDR) {
struct ist n = htx_get_blk_name(htx, blk);
struct ist v = htx_get_blk_value(htx, blk);
FLT_OT_DBG(2, "'%.*s: %.*s'", (int)n.len, n.ptr, (int)v.len, v.ptr);
}
else if (type == HTX_BLK_EOH)
break;
}
FLT_OT_RETURN();
}
#endif /* DEBUG_OT */
/***
* NAME
* flt_ot_http_headers_get -
*
* ARGUMENTS
* chn -
* prefix -
* len -
* err -
*
* DESCRIPTION
* This function is very similar to function http_action_set_header(), from
* the HAProxy source.
*
* RETURN VALUE
* -
*/
struct otc_text_map *flt_ot_http_headers_get(struct channel *chn, const char *prefix, size_t len, char **err)
{
const struct htx *htx;
size_t prefix_len = (!FLT_OT_STR_ISVALID(prefix) || (len == 0)) ? 0 : (len + 1);
int32_t pos;
struct otc_text_map *retptr = NULL;
FLT_OT_FUNC("%p, \"%s\", %zu, %p:%p", chn, prefix, len, FLT_OT_DPTR_ARGS(err));
if (chn == NULL)
FLT_OT_RETURN(retptr);
htx = htxbuf(&(chn->buf));
for (pos = htx_get_first(htx); pos != -1; pos = htx_get_next(htx, pos)) {
struct htx_blk *blk = htx_get_blk(htx, pos);
enum htx_blk_type type = htx_get_blk_type(blk);
if (type == HTX_BLK_HDR) {
struct ist v, n = htx_get_blk_name(htx, blk);
if ((prefix_len == 0) || ((n.len >= prefix_len) && (strncasecmp(n.ptr, prefix, len) == 0))) {
if (retptr == NULL) {
retptr = otc_text_map_new(NULL, 8);
if (retptr == NULL) {
FLT_OT_ERR("failed to create HTTP header data");
break;
}
}
v = htx_get_blk_value(htx, blk);
/*
* Here, an HTTP header (which is actually part
* of the span context is added to the text_map.
*
* Before adding, the prefix is removed from the
* HTTP header name.
*/
if (otc_text_map_add(retptr, n.ptr + prefix_len, n.len - prefix_len, v.ptr, v.len, OTC_TEXT_MAP_DUP_KEY | OTC_TEXT_MAP_DUP_VALUE) == -1) {
FLT_OT_ERR("failed to add HTTP header data");
otc_text_map_destroy(&retptr, OTC_TEXT_MAP_FREE_KEY | OTC_TEXT_MAP_FREE_VALUE);
break;
}
}
}
else if (type == HTX_BLK_EOH)
break;
}
ot_text_map_show(retptr);
if ((retptr != NULL) && (retptr->count == 0)) {
FLT_OT_DBG(2, "WARNING: no HTTP headers found");
otc_text_map_destroy(&retptr, OTC_TEXT_MAP_FREE_KEY | OTC_TEXT_MAP_FREE_VALUE);
}
FLT_OT_RETURN(retptr);
}
/***
* NAME
* flt_ot_http_header_set -
*
* ARGUMENTS
* chn -
* prefix -
* name -
* value -
* err -
*
* DESCRIPTION
* This function is very similar to function http_action_set_header(), from
* the HAProxy source.
*
* RETURN VALUE
* -
*/
int flt_ot_http_header_set(struct channel *chn, const char *prefix, const char *name, const char *value, char **err)
{
struct http_hdr_ctx ctx = { .blk = NULL };
struct ist ist_name;
struct buffer *buffer = NULL;
struct htx *htx;
int retval = -1;
FLT_OT_FUNC("%p, \"%s\", \"%s\", \"%s\", %p:%p", chn, prefix, name, value, FLT_OT_DPTR_ARGS(err));
if ((chn == NULL) || (!FLT_OT_STR_ISVALID(prefix) && !FLT_OT_STR_ISVALID(name)))
FLT_OT_RETURN(retval);
htx = htxbuf(&(chn->buf));
/*
* Very rare (about 1% of cases), htx is empty.
* In order to avoid segmentation fault, we exit this function.
*/
if (htx_is_empty(htx)) {
FLT_OT_ERR("HTX is empty");
FLT_OT_RETURN(retval);
}
if (!FLT_OT_STR_ISVALID(prefix)) {
ist_name.ptr = (char *)name;
ist_name.len = strlen(name);
}
else if (!FLT_OT_STR_ISVALID(name)) {
ist_name.ptr = (char *)prefix;
ist_name.len = strlen(prefix);
}
else {
buffer = flt_ot_trash_alloc(0, err);
if (buffer == NULL)
FLT_OT_RETURN(retval);
(void)chunk_printf(buffer, "%s-%s", prefix, name);
ist_name.ptr = buffer->area;
ist_name.len = buffer->data;
}
/* Remove all occurrences of the header. */
while (http_find_header(htx, ist(""), &ctx, 1) == 1) {
struct ist n = htx_get_blk_name(htx, ctx.blk);
#ifdef DEBUG_OT
struct ist v = htx_get_blk_value(htx, ctx.blk);
#endif
/*
* If the <name> parameter is not set, then remove all headers
* that start with the contents of the <prefix> parameter.
*/
if (!FLT_OT_STR_ISVALID(name))
n.len = ist_name.len;
if (isteqi(n, ist_name))
if (http_remove_header(htx, &ctx) == 1)
FLT_OT_DBG(3, "HTTP header '%.*s: %.*s' removed", (int)n.len, n.ptr, (int)v.len, v.ptr);
}
/*
* If the value pointer has a value of NULL, the HTTP header is not set
* after deletion.
*/
if (value == NULL) {
/* Do nothing. */
}
else if (http_add_header(htx, ist_name, ist(value)) == 1) {
retval = 0;
FLT_OT_DBG(3, "HTTP header '%s: %s' added", ist_name.ptr, value);
}
else {
FLT_OT_ERR("failed to set HTTP header '%s: %s'", ist_name.ptr, value);
}
flt_ot_trash_free(&buffer);
FLT_OT_RETURN(retval);
}
/***
* NAME
* flt_ot_http_headers_remove -
*
* ARGUMENTS
* chn -
* prefix -
* err -
*
* DESCRIPTION
* -
*
* RETURN VALUE
* -
*/
int flt_ot_http_headers_remove(struct channel *chn, const char *prefix, char **err)
{
int retval;
FLT_OT_FUNC("%p, \"%s\", %p:%p", chn, prefix, FLT_OT_DPTR_ARGS(err));
retval = flt_ot_http_header_set(chn, prefix, NULL, NULL, err);
FLT_OT_RETURN(retval);
}
/*
* Local variables:
* c-indent-level: 8
* c-basic-offset: 8
* End:
*
* vi: noexpandtab shiftwidth=8 tabstop=8
*/

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,223 @@
/***
* Copyright 2020 HAProxy Technologies
*
* This file is part of the HAProxy OpenTracing filter.
*
* 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.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include "include.h"
/***
* NAME
* flt_ot_pool_alloc -
*
* ARGUMENTS
* pool -
* size -
* flag_clear -
* err -
*
* DESCRIPTION
* -
*
* RETURN VALUE
* -
*/
void *flt_ot_pool_alloc(struct pool_head *pool, size_t size, bool flag_clear, char **err)
{
void *retptr;
FLT_OT_FUNC("%p, %zu, %hhu, %p:%p", pool, size, flag_clear, FLT_OT_DPTR_ARGS(err));
if (pool != NULL) {
retptr = pool_alloc_dirty(pool);
if (retptr != NULL)
FLT_OT_DBG(2, "POOL_ALLOC: %s:%d(%p %zu)", __func__, __LINE__, retptr, FLT_OT_DEREF(pool, size, size));
} else {
retptr = FLT_OT_MALLOC(size);
}
if (retptr == NULL)
FLT_OT_ERR("out of memory");
else if (flag_clear)
(void)memset(retptr, 0, size);
FLT_OT_RETURN(retptr);
}
/***
* NAME
* flt_ot_pool_strndup -
*
* ARGUMENTS
* pool -
* s -
* size -
* err -
*
* DESCRIPTION
* -
*
* RETURN VALUE
* -
*/
void *flt_ot_pool_strndup(struct pool_head *pool, const char *s, size_t size, char **err)
{
void *retptr;
FLT_OT_FUNC("%p, \"%.*s\", %zu, %p:%p", pool, (int)size, s, size, FLT_OT_DPTR_ARGS(err));
if (pool != NULL) {
retptr = pool_alloc_dirty(pool);
if (retptr != NULL) {
(void)memcpy(retptr, s, MIN(pool->size - 1, size));
((uint8_t *)retptr)[MIN(pool->size - 1, size)] = '\0';
}
} else {
retptr = FLT_OT_STRNDUP(s, size);
}
if (retptr != NULL)
FLT_OT_DBG(2, "POOL_STRNDUP: %s:%d(%p %zu)", __func__, __LINE__, retptr, FLT_OT_DEREF(pool, size, size));
else
FLT_OT_ERR("out of memory");
FLT_OT_RETURN(retptr);
}
/***
* NAME
* flt_ot_pool_free -
*
* ARGUMENTS
* pool -
* ptr -
*
* DESCRIPTION
* -
*
* RETURN VALUE
* This function does not return a value.
*/
void flt_ot_pool_free(struct pool_head *pool, void **ptr)
{
FLT_OT_FUNC("%p, %p:%p", pool, FLT_OT_DPTR_ARGS(ptr));
if ((ptr == NULL) || (*ptr == NULL))
FLT_OT_RETURN();
FLT_OT_DBG(2, "POOL_FREE: %s:%d(%p %u)", __func__, __LINE__, *ptr, FLT_OT_DEREF(pool, size, 0));
if (pool != NULL)
pool_free(pool, *ptr);
else
FLT_OT_FREE(*ptr);
*ptr = NULL;
FLT_OT_RETURN();
}
/***
* NAME
* flt_ot_trash_alloc -
*
* ARGUMENTS
* flag_clear -
* err -
*
* DESCRIPTION
* -
*
* RETURN VALUE
* This function does not return a value.
*/
struct buffer *flt_ot_trash_alloc(bool flag_clear, char **err)
{
struct buffer *retptr;
FLT_OT_FUNC("%hhu, %p:%p", flag_clear, FLT_OT_DPTR_ARGS(err));
#ifdef USE_TRASH_CHUNK
retptr = alloc_trash_chunk();
if (retptr != NULL)
FLT_OT_DBG(2, "TRASH_ALLOC: %s:%d(%p %zu)", __func__, __LINE__, retptr, retptr->size);
#else
retptr = FLT_OT_MALLOC(sizeof(*retptr));
if (retptr != NULL) {
chunk_init(retptr, FLT_OT_MALLOC(global.tune.bufsize), global.tune.bufsize);
if (retptr->area == NULL)
FLT_OT_FREE_CLEAR(retptr);
else
*(retptr->area) = '\0';
}
#endif
if (retptr == NULL)
FLT_OT_ERR("out of memory");
else if (flag_clear)
(void)memset(retptr->area, 0, retptr->size);
FLT_OT_RETURN(retptr);
}
/***
* NAME
* flt_ot_trash_free -
*
* ARGUMENTS
* ptr -
*
* DESCRIPTION
* -
*
* RETURN VALUE
* This function does not return a value.
*/
void flt_ot_trash_free(struct buffer **ptr)
{
FLT_OT_FUNC("%p:%p", FLT_OT_DPTR_ARGS(ptr));
if ((ptr == NULL) || (*ptr == NULL))
FLT_OT_RETURN();
FLT_OT_DBG(2, "TRASH_FREE: %s:%d(%p %zu)", __func__, __LINE__, *ptr, (*ptr)->size);
#ifdef USE_TRASH_CHUNK
free_trash_chunk(*ptr);
#else
FLT_OT_FREE((*ptr)->area);
FLT_OT_FREE(*ptr);
#endif
*ptr = NULL;
FLT_OT_RETURN();
}
/*
* Local variables:
* c-indent-level: 8
* c-basic-offset: 8
* End:
*
* vi: noexpandtab shiftwidth=8 tabstop=8
*/

View file

@ -0,0 +1,631 @@
/***
* Copyright 2020 HAProxy Technologies
*
* This file is part of the HAProxy OpenTracing filter.
*
* 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.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include "include.h"
static struct pool_head *pool_head_ot_scope_span = NULL;
static struct pool_head *pool_head_ot_scope_context = NULL;
static struct pool_head *pool_head_ot_runtime_context = NULL;
#ifdef USE_POOL_OT_SCOPE_SPAN
REGISTER_POOL(&pool_head_ot_scope_span, "ot_scope_span", sizeof(struct flt_ot_scope_span));
#endif
#ifdef USE_POOL_OT_SCOPE_CONTEXT
REGISTER_POOL(&pool_head_ot_scope_context, "ot_scope_context", sizeof(struct flt_ot_scope_context));
#endif
#ifdef USE_POOL_OT_RUNTIME_CONTEXT
REGISTER_POOL(&pool_head_ot_runtime_context, "ot_runtime_context", sizeof(struct flt_ot_runtime_context));
#endif
#ifdef DEBUG_OT
/***
* NAME
* flt_ot_pools_info -
*
* ARGUMENTS
* This function takes no arguments.
*
* DESCRIPTION
* -
*
* RETURN VALUE
* This function does not return a value.
*/
void flt_ot_pools_info(void)
{
/*
* In case we have some error in the configuration file,
* it is possible that this pool was not initialized.
*/
#ifdef USE_POOL_BUFFER
FLT_OT_DBG(2, "sizeof_pool(buffer) = %u", FLT_OT_DEREF(pool_head_buffer, size, 0));
#endif
#ifdef USE_TRASH_CHUNK
FLT_OT_DBG(2, "sizeof_pool(trash) = %u", FLT_OT_DEREF(pool_head_trash, size, 0));
#endif
#ifdef USE_POOL_OT_SCOPE_SPAN
FLT_OT_DBG(2, "sizeof_pool(ot_scope_span) = %u", pool_head_ot_scope_span->size);
#endif
#ifdef USE_POOL_OT_SCOPE_CONTEXT
FLT_OT_DBG(2, "sizeof_pool(ot_scope_context) = %u", pool_head_ot_scope_context->size);
#endif
#ifdef USE_POOL_OT_RUNTIME_CONTEXT
FLT_OT_DBG(2, "sizeof_pool(ot_runtime_context) = %u", pool_head_ot_runtime_context->size);
#endif
}
#endif /* DEBUG_OT */
/***
* NAME
* flt_ot_runtime_context_init -
*
* ARGUMENTS
* s -
* f -
* err -
*
* DESCRIPTION
* -
*
* RETURN VALUE
* -
*/
struct flt_ot_runtime_context *flt_ot_runtime_context_init(struct stream *s, struct filter *f, char **err)
{
const struct flt_ot_conf *conf = FLT_OT_CONF(f);
struct flt_ot_runtime_context *retptr = NULL;
FLT_OT_FUNC("%p, %p, %p:%p", s, f, FLT_OT_DPTR_ARGS(err));
retptr = flt_ot_pool_alloc(pool_head_ot_runtime_context, sizeof(*retptr), 1, err);
if (retptr == NULL)
FLT_OT_RETURN(retptr);
retptr->stream = s;
retptr->filter = f;
retptr->uuid.u64[0] = ha_random64();
retptr->uuid.u64[1] = ha_random64();
retptr->flag_harderr = conf->tracer->flag_harderr;
retptr->flag_disabled = conf->tracer->flag_disabled;
retptr->logging = conf->tracer->logging;
LIST_INIT(&(retptr->spans));
LIST_INIT(&(retptr->contexts));
(void)snprintf(retptr->uuid.s, sizeof(retptr->uuid.s), "%08x-%04hx-%04hx-%04hx-%012" PRIx64,
retptr->uuid.time_low,
retptr->uuid.time_mid,
(retptr->uuid.time_hi_and_version & UINT16_C(0xfff)) | UINT16_C(0x4000),
retptr->uuid.clock_seq | UINT16_C(0x8000),
(uint64_t)retptr->uuid.node);
if (flt_ot_var_register(FTL_OT_VAR_UUID, err) != -1)
(void)flt_ot_var_set(s, FTL_OT_VAR_UUID, retptr->uuid.s, SMP_OPT_DIR_REQ, err);
FLT_OT_DBG_RUNTIME_CONTEXT("session context: ", retptr);
FLT_OT_RETURN(retptr);
}
/***
* NAME
* flt_ot_runtime_context_free -
*
* ARGUMENTS
* f -
*
* DESCRIPTION
* -
*
* RETURN VALUE
* This function does not return a value.
*/
void flt_ot_runtime_context_free(struct filter *f)
{
struct flt_ot_runtime_context *rt_ctx = f->ctx;
FLT_OT_FUNC("%p", f);
if (rt_ctx == NULL)
FLT_OT_RETURN();
FLT_OT_DBG_RUNTIME_CONTEXT("session context: ", rt_ctx);
if (!LIST_ISEMPTY(&(rt_ctx->spans))) {
struct timespec ts;
struct flt_ot_scope_span *span, *span_back;
/* All spans should be completed at the same time. */
(void)clock_gettime(CLOCK_MONOTONIC, &ts);
list_for_each_entry_safe(span, span_back, &(rt_ctx->spans), list) {
ot_span_finish(&(span->span), &ts, NULL, NULL, NULL);
flt_ot_scope_span_free(&span);
}
}
if (!LIST_ISEMPTY(&(rt_ctx->contexts))) {
struct flt_ot_scope_context *ctx, *ctx_back;
list_for_each_entry_safe(ctx, ctx_back, &(rt_ctx->contexts), list)
flt_ot_scope_context_free(&ctx);
}
flt_ot_pool_free(pool_head_ot_runtime_context, &(f->ctx));
FLT_OT_RETURN();
}
/***
* NAME
* flt_ot_scope_span_init -
*
* ARGUMENTS
* rt_ctx -
* id -
* id_len -
* ref_type -
* ref_id -
* ref_id_len -
* dir -
* err -
*
* DESCRIPTION
* -
*
* RETURN VALUE
* -
*/
struct flt_ot_scope_span *flt_ot_scope_span_init(struct flt_ot_runtime_context *rt_ctx, const char *id, size_t id_len, otc_span_reference_type_t ref_type, const char *ref_id, size_t ref_id_len, uint dir, char **err)
{
struct otc_span *ref_span = NULL;
struct otc_span_context *ref_ctx = NULL;
struct flt_ot_scope_span *span, *retptr = NULL;
struct flt_ot_scope_context *ctx;
FLT_OT_FUNC("%p, \"%s\", %zu, %d, \"%s\", %zu, %u, %p:%p", rt_ctx, id, id_len, ref_type, ref_id, ref_id_len, dir, FLT_OT_DPTR_ARGS(err));
if ((rt_ctx == NULL) || (id == NULL))
FLT_OT_RETURN(retptr);
list_for_each_entry(span, &(rt_ctx->spans), list)
if ((span->id_len == id_len) && (memcmp(span->id, id, id_len) == 0)) {
FLT_OT_DBG(2, "found span %p", span);
FLT_OT_RETURN(span);
}
if (ref_id != NULL) {
list_for_each_entry(span, &(rt_ctx->spans), list)
if ((span->id_len == ref_id_len) && (memcmp(span->id, ref_id, ref_id_len) == 0)) {
ref_span = span->span;
break;
}
if (ref_span != NULL) {
FLT_OT_DBG(2, "found referenced span %p", span);
} else {
list_for_each_entry(ctx, &(rt_ctx->contexts), list)
if ((ctx->id_len == ref_id_len) && (memcmp(ctx->id, ref_id, ref_id_len) == 0)) {
ref_ctx = ctx->context;
break;
}
if (ref_ctx != NULL) {
FLT_OT_DBG(2, "found referenced context %p", ctx);
} else {
FLT_OT_ERR("cannot find referenced span/context '%s'", ref_id);
FLT_OT_RETURN(retptr);
}
}
}
retptr = flt_ot_pool_alloc(pool_head_ot_scope_span, sizeof(*retptr), 1, err);
if (retptr == NULL)
FLT_OT_RETURN(retptr);
retptr->id = id;
retptr->id_len = id_len;
retptr->smp_opt_dir = dir;
retptr->ref_type = ref_type;
retptr->ref_span = ref_span;
retptr->ref_ctx = ref_ctx;
LIST_ADD(&(rt_ctx->spans), &(retptr->list));
FLT_OT_DBG_SCOPE_SPAN("new span ", retptr);
FLT_OT_RETURN(retptr);
}
/***
* NAME
* flt_ot_scope_span_free -
*
* ARGUMENTS
* ptr -
*
* DESCRIPTION
* -
*
* RETURN VALUE
* This function does not return a value.
*/
void flt_ot_scope_span_free(struct flt_ot_scope_span **ptr)
{
FLT_OT_FUNC("%p:%p", FLT_OT_DPTR_ARGS(ptr));
if ((ptr == NULL) || (*ptr == NULL))
FLT_OT_RETURN();
FLT_OT_DBG_SCOPE_SPAN("", *ptr);
/* If the span is still active, do nothing. */
if ((*ptr)->span != NULL) {
FLT_OT_DBG(2, "cannot finish active span");
FLT_OT_RETURN();
}
FLT_OT_LIST_DEL(&((*ptr)->list));
flt_ot_pool_free(pool_head_ot_scope_span, (void **)ptr);
FLT_OT_RETURN();
}
/***
* NAME
* flt_ot_scope_context_init -
*
* ARGUMENTS
* rt_ctx -
* tracer -
* id -
* id_len -
* text_map -
* dir -
* err -
*
* DESCRIPTION
* -
*
* RETURN VALUE
* -
*/
struct flt_ot_scope_context *flt_ot_scope_context_init(struct flt_ot_runtime_context *rt_ctx, struct otc_tracer *tracer, const char *id, size_t id_len, const struct otc_text_map *text_map, uint dir, char **err)
{
struct otc_http_headers_reader reader;
struct otc_span_context *span_ctx;
struct flt_ot_scope_context *retptr = NULL;
FLT_OT_FUNC("%p, %p, \"%s\", %zu, %p, %u, %p:%p", rt_ctx, tracer, id, id_len, text_map, dir, FLT_OT_DPTR_ARGS(err));
if ((rt_ctx == NULL) || (tracer == NULL) || (id == NULL) || (text_map == NULL))
FLT_OT_RETURN(retptr);
list_for_each_entry(retptr, &(rt_ctx->contexts), list)
if ((retptr->id_len == id_len) && (memcmp(retptr->id, id, id_len) == 0)) {
FLT_OT_DBG(2, "found context %p", retptr);
FLT_OT_RETURN(retptr);
}
retptr = flt_ot_pool_alloc(pool_head_ot_scope_context, sizeof(*retptr), 1, err);
if (retptr == NULL)
FLT_OT_RETURN(retptr);
span_ctx = ot_extract_http_headers(tracer, &reader, text_map, err);
if (span_ctx == NULL) {
flt_ot_scope_context_free(&retptr);
FLT_OT_RETURN(retptr);
}
retptr->id = id;
retptr->id_len = id_len;
retptr->smp_opt_dir = dir;
retptr->context = span_ctx;
LIST_ADD(&(rt_ctx->contexts), &(retptr->list));
FLT_OT_DBG_SCOPE_CONTEXT("new context ", retptr);
FLT_OT_RETURN(retptr);
}
/***
* NAME
* flt_ot_scope_context_free -
*
* ARGUMENTS
* ptr -
*
* DESCRIPTION
* -
*
* RETURN VALUE
* This function does not return a value.
*/
void flt_ot_scope_context_free(struct flt_ot_scope_context **ptr)
{
FLT_OT_FUNC("%p:%p", FLT_OT_DPTR_ARGS(ptr));
if ((ptr == NULL) || (*ptr == NULL))
FLT_OT_RETURN();
FLT_OT_DBG_SCOPE_CONTEXT("", *ptr);
if ((*ptr)->context != NULL)
(*ptr)->context->destroy(&((*ptr)->context));
FLT_OT_LIST_DEL(&((*ptr)->list));
flt_ot_pool_free(pool_head_ot_scope_context, (void **)ptr);
FLT_OT_RETURN();
}
/***
* NAME
* flt_ot_scope_data_free -
*
* ARGUMENTS
* ptr -
*
* DESCRIPTION
* -
*
* RETURN VALUE
* This function does not return a value.
*/
void flt_ot_scope_data_free(struct flt_ot_scope_data *ptr)
{
int i;
FLT_OT_FUNC("%p", ptr);
if (ptr == NULL)
FLT_OT_RETURN();
FLT_OT_DBG_SCOPE_DATA("", ptr);
for (i = 0; i < ptr->num_tags; i++)
if (ptr->tags[i].value.type == otc_value_string)
FLT_OT_FREE_VOID(ptr->tags[i].value.value.string_value);
otc_text_map_destroy(&(ptr->baggage), OTC_TEXT_MAP_FREE_VALUE);
for (i = 0; i < ptr->num_log_fields; i++)
if (ptr->log_fields[i].value.type == otc_value_string)
FLT_OT_FREE_VOID(ptr->log_fields[i].value.value.string_value);
(void)memset(ptr, 0, sizeof(*ptr));
FLT_OT_RETURN();
}
/***
* NAME
* flt_ot_scope_finish_mark -
*
* ARGUMENTS
* rt_ctx -
* id -
* id_len -
*
* DESCRIPTION
* -
*
* RETURN VALUE
* -
*/
int flt_ot_scope_finish_mark(const struct flt_ot_runtime_context *rt_ctx, const char *id, size_t id_len)
{
struct flt_ot_scope_span *span;
struct flt_ot_scope_context *ctx;
int span_cnt = 0, ctx_cnt = 0, retval;
FLT_OT_FUNC("%p, \"%s\", %zu", rt_ctx, id, id_len);
if (FLT_OT_STR_CMP(FLT_OT_SCOPE_SPAN_FINISH_ALL, id, id_len)) {
list_for_each_entry(span, &(rt_ctx->spans), list) {
span->flag_finish = 1;
span_cnt++;
}
list_for_each_entry(ctx, &(rt_ctx->contexts), list) {
ctx->flag_finish = 1;
ctx_cnt++;
}
FLT_OT_DBG(2, "marked %d span(s), %d context(s)", span_cnt, ctx_cnt);
}
else if (FLT_OT_STR_CMP(FLT_OT_SCOPE_SPAN_FINISH_REQ, id, id_len)) {
list_for_each_entry(span, &(rt_ctx->spans), list)
if (span->smp_opt_dir == SMP_OPT_DIR_REQ) {
span->flag_finish = 1;
span_cnt++;
}
list_for_each_entry(ctx, &(rt_ctx->contexts), list)
if (ctx->smp_opt_dir == SMP_OPT_DIR_REQ) {
ctx->flag_finish = 1;
span_cnt++;
}
FLT_OT_DBG(2, "marked REQuest channel %d span(s), %d context(s)", span_cnt, ctx_cnt);
}
else if (FLT_OT_STR_CMP(FLT_OT_SCOPE_SPAN_FINISH_RES, id, id_len)) {
list_for_each_entry(span, &(rt_ctx->spans), list)
if (span->smp_opt_dir == SMP_OPT_DIR_RES) {
span->flag_finish = 1;
span_cnt++;
}
list_for_each_entry(ctx, &(rt_ctx->contexts), list)
if (ctx->smp_opt_dir == SMP_OPT_DIR_RES) {
ctx->flag_finish = 1;
ctx_cnt++;
}
FLT_OT_DBG(2, "marked RESponse channel %d span(s), %d context(s)", span_cnt, ctx_cnt);
}
else {
list_for_each_entry(span, &(rt_ctx->spans), list)
if ((span->id_len == id_len) && (memcmp(span->id, id, id_len) == 0)) {
span->flag_finish = 1;
span_cnt++;
break;
}
list_for_each_entry(ctx, &(rt_ctx->contexts), list)
if ((ctx->id_len == id_len) && (memcmp(ctx->id, id, id_len) == 0)) {
ctx->flag_finish = 1;
ctx_cnt++;
break;
}
if (span_cnt > 0)
FLT_OT_DBG(2, "marked span '%s'", id);
if (ctx_cnt > 0)
FLT_OT_DBG(2, "marked context '%s'", id);
if ((span_cnt + ctx_cnt) == 0)
FLT_OT_DBG(2, "cannot find span/context '%s'", id);
}
retval = span_cnt + ctx_cnt;
FLT_OT_RETURN(retval);
}
/***
* NAME
* flt_ot_scope_finish_marked -
*
* ARGUMENTS
* rt_ctx -
* ts_finish -
*
* DESCRIPTION
* Finish marked spans.
*
* RETURN VALUE
* This function does not return a value.
*/
void flt_ot_scope_finish_marked(const struct flt_ot_runtime_context *rt_ctx, const struct timespec *ts_finish)
{
struct flt_ot_scope_span *span;
struct flt_ot_scope_context *ctx;
FLT_OT_FUNC("%p, %p", rt_ctx, ts_finish);
list_for_each_entry(span, &(rt_ctx->spans), list)
if (span->flag_finish) {
FLT_OT_DBG_SCOPE_SPAN("finishing span ", span);
ot_span_finish(&(span->span), ts_finish, NULL, NULL, NULL);
span->flag_finish = 0;
}
list_for_each_entry(ctx, &(rt_ctx->contexts), list)
if (ctx->flag_finish) {
FLT_OT_DBG_SCOPE_CONTEXT("finishing context ", ctx);
if (ctx->context != NULL)
ctx->context->destroy(&(ctx->context));
ctx->flag_finish = 0;
}
FLT_OT_RETURN();
}
/***
* NAME
* flt_ot_scope_free_unused -
*
* ARGUMENTS
* rt_ctx -
* chn -
*
* DESCRIPTION
* -
*
* RETURN VALUE
* This function does not return a value.
*/
void flt_ot_scope_free_unused(struct flt_ot_runtime_context *rt_ctx, struct channel *chn)
{
FLT_OT_FUNC("%p", rt_ctx);
if (rt_ctx == NULL)
FLT_OT_RETURN();
if (!LIST_ISEMPTY(&(rt_ctx->spans))) {
struct flt_ot_scope_span *span, *span_back;
list_for_each_entry_safe(span, span_back, &(rt_ctx->spans), list)
if (span->span == NULL)
flt_ot_scope_span_free(&span);
}
if (!LIST_ISEMPTY(&(rt_ctx->contexts))) {
struct flt_ot_scope_context *ctx, *ctx_back;
list_for_each_entry_safe(ctx, ctx_back, &(rt_ctx->contexts), list)
if (ctx->context == NULL) {
/*
* All headers and variables associated with
* the context in question should be deleted.
*/
(void)flt_ot_http_headers_remove(chn, ctx->id, NULL);
(void)flt_ot_vars_unset(rt_ctx->stream, FLT_OT_VARS_SCOPE, ctx->id, ctx->smp_opt_dir, NULL);
flt_ot_scope_context_free(&ctx);
}
}
FLT_OT_DBG_RUNTIME_CONTEXT("session context: ", rt_ctx);
FLT_OT_RETURN();
}
/*
* Local variables:
* c-indent-level: 8
* c-basic-offset: 8
* End:
*
* vi: noexpandtab shiftwidth=8 tabstop=8
*/

View file

@ -0,0 +1,793 @@
/***
* Copyright 2020 HAProxy Technologies
*
* This file is part of the HAProxy OpenTracing filter.
*
* 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.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include "include.h"
#ifdef DEBUG_OT
/***
* NAME
* flt_ot_args_dump -
*
* ARGUMENTS
* args -
*
* DESCRIPTION
* -
*
* RETURN VALUE
* This function does not return a value.
*/
void flt_ot_args_dump(char **args)
{
int i, n;
for (n = 1; FLT_OT_ARG_ISVALID(n); n++);
(void)fprintf(stderr, FLT_OT_DBG_FMT("%.*sargs[%d]: { '%s' "), dbg_indent_level, FLT_OT_DBG_INDENT, n, args[0]);
for (i = 1; FLT_OT_ARG_ISVALID(i); i++)
(void)fprintf(stderr, "'%s' ", args[i]);
(void)fprintf(stderr, "}\n");
}
/***
* NAME
* flt_ot_filters_dump -
*
* ARGUMENTS
* This function takes no arguments.
*
* DESCRIPTION
* -
*
* RETURN VALUE
* This function does not return a value.
*/
void flt_ot_filters_dump(void)
{
struct flt_conf *fconf;
struct proxy *px;
FLT_OT_FUNC("");
for (px = proxies_list; px != NULL; px = px->next) {
FLT_OT_DBG(2, "proxy '%s'", px->id);
list_for_each_entry(fconf, &(px->filter_configs), list)
if (fconf->id == ot_flt_id) {
struct flt_ot_conf *conf = fconf->conf;
FLT_OT_DBG(2, " OT filter '%s'", conf->id);
}
}
FLT_OT_RETURN();
}
/***
* NAME
* flt_ot_chn_label -
*
* ARGUMENTS
* chn -
*
* DESCRIPTION
* -
*
* RETURN VALUE
* -
*/
const char *flt_ot_chn_label(const struct channel *chn)
{
return (chn->flags & CF_ISRESP) ? "RESponse" : "REQuest";
}
/***
* NAME
* flt_ot_pr_mode -
*
* ARGUMENTS
* s -
*
* DESCRIPTION
* -
*
* RETURN VALUE
* -
*/
const char *flt_ot_pr_mode(const struct stream *s)
{
struct proxy *px = (s->flags & SF_BE_ASSIGNED) ? s->be : strm_fe(s);
return (px->mode == PR_MODE_HTTP) ? "HTTP" : "TCP";
}
/***
* NAME
* flt_ot_stream_pos -
*
* ARGUMENTS
* s -
*
* DESCRIPTION
* -
*
* RETURN VALUE
* -
*/
const char *flt_ot_stream_pos(const struct stream *s)
{
return (s->flags & SF_BE_ASSIGNED) ? "backend" : "frontend";
}
/***
* NAME
* flt_ot_type -
*
* ARGUMENTS
* f -
*
* DESCRIPTION
* -
*
* RETURN VALUE
* -
*/
const char *flt_ot_type(const struct filter *f)
{
return (f->flags & FLT_FL_IS_BACKEND_FILTER) ? "backend" : "frontend";
}
/***
* NAME
* flt_ot_analyzer -
*
* ARGUMENTS
* an_bit -
*
* DESCRIPTION
* -
*
* RETURN VALUE
* -
*/
const char *flt_ot_analyzer(uint an_bit)
{
#define FLT_OT_AN_DEF(a) { a, #a },
static const struct {
uint an_bit;
const char *str;
} flt_ot_an[] = { FLT_OT_AN_DEFINES };
#undef FLT_OT_AN_DEF
const char *retptr = "invalid an_bit";
int i;
for (i = 0; i < FLT_OT_TABLESIZE(flt_ot_an); i++)
if (flt_ot_an[i].an_bit == an_bit) {
retptr = flt_ot_an[i].str;
break;
}
return retptr;
}
/***
* NAME
* flt_ot_str_hex -
*
* ARGUMENTS
* data -
* size -
*
* DESCRIPTION
* -
*
* RETURN VALUE
* -
*/
const char *flt_ot_str_hex(const void *data, size_t size)
{
static THREAD_LOCAL char retbuf[BUFSIZ];
const uint8_t *ptr = data;
size_t i;
if (data == NULL)
return "(null)";
else if (size == 0)
return "()";
for (i = 0, size <<= 1; (i < (sizeof(retbuf) - 2)) && (i < size); ptr++) {
retbuf[i++] = FLT_OT_NIBBLE_TO_HEX(*ptr >> 4);
retbuf[i++] = FLT_OT_NIBBLE_TO_HEX(*ptr & 0x0f);
}
retbuf[i] = '\0';
return retbuf;
}
/***
* NAME
* flt_ot_str_ctrl -
*
* ARGUMENTS
* data -
* size -
*
* DESCRIPTION
* -
*
* RETURN VALUE
* -
*/
const char *flt_ot_str_ctrl(const void *data, size_t size)
{
static THREAD_LOCAL char retbuf[BUFSIZ];
const uint8_t *ptr = data;
size_t i, n = 0;
if (data == NULL)
return "(null)";
else if (size == 0)
return "()";
for (i = 0; (n < (sizeof(retbuf) - 1)) && (i < size); i++)
retbuf[n++] = ((ptr[i] >= 0x20) && (ptr[i] <= 0x7e)) ? ptr[i] : '.';
retbuf[n] = '\0';
return retbuf;
}
/***
* NAME
* flt_ot_list_debug -
*
* ARGUMENTS
* head -
*
* DESCRIPTION
* -
*
* RETURN VALUE
* -
*/
const char *flt_ot_list_debug(const struct list *head)
{
FLT_OT_BUFFER_THR(retbuf, 4, 64, retptr);
if ((head == NULL) || LIST_ISEMPTY(head)) {
(void)strncpy(retptr, (head == NULL) ? "{ null list }" : "{ empty list }", sizeof(retbuf[0]));
}
else if (head->p == head->n) {
(void)snprintf(retptr, sizeof(retbuf[0]), "{ %p * 1 }", head->p);
}
else {
const struct list *ptr;
size_t count = 0;
for (ptr = head->n; ptr != head; ptr = ptr->n, count++);
(void)snprintf(retptr, sizeof(retbuf[0]), "{ %p %p %zu }", head->p, head->n, count);
}
return (retptr);
}
#endif /* DEBUG_OT */
/***
* NAME
* flt_ot_chunk_add -
*
* ARGUMENTS
* chk -
* src -
* n -
* err -
*
* DESCRIPTION
* -
*
* RETURN VALUE
* -
*/
ssize_t flt_ot_chunk_add(struct buffer *chk, const void *src, size_t n, char **err)
{
FLT_OT_FUNC("%p, %p, %zu, %p:%p", chk, src, n, FLT_OT_DPTR_ARGS(err));
if ((chk == NULL) || (src == NULL))
FLT_OT_RETURN(-1);
if (chk->area == NULL)
chunk_init(chk, FLT_OT_CALLOC(1, global.tune.bufsize), global.tune.bufsize);
if (chk->area == NULL) {
FLT_OT_ERR("out of memory");
FLT_OT_RETURN(-1);
}
else if (n > (chk->size - chk->data)) {
FLT_OT_ERR("chunk size too small");
FLT_OT_RETURN(-1);
}
(void)memcpy(chk->area + chk->data, src, n);
chk->data += n;
FLT_OT_RETURN(chk->data);
}
/***
* NAME
* flt_ot_args_count -
*
* ARGUMENTS
* args -
*
* DESCRIPTION
* -
*
* RETURN VALUE
* -
*/
int flt_ot_args_count(char **args)
{
int retval = 0;
if (args != NULL)
for ( ; FLT_OT_ARG_ISVALID(retval); retval++);
return retval;
}
/***
* NAME
* flt_ot_args_to_str -
*
* ARGUMENTS
* args -
* idx -
* str -
*
* DESCRIPTION
* -
*
* RETURN VALUE
* This function does not return a value.
*/
void flt_ot_args_to_str(char **args, int idx, char **str)
{
int i;
if ((args == NULL) || (*args == NULL))
return;
for (i = idx; FLT_OT_ARG_ISVALID(i); i++)
(void)memprintf(str, "%s%s%s", (*str == NULL) ? "" : *str, (i == idx) ? "" : " ", args[i]);
}
/***
* NAME
* flt_ot_strtod -
*
* ARGUMENTS
* nptr -
* limit_min -
* limit_max -
* err -
*
* DESCRIPTION
* -
*
* RETURN VALUE
* -
*/
double flt_ot_strtod(const char *nptr, double limit_min, double limit_max, char **err)
{
char *endptr = NULL;
double retval;
errno = 0;
retval = strtod(nptr, &endptr);
if ((errno != 0) || FLT_OT_STR_ISVALID(endptr))
FLT_OT_ERR("'%s' : invalid value", nptr);
else if (!FLT_OT_IN_RANGE(retval, limit_min, limit_max))
FLT_OT_ERR("'%s' : value out of range [%.2f, %.2f]", nptr, limit_min, limit_max);
return retval;
}
/***
* NAME
* flt_ot_strtoll -
*
* ARGUMENTS
* nptr -
* limit_min -
* limit_max -
* err -
*
* DESCRIPTION
* -
*
* RETURN VALUE
* -
*/
int64_t flt_ot_strtoll(const char *nptr, int64_t limit_min, int64_t limit_max, char **err)
{
char *endptr = NULL;
int64_t retval;
errno = 0;
retval = strtoll(nptr, &endptr, 0);
if ((errno != 0) || FLT_OT_STR_ISVALID(endptr))
FLT_OT_ERR("'%s' : invalid value", nptr);
else if (!FLT_OT_IN_RANGE(retval, limit_min, limit_max))
FLT_OT_ERR("'%s' : value out of range [%" PRId64 ", %" PRId64 "]", nptr, limit_min, limit_max);
return retval;
}
/***
* NAME
* flt_ot_sample_to_str -
*
* ARGUMENTS
* data -
* value -
* size -
* err -
*
* DESCRIPTION
* -
*
* RETURN VALUE
* -
*/
int flt_ot_sample_to_str(const struct sample_data *data, char *value, size_t size, char **err)
{
int retval = -1;
FLT_OT_FUNC("%p, %p, %zu, %p:%p", data, value, size, FLT_OT_DPTR_ARGS(err));
if ((data == NULL) || (value == NULL) || (size == 0))
FLT_OT_RETURN(retval);
*value = '\0';
if (data->type == SMP_T_ANY) {
FLT_OT_ERR("invalid sample data type %d", data->type);
}
else if (data->type == SMP_T_BOOL) {
value[0] = data->u.sint ? '1' : '0';
value[1] = '\0';
retval = 1;
}
else if (data->type == SMP_T_SINT) {
retval = snprintf(value, size, "%lld", data->u.sint);
}
else if (data->type == SMP_T_ADDR) {
/* This type is never used to qualify a sample. */
}
else if (data->type == SMP_T_IPV4) {
if (INET_ADDRSTRLEN > size)
FLT_OT_ERR("sample data size too large");
else if (inet_ntop(AF_INET, &(data->u.ipv4), value, INET_ADDRSTRLEN) == NULL)
FLT_OT_ERR("invalid IPv4 address");
else
retval = strlen(value);
}
else if (data->type == SMP_T_IPV6) {
if (INET6_ADDRSTRLEN > size)
FLT_OT_ERR("sample data size too large");
else if (inet_ntop(AF_INET6, &(data->u.ipv6), value, INET6_ADDRSTRLEN) == NULL)
FLT_OT_ERR("invalid IPv6 address");
else
retval = strlen(value);
}
else if (data->type == SMP_T_STR) {
if (data->u.str.data >= size) {
FLT_OT_ERR("sample data size too large");
}
else if (data->u.str.data > 0) {
retval = data->u.str.data;
(void)strncat(value, data->u.str.area, retval);
}
else {
/*
* There is no content to add but we will still return
* the correct status.
*/
retval = 0;
}
}
else if (data->type == SMP_T_BIN) {
FLT_OT_ERR("invalid sample data type %d", data->type);
}
else if (data->type != SMP_T_METH) {
FLT_OT_ERR("invalid sample data type %d", data->type);
}
else if (data->u.meth.meth == HTTP_METH_OPTIONS) {
retval = FLT_OT_STR_SIZE(HTTP_METH_STR_OPTIONS);
(void)memcpy(value, HTTP_METH_STR_OPTIONS, retval + 1);
}
else if (data->u.meth.meth == HTTP_METH_GET) {
retval = FLT_OT_STR_SIZE(HTTP_METH_STR_GET);
(void)memcpy(value, HTTP_METH_STR_GET, retval + 1);
}
else if (data->u.meth.meth == HTTP_METH_HEAD) {
retval = FLT_OT_STR_SIZE(HTTP_METH_STR_HEAD);
(void)memcpy(value, HTTP_METH_STR_HEAD, retval + 1);
}
else if (data->u.meth.meth == HTTP_METH_POST) {
retval = FLT_OT_STR_SIZE(HTTP_METH_STR_POST);
(void)memcpy(value, HTTP_METH_STR_POST, retval + 1);
}
else if (data->u.meth.meth == HTTP_METH_PUT) {
retval = FLT_OT_STR_SIZE(HTTP_METH_STR_PUT);
(void)memcpy(value, HTTP_METH_STR_PUT, retval + 1);
}
else if (data->u.meth.meth == HTTP_METH_DELETE) {
retval = FLT_OT_STR_SIZE(HTTP_METH_STR_DELETE);
(void)memcpy(value, HTTP_METH_STR_DELETE, retval + 1);
}
else if (data->u.meth.meth == HTTP_METH_TRACE) {
retval = FLT_OT_STR_SIZE(HTTP_METH_STR_TRACE);
(void)memcpy(value, HTTP_METH_STR_TRACE, retval + 1);
}
else if (data->u.meth.meth == HTTP_METH_CONNECT) {
retval = FLT_OT_STR_SIZE(HTTP_METH_STR_CONNECT);
(void)memcpy(value, HTTP_METH_STR_CONNECT, retval + 1);
}
else if (data->u.meth.meth == HTTP_METH_OTHER) {
if (data->u.meth.str.data >= size) {
FLT_OT_ERR("sample data size too large");
} else {
retval = data->u.meth.str.data;
(void)strncat(value, data->u.meth.str.area, retval);
}
}
else {
FLT_OT_ERR("invalid HTTP method");
}
FLT_OT_RETURN(retval);
}
/***
* NAME
* flt_ot_sample_to_value -
*
* ARGUMENTS
* key -
* data -
* value -
* err -
*
* DESCRIPTION
* -
*
* RETURN VALUE
* -
*/
int flt_ot_sample_to_value(const char *key, const struct sample_data *data, struct otc_value *value, char **err)
{
int retval = -1;
FLT_OT_FUNC("\"%s\", %p, %p, %p:%p", key, data, value, FLT_OT_DPTR_ARGS(err));
if ((data == NULL) || (value == NULL))
FLT_OT_RETURN(retval);
if (data->type == SMP_T_BOOL) {
value->type = otc_value_bool;
value->value.bool_value = data->u.sint ? 1 : 0;
retval = sizeof(value->value.bool_value);
}
else if (data->type == SMP_T_SINT) {
value->type = otc_value_int64;
value->value.int64_value = data->u.sint;
retval = sizeof(value->value.int64_value);
}
else {
value->type = otc_value_string;
value->value.string_value = FLT_OT_MALLOC(global.tune.bufsize);
if (value->value.string_value == NULL)
FLT_OT_ERR("out of memory");
else
retval = flt_ot_sample_to_str(data, (char *)value->value.string_value, global.tune.bufsize, err);
}
FLT_OT_RETURN(retval);
}
/***
* NAME
* flt_ot_sample_add -
*
* ARGUMENTS
* s -
* dir -
* sample -
* data -
* type -
* err -
*
* DESCRIPTION
* -
*
* RETURN VALUE
* Returns a negative value if an error occurs, 0 if it needs to wait,
* any other value otherwise.
*/
int flt_ot_sample_add(struct stream *s, uint dir, struct flt_ot_conf_sample *sample, struct flt_ot_scope_data *data, int type, char **err)
{
const struct flt_ot_conf_sample_expr *expr;
struct sample smp;
struct otc_value value;
struct buffer buffer;
int idx = 0, rc, retval = FLT_OT_RET_OK;
FLT_OT_FUNC("%p, %u, %p, %p, %d, %p:%p", s, dir, data, sample, type, FLT_OT_DPTR_ARGS(err));
FLT_OT_DBG_CONF_SAMPLE("sample ", sample);
(void)memset(&buffer, 0, sizeof(buffer));
list_for_each_entry(expr, &(sample->exprs), list) {
FLT_OT_DBG_CONF_SAMPLE_EXPR("sample expression ", expr);
(void)memset(&smp, 0, sizeof(smp));
/*
* If we have only one expression to process, then the data
* type that is the result of the expression is converted to
* an equivalent data type (if possible) that is written to
* the tracer.
*
* If conversion is not possible, or if we have multiple
* expressions to process, then the result is converted to
* a string and as such sent to the tracer.
*/
if (sample_process(s->be, s->sess, s, dir | SMP_OPT_FINAL, expr->expr, &smp) != NULL) {
FLT_OT_DBG(3, "data type %d: '%s'", smp.data.type, expr->value);
} else {
FLT_OT_DBG(2, "WARNING: failed to fetch '%s' value", expr->value);
/*
* In case the fetch failed, we will set the result
* (sample) to an empty static string.
*/
(void)memset(&(smp.data), 0, sizeof(smp.data));
smp.data.type = SMP_T_STR;
smp.data.u.str.area = "";
}
if ((sample->num_exprs == 1) && (type == FLT_OT_EVENT_SAMPLE_TAG)) {
if (flt_ot_sample_to_value(sample->key, &(smp.data), &value, err) == -1)
retval = FLT_OT_RET_ERROR;
} else {
if (buffer.area == NULL) {
chunk_init(&buffer, FLT_OT_CALLOC(1, global.tune.bufsize), global.tune.bufsize);
if (buffer.area == NULL) {
FLT_OT_ERR("out of memory");
retval = FLT_OT_RET_ERROR;
break;
}
}
rc = flt_ot_sample_to_str(&(smp.data), buffer.area + buffer.data, buffer.size - buffer.data, err);
if (rc == -1) {
retval = FLT_OT_RET_ERROR;
} else {
buffer.data += rc;
if (sample->num_exprs == ++idx) {
value.type = otc_value_string;
value.value.string_value = buffer.area;
}
}
}
}
if (retval == FLT_OT_RET_ERROR) {
/* Do nothing. */
}
else if (type == FLT_OT_EVENT_SAMPLE_TAG) {
struct otc_tag *tag = data->tags + data->num_tags++;
tag->key = sample->key;
(void)memcpy(&(tag->value), &value, sizeof(tag->value));
}
else if (type == FLT_OT_EVENT_SAMPLE_LOG) {
struct otc_log_field *log_field = data->log_fields + data->num_log_fields++;
log_field->key = sample->key;
(void)memcpy(&(log_field->value), &value, sizeof(log_field->value));
}
else {
if (data->baggage == NULL)
data->baggage = otc_text_map_new(NULL, FLT_OT_MAXBAGGAGES);
if (data->baggage == NULL) {
FLT_OT_ERR("out of memory");
retval = FLT_OT_RET_ERROR;
}
else if (otc_text_map_add(data->baggage, sample->key, 0, value.value.string_value, 0, 0) == -1) {
FLT_OT_ERR("out of memory");
retval = FLT_OT_RET_ERROR;
}
else
FLT_OT_DBG(3, "baggage[%zu]: '%s' -> '%s'", data->baggage->count - 1, data->baggage->key[data->baggage->count - 1], data->baggage->value[data->baggage->count - 1]);
}
FLT_OT_RETURN(retval);
}
/*
* Local variables:
* c-indent-level: 8
* c-basic-offset: 8
* End:
*
* vi: noexpandtab shiftwidth=8 tabstop=8
*/

View file

@ -0,0 +1,578 @@
/***
* Copyright 2020 HAProxy Technologies
*
* This file is part of the HAProxy OpenTracing filter.
*
* 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.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include "include.h"
#ifdef DEBUG_OT
/***
* NAME
* flt_ot_vars_scope_dump -
*
* ARGUMENTS
* vars -
* scope -
*
* DESCRIPTION
* -
*
* RETURN VALUE
* This function does not return a value.
*/
static void flt_ot_vars_scope_dump(struct vars *vars, const char *scope)
{
const struct var *var;
if (vars == NULL)
return;
HA_RWLOCK_RDLOCK(VARS_LOCK, &(vars->rwlock));
list_for_each_entry(var, &(vars->head), l)
FLT_OT_DBG(2, "'%s.%s' -> '%.*s'", scope, var->name, (int)var->data.u.str.data, var->data.u.str.area);
HA_RWLOCK_RDUNLOCK(VARS_LOCK, &(vars->rwlock));
}
/***
* NAME
* flt_ot_vars_dump -
*
* ARGUMENTS
* s -
*
* DESCRIPTION
* -
*
* RETURN VALUE
* This function does not return a value.
*/
void flt_ot_vars_dump(struct stream *s)
{
FLT_OT_FUNC("%p", s);
/*
* It would be nice if we could use the get_vars() function from HAProxy
* source here to get the value of the 'vars' pointer, but it is defined
* as 'static inline', so unfortunately none of this is possible.
*/
flt_ot_vars_scope_dump(&(global.vars), "PROC");
flt_ot_vars_scope_dump(&(s->sess->vars), "SESS");
flt_ot_vars_scope_dump(&(s->vars_txn), "TXN");
flt_ot_vars_scope_dump(&(s->vars_reqres), "REQ/RES");
FLT_OT_RETURN();
}
#endif /* DEBUG_OT */
/***
* NAME
* flt_ot_get_vars -
*
* ARGUMENTS
* s -
* scope -
*
* DESCRIPTION
* -
*
* RETURN VALUE
* -
*/
static inline struct vars *flt_ot_get_vars(struct stream *s, const char *scope)
{
struct vars *retptr = NULL;
if (strcasecmp(scope, "proc") == 0)
retptr = &(global.vars);
else if (strcasecmp(scope, "sess") == 0)
retptr = (&(s->sess->vars));
else if (strcasecmp(scope, "txn") == 0)
retptr = (&(s->vars_txn));
else if ((strcasecmp(scope, "req") == 0) || (strcasecmp(scope, "res") == 0))
retptr = (&(s->vars_reqres));
return retptr;
}
/***
* NAME
* flt_ot_normalize_name -
*
* ARGUMENTS
* var_name -
* size -
* len -
* name -
* err -
*
* DESCRIPTION
* -
*
* RETURN VALUE
* -
*/
static int flt_ot_normalize_name(char *var_name, size_t size, int *len, const char *name, char **err)
{
int retval = 0;
FLT_OT_FUNC("%p, %zu, %p, \"%s\", %p:%p", var_name, size, len, name, FLT_OT_DPTR_ARGS(err));
if (!FLT_OT_STR_ISVALID(name))
FLT_OT_RETURN(retval);
/*
* In case the name of the variable consists of several elements,
* the character '.' is added between them.
*/
if ((*len == 0) || (var_name[*len - 1] == '.'))
/* Do nothing. */;
else if (*len < (size - 1))
var_name[(*len)++] = '.';
else
retval = -1;
/*
* HAProxy does not allow the use of variable names containing '-'
* or ' '. This of course applies to HTTP header names as well.
* Also, here the capital letters are converted to lowercase.
*/
while (retval != -1)
if (*len >= (size - 1)) {
FLT_OT_ERR("failed to normalize variable name, buffer too small");
retval = -1;
} else {
uint8_t ch = name[retval];
if (ch == '\0')
break;
else if (ch == '-')
ch = FLT_OT_VAR_CHAR_DASH;
else if (ch == ' ')
ch = FLT_OT_VAR_CHAR_SPACE;
else if (isupper(ch))
ch = ist_lc[ch];
var_name[(*len)++] = ch;
retval++;
}
var_name[*len] = '\0';
FLT_OT_DBG(3, "var_name: \"%s\" %d/%d", var_name, retval, *len);
if (retval == -1)
*len = retval;
FLT_OT_RETURN(retval);
}
/***
* NAME
* flt_ot_var_name -
*
* ARGUMENTS
* scope -
* prefix -
* name -
* var_name -
* size -
* err -
*
* DESCRIPTION
* -
*
* RETURN VALUE
* -
*/
static int flt_ot_var_name(const char *scope, const char *prefix, const char *name, char *var_name, size_t size, char **err)
{
int retval = 0;
FLT_OT_FUNC("\"%s\", \"%s\", \"%s\", %p, %zu, %p:%p", scope, prefix, name, var_name, size, FLT_OT_DPTR_ARGS(err));
if (flt_ot_normalize_name(var_name, size, &retval, scope, err) >= 0)
if (flt_ot_normalize_name(var_name, size, &retval, prefix, err) >= 0)
(void)flt_ot_normalize_name(var_name, size, &retval, name, err);
if (retval == -1)
FLT_OT_ERR("failed to construct variable name '%s.%s.%s'", scope, prefix, name);
FLT_OT_RETURN(retval);
}
/***
* NAME
* flt_ot_var_register -
*
* ARGUMENTS
* scope -
* prefix -
* name -
* err -
*
* DESCRIPTION
* -
*
* RETURN VALUE
* -
*/
int flt_ot_var_register(const char *scope, const char *prefix, const char *name, char **err)
{
struct arg arg;
char var_name[BUFSIZ];
int retval;
FLT_OT_FUNC("\"%s\", \"%s\", \"%s\", %p:%p", scope, prefix, name, FLT_OT_DPTR_ARGS(err));
retval = flt_ot_var_name(scope, prefix, name, var_name, sizeof(var_name), err);
if (retval == -1)
FLT_OT_RETURN(retval);
/* Set <size> to 0 to not release var_name memory in vars_check_arg(). */
(void)memset(&arg, 0, sizeof(arg));
arg.type = ARGT_STR;
arg.data.str.area = var_name;
arg.data.str.data = retval;
if (vars_check_arg(&arg, err) == 0) {
FLT_OT_ERR_APPEND("failed to register variable '%s': %s", var_name, *err);
retval = -1;
} else {
FLT_OT_DBG(2, "variable '%s' registered", arg.data.var.name);
}
FLT_OT_RETURN(retval);
}
/***
* NAME
* flt_ot_var_set -
*
* ARGUMENTS
* s -
* scope -
* prefix -
* name -
* value -
* opt -
* err -
*
* DESCRIPTION
* -
*
* RETURN VALUE
* -
*/
int flt_ot_var_set(struct stream *s, const char *scope, const char *prefix, const char *name, const char *value, uint opt, char **err)
{
struct sample smp;
char var_name[BUFSIZ];
int retval;
FLT_OT_FUNC("%p, \"%s\", \"%s\", \"%s\", \"%s\", %u, %p:%p", s, scope, prefix, name, value, opt, FLT_OT_DPTR_ARGS(err));
retval = flt_ot_var_name(scope, prefix, name, var_name, sizeof(var_name), err);
if (retval == -1)
FLT_OT_RETURN(retval);
(void)memset(&smp, 0, sizeof(smp));
(void)smp_set_owner(&smp, s->be, s->sess, s, opt | SMP_OPT_FINAL);
smp.data.type = SMP_T_STR;
smp.data.u.str.area = (char *)value;
smp.data.u.str.data = strlen(value);
vars_set_by_name_ifexist(var_name, retval, &smp);
FLT_OT_RETURN(retval);
}
/***
* NAME
* flt_ot_var_unset -
*
* ARGUMENTS
* s -
* scope -
* prefix -
* name -
* opt -
* err -
*
* DESCRIPTION
* -
*
* RETURN VALUE
* -
*/
int flt_ot_var_unset(struct stream *s, const char *scope, const char *prefix, const char *name, uint opt, char **err)
{
struct sample smp;
char var_name[BUFSIZ];
int retval;
FLT_OT_FUNC("%p, \"%s\", \"%s\", \"%s\", %u, %p:%p", s, scope, prefix, name, opt, FLT_OT_DPTR_ARGS(err));
retval = flt_ot_var_name(scope, prefix, name, var_name, sizeof(var_name), err);
if (retval == -1)
FLT_OT_RETURN(retval);
(void)memset(&smp, 0, sizeof(smp));
(void)smp_set_owner(&smp, s->be, s->sess, s, opt | SMP_OPT_FINAL);
vars_unset_by_name_ifexist(var_name, retval, &smp);
FLT_OT_RETURN(retval);
}
/***
* NAME
* flt_ot_vars_unset -
*
* ARGUMENTS
* s -
* scope -
* prefix -
* opt -
* err -
*
* DESCRIPTION
* -
*
* RETURN VALUE
* -
*/
int flt_ot_vars_unset(struct stream *s, const char *scope, const char *prefix, uint opt, char **err)
{
struct sample smp;
struct vars *vars;
struct var *var, *var_back;
char var_prefix[BUFSIZ], var_name[BUFSIZ];
uint size;
int var_prefix_len, var_name_len, retval = -1;
FLT_OT_FUNC("%p, \"%s\", \"%s\", %u, %p:%p", s, scope, prefix, opt, FLT_OT_DPTR_ARGS(err));
vars = flt_ot_get_vars(s, scope);
if (vars == NULL)
FLT_OT_RETURN(retval);
var_prefix_len = flt_ot_var_name(NULL, prefix, NULL, var_prefix, sizeof(var_prefix), err);
if (var_prefix_len == -1)
FLT_OT_RETURN(retval);
retval = 0;
HA_RWLOCK_WRLOCK(VARS_LOCK, &(vars->rwlock));
list_for_each_entry_safe(var, var_back, &(vars->head), l) {
FLT_OT_DBG(3, "variable cmp '%s' '%s' %d", var_prefix, var->name, var_prefix_len);
if (strncmp(var_prefix, var->name, var_prefix_len) == 0) {
var_name_len = snprintf(var_name, sizeof(var_name), "%s.%s", scope, var->name);
if ((var_name_len == -1) || (var_name_len >= sizeof(var_name))) {
FLT_OT_DBG(2, "'%s.%s' variable name too long", scope, var->name);
break;
}
FLT_OT_DBG(2, "- '%s' -> '%.*s'", var_name, (int)var->data.u.str.data, var->data.u.str.area);
(void)memset(&smp, 0, sizeof(smp));
(void)smp_set_owner(&smp, s->be, s->sess, s, opt | SMP_OPT_FINAL);
size = var_clear(var);
var_accounting_diff(vars, smp.sess, smp.strm, -size);
retval++;
}
}
HA_RWLOCK_WRUNLOCK(VARS_LOCK, &(vars->rwlock));
FLT_OT_RETURN(retval);
}
/***
* NAME
* flt_ot_var_get -
*
* ARGUMENTS
* s -
* scope -
* prefix -
* name -
* value -
* opt -
* err -
*
* DESCRIPTION
* -
*
* RETURN VALUE
* -
*/
int flt_ot_var_get(struct stream *s, const char *scope, const char *prefix, const char *name, char **value, uint opt, char **err)
{
struct sample smp;
char var_name[BUFSIZ], var_value[BUFSIZ];
int retval;
FLT_OT_FUNC("%p, \"%s\", \"%s\", \"%s\", %p:%p, %u, %p:%p", s, scope, prefix, name, FLT_OT_DPTR_ARGS(value), opt, FLT_OT_DPTR_ARGS(err));
retval = flt_ot_var_name(scope, prefix, name, var_name, sizeof(var_name), err);
if (retval == -1)
FLT_OT_RETURN(retval);
(void)memset(&smp, 0, sizeof(smp));
(void)smp_set_owner(&smp, s->be, s->sess, s, opt | SMP_OPT_FINAL);
if (vars_get_by_name(var_name, retval, &smp)) {
retval = flt_ot_sample_to_str(&(smp.data), var_value, sizeof(var_value), err);
if (retval != -1)
FLT_OT_DBG(3, "data type %d: '%s' = '%s'", smp.data.type, var_name, var_value);
} else {
FLT_OT_ERR("failed to get variable '%s'", var_name);
retval = -1;
}
FLT_OT_RETURN(retval);
}
/***
* NAME
* flt_ot_vars_get -
*
* ARGUMENTS
* s -
* scope -
* prefix -
* opt -
* err -
*
* DESCRIPTION
* -
*
* RETURN VALUE
* -
*/
struct otc_text_map *flt_ot_vars_get(struct stream *s, const char *scope, const char *prefix, uint opt, char **err)
{
struct vars *vars;
const struct var *var;
char var_name[BUFSIZ], ot_var_name[BUFSIZ];
int rc, i;
struct otc_text_map *retptr = NULL;
FLT_OT_FUNC("%p, \"%s\", \"%s\", %u, %p:%p", s, scope, prefix, opt, FLT_OT_DPTR_ARGS(err));
vars = flt_ot_get_vars(s, scope);
if (vars == NULL)
FLT_OT_RETURN(retptr);
rc = flt_ot_var_name(NULL, prefix, NULL, var_name, sizeof(var_name), err);
if (rc == -1)
FLT_OT_RETURN(retptr);
HA_RWLOCK_RDLOCK(VARS_LOCK, &(vars->rwlock));
list_for_each_entry(var, &(vars->head), l) {
FLT_OT_DBG(3, "variable cmp '%s' '%s' %d", var_name, var->name, rc);
if (strncmp(var_name, var->name, rc) == 0) {
FLT_OT_DBG(2, "'%s.%s' -> '%.*s'", scope, var->name, (int)var->data.u.str.data, var->data.u.str.area);
if (retptr == NULL) {
retptr = otc_text_map_new(NULL, 8);
if (retptr == NULL) {
FLT_OT_ERR("failed to create data");
break;
}
}
/*
* Eh, because the use of some characters is not allowed
* in the variable name, the conversion of the replaced
* characters to the original is performed here.
*/
for (i = 0; ; )
if (i >= (FLT_OT_TABLESIZE(ot_var_name) - 1)) {
FLT_OT_ERR("failed to reverse variable name, buffer too small");
otc_text_map_destroy(&retptr, OTC_TEXT_MAP_FREE_KEY | OTC_TEXT_MAP_FREE_VALUE);
break;
} else {
char ch = var->name[rc + i + 1];
if (ch == '\0')
break;
else if (ch == FLT_OT_VAR_CHAR_DASH)
ch = '-';
else if (ch == FLT_OT_VAR_CHAR_SPACE)
ch = ' ';
ot_var_name[i++] = ch;
}
ot_var_name[i] = '\0';
if (retptr == NULL) {
break;
}
else if (otc_text_map_add(retptr, ot_var_name, i, var->data.u.str.area, var->data.u.str.data, OTC_TEXT_MAP_DUP_KEY | OTC_TEXT_MAP_DUP_VALUE) == -1) {
FLT_OT_ERR("failed to add map data");
otc_text_map_destroy(&retptr, OTC_TEXT_MAP_FREE_KEY | OTC_TEXT_MAP_FREE_VALUE);
break;
}
}
}
HA_RWLOCK_RDUNLOCK(VARS_LOCK, &(vars->rwlock));
ot_text_map_show(retptr);
if ((retptr != NULL) && (retptr->count == 0)) {
FLT_OT_DBG(2, "WARNING: no variables found");
otc_text_map_destroy(&retptr, OTC_TEXT_MAP_FREE_KEY | OTC_TEXT_MAP_FREE_VALUE);
}
FLT_OT_RETURN(retptr);
}
/*
* Local variables:
* c-indent-level: 8
* c-basic-offset: 8
* End:
*
* vi: noexpandtab shiftwidth=8 tabstop=8
*/

View file

@ -0,0 +1,111 @@
--- rate-limit 100.0 --------------------------------------------------
Running 5m test @ http://localhost:10080/index.html
8 threads and 8 connections
Thread Stats Avg Stdev Max +/- Stdev
Latency 650.95us 431.15us 46.44ms 96.67%
Req/Sec 1.44k 51.39 2.57k 74.89%
Latency Distribution
50% 608.00us
75% 760.00us
90% 0.91ms
99% 1.31ms
3434836 requests in 5.00m, 0.89GB read
Requests/sec: 11446.99
Transfer/sec: 3.03MB
----------------------------------------------------------------------
--- rate-limit 50.0 --------------------------------------------------
Running 5m test @ http://localhost:10080/index.html
8 threads and 8 connections
Thread Stats Avg Stdev Max +/- Stdev
Latency 398.00us 371.39us 22.56ms 97.23%
Req/Sec 2.32k 84.01 2.76k 74.84%
Latency Distribution
50% 350.00us
75% 467.00us
90% 593.00us
99% 1.03ms
5530848 requests in 5.00m, 1.43GB read
Requests/sec: 18434.31
Transfer/sec: 4.89MB
----------------------------------------------------------------------
--- rate-limit 10.0 --------------------------------------------------
Running 5m test @ http://localhost:10080/index.html
8 threads and 8 connections
Thread Stats Avg Stdev Max +/- Stdev
Latency 316.75us 351.92us 23.00ms 98.57%
Req/Sec 2.87k 94.02 3.22k 79.30%
Latency Distribution
50% 273.00us
75% 342.00us
90% 424.00us
99% 0.94ms
6859293 requests in 5.00m, 1.78GB read
Requests/sec: 22862.16
Transfer/sec: 6.06MB
----------------------------------------------------------------------
--- rate-limit 2.5 --------------------------------------------------
Running 5m test @ http://localhost:10080/index.html
8 threads and 8 connections
Thread Stats Avg Stdev Max +/- Stdev
Latency 307.90us 368.64us 26.08ms 98.71%
Req/Sec 2.96k 103.84 3.23k 83.76%
Latency Distribution
50% 264.00us
75% 327.00us
90% 402.00us
99% 0.97ms
7065667 requests in 5.00m, 1.83GB read
Requests/sec: 23550.37
Transfer/sec: 6.24MB
----------------------------------------------------------------------
--- rate-limit 0.0 --------------------------------------------------
Running 5m test @ http://localhost:10080/index.html
8 threads and 8 connections
Thread Stats Avg Stdev Max +/- Stdev
Latency 304.60us 376.36us 30.26ms 98.74%
Req/Sec 2.99k 106.93 3.24k 83.08%
Latency Distribution
50% 262.00us
75% 323.00us
90% 396.00us
99% 0.95ms
7136261 requests in 5.00m, 1.85GB read
Requests/sec: 23785.77
Transfer/sec: 6.31MB
----------------------------------------------------------------------
--- rate-limit disabled --------------------------------------------------
Running 5m test @ http://localhost:10080/index.html
8 threads and 8 connections
Thread Stats Avg Stdev Max +/- Stdev
Latency 300.90us 342.35us 22.13ms 98.74%
Req/Sec 3.00k 95.67 3.33k 81.11%
Latency Distribution
50% 261.00us
75% 322.00us
90% 394.00us
99% 806.00us
7159525 requests in 5.00m, 1.85GB read
Requests/sec: 23863.05
Transfer/sec: 6.33MB
----------------------------------------------------------------------
--- rate-limit off --------------------------------------------------
Running 5m test @ http://localhost:10080/index.html
8 threads and 8 connections
Thread Stats Avg Stdev Max +/- Stdev
Latency 302.51us 371.99us 30.26ms 98.77%
Req/Sec 3.00k 104.43 3.73k 83.74%
Latency Distribution
50% 260.00us
75% 321.00us
90% 394.00us
99% 0.89ms
7170345 requests in 5.00m, 1.86GB read
Requests/sec: 23898.19
Transfer/sec: 6.34MB
----------------------------------------------------------------------

View file

@ -0,0 +1,111 @@
--- rate-limit 100.0 --------------------------------------------------
Running 5m test @ http://localhost:10080/index.html
8 threads and 8 connections
Thread Stats Avg Stdev Max +/- Stdev
Latency 2.49ms 799.87us 43.00ms 70.90%
Req/Sec 393.01 20.61 696.00 71.68%
Latency Distribution
50% 2.50ms
75% 3.00ms
90% 3.38ms
99% 4.23ms
939237 requests in 5.00m, 249.01MB read
Requests/sec: 3130.01
Transfer/sec: 849.75KB
----------------------------------------------------------------------
--- rate-limit 50.0 --------------------------------------------------
Running 5m test @ http://localhost:10080/index.html
8 threads and 8 connections
Thread Stats Avg Stdev Max +/- Stdev
Latency 1.27ms 0.97ms 40.77ms 56.91%
Req/Sec 778.22 70.30 1.36k 69.10%
Latency Distribution
50% 1.36ms
75% 1.80ms
90% 2.49ms
99% 3.51ms
1859055 requests in 5.00m, 492.88MB read
Requests/sec: 6195.58
Transfer/sec: 1.64MB
----------------------------------------------------------------------
--- rate-limit 10.0 --------------------------------------------------
Running 5m test @ http://localhost:10080/index.html
8 threads and 8 connections
Thread Stats Avg Stdev Max +/- Stdev
Latency 442.00us 481.47us 31.61ms 90.27%
Req/Sec 2.25k 130.05 2.73k 72.83%
Latency Distribution
50% 287.00us
75% 526.00us
90% 0.92ms
99% 1.76ms
5380213 requests in 5.00m, 1.39GB read
Requests/sec: 17930.27
Transfer/sec: 4.75MB
----------------------------------------------------------------------
--- rate-limit 2.5 --------------------------------------------------
Running 5m test @ http://localhost:10080/index.html
8 threads and 8 connections
Thread Stats Avg Stdev Max +/- Stdev
Latency 346.65us 414.65us 28.50ms 95.63%
Req/Sec 2.75k 159.74 3.23k 84.68%
Latency Distribution
50% 271.00us
75% 353.00us
90% 505.00us
99% 1.55ms
6560093 requests in 5.00m, 1.70GB read
Requests/sec: 21864.43
Transfer/sec: 5.80MB
----------------------------------------------------------------------
--- rate-limit 0.0 --------------------------------------------------
Running 5m test @ http://localhost:10080/index.html
8 threads and 8 connections
Thread Stats Avg Stdev Max +/- Stdev
Latency 313.32us 402.25us 24.73ms 98.55%
Req/Sec 2.95k 145.03 3.21k 88.99%
Latency Distribution
50% 264.00us
75% 327.00us
90% 403.00us
99% 1.33ms
7050847 requests in 5.00m, 1.83GB read
Requests/sec: 23501.14
Transfer/sec: 6.23MB
----------------------------------------------------------------------
--- rate-limit disabled --------------------------------------------------
Running 5m test @ http://localhost:10080/index.html
8 threads and 8 connections
Thread Stats Avg Stdev Max +/- Stdev
Latency 310.19us 384.76us 22.18ms 98.66%
Req/Sec 2.96k 115.62 3.37k 84.30%
Latency Distribution
50% 265.00us
75% 327.00us
90% 402.00us
99% 1.10ms
7058682 requests in 5.00m, 1.83GB read
Requests/sec: 23526.70
Transfer/sec: 6.24MB
----------------------------------------------------------------------
--- rate-limit off --------------------------------------------------
Running 5m test @ http://localhost:10080/index.html
8 threads and 8 connections
Thread Stats Avg Stdev Max +/- Stdev
Latency 305.86us 367.56us 25.76ms 98.65%
Req/Sec 2.99k 116.93 3.43k 85.59%
Latency Distribution
50% 261.00us
75% 322.00us
90% 396.00us
99% 1.09ms
7137173 requests in 5.00m, 1.85GB read
Requests/sec: 23788.84
Transfer/sec: 6.31MB
----------------------------------------------------------------------

View file

@ -0,0 +1,111 @@
--- rate-limit 100.0 --------------------------------------------------
Running 5m test @ http://localhost:10080/index.html
8 threads and 8 connections
Thread Stats Avg Stdev Max +/- Stdev
Latency 0.89ms 466.84us 35.44ms 94.39%
Req/Sec 1.09k 39.30 1.32k 72.60%
Latency Distribution
50% 823.00us
75% 1.00ms
90% 1.20ms
99% 2.14ms
2594524 requests in 5.00m, 687.86MB read
Requests/sec: 8645.83
Transfer/sec: 2.29MB
----------------------------------------------------------------------
--- rate-limit 50.0 --------------------------------------------------
Running 5m test @ http://localhost:10080/index.html
8 threads and 8 connections
Thread Stats Avg Stdev Max +/- Stdev
Latency 681.74us 463.28us 20.45ms 95.46%
Req/Sec 1.41k 54.00 1.60k 68.97%
Latency Distribution
50% 613.00us
75% 785.00us
90% 0.98ms
99% 2.06ms
3367473 requests in 5.00m, 0.87GB read
Requests/sec: 11222.76
Transfer/sec: 2.98MB
----------------------------------------------------------------------
--- rate-limit 10.0 --------------------------------------------------
Running 5m test @ http://localhost:10080/index.html
8 threads and 8 connections
Thread Stats Avg Stdev Max +/- Stdev
Latency 558.32us 458.54us 29.40ms 97.73%
Req/Sec 1.72k 60.67 2.05k 73.10%
Latency Distribution
50% 494.00us
75% 610.00us
90% 743.00us
99% 2.08ms
4105420 requests in 5.00m, 1.06GB read
Requests/sec: 13683.36
Transfer/sec: 3.63MB
----------------------------------------------------------------------
--- rate-limit 2.5 --------------------------------------------------
Running 5m test @ http://localhost:10080/index.html
8 threads and 8 connections
Thread Stats Avg Stdev Max +/- Stdev
Latency 542.66us 440.31us 22.63ms 97.88%
Req/Sec 1.76k 60.02 2.00k 72.27%
Latency Distribution
50% 481.00us
75% 588.00us
90% 710.00us
99% 2.05ms
4214525 requests in 5.00m, 1.09GB read
Requests/sec: 14046.76
Transfer/sec: 3.72MB
----------------------------------------------------------------------
--- rate-limit 0.0 --------------------------------------------------
Running 5m test @ http://localhost:10080/index.html
8 threads and 8 connections
Thread Stats Avg Stdev Max +/- Stdev
Latency 529.06us 414.38us 30.09ms 97.97%
Req/Sec 1.80k 59.34 2.05k 74.47%
Latency Distribution
50% 473.00us
75% 576.00us
90% 692.00us
99% 1.79ms
4287428 requests in 5.00m, 1.11GB read
Requests/sec: 14290.45
Transfer/sec: 3.79MB
----------------------------------------------------------------------
--- rate-limit disabled --------------------------------------------------
Running 5m test @ http://localhost:10080/index.html
8 threads and 8 connections
Thread Stats Avg Stdev Max +/- Stdev
Latency 517.81us 463.10us 36.81ms 98.25%
Req/Sec 1.85k 62.39 2.21k 75.65%
Latency Distribution
50% 458.00us
75% 558.00us
90% 670.00us
99% 1.96ms
4416273 requests in 5.00m, 1.14GB read
Requests/sec: 14719.43
Transfer/sec: 3.90MB
----------------------------------------------------------------------
--- rate-limit off --------------------------------------------------
Running 5m test @ http://localhost:10080/index.html
8 threads and 8 connections
Thread Stats Avg Stdev Max +/- Stdev
Latency 511.67us 428.18us 27.68ms 98.15%
Req/Sec 1.86k 60.67 2.05k 75.44%
Latency Distribution
50% 455.00us
75% 554.00us
90% 666.00us
99% 1.81ms
4441271 requests in 5.00m, 1.15GB read
Requests/sec: 14803.32
Transfer/sec: 3.92MB
----------------------------------------------------------------------

View file

@ -0,0 +1,111 @@
--- rate-limit 100.0 --------------------------------------------------
Running 5m test @ http://localhost:10080/index.html
8 threads and 8 connections
Thread Stats Avg Stdev Max +/- Stdev
Latency 1.24ms 522.78us 35.59ms 79.12%
Req/Sec 767.71 38.72 3.02k 72.19%
Latency Distribution
50% 1.20ms
75% 1.51ms
90% 1.78ms
99% 2.37ms
1834067 requests in 5.00m, 486.25MB read
Requests/sec: 6111.57
Transfer/sec: 1.62MB
----------------------------------------------------------------------
--- rate-limit 50.0 --------------------------------------------------
Running 5m test @ http://localhost:10080/index.html
8 threads and 8 connections
Thread Stats Avg Stdev Max +/- Stdev
Latency 593.11us 476.81us 43.00ms 91.27%
Req/Sec 1.59k 81.15 2.07k 71.14%
Latency Distribution
50% 549.00us
75% 788.00us
90% 1.03ms
99% 1.62ms
3795987 requests in 5.00m, 0.98GB read
Requests/sec: 12650.65
Transfer/sec: 3.35MB
----------------------------------------------------------------------
--- rate-limit 10.0 --------------------------------------------------
Running 5m test @ http://localhost:10080/index.html
8 threads and 8 connections
Thread Stats Avg Stdev Max +/- Stdev
Latency 326.02us 355.00us 29.23ms 98.05%
Req/Sec 2.80k 88.05 3.30k 75.36%
Latency Distribution
50% 277.00us
75% 356.00us
90% 456.00us
99% 0.97ms
6675563 requests in 5.00m, 1.73GB read
Requests/sec: 22249.78
Transfer/sec: 5.90MB
----------------------------------------------------------------------
--- rate-limit 2.5 --------------------------------------------------
Running 5m test @ http://localhost:10080/index.html
8 threads and 8 connections
Thread Stats Avg Stdev Max +/- Stdev
Latency 311.77us 357.45us 24.11ms 98.62%
Req/Sec 2.91k 94.70 3.18k 78.52%
Latency Distribution
50% 268.00us
75% 334.00us
90% 413.00us
99% 0.94ms
6960933 requests in 5.00m, 1.80GB read
Requests/sec: 23201.07
Transfer/sec: 6.15MB
----------------------------------------------------------------------
--- rate-limit 0.0 --------------------------------------------------
Running 5m test @ http://localhost:10080/index.html
8 threads and 8 connections
Thread Stats Avg Stdev Max +/- Stdev
Latency 302.51us 330.50us 25.84ms 98.69%
Req/Sec 2.98k 91.46 3.40k 78.84%
Latency Distribution
50% 263.00us
75% 325.00us
90% 397.00us
99% 812.00us
7112084 requests in 5.00m, 1.84GB read
Requests/sec: 23705.14
Transfer/sec: 6.28MB
----------------------------------------------------------------------
--- rate-limit disabled --------------------------------------------------
Running 5m test @ http://localhost:10080/index.html
8 threads and 8 connections
Thread Stats Avg Stdev Max +/- Stdev
Latency 303.01us 353.98us 28.03ms 98.76%
Req/Sec 2.99k 93.97 3.34k 81.12%
Latency Distribution
50% 262.00us
75% 323.00us
90% 395.00us
99% 838.00us
7133837 requests in 5.00m, 1.85GB read
Requests/sec: 23777.95
Transfer/sec: 6.30MB
----------------------------------------------------------------------
--- rate-limit off --------------------------------------------------
Running 5m test @ http://localhost:10080/index.html
8 threads and 8 connections
Thread Stats Avg Stdev Max +/- Stdev
Latency 302.61us 349.74us 25.48ms 98.75%
Req/Sec 2.99k 94.85 3.49k 80.75%
Latency Distribution
50% 262.00us
75% 323.00us
90% 395.00us
99% 822.00us
7132714 requests in 5.00m, 1.85GB read
Requests/sec: 23773.35
Transfer/sec: 6.30MB
----------------------------------------------------------------------

View file

@ -0,0 +1,5 @@
{
"service": "BE",
"agent_host": "localhost",
"agent_port": 8126
}

View file

@ -0,0 +1,34 @@
service_name:
BE
###
# When using configuration object to instantiate the tracer, the type of
# sampling can be selected via sampler.type and sampler.param properties.
# Jaeger libraries support the following samplers:
#
# - Constant (sampler.type=const) sampler always makes the same decision for
# all traces. It either samples all traces (sampler.param=1) or none of
# them (sampler.param=0).
#
# - Probabilistic (sampler.type=probabilistic) sampler makes a random sampling
# decision with the probability of sampling equal to the value of
# sampler.param property. For example, with sampler.param=0.1 approximately
# 1 in 10 traces will be sampled.
#
# - Rate Limiting (sampler.type=ratelimiting) sampler uses a leaky bucket rate
# limiter to ensure that traces are sampled with a certain constant rate.
# For example, when sampler.param=2.0 it will sample requests with the rate
# of 2 traces per second.
#
# - Remote (sampler.type=remote, which is also the default) sampler consults
# Jaeger agent for the appropriate sampling strategy to use in the current
# service. This allows controlling the sampling strategies in the services
# from a central configuration in Jaeger backend, or even dynamically.
#
sampler:
type: ratelimiting
param: 10.0
reporter:
logSpans: true
localAgentHostPort: localhost:6831

View file

@ -0,0 +1,4 @@
{
"service_name": "BE",
"collector_host": "localhost"
}

View file

@ -0,0 +1,37 @@
global
# nbthread 1
maxconn 5000
hard-stop-after 10s
# log localhost:514 local7 debug
# debug
stats socket /tmp/haproxy-be.sock mode 666 level admin
defaults
log global
mode http
option httplog
option dontlognull
option httpclose
retries 3
maxconn 4000
timeout connect 5000
timeout client 50000
timeout server 50000
listen stats
mode http
bind *:8002
stats uri /
stats admin if TRUE
stats refresh 10s
frontend ot-test-be-frontend
bind *:11080
mode http
default_backend servers-backend
filter opentracing id ot-test-be config be/ot.cfg
backend servers-backend
mode http
server server-1 127.0.0.1:8000

View file

@ -0,0 +1,62 @@
[ot-test-be]
ot-tracer ot-test-tracer
config be/cfg-jaeger.yml
plugin libjaeger_opentracing_plugin-0.5.0.so
# log localhost:514 local7 debug
option dontlog-normal
option hard-errors
no option disabled
scopes frontend_http_request
scopes backend_tcp_request
scopes backend_http_request
scopes client_session_end
scopes server_session_start
scopes tcp_response
scopes http_response
scopes server_session_end
ot-scope frontend_http_request
extract "ot-ctx" use-headers
span "HAProxy session" child-of "ot-ctx" root
baggage "haproxy_id" var(sess.ot.uuid)
span "Client session" child-of "HAProxy session"
span "Frontend HTTP request" child-of "Client session"
tag "http.method" method
tag "http.url" url
tag "http.version" str("HTTP/") req.ver
event on-frontend-http-request
ot-scope backend_tcp_request
span "Backend TCP request" follows-from "Frontend HTTP request"
finish "Frontend HTTP request"
event on-backend-tcp-request
ot-scope backend_http_request
span "Backend HTTP request" follows-from "Backend TCP request"
finish "Backend TCP request"
event on-backend-http-request
ot-scope client_session_end
finish "Client session"
event on-client-session-end
ot-scope server_session_start
span "Server session" child-of "HAProxy session"
finish "Backend HTTP request"
event on-server-session-start
ot-scope tcp_response
span "TCP response" child-of "Server session"
event on-tcp-response
ot-scope http_response
span "HTTP response" follows-from "TCP response"
tag "http.status_code" status
finish "TCP response"
event on-http-response
ot-scope server_session_end
finish *
event on-server-session-end

View file

@ -0,0 +1,5 @@
{
"service": "CMP",
"agent_host": "localhost",
"agent_port": 8126
}

View file

@ -0,0 +1,34 @@
service_name:
CMP
###
# When using configuration object to instantiate the tracer, the type of
# sampling can be selected via sampler.type and sampler.param properties.
# Jaeger libraries support the following samplers:
#
# - Constant (sampler.type=const) sampler always makes the same decision for
# all traces. It either samples all traces (sampler.param=1) or none of
# them (sampler.param=0).
#
# - Probabilistic (sampler.type=probabilistic) sampler makes a random sampling
# decision with the probability of sampling equal to the value of
# sampler.param property. For example, with sampler.param=0.1 approximately
# 1 in 10 traces will be sampled.
#
# - Rate Limiting (sampler.type=ratelimiting) sampler uses a leaky bucket rate
# limiter to ensure that traces are sampled with a certain constant rate.
# For example, when sampler.param=2.0 it will sample requests with the rate
# of 2 traces per second.
#
# - Remote (sampler.type=remote, which is also the default) sampler consults
# Jaeger agent for the appropriate sampling strategy to use in the current
# service. This allows controlling the sampling strategies in the services
# from a central configuration in Jaeger backend, or even dynamically.
#
sampler:
type: ratelimiting
param: 10.0
reporter:
logSpans: true
localAgentHostPort: localhost:6831

View file

@ -0,0 +1,4 @@
{
"service_name": "CMP",
"collector_host": "localhost"
}

View file

@ -0,0 +1,36 @@
global
# nbthread 1
maxconn 5000
hard-stop-after 10s
stats socket /tmp/haproxy.sock mode 666 level admin
defaults
log global
mode http
option httplog
option dontlognull
option httpclose
retries 3
maxconn 4000
timeout connect 5000
timeout client 50000
timeout server 50000
listen stats
mode http
bind *:8001
stats uri /
stats admin if TRUE
stats refresh 10s
frontend ot-test-cmp-frontend
bind *:10080
mode http
default_backend servers-backend
acl acl-http-status-ok status 100:399
filter opentracing id ot-test-cmp config cmp/ot.cfg
backend servers-backend
mode http
server server-1 127.0.0.1:8000

View file

@ -0,0 +1,83 @@
[ot-test-cmp]
ot-tracer ot-test-tracer
config cmp/cfg-jaeger.yml
plugin libjaeger_opentracing_plugin-0.5.0.so
# log localhost:514 local7 debug
option dontlog-normal
option hard-errors
no option disabled
rate-limit 100.0
scopes client_session_start
scopes frontend_tcp_request
scopes frontend_http_request
scopes backend_tcp_request
scopes backend_http_request
scopes server_unavailable
scopes server_session_start
scopes tcp_response
scopes http_response http_response-error server_session_end client_session_end
ot-scope client_session_start
span "HAProxy session" root
baggage "haproxy_id" var(sess.ot.uuid)
span "Client session" child-of "HAProxy session"
event on-client-session-start
ot-scope frontend_tcp_request
span "Frontend TCP request" child-of "Client session"
event on-frontend-tcp-request
ot-scope frontend_http_request
span "Frontend HTTP request" follows-from "Frontend TCP request"
tag "http.method" method
tag "http.url" url
tag "http.version" str("HTTP/") req.ver
finish "Frontend TCP request"
event on-frontend-http-request
ot-scope backend_tcp_request
span "Backend TCP request" follows-from "Frontend HTTP request"
finish "Frontend HTTP request"
event on-backend-tcp-request
ot-scope backend_http_request
span "Backend HTTP request" follows-from "Backend TCP request"
finish "Backend TCP request"
event on-backend-http-request
ot-scope server_unavailable
span "HAProxy session"
tag "error" bool(true)
log "status" str("503 Service Unavailable")
finish *
event on-server-unavailable
ot-scope server_session_start
span "Server session" child-of "HAProxy session"
finish "Backend HTTP request"
event on-server-session-start
ot-scope tcp_response
span "TCP response" child-of "Server session"
event on-tcp-response
ot-scope http_response
span "HTTP response" follows-from "TCP response"
tag "http.status_code" status
finish "TCP response"
event on-http-response
ot-scope http_response-error
span "HTTP response"
tag "error" bool(true)
event on-http-response if !acl-http-status-ok
ot-scope server_session_end
finish "HTTP response" "Server session"
event on-http-response
ot-scope client_session_end
finish "*"
event on-http-response

View file

@ -0,0 +1,5 @@
{
"service": "CTX",
"agent_host": "localhost",
"agent_port": 8126
}

View file

@ -0,0 +1,34 @@
service_name:
CTX
###
# When using configuration object to instantiate the tracer, the type of
# sampling can be selected via sampler.type and sampler.param properties.
# Jaeger libraries support the following samplers:
#
# - Constant (sampler.type=const) sampler always makes the same decision for
# all traces. It either samples all traces (sampler.param=1) or none of
# them (sampler.param=0).
#
# - Probabilistic (sampler.type=probabilistic) sampler makes a random sampling
# decision with the probability of sampling equal to the value of
# sampler.param property. For example, with sampler.param=0.1 approximately
# 1 in 10 traces will be sampled.
#
# - Rate Limiting (sampler.type=ratelimiting) sampler uses a leaky bucket rate
# limiter to ensure that traces are sampled with a certain constant rate.
# For example, when sampler.param=2.0 it will sample requests with the rate
# of 2 traces per second.
#
# - Remote (sampler.type=remote, which is also the default) sampler consults
# Jaeger agent for the appropriate sampling strategy to use in the current
# service. This allows controlling the sampling strategies in the services
# from a central configuration in Jaeger backend, or even dynamically.
#
sampler:
type: ratelimiting
param: 10.0
reporter:
logSpans: true
localAgentHostPort: localhost:6831

View file

@ -0,0 +1,4 @@
{
"service_name": "CTX",
"collector_host": "localhost"
}

View file

@ -0,0 +1,38 @@
global
# nbthread 1
maxconn 5000
hard-stop-after 10s
stats socket /tmp/haproxy.sock mode 666 level admin
defaults
log global
mode http
option httplog
option dontlognull
option httpclose
retries 3
maxconn 4000
timeout connect 5000
timeout client 50000
timeout server 50000
listen stats
mode http
bind *:8001
stats uri /
stats admin if TRUE
stats refresh 10s
frontend ot-test-ctx-frontend
bind *:10080
mode http
default_backend servers-backend
acl acl-http-status-ok status 100:399
filter opentracing id ot-test-ctx config ctx/ot.cfg
http-response ot-group ot-test-ctx http_response_group if acl-http-status-ok
http-after-response ot-group ot-test-ctx http_after_response_group if !acl-http-status-ok
backend servers-backend
mode http
server server-1 127.0.0.1:8000

View file

@ -0,0 +1,197 @@
[ot-test-ctx]
ot-tracer ot-test-tracer
log localhost:514 local7 debug
config ctx/cfg-jaeger.yml
plugin libjaeger_opentracing_plugin-0.5.0.so
option dontlog-normal
option hard-errors
no option disabled
rate-limit 100.0
groups http_response_group
groups http_after_response_group
scopes client_session_start_1
scopes client_session_start_2
scopes frontend_tcp_request
scopes http_wait_request
scopes http_body_request
scopes frontend_http_request
scopes switching_rules_request
scopes backend_tcp_request
scopes backend_http_request
scopes process_server_rules_request
scopes http_process_request
scopes tcp_rdp_cookie_request
scopes process_sticking_rules_request
scopes client_session_end
scopes server_unavailable
scopes server_session_start
scopes tcp_response
scopes http_wait_response
scopes process_store_rules_response
scopes http_response http_response-error
scopes server_session_end
ot-group http_response_group
scopes http_response_1
scopes http_response_2
ot-scope http_response_1
span "HTTP response"
log "hdr.content" res.hdr("content-type") str("; length: ") res.hdr("content-length") str(" bytes")
ot-scope http_response_2
span "HTTP response"
log "hdr.date" res.hdr("date") str(" / ") res.hdr("last-modified")
ot-group http_after_response_group
scopes http_after_response
ot-scope http_after_response
span "HAProxy response" child-of "HAProxy session"
tag "error" bool(true)
tag "http.status_code" status
ot-scope client_session_start_1
span "HAProxy session" root
inject "ot_ctx_1" use-headers use-vars
baggage "haproxy_id" var(sess.ot.uuid)
event on-client-session-start
ot-scope client_session_start_2
extract "ot_ctx_1" use-vars
span "Client session" child-of "ot_ctx_1"
inject "ot_ctx_2" use-headers use-vars
event on-client-session-start
ot-scope frontend_tcp_request
extract "ot_ctx_2" use-vars
span "Frontend TCP request" child-of "ot_ctx_2"
inject "ot_ctx_3" use-headers use-vars
event on-frontend-tcp-request
ot-scope http_wait_request
extract "ot_ctx_3" use-vars
span "HTTP wait request" follows-from "ot_ctx_3"
inject "ot_ctx_4" use-headers use-vars
finish "Frontend TCP request" "ot_ctx_3"
event on-http-wait-request
ot-scope http_body_request
extract "ot_ctx_4" use-vars
span "HTTP body request" follows-from "ot_ctx_4"
inject "ot_ctx_5" use-headers use-vars
finish "HTTP wait request" "ot_ctx_4"
event on-http-body-request
ot-scope frontend_http_request
extract "ot_ctx_5" use-vars
span "Frontend HTTP request" follows-from "ot_ctx_5"
tag "http.method" method
tag "http.url" url
tag "http.version" str("HTTP/") req.ver
inject "ot_ctx_6" use-headers use-vars
finish "HTTP body request" "ot_ctx_5"
event on-frontend-http-request
ot-scope switching_rules_request
extract "ot_ctx_6" use-vars
span "Switching rules request" follows-from "ot_ctx_6"
inject "ot_ctx_7" use-headers use-vars
finish "Frontend HTTP request" "ot_ctx_6"
event on-switching-rules-request
ot-scope backend_tcp_request
extract "ot_ctx_7" use-vars
span "Backend TCP request" follows-from "ot_ctx_7"
inject "ot_ctx_8" use-headers use-vars
finish "Switching rules request" "ot_ctx_7"
event on-backend-tcp-request
ot-scope backend_http_request
extract "ot_ctx_8" use-vars
span "Backend HTTP request" follows-from "ot_ctx_8"
inject "ot_ctx_9" use-headers use-vars
finish "Backend TCP request" "ot_ctx_8"
event on-backend-http-request
ot-scope process_server_rules_request
extract "ot_ctx_9" use-vars
span "Process server rules request" follows-from "ot_ctx_9"
inject "ot_ctx_10" use-headers use-vars
finish "Backend HTTP request" "ot_ctx_9"
event on-process-server-rules-request
ot-scope http_process_request
extract "ot_ctx_10" use-vars
span "HTTP process request" follows-from "ot_ctx_10"
inject "ot_ctx_11" use-headers use-vars
finish "Process server rules request" "ot_ctx_10"
event on-http-process-request
ot-scope tcp_rdp_cookie_request
extract "ot_ctx_11" use-vars
span "TCP RDP cookie request" follows-from "ot_ctx_11"
inject "ot_ctx_12" use-headers use-vars
finish "HTTP process request" "ot_ctx_11"
event on-tcp-rdp-cookie-request
ot-scope process_sticking_rules_request
extract "ot_ctx_12" use-vars
span "Process sticking rules request" follows-from "ot_ctx_12"
inject "ot_ctx_13" use-headers use-vars
finish "TCP RDP cookie request" "ot_ctx_12"
event on-process-sticking-rules-request
ot-scope client_session_end
finish "Client session" "ot_ctx_2"
event on-client-session-end
ot-scope server_unavailable
finish *
event on-server-unavailable
ot-scope server_session_start
span "Server session" child-of "ot_ctx_1"
inject "ot_ctx_14" use-vars
extract "ot_ctx_13" use-vars
finish "Process sticking rules request" "ot_ctx_13"
event on-server-session-start
ot-scope tcp_response
extract "ot_ctx_14" use-vars
span "TCP response" child-of "ot_ctx_14"
inject "ot_ctx_15" use-vars
event on-tcp-response
ot-scope http_wait_response
extract "ot_ctx_15" use-vars
span "HTTP wait response" follows-from "ot_ctx_15"
inject "ot_ctx_16" use-headers use-vars
finish "TCP response" "ot_ctx_15"
event on-http-wait-response
ot-scope process_store_rules_response
extract "ot_ctx_16" use-vars
span "Process store rules response" follows-from "ot_ctx_16"
inject "ot_ctx_17" use-headers use-vars
finish "HTTP wait response" "ot_ctx_16"
event on-process-store-rules-response
ot-scope http_response
extract "ot_ctx_17" use-vars
span "HTTP response" follows-from "ot_ctx_17"
tag "http.status_code" status
finish "Process store rules response" "ot_ctx_17"
event on-http-response
ot-scope http_response-error
span "HTTP response"
tag "error" bool(true)
event on-http-response if !acl-http-status-ok
ot-scope server_session_end
finish *
event on-server-session-end

View file

@ -0,0 +1,5 @@
{
"service": "EMPTY",
"agent_host": "localhost",
"agent_port": 8126
}

View file

@ -0,0 +1,34 @@
service_name:
EMPTY
###
# When using configuration object to instantiate the tracer, the type of
# sampling can be selected via sampler.type and sampler.param properties.
# Jaeger libraries support the following samplers:
#
# - Constant (sampler.type=const) sampler always makes the same decision for
# all traces. It either samples all traces (sampler.param=1) or none of
# them (sampler.param=0).
#
# - Probabilistic (sampler.type=probabilistic) sampler makes a random sampling
# decision with the probability of sampling equal to the value of
# sampler.param property. For example, with sampler.param=0.1 approximately
# 1 in 10 traces will be sampled.
#
# - Rate Limiting (sampler.type=ratelimiting) sampler uses a leaky bucket rate
# limiter to ensure that traces are sampled with a certain constant rate.
# For example, when sampler.param=2.0 it will sample requests with the rate
# of 2 traces per second.
#
# - Remote (sampler.type=remote, which is also the default) sampler consults
# Jaeger agent for the appropriate sampling strategy to use in the current
# service. This allows controlling the sampling strategies in the services
# from a central configuration in Jaeger backend, or even dynamically.
#
sampler:
type: ratelimiting
param: 10.0
reporter:
logSpans: true
localAgentHostPort: localhost:6831

View file

@ -0,0 +1,4 @@
{
"service_name": "EMPTY",
"collector_host": "localhost"
}

View file

@ -0,0 +1,30 @@
global
stats socket /tmp/haproxy.sock mode 666 level admin
defaults
log global
mode http
option httplog
option dontlognull
option httpclose
timeout connect 5000
timeout client 50000
timeout server 50000
listen stats
mode http
bind *:8001
stats uri /
stats admin if TRUE
stats refresh 10s
frontend ot-test-empty
bind *:10080
mode http
default_backend servers-backend
filter opentracing id ot-test-empty config empty/ot.cfg
backend servers-backend
mode http
server server-1 127.0.0.1:8000

View file

@ -0,0 +1,3 @@
ot-tracer ot-test-tracer
config empty/cfg-jaeger.yml
plugin libjaeger_opentracing_plugin-0.5.0.so

View file

@ -0,0 +1,5 @@
{
"service": "FE",
"agent_host": "localhost",
"agent_port": 8126
}

View file

@ -0,0 +1,34 @@
service_name:
FE
###
# When using configuration object to instantiate the tracer, the type of
# sampling can be selected via sampler.type and sampler.param properties.
# Jaeger libraries support the following samplers:
#
# - Constant (sampler.type=const) sampler always makes the same decision for
# all traces. It either samples all traces (sampler.param=1) or none of
# them (sampler.param=0).
#
# - Probabilistic (sampler.type=probabilistic) sampler makes a random sampling
# decision with the probability of sampling equal to the value of
# sampler.param property. For example, with sampler.param=0.1 approximately
# 1 in 10 traces will be sampled.
#
# - Rate Limiting (sampler.type=ratelimiting) sampler uses a leaky bucket rate
# limiter to ensure that traces are sampled with a certain constant rate.
# For example, when sampler.param=2.0 it will sample requests with the rate
# of 2 traces per second.
#
# - Remote (sampler.type=remote, which is also the default) sampler consults
# Jaeger agent for the appropriate sampling strategy to use in the current
# service. This allows controlling the sampling strategies in the services
# from a central configuration in Jaeger backend, or even dynamically.
#
sampler:
type: ratelimiting
param: 10.0
reporter:
logSpans: true
localAgentHostPort: localhost:6831

View file

@ -0,0 +1,4 @@
{
"service_name": "FE",
"collector_host": "localhost"
}

View file

@ -0,0 +1,37 @@
global
# nbthread 1
maxconn 5000
hard-stop-after 10s
# log localhost:514 local7 debug
# debug
stats socket /tmp/haproxy-fe.sock mode 666 level admin
defaults
log global
mode http
option httplog
option dontlognull
option httpclose
retries 3
maxconn 4000
timeout connect 5000
timeout client 50000
timeout server 50000
listen stats
mode http
bind *:8001
stats uri /
stats admin if TRUE
stats refresh 10s
frontend ot-test-fe-frontend
bind *:10080
mode http
default_backend servers-backend
filter opentracing id ot-test-fe config fe/ot.cfg
backend servers-backend
mode http
server server-1 127.0.0.1:11080

View file

@ -0,0 +1,74 @@
[ot-test-fe]
ot-tracer ot-test-tracer
config fe/cfg-jaeger.yml
plugin libjaeger_opentracing_plugin-0.5.0.so
# log localhost:514 local7 debug
option dontlog-normal
option hard-errors
no option disabled
rate-limit 100.0
scopes client_session_start
scopes frontend_tcp_request
scopes frontend_http_request
scopes backend_tcp_request
scopes backend_http_request
scopes client_session_end
scopes server_session_start
scopes tcp_response
scopes http_response
scopes server_session_end
ot-scope client_session_start
span "HAProxy session" root
baggage "haproxy_id" var(sess.ot.uuid)
span "Client session" child-of "HAProxy session"
event on-client-session-start
ot-scope frontend_tcp_request
span "Frontend TCP request" child-of "Client session"
event on-frontend-tcp-request
ot-scope frontend_http_request
span "Frontend HTTP request" follows-from "Frontend TCP request"
tag "http.method" method
tag "http.url" url
tag "http.version" str("HTTP/") req.ver
finish "Frontend TCP request"
event on-frontend-http-request
ot-scope backend_tcp_request
span "Backend TCP request" follows-from "Frontend HTTP request"
finish "Frontend HTTP request"
event on-backend-tcp-request
ot-scope backend_http_request
span "Backend HTTP request" follows-from "Backend TCP request"
finish "Backend TCP request"
span "HAProxy session"
inject "ot-ctx" use-headers
event on-backend-http-request
ot-scope client_session_end
finish "Client session"
event on-client-session-end
ot-scope server_session_start
span "Server session" child-of "HAProxy session"
finish "Backend HTTP request"
event on-server-session-start
ot-scope tcp_response
span "TCP response" child-of "Server session"
event on-tcp-response
ot-scope http_response
span "HTTP response" follows-from "TCP response"
tag "http.status_code" status
finish "TCP response"
event on-http-response
ot-scope server_session_end
finish *
event on-server-session-end

View file

@ -0,0 +1,5 @@
#!/bin/sh
#
test ${#} -lt 1 && exit 1
awk '/ {$/ { sub(/\(.*/, "", $5); print $5 }' "${@}" | sort | uniq -c

View file

@ -0,0 +1,45 @@
#!/bin/sh
#
_ARG_DIR="${1:-.}"
get ()
{
local _arg_tracer="${1}"
local _arg_version="${2}"
local _arg_url="${3}"
local _arg_file="${4}"
local _var_tmpfile="_tmpfile_"
local _var_plugin="lib${_arg_tracer}_opentracing_plugin-${_arg_version}.so"
test -e "${_var_plugin}" && return 0
wget "https://github.com/${_arg_url}/releases/download/v${_arg_version}/${_arg_file}" -O "${_var_tmpfile}" || {
rm "${_var_tmpfile}"
return 1
}
case "$(file ${_var_tmpfile})" in
*shared\ object*)
mv "${_var_tmpfile}" "${_var_plugin}" ;;
*gzip\ compressed\ data*)
gzip -cd "${_var_tmpfile}" > "${_var_plugin}"
rm "${_var_tmpfile}" ;;
esac
}
mkdir -p "${_ARG_DIR}" && cd "${_ARG_DIR}" || exit 1
get dd 1.1.2 DataDog/dd-opentracing-cpp linux-amd64-libdd_opentracing_plugin.so.gz
get dd 1.2.0 DataDog/dd-opentracing-cpp linux-amd64-libdd_opentracing_plugin.so.gz
get jaeger 0.4.2 jaegertracing/jaeger-client-cpp libjaegertracing_plugin.linux_amd64.so
#et jaeger 0.5.0 jaegertracing/jaeger-client-cpp libjaegertracing_plugin.linux_amd64.so
#et jaeger 0.6.0 jaegertracing/jaeger-client-cpp libjaegertracing_plugin.linux_amd64.so
get lightstep 0.12.0 lightstep/lightstep-tracer-cpp linux-amd64-liblightstep_tracer_plugin.so.gz
get lightstep 0.13.0 lightstep/lightstep-tracer-cpp linux-amd64-liblightstep_tracer_plugin.so.gz
get zipkin 0.5.2 rnburn/zipkin-cpp-opentracing linux-amd64-libzipkin_opentracing_plugin.so.gz

View file

@ -0,0 +1 @@
<html><body><p>Did I err?</p></body></html>

View file

@ -0,0 +1,13 @@
#!/bin/sh
#
_ARG_HAPROXY="${1:-$(realpath -L ${PWD}/../../../haproxy)}"
_ARGS="-f cmp/haproxy.cfg"
_LOG_DIR="_logs"
_LOG="${_LOG_DIR}/_log-$(basename ${0} .sh)-$(date +%s)"
test -x "${_ARG_HAPROXY}" || exit 1
mkdir -p "${_LOG_DIR}" || exit 2
echo "executing: ${_ARG_HAPROXY} ${_ARGS} > ${_LOG}"
"${_ARG_HAPROXY}" ${_ARGS} >"${_LOG}" 2>&1

View file

@ -0,0 +1,13 @@
#!/bin/sh
#
_ARG_HAPROXY="${1:-$(realpath -L ${PWD}/../../../haproxy)}"
_ARGS="-f ctx/haproxy.cfg"
_LOG_DIR="_logs"
_LOG="${_LOG_DIR}/_log-$(basename ${0} .sh)-$(date +%s)"
test -x "${_ARG_HAPROXY}" || exit 1
mkdir -p "${_LOG_DIR}" || exit 2
echo "executing: ${_ARG_HAPROXY} ${_ARGS} > ${_LOG}"
"${_ARG_HAPROXY}" ${_ARGS} >"${_LOG}" 2>&1

View file

@ -0,0 +1,47 @@
#!/bin/sh
#
_ARG_HAPROXY="${1:-$(realpath -L ${PWD}/../../../haproxy)}"
_ARGS_FE="-f fe/haproxy.cfg"
_ARGS_BE="-f be/haproxy.cfg"
_TIME="$(date +%s)"
_LOG_DIR="_logs"
_LOG_FE="${_LOG_DIR}/_log-$(basename ${0} fe-be.sh)fe-${_TIME}"
_LOG_BE="${_LOG_DIR}/_log-$(basename ${0} fe-be.sh)be-${_TIME}"
__exit ()
{
test -z "${2}" && {
echo
echo "Script killed!"
echo "Waiting for jobs to complete..."
pkill --signal SIGUSR1 haproxy
wait
}
test -n "${1}" && {
echo
echo "${1}"
echo
}
exit ${2:-100}
}
trap __exit INT TERM
test -x "${_ARG_HAPROXY}" || __exit "${_ARG_HAPROXY}: executable does not exist" 1
mkdir -p "${_LOG_DIR}" || __exit "${_ARG_HAPROXY}: cannot create log directory" 2
echo "\n------------------------------------------------------------------------"
echo "--- executing: ${_ARG_HAPROXY} ${_ARGS_BE} > ${_LOG_BE}"
"${_ARG_HAPROXY}" ${_ARGS_BE} >"${_LOG_BE}" 2>&1 &
echo "--- executing: ${_ARG_HAPROXY} ${_ARGS_FE} > ${_LOG_FE}"
"${_ARG_HAPROXY}" ${_ARGS_FE} >"${_LOG_FE}" 2>&1 &
echo "------------------------------------------------------------------------\n"
echo "Press CTRL-C to quit..."
wait

View file

@ -0,0 +1,13 @@
#!/bin/sh
#
_ARG_HAPROXY="${1:-$(realpath -L ${PWD}/../../../haproxy)}"
_ARGS="-f sa/haproxy.cfg"
_LOG_DIR="_logs"
_LOG="${_LOG_DIR}/_log-$(basename ${0} .sh)-$(date +%s)"
test -x "${_ARG_HAPROXY}" || exit 1
mkdir -p "${_LOG_DIR}" || exit 2
echo "executing: ${_ARG_HAPROXY} ${_ARGS} > ${_LOG}"
"${_ARG_HAPROXY}" ${_ARGS} >"${_LOG}" 2>&1

View file

@ -0,0 +1,5 @@
{
"service": "SA",
"agent_host": "localhost",
"agent_port": 8126
}

View file

@ -0,0 +1,34 @@
service_name:
SA
###
# When using configuration object to instantiate the tracer, the type of
# sampling can be selected via sampler.type and sampler.param properties.
# Jaeger libraries support the following samplers:
#
# - Constant (sampler.type=const) sampler always makes the same decision for
# all traces. It either samples all traces (sampler.param=1) or none of
# them (sampler.param=0).
#
# - Probabilistic (sampler.type=probabilistic) sampler makes a random sampling
# decision with the probability of sampling equal to the value of
# sampler.param property. For example, with sampler.param=0.1 approximately
# 1 in 10 traces will be sampled.
#
# - Rate Limiting (sampler.type=ratelimiting) sampler uses a leaky bucket rate
# limiter to ensure that traces are sampled with a certain constant rate.
# For example, when sampler.param=2.0 it will sample requests with the rate
# of 2 traces per second.
#
# - Remote (sampler.type=remote, which is also the default) sampler consults
# Jaeger agent for the appropriate sampling strategy to use in the current
# service. This allows controlling the sampling strategies in the services
# from a central configuration in Jaeger backend, or even dynamically.
#
sampler:
type: ratelimiting
param: 10.0
reporter:
logSpans: true
localAgentHostPort: localhost:6831

View file

@ -0,0 +1,4 @@
{
"service_name": "SA",
"collector_host": "localhost"
}

View file

@ -0,0 +1,40 @@
global
# nbthread 1
maxconn 5000
hard-stop-after 10s
# log localhost:514 local7 debug
# debug
stats socket /tmp/haproxy.sock mode 666 level admin
defaults
log global
mode http
option httplog
option dontlognull
option httpclose
retries 3
maxconn 4000
timeout connect 5000
timeout client 50000
timeout server 50000
listen stats
mode http
bind *:8001
stats uri /
stats admin if TRUE
stats refresh 10s
frontend ot-test-sa-frontend
bind *:10080
mode http
default_backend servers-backend
acl acl-http-status-ok status 100:399
filter opentracing id ot-test-sa config sa/ot.cfg
http-response ot-group ot-test-sa http_response_group if acl-http-status-ok
http-after-response ot-group ot-test-sa http_after_response_group if !acl-http-status-ok
backend servers-backend
mode http
server server-1 127.0.0.1:8000

View file

@ -0,0 +1,160 @@
[ot-test-sa]
ot-tracer ot-test-tracer
log localhost:514 local7 debug
config sa/cfg-jaeger.yml
plugin libjaeger_opentracing_plugin-0.5.0.so
option dontlog-normal
option hard-errors
no option disabled
rate-limit 100.0
groups http_response_group
groups http_after_response_group
scopes client_session_start
scopes frontend_tcp_request
scopes http_wait_request
scopes http_body_request
scopes frontend_http_request
scopes switching_rules_request
scopes backend_tcp_request
scopes backend_http_request
scopes process_server_rules_request
scopes http_process_request
scopes tcp_rdp_cookie_request
scopes process_sticking_rules_request
scopes client_session_end
scopes server_unavailable
scopes server_session_start
scopes tcp_response
scopes http_wait_response
scopes process_store_rules_response
scopes http_response http_response-error
scopes server_session_end
ot-group http_response_group
scopes http_response_1
scopes http_response_2
ot-scope http_response_1
span "HTTP response"
log "hdr.content" res.hdr("content-type") str("; length: ") res.hdr("content-length") str(" bytes")
ot-scope http_response_2
span "HTTP response"
log "hdr.date" res.hdr("date") str(" / ") res.hdr("last-modified")
ot-group http_after_response_group
scopes http_after_response
ot-scope http_after_response
span "HAProxy response" child-of "HAProxy session"
tag "error" bool(true)
tag "http.status_code" status
ot-scope client_session_start
span "HAProxy session" root
baggage "haproxy_id" var(sess.ot.uuid)
span "Client session" child-of "HAProxy session"
acl acl-test-src-ip src 127.0.0.1
event on-client-session-start if acl-test-src-ip
ot-scope frontend_tcp_request
span "Frontend TCP request" child-of "Client session"
event on-frontend-tcp-request
ot-scope http_wait_request
span "HTTP wait request" follows-from "Frontend TCP request"
finish "Frontend TCP request"
event on-http-wait-request
ot-scope http_body_request
span "HTTP body request" follows-from "HTTP wait request"
finish "HTTP wait request"
event on-http-body-request
ot-scope frontend_http_request
span "Frontend HTTP request" follows-from "HTTP body request"
tag "http.method" method
tag "http.url" url
tag "http.version" str("HTTP/") req.ver
finish "HTTP body request"
event on-frontend-http-request
ot-scope switching_rules_request
span "Switching rules request" follows-from "Frontend HTTP request"
finish "Frontend HTTP request"
event on-switching-rules-request
ot-scope backend_tcp_request
span "Backend TCP request" follows-from "Switching rules request"
finish "Switching rules request"
event on-backend-tcp-request
ot-scope backend_http_request
span "Backend HTTP request" follows-from "Backend TCP request"
finish "Backend TCP request"
event on-backend-http-request
ot-scope process_server_rules_request
span "Process server rules request" follows-from "Backend HTTP request"
finish "Backend HTTP request"
event on-process-server-rules-request
ot-scope http_process_request
span "HTTP process request" follows-from "Process server rules request"
finish "Process server rules request"
event on-http-process-request
ot-scope tcp_rdp_cookie_request
span "TCP RDP cookie request" follows-from "HTTP process request"
finish "HTTP process request"
event on-tcp-rdp-cookie-request
ot-scope process_sticking_rules_request
span "Process sticking rules request" follows-from "TCP RDP cookie request"
finish "TCP RDP cookie request"
event on-process-sticking-rules-request
ot-scope client_session_end
finish "Client session"
event on-client-session-end
ot-scope server_unavailable
finish *
event on-server-unavailable
ot-scope server_session_start
span "Server session" child-of "HAProxy session"
finish "Process sticking rules request"
event on-server-session-start
ot-scope tcp_response
span "TCP response" child-of "Server session"
event on-tcp-response
ot-scope http_wait_response
span "HTTP wait response" follows-from "TCP response"
finish "TCP response"
event on-http-wait-response
ot-scope process_store_rules_response
span "Process store rules response" follows-from "HTTP wait response"
finish "HTTP wait response"
event on-process-store-rules-response
ot-scope http_response
span "HTTP response" follows-from "Process store rules response"
tag "http.status_code" status
finish "Process store rules response"
event on-http-response
ot-scope http_response-error
span "HTTP response"
tag "error" bool(true)
event on-http-response if !acl-http-status-ok
ot-scope server_session_end
finish *
event on-server-session-end

View file

@ -0,0 +1,96 @@
#!/bin/sh
#
_ARG_CFG="${1}"
_ARG_DIR="${2}"
_LOG_DIR="_logs"
_HTTPD_PIDFILE="${_LOG_DIR}/thttpd.pid"
httpd_run ()
{
test -e "${_HTTPD_PIDFILE}" && return
thttpd -p 8000 -d . -nos -nov -l /dev/null -i "${_HTTPD_PIDFILE}"
}
httpd_stop ()
{
test -e "${_HTTPD_PIDFILE}" || return
kill -TERM "$(cat ${_HTTPD_PIDFILE})"
rm "${_HTTPD_PIDFILE}"
}
haproxy_run ()
{
_arg_ratio="${1}"
_var_sed_ot=
_var_sed_haproxy=
if test "${_arg_ratio}" = "disabled"; then
_var_sed_ot="s/no \(option disabled\)/\1/"
elif test "${_arg_ratio}" = "off"; then
_var_sed_haproxy="s/^\(.* filter opentracing .*\)/#\1/g; s/^\(.* ot-group .*\)/#\1/g"
else
_var_sed_ot="s/\(rate-limit\) 100.0/\1 ${_arg_ratio}/"
fi
sed "${_var_sed_haproxy}" "${_ARG_DIR}/haproxy.cfg.in" > "${_ARG_DIR}/haproxy.cfg"
sed "${_var_sed_ot}" "${_ARG_DIR}/ot.cfg.in" > "${_ARG_DIR}/ot.cfg"
if test "${_ARG_DIR}" = "fe"; then
if test "${_arg_ratio}" = "disabled" -o "${_arg_ratio}" = "off"; then
sed "${_var_sed_haproxy}" "be/haproxy.cfg.in" > "be/haproxy.cfg"
sed "${_var_sed_ot}" "be/ot.cfg.in" > "be/ot.cfg"
fi
fi
./run-${_ARG_CFG}.sh &
sleep 5
}
wrk_run ()
{
_arg_ratio="${1}"
echo "--- rate-limit ${_arg_ratio} --------------------------------------------------"
wrk -c8 -d300 -t8 --latency http://localhost:10080/index.html
echo "----------------------------------------------------------------------"
echo
sleep 10
}
mkdir -p "${_LOG_DIR}" || exit 1
if test "${_ARG_CFG}" = "all"; then
${0} fe-be fe > "${_LOG_DIR}/README-speed-fe-be"
${0} sa sa > "${_LOG_DIR}/README-speed-sa"
${0} cmp cmp > "${_LOG_DIR}/README-speed-cmp"
${0} ctx ctx > "${_LOG_DIR}/README-speed-ctx"
exit 0
fi
test -n "${_ARG_CFG}" -a -f "run-${_ARG_CFG}.sh" || exit 2
test -n "${_ARG_DIR}" -a -d "${_ARG_DIR}" || exit 3
test -e "${_ARG_DIR}/haproxy.cfg.in" || cp -af "${_ARG_DIR}/haproxy.cfg" "${_ARG_DIR}/haproxy.cfg.in"
test -e "${_ARG_DIR}/ot.cfg.in" || cp -af "${_ARG_DIR}/ot.cfg" "${_ARG_DIR}/ot.cfg.in"
if test "${_ARG_DIR}" = "fe"; then
test -e "be/haproxy.cfg.in" || cp -af "be/haproxy.cfg" "be/haproxy.cfg.in"
test -e "be/ot.cfg.in" || cp -af "be/ot.cfg" "be/ot.cfg.in"
fi
httpd_run
for _var_ratio in 100.0 50.0 10.0 2.5 0.0 disabled off; do
haproxy_run "${_var_ratio}"
wrk_run "${_var_ratio}"
pkill --signal SIGUSR1 haproxy
wait
done
httpd_stop