lordmilko / PrtgAPI

C#/PowerShell interface for PRTG Network Monitor
MIT License
301 stars 37 forks source link

High memory usage after script #258

Closed noaboa97 closed 2 years ago

noaboa97 commented 2 years ago

Describe the bug

After running a script containing Set-ChannelProperty or Set-ObjectProperty there is very high memory usage and the server needs a reboot to recover from that. Is that a memory leak caused by PRTG API or PrtgAPI?

Steps to reproduce

$sensors = get-sensor -Tag wmidiskspacesensor

foreach($sensor in $sensors) {

    $sensor

    $properties = $sensor | get-objectproperty -Raw

    if($properties.limitpercent -eq 0){

        $sensor | Set-ObjectProperty -RawProperty limitpercent_ -RawValue 1 -Force
        $sensor | Set-ObjectProperty -RawProperty lowerlimitwarningpct_ -RawValue 5 -force
        $sensor | Set-ObjectProperty -RawProperty lowerlimiterrorpct_ -RawValue 3 -Force

    }else{

    Write-Host "$($sensor.id) Already applied"

    }

}

--------------------------------------------OR-------------------------------------
$allchannels = get-sensor -tags wmiuptimesensor | get-channel

$i = 1
foreach($channel in $channels){

    $channel
    $i

    #Error
    $ChannelValueSetting = "UpperErrorLimit"
    $ChannelMessageSetting = "ErrorLimitMessage"
    $LimitMessage = ""
    $Value = $null

    if($channel.LimitsEnabled){

        $channel | Set-ChannelProperty $ChannelMessageSetting $LimitMessage

        $channel = get-channel -SensorId $channel.SensorId

        $channel | Set-ChannelProperty $ChannelValueSetting $Value

    }

    #Warning
    $ChannelValueSetting = "UpperWarningLimit"
    $ChannelMessageSetting = "WarningLimitMessage"
    $Value = 15552000
    $LimitMessage = "Server has not been restartet for 180 days. Please take the necessary steps to restart the server."
    $channel = get-channel -SensorId $channel.SensorId
    $channel | Set-ChannelProperty $ChannelValueSetting $Value
    $channel = get-channel -SensorId $channel.SensorId
    $channel | Set-ChannelProperty $ChannelMessageSetting $LimitMessage

    start-sleep 5
    $i++

    $memory = (get-sensor -Id 1001 | get-channel -id 3).LastValue
    if($memory -lt 5624745984){

        Write-host "Memory less than 5 GB waiting 5 min"
        Start-Sleep 300

    }

}

What is the output of 'Get-PrtgClient -Diagnostic'?

PSVersion      : 5.1.19041.1320
PSEdition      : Desktop
OS             : Microsoft Windows 10 Enterprise
PrtgAPIVersion : 0.9.13
Culture        : de-CH
CLRVersion     : 528372
PrtgVersion    : 21.3.71.1416
PrtgLanguage   : english.lng

Additional context

For me it happens after about 100-200 sensors.

Both Servers have 32 GB RAM and usually using about 7-8 GB. We have a quite large environment with two core servers. Server 1 -> 12'000 Sensors Server 2 -> 6'000 Sensors

First I thought maybe the requests are to fast and it will write it to memory before to disk. But the memory usage didn't go down after a few days so I rebooted.

Also not using the newest PRTG Version. We gotta update.

EDIT Just did some more tests. If I run the script and let the memory almost fill up. Stop the script and reboot. All changes are gone because they are saved in the memory. I guess it will process them but the memory doesn't go down and we don't really now when they are applied.

lordmilko commented 2 years ago

Hi @noaboa97,

As noted in #253, #202, and #198, my perspective on this issue is that this is an issue with PRTG, rather than PrtgAPI. As mentioned in #253, Paessler recently alerted me to a secret setting that can potentially be included in Set-ObjectProperty / Set-ChannelProperty API requests that should help with memory usage; these changes will be present in the next release of PrtgAPI. Never-the-less, there's no guarantee that this will actually help in all scenarios, and it is still ultimately PRTG's responsibility to deal with its memory appropriately whether you call its API endpoints "correctly" or not.

Case in point /editsettings API endpoint is not a "public API"; the public API for modifying object properties is /api/setobjectproperty.htm. However the public API for modifying object properties doesn't support all properties and can't modify multiple properties at once. So it is no surprise you have forum posts from Paessler's own employees telling people to use the "internal" API, despite the fact evidently anyone who tries to use that API call en masse will potentially cause a huge memory leak. Woops! Hence, this is an issue with PRTG, and Paessler needs to update it to deal with the scenario of people invoking API calls "they're not supposed to" (which is clearly not an uncommon occurrence even ignoring PrtgAPI). IMO it is highly unlikely Paessler will properly fix these sorts of issues given they're working on APIv2, but I guess you never know.

In any case, please see the linked posts for some of my recommendations for managing memory issues in PRTG; also note that if you want to modify multiple raw properties on a given object, you can do them all in one go via a single API call with a set of -RawParameters rather than a single RawProperty/ RawValue

Regards, lordmilko

noaboa97 commented 2 years ago

-RawParameters works good and also feel like the memory isn't hit to hard. Can Set-ChannelProperty also accept multiple parameters.

lordmilko commented 2 years ago

Hi @noaboa97,

You can specify multiple parameters to Set-ChannelProperty as follows

$sensor | Set-ChannelProperty -UpperErrorLimit 10 -LowerErrorLimit 5

If the parameters that should be specified are dynamic, you can instead splat the parameters instead

# Suppose you have some variable or some object property or whatever that stores the name(s) of the parameter(s)
$p1 = "UpperErrorLimit"
$p2 = "LowerErrorLimit"

# Construct a hashtable assigning the appropriate value to each parameter (your values could even come from a variable or whatever as well)
$params = @{
    $p1 = 10
    $p2 = 5
}

# Splat it
$sensor | Set-ChannelProperty @params
noaboa97 commented 2 years ago

Hello @lordmilko

Thank you specifying multiple parameters worked fine for me. And Memory isn't filling up as fast.

Splatting it didn't work for me.

no matter what I tried I got the following error:

Set-ChannelProperty : Der Parameter "Property" kann nicht gebunden werden. Objekt vom Typ "PrtgAPI.ChannelProperty. Die ErrorLimitMessage- Eigenschaft wurde für das PrtgAPI.ChannelProperty-Objekt nicht gefunden. Die verfügbare 
Eigenschaft lautet: [value__ <System.Int32>]" kann nicht erstellt werden.
In Zeile:6 Zeichen:39
+         $sensor | Set-ChannelProperty $params
+                                       ~~~~~~~
    + CategoryInfo          : InvalidArgument: (:) [Set-ChannelProperty], ParameterBindingException
    + FullyQualifiedErrorId : CannotConvertArgumentNoMessage,PrtgAPI.PowerShell.Cmdlets.SetChannelProperty
lordmilko commented 2 years ago

Hi @noaboa97,

You are not splatting correctly

$sensor | Set-ChannelProperty $params

Splatting is done with the @ character.

$sensor | Set-ChannelProperty @params

For more information about splatting please see the following article

Regards, lordmilko

noaboa97 commented 2 years ago

Oops my bad. Thanks.