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.
diff --git a/contrib/opentracing/test/README-speed-cmp b/contrib/opentracing/test/README-speed-cmp
new file mode 100644
index 0000000..9251faa
--- /dev/null
+++ b/contrib/opentracing/test/README-speed-cmp
@@ -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
+----------------------------------------------------------------------
diff --git a/contrib/opentracing/test/README-speed-ctx b/contrib/opentracing/test/README-speed-ctx
new file mode 100644
index 0000000..fa8fc2c
--- /dev/null
+++ b/contrib/opentracing/test/README-speed-ctx
@@ -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
+----------------------------------------------------------------------
diff --git a/contrib/opentracing/test/README-speed-fe-be b/contrib/opentracing/test/README-speed-fe-be
new file mode 100644
index 0000000..ab2b7af
--- /dev/null
+++ b/contrib/opentracing/test/README-speed-fe-be
@@ -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
+----------------------------------------------------------------------
diff --git a/contrib/opentracing/test/README-speed-sa b/contrib/opentracing/test/README-speed-sa
new file mode 100644
index 0000000..ea8749d
--- /dev/null
+++ b/contrib/opentracing/test/README-speed-sa
@@ -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
+----------------------------------------------------------------------
diff --git a/contrib/opentracing/test/be/cfg-dd.json b/contrib/opentracing/test/be/cfg-dd.json
new file mode 100644
index 0000000..8b69b03
--- /dev/null
+++ b/contrib/opentracing/test/be/cfg-dd.json
@@ -0,0 +1,5 @@
+{
+    "service":    "BE",
+    "agent_host": "localhost",
+    "agent_port": 8126
+}
diff --git a/contrib/opentracing/test/be/cfg-jaeger.yml b/contrib/opentracing/test/be/cfg-jaeger.yml
new file mode 100644
index 0000000..0893166
--- /dev/null
+++ b/contrib/opentracing/test/be/cfg-jaeger.yml
@@ -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
diff --git a/contrib/opentracing/test/be/cfg-zipkin.json b/contrib/opentracing/test/be/cfg-zipkin.json
new file mode 100644
index 0000000..f0e30d5
--- /dev/null
+++ b/contrib/opentracing/test/be/cfg-zipkin.json
@@ -0,0 +1,4 @@
+{
+    "service_name":   "BE",
+    "collector_host": "localhost"
+}
diff --git a/contrib/opentracing/test/be/haproxy.cfg b/contrib/opentracing/test/be/haproxy.cfg
new file mode 100644
index 0000000..c225a2f
--- /dev/null
+++ b/contrib/opentracing/test/be/haproxy.cfg
@@ -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
diff --git a/contrib/opentracing/test/be/ot.cfg b/contrib/opentracing/test/be/ot.cfg
new file mode 100644
index 0000000..edd3f76
--- /dev/null
+++ b/contrib/opentracing/test/be/ot.cfg
@@ -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
diff --git a/contrib/opentracing/test/cmp/cfg-dd.json b/contrib/opentracing/test/cmp/cfg-dd.json
new file mode 100644
index 0000000..a931f45
--- /dev/null
+++ b/contrib/opentracing/test/cmp/cfg-dd.json
@@ -0,0 +1,5 @@
+{
+    "service":    "CMP",
+    "agent_host": "localhost",
+    "agent_port": 8126
+}
diff --git a/contrib/opentracing/test/cmp/cfg-jaeger.yml b/contrib/opentracing/test/cmp/cfg-jaeger.yml
new file mode 100644
index 0000000..78efc2d
--- /dev/null
+++ b/contrib/opentracing/test/cmp/cfg-jaeger.yml
@@ -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
diff --git a/contrib/opentracing/test/cmp/cfg-zipkin.json b/contrib/opentracing/test/cmp/cfg-zipkin.json
new file mode 100644
index 0000000..7e9d3dd
--- /dev/null
+++ b/contrib/opentracing/test/cmp/cfg-zipkin.json
@@ -0,0 +1,4 @@
+{
+    "service_name":   "CMP",
+    "collector_host": "localhost"
+}
diff --git a/contrib/opentracing/test/cmp/haproxy.cfg b/contrib/opentracing/test/cmp/haproxy.cfg
new file mode 100644
index 0000000..9d22725
--- /dev/null
+++ b/contrib/opentracing/test/cmp/haproxy.cfg
@@ -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
diff --git a/contrib/opentracing/test/cmp/ot.cfg b/contrib/opentracing/test/cmp/ot.cfg
new file mode 100644
index 0000000..21b15dd
--- /dev/null
+++ b/contrib/opentracing/test/cmp/ot.cfg
@@ -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
diff --git a/contrib/opentracing/test/ctx/cfg-dd.json b/contrib/opentracing/test/ctx/cfg-dd.json
new file mode 100644
index 0000000..f68d97a
--- /dev/null
+++ b/contrib/opentracing/test/ctx/cfg-dd.json
@@ -0,0 +1,5 @@
+{
+    "service":    "CTX",
+    "agent_host": "localhost",
+    "agent_port": 8126
+}
diff --git a/contrib/opentracing/test/ctx/cfg-jaeger.yml b/contrib/opentracing/test/ctx/cfg-jaeger.yml
new file mode 100644
index 0000000..659724a
--- /dev/null
+++ b/contrib/opentracing/test/ctx/cfg-jaeger.yml
@@ -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
diff --git a/contrib/opentracing/test/ctx/cfg-zipkin.json b/contrib/opentracing/test/ctx/cfg-zipkin.json
new file mode 100644
index 0000000..3a3a257
--- /dev/null
+++ b/contrib/opentracing/test/ctx/cfg-zipkin.json
@@ -0,0 +1,4 @@
+{
+    "service_name":   "CTX",
+    "collector_host": "localhost"
+}
diff --git a/contrib/opentracing/test/ctx/haproxy.cfg b/contrib/opentracing/test/ctx/haproxy.cfg
new file mode 100644
index 0000000..d240a99
--- /dev/null
+++ b/contrib/opentracing/test/ctx/haproxy.cfg
@@ -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
diff --git a/contrib/opentracing/test/ctx/ot.cfg b/contrib/opentracing/test/ctx/ot.cfg
new file mode 100644
index 0000000..a06a4e0
--- /dev/null
+++ b/contrib/opentracing/test/ctx/ot.cfg
@@ -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
diff --git a/contrib/opentracing/test/empty/cfg-dd.json b/contrib/opentracing/test/empty/cfg-dd.json
new file mode 100644
index 0000000..38b65f1
--- /dev/null
+++ b/contrib/opentracing/test/empty/cfg-dd.json
@@ -0,0 +1,5 @@
+{
+    "service":    "EMPTY",
+    "agent_host": "localhost",
+    "agent_port": 8126
+}
diff --git a/contrib/opentracing/test/empty/cfg-jaeger.yml b/contrib/opentracing/test/empty/cfg-jaeger.yml
new file mode 100644
index 0000000..08fadd8
--- /dev/null
+++ b/contrib/opentracing/test/empty/cfg-jaeger.yml
@@ -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
diff --git a/contrib/opentracing/test/empty/cfg-zipkin.json b/contrib/opentracing/test/empty/cfg-zipkin.json
new file mode 100644
index 0000000..55fde9f
--- /dev/null
+++ b/contrib/opentracing/test/empty/cfg-zipkin.json
@@ -0,0 +1,4 @@
+{
+    "service_name":   "EMPTY",
+    "collector_host": "localhost"
+}
diff --git a/contrib/opentracing/test/empty/haproxy.cfg b/contrib/opentracing/test/empty/haproxy.cfg
new file mode 100644
index 0000000..9d40db9
--- /dev/null
+++ b/contrib/opentracing/test/empty/haproxy.cfg
@@ -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
diff --git a/contrib/opentracing/test/empty/ot.cfg b/contrib/opentracing/test/empty/ot.cfg
new file mode 100644
index 0000000..961c8bc
--- /dev/null
+++ b/contrib/opentracing/test/empty/ot.cfg
@@ -0,0 +1,3 @@
+ot-tracer ot-test-tracer
+    config empty/cfg-jaeger.yml
+    plugin libjaeger_opentracing_plugin-0.5.0.so
diff --git a/contrib/opentracing/test/fe/cfg-dd.json b/contrib/opentracing/test/fe/cfg-dd.json
new file mode 100644
index 0000000..84afe56
--- /dev/null
+++ b/contrib/opentracing/test/fe/cfg-dd.json
@@ -0,0 +1,5 @@
+{
+    "service":    "FE",
+    "agent_host": "localhost",
+    "agent_port": 8126
+}
diff --git a/contrib/opentracing/test/fe/cfg-jaeger.yml b/contrib/opentracing/test/fe/cfg-jaeger.yml
new file mode 100644
index 0000000..1365efa
--- /dev/null
+++ b/contrib/opentracing/test/fe/cfg-jaeger.yml
@@ -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
diff --git a/contrib/opentracing/test/fe/cfg-zipkin.json b/contrib/opentracing/test/fe/cfg-zipkin.json
new file mode 100644
index 0000000..1546b10
--- /dev/null
+++ b/contrib/opentracing/test/fe/cfg-zipkin.json
@@ -0,0 +1,4 @@
+{
+    "service_name":   "FE",
+    "collector_host": "localhost"
+}
diff --git a/contrib/opentracing/test/fe/haproxy.cfg b/contrib/opentracing/test/fe/haproxy.cfg
new file mode 100644
index 0000000..bfc0ec9
--- /dev/null
+++ b/contrib/opentracing/test/fe/haproxy.cfg
@@ -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
diff --git a/contrib/opentracing/test/fe/ot.cfg b/contrib/opentracing/test/fe/ot.cfg
new file mode 100644
index 0000000..11de828
--- /dev/null
+++ b/contrib/opentracing/test/fe/ot.cfg
@@ -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
diff --git a/contrib/opentracing/test/func-stat.sh b/contrib/opentracing/test/func-stat.sh
new file mode 100755
index 0000000..cf5bd9e
--- /dev/null
+++ b/contrib/opentracing/test/func-stat.sh
@@ -0,0 +1,5 @@
+#!/bin/sh
+#
+test ${#} -lt 1 && exit 1
+
+awk '/ {$/ { sub(/\(.*/, "", $5); print $5 }' "${@}" | sort | uniq -c
diff --git a/contrib/opentracing/test/get-opentracing-plugins.sh b/contrib/opentracing/test/get-opentracing-plugins.sh
new file mode 100755
index 0000000..f2fe2d6
--- /dev/null
+++ b/contrib/opentracing/test/get-opentracing-plugins.sh
@@ -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
diff --git a/contrib/opentracing/test/index.html b/contrib/opentracing/test/index.html
new file mode 100644
index 0000000..09ed6fa
--- /dev/null
+++ b/contrib/opentracing/test/index.html
@@ -0,0 +1 @@
+<html><body><p>Did I err?</p></body></html>
diff --git a/contrib/opentracing/test/run-cmp.sh b/contrib/opentracing/test/run-cmp.sh
new file mode 100755
index 0000000..77b48bd
--- /dev/null
+++ b/contrib/opentracing/test/run-cmp.sh
@@ -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
diff --git a/contrib/opentracing/test/run-ctx.sh b/contrib/opentracing/test/run-ctx.sh
new file mode 100755
index 0000000..064fa7d
--- /dev/null
+++ b/contrib/opentracing/test/run-ctx.sh
@@ -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
diff --git a/contrib/opentracing/test/run-fe-be.sh b/contrib/opentracing/test/run-fe-be.sh
new file mode 100755
index 0000000..7e70ad6
--- /dev/null
+++ b/contrib/opentracing/test/run-fe-be.sh
@@ -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
diff --git a/contrib/opentracing/test/run-sa.sh b/contrib/opentracing/test/run-sa.sh
new file mode 100755
index 0000000..e5682ea
--- /dev/null
+++ b/contrib/opentracing/test/run-sa.sh
@@ -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
diff --git a/contrib/opentracing/test/sa/cfg-dd.json b/contrib/opentracing/test/sa/cfg-dd.json
new file mode 100644
index 0000000..0c476f7
--- /dev/null
+++ b/contrib/opentracing/test/sa/cfg-dd.json
@@ -0,0 +1,5 @@
+{
+    "service":    "SA",
+    "agent_host": "localhost",
+    "agent_port": 8126
+}
diff --git a/contrib/opentracing/test/sa/cfg-jaeger.yml b/contrib/opentracing/test/sa/cfg-jaeger.yml
new file mode 100644
index 0000000..e14f91e
--- /dev/null
+++ b/contrib/opentracing/test/sa/cfg-jaeger.yml
@@ -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
diff --git a/contrib/opentracing/test/sa/cfg-zipkin.json b/contrib/opentracing/test/sa/cfg-zipkin.json
new file mode 100644
index 0000000..9d155ba
--- /dev/null
+++ b/contrib/opentracing/test/sa/cfg-zipkin.json
@@ -0,0 +1,4 @@
+{
+    "service_name":   "SA",
+    "collector_host": "localhost"
+}
diff --git a/contrib/opentracing/test/sa/haproxy.cfg b/contrib/opentracing/test/sa/haproxy.cfg
new file mode 100644
index 0000000..988e3ab
--- /dev/null
+++ b/contrib/opentracing/test/sa/haproxy.cfg
@@ -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
diff --git a/contrib/opentracing/test/sa/ot.cfg b/contrib/opentracing/test/sa/ot.cfg
new file mode 100644
index 0000000..ae7413b
--- /dev/null
+++ b/contrib/opentracing/test/sa/ot.cfg
@@ -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
diff --git a/contrib/opentracing/test/test-speed.sh b/contrib/opentracing/test/test-speed.sh
new file mode 100755
index 0000000..ef2ccf0
--- /dev/null
+++ b/contrib/opentracing/test/test-speed.sh
@@ -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