The Perl Toolchain Summit needs more sponsors. If your company depends on Perl, please support this very important event.

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

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

    $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 or XML-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

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.