Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions doc/100-General/10-Changelog.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ Released closed milestones can be found on [GitHub](https://github.com/Icinga/ic

[Issues and PRs](https://github.com/Icinga/icinga-powershell-framework/milestone/38)

* [#11](https://github.com/Icinga/icinga-powershell-framework/pull/11) Adds feature to update the cache for performance counter instances to keep track of system changes

## 1.13.4 (tbd)

[Issues and PRs](https://github.com/Icinga/icinga-powershell-framework/milestone/42)
Expand Down
43 changes: 32 additions & 11 deletions lib/core/perfcounter/New-IcingaPerformanceCounter.psm1
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,9 @@
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
.PARAMETER NoCache
Set this if no caching of the counter is intended. This will prevent from adding
single counters to the internal cache during update phase
.INPUTS
System.String
.LINK
Expand All @@ -36,7 +39,8 @@ function New-IcingaPerformanceCounter()
{
param(
[string]$Counter = '',
[boolean]$SkipWait = $FALSE
[boolean]$SkipWait = $FALSE,
[switch]$NoCache = $FALSE
);

# Simply use the counter name, like
Expand All @@ -45,7 +49,7 @@ function New-IcingaPerformanceCounter()
return (New-IcingaPerformanceCounterNullObject -FullName $Counter -ErrorMessage 'Failed to initialise counter, as no counter was specified.');
}

[array]$CounterArray = $Counter.Split('\');
[array]$CounterArray = $Counter.Split('\');
[string]$UseCounterCategory = '';
[string]$UseCounterName = '';
[string]$UseCounterInstance = '';
Expand All @@ -72,6 +76,13 @@ function New-IcingaPerformanceCounter()
# At last get the actual counter containing our values
$UseCounterName = $CounterArray[2];

if ($NoCache -eq $FALSE) {
# If we are not skipping the cache, we will update the cache
# with the current counter path. This will ensure that we
# have a valid cache for the counter and can return it later
Update-IcingaPerformanceCounterCache -Counter $Counter;
}

# Now as we know how the counter path is constructed and has been split into
# the different values, we need to know how to handle the instances of the counter

Expand All @@ -80,11 +91,13 @@ function New-IcingaPerformanceCounter()
# 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 ($NoCache -eq $FALSE) {
# 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 ($null -ne $CachedCounter) {
return (New-IcingaPerformanceCounterResult -FullName $Counter -PerformanceCounters $CachedCounter);
}
}

# If we need to build the array, load all instances from the counters and
Expand Down Expand Up @@ -116,24 +129,32 @@ function New-IcingaPerformanceCounter()
# 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 $AllCountersInstances;
if ($NoCache -eq $FALSE) {
Add-IcingaPerformanceCounterCache -Counter $Counter -Instances $AllCountersInstances;
}
return (New-IcingaPerformanceCounterResult -FullName $Counter -PerformanceCounters $AllCountersInstances);
} else {
# This part will handle the counters without any instances as well as
# specifically 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 ($NoCache -eq $FALSE) {
$CachedCounter = Get-IcingaPerformanceCounterCacheItem -Counter $Counter;

if ($null -ne $CachedCounter) {
return $CachedCounter;
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;
if ($NoCache -eq $FALSE) {
Add-IcingaPerformanceCounterCache -Counter $Counter -Instances $NewCounter;
} else {
return $NewCounter;
}
}

# This function will always return non-instance counters or
Expand Down
13 changes: 0 additions & 13 deletions lib/core/perfcounter/New-IcingaPerformanceCounterArray.psm1
Original file line number Diff line number Diff line change
Expand Up @@ -40,26 +40,13 @@ function New-IcingaPerformanceCounterArray()
# NumOfCounters * 500 milliseconds for the first runs. This will speed
# up the general loading of counters and will not require some fancy
# pre-caching / configuration handler
$CachedCounter = Get-IcingaPerformanceCounterCacheItem -Counter $Counter;

# Remove this for now to ensure our CPU metrics will not be cached
# and represent correct values, not exceeding 200% and beyond
#if ($null -ne $CachedCounter) {
# $RequireSleep = $FALSE;
#}

$obj = New-IcingaPerformanceCounter -Counter $counter -SkipWait $TRUE;
if ($CounterResult.ContainsKey($obj.Name()) -eq $FALSE) {
$CounterResult.Add($obj.Name(), $obj.Value());
}
}

# TODO: Add a cache for our Performance Counters to only fetch them once
# for each session to speed up the loading. This cold be something like
# this:
#
# $Global:Icinga.Private.PerformanceCounter.Cache += $CounterResult;

# Above we initialise ever single counter and we only require a sleep once
# in case a new, yet unknown counter was added
if ($RequireSleep) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ function Show-IcingaPerformanceCounterInstances()
return;
}

$PerfCounter = New-IcingaPerformanceCounter -Counter $Counter -SkipWait $TRUE;
$PerfCounter = New-IcingaPerformanceCounter -Counter $Counter -SkipWait $TRUE -NoCache;

foreach ($entry in $PerfCounter.Counters) {
$Instances.Add(
Expand Down
75 changes: 75 additions & 0 deletions lib/core/perfcounter/Update-IcingaPerformanceCounterCache.psm1
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
<#
.SYNOPSIS
Updates the cached instances of a specified performance counter in the Icinga PowerShell Framework.

.DESCRIPTION
The Update-IcingaPerformanceCounterCache function synchronizes the cached instances of a given performance counter.
It removes instances that no longer exist and adds new instances that are not yet cached.
This ensures that the cache accurately reflects the current state of the performance counter instances.

.PARAMETER Counter
The name of the performance counter whose cache should be updated.

.EXAMPLE
Update-IcingaPerformanceCounterCache -Counter "\Processor(_Total)\% Processor Time"

Updates the cache for the specified performance counter.

.NOTES
This function is intended for internal use within the Icinga PowerShell Framework.
It requires that the global cache variable and related functions are available.

#>
function Update-IcingaPerformanceCounterCache()
{
param (
$Counter
);

if ([string]::IsNullOrEmpty($Counter)) {
return;
}

if ($Global:Icinga.Private.PerformanceCounter.Cache.ContainsKey($Counter) -eq $FALSE) {
# If there is no cache entry for the provided counter, we don't need to do anything yet
return;
}

# First we need to prepare some data by fetching the current instances of the counter
# and the cached instances. We will then compare them and update the cache accordingly
[array]$CounterInstances = Show-IcingaPerformanceCounterInstances -Counter $Counter;
[array]$CachedInstances = $Global:Icinga.Private.PerformanceCounter.Cache[$Counter];
[array]$UpdatedInstances = @();
[array]$CachedInstanceNames = $CachedInstances.FullName;

# We will now iterate over the cached instances and check if they are still present in the current
# counter instances. If they are not, we will remove them from the cache.
# If they are present, we will keep them in the updated instances array.
for ($index = 0; $index -lt $CachedInstances.Count; $index++) {
$cachedInstance = $CachedInstances[$index];
$instanceName = $cachedInstance.FullName;

# If the instance is not in the current list, we remove it
if ($CounterInstances.Value -contains $instanceName) {
$UpdatedInstances += $cachedInstance;
}
}

# Now we will iterate over the current counter instances and check if they are already cached.
# If they are not, we will add them to the updated instances array.
# This ensures that we only add new instances that are not already cached.
for ($index = 0; $index -lt $CounterInstances.Count; $index++) {
$instanceName = $CounterInstances[$index].Value;

if ($CachedInstanceNames -notcontains $instanceName) {
# If the instance is not cached, we create a new performance counter object
# and add it to the updated instances array
$UpdatedInstances += (New-IcingaPerformanceCounter -Counter $instanceName -SkipWait $TRUE -NoCache);
}
}

# Finally, we update the cache with the new instances
# This will ensure that the cache is up-to-date with the current state of the performance
# counter instances
$Global:Icinga.Private.PerformanceCounter.Cache[$Counter] = $UpdatedInstances;
}