HAProxy & Lua: How to debug configurations

Because HAProxy configuration complexity increase using advanced things like stick-tables, we need some debugging tools.

This article shows 3 way for debug HAProxy configuration:

  • Enable some debug functions at compilation time
  • Debug Lua advanced structs
  • Use Lua function for debugging HAProxy

Compile HAProxy with debug functions

This compilation option is not famous because it is designed for developers. These debug option allow to get information about internal memory pool, SPOE protocol, and something like that. Anyway, one of these function is designed for debugging configuration.

Just enable a debug directive in the compilation options:

$ make TARGET=linux DEBUG=-DDEBUG_EXPR

This compilation directive simply add a new converter which display information about his input value on the standard output and return it unchanged. The debug directive is used to watch type and content of saple fetches. This is a simple HAProxy configuration:

global
    stats socket /tmp/haproxy.sock mode 644 level admin

defaults
    timeout client 1m
    timeout server 1m

listen sample1
    mode http
    bind *:10010
    acl is_redir path,debug -m beg /old-stuff
    http-request redirect location /redir if is_redir
    http-request redirect location /main

Start haproxy like below. It is absolutely necessary to start HAProxy in debug mode, otherwise the debug information can't be displayed.

./haproxy -d -f haproxy-debug.conf

And use Curl command for activating debug:

$ curl "http://127.0.0.1:10010/test"

The result is:

$ ./haproxy -d -f haproxy-debug.conf
Note: setting global.maxconn to 2000.
Available polling systems :
        poll : pref=200,  test result OK
        select : pref=150,  test result FAILED
Total: 2 (1 usable), will use poll.

Available filters :
        [COMP] compression
        [TRACE] trace
        [SPOE] spoe
Using poll() as the polling mechanism.
00000000:sample1.accept(0004)=0005 from [127.0.0.1:41392]
00000000:sample1.clireq[0005:ffffffff]: GET /test HTTP/1.1
00000000:sample1.clihdr[0005:ffffffff]: User-Agent: curl/7.26.0
00000000:sample1.clihdr[0005:ffffffff]: Host: 127.0.0.1:10010
00000000:sample1.clihdr[0005:ffffffff]: Accept: */*
[debug converter] type: str </test>
00000001:sample1.clicls[0005:ffffffff]
00000001:sample1.closed[0005:ffffffff]

Lua print_r() function

Modern script languages like PHP or Python provides a debug function which dumps variables values and their metadata. There are respectively var_dump() and pprint(). These kind of function are useful for debugging scripts.

I do not found this kind of fucntion with Lua, so the following is mine.

You can embed this tool with the Lua line require("print_r"). For displaying a variable, you can write print_r(my_var). The variable will be displayed on stdout with ANSI colors.

The prototype is:

print_r(<var> [, <color (boolean)> [, <display (function)>]])
  • <var> is the displayed variable
  • <color> if true, use ANSI color. if false, displays flat text.
  • <display> The prototype of this function is function(msg).

This function is called each time that we want. The following call example can be included in the first Lua file loaded by HAProxy and displays the provided lua structure.

require("print_r")
print_r(core)

Debug HAProxy configuration using Lua

This method is approximatively the same than the "debug" converter. The way is writing a lua converter which dumps its input and return it. This method works only with string, any input is converted as string. The main advantage is using HAProxy without recompile it. Just write this simple function:

require("print_r");

core.register_converters("debug", function(data, name)
    print_r("["..name.."] :<"..data..">")
end)

And used it like this in the haproxy configuraiton file:

global
    lua-load debug.lua
    stats socket /tmp/haproxy.sock mode 644 level admin

defaults
    timeout client 1m
    timeout server 1m

listen sample1
    mode http
    bind *:10010
    acl is_redir path,lua.debug(PATH) -m beg /old-stuff
    http-request redirect location /redir if is_redir
    http-request redirect location /main
$ ./haproxy -d -f haproxy-debug.conf

And use Curl command for activating debug:

$ curl "http://127.0.0.1:10010/test"

The result is:

$ ./haproxy -d -f haproxy-debug.conf
Note: setting global.maxconn to 2000.
Available polling systems :
        poll : pref=200,  test result OK
        select : pref=150,  test result FAILED
Total: 2 (1 usable), will use poll.

Available filters :
        [COMP] compression
        [TRACE] trace
        [SPOE] spoe
Using poll() as the polling mechanism.
00000000:sample1.accept(0004)=0005 from [127.0.0.1:41667]
00000000:sample1.clireq[0005:ffffffff]: GET /test HTTP/1.1
00000000:sample1.clihdr[0005:ffffffff]: User-Agent: curl/7.26.0
00000000:sample1.clihdr[0005:ffffffff]: Host: 127.0.0.1:10010
00000000:sample1.clihdr[0005:ffffffff]: Accept: */*
(string) "[PATH] :</test>"
00000001:sample1.clicls[0005:ffffffff]
00000001:sample1.closed[0005:ffffffff]