lib/core/perfcounter/New-IcingaPerformanceCounter.psm1

<#
 # This is the main function which is called from this script, constructing our counters
 # and loading possible sub-instances from our Performance Counter.
 # It will return either an New-IcingaPerformanceCounterObject or New-IcingaPerformanceCounterResult
 # which both contain the same members, allowing us to dynamicly use the objects
 # without having to worry about exception.
 #>

 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
         # TODO: Re-Implement caching for counters
         <#if ($Icinga2.Cache.PerformanceCounter.ContainsKey($Counter) -eq $TRUE) {
             return (New-IcingaPerformanceCounterResult -FullName $Counter -PerformanceCounters $Icinga2.Cache.PerformanceCounter[$Counter]);
         }#>

 
         # 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
         # TODO: Re-Implement caching for counters
         # $Icinga2.Cache.PerformanceCounter.Add($Counter, $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
         # TODO: Re-Implement caching for counters
         <#if ($Icinga2.Cache.PerformanceCounter.ContainsKey($Counter) -eq $TRUE) {
             return $Icinga2.Cache.PerformanceCounter[$Counter];
         }#>

 
         # 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;
         # TODO: Re-Implement caching for counters
         #$Icinga2.Cache.PerformanceCounter.Add($Counter, $NewCounter);
         return $NewCounter; #TODO: Remove once caching is implemented
     }
 
     # 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
     # TODO: Re-Implement caching for counters, right now we return $NewCounter by default
     #return $Icinga2.Cache.PerformanceCounter[$Counter];
 }