Marcel
Marcel That's me: Marcel

Windows Virtual Desktop - Monitoring the Spring Backend - WVD

Windows Virtual Desktop - Monitoring the Spring Backend - WVD

The long await update from WVD is public. It comes with a full ARM integration and is natively useable in the Azure Portal. Some things changed from the Fall to Spring update, and that’s include monitoring.

In this post, I’m focused on monitoring the WVD backend and not monitoring the sessions, applications, session host performance, latency, etc. To exactly monitoring these metrics, check out the solution “Azure Monitor for WVD” which works for Fall and the Spring update - and the new version comes with great Azure workbooks to additionally visualize data by host pool.

The Fall update writes logs to Azure Monitor / Log Analytics as custom logs. There is a really good blog post about this.

The Spring update writes logs to Log Analytics as well, but they have a different name and schema. To enable logging the backend, you have to enable the diagnostic settings on all involved resources:

  • Workspace
  • Host Pool
  • App Group

Make sure that you select all logs and select your Log Analytics workspace (if you use sepago’s “Azure Monitor for WVD” use the same Log Analytics workspace for the backend logging)

Registry with values

If you have done this for all resources, the WVD send logs to the selected workspace. Keep in mind that writing the first entries can take up to 20 minutes to build the data schema initially.

After a while, you should have log data in your Log Analytics workspace:

Registry with values

You can see the following logs (tables):

  • WVDCheckpoints
    • Intermediate steps while establishing and running a connection
  • WVDConnections
    • Start/End of connections
  • WVDErrors
    • Errors while establishing a connection, failures during the administration, failures getting feed informations
  • WVDHostRegistrations
    • About session host registration to host pools
  • WVDManagement
    • Administration log

The logs are internally connectable with their correlation id you have in each log.

Let’s start digging some data

Open Log Analytics an go to “Logs” and run your queries based on the KUSTO query language.

Count of brokered sessions by state

1
2
3
4
WVDConnections 
| where State =~ "Started" and Type =~"WVDConnections" 
| extend CState=iff(SessionHostOSVersion=="<>","Failure","Success") | summarize Count=count() by State=CState
| render piechart 

Registry with values

Failed connections

1
2
3
4
5
6
WVDConnections 
| where State =~ "Started" and Type =~"WVDConnections" 
| extend Multi=split(_ResourceId, "/") | extend CState=iff(SessionHostOSVersion=="<>","Failure","Success")
| where CState=~"Failure" 
| project TimeStamp=TimeGenerated, UserName, ResourceGroup=Multi[4], HostPool=Multi[8],ResourceAlias, SessionHost=SessionHostName, ClientOS=ClientOS, ClientWvdVersion=ClientVersion, CorrelationId
| order by TimeStamp desc

Failed connection with details

1
2
3
4
5
6
7
8
9
10
11
12
WVDConnections | where State =~ "Started" and Type =~"WVDConnections" 
| extend Multi=split(_ResourceId, "/") | extend CState=iff(SessionHostOSVersion=="<>","Failure","Success")
| where CState =~"Failure"
| order by TimeGenerated desc
| where State =~ "Started" | extend Multi=split(_ResourceId, "/") 
| project ResourceAlias, ResourceGroup=Multi[4], HostPool=Multi[8], SessionHostName ,UserName ,CState=iff(SessionHostOSVersion=="<>","Failure","Success"), CorrelationId, TimeGenerated
| join kind= leftouter (
    WVDErrors 
) on CorrelationId
| extend DurationFromLogon=datetime_diff("Second",TimeGenerated1,TimeGenerated)
| project  TimeStamp=TimeGenerated, DurationFromLogon, UserName, ResourceAlias ,SessionHost=SessionHostName ,Source ,CodeSymbolic , ErrorMessage=Message, ErrorCode=Code, ErrorSource=Source ,ServiceError, CorrelationId
| order by TimeStamp desc

Session logon duration by host pool

1
2
3
4
5
6
7
8
9
10
WVDConnections 
| where Type =~"WVDConnections" and State =~ "Started" | extend Multi=split(_ResourceId, "/") | project ResourceAlias, HostPool=toupper(HP=Multi[8]), SessionHostName , UserName ,CState=iff(SessionHostOSVersion=="<>","Failure","Success"), CorrelationId, TimeGenerated, ResourceGroup=Multi[4], DesktopGroup_s=toupper(strcat(RG=Multi[4],".", HP=Multi[8])) 
| join kind= leftouter (
    WVDCheckpoints 
) on CorrelationId
| extend DurationFromLogon=datetime_diff("Second",TimeGenerated1,TimeGenerated)
| where Name=~"RdpStackLogon" 
| project UserName, ResourceGroup, DesktopGroup_s,SessionHost=SessionHostName, TimeStamp=TimeGenerated1, DurationFromLogon
| summarize DurationInSeconds=avg(DurationFromLogon) by HostPool=DesktopGroup_s 
| render columnchart kind=unstacked 

Registry with values

Session logon duration by user (desc)

WVDConnections 
| where Type =~"WVDConnections" and State =~ "Started" | extend Multi=split(_ResourceId, "/") | project ResourceAlias, HostPool=toupper(HP=Multi[8]), SessionHostName , UserName ,CState=iff(SessionHostOSVersion=="<>","Failure","Success"), CorrelationId, TimeGenerated, ResourceGroup=Multi[4], DesktopGroup_s=toupper(strcat(RG=Multi[4],".", HP=Multi[8])) 
| join kind= leftouter (
    WVDCheckpoints 
) on CorrelationId
| extend DurationFromLogon=datetime_diff("Second",TimeGenerated1,TimeGenerated)
| where Name=~"RdpStackLogon" 
| project UserName, ResourceGroup, DesktopGroup_s,SessionHost=SessionHostName, TimeStamp=TimeGenerated1, DurationFromLogon
| summarize DurationInSeconds=avg(DurationFromLogon) by HostPool=UserName
| order by DurationInSeconds desc 

Administrative activities over time

1
2
3
WVDManagement 
| summarize Count=count() by bin(TimeGenerated,15)
| render scatterchart 

Registry with values

Good to know: Sepago’s commercial “Azure Monitor for WVD” brings the ready to use Azure workbooks for the session and app monitoring and workbooks for the WVD backend:

Registry with values