ddtcorex

15 Sept 2026 · 3 min read

Debugging inside Govard: Xdebug, logs, and introspection

Wiring Xdebug, reading container logs, and introspecting the database from a Govard environment

Part 3 of the Govard deep-dive series — wiring Xdebug, reading logs, and introspecting the database from a throwaway environment.

Why debug in a throwaway environment, not in production

When something misbehaves in production, the instinct is to add a log line, deploy, and watch. That turnaround is slow, risky, and often invisible to you entirely — you may not have permission to change the deployed code, and a stray debug statement can leak data or break a customer's session. A throwaway Govard environment removes every one of those constraints: it is a copy of the stack you control, where stepping through code costs nothing.

The deeper point is psychological. In a safe environment you can afford to be wrong — set a breakpoint, watch a variable, break the thing on purpose to see how it fails. That freedom is where most real root causes surface, and it is exactly what production never offers.

Enabling Xdebug in the container

Xdebug ships with the PHP image but stays off until you ask for it. Enable it through configuration and bring the environment up; the debugger then listens on its forwarded port:

# .govard.yml (or a .govard.debug.yml profile)
php:
  version: "8.3"
  xdebug:
    enabled: true
    mode: debug
    idekey: PHPSTORM
    host: host.docker.internal

Your IDE connects to the forwarded port, and a request with the Xdebug session cookie triggers a step-debug session. Because the port is container-forwarded, the IDE on your host talks to the debugger as if it were local.

Reading logs and introspecting the database

Logs are centralized per environment. PHP, NGINX, and Magento each write to their own stream, and govard env logs tails them together so you can correlate a slow request with the PHP warning that caused it:

govard env logs              # tail all service logs
govard env logs --service php-fpm

For the database, drop into a shell rather than guessing. The same container that serves the store is reachable from govard db, and you can inspect a core config value directly:

govard db cli               # open a MySQL/MariaDB shell
# SELECT * FROM core_config_data
#   WHERE path LIKE 'Magento\Framework\App\Config::...';

When you need the search backend instead, the govard family exposes the Elasticsearch or OpenSearch container the same way, so you can query an index without leaving the environment. For profiling entry points, the engine's audit tooling hooks the request lifecycle — enabling it captures timings without modifying application code.

Pitfalls

  • Xdebug port not forwarded. If the IDE never breaks, check that the debug port is published from the container and that host.docker.internal resolves on your host.
  • Log volume growth. Long-lived environments accumulate large logs; rotate or tear down preview envs so a week of debugging does not fill the disk.
  • Profiling overhead. Keep profiling off in day-to-day work — it adds measurable latency and can mask the very performance issue you are trying to measure.

Next in this series: Customizing Govard for your team's stack — /blog/govard-customizing

magento2govarddebugging