Setting up a Debugging Environment for Azure Functions 2.x using VS Code
I build security programs and defend networks. Sometimes with Python or Azure Functions.
Debugging Azure Functions can be extremely easy if you add the appropriate logging and error handling to your code. However, there are going to be times where debugging with these techniques is simply not enough. As a result, we need a robust debugging environment to trace a transaction end to end. Before I get to the environment setup, I want to first outline the high-level transaction flow (as I understand it) for Azure Functions. Please refer to the diagram below, which was posted in March 2018 in the Azure Function Python Worker wiki here
Overall, the Azure Functions Host is the host/runtime that powers Azure Functions apps. Starting at the top of the diagram, incoming HTTP transactions are first routed to the WebHost, which is a sub-component of Azure Functions Host. The WebHost processes the HTTP request and sends the transactions to the Azure Functions Python Worker aka the Python Worker. The Python Worker then routes the transaction to the appropriate function app.
It is apparent from this diagram to appropriately debug an Azure Function; you need to insert yourself into the Azure Functions Host, which is a dotnet core app written in C#. Please note that for the purposes of this tutorial, I am focused on debugging HTTP Trigger function apps. This tutorial assumes that you have a working understanding of Azure Functions and VS Code.
There are two pre-requisites necessary to build and debug Azure Functions Host: dotnet core 2.x and Visual Studio (VS) Code.
dotnet core 2.2.x:
- Download VS Code from here
- Install the C# and python extensions
The following steps help create a stand-alone virtual environment where you can independently debug function apps separate from your other function app development environments. To begin, create a virtual environment and supporting folder structure:
python3 -m venv .afhvenv
As you will see later in the article, following the above folder structure will allow you to debug multiple versions of the Azure Functions Host at the same time.
Azure Functions Host Source Code
Download source code of Azure Functions Host’s latest production release. Please note: you can, of course, download any branch you want from GitHub; however, I want what’s running in production since non-production branches may not build successfully. From the root of the afdebugenv run the following commands:
When finished, you will build the debug version of the Azure
Function Host from source using the dotnet executable from the command line:
dotnet build -c Debug WebJobs.Script.sln
This build will take a few minutes to complete and should build with no errors (even on my MacBook Pro).
Azure Functions Host Symbol files
hold a variety of data that are not actually needed when running the binaries, but which could be very useful in the debugging process. Symbol files are specific for each version of the software, so we are going to create a symbol folder in our Azure Functions Host folder. From the root of the version of Azure Functions Host that you are debugging run the following commands:
Azure Functions Python Worker
The Azure Functions Host ships with a python worker which we will use for debugging purposes. Please note
: the below path is specific to my setup (OS X), the path to your worker.py
will be some variation after “
”. From the worker directory, run the following commands:
After you download
to the worker directory, you have to configure the python worker to run in debug mode when it is called by VS Code. For some background on the proper format of the
file, refer to this document
. To enable debugging on the worker.py
process, add the following directive to
"Arguments": ["-m ptvsd --host 127.0.0.1 --port 9091"]
VS Code Setup
Launch.json and tasks.json need to be customized to properly build and debug the Azure Functions Host. I am providing example files that will allow you to get up and running much quicker, which is why I was so specific as to the naming of directories above. Once you are comfortable, feel free to customize the
file to meet your needs. At the root of the afdebugenv folder, run the following commands:
When finished, open VS Code from the afdebugenv directory. You
may get a notice that says, “Required assets to build and debug are missing
from ‘afdebugenv’. Add them?”. Say yes.
Install Additional Python Packages
We are effectively running the entire Azure Function stack locally, so we need to install ptvsd and Azure functions. Run the following command:
pip install ptvsd azure-functions
Validating Your Environment
If you made it this far, kudos to you. I thought about automating this entire process, but I figured that given the rapid pace of change in this space, it would be obsolete within a few months. Assuming you have a plain vanilla HTTP Trigger function app in your functions directory, we are going to run a short test below to ensure your environment is ready to start debugging. From the root of your afdebugenv directory, open up VS Code and perform the following steps:
- In the explorer screen, navigate to the following path: “
- In the first third of the code, you will find the following function definition: “
”. Set a breakpoint in the left-hand gutter, which will be marked by a red dot
public async Task Invoke(HttpContext context)
- To invoke the debugger for Azure Functions Host, in the debug screen, under the “debug and run” heading, select “.NET Core Launch” from the drop-down and press F5
- You will notice that the integrated terminal opened with similar startup messages as when you execute "func host start". The only main difference is that the Azure Function Host is listening on port TCP 5000. Please refer to the screenshot below:
- To invoke the debugger for the python worker, in the debug screen, under the “debug and run” heading, select “Attach to Python Functions” from the drop-down and press F5
- Run a test transaction against your HTTPTrigger
- The debugger should hit the breakpoint that you set in step 2, and you can now inspect the data that was passed to the function. Please refer to the screenshot below:
- To continue processing the transaction, hit F5. On your terminal where you executed the command, you should see your output. Additionally, the integrated terminal should reflect that you processed the transaction successfully
- To exit the debugging process, press the red square in the debugging control panel
Please note: Stopping the VS Code debugger will NOT kill the worker.py process spawned by Azure Functions Host. As a result, you have to manually kill the process to free ports TCP 5000 back up. Please note x2: you have to stop the VS Code debugger FIRST, otherwise, the Azure Functions Host will continually spawn up worker.py processes every time you kill it.
In future articles, I will be covering advanced debugging topics that rely on this article as a foundation. If you have any feedback, please send me a note at gattjoseph at <hotmail>.
Subscribe to get your daily round-up of top tech stories!