Skip to content

Commit ad59bb9

Browse files
authored
Merge pull request #828 from Icinga:feature/adds_cache_update_for_performance_counters
Feature: Adds caching update for added/removed performance counter instances Adds feature to update the cache for performance counter instances to keep track of system changes. This will ensure that while we are running as a daemon with Icinga for Windows, newly added or removed information for performance counters will be updated whenever required.
2 parents 93ac719 + 4051239 commit ad59bb9

File tree

5 files changed

+109
-25
lines changed

5 files changed

+109
-25
lines changed

doc/100-General/10-Changelog.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ Released closed milestones can be found on [GitHub](https://github.com/Icinga/ic
2020
### Enhancements
2121

2222
* [#838](https://github.com/Icinga/icinga-powershell-framework/pull/838) Enhances Icinga for Windows to never load and user PowerShell profiles
23+
* [#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
2324

2425
## 1.13.4 (tbd)
2526

lib/core/perfcounter/New-IcingaPerformanceCounter.psm1

Lines changed: 32 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,9 @@
2626
if multiple counters are fetched during one call with this function if the sleep
2727
is done afterwards manually. A sleep is set to 500ms to ensure counter data is
2828
valid and contains an offset from previous/current values
29+
.PARAMETER NoCache
30+
Set this if no caching of the counter is intended. This will prevent from adding
31+
single counters to the internal cache during update phase
2932
.INPUTS
3033
System.String
3134
.LINK
@@ -36,7 +39,8 @@ function New-IcingaPerformanceCounter()
3639
{
3740
param(
3841
[string]$Counter = '',
39-
[boolean]$SkipWait = $FALSE
42+
[boolean]$SkipWait = $FALSE,
43+
[switch]$NoCache = $FALSE
4044
);
4145

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

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

79+
if ($NoCache -eq $FALSE) {
80+
# If we are not skipping the cache, we will update the cache
81+
# with the current counter path. This will ensure that we
82+
# have a valid cache for the counter and can return it later
83+
Update-IcingaPerformanceCounterCache -Counter $Counter;
84+
}
85+
7586
# Now as we know how the counter path is constructed and has been split into
7687
# the different values, we need to know how to handle the instances of the counter
7788

@@ -80,11 +91,13 @@ function New-IcingaPerformanceCounter()
8091
# which contains the parent name including counters for all instances that
8192
# have been found
8293
if ($UseCounterInstance -eq '*') {
83-
# In case we already loaded the counters once, return the finished array
84-
$CachedCounter = Get-IcingaPerformanceCounterCacheItem -Counter $Counter;
94+
if ($NoCache -eq $FALSE) {
95+
# In case we already loaded the counters once, return the finished array
96+
$CachedCounter = Get-IcingaPerformanceCounterCacheItem -Counter $Counter;
8597

86-
if ($null -ne $CachedCounter) {
87-
return (New-IcingaPerformanceCounterResult -FullName $Counter -PerformanceCounters $CachedCounter);
98+
if ($null -ne $CachedCounter) {
99+
return (New-IcingaPerformanceCounterResult -FullName $Counter -PerformanceCounters $CachedCounter);
100+
}
88101
}
89102

90103
# If we need to build the array, load all instances from the counters and
@@ -116,24 +129,32 @@ function New-IcingaPerformanceCounter()
116129
# Add the parent counter including the array of Performance Counters to our
117130
# caching mechanism and return the New-IcingaPerformanceCounterResult object for usage
118131
# within the monitoring modules
119-
Add-IcingaPerformanceCounterCache -Counter $Counter -Instances $AllCountersInstances;
132+
if ($NoCache -eq $FALSE) {
133+
Add-IcingaPerformanceCounterCache -Counter $Counter -Instances $AllCountersInstances;
134+
}
120135
return (New-IcingaPerformanceCounterResult -FullName $Counter -PerformanceCounters $AllCountersInstances);
121136
} else {
122137
# This part will handle the counters without any instances as well as
123138
# specifically assigned instances, like (_Total) CPU usage.
124139

125140
# In case we already have the counter within our cache, return the
126141
# cached informations
127-
$CachedCounter = Get-IcingaPerformanceCounterCacheItem -Counter $Counter;
142+
if ($NoCache -eq $FALSE) {
143+
$CachedCounter = Get-IcingaPerformanceCounterCacheItem -Counter $Counter;
128144

129-
if ($null -ne $CachedCounter) {
130-
return $CachedCounter;
145+
if ($null -ne $CachedCounter) {
146+
return $CachedCounter;
147+
}
131148
}
132149

133150
# If the cache is not present yet, create the Performance Counter object,
134151
# and add it to our cache
135152
$NewCounter = New-IcingaPerformanceCounterObject -FullName $Counter -Category $UseCounterCategory -Counter $UseCounterName -Instance $UseCounterInstance -SkipWait $SkipWait;
136-
Add-IcingaPerformanceCounterCache -Counter $Counter -Instances $NewCounter;
153+
if ($NoCache -eq $FALSE) {
154+
Add-IcingaPerformanceCounterCache -Counter $Counter -Instances $NewCounter;
155+
} else {
156+
return $NewCounter;
157+
}
137158
}
138159

139160
# This function will always return non-instance counters or

lib/core/perfcounter/New-IcingaPerformanceCounterArray.psm1

Lines changed: 0 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -40,26 +40,13 @@ function New-IcingaPerformanceCounterArray()
4040
# NumOfCounters * 500 milliseconds for the first runs. This will speed
4141
# up the general loading of counters and will not require some fancy
4242
# pre-caching / configuration handler
43-
$CachedCounter = Get-IcingaPerformanceCounterCacheItem -Counter $Counter;
44-
45-
# Remove this for now to ensure our CPU metrics will not be cached
46-
# and represent correct values, not exceeding 200% and beyond
47-
#if ($null -ne $CachedCounter) {
48-
# $RequireSleep = $FALSE;
49-
#}
5043

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

57-
# TODO: Add a cache for our Performance Counters to only fetch them once
58-
# for each session to speed up the loading. This cold be something like
59-
# this:
60-
#
61-
# $Global:Icinga.Private.PerformanceCounter.Cache += $CounterResult;
62-
6350
# Above we initialise ever single counter and we only require a sleep once
6451
# in case a new, yet unknown counter was added
6552
if ($RequireSleep) {

lib/core/perfcounter/Show-IcingaPerformanceCounterInstances.psm1

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ function Show-IcingaPerformanceCounterInstances()
3535
return;
3636
}
3737

38-
$PerfCounter = New-IcingaPerformanceCounter -Counter $Counter -SkipWait $TRUE;
38+
$PerfCounter = New-IcingaPerformanceCounter -Counter $Counter -SkipWait $TRUE -NoCache;
3939

4040
foreach ($entry in $PerfCounter.Counters) {
4141
$Instances.Add(
Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
<#
2+
.SYNOPSIS
3+
Updates the cached instances of a specified performance counter in the Icinga PowerShell Framework.
4+
5+
.DESCRIPTION
6+
The Update-IcingaPerformanceCounterCache function synchronizes the cached instances of a given performance counter.
7+
It removes instances that no longer exist and adds new instances that are not yet cached.
8+
This ensures that the cache accurately reflects the current state of the performance counter instances.
9+
10+
.PARAMETER Counter
11+
The name of the performance counter whose cache should be updated.
12+
13+
.EXAMPLE
14+
Update-IcingaPerformanceCounterCache -Counter "\Processor(_Total)\% Processor Time"
15+
16+
Updates the cache for the specified performance counter.
17+
18+
.NOTES
19+
This function is intended for internal use within the Icinga PowerShell Framework.
20+
It requires that the global cache variable and related functions are available.
21+
22+
#>
23+
function Update-IcingaPerformanceCounterCache()
24+
{
25+
param (
26+
$Counter
27+
);
28+
29+
if ([string]::IsNullOrEmpty($Counter)) {
30+
return;
31+
}
32+
33+
if ($Global:Icinga.Private.PerformanceCounter.Cache.ContainsKey($Counter) -eq $FALSE) {
34+
# If there is no cache entry for the provided counter, we don't need to do anything yet
35+
return;
36+
}
37+
38+
# First we need to prepare some data by fetching the current instances of the counter
39+
# and the cached instances. We will then compare them and update the cache accordingly
40+
[array]$CounterInstances = Show-IcingaPerformanceCounterInstances -Counter $Counter;
41+
[array]$CachedInstances = $Global:Icinga.Private.PerformanceCounter.Cache[$Counter];
42+
[array]$UpdatedInstances = @();
43+
[array]$CachedInstanceNames = $CachedInstances.FullName;
44+
45+
# We will now iterate over the cached instances and check if they are still present in the current
46+
# counter instances. If they are not, we will remove them from the cache.
47+
# If they are present, we will keep them in the updated instances array.
48+
for ($index = 0; $index -lt $CachedInstances.Count; $index++) {
49+
$cachedInstance = $CachedInstances[$index];
50+
$instanceName = $cachedInstance.FullName;
51+
52+
# If the instance is not in the current list, we remove it
53+
if ($CounterInstances.Value -contains $instanceName) {
54+
$UpdatedInstances += $cachedInstance;
55+
}
56+
}
57+
58+
# Now we will iterate over the current counter instances and check if they are already cached.
59+
# If they are not, we will add them to the updated instances array.
60+
# This ensures that we only add new instances that are not already cached.
61+
for ($index = 0; $index -lt $CounterInstances.Count; $index++) {
62+
$instanceName = $CounterInstances[$index].Value;
63+
64+
if ($CachedInstanceNames -notcontains $instanceName) {
65+
# If the instance is not cached, we create a new performance counter object
66+
# and add it to the updated instances array
67+
$UpdatedInstances += (New-IcingaPerformanceCounter -Counter $instanceName -SkipWait $TRUE -NoCache);
68+
}
69+
}
70+
71+
# Finally, we update the cache with the new instances
72+
# This will ensure that the cache is up-to-date with the current state of the performance
73+
# counter instances
74+
$Global:Icinga.Private.PerformanceCounter.Cache[$Counter] = $UpdatedInstances;
75+
}

0 commit comments

Comments
 (0)