Skip to main content

Set Breakpoints

APISIX ships an inspect plugin that lets you set breakpoint-style hooks on any line of any Lua file loaded by the worker. When execution reaches a hooked line, the plugin captures the local variables and upvalues at that point and runs a filter function that you define, typically to log values or to fire only when a specific condition is met.

This guide is aimed at users who write their own Lua plugins for APISIX (see Create a Plugin in Lua) and need to confirm what their plugin is seeing in a running worker without redeploying or restarting APISIX. The same mechanism can be used to inspect APISIX's own Lua source if you are debugging the gateway itself.

This guide will show you how to enable the inspect plugin, set up a hooks file, and read the captured values from the error log.

Prerequisite(s)

  • A running APISIX instance. Follow the Getting Started tutorial if you do not have one.
  • Shell access to the host or container where the APISIX worker is running, with write access to /usr/local/apisix/.

Enable the Inspect Plugin

To enable the plugin, make sure inspect is listed under plugins in your configuration file:

conf/config.yaml
plugins:
- inspect
# ... other plugins

You can optionally tune the hooks file path and poll interval under plugin_attr:

conf/config.yaml
plugin_attr:
inspect:
delay: 3
hooks_file: "/usr/local/apisix/plugin_inspect_hooks.lua"

delay is the poll interval in seconds at which the plugin re-reads the hooks file. hooks_file is the path the plugin watches; whenever its contents change, the plugin re-installs hooks on the next poll without a restart.

Reload APISIX after changing the configuration file.

Set Up a Hook

Create the hooks file at the path you configured above. The example below hooks a custom plugin at apisix/plugins/my-plugin.lua and logs the value of a local variable named conf whenever line 42 of that file is reached:

/usr/local/apisix/plugin_inspect_hooks.lua
local dbg = require("apisix.inspect.dbg")

dbg.set_hook(
"/usr/local/apisix/apisix/plugins/my-plugin.lua",
42,
nil,
function(info)
ngx.log(ngx.WARN, "conf at line 42: ",
require("cjson").encode(info.vals.conf))
return false
end
)

Within the poll interval (three seconds by default), the plugin picks up the new file and installs the hook. You should see a set hooks message in the error log listing the active hook keys.

To verify, send a request that exercises the plugin you hooked:

curl -i "http://127.0.0.1:9080/anything"

Check the error log. The filter runs the first time the hooked line is reached, and because the filter returns false, the hook stays installed and runs again on every subsequent hit. You should see a line similar to the following:

conf at line 42: {"some_key":"some_value"}

To register more than one hook, call dbg.set_hook again in the same file. To remove all hooks, delete the hooks file. APISIX detects the missing file on the next poll cycle and clears the hook table.

caution

The hooks file is executed as Lua code inside the APISIX worker. Anyone with write access to the file can run arbitrary Lua in the gateway process. Restrict filesystem permissions on this path accordingly.

How It Works

Each hook is identified by a file#line key, which is the same key that the plugin uses in its set hooks and remove hook log messages.

When the Lua VM reaches the hooked line, the filter function is called with a single info table that contains:

  • info.finfo: the result of debug.getinfo at that line, including the source file, current line number, and function name.
  • info.vals: a table of the local variables in scope at that line, keyed by name.
  • info.uv: a table of the upvalues captured by the enclosing function, also keyed by name.

The return value of the filter controls the hook lifetime:

  • Returning false keeps the hook installed and active on the next hit.
  • Returning any other value, including true or nil, removes the hook after this run.
  • If the filter raises a Lua error, the hook is removed and the error is logged.
caution

Installing a hook disables the LuaJIT compiler for the entire worker process, not only the function containing the hooked line. While any hook is installed:

  • The worker continues to serve traffic, but every Lua code path in it falls back to the interpreter and can be substantially slower under load.
  • The JIT compiler is re-enabled only after every hook has been removed, either by the filter returning a value other than false or by deleting the hooks file.

Avoid leaving hooks installed under heavy traffic, and remove them as soon as you have the information you need.

Hooks are per-worker and held in memory only. Each worker installs hooks based on what it reads from the hooks file, and there is no cross-worker coordination. If you restart APISIX, hooks are cleared until each worker re-reads the file on its next poll cycle.

Next Steps

You have now learned how to use the inspect plugin to capture runtime values from a live APISIX worker.

  • To write the custom Lua plugin you are inspecting, see Create a Plugin in Lua.
  • For complementary debugging at the request level rather than the Lua line level, see Use Debug Mode.
API7.ai Logo

The digital world is connected by APIs,
API7.ai exists to make APIs more efficient, reliable, and secure.

Sign up for API7 newsletter

Product

API7 Gateway

SOC2 Type IIISO 27001HIPAAGDPRRed Herring

Copyright © APISEVEN PTE. LTD 2019 – 2026. Apache, Apache APISIX, APISIX, and associated open source project names are trademarks of the Apache Software Foundation