Learn about the queries that you can use to retrieve the diagnostics data for unified routing from Application Insights.
Fallback queues
Purpose: Diagnose number of work items routed to fallback queues.
Query
let _endTime = datetime(2024-11-21T22:29:53Z);
let _startTime = datetime(2024-09-22T21:29:53Z);
Traces
| where timestamp >= _startTime and timestamp <= _endTime
| extend customDim = parse_json(customDimensions)
| extend conversationId = tostring(customDim["powerplatform.analytics.resource.id"]),
subscenario = tostring(customDim["powerplatform.analytics.subscenario"]),
queueResult = parse_json(tostring(customDim["omnichannel.result"])).DisplayName
| extend scenario = tostring(customDim["powerplatform.analytics.scenario"])
| where scenario == "ConversationDiagnosticsScenario"
| where subscenario == "RouteToQueue" and queueResult == "[Insert Your Fallback queue name]"
| project timestamp, conversationId, queueResult
Overflow handling
Purpose: Diagnose number of work items where overflow is trigger.
Query
Traces
| extend customDim = parse_json(customDimensions)
| extend conversationId = tostring(customDim["powerplatform.analytics.resource.id"]),
subscenario = tostring(customDim["powerplatform.analytics.subscenario"])
| extend omnichannelAdditionalInfo = tostring((customDim["omnichannel.additional_info"]))
| extend scenario = tostring(customDim["powerplatform.analytics.scenario"])
| where scenario == "ConversationDiagnosticsScenario"
| where omnichannelAdditionalInfo contains "OverflowTrigger"
| project timestamp, conversationId, subscenario, omnichannelAdditionalInfo
Representatives who reject new assignments
Purpose: Diagnose customer service representatives (service representatives or representatives) who reject new assignments (by conversationId).
Query
let _endTime = datetime(2024-11-21T22:32:51Z);
let _startTime = datetime(2024-09-22T21:32:51Z);
Traces
| where timestamp >= _startTime and timestamp <= _endTime
| extend customDim = parse_json(customDimensions)
| extend conversationId = tostring(customDim["powerplatform.analytics.resource.id"]),
subscenario = tostring(customDim["powerplatform.analytics.subscenario"]),
agentId = tostring(customDim["omnichannel.target_agent.id"]) // Extract representative ID from custom dimensions
| extend scenario = tostring(customDim["powerplatform.analytics.scenario"])
| where scenario == "ConversationDiagnosticsScenario"
| where subscenario == "CSRRejected"
| summarize agentRejectionCount = count() by conversationId, agentId // Count rejections per representative per conversation
| summarize rejectionCount = sum(agentRejectionCount),
agentRejectionDetails = make_list(pack('agentId', agentId, 'rejectionCount', agentRejectionCount))
by conversationId // Aggregate results by conversation
| where rejectionCount > 1 // Filter conversations with more than one rejection
| project conversationId, rejectionCount, agentRejectionDetails
Purpose: Diagnose representatives who reject new assignments (by representatives).
Query
let _endTime = datetime(2024-11-21T22:33:55Z);
let _startTime = datetime(2024-09-22T21:33:55Z);
traces
| where timestamp >= _startTime and timestamp <= _endTime
| extend customDim = parse_json(customDimensions)
| extend agentId = tostring(customDim["omnichannel.target_agent.id"]), // Extract agent ID from custom dimensions
subscenario = tostring(customDim["powerplatform.analytics.subscenario"])
| extend scenario = tostring(customDim["powerplatform.analytics.scenario"])
| where scenario == "ConversationDiagnosticsScenario"
| where subscenario == "CSRRejected"
| summarize totalRejections = count() by agentId // Count total rejections for each agent
| sort by totalRejections desc // Sort by rejection count in descending order
| top 20 by totalRejections // Select top 20 agents
| project agentId, totalRejections // Project relevant columns
Representative assignment took longer than two minutes
Purpose: Diagnose conversations where representative assignment took longer than two minutes.
Query
let _endTime = datetime(2024-11-21T22:35:56Z);
let _startTime = datetime(2024-09-22T21:35:56Z);
// Extract relevant subscenarios
let subscenarios = traces
| where timestamp >= _startTime and timestamp <= _endTime
| extend customDim = parse_json(customDimensions)
| extend conversationId = tostring(customDim["powerplatform.analytics.resource.id"]),
subscenario = tostring(customDim["powerplatform.analytics.subscenario"])
| where subscenario in ("RouteToQueue", "CSRAccepted")
| project timestamp, conversationId, subscenario;
// Find the latest RTQ before each AgentAccept
let latestRTQsBeforeAgentAccept = subscenarios
| where subscenario == "RouteToQueue"
| join kind=inner (
subscenarios
| where subscenario == "CSRAccepted"
| project agentAcceptTime = timestamp, conversationId
) on conversationId
| where timestamp < agentAcceptTime // Ensure RTQ is before AgentAccept
| summarize latestRTQTime = max(timestamp) by conversationId, agentAcceptTime;
// Calculate assignment time
latestRTQsBeforeAgentAccept
| extend assignmentTime = agentAcceptTime - latestRTQTime
| where assignmentTime > 2min
| project conversationId, assignmentTime
Why a conversation wasn’t assigned to any representative until now
Purpose: Determine why the conversation isn't assigned.
Get the conversation lifecycle using the following query.
traces | extend customDim = parse_json(customDimensions) | extend lwiid = tostring(customDim["powerplatform.analytics.resource.id"]) | extend subscenario = tostring(customDim["powerplatform.analytics.subscenario"]) | where lwiid == "a4921f6b-f6a7-4a67-b851-cfee318c2403" // Fill in the conversation id | project timestamp, lwiid, subscenario, customDim | order by timestamp ascUse the results to identify the last assignment attempt event and make a note of the timestamp (UTC) within the CSRAssignment subscenario.
Identify the assignment rules used to assign an agent, using the ruleset details inside the CustomDim section.
Identify the work item details, like queue ID, Allowed presences and required capacity, from the omnichannel.work_item.details field inside the CustomDim section column.
Identify representatives present in the queue and their corresponding presence, unit capacity, capacity profiles, and skills at the time of assignment.
Important
This is a resource-intensive query. We recommend that you use it based on concrete needs. If you need specific details about a service representative, such as their presence, capacity, or skill, you can use the individual component queries.
let assignmentAttemptTime = now(); // Fill in timestamp of assignment attempt let lwiQueueId = "05a59008-f63a-f011-b4cb-6045bd070c8e"; // Fill in queue id of the work item let agentConfigsTemp = traces | extend customDim = parse_json(customDimensions) | extend agentid = tostring(customDim["powerplatform.analytics.resource.id"]) | extend subscenario = tostring(customDim["powerplatform.analytics.subscenario"]) | extend agentQueues = tostring(customDim["omnichannel.queue.ids"]) | where subscenario == "AgentConfiguration" or subscenario == 'CSRConfigurationDetails' | where agentQueues contains lwiQueueId | where timestamp < assignmentAttemptTime | project agentConfigRecordedTime = timestamp, agentid, subscenario, agentConfig = customDim | order by agentConfigRecordedTime desc | summarize arg_max(agentConfigRecordedTime, *) by agentid; let agentids = agentConfigsTemp | project agentid; let latestagentConfig=traces | extend customDim = parse_json(customDimensions) | extend agentid = tostring(customDim["powerplatform.analytics.resource.id"]) | extend subscenario = tostring(customDim["powerplatform.analytics.subscenario"]) | extend agentQueues = tostring(customDim["omnichannel.queue.ids"]) | extend agentProfiles = tostring(customDim["omnichannel.capacity_profile.ids"]) | where subscenario == "AgentConfiguration" or subscenario == 'CSRConfigurationDetails' | where timestamp < assignmentAttemptTime | where agentid in (agentids) | project agentConfigRecordedTime = timestamp, agentid, subscenario, agentConfig = customDim,agentQueues,agentProfiles | order by agentConfigRecordedTime desc | summarize arg_max(agentConfigRecordedTime, *) by agentid; let agentConfigs = traces | extend customDim = parse_json(customDimensions) | extend agentid = tostring(customDim["powerplatform.analytics.resource.id"]) | extend subscenario = tostring(customDim["powerplatform.analytics.subscenario"]) | where subscenario == "AgentConfiguration" or subscenario == 'CSRConfigurationDetails' | join kind=inner latestagentConfig on agentid | extend agentProfiles = tostring(customDim["omnichannel.capacity_profile.ids"]) | mv-expand profileIds = parse_json(agentProfiles) | where timestamp < assignmentAttemptTime | project agentConfigRecordedTime = timestamp, profileIds, agentProfiles, agentid, subscenario, agentConfig = customDim | order by agentConfigRecordedTime desc | summarize arg_max(agentConfigRecordedTime, *) by agentid; let capacityprofiles1 = agentConfigs | mv-expand profileIds = parse_json(agentProfiles) | project agentid, capacityProfileId = tostring(profileIds); let statusCapacityHistoryRecords = traces | extend customDim = parse_json(customDimensions) | where timestamp < assignmentAttemptTime | extend agentid = tostring(customDim["powerplatform.analytics.resource.id"]) | extend subscenario = tostring(customDim["powerplatform.analytics.subscenario"]) | extend cpparsed = parse_json(tostring(customDim["omnichannel.capacity_profile"])) | extend capacityProfileId = tostring(cpparsed["CapacityProfileId"]) | where subscenario in ("AgentStatusAndCapacity", "CSRStatusandCapacityDetails") | project timestamp, agentid, capacityProfileId, subscenario, customDim, cpparsed | join kind=inner ( capacityprofiles1 ) on agentid, capacityProfileId | project statusCapacityHistoryRecordedTime = timestamp, agentid, subscenario, agentStatusAndCapacity = customDim, capacityProfileId, cpparsed | order by statusCapacityHistoryRecordedTime desc | summarize arg_max(statusCapacityHistoryRecordedTime, *) by agentid, capacityProfileId; let unitbasedTable = traces | where timestamp < assignmentAttemptTime | extend customDim = parse_json(customDimensions) | extend agentid = tostring(customDim["powerplatform.analytics.resource.id"]) | extend subscenario = tostring(customDim["powerplatform.analytics.subscenario"]) | where subscenario == "AgentStatusAndCapacity" or subscenario == 'CSRStatusandCapacityDetails' | extend cpparsed = parse_json( tostring(customDim["omnichannel.capacity_profile"])) | where cpparsed == "" | extend UnitAvailableCapacity = tostring(customDim["omnichannel.available_capacity.units"]) | join kind=inner latestagentConfig on agentid | project statusCapacityHistoryRecordedTime = timestamp, agentid, subscenario, agentConfig = customDim, UnitAvailableCapacity | summarize arg_max(statusCapacityHistoryRecordedTime, *) by agentid | order by statusCapacityHistoryRecordedTime desc ; let presenceTable = traces | where timestamp < assignmentAttemptTime | extend customDim = parse_json(customDimensions) | extend agentid = tostring(customDim["powerplatform.analytics.resource.id"]) | extend subscenario = tostring(customDim["powerplatform.analytics.subscenario"]) | where subscenario == "AgentStatusAndCapacity" or subscenario == 'CSRStatusandCapacityDetails' | extend cpparsed = parse_json( tostring(customDim["omnichannel.capacity_profile"])) | where cpparsed == "" | extend BasePresenceStatus = tostring(customDim["omnichannel.current_base_presence"]) | extend PresenceId = tostring(customDim["omnichannel.current_presence_id"]) | join kind=inner latestagentConfig on agentid | project statusCapacityHistoryRecordedTime = timestamp, agentid, subscenario, agentConfig = customDim, BasePresenceStatus, PresenceId | summarize arg_max(statusCapacityHistoryRecordedTime, *) by agentid | order by statusCapacityHistoryRecordedTime desc ; let agentQueuesAndSkills = traces | extend customDim = parse_json(customDimensions) | extend agentid = tostring(customDim["powerplatform.analytics.resource.id"]) | extend subscenario = tostring(customDim["powerplatform.analytics.subscenario"]) | extend skillData = parse_json(tostring(customDim["omnichannel.associated_skills"]) ) | extend agentQueues = tostring(customDim["omnichannel.queue.ids"]) | where subscenario == "AgentConfiguration" or subscenario == 'CSRConfigurationDetails' | join kind=inner latestagentConfig on agentid | where timestamp < assignmentAttemptTime | project agentConfigRecordedTime = timestamp, agentid, subscenario, agentConfig = customDim, skillData, agentQueues | order by agentConfigRecordedTime desc | summarize arg_max(agentConfigRecordedTime, *) by agentid; let agentNames = traces | where timestamp > ago(2d) | extend customDim = parse_json(customDimensions) | extend subscenario = tostring(customDim["powerplatform.analytics.subscenario"]) | where subscenario == "AgentNameConfig" or subscenario == 'CSRConfigurationDetails' | extend agentInfo = tostring(customDim["omnichannel.data"]) | extend agentInfoParsed = parse_json(agentInfo) | mv-expand keyValue = bag_keys(agentInfoParsed) | project agentid = tostring(keyValue), agentName = tostring(agentInfoParsed[tostring(keyValue)]), timestamp | summarize arg_max(timestamp, *) by agentid; let cpListTable = statusCapacityHistoryRecords | summarize capacitprofiles = make_list(cpparsed) by agentid; cpListTable | join kind=leftouter agentNames on agentid | join kind=inner unitbasedTable on agentid | join kind=inner presenceTable on agentid | join kind=inner agentQueuesAndSkills on agentid | project agentid, agentName, UnitAvailableCapacity, BasePresenceStatus, PresenceId, capacitprofiles, skillData, agentQueues;
Why is the work item assigned to service representative X instead of service representative Y
Get the conversation’s lifecycle using the following query.
Query:
traces | extend customDim = parse_json(customDimensions) | extend lwiid = tostring(customDim["powerplatform.analytics.resource.id"]) // Fill in the conversation id | extend subscenario = tostring(customDim["powerplatform.analytics.subscenario"]) | where lwiid == "ac467bad-5d3f-4288-94f9-dc51d17c862f" | project timestamp, lwiid, subscenario, customDim | order by timestamp ascIdentify the last assignment attempt that is denoted by "CSRAssignment" sub-scenario.
Get the IDs of the representative whom we want to check. Let’s say we want to check why this conversation was assigned to Service representative with id 8874e390-9ecc-ef11-a72f-000d3a3652d6 instead of Service representative with id 92a1375c-e9dc-ef11-a72f-000d3a3ad269 or Service representative with id 7ac24088-a804-f011-bae2-000d3a3172e5.
Identify the assignment rules used to assign the conversation, the conversation queue and the conversation requirements.
Identify the presence, unit capacity, capacity profiles, and skills of the representatives shortlisted from Step 3 at the time of assignment.
Query:
let assignmentAttemptTime = now(); // Fill in timestamp of assignment attempt let agentids = dynamic(["92a1375c-e9dc-ef11-a72f-000d3a3ad269", "8874e390-9ecc-ef11-a72f-000d3a3652d6", "fc19139b-facd-ef11-a72e-0022480aa3fe"]); //Fill in system user ids of Customer Service Representatives let latestagentConfig=traces | extend customDim = parse_json(customDimensions) | extend agentid = tostring(customDim["powerplatform.analytics.resource.id"]) | extend subscenario = tostring(customDim["powerplatform.analytics.subscenario"]) | extend agentQueues = tostring(customDim["omnichannel.queue.ids"]) | extend agentProfiles = tostring(customDim["omnichannel.capacity_profile.ids"]) | where subscenario == "AgentConfiguration" or subscenario == 'CSRConfigurationDetails' | where timestamp < assignmentAttemptTime | where agentid in (agentids) | project agentConfigRecordedTime = timestamp, agentid, subscenario, agentConfig = customDim,agentQueues,agentProfiles | order by agentConfigRecordedTime desc | summarize arg_max(agentConfigRecordedTime, *) by agentid; let agentConfigs = traces | extend customDim = parse_json(customDimensions) | extend agentid = tostring(customDim["powerplatform.analytics.resource.id"]) | extend subscenario = tostring(customDim["powerplatform.analytics.subscenario"]) | where subscenario == "AgentConfiguration" or subscenario == 'CSRConfigurationDetails' | join kind=inner latestagentConfig on agentid | extend agentProfiles = tostring(customDim["omnichannel.capacity_profile.ids"]) | mv-expand profileIds = parse_json(agentProfiles) | where timestamp < assignmentAttemptTime | project agentConfigRecordedTime = timestamp, profileIds, agentProfiles, agentid, subscenario, agentConfig = customDim | order by agentConfigRecordedTime desc | summarize arg_max(agentConfigRecordedTime, *) by agentid; let capacityprofiles1 = agentConfigs | mv-expand profileIds = parse_json(agentProfiles) | project agentid, capacityProfileId = tostring(profileIds); let statusCapacityHistoryRecords = traces | extend customDim = parse_json(customDimensions) | where timestamp < assignmentAttemptTime | extend agentid = tostring(customDim["powerplatform.analytics.resource.id"]) | extend subscenario = tostring(customDim["powerplatform.analytics.subscenario"]) | extend cpparsed = parse_json(tostring(customDim["omnichannel.capacity_profile"])) | extend capacityProfileId = tostring(cpparsed["CapacityProfileId"]) | where subscenario in ("AgentStatusAndCapacity", "CSRStatusandCapacityDetails") | project timestamp, agentid, capacityProfileId, subscenario, customDim, cpparsed | join kind=inner ( capacityprofiles1 ) on agentid, capacityProfileId | project statusCapacityHistoryRecordedTime = timestamp, agentid, subscenario, agentStatusAndCapacity = customDim, capacityProfileId, cpparsed | order by statusCapacityHistoryRecordedTime desc | summarize arg_max(statusCapacityHistoryRecordedTime, *) by agentid, capacityProfileId; let unitbasedTable = traces | where timestamp < assignmentAttemptTime | extend customDim = parse_json(customDimensions) | extend agentid = tostring(customDim["powerplatform.analytics.resource.id"]) | extend subscenario = tostring(customDim["powerplatform.analytics.subscenario"]) | where subscenario == "AgentStatusAndCapacity" or subscenario == 'CSRStatusandCapacityDetails' | extend cpparsed = parse_json( tostring(customDim["omnichannel.capacity_profile"])) | where cpparsed == "" | extend UnitAvailableCapacity = tostring(customDim["omnichannel.available_capacity.units"]) | join kind=inner latestagentConfig on agentid | project statusCapacityHistoryRecordedTime = timestamp, agentid, subscenario, agentConfig = customDim, UnitAvailableCapacity | summarize arg_max(statusCapacityHistoryRecordedTime, *) by agentid | order by statusCapacityHistoryRecordedTime desc ; let presenceTable = traces | where timestamp < assignmentAttemptTime | extend customDim = parse_json(customDimensions) | extend agentid = tostring(customDim["powerplatform.analytics.resource.id"]) | extend subscenario = tostring(customDim["powerplatform.analytics.subscenario"]) | where subscenario == "AgentStatusAndCapacity" or subscenario == 'CSRStatusandCapacityDetails' | extend cpparsed = parse_json( tostring(customDim["omnichannel.capacity_profile"])) | where cpparsed == "" | extend BasePresenceStatus = tostring(customDim["omnichannel.current_base_presence"]) | extend PresenceId = tostring(customDim["omnichannel.current_presence_id"]) | join kind=inner latestagentConfig on agentid | project statusCapacityHistoryRecordedTime = timestamp, agentid, subscenario, agentConfig = customDim, BasePresenceStatus, PresenceId | summarize arg_max(statusCapacityHistoryRecordedTime, *) by agentid | order by statusCapacityHistoryRecordedTime desc ; let agentQueuesAndSkills = traces | extend customDim = parse_json(customDimensions) | extend agentid = tostring(customDim["powerplatform.analytics.resource.id"]) | extend subscenario = tostring(customDim["powerplatform.analytics.subscenario"]) | extend skillData = parse_json(tostring(customDim["omnichannel.associated_skills"]) ) | extend agentQueues = tostring(customDim["omnichannel.queue.ids"]) | where subscenario == "AgentConfiguration" or subscenario == 'CSRConfigurationDetails' | join kind=inner latestagentConfig on agentid | where timestamp < assignmentAttemptTime | project agentConfigRecordedTime = timestamp, agentid, subscenario, agentConfig = customDim, skillData, agentQueues | order by agentConfigRecordedTime desc | summarize arg_max(agentConfigRecordedTime, *) by agentid; let agentNames = traces | where timestamp > ago(2d) | extend customDim = parse_json(customDimensions) | extend subscenario = tostring(customDim["powerplatform.analytics.subscenario"]) | where subscenario == "AgentNameConfig" or subscenario == 'CSRConfigurationDetails' | extend agentInfo = tostring(customDim["omnichannel.data"]) | extend agentInfoParsed = parse_json(agentInfo) | mv-expand keyValue = bag_keys(agentInfoParsed) | project agentid = tostring(keyValue), agentName = tostring(agentInfoParsed[tostring(keyValue)]), timestamp | summarize arg_max(timestamp, *) by agentid; let cpListTable = statusCapacityHistoryRecords | summarize capacitprofiles = make_list(cpparsed) by agentid; cpListTable | join kind=leftouter agentNames on agentid | join kind=inner unitbasedTable on agentid | join kind=inner presenceTable on agentid | join kind=inner agentQueuesAndSkills on agentid | project agentid, agentName, UnitAvailableCapacity, BasePresenceStatus, PresenceId, capacitprofiles, skillData, agentQueues;
Individual queries for quick diagnosis
Purpose: Presence of service representatives at a point in time.
Query
let assignmentAttemptTime = now(); // Fill in the timestamp
let agentId = '92a1375c-e9dc-ef11-a72f-000d3a3ad269'; // Fill in the System User Id of the agent
let statusCapacityHistoryRecords = traces
| where timestamp < assignmentAttemptTime
| extend customDim = parse_json(customDimensions)
| extend agentid = tostring(customDim["powerplatform.analytics.resource.id"])
| extend subscenario = tostring(customDim["powerplatform.analytics.subscenario"])
| where subscenario == "AgentStatusAndCapacity" or subscenario == 'CSRStatusandCapacityDetails'
| extend cpparsed = parse_json( tostring(customDim["omnichannel.capacity_profile"]))
| where cpparsed == ""
| extend BasePresenceStatus = tostring(customDim["omnichannel.current_base_presence"])
| extend PresenceId = tostring(customDim["omnichannel.current_presence_id"])
| where agentid == agentId
| project statusCapacityHistoryRecordedTime = timestamp, agentid, subscenario, agentConfig = customDim, BasePresenceStatus, PresenceId
| summarize arg_max(statusCapacityHistoryRecordedTime, *) by agentid
| order by statusCapacityHistoryRecordedTime desc ;
let agentNames = traces
| where timestamp > ago(2d)
| extend customDim = parse_json(customDimensions)
| extend subscenario = tostring(customDim["powerplatform.analytics.subscenario"])
| where subscenario == "AgentNameConfig"
| extend agentInfo = tostring(customDim["omnichannel.data"])
| extend agentInfoParsed = parse_json(agentInfo)
| mv-expand keyValue = bag_keys(agentInfoParsed)
| project agentid = tostring(keyValue), agentName = tostring(agentInfoParsed[tostring(keyValue)]), timestamp
| summarize arg_max(timestamp, *) by agentid;
statusCapacityHistoryRecords
| join kind=leftouter agentNames on agentid
| project statusCapacityHistoryRecordedTime, agentid, agentName, BasePresenceStatus, PresenceId
Purpose: Unit capacity of service representatives at a point in time.
Query
let assignmentAttemptTime = now(); // Fill in the timestamp
let agentId = '92a1375c-e9dc-ef11-a72f-000d3a3ad269'; // Fill in the System User Id of the agent
let statusCapacityHistoryRecords = traces
| where timestamp < assignmentAttemptTime
| extend customDim = parse_json(customDimensions)
| extend agentid = tostring(customDim["powerplatform.analytics.resource.id"])
| extend subscenario = tostring(customDim["powerplatform.analytics.subscenario"])
| where subscenario == "AgentStatusAndCapacity" or subscenario == 'CSRStatusandCapacityDetails'
| extend cpparsed = parse_json( tostring(customDim["omnichannel.capacity_profile"]))
| where cpparsed == ""
| extend UnitAvailableCapacity = tostring(customDim["omnichannel.available_capacity.units"])
| where agentid == agentId
| project statusCapacityHistoryRecordedTime = timestamp, agentid, subscenario, agentConfig = customDim, UnitAvailableCapacity
| summarize arg_max(statusCapacityHistoryRecordedTime, *) by agentid
| order by statusCapacityHistoryRecordedTime desc ;
let agentNames = traces
| where timestamp > ago(2d)
| extend customDim = parse_json(customDimensions)
| extend subscenario = tostring(customDim["powerplatform.analytics.subscenario"])
| where subscenario == "AgentNameConfig"
| extend agentInfo = tostring(customDim["omnichannel.data"])
| extend agentInfoParsed = parse_json(agentInfo)
| mv-expand keyValue = bag_keys(agentInfoParsed)
| project agentid = tostring(keyValue), agentName = tostring(agentInfoParsed[tostring(keyValue)]), timestamp
| summarize arg_max(timestamp, *) by agentid;
statusCapacityHistoryRecords
| join kind=leftouter agentNames on agentid
| project statusCapacityHistoryRecordedTime, agentid, agentName, UnitAvailableCapacity
Purpose: List all service representatives in a queue at a point in time.
Query
let assignmentAttemptTime = now() ; // Fill in the timestamp
let lwiQueueId = "05a59008-f63a-f011-b4cb-6045bd070c8e"; // Fill in queue id of the work item
let agentConfigs = traces
| extend customDim = parse_json(customDimensions)
| extend agentid = tostring(customDim["powerplatform.analytics.resource.id"])
| extend subscenario = tostring(customDim["powerplatform.analytics.subscenario"])
| extend agentQueues = tostring(customDim["omnichannel.queue.ids"])
| where subscenario == "AgentConfiguration" or subscenario == 'CSRConfigurationDetails'
| where agentQueues contains lwiQueueId
| where timestamp < assignmentAttemptTime
| project agentConfigRecordedTime = timestamp, agentid, subscenario, agentConfig = customDim
| order by agentConfigRecordedTime desc
| summarize arg_max(agentConfigRecordedTime, *) by agentid;
let agentids = agentConfigs
| project agentid;
let latestagentConfig=traces
| extend customDim = parse_json(customDimensions)
| extend agentid = tostring(customDim["powerplatform.analytics.resource.id"])
| extend subscenario = tostring(customDim["powerplatform.analytics.subscenario"])
| extend agentQueues = tostring(customDim["omnichannel.queue.ids"])
| extend agentProfiles = tostring(customDim["omnichannel.capacity_profile.ids"])
| where subscenario == "AgentConfiguration" or subscenario == 'CSRConfigurationDetails'
| where timestamp < assignmentAttemptTime
| where agentid in (agentids)
| project agentConfigRecordedTime = timestamp, agentid, subscenario, agentConfig = customDim,agentQueues,agentProfiles
| order by agentConfigRecordedTime desc
| summarize arg_max(agentConfigRecordedTime, *) by agentid;
let agentNames = traces
| where timestamp > ago(2d)
| extend customDim = parse_json(customDimensions)
| extend subscenario = tostring(customDim["powerplatform.analytics.subscenario"])
| where subscenario == "AgentNameConfig"
| extend agentInfo = tostring(customDim["omnichannel.data"])
| extend agentInfoParsed = parse_json(agentInfo)
| mv-expand keyValue = bag_keys(agentInfoParsed)
| project agentid = tostring(keyValue), agentName = tostring(agentInfoParsed[tostring(keyValue)]), timestamp
| summarize arg_max(timestamp, *) by agentid;
let latestagentConfigInQueue = latestagentConfig
| join kind=leftouter agentNames on agentid
| where agentQueues contains lwiQueueId
| project agentConfigRecordedTime , agentid, agentName;
latestagentConfigInQueue
Purpose: Capacity profiles of service representatives at a point in time.
Query
let assignmentAttemptTime = now(); // Fill in timestamp of assignment attempt
let agentId = '92a1375c-e9dc-ef11-a72f-000d3a3ad269'; // Fill in the System User Id of the agent
let agentConfigs = traces
| extend customDim = parse_json(customDimensions)
| extend agentid = tostring(customDim["powerplatform.analytics.resource.id"])
| extend subscenario = tostring(customDim["powerplatform.analytics.subscenario"])
| where subscenario == "AgentConfiguration" or subscenario == 'CSRConfigurationDetails'
| where agentid == agentId
| extend agentProfiles = tostring(customDim["omnichannel.capacity_profile.ids"])
| mv-expand profileIds = parse_json(agentProfiles)
| where timestamp < assignmentAttemptTime
| project agentConfigRecordedTime = timestamp, profileIds, agentProfiles, agentid, subscenario, agentConfig = customDim
| order by agentConfigRecordedTime desc
| summarize arg_max(agentConfigRecordedTime, *) by agentid;
let capacityprofiles1 = agentConfigs
| mv-expand profileIds = parse_json(agentProfiles)
| project profileIds;
let statusCapacityHistoryRecords = traces
| extend customDim = parse_json(customDimensions)
| extend agentid = tostring(customDim["powerplatform.analytics.resource.id"])
| extend subscenario = tostring(customDim["powerplatform.analytics.subscenario"])
| extend cpparsed = parse_json( tostring(customDim["omnichannel.capacity_profile"]))
| extend capacityProfileId = tostring( cpparsed["CapacityProfileId"] )
| extend TotalCapacity = tostring( cpparsed["AvailableCapacity"] )
| extend AvailableCapacity = tostring( cpparsed["DefaultMaxCapacity"] )
| where subscenario == "AgentStatusAndCapacity" or subscenario == 'CSRStatusandCapacityDetails'
| where agentid == agentId
| where capacityProfileId in (capacityprofiles1)
| where timestamp < assignmentAttemptTime
| project statusCapacityHistoryRecordedTime = timestamp, agentid, TotalCapacity, AvailableCapacity, subscenario, agentStatusAndCapacity = customDim, capacityProfileId
| order by statusCapacityHistoryRecordedTime desc
| summarize arg_max(statusCapacityHistoryRecordedTime, *) by agentid, capacityProfileId;
let agentNames = traces
| where timestamp > ago(2d)
| extend customDim = parse_json(customDimensions)
| extend subscenario = tostring(customDim["powerplatform.analytics.subscenario"])
| where subscenario == "AgentNameConfig"
| extend agentInfo = tostring(customDim["omnichannel.data"])
| extend agentInfoParsed = parse_json(agentInfo)
| mv-expand keyValue = bag_keys(agentInfoParsed)
| project agentid = tostring(keyValue), agentName = tostring(agentInfoParsed[tostring(keyValue)]), timestamp
| summarize arg_max(timestamp, *) by agentid;
statusCapacityHistoryRecords
| join kind=leftouter agentNames on agentid
| project statusCapacityHistoryRecordedTime, agentName, agentid, capacityProfileId, TotalCapacity, AvailableCapacity
Purpose: Skills of service representatives at a point in time.
Query
let assignmentAttemptTime = now();// Fill in timestamp of assignment attempt
let agentId = '92a1375c-e9dc-ef11-a72f-000d3a3ad269'; // Fill in the System User Id of the agent
let agentConfigs = traces
| extend customDim = parse_json(customDimensions)
| extend agentid = tostring(customDim["powerplatform.analytics.resource.id"])
| extend subscenario = tostring(customDim["powerplatform.analytics.subscenario"])
| extend skillData = parse_json(tostring(customDim["omnichannel.associated_skills"]) )
| where subscenario == "AgentConfiguration" or subscenario == 'CSRConfigurationDetails'
| where agentid == agentId
| where timestamp < assignmentAttemptTime
| project agentConfigRecordedTime = timestamp, agentid, subscenario, agentConfig = customDim, skillData
| order by agentConfigRecordedTime desc
| summarize arg_max(agentConfigRecordedTime, *) by agentid;
let agentNames = traces
| where timestamp > ago(2d)
| extend customDim = parse_json(customDimensions)
| extend subscenario = tostring(customDim["powerplatform.analytics.subscenario"])
| where subscenario == "AgentNameConfig" or subscenario == 'CSRConfigurationDetails'
| extend agentInfo = tostring(customDim["omnichannel.data"])
| extend agentInfoParsed = parse_json(agentInfo)
| mv-expand keyValue = bag_keys(agentInfoParsed)
| project agentid = tostring(keyValue), agentName = tostring(agentInfoParsed[tostring(keyValue)]), timestamp
| summarize arg_max(timestamp, *) by agentid;
agentConfigs
| mv-expand skillEntry = skillData
| extend
CharacteristicId = tostring(skillEntry.CharacteristicId),
RatingValue = toint(skillEntry.RatingValue),
SkillType = toint(skillEntry.SkillType),
RatingModelMin = toint(skillEntry.RatingModelMin),
RatingModelMax = toint(skillEntry.RatingModelMax)
| join kind=leftouter agentNames on agentid
| project agentid, agentName, CharacteristicId, RatingValue, SkillType, RatingModelMin, RatingModelMax
Track manual assignments, consult, and transfers for a work item
Purpose: Manual assignments of work item with the automated attempts.
Query
traces
| extend customDim = parse_json(customDimensions)
| extend lwiid = tostring(customDim["powerplatform.analytics.resource.id"])
| extend subscenario = tostring(customDim["powerplatform.analytics.subscenario"])
| where subscenario == "CSRAssignment" or subscenario == "ManualAssignment"
//| where lwiid == "ee19abec-6e9c-4c42-9040-df6db34e1072" // Fill in the conversation id
| extend isAgentAssigned = tostring(parse_json(tostring(customDim["omnichannel.assignment.status"]))["IsAgentAssigned"])
| project timestamp, lwiid, subscenario, isAgentAssigned, customDim
| order by timestamp asc
Transfer attempts and transfers with other assignment attempts
Purpose: Transfer of work item and assignment attemps.
Query
traces
| extend customDim = parse_json(customDimensions)
| extend lwiid = tostring(customDim["powerplatform.analytics.resource.id"])
| extend subscenario = tostring(customDim["powerplatform.analytics.subscenario"])
| where lwiid == "9df2b1b5-ade8-4c59-964b-056ef2e5d6a5" // Fill in the conversation id
| project timestamp, lwiid, subscenario, customDim
| order by timestamp asc
Consults with other assignment attempts
Purpose: View consult attempts with other representatives.
Query
traces
| extend customDim = parse_json(customDimensions)
| extend lwiid = tostring(customDim["powerplatform.analytics.resource.id"])
| extend subscenario = tostring(customDim["powerplatform.analytics.subscenario"])
| where lwiid == "ee19abec-6e9c-4c42-9040-df6db34e1072" // Fill in the conversation id
| project timestamp, lwiid, subscenario, customDim
| order by timestamp asc
Conversations that ended unsuccessfully
Purpose: Determine the conversations that ended unsuccessfully.
Query
Traces
| extend customDim = parse_json(customDimensions)
| extend eventType = tostring(customDim["type"])
| extend workitem = tostring(customDim["powerplatform.analytics.resource.id"])
| extend routingStage = tostring(customDim["powerplatform.analytics.subscenario"])
| extend channelType = coalesce(tostring(customDim["omnichannel.channel.type"]), tostring(customDim["ChannelType"]))
| extend callId = tostring(customDim["omnichannel.call.id"])
| extend callStatus = toint(customDim["CallStatusCode"])
| where eventType == "CallEndDiagnosticEvent"
| where callStatus != 0 and isnotnull(callStatus)
| project timestamp, eventType, workitem, callId, routingStage, channelType, callStatus, customDimensions
End-to-end conversation tracing
Purpose: Track the events that occur across the course of a conversation.
Query
Traces
| extend customDim = parse_json(customDimensions)
| extend conversationId = tostring(customDim["powerplatform.analytics.resource.id"])
| extend routingStage = tostring(customDim["powerplatform.analytics.subscenario"])
| extend channelType = coalesce(tostring(customDim["omnichannel.channel.type"]), tostring(customDim["ChannelType"]))
| extend callId = tostring(customDim["omnichannel.call.id"])
| where conversationId == [Insert Your Work Item ID]
| project timestamp, conversationId, callId, routingStage, channelType, customDimensions
Use Azure Data Explorer dashboards with Application Insights queries
Apart from using Kusto queries directly within the Azure portal, you can use Azure Data Explorer Dashboards to visualize the results of these queries and create interactive, real-time reports. It's a powerful way to monitor and analyze the telemetry data from your Dynamics 365 Customer Service, Contact Center environment at a glance. We created a dashboard that you can directly import into your Azure Data Explorer environment.
The dashboard file and the instructions to link it to your ApplicationInsights subscription are in the GitHub repo at https://github.com/microsoft/Dynamics-365-FastTrack-Implementation-Assets/.
The dashboard includes the Conversation diagnostics page and the Unified routing diagnostics page as outlined in the following list:
- Conversation diagnostics page: This page displays diagnostics for a range of scenarios, including the following list:
- Conversation state flow for different conversation IDs.
- Fallback queue routing.
- Conversations that triggered overflow.
- Conversations rejected by multiple agents.
- Top Agent IDs with high reject count.
- Conversations where agent assignment took more than two minutes.
- Conversations where agent handle time was more than five minutes.
The following image illustrates the layout of the page based on sample data.
- Unified routing diagnostics page: This page displays diagnostics for a range of scenarios over time. You can select a work item, and then, through the context menu, you can set a cross-filter option for all tiles to load the diagnostics data for the work item.
The following image illustrates the layout of the page based on sample data.
After your dashboard is ready, you can do one of the following:
- Share the dashboard with anyone in your organization by granting them access to view or edit the dashboard in Azure Data Explorer.
- Alternatively, embed the dashboard into your own portal or website using the embedding features provided by Azure.
By integrating your analytics and insights data into an Azure Data Explorer dashboard, you can continuously monitor your Dynamics 365 Customer Service and Dynamics 365 Contact Center environments.
Related information
Configure conversation diagnostics
Subscenarios in conversation diagnostics