icinga-powershell-framework/lib/core/perfcounter/New-IcingaPerformanceCounter.psm1
2020-08-20 14:28:11 +02:00

144 lines
7.6 KiB
PowerShell

<#
.SYNOPSIS
Creates counter objects and sub-instances from a given Performance Counter
Will return either a New-IcingaPerformanceCounterObject or New-IcingaPerformanceCounterResult
which both contain the same members, allowing for dynmically use of objects
.DESCRIPTION
Creates counter objects and sub-instances from a given Performance Counter
Will return either a New-IcingaPerformanceCounterObject or New-IcingaPerformanceCounterResult
which both contain the same members, allowing for dynmically use of objects
.FUNCTIONALITY
Creates counter objects and sub-instances from a given Performance Counter
Will return either a New-IcingaPerformanceCounterObject or New-IcingaPerformanceCounterResult
which both contain the same members, allowing for dynmically use of objects
.EXAMPLE
PS>New-IcingaPerformanceCounter -Counter '\Processor(*)\% processor time';
FullName Counters
-------- --------
\Processor(*)\% processor time {@{FullName=\Processor(2)\% processor time; Category=Processor; Instance=2; Counter=%...
.EXAMPLE
PS>New-IcingaPerformanceCounter -Counter '\Processor(*)\% processor time' -SkipWait;
.PARAMETER Counter
The path to the Performance Counter to fetch data for
.PARAMETER SkipWait
Set this if no sleep is intended for initialising the counter. This can be useful
if multiple counters are fetched during one call with this function if the sleep
is done afterwards manually. A sleep is set to 500ms to ensure counter data is
valid and contains an offset from previous/current values
.INPUTS
System.String
.LINK
https://github.com/Icinga/icinga-powershell-framework
#>
function New-IcingaPerformanceCounter()
{
param(
[string]$Counter = '',
[boolean]$SkipWait = $FALSE
);
# Simply use the counter name, like
# \Paging File(_total)\% Usage
if ([string]::IsNullOrEmpty($Counter) -eq $TRUE) {
return (New-IcingaPerformanceCounterNullObject -FullName $Counter -ErrorMessage 'Failed to initialise counter, as no counter was specified.');
}
[array]$CounterArray = $Counter.Split('\');
[string]$UseCounterCategory = '';
[string]$UseCounterName = '';
[string]$UseCounterInstance = '';
# If we add the counter as it should be
# \Paging File(_total)\% Usage
# the first array element will be an empty string we can skip
# Otherwise the name was wrong and we should not continue
if (-Not [string]::IsNullOrEmpty($CounterArray[0])) {
return (New-IcingaPerformanceCounterNullObject -FullName $Counter -ErrorMessage ([string]::Format('Failed to deserialize counter "{0}". It seems the leading "\" is missing.', $Counter)));
}
# In case our Performance Counter is containing instances, we should split
# The content and read the instance and counter category out
if ($CounterArray[1].Contains('(')) {
[array]$TmpCounter = $CounterArray[1].Split('(');
$UseCounterCategory = $TmpCounter[0];
$UseCounterInstance = $TmpCounter[1].Replace(')', '');
} else {
# Otherwise we only require the category
$UseCounterCategory = $CounterArray[1];
}
# At last get the actual counter containing our values
$UseCounterName = $CounterArray[2];
# Now as we know how the counter path is constructed and has been splitted into
# the different values, we need to know how to handle the instances of the counter
# If we specify a instance with (*) we want the module to automaticly fetch all
# instances for this counter. This will result in an New-IcingaPerformanceCounterResult
# which contains the parent name including counters for all instances that
# have been found
if ($UseCounterInstance -eq '*') {
# In case we already loaded the counters once, return the finished array
$CachedCounter = Get-IcingaPerformanceCounterCacheItem -Counter $Counter;
if ($null -ne $CachedCounter) {
return (New-IcingaPerformanceCounterResult -FullName $Counter -PerformanceCounters $CachedCounter);
}
# If we need to build the array, load all instances from the counters and
# create single performance counters and add them to a custom array and
# later to a custom object
try {
[array]$AllCountersIntances = @();
$CounterInstances = New-Object System.Diagnostics.PerformanceCounterCategory($UseCounterCategory);
foreach ($instance in $CounterInstances.GetInstanceNames()) {
[string]$NewCounterName = $Counter.Replace('*', $instance);
$NewCounter = New-IcingaPerformanceCounterObject -FullName $NewCounterName -Category $UseCounterCategory -Counter $UseCounterName -Instance $instance -SkipWait $TRUE;
$AllCountersIntances += $NewCounter;
}
} catch {
# Throw an exception in case our permissions are not enough to fetch performance counter
Exit-IcingaThrowException -InputString $_.Exception -StringPattern 'System.UnauthorizedAccessException' -ExceptionType 'Permission' -ExceptionThrown $IcingaExceptions.Permission.PerformanceCounter;
Exit-IcingaThrowException -InputString $_.Exception -StringPattern 'System.InvalidOperationException' -ExceptionType 'Input' -CustomMessage $Counter -ExceptionThrown $IcingaExceptions.Inputs.PerformanceCounter;
Exit-IcingaThrowException -InputString $_.Exception -StringPattern '' -ExceptionType 'Unhandled';
# Shouldn't actually get down here anyways
return (New-IcingaPerformanceCounterNullObject -FullName $Counter -ErrorMessage ([string]::Format('Failed to deserialize instances for counter "{0}". Exception: "{1}".', $Counter, $_.Exception.Message)));
}
# If we load multiple instances, we should add a global wait here instead of a wait for each single instance
# This will speed up CPU loading for example with plenty of cores avaiable
if ($SkipWait -eq $FALSE) {
Start-Sleep -Milliseconds 500;
}
# Add the parent counter including the array of Performance Counters to our
# caching mechanism and return the New-IcingaPerformanceCounterResult object for usage
# within the monitoring modules
Add-IcingaPerformanceCounterCache -Counter $Counter -Instances $AllCountersIntances;
return (New-IcingaPerformanceCounterResult -FullName $Counter -PerformanceCounters $AllCountersIntances);
} else {
# This part will handle the counters without any instances as well as
# specificly assigned instances, like (_Total) CPU usage.
# In case we already have the counter within our cache, return the
# cached informations
$CachedCounter = Get-IcingaPerformanceCounterCacheItem -Counter $Counter;
if ($null -ne $CachedCounter) {
return $CachedCounter;
}
# If the cache is not present yet, create the Performance Counter object,
# and add it to our cache
$NewCounter = New-IcingaPerformanceCounterObject -FullName $Counter -Category $UseCounterCategory -Counter $UseCounterName -Instance $UseCounterInstance -SkipWait $SkipWait;
Add-IcingaPerformanceCounterCache -Counter $Counter -Instances $NewCounter;
}
# This function will always return non-instance counters or
# specificly defined instance counters. Performance Counter Arrays
# are returned within their function. This is just to ensure that the
# function looks finished from developer point of view
return (Get-IcingaPerformanceCounterCacheItem -Counter $Counter);
}