In an upcoming talk at Integrate 2021 in June (check out the sessions here) I will be talking about Log Analytics/Azure Monitor and App Insights when used with Logic Apps. This post is not exactly the same as the talk ill be doing but it touches on a similar area and I thought people will find this quite interesting and maybe wet the appetite a little to know more about what ive been up to recently.
In this post however I will be looking at the scenario where I am using Azure API Management as a proxy to some applications in the cloud and on-premise. I am routing my custom API calls through APIM for a number of reasons but one of the benefits is that my APIM is also connected to App Insights and as an effect of that I will have the ability to do some cool analysis of a number of things related to my Logic Apps consuming services from APIM.
One of the good things is that out of the box with the HTTP and APIM connectors logic apps will be injecting some headers listed below:
- Request-x-ms-workflow-resourcegroup-name
- Request-x-ms-workflow-run-id
- Request-x-ms-workflow-name
This tells me the logic app, its run id and the resource group of the logic app which makes each call automatically. I can then see these headers in the app insights logs.
While there are loads of good features in App Insights which give me useful out of the box functionality, in this post I wanted to talk about what I can do by inspecting the app insights logs with kusto queries to analyst the goldmine of useful telemetry data. Below are a few of the useful queries I have used.
Errors by Logic App
If I want to get a list of the logic apps which got errors when calling APIM I can use the below query
requests
| where resultCode != 200
| extend logicAppName_ = tostring(customDimensions.["Request-x-ms-workflow-name"])
| extend resourceGroup_ = tostring(customDimensions.["Request-x-ms-workflow-resourcegroup-name"])
| extend logicAppId_ = tostring(customDimensions.["Request-x-ms-workflow-run-id"])
| project logicAppName_, resourceGroup_, logicAppId_, name, timestamp, resultCode
I can also summarize the data to findout which logic apps are having the most errors
requests
| where resultCode != 200
| extend logicAppName_ = tostring(customDimensions.["Request-x-ms-workflow-name"])
| summarize count() by logicAppName_
View the above query as a chart you can add the | render column chart to the end of the query
View Errors over time as a graph
If I want to see a profile of the errors by logic app over a period of time I can use the below query and render it as a chart to see which logic apps have errors when.
let min_t = toscalar(requests | summarize min(timestamp));
let max_t = toscalar(requests | summarize max(timestamp));
requests
| where resultCode != 200
| extend logicAppName_ = tostring(customDimensions.["Request-x-ms-workflow-name"])
| make-series num=count() default=0 on timestamp in range(min_t, max_t, 1h) by logicAppName_
| render timechart
View Performance of API’s used by Logic Apps
Next I wanted to look at the requests in relation to the logic apps consuming them and see what the profile of average response time is from a Logic App perspective. This will help me see which logic apps might have performance bottlenecks in them from the API’s they consume.
let min_t = toscalar(requests | summarize min(timestamp));
let max_t = toscalar(requests | summarize max(timestamp));
requests
| extend logicAppName_ = tostring(customDimensions.["Request-x-ms-workflow-name"])
| where isnotnull(logicAppName_) and isnotempty(logicAppName_)
| make-series num=avg(duration) default=0 on timestamp in range(min_t, max_t, 1h) by logicAppName_
| render timechart
This looks like the below
View usage of an API operation by Logic App over a period of time
In this case I want to look at an individual APIM operation and have a look at the profile of usage but break it down by logic app so I can see by hour how many times each logic app is using it. The below query will help me do this and show it as a chart like below.
let min_t = toscalar(requests | summarize min(timestamp));
let max_t = toscalar(requests | summarize max(timestamp));
requests
| extend logicAppName_ = tostring(customDimensions.["Request-x-ms-workflow-name"])
| extend logicAppName_ = tostring(customDimensions.["Request-x-ms-workflow-name"])
| extend resourceGroup_ = tostring(customDimensions.["Request-x-ms-workflow-resourcegroup-name"])
| extend API_Name_ = tostring(customDimensions.["API Name"])
| extend Operation_Name_ = tostring(customDimensions.["Operation Name"])
| where isnotnull(logicAppName_) and isnotempty(logicAppName_)
and operation_Name endswith "[Your operation name]"
| make-series num=count() default=0 on timestamp in range(min_t, max_t, 1h) by logicAppName_
| render timechart
Which Logic app uses which API
This will give you a list of the API’s and which logic app names have used them over the period of data you look at.
requests
| extend logicAppName_ = tostring(customDimensions.["Request-x-ms-workflow-name"])
| extend resourceGroup_ = tostring(customDimensions.["Request-x-ms-workflow-resourcegroup-name"])
| extend API_Name_ = tostring(customDimensions.["API Name"])
| where isnotnull(logicAppName_) and isnotempty(logicAppName_)
| summarize by API_Name_, logicAppName_, resourceGroup_
How many times is each API used by each Operation
This will extend the above query to show you how many times each API has been used by each logic app.
requests
| extend logicAppName_ = tostring(customDimensions.["Request-x-ms-workflow-name"])
| extend resourceGroup_ = tostring(customDimensions.["Request-x-ms-workflow-resourcegroup-name"])
| extend API_Name_ = tostring(customDimensions.["API Name"])
| where isnotnull(logicAppName_) and isnotempty(logicAppName_)
| summarize count() by API_Name_, logicAppName_, resourceGroup_
Which Logic App uses which API operation
If we want to break down the data further we can use the below query to see which logic apps use which API operation
requests
| extend logicAppName_ = tostring(customDimensions.["Request-x-ms-workflow-name"])
| extend resourceGroup_ = tostring(customDimensions.["Request-x-ms-workflow-resourcegroup-name"])
| extend API_Name_ = tostring(customDimensions.["API Name"])
| extend Operation_Name_ = tostring(customDimensions.["Operation Name"])
| where isnotnull(logicAppName_) and isnotempty(logicAppName_)
| summarize by API_Name_, Operation_Name_, logicAppName_, resourceGroup_
How many times is each API operation used by each logic app
As we did earlier we can also break down that query to also show how many times each logic app has used each API operation
requests
| extend logicAppName_ = tostring(customDimensions.["Request-x-ms-workflow-name"])
| extend resourceGroup_ = tostring(customDimensions.["Request-x-ms-workflow-resourcegroup-name"])
| extend API_Name_ = tostring(customDimensions.["API Name"])
| extend Operation_Name_ = tostring(customDimensions.["Operation Name"])
| where isnotnull(logicAppName_) and isnotempty(logicAppName_)
| summarize count() by API_Name_, Operation_Name_, logicAppName_, resourceGroup_