Full-Stack Debugging with Structured Logging

Full-Stack Debugging with Structured Logging

In this step, you’ll learn how to debug issues that only appear when multiple parts of your application work together. Unlike unit tests, which isolate functions and logic, full-stack bugs emerge from the interaction between the frontend (browser), backend (Next.js), and the database. To debug these effectively, you’ll need to combine logging with a unified orchestration workflow so that Copilot can see the entire system executing in one place.

This section teaches you how to leverage Copilot to insert targeted logs, run full browser-driven E2E tests, and trace data across environments to uncover the root cause.

Problem

Your task is to work with GitHub Copilot to diagnose and fix a full-stack bug described in BUG_REPORT.md on the debug-2 branch. This bug only appears during a real browser-driven workflow, not in unit tests — meaning Copilot must observe both the server and the browser execution at the same time.

Debugging this kind of defect requires two key capabilities:

  1. Logging: inserting detailed, well-structured logs across both the frontend and backend to trace what the system is actually doing.

  2. Orchestration: running the dev server and Playwright E2E tests together in a way that Copilot can reliably monitor and react to output from both processes.

What You Need to Know

Why Full-Stack Bugs Require Richer Debugging

Unit tests validate isolated behaviors. But real-world bugs often emerge only when multiple systems interact:

  • the frontend sends data to the backend

  • the backend modifies database state

  • the frontend updates UI state based on responses

  • the browser reflects the final outcome

When something goes wrong in this chain, you may see no stack traces, no visible errors — just incorrect behavior.
That’s why deep logging and cross-environment observation are essential.

Full-stack debugging isn’t about catching exceptions; it’s about reconstructing the flow of truth across systems.

Logging as a Full-Stack Debugging Tool

Copilot is extremely effective at inserting “trace logs” across your code. For multi-environment debugging, good logs should:

  • print important variables (database payloads, request bodies, UI state snapshots)

  • appear at each step in the request/response lifecycle

  • clearly distinguish frontend vs backend output

  • optionally include custom stack traces for deep insight

Well-designed logs allow you and Copilot to:

  • see where the data flow deviates from expectations

  • track state changes across layers

  • detect timing issues and race conditions

  • understand what actually happened, not just what the code should have done

And because Copilot can insert, refine, and later remove logs in bulk, it becomes an efficient partner in exploratory debugging.

Orchestration with VS Code Tasks

How Copilot Orchestrates Multiple Processes

GitHub Copilot can manage complex development workflows by coordinating multiple processes at once — such as running a dev server and executing E2E tests together. With VS Code Tasks, Copilot gains a structured environment that allows it to:

  • spawn multiple terminals

  • run independent processes in parallel

  • monitor outputs from each terminal in real time

  • respond intelligently to events from different environments

  • sequence actions based on log activity (“once the server is ready, start the tests”)

This makes full-stack debugging far more powerful and predictable.

Why Tasks Enable Reliable Multi-Process Control

VS Code Tasks provide Copilot with a consistent, well-defined interface for running commands. You can configure tasks in the .vscode/tasks.json. It’s best to have Copilot help you write this file, as writing it from scratch can be tedious.

Each task has:

  • a label

  • a shell command

  • a dedicated terminal

  • optional background or watch modes

  • predictable lifecycles and statuses

Because tasks behave consistently, Copilot can confidently orchestrate them without guesswork.

For example, when you say:

“Run the dev server, and once it’s ready, run the E2Es.”

Copilot will:

  1. launch the dev server task

  2. watch its terminal until startup logs indicate readiness

  3. start the E2E task in another terminal

  4. read and correlate logs across both environments

  5. make decisions or suggest fixes based on combined output

Example Prompt: Copilot writes a task for you

Generate a task in .vscode/tasks.json that runs the e2e tests. It should find and terminate any processes running on port 3000, start the dev server, then once it’s loaded run the tests.

What VS Code Manages for You

VS Code handles all the process plumbing so Copilot doesn’t have to:

  • Named terminals → predictable, stable output streams

  • Long-running task management → dev servers, watchers, background jobs

  • Task sequencing → run one after another or in parallel

  • Consistent output routing → Copilot always knows where logs will appear

  • Automatic cleanup → stopping tasks when debugging is complete

Together, these features give Copilot the ability to orchestrate full-stack workflows with clarity and control, enabling real-time understanding of how your system behaves across multiple layers.

How Logs Flow in a Multi-Task Environment

VS Code ensures that task output is:

  • grouped by task / terminal

  • consistently formatted

  • available for Copilot to read sequentially

Playwright can also be configured to forward browser console events to its terminal stream:

  • console.log

  • console.error

  • network events

  • page crashes

  • test step tracing

When combined with the server logs, Copilot gets a complete picture:

[Server] API route hit with payload: { ... } [Browser] Button clicked: "Submit" [Browser] Form state: { ... } [Server] Database update → success [Browser] UI updated with new task

This gives the AI enough visibility to follow the chain of cause and effect across the entire stack.

Writing to Log Files (Optional)

In some debugging scenarios — especially for nondeterministic bugs — it’s useful to:

  • write logs to a file

  • ask Copilot to analyze the file after execution

This can supplement the real-time terminal view for deeper historical analysis.

The Full-Stack Debugging Prompt

This step uses a dedicated debugging prompt located in .github/prompts, which is also accessible directly from Copilot by typing /debug-with-logs in the agent chat window.

 

You are a senior developer helping to debug issues in a codebase. A user has reported a bug and you need to help them identify and fix the issue by examining the bug report outlined in BUG_REPORT.md.

Follow the below steps to debug the issue. It's important that everything you do is transparent to the user. For each step, explain what you are doing and why with clear reasoning and documentation. Format your output as a numbered list of steps taken to debug the issue following the list below:

  1. Understand the Bug Report: Carefully read the bug report to understand the issue, including the steps to reproduce, current behavior, expected behavior, and environment details.

  2. Identify Relevant Code Areas: Based on the bug report, identify which parts of the codebase are likely involved in the issue (e.g., task editing logic, database update functions, UI components).

  3. Add logging: Add logs to both the front end and back end code paths involved. In every log, include which file you're in as well as the function and any other relevant information. This will help trace the flow of data and identify where the update is failing.

  4. Run the tests: Run the unit and E2E tests to see if the bug can be reproduced in the test environment. Note any failures or unexpected behaviors. The dev server can be run as a VS Code task, as can the tests. Be sure to use tasks instead of running commands directly in the terminal to ensure the environment is set up correctly.

  • The E2E tests expect a local dev server to be running at <http://localhost:3000,> so make sure to kill any other instances running on port 3000 before running the e2e:debug command.

  • E2E tests can be filtered using the -g option to focus on tests related to the bug report. For example, if the bug report is about editing a task via a modal form, you can run (prefer to use a task for this):

    npm run test:e2e:debug -- -g "edit task via modal form"
  1. (OPTIONAL) Write a new test: If no existing test covers the bug scenario, write a new unit or E2E test that reproduces the bug based on the steps provided in the bug report. This will help ensure that the bug is captured and can be verified as fixed later. Run the new test to confirm it fails as expected.

  2. Fix the Bug: Investigate the logs and code to identify the root cause of the issue. Implement a fix to ensure that the task assignee updates correctly and persists after a page refresh.

  3. Verify the Fix: Re-run the unit and E2E tests to confirm that the bug has been resolved and that no other functionality is broken.

  4. Clean Up: Remove any logging added during the debugging process to keep the codebase clean.

✏️ Hands-On Exploration

Rather than manually stepping through logging, orchestration, and debugging, you will use the provided prompt to guide Copilot through the entire workflow. Your role is to observe how Copilot reasons, what logs it adds, and how it identifies the root cause.

  1. Checkout out the bug-2 branch in TaskFlow

    1. Commit or reset any changes made by Copilot;

      1. Commit git add . && git commit -m “changes“

      2. Reset git reset --hard HEAD && git clean -fd

    2. Check out the new branch

      1. git switch bug-2

  2. Explore the bug outlined in BUG_REPORT.md

    1. Replicate it in TaskFlow and make sure you understand what the problem is

  3. Run the e2e tests normally

    1. Start the dev server npm run dev

    2. In another terminal, run the e2es npm run test:e2e

      1. You may need to re-install the playwright browsers npx playwright install chromium

  4. Look over the logging debug prompt .github/prompts/debug-with-logs.prompt.md

  5. Run the prompt "/debug-with-logs"

    1. Observe the output and how Copilot goes about fixing the bugs

    2. Pro Tip: Use a more advanced model to get better results

  6. Verify the bug is fixed

    1. Manually run the TaskFlow app and try to toggle a task.

    2. Run the tests npm run test:e2e:debug or npm run test:docker

Next Steps

You now know how to orchestrate multiple environments through a unified log stream and use Copilot to debug full-stack issues.

Continue to: Debugging with MCP + PostgreSQL

In the next section, you’ll go deeper by using a PostgreSQL MCP server to debug data issues directly from the database layer — enabling Copilot to query live data while solving bugs.

Sources