Logic App Consumption and APIM

Prev Next

This sample demonstrates how to use Business Activity Monitoring (BAM) data queries to create a transaction view for an AI-powered document processing solution. The integration combines Azure AI Document Intelligence with Logic App Consumption workflows and Azure API Management (APIM) to process invoices. BAM surfaces the invoice data in a view that L2 support users and business users can use without direct access to Azure diagnostics.

Overview

Business value

This sample shows how BAM data queries can combine log data from Log Analytics and Application Insights into a single business-friendly view. Support users can see what invoices are being processed, their current status, and the outcome — reducing the need to raise developer tickets to check the logs.

How it works

The parent query joins workflow start, completion, and action events from Log Analytics to produce one row per invoice run with relevant business properties. Stage queries use the WorkFlowRunID to retrieve Logic App action events and APIM request events from separate log sources, with portal URLs constructed for click-through access to Azure.

KQL queries


Parent query

This query links the workflow start event and workflow completion event to determine when the workflow ran and what the outcome was. It also joins to a specific action that logs tracked properties, so those properties — such as invoice ID, vendor, and amount — appear in the tracking grid.

let resourceGroup = "RND_T360_AI_DOCUMENTINTELLIGENCE";
let subscriptionId = "TBC";
let workflowName = "t360-poc-ai-invoice-process-one-invoice";
let actionWithPropertiesName = "PARSE_JSON_-_LOG_FINISH";
let runStartedEvent = AzureDiagnostics
    | where SubscriptionId == subscriptionId
    | where ResourceGroup == resourceGroup
    | where resource_workflowName_s == workflowName
    | where OperationName == "Microsoft.Logic/workflows/workflowRunStarted"
    | extend WorkFlowName = resource_workflowName_s
    | extend WorkFlowRunID = resource_runId_s
    | extend Start = startTime_t
    | order by TimeGenerated desc
    | project TimeGenerated,  WorkFlowName, WorkFlowRunID, Start;  
let actionWithPropertiesEvent = AzureDiagnostics
    | where SubscriptionId == subscriptionId
    | where ResourceGroup == resourceGroup
    | where  resource_workflowName_s == workflowName
    | where  OperationName == "Microsoft.Logic/workflows/workflowActionCompleted"
    | where  Resource == actionWithPropertiesName
    | extend WorkFlowName = resource_workflowName_s
    | extend WorkFlowRunID = resource_runId_s
    | extend InvoiceId = trackedProperties_LogProperties_InvoiceId_s
    | extend Vendor = trackedProperties_LogProperties_VendorName_s
    | extend InvoiceDate = trackedProperties_LogProperties_InvoiceDate_s
    | extend InvoiceTotal = trackedProperties_LogProperties_InvoiceTotal_s    
    | order by TimeGenerated desc
    | project TimeGenerated,  WorkFlowName, WorkFlowRunID, InvoiceId, Vendor, InvoiceDate, InvoiceTotal;      
let workflowCompetedEvents = AzureDiagnostics
    | where SubscriptionId == subscriptionId
    | where ResourceGroup == resourceGroup
    | where resource_workflowName_s == workflowName
    | where OperationName == "Microsoft.Logic/workflows/workflowRunCompleted"
    | extend EndResult = coalesce(status_s, "In Progress")
    | extend End = endTime_t
    | extend WorkFlowName = resource_workflowName_s
    | extend WorkFlowRunID = resource_runId_s
    | order by TimeGenerated desc
    | project WorkFlowRunID, EndResult, End;
runStartedEvent 
    | join kind=leftouter workflowCompetedEvents on WorkFlowRunID
    | join kind=leftouter actionWithPropertiesEvent on WorkFlowRunID
| extend Duration = End - Start
| extend Result = coalesce(EndResult, "In Progress")
| project TimeGenerated, WorkFlowName, WorkFlowRunID,Result, Start, End, Duration, InvoiceId, Vendor, InvoiceDate, InvoiceTotal
| order by TimeGenerated desc

Logic App actions

This query runs against the Log Analytics workspace used by the Logic App Consumption workflows. You can reuse this query for each action stage in BAM by changing the action name. A portal URL is included so you can click through to the Azure portal from the stage view.

let input_RunId = {WorkFlowRunID};
let resourceGroup = "RND_T360_AI_DOCUMENTINTELLIGENCE";
let subscriptionId = "TBC";
let logicAppName = "t360-poc-ai-invoice-process-one-invoice";
let actionName = "WHEN_A_HTTP_REQUEST_IS_RECEIVED";
let azurePortalUrlTemplate = "https://portal.azure.com/#view/Microsoft_Azure_EMA/DesignerEditorConsumption.ReactView/id/%2Fsubscriptions%2F[subscriptionId]f%2FresourceGroups%2F[resourceGroup]%2Fproviders%2FMicrosoft.Logic%2Fworkflows%2F[logicAppName]/location/northeurope/showGoBackButton~/true/isReadOnly~/true/isMonitoringView~/true/runId/%2Fsubscriptions%2F[subscriptionId]f%2FresourceGroups%2F[resourceGroup]%2Fproviders%2FMicrosoft.Logic%2Fworkflows%2F[logicAppName]%2Fruns%2F[RunId]";
let lookups = dynamic([ '[subscriptionId]', '[resourceGroup]', '[logicAppName]', '[RunId]' ]);
AzureDiagnostics
| where ResourceProvider == "MICROSOFT.LOGIC"
| where OperationName == "Microsoft.Logic/workflows/workflowTriggerCompleted"
| where SubscriptionId == subscriptionId
| where ResourceGroup == resourceGroup
| where resource_workflowName_s == logicAppName
| where resource_runId_s == input_RunId
| where Resource == actionName
| extend PortalUrl = replace_strings(azurePortalUrlTemplate, lookups, pack_array(subscriptionId, resourceGroup, logicAppName, input_RunId))
| project TimeGenerated, PortalUrl, actionName, ActionStatus=status_s, RunID=input_RunId, LogicApp=logicAppName, correlation_clientTrackingId_s, _ResourceId

API Management step

This query uses an Application Insights workspace in a different Azure subscription. APIM logs HTTP headers to Application Insights, which are used to look up the matching request event for this workflow run. The query extends fields from the request and response bodies and constructs a portal URL for click-through access to Application Insights.

  • Logic App headers are extended so they appear in the query response.

  • Fields from the request body are extended to surface invoice data for the user.

  • A portal URL is constructed for direct navigation to the Application Insights record.

let logicAppRunId = {WorkFlowRunID};
let resourceGroup = "Platform";
let subscriptionId = "TBC";
let appInsightsName = "kv-eai-apim-appinsights";
let portalUrlTemplate = "https://portal.azure.com/#blade/AppInsightsExtension/DetailsV2Blade/DataModel/%7B%22eventId%22:%22[RequestID]%22,%22timestamp%22:%22[startTime]%22%7D/ComponentId/%7B%22Name%22:%22[appInsightsName]%22,%22ResourceGroup%22:%22[resourceGroup]%22,%22SubscriptionId%22:%22[subscription]%22%7D";
let lookups = dynamic([ '[subscription]', '[resourceGroup]', '[appInsightsName]' ]);
let portalUrl = replace_strings(portalUrlTemplate, lookups, pack_array(subscriptionId, resourceGroup, appInsightsName));
requests 
| where customDimensions.["API Name"] == "outbound-api-sap-invoices"
| where customDimensions.["Operation Name"] == "submit-invoice"
| where customDimensions.["Request-x-ms-workflow-run-id"] == logicAppRunId
| extend InvoiceTotal_ = tostring(parse_json(tostring(customDimensions.["Request-Body"])).InvoiceTotal)
| extend InvoiceId_ = tostring(parse_json(tostring(customDimensions.["Request-Body"])).InvoiceId)
| extend InvoiceDate_ = tostring(parse_json(tostring(customDimensions.["Request-Body"])).InvoiceDate)
| extend DueDate_ = tostring(parse_json(tostring(customDimensions.["Request-Body"])).DueDate)
| extend CustomerName_ = tostring(parse_json(tostring(customDimensions.["Request-Body"])).CustomerName)
| extend CustomerAddress_ = tostring(parse_json(tostring(customDimensions.["Request-Body"])).CustomerAddress)
| extend BillingAddress_ = tostring(parse_json(tostring(customDimensions.["Request-Body"])).BillingAddress)
| extend VendorName_ = tostring(parse_json(tostring(customDimensions.["Request-Body"])).VendorName)
| extend Request_x_ms_client_tracking_id_ = tostring(customDimensions.["Request-x-ms-client-tracking-id"])
| extend Request_x_ms_correlation_id_ = tostring(customDimensions.["Request-x-ms-correlation-id"])
| extend Request_x_ms_workflow_name_ = tostring(customDimensions.["Request-x-ms-workflow-name"])
| extend Request_x_ms_workflow_resourcegroup_name_ = tostring(customDimensions.["Request-x-ms-workflow-resourcegroup-name"])
| extend Request_x_ms_workflow_run_id_ = tostring(customDimensions.["Request-x-ms-workflow-run-id"])
| extend invoice_id_ = tostring(parse_json(tostring(customDimensions.["Response-Body"])).invoice_id)
| extend success_ = tostring(parse_json(tostring(parse_json(tostring(customDimensions.["Response-Body"])).success)))
| extend azure_portal_url = replace_string(replace_string(portalUrl, "[RequestID]", itemId), "[startTime]", tostring(datetime_add('hour', -1, timestamp)))