Monitor your website performance on IIS with Zabbix, Performance Counters, PowerShell and WMI, because it is important to keep an eye on website and webserver performance. For this, Zabbix is a great tool and knowing how to collect metrics using Performance Counters, PowerShell and WMI is readily in your toolbox.
I've written about Zabbix monitoring before: Use Zabbix to monitor your .NET CLR Garbage Collected heap, and Getting more out your Windows Performance Counters monitoring for web applications - for example. This time you're using almost the same techniques to monitor a website hosted in IIS. Sweet, right? For this you use Win32_PerfRawData_W3SVC_WebService class.
The Web Service object includes counters specific to the World Wide Web Publishing Service.
There are roughly 95 properties in the Win32_PerfRawData_W3SVC_WebService class. A lot are interesting, and a lot are only interesting if you're using them. For instance, I wouldn't want to know PutRequestsPersec
and TotalPutRequests
if I'm not using the HTTP PUT verb on my site or server. In one situation, these are my preferred items to monitor (metrics to collect):
- Name
- AnonymousUsersPersec
- BytesReceivedPersec
- BytesSentPersec
- BytesTotalPersec
- ConnectionAttemptsPersec
- CurrentAnonymousUsers
- CurrentConnections
- DeleteRequestsPersec
- FilesPersec
- FilesReceivedPersec
- FilesSentPersec
- GetRequestsPersec
- LockedErrorsPersec
- LockRequestsPersec
- LogonAttemptsPersec
- MaximumConnections
- NonAnonymousUsersPersec
- NotFoundErrorsPersec
- OptionsRequestsPersec
- OtherRequestMethodsPersec
- PostRequestsPersec
- PropfindRequestsPersec
- PutRequestsPersec
- ServiceUptime
- TotalAnonymousUsers
- TotalBytesReceived
- TotalBytesSent
- TotalBytesTransferred
- TotalDeleteRequests
- TotalFilesReceived
- TotalFilesSent
- TotalFilesTransferred
- TotalGetRequests
- TotalLockedErrors
- TotalLockRequests
- TotalLogonAttempts
- TotalMethodRequests
- TotalMethodRequestsPersec
- TotalNonAnonymousUsers
- TotalNotFoundErrors
- TotalOptionsRequests
- TotalPostRequests
- TotalPropfindRequests
- TotalPutRequests
- TotalUnlockRequests
- UnlockRequestsPersec
Yes this is a lot, but you can always remove items if they don't prove valuable.
Psst, here is how to get the number of current connections in IIS using PowerShell:
Use PowerShell, Performance Counters and WMI to get the current number of active connections to IIS websites. Perfect for monitoring IIS webservers in Zabbix.
Get-WebsiteMetrics.ps1 - Get all Website related performance metrics with PowerShell
The following PowerShell script is what puts everything together and returns the info in a JSON. You run this through Zabbix Agent (2) as a UserParameter
.
param (
[Parameter(Position=0, Mandatory=$False)]
[string] $action = "discovery"
)
# Get all website names
$allwebsites = (Get-CimInstance -EA SilentlyContinue -Query "select * from Win32_PerfRawData_W3SVC_WebService" -Namespace root\cimv2).Name
# Get all Win32_PerfRawData_W3SVC_WebService properties for all websites
$allwebsiteinfo = Get-CimInstance -EA SilentlyContinue -Query "select * from Win32_PerfRawData_W3SVC_WebService" -Namespace root\cimv2 | Select-Object Name,AnonymousUsersPersec,BytesReceivedPersec,BytesSentPersec,BytesTotalPersec,ConnectionAttemptsPersec,CurrentAnonymousUsers,CurrentConnections,DeleteRequestsPersec,FilesPersec,FilesReceivedPersec,FilesSentPersec,GetRequestsPersec,LockedErrorsPersec,LockRequestsPersec,LogonAttemptsPersec,MaximumConnections,NonAnonymousUsersPersec,NotFoundErrorsPersec,OptionsRequestsPersec,OtherRequestMethodsPersec,PostRequestsPersec,PropfindRequestsPersec,PutRequestsPersec,ServiceUptime,TotalAnonymousUsers,TotalBytesReceived,TotalBytesSent,TotalBytesTransferred,TotalDeleteRequests,TotalFilesReceived,TotalFilesSent,TotalFilesTransferred,TotalGetRequests,TotalLockedErrors,TotalLockRequests,TotalLogonAttempts,TotalMethodRequests,TotalMethodRequestsPersec,TotalNonAnonymousUsers,TotalNotFoundErrors,TotalOptionsRequests,TotalPostRequests,TotalPropfindRequests,TotalPutRequests,TotalUnlockRequests,UnlockRequestsPersec
# Master function that returns a hashtable containing metrics per website
function get-WebsiteInfo($website) {
Try {
$data = ($allwebsiteinfo | Where-Object Name -eq "${website}")
$hashtable = @{
Name = $data.Name
AnonymousUsersPersec = $data.AnonymousUsersPersec
BytesReceivedPersec = $data.BytesReceivedPersec
BytesSentPersec = $data.BytesSentPersec
BytesTotalPersec = $data.BytesTotalPersec
ConnectionAttemptsPersec = $data.ConnectionAttemptsPersec
CurrentAnonymousUsers = $data.CurrentAnonymousUsers
CurrentConnections = $data.CurrentConnections
DeleteRequestsPersec = $data.DeleteRequestsPersec
FilesPersec = $data.FilesPersec
FilesReceivedPersec = $data.FilesReceivedPersec
FilesSentPersec = $data.FilesSentPersec
GetRequestsPersec = $data.GetRequestsPersec
LockedErrorsPersec = $data.LockedErrorsPersec
LockRequestsPersec = $data.LockRequestsPersec
LogonAttemptsPersec = $data.LogonAttemptsPersec
MaximumConnections = $data.MaximumConnections
NonAnonymousUsersPersec = $data.NonAnonymousUsersPersec
NotFoundErrorsPersec = $data.NotFoundErrorsPersec
OptionsRequestsPersec = $data.OptionsRequestsPersec
OtherRequestMethodsPersec = $data.OtherRequestMethodsPersec
PostRequestsPersec = $data.PostRequestsPersec
PropfindRequestsPersec = $data.PropfindRequestsPersec
PutRequestsPersec = $data.PutRequestsPersec
ServiceUptime = $data.ServiceUptime
TotalAnonymousUsers = $data.TotalAnonymousUsers
TotalBytesReceived = $data.TotalBytesReceived
TotalBytesSent = $data.TotalBytesSent
TotalBytesTransferred =$data.TotalBytesTransferred
TotalDeleteRequests = $data.TotalDeleteRequests
TotalFilesReceived = $data.TotalFilesReceived
TotalFilesSent = $data.TotalFilesSent
TotalFilesTransferred = $data.TotalFilesTransferred
TotalGetRequests = $data.TotalGetRequests
TotalLockedErrors = $data.TotalLockedErrors
TotalLockRequests = $data.TotalLockRequests
TotalLogonAttempts = $data.TotalLogonAttempts
TotalMethodRequests = $data.TotalMethodRequests
TotalMethodRequestsPersec = $data.TotalMethodRequestsPersec
TotalNonAnonymousUsers = $data.TotalNonAnonymousUsers
TotalNotFoundErrors = $data.TotalNotFoundErrors
TotalOptionsRequests = $data.TotalOptionsRequests
TotalPostRequests = $data.TotalPostRequests
TotalPropfindRequests = $data.TotalPropfindRequests
TotalPutRequests = $data.TotalPutRequests
TotalUnlockRequests = $data.TotalUnlockRequests
UnlockRequestsPersec = $data.UnlockRequestsPersec
}
@($hashtable.keys) | % {
if (-not $hashtable[$_]) {
$hashtable.Remove($_)
}
}
return $hashtable
}
Catch {
}
}
switch ($action) {
"discovery" {
@{
"data" = $allwebsites | foreach { @{
"{#WEBSITE}" = $_
}}
} | ConvertTo-Json
}
"getwebsiteinfo" {
# Loop over all website names, store the function result in an array
$WebsiteInfo = @{}
$allwebsites | foreach {
$WebsiteInfo[$_] = Get-WebsiteInfo $_
}
# Convert the array to JSON
$WebsiteInfo | ConvertTo-Json
}
default {
"Script error"
}
}
When ran, you can expect the following JSON output to use in your Zabbix template:
"example.com": {
"TotalNotFoundErrors": 23,
"MaximumConnections": 12,
"LogonAttemptsPersec": 221,
"TotalNonAnonymousUsers": 120,
"TotalMethodRequests": 222,
"TotalFilesTransferred": 27,
"BytesReceivedPersec": 196478,
"ServiceUptime": 2993992,
"TotalLogonAttempts": 221,
"BytesTotalPersec": 1825488,
"PostRequestsPersec": 4,
"TotalGetRequests": 212,
"FilesPersec": 27,
"BytesSentPersec": 1629010,
"TotalPostRequests": 4,
"NonAnonymousUsersPersec": 120,
"NotFoundErrorsPersec": 23,
"Name": "example.com",
"TotalBytesTransferred": 1825488,
"TotalMethodRequestsPersec": 222,
"TotalFilesSent": 27,
"AnonymousUsersPersec": 94,
"FilesSentPersec": 27,
"GetRequestsPersec": 212,
"TotalBytesSent": 1629010,
"TotalBytesReceived": 196478,
"TotalAnonymousUsers": 94,
"ConnectionAttemptsPersec": 219
},
"example.org": {
"TotalNotFoundErrors": 25,
"MaximumConnections": 8,
"OtherRequestMethodsPersec": 1,
"LogonAttemptsPersec": 375,
"TotalNonAnonymousUsers": 58,
"TotalMethodRequests": 378,
"TotalFilesTransferred": 33,
"BytesReceivedPersec": 133698,
"ServiceUptime": 2993992,
"TotalLogonAttempts": 375,
"BytesTotalPersec": 1339416,
"PostRequestsPersec": 28,
"TotalGetRequests": 339,
"FilesPersec": 33,
"BytesSentPersec": 1205718,
"TotalPostRequests": 28,
"NonAnonymousUsersPersec": 58,
"NotFoundErrorsPersec": 25,
"Name": "example.org",
"TotalBytesTransferred": 1339416,
"TotalMethodRequestsPersec": 378,
"TotalFilesSent": 33,
"AnonymousUsersPersec": 192,
"FilesSentPersec": 33,
"GetRequestsPersec": 339,
"TotalBytesSent": 1205718,
"TotalBytesReceived": 133698,
"TotalAnonymousUsers": 192,
"ConnectionAttemptsPersec": 358
}
Save the above code into a file (Get-WebsiteMetrics.ps1
for example) and configure it in your Zabbix configuration as a UserParameter, along with a parent fetcher:
UserParameter=Fetch,powershell -NoProfile -ExecutionPolicy Bypass -File C:\path\to\Get-WebsiteMetrics.ps1 discovery
UserParameter=w3wp.metric,powershell -NoProfile -ExecutionPolicy Bypass -File C:\path\to\Get-WebsiteMetrics.ps1 getwebsiteinfo
This way you can create an autodiscover template with dependent items:
<items>
<item>
<name>NewFetcher</name>
<key>Fetch</key>
<history>0</history>
<trends>0</trends>
<value_type>TEXT</value_type>
</item>
<!-- ... -->
</items>
<discovery_rules>
<discovery_rule>
<name>Website Insights</name>
<key>w3wp.discovery</key>
<delay>1m</delay>
<item_prototypes>
<item_prototype>
<name>Website: {#WEBSITE} AnonymousUsersPersec</name>
<type>DEPENDENT</type>
<key>w3wp.metric.AnonymousUsersPersec[{#WEBSITE}]</key>
<delay>0</delay>
<history>7d</history>
<description>The rate users are making anonymous connections to the Web service.</description>
<application_prototypes>
<application_prototype>
<name>website: {#WEBSITE}</name>
</application_prototype>
</application_prototypes>
<preprocessing>
<step>
<type>JSONPATH</type>
<params>$.AnonymousUsersPersec</params>
</step>
<step>
<type>CHANGE_PER_SECOND</type>
<params/>
</step>
</preprocessing>
<master_item>
<key>newfetch[{#WEBSITE}]</key>
</master_item>
</item_prototype>
<!-- ... -->
</discovery_rule>
</discovery_rules>
If you liked this post then be sure to check out my other Zabbix posts @ Sysadmins of the North:
- Monitor IIS application pools in Zabbix, part 1
- ASP.NET web application monitoring in Zabbix, part 2
- Getting more out your Windows Performance Counters monitoring for web applications – part 3
- Monitor .NET CLR Garbage Collected heap from your web application
- Monitor SQL Server and databases in depth using Zabbix