NAME

omlc_inject - inject a measurement sample into a measurement point

SYNOPSIS

#include <oml2/omlc.h>
int omlc_inject(OmlMP* mp, OmlValueU* values);
int omlc_inject_metadata(OmlMP* mp, const char* key, const OmlValueU* value, OmlValueT type, const char* fname);

DESCRIPTION

The main purpose of the liboml(3) is to allow easy reporting of measurement tuples from within instrumented applications. This is called injection. A set of Measurement Points (MPs) are first registered to the library, with a fixed schema describing the tuples to be reported through each MP. At run-time, the injected data is serialised as a Measurement Stream (MS), and sent towards a collection point.

omlc_inject() takes an array of values and injects them as a measurement sample into an MP previously defined via a call to omlc_add_mp(3). If omlc_inject(3) is called prior to the start of measurement sampling, it will be ignored. Measurement sampling is initiated by a call to omlc_start(3).

METADATA

The client library can also inject metadata which doesn’t quite fit in the defined measurement points, or occurs too seldom to justify creating a new one. Example metadata includes ancillary information about the application such as version or command line, or some specific details about MPs or specific fields such as precision and units. Metadata is sent along a specific MS named _experiment_metadata. Metadata information consists of key/value pairs qualifying a subject. The subject is a string formatted as .[mpname[.fname]], where . identifies the root of the application, and additional components allow to specify the entity to which the metadata refers more precisely.

Metadata can be injected from the client side using the omlc_inject_metadata() function. The subject is derived from mp (which can be NULL) and that MP’s optional field fname (which is ignored if mp is NULL). The key is specified as a nil-terminated C-string, and the value as an OmlValueU(3), allowing some type flexibility. At the moment, the only valid type for value is OML_STRING_VALUE; anything else will generate an error. Nonetheless it needs to be properly initialised (omlc_zero(3)) and cleaned up (omlc_reset_string(3)).

AN IMPORTANT NOTE ON THE GOODNESS OF GENERATED CODE

Prior to reading the following, it is worthy to note that oml-scaffold(1) can be used to generate custom registration and injection helpers from a high-level description of an application’s MPs. This is sufficient for most applications, and avoids errors in manipulating low-level data structures. This also provides some abstraction from occasional API changes, and simplifies porting to newer versions of OML. It is therefore the recommended approach for all applications with static measurement points (i.e., not created dynamically with variable MPs depending on run-time conditions, such as specific instrumented plugin code).

The code generated by oml-scaffold(1) follows the structure described thereafter. The registration helpers create the OmlMPDef structures as exemplified below, and rely on omlc_add_mp(3) to register the MPs on behalf of the user (in oml_register_mps(3)). The injection helpers (see oml_inject_MPNAME(3)) offer C-functions with typed argument, and map them internally to OmlValueU before calling omlc_inject().

MANUALLY INJECTING SAMPLES

In some cases (mostly when defining MPs dynamically at run time), it is not possible to use injection helpers (see previous section). Only in these cases is it justified to use omlc_inject directly. This is described here.

The mp parameter must be an MP handle returned by a call to omlc_add_mp(3). The values array must contain values whose number and types correspond to the types declared for the MP tuple in the call to omlc_add_mp(3). The convenience macros omlc_set_*() should be used to set up the values array.

For instance, suppose the following MP definition:

OmlMPDef mp_def [] =
{
  { "source", OML_UINT32_VALUE },
  { "destination", OML_UINT32_VALUE },
  { "length", OML_UINT32_VALUE },
  { "weight", OML_DOUBLE_VALUE },
  { "protocol", OML_STRING_VALUE },
  { "txrates", OML_VECTOR_UINT32_VALUE },
  { NULL, (OmlValueT)0 } /* Sentinel value */
};

(See omlc_add_mp(3) for details.)

To inject a measurement sample into this MP, the programmer must first declare an OmlValueU array with the right number of elements, in this case six (the sentinel value is only needed when declaring the MP to omlc_add_mp(3), it doesn’t play any further part). Then, call the value setting macros to load new values into the array, and finally pass the array to omlc_inject():

OmlMP *mp = omlc_add_mp ("myMP", mp_def);

...

omlc_start();

...

uint32_t source_id;
uint32_t destination_id;
uint32_t packet_length;
double weight;
char *protocol;
double txrates[16];
size_t txrates_sz = sizeof(txrates) / sizeof(txrates[0]);

/* Some application-specific code to obtain new values for the variables above */

...

OmlValueU values[6];

omlc_zero_array(values, 6);

omlc_set_uint32 (values[0], source_id);
omlc_set_uint32 (values[1], destination_id);
omlc_set_uint32 (values[2], packet_length);
omlc_set_double (values[3], weight);
omlc_set_string (values[4], protocol);
omlc_set_vector_double (values[5], txrates, txrates_sz);

omlc_inject (mp, values);

omlc_reset_vector(values[5]);
omlc_reset_string(values[4]);

Internally, the library guards each MP with a mutex, so this function should be thread safe.

The caller must be careful to ensure that the values array has enough elements to accommodate the declared number of fields in the tuple for the given mp. Otherwise, omlc_inject() might try to read past the end of the array. Similarly, the types of the values must be as declared, and in the same order in the array as specified for the MP tuple definition. This is particularly important for strings.

The values array should be considered "write-only" and should only be manipulated using the value-setting macros, see OmlValueU(3) for information on supported data types and there accessors.

Once a call to omlc_inject() has been made, it is safe to modify/free the values vector, as omlc_inject() creates internal copies.

RETURN VALUE

These functions return 0 on success, or a negative value on error.

This is particularly the case if the library has not been initialized with a call to omlc_init(3), or if measurement sampling has not been started with a call to omlc_start(3). It this case the function exits, without performing any actions, with status -1. Similarly, if either mp or values is NULL, then the function exits with the same status.

BUGS

If a problem you are experiencing is not addressed in the FAQ (http://oml.mytestbed.net/projects/oml/wiki/FAQ_and_Support) nor already present in the list of know bugs (http://oml.mytestbed.net/projects/oml/issues). You could discuss it on the mailing list (details and archives at http://oml.mytestbed.net/tab/show?id=oml).

It is however advisable to open a ticket on our issue tracker at http://oml.mytestbed.net/projects/oml/issues/new. Don’t forget to include details such as client and server logs (at [--oml-log-level|-d] 2). It also helps if you can share the source code of a (minimal, if possible) example reliably triggering the problem.