Skip to content

Requests

lordmilko edited this page Jun 25, 2018 · 41 revisions

PrtgAPI supports four types of requests

Synchronous

Synchronous requests block the current thread until their results have returned

client.GetSensors();

Synchronous requests are ideal when writing a Console Application, or some other application where the PRTG processing has a thread to itself. Synchronous requests use an asynchronous HTTP Client internally, however return to synchronous methods as soon as the request has completed.

Batch

Certain operations allow you to operate against multiple Object IDs in a single request. When operating against a large number of items, this can provide a substantial performance improvement. Care should be taken when processing multiple operations in a single request, as there will be a much shorter time frame during which execution can be aborted in the event you have made a mistake.

# Pause the objects with IDs 1001, 1002 and 1003 forever
client.PauseObject(new[] {1001, 1002, 1003});

All State and Property Manipulation cmdlets as well as Rename-Object operate in batch mode by defaultThis can be overridden by specifying -Batch:$false

# Pause the sensors with IDs 1001, 1002 and 1003 forever, one at a time
Get-Sensor -Id 1001,1002,1003 | Pause-Object -Forever -Batch:$false

If Remove-Object is invoked with -Force and -Batch:$false has not otherwise been specified, Remove-Object will automatically enable batch mode to speed up the request. If Remove-Object is invoked without any parameters, PrtgAPI will prompt for confirmation and execute removal one by one.

PrtgAPI will process up to 1500 objects per request. If more than 1500 objects are detected, PrtgAPI will split the request into multiple batches (1501 objects = 2 requests, 3001 objects = 3 requests, etc)

PassThru

When piping commands together in PowerShell, it is sometimes desirable to perform multiple operations against a single source object (for example, unpausing an object and then refreshing it). While this can be achieved by executing multiple separate commands, it is also possible to perform multiple operations in a single command via the -PassThru parameter.

When -PassThru is specified, PrtgAPI will output the input object of a cmdlet for use in the next cmdlet in the pipeline.

# Resume and refresh all paused WMI CPU Load sensors
Get-Sensor -Tags wmicpu* -Status Paused | Resume-Object -PassThru | Refresh-Object

Objects are output from operation cmdlets as they are processed. As such, when operating in Batch Mode, objects will be output to the next cmdlet only after all input objects have been read.

Note that when executing in -PassThru mode, PrtgAPI always outputs the original object that was piped into the cmdlet. This is due to the fact that API requests are handled asynchronously by PRTG; as such, by the time a request has completed, there is no guarantee that the target object has updated by the time you try to re-retrieve it.

Asynchronous

Asynchronous requests are implemented using await/async. All internal async calls are configured with ConfigureAwait(false), and so are safe to use in Synchronization Contexts (such as WinForms and ASP.NET)

var sensors = await client.GetSensorsAsync();

Stream

Stream requests allow you to process data from PRTG as it is returned, instead of waiting for all of the data to come back at once. This is performed by splitting large requests up into several smaller requests and returning the responses to the caller in the order they come in.

When you call a Stream method, the method returns an IEnumerable<T> almost immediately. Only when the collection is enumerated are the requests sent to the server. If PrtgAPI detects that more than 20,000 objects will be returned from the request, PRTG will execute requests serially to prevent too many requests from queuing up and timing out. Otherwise, all of the requests will be executed all at once. Internally, the IEnumerable<T> is a generator that forces a collection of Task<> objects to yield their results. As a result of this, Stream requests block their calling threads when they wait for more data.

var sensors = client.StreamSensors();

foreach(var sensor in sensors)
{
    Console.WriteLine(sensor.Name);
}

If you wish to reduce the load on your PRTG Server, you may manually specify that PRTG should stream serially. Sensor, Device, Group and Probe method overloads that support filtering do not support serial streaming.

// Serial stream all sensors
var sensors = client.StreamSensors(true);

// Serial stream a custom request, sorting all devices by their Object IDs ascending
var parameters = new DeviceParameters
{
    SortBy = Property.Id
};

var devices = client.StreamDevices(parameters, true);

Stream requests are supported on the following object types

Query

Note: this feature is currently in development

PrtgAPI implements a custom LINQ Provider, allowing complex API requests to be defined as part of the language, rather than having to specify enum values and SearchFilter objects to request parameters.

//With queries
var sensors = client.QuerySensors(s => s.Name == "Ping" && s.Device == "dc-1");

//With parameters
var sensors = client.GetSensors(
    new SearchFilter(Property.Name, "Ping"),
    new SearchFilter(Property.Device, "dc-1")
);

PrtgAPI supports the execution of arbitrarily complex queries, regardless of whether or not these queries are supported by PRTG. For any operation not supported by PRTG, PrtgAPI will extract the maximal legal expression that can be executed, then apply the remaining expressions client side against the server's response.

As a result of this hybrid nature, it is important to understand you get what you ask for, and that a significant performance impact can occur when executing an ambiguous query

//Returns a different number of results based on whether the element that
//was skipped had an Id > 4000
var ambiguousResults = client.QuerySensors().Skip(1).Where(s => s.Id > 4000);

//Returns the same number of results every time
var unambiguousResults = client.QuerySensors().Where(s => s.Id > 4000).Skip(1);

If you are interested to learn more about how queries work, see Query

Strict

By default, PrtgAPI tries to give you what you want. It is extremely permissible with what it will accept in an expression; barring manual Expression tree construction, PrtgAPI will accept any IQueryable expression considered legal by the compiler. However, in order to achieve this freedom PrtgAPI will freely disregard parts of your expression if it determines they cannot be executed server side, instead opting to filter a broader set of results client side.

While this may offer a greater degree of flexibility when programming, this can come at the cost of performance (requesting potentially many more records than may be actually desired) when an expression is not well formed. If you are writing an extremely performance sensitive application and wish to be protected from yourself, this can be achieved by instructing PrtgAPI to use strict evaluation mode

//NotSupportedException: non-consecutive Where call
client.QuerySensors(true)
    .Where(s => s.Id > 4000)
    .Select(s => s.Name)
    .Where(n => n.Name.Contains("Disk")
    .ToList();

When using strict mode, unsupported query expressions must explicitly be marked as being executed client side. This can be achieved by chaining to Enumerable.AsEnumerable within your expression chain.

//Execute Where(1)/Select server side, Where(2) client side
client.QuerySensors(true)
    .Where(s => s.Id > 4000)
    .Select(s => s.Name)
    .AsEnumerable()
    .Where(n => n.Name.Contains("Disk")
    .ToList();

The following table outlines expressions that cannot be executed server side. In general, when constructing an expression, you can easily identify whether it will be valid by simply asking yourself: do you really think PRTG can evaluate that?

Expression Example
Unsupported LINQ methods .TakeWhile(s => s.Id < 4000)
Unconsecutive LINQ methods .Where(s => s.Id > 1).Select(s => s.Name).Where(n => n == "Ping")
Missing property expressions .Where(s => false && s.Name == "Ping")
Multiple property references .Where(s => s.Name == s.Message)
AND same property .Where(s => s.Name.Contains("Pi") && s.Name.Contains("ng"))
OR different properties .Where(s => s.Id == 4000 || s.Name == "Ping")
Unsupported expression type .Where(s => s.Tags.Length == 3)
Unsupported cast .Where(s => ((CustomType)s.Id) == 3000)
Unsupported method .Where(s => CheckId(s.Id))
Unsupported type ToString .Where(s => s.LastUp.ToString().Contains("2018"))
Clone this wiki locally