Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

error getting probe properties #374

Open
kbilsted opened this issue Dec 20, 2023 · 12 comments
Open

error getting probe properties #374

kbilsted opened this issue Dec 20, 2023 · 12 comments
Labels
bug Issues that have been confirmed to be bugs in PrtgAPI and will be fixed in a future version

Comments

@kbilsted
Copy link

Describe the bug

using the api for the first time i can get probe information, but an exception is raised when getting properties

Steps to reproduce

using PrtgAPI;
using PrtgAPI.Parameters;


var user = "prtg-creator";
var password = "prtg";
var client = new PrtgClient("https://prtg.acme-corp.net/",user, password, AuthMode.Password,false);
Sensor[] sensors = client.QuerySensors(s=>s.Name.ToLower().Contains("myservice")).ToArray();

Console.WriteLine($"found {sensors.Length} sensors");
foreach (var sensor in sensors)
{
    Console.WriteLine($"{sensor.Name}\n active: {sensor.Active}\n type: {sensor.Type}\n tags: {string.Join(", ",sensor.Tags)}");
    var props =client.GetProbeProperties(sensor.Id);
    Console.WriteLine(props);
};

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

System.Xml.XmlException
  HResult=0x80131940
  Message='=' is an unexpected token. The expected token is ';'. Line 1, position 298.
  Source=System.Private.Xml
  StackTrace:
   at System.Xml.XmlTextReaderImpl.Throw(Exception e)
   at System.Xml.XmlTextReaderImpl.Throw(String res, String[] args)
   at System.Xml.XmlTextReaderImpl.ThrowUnexpectedToken(String expectedToken1, String expectedToken2)
   at System.Xml.XmlTextReaderImpl.ThrowUnexpectedToken(Int32 pos, String expectedToken1, String expectedToken2)
   at System.Xml.XmlTextReaderImpl.HandleEntityReference(Boolean isInAttributeValue, EntityExpandType expandType, Int32& charRefEndPos)
   at System.Xml.XmlTextReaderImpl.ParseText(Int32& startPos, Int32& endPos, Int32& outOrChars)
   at System.Xml.XmlTextReaderImpl.FinishPartialValue()
   at System.Xml.XmlTextReaderImpl.get_Value()
   at System.Xml.Linq.XContainer.ContentReader.ReadContentFrom(XContainer rootContainer, XmlReader r)
   at System.Xml.Linq.XContainer.ReadContentFrom(XmlReader r)
   at System.Xml.Linq.XContainer.ReadContentFrom(XmlReader r, LoadOptions o)
   at System.Xml.Linq.XDocument.Load(XmlReader reader, LoadOptions options)
   at PrtgAPI.Request.RequestEngine.ValidateHttpResponse(HttpResponseMessage responseMessage, PrtgResponse response)
   at PrtgAPI.Request.RequestEngine.ExecuteRequest(PrtgRequestMessage request, CancellationToken token, Func`2 responseParser)
   at PrtgAPI.PrtgClient.GetObjectProperties[T](Either`2 objectOrId, ObjectType objectType, ObjectProperty mandatoryProperty)
   at PrtgAPI.PrtgClient.GetProbeProperties(Either`2 probe)
   at Program.<Main>$(String[] args) in C:\git\tools\prtg creator\xx\Program.cs:line 17



cannot easily find the raw xml that it has error parsing

Additional context

No response

@kbilsted kbilsted added the alleged-bug Bugs raised by people helpfully using the Bug Report template! label Dec 20, 2023
@lordmilko
Copy link
Owner

lordmilko commented Dec 20, 2023

Hi @kbilsted,

Just prior to calling GetProbeProperties, can you follow the steps listed in Troubleshooting as follows

client.LogLevel = LogLevel.Request | LogLevel.Response;

client.LogVerbose (sender, args) => {
    Console.WriteLine(args.Message);
};

and then provide the resulting XML output. Please check there is no sensitive information in the output prior to posting

@kbilsted
Copy link
Author

I get the following output

Synchronously executing request https://xxxx.net/controls/objectdata.htm?id=15362&objecttype=probenode&username=yyyyy&passhash=22222222
<div class="errormsg"><p>PRTG Network Monitor has discovered a problem. Your last request could not be processed properly.</p>
<h3>Error message: The selected object cannot be used here.</h3>
<small style="padding:5px;text-align:left">
URL: /controls/objectdata.htm<br>
Parameters: id=15362&objecttype=probenode&username=yyyyy&passhash=***&</small></div>

not sure it really helps me much. The problem im trying to solve is to figure out what is the url used in my http probe and how can i change this url from your api-library. I figured since the information was not available in the Sensor I had to dig into other data structures after the information.

Not sure if it is relevant, but alternatively to logging, you can add data to exceptions by changing

throw new PrtgRequestException("PRTG was unable to complete the request. The server responded with the following error: " + str.EnsurePeriod());

to

var ex = new PrtgRequestException("PRTG was unable to complete the request. The server responded with the following error: " + str.EnsurePeriod());
ex.Data.Add("response", response);
throw ex;

@lordmilko
Copy link
Owner

Ah, I see the issue!

var props =client.GetProbeProperties(sensor.Id);

You are attempting to retrieve the probe properties of a sensor

To retrieve sensor properties you must use GetSensorProperties

Additionally, if the property you want isn't defined on the object emitted from GetSensorProperties, you can use GetObjectPropertiesRaw to view all properties that exist (albeit in a non type safe manor)

@lordmilko
Copy link
Owner

Also, I can't believe I never tested this before, but I don't think my IQueryable provider supports doing ToLower like this

Sensor[] sensors = client.QuerySensors(s=>s.Name.ToLower().Contains("myservice")).ToArray();

From a quick test I think this will result in pulling all sensors from the server, and then filtering client side. On this basis it might be best to retrieve sensors normally

//The Contains operator is case insensitive
client.GetSensors(Property.Name, FilterOperator.Contains, "myservice");

@kbilsted
Copy link
Author

Ah, I see the issue!

var props =client.GetProbeProperties(sensor.Id);

You are attempting to retrieve the probe properties of a sensor

To retrieve sensor properties you must use GetSensorProperties

Additionally, if the property you want isn't defined on the object emitted from GetSensorProperties, you can use GetObjectPropertiesRaw to view all properties that exist (albeit in a non type safe manor)

OMG! What a silly mistake! Sorry for wasting your time on that. hmm.. oh!.. this was just a test to see the rigor of your error handling... :-)

I am not sure it makes sense, but why do we not first fetch the object and check the type to see that it is compatible with the operation we are doing? If it takes too much time, perhaps an extra parameter can be added turning this behaviour on/off. or maybe do it in some introduced exception handling.

@kbilsted
Copy link
Author

Also, I can't believe I never tested this before, but I don't think my IQueryable provider supports doing ToLower like this

Sensor[] sensors = client.QuerySensors(s=>s.Name.ToLower().Contains("myservice")).ToArray();

From a quick test I think this will result in pulling all sensors from the server, and then filtering client side. On this basis it might be best to retrieve sensors normally

//The Contains operator is case insensitive
client.GetSensors(Property.Name, FilterOperator.Contains, "myservice");

Many thanks, i believe you are correct, the query takes a very long time!

Can the filter-operations you suggest be specified as case insensitive? We have a mix of manually created probes over the last decade, so you will find all sorts of mess in there.

@lordmilko lordmilko added bug Issues that have been confirmed to be bugs in PrtgAPI and will be fixed in a future version and removed alleged-bug Bugs raised by people helpfully using the Bug Report template! labels Dec 21, 2023
@lordmilko
Copy link
Owner

If GetProbeProperties first had to do GetProbe on the ID you passed in to verify whether or not it's actually a probe, this would double the number of API requests that need to be performed for this one operation and decrease performance. If you pass the wrong type of object in, PRTG will spit out an error message (albeit one that doesn't explain the issue as PrtgAPI might)

<div class="errormsg"><p>PRTG Network Monitor has discovered a problem. Your last request could not be processed properly.</p>
<h3>Error message: The selected object cannot be used here.</h3>

In this case, this failed because there is a bug in PrtgAPI's parsing of this error message. If PrtgAPI had been able to parse this message properly, it would have been a lot easier to see the reason that your call to GetProbeProperties was failing

@lordmilko
Copy link
Owner

Can the filter-operations you suggest be specified as case insensitive? We have a mix of manually created probes over the last decade, so you will find all sorts of mess in there.

My experience is that when exactly one filter is specified, FilterOperator.Equals is case insensitive. However, if two filters are specified, PRTG treats Equals as case sensitive. This is not very reliable, so as a workaround you can use FilterOperator.Contains which is always treated as case insensitive. This is how PrtgAPI's PowerShell cmdlets handle applying filters. The downside to this however is that if you're after myservice (case insensitive), a Contains filter will also give you myservice1

@kbilsted
Copy link
Author

If GetProbeProperties first had to do GetProbe on the ID you passed in to verify whether or not it's actually a probe, this would double the number of API requests that need to be performed for this one operation and decrease performance. If you pass the wrong type of object in, PRTG will spit out an error message (albeit one that doesn't explain the issue as PrtgAPI might)

<div class="errormsg"><p>PRTG Network Monitor has discovered a problem. Your last request could not be processed properly.</p>
<h3>Error message: The selected object cannot be used here.</h3>

In this case, this failed because there is a bug in PrtgAPI's parsing of this error message. If PrtgAPI had been able to parse this message properly, it would have been a lot easier to see the reason that your call to GetProbeProperties was failing

Hi Milko

Yes the tradeof is twice the number of requests. Perhaps that is a very low overhead? Perhaps it is ok when exceptions are thrown? Perhaps a simple error text telling the user to double check the types manually.

btw I keep writing probe when i mean sensor. :-)

@kbilsted
Copy link
Author

Extracting all of our sensors i get more deserialization errors.

PrtgAPI.XmlDeserializationException
HResult=0x80131500
Message=Could not deserialize value '2' as it is not a valid member of type 'PrtgAPI.GraphType'. Could not process XML '<injected_stack>2</injected_stack>'.
Source=PrtgAPI
StackTrace:
at PrtgAPI.Linq.Expressions.Serialization.XmlExpressionSerializerBase.FailEnum(String s, Type type) in PrtgAPI.Linq.Expressions.Serialization\XmlExpressionSerializerBase.cs:line 119
at PrtgAPI.Request.ResponseParser.GetObjectProperties[T](PrtgResponse response, XmlEngine xmlEngine, ObjectProperty mandatoryProperty) in PrtgAPI.Request\ResponseParser.cs:line 287
at PrtgAPI.PrtgClient.GetObjectProperties[T](Either2 objectOrId, ObjectType objectType, ObjectProperty mandatoryProperty) in PrtgAPI\PrtgClient.cs:line 723 at PrtgAPI.PrtgClient.GetSensorProperties(Either2 sensor) in PrtgAPI\PrtgClient.cs:line 3909
at Program.

$(String[] args) in C:\xxx.prtg alarm xxx\xxx.yyy\Program.cs:line 31

var sensors = client.GetSensors();

Console.WriteLine($"found {sensors.Count} sensors");

Console.WriteLine("name;active;type;tags;url");
foreach (var sensor in sensors)
{
    var props =client.GetSensorProperties(sensor.Id);

    Console.WriteLine($"{sensor.Name};{sensor.Active};{sensor.Type};{string.Join("+",sensor.Tags)};{props.Url}");

    Console.WriteLine(props.Url);
};

the log file does not contain <injected_stack> anythere...

@lordmilko
Copy link
Owner

It sounds like PRTG has added a new GraphType that is not known to PrtgAPI.

You can work around this for now by doing GetObjectPropertiesRaw instead of GetSensorProperties. This will give you a dictionary of raw values and bypass any enum values that are unknown to PrtgAPI

@kbilsted
Copy link
Author

Are you interested in a data dump so the parser can be extended to support the new types?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Issues that have been confirmed to be bugs in PrtgAPI and will be fixed in a future version
Projects
None yet
Development

No branches or pull requests

2 participants