NAME
Geneos::API - Handy Perl interface to ITRS Geneos XML-RPC Instrumentation API
VERSION
Version 1.00
SYNOPSIS
use Geneos::API;
# open API to NetProbe running on host example.com and port 7036
my $api = Geneos::API->new("http://example.com:7036/xmlrpc");
# get the sampler "Residents" in the managed entity "Zoo"
my $sampler = $api->get_sampler("Zoo", "Residents");
# create view "Monkeys" in the group "Locals"
my $view = $sampler->create_view("Monkeys", "Locals");
# prepare some data
my $monkeys = [
["Name", "Type" ],
["Funky", "Red-tailed monkey"],
["Cheeky", "Tibetan macaque" ]
];
# populate the view
$view->update_entire_table($monkeys);
# get stream "News" on sampler "Channels" in the managed entity "Zoo"
my $stream = $api->get_sampler("Zoo","Channels")->get_stream("News");
# add a message to the stream
$stream->add_message("Funky beats Cheeky in a chess boxing match!");
DESCRIPTION
Geneos::API
is a Perl module that implements ITRS XML-RPC Instrumentation API. It can be used to create clients for both Geneos API and API Steams plug-ins. The plug-in acts as an XML-RPC server.
Geneos Samplers
, Data Views
and Streams
are represented by instances of Geneos::API::Sampler
, Geneos::API::Sampler::View
and Geneos::API::Sampler::Stream
classes. This provides easy to use building blocks for developing monitoring applications.
This module comes with its own XML-RPC module based on XML::LibXML as ITRS implementation of XML-RPC does not conform to the XML-RPC standard and therefore most of the available XML-RPC modules cannot be used. The client uses LWP::UserAgent and gives access to all the available constructor options provided by LWP::UserAgent.
The module also provides customizable error and debug hanlders.
INSTALLATION
One of the easiest ways is to run:
perl -MCPAN -e'install Geneos::API'
This will download and install the latest production version available from CPAN.
Alternatively, use any other method that suits you.
METHODS
Constructor
new
$api->new($url)
$api->new($url, $options)
$url
is required and must be in the format:
http://host:port/path
For example:
my $api = Geneos::API->new("http://localhost:7036/xmlrpc");
XML-RPC Client is initialized upon call to the API constructor
Options
The constructor accepts a reference to the options hash as optional second parameter:
my $api = Geneos::API->new("http://localhost:7036/xmlrpc", {
api => {
# XML-RPC API options:
raise_error => 1,
},
ua => {
# UserAgent options:
keep_alive => 20,
timeout => 60,
},
});
api - XML-RPC options
raise_error
Force errors to raise exceptions via
Carp::croak
print_error
Force errors to raise warnings via
Carp::carp
error_handler
Custom error handler. See "error_handler" section for more details.
debug_handler
Debug handler. See "Debugging" section for more details.
The order of precedence for error handling is as follows:
error_handler
raise_error
print_error
If neither is set, the errors won't be reported and "error" method will need to be called to check if the latest call generated an error or not.
Example
# force errors to raise exceptions:
my $api = Geneos::API->new("http://example.com:7036/xmlrpc", {api=>{raise_error=>1,},});
ua - UserAgent options
any options supported by LWP::UserAgent
If no LWP::UserAgent options are passed to the constructor, the keep alive will be enabled with the total capacity of 10. In other words, the two calls below are identical:
$api = Geneos::API->new("http://localhost:7036/xmlrpc")
# is identical to
$api = Geneos::API->new("http://localhost:7036/xmlrpc", {
ua => {
keep_alive => 10,
},
});
# but different to (keep alive disabled):
$api = Geneos::API->new("http://localhost:7036/xmlrpc", {
ua => {},
});
Note that if you pass the LWP::UserAgent options, the keep alive default won't be applied:
# keep alive is not enabled
$api = Geneos::API->new("http://localhost:7036/xmlrpc", {
ua => {
timeout => 300,
},
});
Examples:
# sets http timeout to 30 seconds and implicitly disables keep alive:
$api = Geneos::API->new("http://example.com:7036/xmlrpc", {
ua => {
timeout=>30,
},
});
# sets the agent name to "geneos-client/1.00"
$api = Geneos::API->new("http://example.com:7036/xmlrpc", {
ua => {
agent=>"geneos-client/1.00",
},
});
API and API Streams Function Calls
There are three classes that represent Samplers, Views and Streams.
Samplers are represented by the internal Geneos::API::Sampler
class. First, a sampler object must be created using get_sampler
method:
get_sampler
$api->get_sampler($managed_entity, $sampler_name)
$api->get_sampler($managed_entity, $sampler_name, $type_name)
This method doesn't check whether the sampler exists. Use $type_name
parameter only if the sampler is a part of that type
Returns sampler object.
$sampler = $api->get_sampler($managed_entity, $sampler_name, $type_name)
This will create a Sampler object representing a sampler with the name $sampler_name
in the managed entity $managed_entity
. You can call any method from the section "Sampler methods" on this object.
To reference samplers which are part of a type, use $type_name parameter:
# This will get sampler "Monkeys" in type "Animals" on managed entity "Zoo":
$sampler_in_type = $api->get_sampler("Zoo", "Monkeys", "Animals")
# If the sampler is assigned directly to managed entity:
$sampler = $api->get_sampler("Zoo", "Monkeys")
Views are represented by the internal Geneos::API::Sampler::View
class. In order to create an instance of this class, you can use:
# if the view already exists
$view = $sampler->get_view($view_name, $group_heading)
# if the view does not exist yet and you want to create it
$view = $sampler->create_view($view_name, $group_heading)
Once the view object is created, you can call any of the "View methods" on it.
Streams are represented by the internal Geneos::API::Sampler::Stream
class. In order to create an instance of this class, you can use:
$stream = $sampler->get_stream($stream_name)
Once the object is created, you can call any of the "Stream methods" on it.
Sampler methods
get_stream
$sampler->get_stream($stream_name)
The stream must already exist. This method will NOT check that the stream extists or not.
Returns an object representing the stream $stream_name
.
create_view
$sampler->create_view($view_name, $group_heading)
Creates a new, empty view $view_name
in the specified sampler under the specified $group_heading
. This method will create a view and returns the object representing it. An error will be produced if the view already exists.
Returns OK
on successful completion.
get_view
$sampler->get_view($view_name, $group_heading)
The view must already exist. This method will NOT check that the view extists or not. Use "view_exists" method for that.
Returns an object representing the view $view_name
.
view_exists
$sampler->view_exists($view_name, $group_heading)
Checks whether a particular view exists in this sampler.
Returns 1
if the view exists, 0
otherwise.
remove_view
$sampler->remove_view($view_name)
Removes a view that has been created with create_view.
Returns OK
on successful completion.
get_parameter
$sampler->get_parameter($parameter_name)
Retrieves the value of a sampler parameter that has been defined in the gateway configuration.
Returns the parameter text written in the gateway configuration.
sign_on
$sampler->sign_on($period)
$period - The maximum time between updates before samplingStatus becomes FAILED
Commits the API client to provide at least one heartbeat or update to the view within the time period specified.
Returns OK
on successful completion.
sign_off
$sampler->sign_off()
Cancels the commitment to provide updates to a view.
Returns OK
on successful completion.
heartbeat
$sampler->heartbeat()
Prevents the sampling status from becoming failed when no updates are needed to a view and the client is signed on.
Returns OK
on successful completion.
View methods
add_table_row
$view->add_table_row($row_name,$data)
Adds a new, table row to the specified view and populates it with data.
Returns OK
on successful completion.
remove_table_row
$view->remove_table_row($row_name)
Removes an existing row from the specified view.
Returns OK
on successful completion.
add_headline
$view->add_headline($headline_name)
Adds a headline variable to the view.
Returns OK
on successful completion.
remove_headline
$view->remove_headline($headline_name)
Removes a headline variable from the view.
Returns OK
on successful completion.
update_variable
$view->update_variable($variable_name, $new_value)
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.
Returns OK
on successful completion.
update_headline
$view->update_headline($headline_name, $new_value)
Updates a headline variable.
Returns OK
on successful completion.
update_table_cell
$view->update_table_cell($cell_name, $new_value)
Updates a single cell in a table. The standard row.column
format should be used to reference a cell.
Returns OK
on successful completion.
update_table_row
$view->update_table_row($row_name, $new_value)
Updates an existing row from the specified view with the new values provided.
Returns OK
on successful completion.
add_table_column
$view->add_table_column($column_name)
Adds another column to the table.
Returns OK
on successful completion.
update_entire_table
$view->update_entire_table($new_table)
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.
Returns OK
on successful completion.
column_exists
$view->column_exists($column_name)
Check if the headline variable exists.
Returns 1
if the column exists, 0
otherwise.
row_exists
$view->row_exists($row_name)
Check if the headline variable exists.
Returns 1
if the row exists, 0
otherwise.
headline_exists
$view->headline_exists($headline_name)
Check if the headline variable exists.
Returns 1
if the headline variable exists, 0
otherwise.
get_column_count
$view->get_column_count()
Return the column count of the view.
Returns the number of columns in the view. This includes the rowName column.
get_row_count
$view->get_row_count()
Return the headline count of the view.
Returns the number of headlines in the view. This includes the samplingStatus
headline.
get_headline_count
$view->get_headline_count()
Returns the number of headlines in the view. This includes the samplingStatus
headline.
get_column_names
$view->get_column_names()
Returns the names of existing columns in the view. This includes the rowNames column name.
get_row_names
$view->get_row_names()
Returns the names of existing rows in the view
get_headline_names
$view->get_headline_names()
Returns the names of existing headlines in the view. This includes the samplingStatus
headline.
get_row_names_older_than
$view->get_row_names_older_than($timestamp)
$timestamp
- 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.
Stream methods
add_message
$stream->add_message($message)
Adds a new message to the end of the stream.
Returns OK
on successful completion.
NetProbe Function Calls
managed_entity_exists
$api->managed_entity_exists($managed_entity)
Checks whether a particular Managed Entity exists on this NetProbe containing any API or API-Streams samplers.
Returns 1
if the Managed Entity exists, 0
otherwise
sampler_exists
$api->sampler_exists($managed_entity, $sampler_name)
$api->sampler_exists($managed_entity, $sampler_name, $type_name)
Checks whether a particular API or API-Streams sampler exists on this NetProbe
Returns 1
if sampler exists, 0
otherwise
If the sampler in the question is part of the type - use the $type_name parameter. See examples for "get_sampler" method
gateway_connected
$api->gateway_connected()
Checks whether the Gateway is connected to this NetProbe
Returns 1
if the Gateway is connected, 0
otherwise
Gateway Function Calls
add_managed_entity
$api->add_managed_entity($managed_entity, $data_section)
Adds the managed entity to the particular data section
Returns 1
on success, 0
otherwise
Error handling
raise_error
$api->raise_error()
Get the raise_error attribute value
Returns 1
is the raise_error attribute is set or 0
otherwise
If the raise_error attribute is set, errors generated by API calls will be passed to Carp::croak
remove_raise_error
$api->remove_raise_error()
Remove the raise_error attribute
print_error
$api->print_error()
Get the print_error attribute value
Returns 1
is the print_error attribute is set or 0
othersise
If the print_error attribute is set, errors generated by API calls will be passed to Carp::carp
print_error attribute is ignored if raise_error is set.
remove_print_error
$api->remove_print_error()
Remove the print_error attribute
status_line
$api->status_line()
Returns the string <code> <message>
. Returns undef
if there is no error.
error
$api->error
Get the error produced by the last api call.
Returns reference to the error hash or undef if the last call produced no error. The hash contains three elements:
code
HTTP or XML-RPC error code.
message
Error string.
class
The component that produced the error:
HTTP
orXML-RPC
.
Example
my $e = $api->error;
printf("code: %d\nmessage: %s\n", $e->{code}, $e->{message});
# example output:
code: 202
message: Sampler does not exist
error_handler
$api->error_handler()
Allows you to provide your own behaviour in case of errors.
The handler must be passed as a reference to subroutine and it could be done as a constructor option:
my $api = Geneos::API->new("http://localhost:7036/xmlrpc", {
api => { error_handler => \&my_error_handler, },
});
or via a separate method:
$api->error_handler(\&my_error_handler)
The subroutine is called with two parameters: reference to the error hash and the api object itself.
For example, to die with a full stack trace for any error:
use Carp;
$api->error_handler( sub { confess("$_[0]->{code} $_[0]->{message}") } );
Please note that the custom error handler overrides the raise_error and print_error settings.
The error handler can be removed by calling:
$api->remove_error_handler()
Debugging
The module comes with a debug handler. The handler must be passed as a reference to subroutine and it could be done as a constructor option:
my $api = Geneos::API->new("http://localhost:7036/xmlrpc", {
api => { debug_handler => \&my_debug_handler, },
});
# or via a separate method:
$api->debug_handler(\&my_debug_handler)
The subroutine is called with one parameter: Geneos::API::XMLRPC
object.
The following Geneos::API::XMLRPC
methods might be useful for debugging purposes:
t0
Returns the time at the start of the request. It's captured using Time::HiRes::gettimeofday method:
$t0 = [gettimeofday]
xmlrpc_request
Returns the
Geneos::API::XMLRPC::Request
object.xmlrpc_response
Returns the
Geneos::API::XMLRPC::Response
object.http_request
Returns the
HTTP::Request
object. See HTTP::Request for more details.http_response
Returns the
HTTP::Response
object. See HTTP::Response for more details.
The debug handler can be removed by calling:
$api->remove_debug_handler()
Example.
The custom debug handler in this example will output the following stats:
Elapsed time
HTTP request headers
HTTP response headers
use Time::HiRes qw(tv_interval);
$api->debug_handler(\&custom_debug_handler);
sub custom_debug_handler {
my $api_obj = shift;
printf "# elapsed time: %f\n\n# request header:\n%s\n# response header:\n%s\n",
tv_interval($api_obj->t0),
$api_obj->http_request->headers_as_string,
$api_obj->http_response->headers_as_string;
}
Upon execution, it will produce output similar to:
# elapsed time: 0.002529
# request header:
User-Agent: libwww-perl/6.04
Content-Type: text/xml
# response header:
Connection: Keep-Alive
Server: GENEOS XML-RPC
Content-Length: 152
Content-Type: text/xml
Client-Date: Fri, 26 Dec 2014 16:18:10 GMT
Client-Peer: 127.0.0.1:7036
Client-Response-Num: 1
EXAMPLE
This is a Perl version of the C++/Java example from the ITRS documentation.
#!/usr/bin/perl
use strict;
use warnings;
use Geneos::API;
unless (@ARGV == 2) {
warn "Usage: QueueSamplerClient serverHost serverPort\n";
exit -1;
}
my ($host,$port) = @ARGV;
my $api = Geneos::API->new("http://$host:$port/xmlrpc",{api=>{raise_error=>1,},});
my $sampler = $api->get_sampler("myManEnt","mySampler");
my $view = $sampler->create_view("queues","myGroup");
$view->add_headline("totalQueues");
$view->add_headline("queuesOffline");
my $table = [
["queueName","currentSize","maxSize","currentUtilisation","status"],
["queue1",332,30000,"0.11","online"],
["queue2",0,90000,"0","offline"],
["queue3",7331,45000,"0.16","online"]
];
$view->update_entire_table($table);
$view->update_headline("totalQueues",3);
$view->update_headline("queuesOffline",1);
for(1..1000) {
$view->update_table_cell("queue2.currentSize",$_);
sleep 1;
}
To run this example: setup the managed entity and the sampler as per the instructions given in the ITRS documentation, save this code as QueueSamplerClient, make it executable and run:
./QueueSamplerClient localhost 7036
This assumes that the NetProbe runs on the localhost and port 7036
ONLINE RESOURCES AND SUPPORT
Drop me an email if you have any questions with Geneos::API in the subject
KNOWN ISSUES
Few issues have been discovered while testing ITRS Instrumentation API. These issues are not caused by Geneos::API Perl module but ITRS implementation of the XML-RPC interface to Geneos.
Memory leak in the netprobe
Memory leak occurs when data view is removed via entity.sampler.removeView call
One way to reproduce this issue is to perform a serious of calls:
... entity.sampler.removeView entity.sampler.createView entity.sampler.view.updateEntireTable ...
The memory usage by the NetProbe process grows almost linear when the data view size is constant.
Invalid parameters passed to XML-RPC method can crash netprobe
An entity.sampler.UpdateEntireTable call with a scalar parameter instead of 2 dimensional array crashes the NetProbe:
<?xml version="1.0" encoding="utf-8"?> <methodCall> <methodName>entity.sampler.group-view.updateEntireTable</methodName> <params> <param> <value><string>scalar instead of array</string></value> </param> </params> </methodCall>
Please contact ITRS directly for the latest status.
BUGS
Of course. Please raise a ticket via rt.cpan.org
AUTHOR
Ivan Dmitriev, <tot@cpan.org>
COPYRIGHT AND LICENSE
Copyright (C) 2015 by Ivan Dmitriev
This library is free software; you can redistribute it and/or modify it under the same terms as Perl itself.