Skip to content

Commit

Permalink
CP-18271 first cut at C library for RRD plugins
Browse files Browse the repository at this point in the history
This PR implements the C library for writing RRD plugins. It has been tested using the code in the repository and against the rrd-transport library. A strange bug currently remains: the rrd-transport installed via yum (`ocaml-rrd-transport-devel`) reports a problem whereas an rrd-transport library compiled from source code does not.
  • Loading branch information
lindig authored Aug 8, 2016
1 parent 5c1d2b4 commit 35d116b
Show file tree
Hide file tree
Showing 12 changed files with 1,051 additions and 41 deletions.
9 changes: 9 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
*.[ch]~
rrdclient
rrdtest
ocaml/_build
ocaml/rrdreader.native
*.o
*.a
*.rrd

3 changes: 3 additions & 0 deletions .gitmodules
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
[submodule "parson"]
path = parson
url = https://github.com/kgabis/parson.git
14 changes: 14 additions & 0 deletions .travis.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@

language: c
sudo: false

matrix:
include:
- compiler: gcc
os: linux

script:
- make parson
- make
- make test

21 changes: 21 additions & 0 deletions LICENSE
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
The MIT License (MIT)

Copyright (c) 2016 Citrix

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
99 changes: 99 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
# vim: set ts=8 sw=8 noet:
#
#

CC = gcc
CFLAGS = -std=gnu99 -g -Wall
OBJ += librrd.o
OBJ += parson/parson.o
LIB += -lz

OCB = ocamlbuild -use-ocamlfind

.PHONY: all
all: librrd.a rrdtest rrdclient

.PHONY: clean
clean:
rm -f $(OBJ)
rm -f librrd.a
rm -f librrd.o
rm -f parson/parson.o
rm -f rrdtest.o rrdtest
rm -f rrdclient.o rrdclient
rm -rf config.xml cov-int html coverity.out
cd ocaml; $(OCB) -clean

.PHONY: test
test: rrdtest rrdclient
./rrdtest
seq 1 10 | ./rrdclient rrdclient.rrd
seq 1 10 \
| while read i; do echo $$i; sleep 1; done \
| ./rrdclient rrdclient.rrd

.PHONY: valgrind
valgrind: rrdtest
valgrind --leak-check=yes ./rrdtest
seq 1 10 | valgrind --leak-check=yes ./rrdclient rrdclient.rrd

.PHONY: indent
indent: librrd.h librrd.c rrdtest.c
indent -orig -nut $^

.PHONY: depend
depend: librrd.c rrdtest.c
$(CC) -MM $^

.PHONY: parson
parson:
# git submodule add https://github.com/kgabis/parson.git
git submodule init
git submodule update

%.o: %.c
$(CC) $(CFLAGS) -c -o $@ $<

librrd.a: $(OBJ)
ar rc $@ $(OBJ)
ranlib $@

rrdtest: rrdtest.o librrd.a
$(CC) $(CFLAGS) -o $@ $^ $(LIB)

rrdclient: rrdclient.o librrd.a
$(CC) $(CFLAGS) -o $@ $^ $(LIB)

# coverity analysis

COV_OPTS += --cpp
COV_OPTS += --aggressiveness-level high
COV_OPTS += --all
COV_OPTS += --rule
COV_OPTS += --disable-parse-warnings
COV_OPTS += --enable-fnptr

COV_DIR = cov-int

cov: parson
cov-configure --gcc --config config.xml
cov-build --dir $(COV_DIR) --config config.xml $(MAKE)
cov-analyze $(COV_OPTS) --dir $(COV_DIR) --config config.xml
cov-format-errors --dir $(COV_DIR) --emacs-style > coverity.out
cov-format-errors --dir $(COV_DIR) --html-output html

# C dependencies

parson/parson.h: parson
parson/parson.c: parson

parson/parson.o: parson/parson.h
rrdtest.o: parson/parson.h librrd.h
librrd.o: parson/parson.h librrd.h

# OCaml test utility
# You need: yum install -y ocaml-rrd-transport-devel

rrdreader:
cd ocaml; $(OCB) -pkg rrd-transport -tag thread rrdreader.native

95 changes: 54 additions & 41 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@

[![Build Status](https://travis-ci.org/lindig/rrd-client-lib-1.svg?branch=master)](https://travis-ci.org/lindig/rrd-client-lib-1)

# rrd-client-lib - A Library to Provide RRD Data

The RRD service is a system-level service that aggregates
Expand All @@ -19,26 +21,27 @@ needs to be initialised:

make parson
make


make test
./rrdtest

## Parson

The [Parson](https://github.com/kgabis/parson.git) library is included
as a Git submodule. A submodule points to a specific commit in an
external repository and does not track its master branch as this
The JSON library [Parson](https://github.com/kgabis/parson.git) is
included as a Git submodule. A submodule points to a specific commit in
an external repository and does not track its master branch as this
advances. Instead, it needs to be updated explicitly.

## Documentation - Overview

The header file `librrd.h` contains the essential information to use the
library:

typedef ... rrd_value;
typedef ... rrd_value_t;
typedef ... RRD_SOURCE;
typedef ... RRD_PLUGIN;

RRD_PLUGIN *rrd_open(char *name, rrd_domain domain, char *path);
RRD_PLUGIN *rrd_open(char *name, rrd_domain_t domain, char *path);
int rrd_close(RRD_PLUGIN * plugin);
int rrd_add_src(RRD_PLUGIN * plugin, RRD_SOURCE * source);
int rrd_del_src(RRD_PLUGIN * plugin, RRD_SOURCE * source);
Expand All @@ -55,6 +58,20 @@ samples values from all data sources and writes the data to the `path`
provided to `rrd_open`. It is the client's responsibility to call
`rrd_sample` regularly at an interval of 5 seconds.

## Sample Code

See `rrdclient.c` for a simple client that reads integers from standard
input as a data source and reports them to RRD. Here is how everything
is compiled and linked:

gcc -std=gnu99 -g -Wall -c -o librrd.o librrd.c
gcc -std=gnu99 -g -Wall -c -o parson/parson.o parson/parson.c
ar rc librrd.a librrd.o parson/parson.o
ranlib librrd.a
gcc -std=gnu99 -g -Wall -c -o rrdclient.o rrdclient.c
gcc -std=gnu99 -g -Wall -o rrdclient rrdclient.o librrd.a -lz


## Interface

<<librrd.h>>=
Expand All @@ -78,11 +95,15 @@ A plugin opens a file for communication and periodically calls
considered private to the library.

<<type definitions>>=
typedef enum { RRD_LOCAL_DOMAIN = 0, RRD_INTER_DOMAIN } rrd_domain;
/* rrd_domain_t */
typedef int32_t rrd_domain_t;
#define RRD_LOCAL_DOMAIN 0
#define RRD_INTER_DOMAIN 1



<<function declarations>>=
RRD_PLUGIN *rrd_open(char *name, rrd_domain domain, char *path);
RRD_PLUGIN *rrd_open(char *name, rrd_domain_t domain, char *path);
int rrd_close(RRD_PLUGIN * plugin);
int rrd_sample(RRD_PLUGIN * plugin);

Expand All @@ -98,32 +119,44 @@ integer or float values. Data sources can be added and removed
dynamically.

<<type definitions>>=
typedef enum { RRD_GAUGE = 0, RRD_ABSOLUTE, RRD_DERIVE } rrd_scale;
typedef enum { RRD_HOST = 0, RRD_VM, RRD_SR } rrd_owner;
typedef enum { RRD_FLOAT64 = 0, RRD_INT64 } rrd_type;
/* rrd_scale_t */
typedef int32_t rrd_scale_t;
#define RRD_GAUGE 0
#define RRD_ABSOLUTE 1
#define RRD_DERIVE 2

/* rrd_owner_t */
typedef int32_t rrd_owner_t;
#define RRD_HOST 0
#define RRD_VM 1
#define RRD_SR 2

/* rrd_type_t */
typedef int32_t rrd_type_t;
#define RRD_FLOAT64 0
#define RRD_INT64 1

typedef union {
int64_t int64;
float float64;
} rrd_value;
double float64;
} rrd_value_t;

typedef struct rrd_source {
char *name; /* name of the data source */
char *description; /* for user interface */
rrd_owner owner;
int rrd_default;/* true: rrd daemon will archive */
char *owner_uuid; /* UUID of the owner or NULL */
char *rrd_units; /* for user interface */
rrd_scale scale; /* presentation of value */
rrd_type type; /* type of value */
char *min; /* min <= sample() <= max */
char *max; /* min <= sample() <= max */
rrd_value(*sample) (void); /* reads value that gets *
* reported */
rrd_value_t(*sample) (void); /* reads value */
rrd_owner_t owner;
int32_t rrd_default; /* true: rrd daemon will archive */
rrd_scale_t scale; /* presentation of value */
rrd_type_t type; /* type of value */
} RRD_SOURCE;

typedef struct rrd_plugin RRD_PLUGIN;

<<typedef RRD_PLUGIN>>

<<function declarations>>=
int rrd_add_src(RRD_PLUGIN *plugin, RRD_SOURCE *source);
Expand All @@ -135,7 +168,7 @@ reporting. It includes a function (pointer) `sample` that obtains the
value being reported. A value can be either a 64-bit integer or a 64-bit
floating point value -- discriminated by `type`.

## Error Handling
## Constants and Error Handling

Some functions return an error code.

Expand All @@ -149,26 +182,6 @@ Some functions return an error code.
#define RRD_ERROR 4



## Private Types

<<constants>>=
#define RRD_MAX_SOURCES 128


<<typedef RRD_PLUGIN>>=
typedef struct rrd_plugin {
char *name; /* name of the plugin */
int file; /* where we report data */
rrd_domain domain; /* domain of this plugin */
RRD_SOURCE *sources[RRD_MAX_SOURCES];
uint32_t n; /* number of used slots */
JSON_Value *meta; /* meta data for the plugin */
char *buf; /* buffer where we keep protocol data */
size_t buf_size; /* size of the buffer */
} RRD_PLUGIN;


## Design

The library updates the file provided to `rrd_open` when `rrd_sample` is
Expand Down
Loading

0 comments on commit 35d116b

Please sign in to comment.