The riemann-c-client API docs
=============================

Since I don't particularly like boring and dry documentation, these
API docs will have a lot of prose to go along with them, and should be
read along with the header files, as not every function will have its
signature copied here.

We'll start by laying down the foundations, and agreeing on a few
terms I will be using throghout this documentation. There are two
things we can send [Riemann][riemann]: [events](#api-event) and
[queries](#api-query), and we send both (and receive the response)
using the [client](#api-client) structure. The events can have
[tags](#api-tags) and [attributes](#api-attributes), along with a few
other settings, and both events and queries are encapsulated in
[messages](#api-message). There's also a [simplified API](#api-simple)
for when the whole event or query can be constructed in a single step,
but more about that later.

 [riemann]: http://riemann.io/

With that out of the way, lets start at the top level! For
convenience, we have the `<riemann/riemann-client.h>` header, which
includes everything you'll need to get started writing
[Riemann][riemann] clients. You can also include the individual
headers, but you'll likely need most - if not all - of them anyway, so
might as well choose the easy route from the start.

```c
#include <riemann/riemann-client.h>
```

Before we start to discuss any of the functions, there's a general
rule of thumb followed throughout the library: in case of an error,
the library will signal it. If the function in question returns a
pointer, it will return NULL, and set `errno` to an appropriate value.
If the function returns an int, it will return zero on success, and a
negated `errno` value upon failure. This is true for all functions in
the library.

##### Clients

With that out of the way, we'll need to connect to [Riemann][riemann],
and this is where the [riemann_client_t](#api-client) structure and
associated functions help!

There are two ways to create a client object: `riemann_client_new()`
and `riemann_client_create()`. The difference is that the latter will
also connect to the server (using
[`riemann_client_connect()`](#api-client-connect), more about that
later). The first takes no arguments, and returns a `riemann_client_t`
instance, which one will need to free later using
`riemann_client_free()`. The second option, `riemann_client_create()`
takes the same arguments as
[`riemann_client_connect()`](#api-client-connect) does, except for the
object itself.

 So lets discuss how to connect to Riemann!

```c
int riemann_client_connect (riemann_client_t *client, riemann_client_type_t type,
                            const char *hostname, int port);
```

The first argument is - obviously - an instance of the client object,
created via `riemann_client_new()`. If the instance is already
connected, the old connection will be correctly closed, disconnected
and dropped as soon as the new connection was established. The second
argument is the type of connection we want: we can have either TCP or
UDP. If we want to do queries, we'll need TCP. The valid options here
are `RIEMANN_CLIENT_TCP` and `RIEMANN_CLIENT_UDP`. Then we have a
hostname and a port, those should, I hope, be clear enough not to need
an explanation.

In case we'd want to disconnect from the server, we can use
`riemann_client_disconnect()`, which takes a single argument: the
client object. Personally, I find it unlikely that one would ever want
to do this, but hey!

There are three other functions of note that need a client:

```c
int riemann_client_send_message (riemann_client_t *client,
                                 riemann_message_t *message);
```

```c
int riemann_client_send_message_oneshot (riemann_client_t *client,
                                         riemann_message_t *message);
```

```c
riemann_message_t *riemann_client_recv_message (riemann_client_t *client);
```

The first sends a [message](#api-message) to Riemann, so does the
second, but it also frees it, and the third receives a reply.

Unless using
[`riemann_client_send_message_oneshot()`](#api-client-send-msg-1),
sending a message does not destroy the message object, so we'll have
to free it ourselves. Also, every received message object must be
freed manually, the function returns a newly allocated message object.

##### Messages

But what is a message?

The message - and the rest of the structures - are defined in
[`lib/proto/riemann.proto`][proto], and are standard structures
generated by the [Protobuf C Compiler][proto-c]. I will briefly
explain their structure, but won't go into much detail: it is both
easy to figure out, and the protocol buffers documentation should have
reasonable pointers anyway.

 [proto]: https://github.com/algernon/riemann-c-client/blob/master/lib/proto/riemann.proto
 [proto-c]: http://protobuf-c.googlecode.com

Anyway! A message is a container that can encapsulate
[events](#api-event), [queries](#api-query) and
[responses](#api-response).

Of these, responses are the easiest and simplest: the response is
contained within the message itself: the `ok` and `error` fields are
set on response messages.

Other than these, the `query` and `events` fields are interesting to
us. The first one is a [`riemann_query_t`](#api-query) object, the
other is a list of [`riemann_event_t`](#api-event) objects (where
their number is stored in the `n_events` field).

Creating a message is possible in three ways:

```c
riemann_message_t *riemann_message_new (void);
```

```c
riemann_message_t *riemann_message_create_with_events (riemann_event_t *event, ...);
```

```c
riemann_message_t *riemann_message_create_with_query (riemann_query_t *query);
```

The first form creates an empty message, which one can later use to
attach events or a query too, using
[`riemann_event_set_events`](#api-event-set-events) or
[`riemann_event_set_query`](#api-event-set-query). The other two are
the usual two-in-one functions that create a new message, and calls
the appropriate set function aswell, with similar arguments.

Using any of these, the message must be freed with
`riemann_message_free()` when it is no longer useful. Freeing a
message will also free all associated events and the query too.

```c
int riemann_message_set_events (riemann_message_t *message, ...);
```

Setting events on a message is as easy as passing a NULL-terminated
list of [`riemann_event_t`](#api-event) objects to this function. If
the message already had events, they will be freed before setting the
new ones.

```c
int riemann_message_set_query (riemann_message_t *message,
                               riemann_query_t *query);
```

Similarly, setting the query is similar: pass a
[`riemann_query_t`](#api-query) object to the setter function, and
that is all.

##### Queries

Since there are only a handful of things one can do with a query, lets
look at what these things are!

We can create new queries with `riemann_query_new()`, which takes a
string argument: the query itself. It returns a newly allocated
object, as is usual, which we can free with `riemann_query_free()`.

Then there's `riemann_query_set_string()`, which takes a query object
and a string, and replaces the query string. The old string is
conveniently freed up for us.

##### Events

Events are a lot more complex, they have a number of interesting
fields, and a few functions to set them too.

There are two ways to create an event: with `riemann_event_new()`,
which takes no arguments and returns a newly allocated object, or with
`riemann_event_create()`, which takes a list of fields and their
contents, and must be terminated with `RIEMANN_EVENT_FIELD_NONE`. This
latter function works the same way as
[`riemann_event_set()`](#api-event-set) does:

```c
int riemann_event_set (riemann_event_t *event, ...);
```

This funcition expects at least two arguments: the event object to set
fields on, and a list of field - value pairs, terminated by
`RIEMANN_EVENT_FIELD_NONE`. What the value part is depends on the
field type.

The library supports all fields Riemann recognises:

* `RIEMANN_EVENT_FIELD_TIME`: An optional timestamp (seconds since the
  Unix epoch, as a 64-bit integer).
* `RIEMANN_EVENT_FIELD_STATE`: A string, describing the state of this
  event.
* `RIEMANN_EVENT_FIELD_SERVICE`: A string, the service the event
  belongs to.
* `RIEMANN_EVENT_FIELD_HOST`: A string, the host the event originates
  from.
* `RIEMANN_EVENT_FIELD_DESCRIPTION`: A free-form string, to serve as
  the event description.
* `RIEMANN_EVENT_FIELD_TTL`: A floating point number, the number of
  seconds the event should be considered valid.
* `RIEMANN_EVENT_FIELD_METRIC_S64`: A signed 64-bit integer metric.
* `RIEMANN_EVENT_FIELD_METRIC_D`: A double type metric.
* `RIEMANN_EVENT_FIELD_METRIC_F`: A float type metric.
* `RIEMANN_EVENT_FIELD_TAGS`:  A list of string
  tags, terminated by `NULL`.
* `RIEMANN_EVENT_FIELD_ATTRIBUTES`: A list of
  [`riemann_attribute_t`](#api-attributes) objects, terminated by
  NULL.

Of the metric fields, only one should be set at a time.

In case one only wants to set one single field,
[`riemann_event_set_one`](#api-event-set-one) is there for
convenience:

```c
int riemann_event_set_one (event, field, ...);
```

Adding tags and attributes is also supported via the
`riemann_event_tag_add` and `riemann_event_attribute_add` functions:

```c
int riemann_event_tag_add (riemann_event_t *event, const char *tag);
int riemann_event_attribute_add (riemann_event_t *event,
                                 riemann_attribute_t *attrib);
```

Both of them take an event first, followed by either a tag or an
[attribute object](#api-attributes).

Events must be freed with `riemann_event_free()`, to avoid memory
leaks. Freeing an event will also free all associated data: tags and
attributes included.

Examples of using these functions can be found in the
[test suite][test-event].

 [test-event]: https://github.com/algernon/riemann-c-client/blob/master/tests/check_events.c#L15

###### Attributes

The last thing we need to talk about are attributes. Attributes are
key-value pairs, which we can attach to events.

They can be instanciated in two ways: with `riemann_attribute_new()`,
which takes no arguments and returns an empty `riemann_attribute_t`
object; or `riemann_attribute_create()`, which takes a `key` and a
`value` argument, and returns a `riemann_attribute_t` with key and
value already set.

Attributes must be freed either with `riemann_attribute_free()`, or if
they're embedded in an event, freeing the event will take care of
freeing the attributes too.

One can also set the key and the value of an attribute with the
`riemann_attribute_set_key()` and `riemann_attribute_set_value()`
functions, respectively. Both of them expect an attribute object, and
a string. And for convenience, there is also
`riemann_attribute_set()`, which can set both key and value at the
same time. All three of these free the former values of the attribute,
before setting the new one.

###### Simplified API

With all the groundwork laid out, there's one more thing of note: the
simplified API. With these functions, one can send an event or a query
in one single step, but it has some limitations: one has much less
control over the event, and can't build it up programmatically. But if
the event can be constructed in a single step, and reusing the event
object is not needed, these APIs simplify the task considerably.

So, without much further ado:

```c
#include <riemann/simple.h>

int riemann_send (riemann_client_t *client, riemann_event_field_t field, ...);
riemann_message_t *riemann_query (riemann_client_t *client, const char *query);
```

One needs to include the `riemann/simple.h` header for these
functions, they're not available when only `riemann/riemann-client.h`
is included.

The first function takes a `riemann_client_t`, and a list of field -
value pairs, much like [`riemann_event_set()`](#api-event-set). What
it does, is it constructs the event and the message internally, fires
it off, and frees them up. It returns zero on success, a negative
errno value otherwise.

The second function is similar, but instead of sending an event to the
specified `riemann_client_t` client, it sends a [query](#api-query),
and returns the resulting `riemann_message_t` object. If there is a
failure, it either returns NULL (if the query couldn't be constructed
or sent at all), or a response with it's `ok` field set to zero if the
query failed on the Riemann side.

##### Concluding thoughts

This is all there is to it, really: the library is simple and
straightforward. For examples, look at the [test suite][test-suite]
and the [demo programs][demos].

 [test-suite]: https://github.com/algernon/riemann-c-client/tree/master/tests
 [demos]: https://github.com/algernon/riemann-c-client/tree/master/src
