XML-RPC Instrumentation API - Technical Reference

Intended Audience

This document describes how Geneos API can be used to create customised views, or write to streams that may be read any plug-in that supports streams (File Keyword Monitoring (FKM), Trapmon, API Stream, TIB-RV Stream, Windows Event Queue).

Following a general overview, there are two tutorial sections - one on writing an API client in C++ and the other in Java. There is then a description of how to set up streams and how to use the additional NetProbe and Gateway functions. A full technical reference of the API function calls is provided in the "API Technical Reference" section.

API custom views allow system operators and managers to see management data published from in-house applications regardless of the programming language used for those applications. This extends the value of the Geneos Enterprise Management Framework into the areas where no 'off-the-shelf' plug-ins are available.

API Streams may be used to output log files through the Geneos Framework so that events may be triggered when specific keywords are encountered.

The API functionality is separately licensable. Please contact ITRS Sales for details.

Using the API

Topology

The Instrumentation API allows an external process to create views and publish data in real-time through the Geneos Enterprise Management Framework. This is achieved by running API and/or API-STREAMS plug-ins on the NetProbe. The API plug-ins act as an XML-RPC server and can handle connections from multiple clients.

xml_rpc_api_image2

Communication Model

Geneos API clients communicate with the API plug-ins using the industry standard, well defined XML-RPC protocol over TCP/IP. This is a light weight protocol using HTTP or HTTPS as the transport and XML as the encoding. XML-RPC is designed to be as simple as possible, while allowing complex data structures to be transmitted, processed and returned. It is similar to SOAP but is much easier to implement. Since TCP/IP is used, clients may operate on the same host as the NetProbe, giving maximum performance, or remotely, giving maximum flexibility. XML-RPC clients should connect to the NetProbe on the same port as the Gateway connects. The API plug-in acts as an XML-RPC server.

If the Netprobe is running in secure mode, then the XML-RPC client needs to use HTTPS as a transport protocol rather than HTTP. More details about secure communications in Geneos can be found in the 'Geneos Secure Communications' guide.

There are a number of libraries available to aid the production of an XML-RPC compliant program. These are available for numerous languages including C, C++, Java, PERL, .NET and many more. This means that the ability to publish views can be added to existing software systems with minimal effort.

It is also possible to make function calls without using any third-party libraries as long as the XML‑RPC specification is followed. This would involve creating a socket connection to the remote host, writing the relevant HTTP header and XML payload, and reading off the results. This method may be desirable if the use of external libraries is not practical or if greater control is required.

For information on XML-RPC see http://xmlrpc.scripting.com/spec.html. It is important to understand that in the XML-RPC specification only upper and lower-case alphanumeric characters, underscore, dot, colon and slash are accepted in method names.

XML-RPC traffic is neither encrypted or authenticated. If this is important in your environment you may wish to consider employing the IPSec protocol to secure connections between machines.

Making Function Calls

Function calls are performed on a particular plug-in with a period (.) separating the Managed Entity name, the plug-in name and the function name. To create a view in a sampler called mySampler on Managed Entity myManEnt, the following function would be called:

myManEnt.mySampler.createView

Once a view is created (e.g called myView in group myGroup), function calls may be performed on it in the same way:

myManEnt.mySampler.myGroupmyView.addHeadline

For cases where a sampler is placed inside a type (e.g. Managed Entity myManEnt has a Type myType, which then contains a Sampler mySampler), then the Type name may be included in the function call:

myManEnt.mySampler(myType).createView

This is useful for instances where the same Sampler is used for two or more Types under the same Managed Entity.

The complete list of function calls available is defined in the technical reference at the end of this document.

Return Values and Error Handling

All functions return a value. If the function has no specific return value it will return the text string "OK" to indicate that it was executed successfully.

If an error occurred during the execution of the function then an error code and description will be returned. All error codes are named in this document, for example NO_SUCH_VIEW, and it is highly recommended that these are statically defined in external code to aid readability.

When new configuration is received from the gateway, a probe will restart all the plug-ins that it is running. This means that all views will be lost and will need to be recreated. It is therefore particularly important that clients are able to recognise the NO_SUCH_SAMPLER and NO_SUCH_VIEW errors and respond accordingly.

Session Keep-Alive

The HTTP protocol allows pipelining of requests using the Connection: Keep-Alive header. If this is included in the request or response then, if both sides are able, the TCP connection will be kept open. This makes multiple requests more efficient as there is no overhead from creating and destroying the connection. The Geneos XML-RPC server will keep the connection open wherever possible. The XmlRpc++ and org.apache.xmlrpc libraries that are used in the tutorials below respect this Keep-Alive request. If the specification has been implemented without the aid of a library, it is strongly recommended that Keep-Alive requests be honoured.

C++ Client Tutorial

Introduction

The following sections provide concrete examples of how to construct custom views using the Geneos API in C++. The example view will show a set of dataviews for a particular component of a custom developed system and will look like this:

xml_rpc_api_image3

Although it is possible to write an API client without using any supporting libraries, it is easier to use an XML-RPC library. Here we will give examples of how to write a simple API client in C++ using the XmlRpc++ library.

The following are the implementation steps:

  • Write API client in C++.
  • Link with XML-RPC++ library.
  • Create API plug-in using the Gateway setup.
  • Run the API client.

Note: The XML-RPC C++ is written in 2003 and is compiled on gcc-3. It is recommended to use a compatible compiler with gcc and install the following packages, such as compat-gcc-34-3.4.6-46.fc28.x86_64.rpm and compat-gcc-34-c++-3.4.6-46.fc28.x86_64.rpm.

Writing a C++ Client

The XmlRpc++ library defines several classes that make it easy to call functions on an XML-RPC server. This step-by-step example shows how to use these classes and is followed by the complete working program and an explanation of how to get started.

XmlRpcClient c(server, port, "/xmlrpc");

This defines a client called c that will connect to server on port and use the URI /xmlrpc to handle the requests. Server should be a char* and port should be an int.

XmlRpcValue parameters;
XmlRpcValue result;

These define variables that can be used to pass parameters to and collect the result from a function call. All values are represented as XmlRpcValues. The [] operator has been overloaded to provide arrays of XmlRpcValues and structures of XmlRpcValues. Several cast operators have also been overloaded to provide easy conversions.

parameters[0] = "queues";
parameters[1] = "myGroup";

This defines the first parameter as the text string "queues" and the second parameter as "myGroup".

if (c.execute("myManEnt.mySampler.createView", parameters, result))
std::cout << "Result: " << result << "\n";

The execute function takes three parameters. The first two define the remote function to call and the parameters to pass to the remote function. The function returns true if it was possible to execute the method remotely, false if there was a problem connecting to the remote host. If the execute function returns true then the third (result) parameter will be populated with the remote function's return value and this can then be output to the screen or processed as necessary.

The above code creates the queues view in the mySampler plug-in. It will be listed under the group heading "myGroup".

parameters[0] = "totalQueues";
if (c.execute("myManEnt.mySampler.myGroup-queues.addHeadline", parameters, result))
if (c.isFault())
if ((int)result["faultCode"] == NO_SUCH_SAMPLER)
std::cout << "NO_SUCH_SAMPLER\n";

Even if the remote call executes successfully, result may in fact be an error. This can be checked for by calling the isFault() function on the XmlRpcClient object. If isFault() returns true then result will be a structure with a faultCode and a faultString. The faultCode element can be cast into an int for comparison.

The above code adds the totalQueues headline variable to the view. It outputs the text "NO_SUCH_SAMPLER" if that error occurred.

XmlRpcValue table;
table[0][0] = "queueName";
table[0][1] = "currentSize";
table[0][2] = "maxSize";
table[0][3] = "currentUtilisation";
table[0][4] = "status";
table[1][0] = "queue1";
table[1][1] = 332;
table[1][2] = 30000;
table[1][3] = 0.11;
table[1][4] = "online";
...
parameters[0] = table;
c.execute("myManEnt.mySampler.myGroup-queues.updateEntireTable", parameters, result);

Creating the entire table in one go is done by defining the rows and columns in an array that is passed as a parameter.

Note: It is necessary to add the line parameters[0] = table; rather than passing the table directly. Otherwise four parameters will be passed to the function (the headers and three rows), and the function expects a single parameter containing the table.

parameters[0] = "totalQueues";
parameters[1] = 3;
c.execute("myManEnt.mySampler.myGroup-queues.updateHeadline", parameters, result);
parameters[0] = "queue2.currentUtilisation";
parameters[1] = 25;
c.execute("myManEnt.mySampler.myGroup-queues.updateTableCell", parameters, result);

Once the table has been created, values may be updated individually by using the updateHeadline or updateTableCell functions. Alternatively the whole table may be sent again. The method chosen is up to the developer and will depend on the frequency of updates and percentage of the table that changes each time.

When the entire table is sent, the API plug-in will calculate the changes and will only sent the updates required to the Geneos Framework.

Complete C++ Client Listing

The example program below combines all of the above to create a simple plug-in.

#include "XmlRpc.h"
#include <iostream>
#include <unistd.h>								
#define NO_SUCH_SAMPLER 202
using namespace XmlRpc;
int main(int argc, char* argv[])
{
if (argc != 3)
{
std::cerr << "Usage: QueueSamplerClient serverHost serverPort\n";
return -1;
}
int port = atoi(argv[2]);
//XmlRpc::setVerbosity(5);
											
XmlRpcClient c(argv[1], port, "/xmlrpc");
XmlRpcValue parameters;
XmlRpcValue result;

parameters[0] = "queues";
parameters[1] = "myGroup";
if (c.execute("myManEnt.mySampler.createView", parameters, result))
std::cout << "Result: " << result << "\n\n";

parameters.clear();

parameters[0] = "totalQueues";
if (c.execute("myManEnt.mySampler.myGroup-queues.addHeadline", parameters, result))
if (c.isFault())
if ((int)result["faultCode"] == NO_SUCH_SAMPLER)
std::cout << "NO_SUCH_SAMPLER\n";

parameters[0] = "queuesOffline";
if (c.execute("myManEnt.mySampler.myGroup-queues.addHeadline", parameters, result))
if (!c.isFault()) std::cout << "Result: " << result << "\n\n";

XmlRpcValue table;
table[0][0] = "queueName";
table[0][1] = "currentSize";
table[0][2] = "maxSize";
table[0][3] = "currentUtilisation";
table[0][4] = "status";
table[1][0] = "queue1";
table[1][1] = 332;
table[1][2] = 30000;
table[1][3] = "0.11";
table[1][4] = "online";
table[2][0] = "queue2";
table[2][1] = 0;
table[2][2] = 90000;
table[2][3] = "0";
table[2][4] = "offline";
table[3][0] = "queue3";
table[3][1] = 7331;
table[3][2] = 45000;
table[3][3] = "0.16";
table[3][4] = "online";

parameters[0] = table;
c.execute("myManEnt.mySampler.myGroup-queues.updateEntireTable", parameters, result);

parameters[0] = "totalQueues";
parameters[1] = 3;										
c.execute("myManEnt.mySampler.myGroup-queues.updateHeadline", parameters, result);

parameters[0] = "queuesOffline";
parameters[1] = 1; 
c.execute("myManEnt.mySampler.myGroup-queues.updateHeadline", parameters, result);

bool bSendTestData = true; // set to false to switch this part off
if (bSendTestData)
{
parameters[0] = "queue2.currentSize";
for (int ix = 0; ix < 1000; ix++)
{
parameters[1] = ix;
c.execute("myManEnt.mySampler.myGroup-queues.updateTableCell", parameters, result);
sleep(1);
if (c.isFault()) break;
}
}

return 0;
}

Linking with the XML-RPC++ Library

To use XmlRpc++, the library should be downloaded from the SourceForge project page (http://sourceforge.net/projects/xmlrpcpp) and extracted to a suitable place. This should create an xmlrpc++x.x directory (where x.x is the version number) and within this directory a src and a test directory.

In order to compile the above code, it should be in a file named QueueSamplerClient.cpp in the test directory. The test/Makefile should be altered as follows:

TESTS = <as before> QueueSamplerClient

cd to the xmlrpc++x.x directory and then run:

make

Creating an API Plug-In

An API plug-in should be created in the same way as any other plug-in, by defining it in the gateway configuration as in the following example:

xml_rpc_api_image4

Figure 1 Basic Sampler Setup

xml_rpc_api_image5

Figure 2 Basic Managed Entity Setup

When the Netprobe is started or restarted, no views will initially be visible in Active Console since views are created by the external process. Once the view has been created, it will be empty until calls have been made to addTableColumn, addTableRow or updateEntireTable.

Running the API Client

Run the API client by passing it the name of the NetProbe host and the port number that NetProbe is listening on.

test/QueueSamplerClient hostname port

Open the ManagedEntity in ActiveConsole. Select the queues view. The value for queue2.currentSize should be increasing from 0 to 999.

The view will remain visible in ActiveConsole until the NetProbe restarts or the NetProbe configuration changes.

Java Client Tutorial

Introduction

The following sections provide concrete examples of how to construct custom views using the Geneos API in Java. The example view will show a set of dataviews for a particular component of a custom developed system and will look like this:

xml_rpc_api_image6

Although it is possible to write an API client without using any supporting libraries, it is easier to use an XML-RPC library. Here we will give examples of how to write a simple API client in Java using the org.apache.xmlrpc library. This example has been tested against version 3.1.2.

The following are the implementation steps:

  • Write API client in Java
  • Link with org.apache.xmlrpc library
  • Create API plug-in using the Gateway setup
  • Run the API client

Writing a Java Client

The Apache XML-RPC library for Java defines several classes to make it easy to call function on an XML-RPC server. Standard Java classes are used to represent data and Exceptions are thrown to represent errors. This step-by-step example shows how to use this library and is followed by the complete working program and an explanation of how to get started.

Insecure Netprobe

XmlRpcClientConfigImpl config = new XmlRpcClientConfigImpl();
config.setServerURL(new URL("http://server:port/xmlrpc"));
XmlRpcClient c = new XmlRpcClient();
c.setConfig(config);

Secured Netprobe

XmlRpcClientConfigImpl config = new XmlRpcClientConfigImpl();
config.setServerURL(new URL("https://server:port/xmlrpc"));
XmlRpcClient c = new XmlRpcClient();
c.setConfig(config);

// Create a trust manager that does not validate certificate chains
TrustManager[] trustAllCerts = new TrustManager[] { new X509TrustManager() {
public X509Certificate[] getAcceptedIssuers() {
return null;
}

public void checkClientTrusted(X509Certificate[] certs, String authType) {
// Trust always
}

public void checkServerTrusted(X509Certificate[] certs, String authType) {										
// Trust always
}
} };

// Install the all-trusting trust manager
SSLContext sc = SSLContext.getInstance("SSL");
// Create empty HostnameVerifier
HostnameVerifier hv = new HostnameVerifier() {
public boolean verify(String arg0, SSLSession arg1) {
return true;
}
};

sc.init(null, trustAllCerts, new java.security.SecureRandom());
HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory());
HttpsURLConnection.setDefaultHostnameVerifier(hv);

This defines a client called c that will connect to server on port and use the URI /xmlrpc to handle the requests.

Vector parameters = new Vector();
String result = null;

The parameters to functions should be defined in a Vector. The return value from functions is an Object, but all the functions in this example will return a String. This will be explored further in a moment.

parameters.addElement("jqueues");
parameters.addElement("myGroup");

Strings can be added to the Vector in the standard way to form the parameters.

result = (String)c.execute("myManEnt.mySampler.createView", parameters);
System.out.println(result);

The execute function takes two parameters. The first is a String naming the function to call, the second is a Vector of parameters. Each parameter may be a String or a Vector. The return type is Object so that either a String or a Vector may be returned. It is cast into a String here as we know that we will be expecting a String. If a function returns a Vector then a ClassCastException will be thrown. If the return type is not known the instanceof operator can be used.

The above code creates the jqueues view in the mySampler plug-in. It will be listed under the group heading "myGroup".

parameters.removeElementAt(1);
parameters.setElementAt("totalQueues", 0);
try
{
c.execute("myManEnt.mySampler.myGroup-jqueues.addHeadline", parameters);
}
catch (XmlRpcException e)
{
if (e.code == NO_SUCH_SAMPLER)
System.out.println("NO_SUCH_SAMPLER");
}

If the remote function returns an error then the execute method will throw an XmlRpcException. The error number is in a field called code and the error string is in the standard message for all Throwable objects and can be retrieved with e.getMessage().

The above code adds the totalQueues headline variable to the view. It outputs the text "NO_SUCH_SAMPLER" if that error occurred.

String[][] strTable =
{
{"queueName","currentSize","maxSize","currentUtilisation","status"},
{"queue1","332","30000","0.11","online"},
{"queue2","0","90000","0","offline"},
{"queue3","7331","45000","0.16","online"}
};
Vector table = new Vector();
for (int ix = 0; ix < strTable.length; ix++)
table.addElement(new Vector(Arrays.asList(strTable[ix])));

parameters.setElementAt(table, 0);
c.execute("myManEnt.mySampler.myGroup-jqueues.updateEntireTable", parameters);	

An entire table may be created with a Vector of Vectors forming the rows and columns. The above code shows one way of creating the table. It is necessary to set the first parameter to be the table rather than passing the table directly to the function. Otherwise four parameters will be passed to the function (the headlines and three rows) instead of one parameter containing the table.

parameters.setElementAt("totalQueues", 0); // Headline variable name
parameters.addElement("3"); // New value for the headline
c.execute("myManEnt.mySampler.myGroup-jqueues.updateHeadline", parameters);
parameters.setElementAt("queue2.currentUtilisation", 0); // TableCell variable name
parameters.setElementAt("25", 1); // New value for the TableCell
c.execute("myManEnt.mySampler.myGroup-jqueues.updateTableCell", parameters);

Once the table has been created, values may be updated individually by using the updateHeadline or updateTableCell functions. Alternatively the whole table may be sent again. The method chosen is up to the developer and will depend on the frequency of updates and percentage of the table that changes each time.

When the entire table is sent, the API plug-in will calculate the changes and will only sent the updates required to the Geneos Framework.

Complete Java Client Listing

The example program overleaf combines all of the above to create a simple plug-in.


import java.util.Vector;
import java.util.Arrays;										
import java.net.URL;											
import org.apache.xmlrpc.XmlRpcException;											
import org.apache.xmlrpc.client.XmlRpcClient;											
import org.apache.xmlrpc.client.XmlRpcClientConfigImpl;

public class QueueSamplerClient{											
public static void main(String[] args) throws Exception{											
if (args.length != 2){											
System.err.println("Usage: QueueSamplerClient serverHost serverPort");											
System.exit(1);											
}
if (args.length != 2)	{											
System.err.println("Usage: QueueSamplerClient serverHost serverPort");											
System.exit(1);
}
XmlRpcClientConfigImpl config = new XmlRpcClientConfigImpl();											
config.setServerURL(new URL("http://"+args[0]+":"+args[1]+"/xmlrpc"));											
XmlRpcClient c = new XmlRpcClient();											
c.setConfig(config);
Vector parameters = new Vector();											
String result = null;
parameters.addElement("jqueues");											
parameters.addElement("myGroup");											
result = (String)c.execute("myManEnt.mySampler.createView", parameters);											
System.out.println(result);
parameters.removeElementAt(1);										
parameters.setElementAt("totalQueues", 0);											
try{											
c.execute("myManEnt.mySampler.myGroup-jqueues.addHeadline", parameters);											
}											
catch (XmlRpcException e){											
if (e.code == NO_SUCH_SAMPLER)											
System.out.println("NO_SUCH_SAMPLER");											
}
parameters.setElementAt("queuesOffline", 0);											
c.execute("myManEnt.mySampler.myGroup-jqueues.addHeadline", parameters);
String[][] strTable ={										
{"queueName","currentSize","maxSize","currentUtilisation","status"},										
{"queue1","332","30000","0.11","online"},											
{"queue2","0","90000","0","offline"},											
{"queue3","7331","45000","0.16","online"}											
};											
Vector table = new Vector();											
for (int ix = 0; ix < strTable.length; ix++)											
table.addElement(new Vector(Arrays.asList(strTable[ix])));
parameters.setElementAt(table, 0);											
c.execute("myManEnt.mySampler.myGroup-jqueues.updateEntireTable", parameters);
parameters.setElementAt("totalQueues", 0);										
parameters.addElement("3");										
c.execute("myManEnt.mySampler.myGroup-jqueues.updateHeadline", parameters);
parameters.setElementAt("queuesOffline", 0);										
parameters.setElementAt("1", 1);											
c.execute("myManEnt.mySampler.myGroup-jqueues.updateHeadline", parameters);
boolean bSendTestData = true; // set to false to switch this part off											
if (bSendTestData){										
parameters.setElementAt("queue2.currentSize", 0);											
for (int ix = 0; ix < 1000; ix++){										
parameters.setElementAt(""+ix, 1);										
c.execute("myManEnt.mySampler.myGroup-jqueues.updateTableCell", parameters);										
Thread.sleep(1000);										
}											
}
}											
private static final int NO_SUCH_SAMPLER = 202;											
}

Linking with the Apache XMLRPC Library

To use the org.apache.xmlrpc classes, the library should be downloaded by following the links from http://ws.apache.org/xmlrpc/download.html and extracted to a suitable place. The classes are pre-compiled into a jar file if the non-src version is downloaded.

On extraction, an apache‑xmlrpc-x.x.x directory will have been created, and the lib directory within it will contain a number of jar files (where x.x.x is the version number).

In order to compile this code, it should be in a file named QueueSamplerClient.java in the same directory as the jar files.

Go to the xmlrpc-x.x.x/lib directory and then run the following OS-dependent command, remembering to substitute the version numbers of the library being used.

On Windows:

javac -classpath ".;xmlrpc-client-x.x.x.jar;xmlrpc-common-x.x.x.jar" QueueSamplerClient.java

Or , on UNIX-based systems:

javac -classpath ".:xmlrpc-client-x.x.x.jar:xmlrpc-common-x.x.x.jar" QueueSamplerClient.java

Creating an API Plug-In

An API plug-in should be created in the same way as any other plug-in, by defining it in the gateway configuration as in the following example:

xml_rpc_api_image7

Figure 3 Basic Sampler Setup

xml_rpc_api_image8

Figure 4 Basic Managed Entity Setup

When the NetProbe is started or restarted, no views will initially be visible in ActiveConsole since views are created by the external process. Once the view has been created, it will be empty until calls have been made to addTableColumn, addTableRow or updateEntireTable.

Run the API Client

Run the API client by passing it the name of the NetProbe host and the port number that NetProbe is listening on, remembering to substitute the version numbers of the library being used.

On Windows:

java -classpath ".;xmlrpc-client-x.x.x.jar;xmlrpc-common-x.x.x.jar;ws-commons-util-x.x.x.jar" QueueSamplerClient hostname port

Or, on UNIX-based systems:

java -classpath ".:xmlrpc-client-x.x.x.jar:xmlrpc-common-x.x.x.jar:ws-commons-util-x.x.x.jar" QueueSamplerClient hostname port

Note: The ws-commons-util version will likely be different to the other two jar files.

Open the ManagedEntity in ActiveConsole.

Select the jqueues view. The value for queue2.currentSize should be increasing from 0 to 999.

The view will remain visible in ActiveConsole until the NetProbe restarts or the NetProbe configuration changes.

API Streams

Introduction

API Streams may be used to send logs from external processes through the File Keyword Monitoring plug-in, which then allows rules to be set on it. The API-STREAMS plug-in is separate from the API plug-in, but function calls are made in the same way, through XML-RPC.

Creating an API Streams Plug-In

An API Streams plug-in should be created in the same way as any other plug-in, by defining it in the gateway configuration as in the following example:

xml_rpc_api_image9

Figure 5 Basic API- Streams Sampler Setup

xml_rpc_api_image10

Figure 6 Basic Managed Entity Setup

The streams should be named in the sampler descriptor using the STREAMS sampler parameter as shown above. These names will be used to refer to the streams in the sampler (example with FKM is below).

Each stream uses a buffer to hold the messages between the time the API client writes to the stream and the time the sampler reads from the stream. It may optionally be set using the "Buffer size" sampler parameter (See API-Streams Configuration: bufferSize). This buffer refers to the number of messages that may be stored. The default buffer is 1000 messages. If the buffer becomes full then the API client will receive a STREAM_BUFFER_FULL error. From this point until the sampler reads some messages from the stream, each line that is added to the buffer will force the oldest unread message to be dropped from the buffer. When the sampler next reads from the stream, it will get an additional message indicating how many messages have been lost.

Sampler debug view

The "Create view" sampler parameter may be used to switch on the debug view (See API-Streams Configuration: createView).

xml_rpc_api_image11

Headline Legend

Name Description
totalStreams The total number of streams configured.

Table Legend

Name Description
name The stream name.
currentBufferSize Number of messages that are waiting to be read by at least one sampler.
maxBufferSize The capacity of the buffer, as set by the bufferSize setting.
totalMessagesReceived The total number of messages received on the stream, whether read or not.
totalMessagesLost The number of messages that have been lost by at least one sampler.
heartbeatRate The total number in seconds that the client needs to provide a heartbeat. The value is 0 when heartbeat is not set.
status The status of stream. Displays "OK" when no problem and "FAILED: No heartbeat from client" when no heartbeat or update is received.

Because more than one sampler may be configured to read from the stream and each sampler has its own reading position in the buffer, the currentBufferSize and totalMessagesLost columns reflect the state of the slowest sampler.

Configuring FKM to Read from Streams

For FKM to read API streams, each stream name must be added to the FKM file list as follows:

xml_rpc_api_image12

The stream names in the FKM configuration are entered in the form:

<Managed Entity Name>.<API Stream Sampler Name>.<Stream>

If the FKM sampler and the API stream sampler are part of the same managed entity, then the managed entity section of this name can be omitted, along with the dot separator which follows it.

Normal FKM tables, aliases and groups may be specified.

As with other streams, once the lines have been read by FKM they are no longer available. This means that continuous view is available but snapshot view is not. The fileSize column is also not applicable since there is no physical file on disc.

For setting up rules and tables, please refer to the FKM plug-in document. With FKM set up on the above streams, the view will look like this:

xml_rpc_api_image13

Using the API to Write to Streams

Calls to the streams may be made in exactly the same way as with the standard API.

parameters[0] = "This is a line to be sent through a stream";
if (c.execute("myManEnt.myStreamsSampler.a.addMessage", parameters, result))
std::cout << "Result: " << result << "\n";

This will append the log message to the stream called 'a' in the plug-in called 'myStreamsSampler'.

Additional Functionality

Beyond the basic creation of views or streams, additional methods exist that help with the creation of custom plug-ins.

Additional methods also exist that are not bound to any particular API or API-Streams plug-ins. These methods use the keywords _netprobe and _gateway instead of a Managed Entity name. You should not define managed entities with these special names.

Heartbeats

It is sometimes necessary to be alerted when no updates are received for a particular Sampler, as this can be an indication that an external process has stopped functioning.

Clients may call the signOn method to commit to providing updates for a Sampler. The maximum number of seconds between updates is specified as a parameter. This may be between 1 second and 86400 seconds (24 hours) inclusive.

The samplingStatus is shown in ActiveConsole at the bottom of each view created by the API. It is initially set to "OK" and will remain that way if no clients have signed on. If a client has signed on and subsequently stops providing updates then the samplingStatus of each view belonging to that Sampler will display "FAILED: No heartbeat from the client in the last xx seconds", where xx is the number of seconds since the last update. If this is above 60 seconds then the time will be given in minutes. If an update is then received then the sampling status will be returned to "OK".

For example:

parameters[0] = 120;
if (c.execute("myManEnt.mySampler.signOn", parameters, result))
std::cout << "Result: " << result << "\n";

would commit this sampler to providing updates every 120 seconds. At any point from then on, if the last method call to the Sampler was received over 2 minutes ago then the samplingStatus will be set to FAILED.

If a client is signed on but does not wish to update any values for a long period of time then they may instead send a heartbeat by calling the heatbeat method on the Sampler.

When a client no longer wishes to commit to providing updates, it may call the signOff method. If it wishes to change the time it has committed to, it may call the signOn method again without having to sign off first.

Calling signOff or heartbeat when not signed on will return "OK" but will have no effect on the view.

NetProbe Function Calls

Checking Whether a Managed Entity Exists

It is possible to interrogate the NetProbe to determine whether a particular Managed Entity exists containing any API samplers. This is done as follows:

parameters[0] = "myManEnt";
if (c.execute("_netprobe.managedEntityExists", parameters, result))
std::cout << "Result: " << result << "\n";

Unlike most of the API calls, this method returns a boolean value.

Checking Whether a Sampler Exists

It is possible to interrogate the NetProbe to determine whether a particular API sampler exists. This can be done with the following call:

parameters[0] = "myManEnt.mySampler";
if (c.execute("_netprobe.samplerExists", parameters, result))
std::cout << "Result: " << result << "\n";

Unlike most of the API calls, this method returns a boolean value.

Gateway Function Calls

Function calls starting _gateway will be passed to the gateway for processing. These function calls will return "OK" if the command was successfully passed to the gateway and will return the error GATEWAY_NOT_CONNECTED if there is no Gatway currently connected. No other information is available to the API.

Expect View

Heartbeats can be used to detect an application stopping after it has created API views, but if an application has never started then there will be no views present to set rules on. Expect view functionality addresses this problem by being able to specify views that you expect to be created.

The name the name of the view and the group heading should be specified in the Expect Views section of the plugin setup. Any number of Expect Views can be specified. See API Plug-In Configuration.

Summary View

The summary view can be used for detecting missing views by setting a rule on the totalViews headline e.g. you may expect 10 view to be created but total views only shows 8. The summary view also shows the last time any command was sent to the sampler and to each view, this is to detect processes that are no longer sending information to the netprobe.

Security

Restricting Access to the API

It is possible to prevent access to the API from hosts that are not trusted. To do this, TRUSTED_API_HOSTS should be set to a comma-separated list of hosts and/or IP addresses that are trusted. This can be set as an environment variable or in the managed entity descriptor. Any API method calls from non-trusted hosts will return immediately with the HOST_NOT_TRUSTED error. The first time this occurs from any given host, a message will be written to the NetProbe log file.

Plugin Technical Reference

Configuration for API plugin is minimal. Most of the work is performed by the program that sends data to the probe via the API. The configuration that can be set is listed below;

expectViews

This parameter specifies a list of views that are expected to be created. These views will be created by the probe even if there has been no requests to create these views sent by the feeding application. There can be any number of these views. (See section Expect View)

Mandatory: No

expectViews > expectView

This parameter specifies an individual view that you expect to be created. The view definition is composed of both a name and a group.

Mandatory: No

expectViews > expectView > view

Specifies the name of a view that you expect to be created.

Mandatory: Yes (if an Expect View has been specified)

expectViews > expectView > group

Specifies the group to which to add view that you expect to be created.

Mandatory: Yes (if an Expect View has been specified)

expectViewDelay

This specifies the amount of time (in seconds) to wait after starting the sampler before creating expected views that have not been created by the feeding application.

Mandatory: No
Default: 0 s

parameters

This provides a list of name value pairs that are stored in the probe and can be queried by the feeding application using the "entity.sampler.getParameter" API call. (See Section API Technical Reference)

Mandatory: No

parameters > parameter

This specifies an individual parameter that is stored in the probe. The parameter is composed of a name and a value.

Mandatory: No

showSummaryView

The summary view reports on all views that have been published by api processes. This view displays:

Headlines: total views (published by all api processes to this sampler) and heartbeat rate

Rows: Name of the view (published by an api process), last time that view was updated and duration in seconds since the last update.

Rules can be set on the total views to detect when all the required views have not been created or duration since last update to detect views that have "frozen" i.e. no more updates are being received.

The summary view can either be displayed all the time or never. The default for the summary view is never.

Mandatory: No

showSummaryView > always > viewName

This specifies the name for the summary view.

Mandatory: No
Default: Sampler name

API-STREAMS Plug-In Configuration

Configuration for API-STREAMS plugin is minimal. Most of the work is performed by the program that sends data to the probe via the API. The configuration that can be set is listed below;

streams

This parameter specifies a list of streams that should be created. These can be written to by the feeding application. (See Using the API to Write to Streams)

Mandatory: Yes

bufferSize

This parameter specifies the maximum number of items to hold in memory at a time. If the sampler is not configured to read the stream often enough for the data rate then this parameter may need to be increased, otherwise the feeding application will not be able to write to the stream.

Mandatory: No
Default: 1000

createView

This parameter specifies whether a debug view should be created that shows how many messages are passing through each stream and how many messages have been dropped.

Mandatory: No
Default: false

API Technical Reference

API Function Calls

entity.sampler.createView

string entity.sampler.createView(string viewName, string groupHeading)

Creates a new, empty view in the specified sampler under the specified groupHeading. This view will appear in Active Console once it has been created, even if no information has been added to it. For historic reasons, the groupHeading must not be the same as the viewName.

Parameters
viewName - The name of the view to be created.
groupHeading - The group heading to use.
Returns
"OK" on successful completion.
Errors
GATEWAY_NOT_CONNECTED, NO_SUCH_SAMPLER, VIEW_EXISTS, VIEW_AND_GROUP_EQUAL

entity.sampler.viewExists

boolean entity.sampler.viewExists(string groupHeading-viewName)

Checks whether a particular view exists in this sampler. viewName should be in the form group-view. This method is useful if no updates are needed in a long period of time, to check whether the NetProbe has restarted. If this were the case then the sampler would exist, but the view would not.

Parameters
groupHeading-viewName - The name of the group heading and the view name concatenated with "-". (e.g."groupHeading-viewName").
Returns
true if the view exists, false otherwise.
Errors
GATEWAY_NOT_CONNECTED, NO_SUCH_SAMPLER

entity.sampler.removeView

string entity.sampler.removeView(string viewName, string groupHeading)

Removes a view that has been created with createView.

Note: This cannot be used if a Gateway1 is connected.

Parameters
viewName - The name of the view.
groupHeading - The group heading.
Returns
"OK" on successful completion.
Errors
GATEWAY_NOT_CONNECTED, GATEWAY_NOT_SUPPORTED, NO_SUCH_SAMPLER, NO_SUCH_VIEW

entity.sampler.getParameter

string entity.sampler.getParameter(string parameterName)

Retrieves the value of a sampler parameter that has been defined in the gateway configuration.

For example:

[mysampler_SAMPLER_DESCRIPTOR]
PLUGIN = API
INFO = Some text

allows the call sampler.getParameter("INFO") to retrieve the text "Some text". If the sampler is not defined in the gateway configuration then an error will be returned.

Parameters
parameterName - The name of the parameter to be retrieved.
Returns
The parameter text written in the gateway configuration.
Errors
GATEWAY_NOT_CONNECTED, NO_SUCH_SAMPLER, SAMPLER_PARAM_NOT_FOUND

entity.sampler.view.addTableRow

string entity.sampler.view.addTableRow(string rowName)

Adds a new, blank table row to the specified view. The name of each row must be unique to that table. An attempt to create two rows with the same name will result in an error.

Parameters
rowName - The name of the row to be created.
Returns
"OK" on successful completion.
Errors
GATEWAY_NOT_CONNECTED, NO_SUCH_SAMPLER, NO_SUCH_VIEW, ROW_EXISTS

entity.sampler.view.removeTableRow

string entity.sampler.view.removeTableRow(string rowName)

Removes an existing row from the specified view.

Parameters
rowName - The name of the row to be removed.
Returns
"OK" on successful completion.
Errors
GATEWAY_NOT_CONNECTED, NO_SUCH_SAMPLER, NO_SUCH_VIEW, NO_SUCH_ROW

entity.sampler.view.addHeadline

string entity.sampler.view.addHeadline(string headlineName)

Adds a headline variable to the view.

Parameters
headlineName - The name of the headline to be created.
Returns
"OK" on successful completion.
Errors
GATEWAY_NOT_CONNECTED, NO_SUCH_SAMPLER, NO_SUCH_VIEW, HEADLINE_EXISTS

entity.sampler.view.removeHeadline

string entity.sampler.view.removeHeadline(string headlineName)

Removes a headline variable from the view.

Note: This cannot be used if a Gateway1 is connected.

Parameters
headlineName - The name of the headline to be removed.
Returns
"OK" on successful completion.
Errors
GATEWAY_NOT_CONNECTED, GATEWAY_NOT_SUPPORTED, NO_SUCH_SAMPLER, NO_SUCH_VIEW, NO_SUCH_HEADLINE

entity.sampler.view.updateVariable

string entity.sampler.view.updateVariable(string variableName, stringnewValue)

Can be used to update either a headline variable or a table cell. If the variable name contains a period (.) then a cell is assumed, otherwise a headline variable is assumed.

Parameters
variableName - The name of the variable to be updated.
newValue - The new value it should take.
Returns
"OK" on successful completion.
Errors
GATEWAY_NOT_CONNECTED, NO_SUCH_SAMPLER, NO_SUCH_VIEW, NO_SUCH_CELL, NO_SUCH_HEADLINE

entity.sampler.view.updateHeadline

string entity.sampler.view.updateHeadline(string headlineName, string newValue)

Updates a headline variable. This performs the same action as updateVariable, but is fractionally faster as it is not necessary to determine the variable type.

Parameters
headlineName - The name of the headline to be updated.
newValue - The new value it should take.
Returns
"OK" on successful completion.
Errors
GATEWAY_NOT_CONNECTED, NO_SUCH_SAMPLER, NO_SUCH_VIEW, NO_SUCH_HEADLINE

entity.sampler.view.updateTableCell

string entity.sampler.view.updateTableCell(string cellName, string newValue)

Updates a single cell in a table. The standard row.column format should be used to reference a cell. This performs the same action as updateVariable, but is fractionally faster as it is not necessary to determine the variable type.

Parameters
cellName - The name of the cell to be updated.
newValue - The new value it should take.
Returns
"OK" on successful completion.
Errors
GATEWAY_NOT_CONNECTED, NO_SUCH_SAMPLER, NO_SUCH_VIEW, NO_SUCH_CELL

entity.sampler.view.updateTableRow

string entity.sampler.view.updateTableRow(string rowName, array newValue)

Updates an existing row from the specified view with the new values provided.

Parameters
rowName - The name of the row whose values are to be updated.
newValue - The new values.
Returns
"OK" on successful completion.
Errors
GATEWAY_NOT_CONNECTED, NO_SUCH_SAMPLER, NO_SUCH_VIEW, NO_SUCH_ROW

entity.sampler.view.addTableColumn

string entity.sampler.view.addTableColumn(string columnName)

Adds another column to the table. Each column must be unique.

Parameters
columnName - The name of the column to add.
Returns
"OK" on successful completion.
Errors
GATEWAY_NOT_CONNECTED, NO_SUCH_SAMPLER, NO_SUCH_VIEW, COLUMN_EXISTS

entity.sampler.view.updateEntireTable

string entity.sampler.view.updateEntireTable(array newTable)

Updates the entire table for a given view. This is useful if the entire table will change at once or the table is being created for the first time. The array passed should be two dimensional. The first row should be the column headings and the first column of each subsequent row should be the name of the row. The array should be at least 2 columns by 2 rows. Once table columns have been defined, they cannot be changed by this method.

Parameters
newTable - The table data.
Returns
"OK" on successful completion.
Errors
GATEWAY_NOT_CONNECTED, NO_SUCH_SAMPLER, NO_SUCH_VIEW, COLUMN_MISMATCH

entity.sampler.view.columnExists

boolean entity.sampler.columnExists(string columnName)

Check if the headline variable exists.

Parameters
columnName - The unique name of the row.
Returns
true if the column exists, false otherwise.
Errors
GATEWAY_NOT_CONNECTED, NO_SUCH_SAMPLER, NO_SUCH_VIEW

entity.sampler.view.rowExists

boolean entity.sampler.rowExists(string rowName)

Check if the headline variable exists.

Parameters
rowName - The unique name of the row.
Returns
true if the row exists, false otherwise.
Errors
GATEWAY_NOT_CONNECTED, NO_SUCH_SAMPLER, NO_SUCH_VIEW

entity.sampler.view.headlineExists

boolean entity.sampler.headlineExists(string headlineName)

Check if the headline variable exists.

Parameters
headlineName - The name of the headline variable.
Returns
true if the headline variable exists, false otherwise.
Errors
GATEWAY_NOT_CONNECTED, NO_SUCH_SAMPLER, NO_SUCH_VIEW

entity.sampler.view.getColumnCount

int entity.sampler.getColumnCount()

Return the column count of the view

Parameters
None
Returns
The number of columns in the view. This includes the rowName column.
Errors
GATEWAY_NOT_CONNECTED, NO_SUCH_SAMPLER, NO_SUCH_VIEW

entity.sampler.view.getRowCount

int entity.sampler.getRowCount()

Return the rowcount of the view.

Parameters
None
Returns
The number of rows in the view
Errors
GATEWAY_NOT_CONNECTED, NO_SUCH_SAMPLER, NO_SUCH_VIEW

entity.sampler.view.getHeadlineCount

int entity.sampler.getHeadlineCount()

Return the headline count of the view.

Parameters
None
Returns
The number of headlines in the view. This includes the samplingStatus headline.
Errors
GATEWAY_NOT_CONNECTED, NO_SUCH_SAMPLER, NO_SUCH_VIEW

entity.sampler.view.getColumnNames

array entity.sampler.getColumnNames()

Returns the names of existing columns

Parameters
None
Returns
The names of existing columns in the view. This includes the rowNames column name.
Errors
GATEWAY_NOT_CONNECTED, NO_SUCH_SAMPLER, NO_SUCH_VIEW

entity.sampler.view.getRowNames

array entity.sampler.getRowNames()

Returns the names of existing rows

Parameters
None
Returns
the names of existing rows in the view
Errors
GATEWAY_NOT_CONNECTED, NO_SUCH_SAMPLER, NO_SUCH_VIEW

entity.sampler.view.getHeadlineNames

array entity.sampler.getHeadlineNames()

Returns the names of existing headlines

Parameters
None
Returns
the names of existing headlines in the view. This includes the samplingStatus headline.
Errors
GATEWAY_NOT_CONNECTED, NO_SUCH_SAMPLER, NO_SUCH_VIEW

entity.sampler.view.getRowNamesOlderThan

array entity.sampler.view.getRowNamesOlderThan(string time)

Returns the names of rows whose update time is older than the time provided.

Parameters
time - The timestamp against which to compare row update time. The timestamp should be provided as Unix timestamp, i.e. number of seconds elapsed since UNIX epoch.
Returns
The names of rows whose update time is older than the time provided.
Errors
GATEWAY_NOT_CONNECTED, NO_SUCH_SAMPLER, NO_SUCH_VIEW

entity.sampler.signOn

string entity.sampler.signOn(int seconds)

Commits the API client to provide at least one heartbeat or update to the view within the time period specified. seconds should be at least 1 and no more than 86400 (24 hours). signOn may be called again to change the time period without the need to sign off first.

Parameters
seconds - The maximum time between updates before samplingStatus becomes FAILED.
Returns
"OK" on successful completion.
Errors
GATEWAY_NOT_CONNECTED, NO_SUCH_SAMPLER, NUMBER_OUT_OF_RANGE

entity.sampler.signOff

string entity.sampler.signOff()

Cancels the commitment to provide updates to a view. If this method is called when signOn has not been called then it has no effect.

Parameters
None.
Returns
"OK" on successful completion.
Errors
GATEWAY_NOT_CONNECTED, NO_SUCH_SAMPLER

entity.sampler.heartbeat

string entity.sampler.heartbeat()

Prevents the sampling status from becoming failed when no updates are needed to a view and the client is signed on. If this method is called when signOn has not been called then it has no effect.

Parameters
None.
Returns
"OK" on successful completion.
Errors
GATEWAY_NOT_CONNECTED, NO_SUCH_SAMPLER

API Streams Function Calls

entity.sampler.stream.addMessage

string entity.sampler.stream.addMessage(string message)

Adds a new message to the end of the stream.

Parameters
message - The line of text to be added to the stream.
Returns
"OK" on successful completion.
Errors
GATEWAY_NOT_CONNECTED, NO_SUCH_SAMPLER, NO_SUCH_STREAM, STREAM_BUFFER_FULL

entity.sampler.stream.signOn

string entity.sampler.stream.signOn(int seconds)

Commits the API-STREAM client to provide at least one heartbeat or update to the view within the time period specified. seconds should be at least 1 and no more than 86400 (24 hours). signOn may be called again to change the time period without the need to sign off first.

Parameters
seconds - The maximum time between updates before status becomes FAILED.
Returns
"OK" on successful completion.
Errors
GATEWAY_NOT_CONNECTED, NO_SUCH_SAMPLER, NUMBER_OUT_OF_RANGE

entity.sampler.stream.signOff

string entity.sampler.stream.signOff()

Cancels the commitment to provide updates to a view. If this method is called when signOn has not been called then it has no effect.

Parameters
None.
Returns
"OK" on successful completion.
Errors
GATEWAY_NOT_CONNECTED, NO_SUCH_SAMPLER

entity.sampler.stream.heartbeat

string entity.sampler.stream.heartbeat()

Prevents the status from becoming failed when no updates are needed to a view and the client is signed on. If this method is called when signOn has not been called then it has no effect.

Parameters
None.
Returns
"OK" on successful completion.
Errors
GATEWAY_NOT_CONNECTED, NO_SUCH_SAMPLER

NetProbe Function Calls

_netprobe.managedEntityExists

boolean _netprobe.managedEntityExists(string managedEntity)

Checks whether a particular Managed Entity exists on this NetProbe containing any API or API-Streams samplers.

Parameters
managedEntity - The name of the Managed Entity.
Returns
true if the Managed Entity exists, false otherwise.
Errors
No errors specific to this method.

_netprobe.samplerExists

boolean _netprobe.samplerExists(string sampler)

Checks whether a particular API or API-Streams sampler exists on this NetProbe.

Parameters
sampler - The name of the sampler.
Returns
true if the sampler exists, false otherwise.
Errors
No errors specific to this method.

_netprobe.gatewayConnected

boolean _netprobe.gatewayConnected()

Checks whether the Gateway is connected to this NetProbe.

Parameters
None.
Returns
true if the Gateway is connected, false otherwise.
Errors
No errors specific to this method.

Gateway Function Calls

_gateway.addManagedEntity

string _gateway.addManagedEntity(string managedEntity, string dataSection)

Adds the managed entity to the particular data section. The data section should be #include'd into the MANAGED_ENTITIES section of the gateway setup. As long as a Gatway is connected, this method will always return "OK". If the managed entity already exists, a warning will be seen in the Gateway log.

Parameters
managedEntity - The name of the Managed Entity to add.
dataSection - The data section to add the managed entity to.
Returns
"OK".
Errors
GATEWAY_NOT_CONNECTED

General Error Codes

Code Name Description
100 MISC_ERROR An error has occurred that has not been defined specifically.
101 NUMBER_OUT_OF_RANGE Either an invalid number was sent (e.g. text), or it is out of the range of numbers required by the function.
102 HOST_NOT_TRUSTED Your host is not allowed to make API calls (see the security section in this document).

Operational Error Codes

Code Name Description
200 NO_SUCH_METHOD An attempt has been made to call a method that has not been defined above.
201 WRONG_PARAM_COUNT The wrong number of parameters has been passed to the function.
202 NO_SUCH_SAMPLER An attempt has been made to call a method on a sampler that has not been created.
203 GATEWAY_NOT_CONNECTED An attempt has been made to pass a command to the Gateway, but no gateway is currently connected.
204 GATEWAY_NOT_SUPPORTED An unsupported Gateway is currently connected to the Netprobe. This will typically be issued for individual commands that do not work with Gateway1.

Sampler Error Codes

Code Name Description
300 SAMPLER_PARAM_NOT_FOUND A request has been made for a sampler parameter that has not been defined in the gateway setup.
301 VIEW_EXISTS An attempt has been made to create a view that already exists. Each view must have a unique name within the sampler.
302 NO_SUCH_VIEW An attempt has been made to call a method on a sampler view that has not been created.
303 NO_SUCH_STREAM An attempt has been made to call a method on a stream that has not been defined in the sampler descriptor.
304 VIEW_AND_GROUP_EQUAL When views are created, the view name must not be the same as the group heading.

View Error Codes

Code Name Description
400 NO_SUCH_CELL An attempt has been made to reference a cell that does not exist in this view.
401 ROW_EXISTS An attempt has been made to add a row that already exists. Each row must have a unique name.
402 COLUMN_EXISTS An attempt has been made to create a column that already exists.
403 NO_SUCH_HEADLINE An attempt has been made to update a headline that has not been created.
404 HEADLINE_EXISTS An attempt has been made to add a headline that already exists. Each headline must have a unique name.
405 NO_SUCH_ROW An attempt has been made to reference or remove a row that doesn't exist.
406 NO_SUCH_COLUMN An attempt has been made to reference a column that doesn't exist.
407 COLUMN_MISMATCH An attempt was made to change the number/names of columns with the updateEntireTable method.

XML-RPC Error Codes

Code Name Description
500 NO_XML_SENT A header was sent but no XML was included with the request.

Stream Error Codes

Code Name Description
600 STREAM_BUFFER_FULL The buffer for this stream is full so the message has not been appended to the stream. This is probably caused by the sampler not being set up on the stream or not reading data fast enough.