Thank you for reaching out ZackB903!
At a high level, Azure Virtual Desktop Insights is designed to help IT administrators monitor and manage their Azure Virtual Desktop environments. By setting up Log Analytics, you can pipe Azure Virtual Desktop diagnostics data into Azure Virtual Desktop Insights. This setup will provide you with a comprehensive view of your deployment, making it easier to find and troubleshoot problems, and understand resource utilization. If you haven’t already set up Log Analytics, please refer to our documentation here.
In general, all data available in Azure Virtual Desktop Insights can be accessed in a tabular format. You can customize our charts, graphs and queries to suit your specific use cases. For more information, check out this link.
To collect client disconnect events as time-series data for your monitoring system, consider trying the query below.
The query takes two parameters at the top:
- WindowStart: The beginning of the time frame being analyzed. For example, you might set this to be 12 hours ago.
- WindowDuration: The length of the time frame being analyzed. For example, if starting 12 hours ago, to cover even the most recent events, you would set it to 12 hours.
The query will output four time series:
- TimeStamp: The slices of timestamps mapping to the results reported in the other time series data.
- ConcurrentConnections: The peak number of active concurrent connections to the Azure Virtual Desktop session hosts in this time slice.
- Disconnects: The number of times a connection is unexpectedly terminated.
- PercentageDrop: The portion of connections that disconnected, expressed as a percentage of all concurrent connections at that time.
let WindowStart = ago(3d); // Set this to the start of the analysis window
let WindowDuration = 1d; // Set this to the length of the window
let WindowEnd = WindowStart + WindowDuration;
let WindowResolution = max_of(WindowDuration / 144, 1m); // Provide 144 data points, but no sub-minute granularity
WVDConnections
| where (State == "Started" and TimeGenerated between(WindowStart .. WindowEnd)) // All connections that started within the time window
or (State == "Completed" and TimeGenerated > WindowStart) // All connections that ended after the time window
or (State == "Connected" and TimeGenerated between(WindowStart .. WindowEnd)) // All connections established within the time window
| summarize
StartDate = minif(TimeGenerated, State == "Started"), // Bring the main properties of the connection into a single row
EndDate = minif(TimeGenerated, State == "Completed"),
ConnectedTime = minif(TimeGenerated, State == "Connected"),
UserName = take_any(UserName),
SessionHostName = take_any(SessionHostName)
by CorrelationId
| where isnotempty(ConnectedTime) // Only keep connections that actually got connected to avoid noise from authentication errors, etc.
| project CorrelationId, UserName, StartDate, EndDate = coalesce(EndDate, now()), // If the connection does not have a termination event, assume it terminates now
SessionHostName, ConnectedTime
| where EndDate > WindowStart and ConnectedTime < WindowEnd // Only keep connections that have some overlap with the time window selected
| join kind=leftouter
(
WVDErrors
| where TimeGenerated > WindowStart
| summarize FirstError = min(TimeGenerated) by CorrelationId
)
on CorrelationId
| extend
Probe=range(WindowStart, WindowEnd, WindowResolution),
EndDate=coalesce(FirstError, EndDate), // For connections that have an error, the earliest error is the disconnection point
HasErrors=isnotempty(FirstError)
| mv-apply Probe to typeof(datetime) on
(
where (Probe between (StartDate .. EndDate) or (EndDate between(Probe .. (WindowResolution + Probe))))
| extend
ConnectionContainsProbe = Probe between(StartDate .. EndDate),
ConnectionEndedHere=EndDate between(Probe .. (WindowResolution + Probe))
)
| where ConnectionContainsProbe
| extend ErrorMarker = (ConnectionEndedHere and HasErrors) // This connection will be rendered as an error in this time probe
| extend ActiveConnection = ConnectionContainsProbe and not(ErrorMarker) // This connection will be rendered as an active connection in this time probe
| make-series
Disconnects=dcountif(CorrelationId, ErrorMarker),
ConcurrentConnections=dcountif(CorrelationId, ActiveConnection),
default=0
on Probe
from WindowStart to WindowEnd step WindowResolution
| extend PercentageDrop = series_fill_const(series_divide(Disconnects, series_add(ConcurrentConnections, Disconnects)), 0, todouble("NaN")) // For times with no connections, percentage drop should be zero
| project TimeStamp=Probe, ConcurrentConnections, Disconnects, PercentageDrop
| render timechart
If you’d rather handle the results as individual rows, you can use the mv-expand operator.
With these outputs, you might define an alert based on an absolute number of disconnects happening in a single time slice. You might also set one based on a percentage drop, but only allow it to trigger if there were more than a certain number of other connections, to avoid alerting noise from a single user disconnecting, etc. E.g. You may want to set an alert based on the percentage drop, but only if there are more than 10 connections to avoid alerting based on a single user disconnecting.
The query shared is based on the visualizations from the Connection Reliability tab in Azure Virtual Desktop Insights, and this new feature will give you a starting point to investigate any disconnection alerts that trigger in your deployments. Let us know how it works out for you, and we would love to hear more about how you monitor your environment in general. Your feedback is incredibly valuable to us, so please feel free to share any insights and questions you have!