When getting channel values for a sensor where the channel has both a volume and speed value using the API, the output is ambiguous and problematic for programmatic usage.
When getting XML output, using /api/table.xml?content=channels&output=xml&columns=name,lastvalue,lastvalue_&id=<SENSORID>
, the output is as follows
<?xml version="1.0" encoding="UTF-8"?> <channels totalcount="0" listend="1"> <prtg-version>18.2.41.1652</prtg-version> <item> <name>Downtime</name> <lastvalue/> </item> <item> <name>Traffic In</name> <lastvalue>6,522 MByte</lastvalue> <lastvalue_raw>6838698632.0000</lastvalue_raw> <lastvalue>912 Mbit/s</lastvalue> <lastvalue_raw>113978310.5333</lastvalue_raw> </item> <item> <name>Traffic Out</name> <lastvalue>1,072 MByte</lastvalue> <lastvalue_raw>1123960141.0000</lastvalue_raw> <lastvalue>150 Mbit/s</lastvalue> <lastvalue_raw>18732669.0167</lastvalue_raw> </item> <item> <name>Traffic Total</name> <lastvalue>7,594 MByte</lastvalue> <lastvalue_raw>7962658773.0000</lastvalue_raw> <lastvalue>1,062 Mbit/s</lastvalue> <lastvalue_raw>132710979.5500</lastvalue_raw> </item> </channels>
The XML nodes are ambiguous, and except for string processing, there is no way of knowing which node is speed and which is volume.
Things get worse when pulling the data in JSON with /api/table.xml?content=channels&output=json&columns=name,lastvalue,lastvalue_&id=<SENSORID>
This is the output:
{ "prtg-version": "18.2.41.1652", "treesize": 0, "channels": [{ "name": "Downtime", "lastvalue": "", "lastvalue": "", "lastvalue_raw": "" }, { "name": "Traffic In", "lastvalue": "6,522 MByte", "lastvalue_raw": 6838698632.0000, "lastvalue": "912 Mbit/s", "lastvalue_raw": 113978310.5333 }, { "name": "Traffic Out", "lastvalue": "1,072 MByte", "lastvalue_raw": 1123960141.0000, "lastvalue": "150 Mbit/s", "lastvalue_raw": 18732669.0167 }, { "name": "Traffic Total", "lastvalue": "7,594 MByte", "lastvalue_raw": 7962658773.0000, "lastvalue": "1,062 Mbit/s", "lastvalue_raw": 132710979.5500 }] }
With JSON, having multiple keys in a hash with the same key value is frowned on (see this SO answer), and most parsing libraries will only use the last instance of the key.
Further, this ambiguous nature of the results combined with the fact that node/value order is not guaranteed by either XML specs or JSON specs, there is no way to ever know for sure which raw value is which in a programmatic way, effectively making those values useless for further processing.
Only CSV (/api/table.xml?content=channels&output=csvtable&columns=name,lastvalue_&id=<SENSORID>
) output will definitively mark the data point as either volume or speed, as shown below.
"Channel","Channel(RAW)","Last Value (volume)","Last Value (volume)(RAW)","Last Value (speed)","Last Value (speed)(RAW)" "Downtime","Downtime","","","","" "Traffic In","Traffic In","3,879 MByte","4067636651.0000","542 Mbit/s","67805245.0575" "Traffic Out","Traffic Out","1,026 MByte","1076308276.0000","144 Mbit/s","17941461.5103" "Traffic Total","Traffic Total","4,906 MByte","5143944927.0000","686 Mbit/s","85746706.5678"
I would like to avoid converting CSV into XML or JSON for further processing, especially if I need to the raw values. Am I missing something in the API docs on how to get around this (outside of using CSV), or does this need to go in as a bug fix/feature request?
Article Comments
I tried adding &usecaption=1
to the query string, but the resulting JSON was the same.
API call:
/api/table.json?content=channels&output=json&columns=name,lastvalue_&id=<SENSORID>&usecaption=1
Results:
{ "prtg-version": "18.2.41.1652", "treesize": 0, "channels": [{ "name": "Downtime", "lastvalue": "", "lastvalue": "" }, { "name": "Traffic In", "lastvalue": "2,148 MByte", "lastvalue": "300 Mbit/s" }, { "name": "Traffic Out", "lastvalue": "612 MByte", "lastvalue": "86 Mbit/s" }, { "name": "Traffic Total", "lastvalue": "2,760 MByte", "lastvalue": "386 Mbit/s" }] }
Aug, 2018 - Permalink
I believe "&usecaption=1" only applies to retrieving historic data.
My observation has been that it appears to be an implementation detail that the values are always ordered volume, then speed.
If you do
http://<server>/controls/table.htm?tableid=channeldisplaytable&content=channels&columns=lastvalue_&count=*&id=<id>&username=<username>&password=<password>
Replacing <server>, <id>, <username> and <password> respectively, you will get the "Last Value (volume)" and "Last Value (speed)" columns that are displayed on the normal sensor page. If you change the "lastvalue_" column to simply "lastvalue" you only get one column - the volume channel.
Based on that, I'm not sure Stephan whether you're able to confirm whether the handler controls/table.htm delegates to simply asserts that the second value must be the speed value?
Aug, 2018 - Permalink
I was able to recreate this, seemingly my JSON prettyprint plugin stripped the duplicates ô_Ô Lordmilko, consider it confirmed that the speed/volume sensors do it like that. So [0] is volume, [1] is speed. Even though it's invalid JSON :/ The next API iteration will hopefully not have quirks like that.
Kind regards,
Stephan Linke, Tech Support Team
Aug, 2018 - Permalink
When is this next API iteration coming? I want to make my own interface in html that will receive json and plug the data into google charts, but the duplicates and lack of labeling etc is making this a pain. For example, when I get (from a memory sensor):
{ "prtg-version":"18.4.45.1898", "treesize":0, "channels":[ { "name":"Available Memory", "lastvalue":"7,600 MByte", "lastvalue_raw":7969386496.0000, "lastvalue":"7,600 MByte", "lastvalue_raw":7969386496.0000 }, { "name":"Downtime", "lastvalue":"", "lastvalue":"" }, { "name":"Percent Available Memory", "lastvalue":"37 %", "lastvalue_raw":37.0000, "lastvalue":"37 %", "lastvalue_raw":37.0000 } ] }
Besides having the duplicate keys, you have to go through the array of channels to find the one you are looking for. Take advantage of JSON and use objects (even if you leave the name in the object), so it would be more like:
{ "prtg-version":"18.4.45.1898", "treesize":0, "channels":{ "Available Memory":{ "name":"Available Memory", "lastvalue":"7,600 MByte", "lastvalue_raw":7969386496.0000 }, "Downtime":{ "name":"Downtime", "lastvalue":"" }, "Percent Available Memory":{ "name":"Percent Available Memory", "lastvalue":"37 %", "lastvalue_raw":37.0000 } } }
So now if I were to look at the value of arrayName["channels"]["Percent Available Memory"]["lastvalue_raw"] it would equal 37.0000. Currently to get this, I would have to loop through the channels array, checking the name value for each item until it equaled "Percent Available Memory".
This means a lot more coding and resource usage.
Oct, 2018 - Permalink
@MicWit I'm afraid it's still quite off, no ETA yet :(
PRTG Scheduler |
PRTGapi |
Feature Requests |
WMI Issues |
SNMP Issues
Kind regards,
Stephan Linke, Tech Support Team
Oct, 2018 - Permalink
IIRC the JSON output requires &usecaption=1 in the call to also output those properties. JSON is often use internally and does not need those captions for the internal processing. Let me know if that did the trick :)
Kind regards,
Stephan Linke, Tech Support Team
Aug, 2018 - Permalink