Azure Functions is a great option for accelerating your development efforts with a serverless compute experience when you don’t want to worry about maintaining servers but rather focus on building your applications. Still, your servers, databases, services, and other infrastructure components may experience errors or performance problems that you need to be informed of so that you can optimize your applications for peak performance.

In this blog post, I’ll explain the benefits of using Dynatrace to gain insights into Azure Functions that are written in C# so you can better understand and tweak your application performance and reduce the duration of outages, if they occur.

But, first things first…

What is Azure Functions?

Ever wanted to run a small piece of code in the cloud without worrying about an entire application or infrastructure to run it? Then Azure Functions is the way to go. Simply write the code you need and then run it in the cloud without dealing with the underlying infrastructure. Even more convenient, you can directly deploy functions from Visual Studio into your Azure cloud environment. No need to set up a server or other infrastructure. With Azure Functions, you don’t need to worry about wasting resources when your application isn’t under heavy load, or scaling up your server infrastructure manually to accommodate high traffic levels during peak hours. Simply deploy your function—everything else is taken care of for you. It’s that simple.

What’s going on with my functions?

Once your functions are built and deployed, you’ll definitely want to know how they’re performing, right? The good news is that with our new tech preview you can now get detailed insights into your Dynatrace-monitored functions. This means that—in addition to the great monitoring capabilities we already provide for Azure (for example, VMs, Container Services, and App Services)—soon you’ll be able to take advantage of Dynatrace performance monitoring capabilities when using Azure functions with C#.

Since Azure Functions provides multiple means of triggering functions, let’s take a look at some examples.

The example service below consists of two functions. One function is triggered by an HTTP request (HttpTrigger). This function outputs the GET parameters that are sent. The other function periodically fetches all the catchy headlines from the Dynatrace blog and prints the titles to the Azure TimerTrigger console. Of course, you’ll want to have more magic in your own app code, but for this demo scenario, these simple functions work fine.

For the first Azure function, let’s investigate why a recent response-time increase occurred (see image below).

Azure Functions

We can leverage the capabilities of Dynatrace to not only see how many requests were made but also to deep dive into the actual code that was executed so we understand exactly what went wrong. Even more, we can see the actual CPU consumption on the method-level of the C# Azure Functions. This helps to drastically reduce the mean time to repair (MTTR) as we’ve already pinpointed the root cause of the problem.

The image below shows the distribution of execution time of the Azure function. This stacktrace-like overview provides details about the code that’s been executed and the distribution of CPU consumption. As you can see at the bottom of the page, 27% of the CPU consumption is consumed by an internal sleep command inside the Run() method, while another 73% of CPU is consumed by the HttpTrigger.SleepMethod(), which again calls a sleep method. These two measurements add up to 100%, so there’s no need to investigate any other method calls—the CPU consumption is clearly occurring due to the main Run() method.

Azure Functions

You can easily see the problem once you dive into the corresponding code with Visual Studio. For example, here’s the code from the SleepMethod():

private static void SleepMethod(TraceWriter log)
{
  log.Info("sleeping method called");
  System.Threading.Thread.Sleep(5000);
}

This method was likely called by the main Run() method:

Random rnd = new Random();
if (rnd.Next(10) > 8)
{
  System.Threading.Thread.Sleep(1000);
  SleepMethod(log);
}

We can fix this issue by removing the code that slowed down the application. How easy!

For the second Azure function, let’s leverage the monitoring capabilities of Dynatrace to gain insights into the service flow, to see which services or external resources were called when this Azure function was triggered.

Azure Functions

As you can see, the function not only calls the internal Azure functions, it also sends requests to a public network (i.e., the Dynatrace blog in this example). We can see that 24 requests were made during the analysis time frame, and all the requests were successful (thumbs up for the Dynatrace blog)!

Also, we can see that the function was called periodically with no interruptions and relatively stable response time (see below).

Azure Functions

Conclusion

Now you’ve seen how the upcoming Dynatrace support for C# in Azure Functions helps you gain method-level insights into your functions, painlessly identify slowdowns and outages, quickly fix detected problems, and analyze the service flow of your functions. Similar to our existing support for monitoring Web Apps in Azure, our Site Extension will soon include support for Azure Functions.

Disclaimer / Outlook

Support for Azure Functions in C# is currently in a technical preview period. If you’re interested in learning more about our plans for support of Azure Functions in C#, drop us an email.