Bitdribble documentation

Install

Install from source code

The source code is available under Apache 2.0 license at https://github.com/bitdribble/bitdribble:

git clone git@github.com:bitdribble/bitdribble.git

All platforms require the expat, libyaml, jansson, microhttpd, openssl and libcurl development libraries installed.

Centos

Centos 7 has been tested. The default cmake on Centos 7 is version 2. We need cmake version 3, which we install and execute as cmake3.

sudo yum install cmake3 expat-devel libyaml-devel jansson-devel libmicrohttpd-devel openssl-devel libcurl-devel

cd .../bitdribble
mkdir build && cd build && cmake3 ..
make
sudo make install

The make install command will install headers, libraries and binaries under /usr/local. The installer can also be packaged as an rpm package.

cpack3 -G RPM

To install the rpm package, execute the command below. This will install headers, libraries and binaries under /usr.

sudo rpm -ivh bitd-<version>-<platform>.rpm

After installing the package, enable and start the bitd service:

sudo systemctl enable bitd
sudo systemctl start bitd

To uninstall the package:

sudo rpm -e bitd

Ubuntu

Ubuntu 18.04 has been tested. The default cmake on Ubuntu 18.04 has version higher than 3.1, and can be used directly.

sudo add-apt-repository universe
sudo add-apt-repository multiverse
sudo apt-get install build-essential libexpat-dev libyaml-dev libjansson-dev libmicrohttpd-dev libssl-dev libcurl4-openssl-dev

cd .../bitdribble
mkdir build && cd build && cmake ..
make
sudo make install

The make install command will install headers, libraries and binaries under /usr/local. The installer can also be packaged as a deb package:

cpack -G DEB

To install the deb package, execute the command below. This will install headers, libraries and binaries under /usr.

sudo dpkg -i bitd-<version>-<platform>.deb

After installing the package, enable and start the bitd service:

sudo systemctl enable bitd
sudo systemctl start bitd

To uninstall the package:

sudo dpkg -r bitd

Raspbian

Raspbian GNU/Linux 8 (jessie) and GNU/Linux 9.4 (stretch) have been tested. Raspberry Pi boards usually have a limited amount of flash. Before beginning installation, check the available flash size: df. The system I tested had 14G available on the root file system, and the root file system was 33% full.

Start by upgrading all packages:

sudo apt-get update
sudo apt-get upgrade

After upgrading all the packages, the root file system became 35% full. To compile the code, cmake needs to be installed as well, if not already installed.

sudo apt-get install build-essential cmake \
      libexpat-dev libyaml-dev libjansson-dev libmicrohttpd-dev \
      libssl-dev libcurl4-openssl-dev

cd .../bitdribble
mkdir build && cd build && cmake ..
make
sudo make install

The make install command will install headers, libraries and binaries under /usr/local. The installer can also be packaged as a deb package:

cpack -G DEB

To install the deb package, execute the command below. This will install headers, libraries and binaries under /usr.

sudo apt-get install expat libyaml-0-2 openssl libcurl3
sudo dpkg -i bitd-<version>-<platform>.deb

Note that on Raspbian Jessie and Stretch we need libcurl4-ssl-dev for the compilation, but libcurl3 for installing the bitd Debian package. After installing the package, enable and start the bitd service:

sudo systemctl enable bitd
sudo systemctl start bitd

To uninstall the package:

sudo dpkg -r bitd

OpenWRT

Use these instructions to install the OpenWRT SDK sources on Ubuntu. At the make menuconfig step, enable compilation of

  • Libraries->jansson
  • Libraries->libexpat
  • Libraries->libmicrohttpd (leave libmicrohttpd-no-ssl unchecked)
  • Libraries->Languages->libyaml
  • Libraries->SSL->libopenssl
  • Libraries->libcurl

These packages should either be included in the firmware image file, or should be installed with opkg after the firmware has been flashed to the device.

In this example, we build OpenWRT for Target System (x86), Subtarget (x86_64), and we enable Target Image->VMDK. The resulting toolchain under openwrt/staging_dir is toolchain-x86_64_gcc-7.3.0_musl, and the target is target-x86_64_musl. We use these settings to create bitdribble/cmake/Toolchains/Toolchain-openwrt-x86_64_gcc_musl.cmake in the bitdribble source tree, then we build the bitdribble code:

cd .../bitdribble
mkdir build-openwrt-x86 && cd build-openwrt-x86
cmake -DCMAKE_TOOLCHAIN_FILE=../cmake/Toolchains/Toolchain-openwrt-x86.cmake ..
make

For different a OpenWRT target, create a corresponding toolchain file under bitdribble/cmake/Toolchains, and pass it on the cmake command line using -DCMAKE_TOOLCHAIN_FILE.

Mac OSX

The default openssl and curl libraries installed by OSX are incompatible with bitdribble. Instead, install these packages using brew, along with other package dependencies that are needed:

brew install make cmake expat libyaml jansson libmicrohttpd openssl curl

cd .../bitdribble
mkdir build && cd build && cmake ..
make

Cygwin

Older Cygwin only distributes cmake version 2. You need a version of Cygwin that distributes cmake version 3. We have tested Cygwin version 2.893 (64 bit) which has cmake version 3.

Use the Cygwin Setup program to install these packages:

  • Debug, Devel categories
  • expat-devel
  • openssl-devel
  • libjansson-devel
  • libcurl-devel.

Additional packages not included in the Cygwin distribution must be compiled from sources, running configure then make && make install. Following package needs to be compiled from sources:

  • libmicrohttpd version 0.9.60 or later

Then, in a Cygwin bash terminal, do the following:

cd .../bitdribble

mkdir ../cygwin && cd ../cygwin && cmake ../cygwin
make

The install step will install the packages under /usr/local/bin and /usr/local/include, in the cygwin installation tree:

make install

The installer package can be set up as a .tar.bz2 archive with the command cpack -G CygwinBinary, but modern Cygwin installers use cygport instead. We do not have cygport support at this time.

Windows

We use the mingw cross compilers distributed as Cygwin package. As explained in the Cygwin section, you need a version of Cygwin that distributes cmake version 3.

The instructions below assume a 64 bit Cygwin installation. Install all the Cygwin mingw64-x86_64 and mingw64-i686 packages. These packages include:

  • expat-devel
  • openssl-devel
  • libcurl-devel.

Additional packages must be compiled from sources running

configure --host=x86_64-w64-mingw32 --prefix=/usr/x86_64-w64-mingw32/sys-root/mingw
# respectively
configure --host=i686-w64-mingw32 --prefix=/usr/i686-w64-mingw32/sys-root/mingw
# both followed by
make && make install

The additional packages needed are:

  • libjansson version 2.11 or later
  • libmicrohttpd version 0.9.60 or later

For 64 bit Windows builds:

cd .../bitdribble
mkdir ../x86_64-w64-mingw32 && cd ../cygwin

cmake -DCMAKE_TOOLCHAIN_FILE=../bitdribble/cmake/Toolchains/Toolchain-x86_64-w64-mingw32.cmake ../bitdribble
make

Or this for 32 bit Windows builds:

cd .../bitdribble
mkdir ../i686-w64-mingw32 && cd ../cygwin

cmake -DCMAKE_TOOLCHAIN_FILE=../bitdribble/cmake/Toolchains/Toolchain-i686-w64-mingw32.cmake ../bitdribble
make

The install step will install the packages under /usr/local/bin and /usr/local/include, in the cygwin installation tree. Note that the expat, libyaml, ssl and curl libraries are dependencies and need to be manually copied in the PATH.

make install

Run the unit tests

After compiling from sources, and before make install, you can optionally run the unit tests:

make test

You can selectively run some of the tests by executing ctest instead of make test, passing a substring of the test labels using the -R argument:

ctest -R bitd-agent

This command will run all tests with labels containing bitd-agent as substring. To run all tests except those matchin the substring long in the test label:

ctest -E long

These commands will work on all platforms except on Win32 mingw builds, where you must put /usr/x86_64-w64-mingw32/sys-root/mingw/bin in the PATH:

export PATH=/usr/x86_64-w64-mingw32/sys-root/mingw/bin:$PATH
make test
ctest -R bitd-agent
ctest -E long

Test labels contain bitd-agent when the program tested is the bitd-agent itself. Executing all bitd-agent tests will cover test modules as well as the bitd-agent itself. Blocking tests that take multiple seconds to run contain long in the label, and can be skipped if a quick sanity check test run is desired.

Install precompiled packages

At this point, Bitdribble packages must be manually compiled. Precompiled Bitdribble packages are not available. When an rpm or deb package has been compiled, install it with the usual rpm and dpkg commands, then enable and start the bitd service.

sudo systemctl enable bitd
sudo systemctl start bitd

Building the docs

Install the sphinx software and its sphinx_rtd_theme. Check out the bitdribble-doc git sandbox, cd to bitdribble-doc, and make html. Copy the build/html folder to a web server (or, if you have key-based ssh access to your web server, customize the install make rule so that make install copies the build/html folder to your web server).

The bitd-agent

An example run of the bitd-agent

The main Bitribble application is the bitd-agent. The bitd-agent yaml or xml configuration file lists the task instances that the bitd-agent will run. For example:

bitd-agent -c echo-config.yml

The configuration file describes the task instance parameters, the modules that contain the task implementation, as well as the task instance schedule. Here is the echo-config.yml:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
modules:
  module-name: bitd-echo
task-inst:
  task-name: echo
  task-inst-name: Echo task inst 1
  schedule:
    type: periodic
    interval: 1s
  args:
    name-int64: -128
    name-int64: 127

By default, bitd-agent will print the task instace results to stdout in yaml format:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
$ bitd-agent -c modules/echo-config.yml
---
tags:
  task: echo
  task-instance: Echo task inst 1
run-id: 0
run-timestamp: 1539370698248977666
exit-code: 0
output:
  name-int64: -128
  name-int64: 127
---
tags:
  task: echo
  task-instance: Echo task inst 1
run-id: 1
run-timestamp: 1539370699250138126
exit-code: 0
output:
  name-int64: -128
  name-int64: 127
---
^C...

The task instance will run every second until the bitd-agent is interrupted with Ctrl-C.

The echo task just echoes back the input as output. Other task modules are available:

  • The exec task will execute any shell command
  • The sink-graphite task in the bitd-sink-graphite module will send results directed to it to a Graphite back-end database
  • The sink-influxdb task in the bitd-sink-influxdb module will send results directed to it to an Influxdb back-end database

Annotated configuration and output

This section can be skipped on first reading. Here is an annotate version of the configuration file:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
modules: # The list of modules
  module-name: bitd-echo # The module implementing the echo task
task-inst: # The task instance block
  task-name: echo # The echo task
  task-inst-name: Echo task inst 1 # Multiple task instances can be defined for the same task
  schedule:
    type: periodic # Running periodically
    interval: 1s # ... every second
  args: # The equivalent of Linux process command line arguments
    name-int64: -128
    name-int64: 127

And here is an annotated version of the output:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
$ bitd-agent -c modules/echo-config.yml
---
tags: # The task and task instance name are reported back as tags
  task: echo
  task-instance: Echo task inst 1
run-id: 0 # The run-id is incremented with each task instance run
run-timestamp: 1539370698248977666 # The Unix time, in nanosecs, when results were reported
exit-code: 0 # The exit code of the task instance
output: # The task instance output
  name-int64: -128
  name-int64: 127
---
^C...

The bitd-agent command line parameters

The full list of bitd-agent command line parameters are displayed by running

bitd-agent -h

Configuration file

The config file is passed in using a -c parameter. The type of config file can be yaml or xml. The filename suffix is used to detect the syntax used in the file: .yml or .yaml files will be parsed as yaml files, and .xml files will be parsed as xml files.

-c config_file.{xml|yml|yaml}
  The bitd-agent configuration file. Format is determined from
  file suffix. Default format is yaml.

If you don’t wish to rely on the filename suffix to determine the syntax of the file, pass the configuration file used -cx for xml, and -cy for yaml:

-cx config_file.xml
  The bitd-agent configuration file, in xml format.
-cy config_file.yaml
  The bitd-agent configuration file, in yaml format.

Results display

The task instance results can be displayed in yaml or xml format. These parameters control the display format, and where the results are saved:

-r result_file
  The bitd-agent result file. Default: stdout.
-rx
  Format the result output as xml.
-ry
  Format the result output as yaml (default).

To discard the results, pass -r /dev/null. If the result file is stdout, results will be sent to stdout. On Unix type systems, including Cygwin, the same effect can be achieved passing /dev/stdout as a result file - but Windows does not have a notion of dev/stdout. On Windows, it is therefore handy to be about to specify stdout directly as a parameter to -r.

Module load path

The modules containing task implementations are DLLs (i.e., Linux shared libraries and Windows dynamically loaded libaries). By default, the bitd-agent will look for modules in the path specified by the

  • LD_LIBRARY_PATH environment variable on Linux
  • PATH environment variable in Windows Win32 and Cygwin
  • DYLD_FALLBACK_LIBRARY_PATH environment variable on OSX

Additional path lookup folders can be specified with the following parameter:

-lp load_path
  DLL load library path.

Worker thread pool size

Task instances are executed in the context of threads in a worker thread pool. If insufficient threads are available, task instances are delayed until a thread becomes available. The default number of threads in the pool rarely needs to be adjusted, but it can be with the following parameter:

--n-worker-threads thread_count
  Set the max number of worker theads.

Log level

The log level can be controlled using the following options:

-l|--log-level none|crit|error|warn|info|debug|trace
  Set the log level (default: none).
-lk|--log-key-level key_name none|crit|error|warn|info|debug|trace
  Set log key level.
-lf|--log-file file_name
  Save log messages to a file. Default: stdout.
-ls|--log-file-size size
  Set the log file size. Default: 16777216.
-lc|--log-file-count count
  Set the log file count. Default: 3.

The -l level option controls the global log level. Sometimes, when many task instances are running, increasing the global log level results in too many messages. In that case, it is better to keep the global log level set to none and instead enable the log for specific keys, using -lk key_name level. Each task instance will send its log messages to a specific key. The task instance log key name will be specific to the task instance.

Log levels can also be controlled using the config-log task located in the bitd-config-log module. Here is an example configuration enabling logs only for the module-mgr key (in effect, enabling log messages only from the module-mgr subsystem):

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
modules:
  module-name: bitd-config-log
task-inst:
  task-name: config-log
  task-inst-name: config-log
  schedule:
    type: config
  input:
    log-level: none
    log-key:
      key-name: module-mgr
      log-level: info

This configuration file can be merged into any other configuration file - for example, here it is merged into the echo task instance configuration file:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
modules:
  module-name: bitd-echo
  module-name: bitd-config-log
task-inst:
  task-name: echo
  task-inst-name: Echo task inst 1
  schedule:
    type: periodic
    interval: 1s
  args:
    name-int64: -128
    name-int64: 127
task-inst:
  task-name: config-log
  task-inst-name: config-log
  schedule:
    type: config
  input:
    log-level: none
    log-key:
      key-name: module-mgr
      log-level: info

The bitd-agent configuration file

The bitd-agent configuration can be specified either in yaml or xml format. In this section, we will describe the yaml version of the configuration file. All the examples in this section can be converted to xml using the test-object unit tester tool. (Run test-object -h for options.)

It is easiest to work through the structure of the configuration file through examples. Here is the basic example we will start with:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
modules:
  module-name: bitd-echo
  module-name: bitd-sink-graphite
  module-name: bitd-config-log
task-inst:
  task-name: config-log
  task-inst-name: config-log
  schedule:
    type: config
  input:
    log-level: warn
    log-key:
      key-name: bit-sink-graphite
      log-level: debug
task-inst:
  task-name: echo
  task-inst-name: Echo task inst
  schedule:
    type: random
    interval: 1s
  args:
    name-int64: -128
    name-int64-2: 127
task-inst:
  task-name: sink-graphite
  task-inst-name: Graphite sink inst
  schedule:
    type: triggered-raw
    task-name: echo
  args:
    server: localhost:2013
    queue-size: 1000

The config file has two types of top-level elemets: modules and task-inst. The task-inst element may be repeated multiple times, and each task-inst contains configuration for a single task instance. The modules element appears only once, and contains a single module-name element per module.

Here is the modules section highlighted:

1
2
3
4
5
6
7
8
modules:
  module-name: bitd-echo
  module-name: bitd-sink-graphite
  module-name: bitd-config-log
task-inst:
  task-name: config-log
  task-inst-name: config-log
  #...

The module-names get translated into DLL names, and the DLLs are loaded into the running bitd-agent. Different platforms have different naming conventions for the module DLLs. The DLL name corresponding to module-name abc is:

  • libabc.so on Unix
  • abc.dll on Win32 Windows
  • cygabc.dll on Cygwin Windows
  • libabc.dylib on OSX

These DLLs must be found in the platform-specific PATH, or must be located in a folder specified using the -lp command line parameter to bitd-agent (see Module load path). Each DLL will implement one or more tasks in the configuration.

Each task-inst block has one task-name element (a task implemented in one of the modules), and a task-inst-name that should be unique per task. Here are the task names and task instance names highlighted:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
modules:
  module-name: bitd-echo
  module-name: bitd-sink-graphite
  module-name: bitd-config-log
task-inst:
  task-name: config-log
  task-inst-name: config-log
  schedule:
    type: config
  input:
    log-level: warn
    log-key:
      key-name: bitd-sink-graphite
      log-level: debug
task-inst:
  task-name: echo
  task-inst-name: Echo task inst
  schedule:
    type: random
    interval: 1s
  args:
    name-int64: -128
    name-int64-2: 127
task-inst:
  task-name: sink-graphite
  task-inst-name: Graphite sink inst
  schedule:
    type: triggered-raw
    task-name: echo
  args:
    server: localhost:2013
    queue-size: 1000

The task instances each have a schedule element. The schedule determines when the task instance will run.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
modules:
  module-name: bitd-echo
  module-name: bitd-sink-graphite
  module-name: bitd-config-log
task-inst:
  task-name: config-log
  task-inst-name: config-log
  schedule:
    type: config
  input:
    log-level: warn
    log-key:
      key-name: bitd-sink-graphite
      log-level: debug
task-inst:
  task-name: echo
  task-inst-name: Echo task inst
  schedule:
    type: random
    interval: 1s
  args:
    name-int64: -128
    name-int64-2: 127
task-inst:
  task-name: sink-graphite
  task-inst-name: Graphite sink inst
  schedule:
    type: triggered-raw
    task-name: echo
  args:
    server: localhost:2013
    queue-size: 1000

Task instance schedule types

The task instance schedule can be of one of these types:

  • periodic: most tasks are periodic. You can specify the task instance run interval at which the task is running. The period is specified by the interval element, which is of the form [number]us|ms|s|m|h|d, where us is microseconds, ms is milliseconds, s is seconds, m is minutes, h is hours, d is days.
  • random: this is similar to periodic, but the start time is random within the period. The interval element specifies the period duration from which the random start is picked.
  • once: these tasks run only once
  • config: these tasks run once when the bitd-agent is initialized, and also each time the config is reloaded. On Unix and OSX, the config is reloaded when the bitd-agent receives a SIGHUP signal. On Windows it’s not possible to reload the config.
  • triggered and triggered-raw: these tasks are triggered by other tasks in the config file, and take as input the output of these other tasks. When a task instance is triggered, it gets only the output of the task instance run that triggered it. When a task instance has a triggered-raw schedule, it gets the tags, run-id, run-timestamp, exit-code, output and error of the task instance run that triggered it.

Modules and tasks

For a listing of the available modules, and for the tasks supported in each module, see Modules.

Configuration model

This section describes configuration files, how they are structured, and how they are represented in C structures. The bitd-agent uses a common object model to describe all types of configuration. It is easier to understand the object model starting with its C language representation, then understand how it is translated into and from yaml and xml.

The bitd-agent configuration file is passed in using the -c argument. The configuration file can be formatted as either yaml or xml. The bitd-agent uses utilities in the libbitd library to parse the configuration into C data types, then runs the configured task instances, and converts back the output of task instances from C data type format to yaml or xml.

Understanding the conversion mechanism between yaml, xml and C data types, thus, facilitates working with the bitd-agent.

The C object model

Look at the include/bitd/platform-types.h header for the data types defined below. The primary C data types are:

bitd_void

bitd_void represents the empty type, and is defined as the C type void.

bitd_boolean

bitd_boolean is defined as signed char, and holds FALSE as 0 and TRUE as any non-zero value.

bitd_int64, bitd_uint64

bitd_int64, bitd_uint64 are unsigned and signed 64 bit data types, defined as long long, resp. unsigned long long on all platforms where long long is 64 bits.

The header file defines, in similar vein, data types for smaller width integers: bitd_int8, bitd_uint8, bitd_int16, bitd_uint16, bitd_int32, bitd_uint32. While these types are used frequently in the source code, the Bitdribble object model represents all integers parsed from yaml or xml as either bitd_int64 or bitd_uint64, for simplicity.

bitd_double

bitd_double is mapped to the C language double float type. No bitd_float type is defined - we use bitd_double instead.

The composite data types for C objects are:

bitd_string

bitd_string is used for NULL-terminated char * strings.

bitd_blob

bitd_blob holds arbitray buffers that may contain the character 0. The bitd_blob contains a 4 byte length field followed by the actual blob payload.

/* The blob type */
typedef struct {
    bitd_uint32 nbytes;
} bitd_blob;

#define bitd_blob_size(b) ((b)->nbytes)
#define bitd_blob_payload(b) ((char *)(((bitd_blob *)b)+1))

Nvp arrays

bitd_nvp_t holds an array of name-value pairs, each element of which has its own type. In short, this type is called an nvp array. Elements in an nvp array can have any simple or composite type, including the nvp array type itself.

/* Forward declaration */
struct bitd_nvp_s;

/* Enumeration of types */
typedef enum {
    bitd_type_void,
    bitd_type_boolean,
    bitd_type_int64,
    bitd_type_uint64,
    bitd_type_double,
    bitd_type_string,
    bitd_type_blob,
    bitd_type_nvp,
    bitd_type_max
} bitd_type_t;

/* Untyped value */
typedef union {
    bitd_boolean value_boolean;
    bitd_int64 value_int64;
    bitd_uint64 value_uint64;
    bitd_double value_double;
    bitd_string value_string;
    bitd_blob *value_blob;
    struct bitd_nvp_s *value_nvp;
} bitd_value_t;

/* A name-value-pair element - or 'nvp element' */
typedef struct {
    char *name;
    bitd_value_t v;
    bitd_type_t type;
} bitd_nvp_element_t;

/* A name-value-pair array - or 'nvp' */
typedef struct bitd_nvp_s {
    int n_elts;
    int n_elts_allocated;
    bitd_nvp_element_t e[1]; /* Array of named objects */
} *bitd_nvp_t;

Objects

The bitd_object_t type holds any arbitrary typed value:

/* An object is a typed value */
typedef struct {
    bitd_value_t v;
    bitd_type_t type;
} bitd_object_t;

Any object, thus, can be represented as bitd_object_t. This means objects can be bitd_boolean, or bitd_int64, or of nvp type. And, since nvp` is an array type, the objects of type nvp can be thought of as arrays of other objects.

The Json object model

For the definition of json, see https://www.json.org. Simple bitdribble types are represented in json as follows:

bitd_void

bitd_void is formatted as the null json value, and the null json value is represented as a bitd_void type.

bitd_boolean

bitd_boolean TRUE is represented in json as true, and bitd_boolean FALSE as false. Conversely, json true, false are respectively represented as bitd_boolean values TRUE and FALSE.

bitd_int64 and bitd_uint64

bitd_int64 and bitd_uint64 are represented in json as numeric integers, except when the bitd_uint64 value is larger than LONG_MAX, in which case it is represented as a string. When bitd_uint64 is represented as string, the key name is appended the suffix _!!uint64.

Conversely, numeric json integers are represented as bitd_int64, or if the key name has a _!!uint64 suffix, as a bitd_uint64.

bitd_double

bitd_double is represented in json as a numeric string formatted as a floating point number, in decimal format. Numeric strings in json that have a floating point, or are outside of the int64 and uint64 range are represented in C as bitd_double.

Composite bitdribble types are represented in json as follows:

bitd_string

bitd_string is represented in json as a string. Json strings that are non-void, non-numeric, and do not have a key suffix of _!!uint64 or _!!blob format are represented as bitd_string.

bitd_blob

bitd_blob types are represented in json as base64 encoded strings, with a key name that gets appended a _!!blob suffix. Conversely, json values of string type with a key name suffix of _!!blob are base64 decoded and represented as bitd_blob types.

Nvp arrays

bitd_nvp_t types are represented as json object, if at least one of the element names are non-NULL and a non-zero-length string - and as a json array otherwise. A json object is represented as nvp array, and a json array is represented as nvp array with NULL-named elements.

Objects

The bitd_object_t type is represented in json simply by representing the underlying type and value of the object in json. Conversely, a json object is represented by a bitd_object_t type.

This sets a correspondence between bitd_object_t objects and json objects that is onto, in a mathematical sense: any json object corresponds to one or more bitd_object_t objects.

Using Json attributes

The bitd_object_t type can be implied from the json value type, but can also be set explicitly in the json object by appending _!!<type> to the key name corresponding to the json value. Here the <type> is any of void, boolean, int64, uint64, double, string, blob or nvp.

The source code

The implementation of the json object model is in src/libs/bitd/types-json.c.

The Xml object model

For an introduction to xml, see https://en.wikipedia.org/wiki/XML. For a quick introduction, xml documents emply angle brackets to delineate element names and element content. Elements can have zero or more attributes:

<?xml version='1.0'?>
<root-element-name>
  <element-name1/>
  <element-name2>127</element-name2>
  <element-name3 attribute1='value1' attribute2='value2'>abc</element-name3>
  <element-name4>
    <embedded-element-name5 attribute1='value1'>def</embedded-element-name5>
  </element-name4>
</root-element-name>

The order of attributes is not important in an element, but the order of subelements matters - in the sense that changing the attribute order does not change the xml document, but changing the element order does change the xml document.

We will describe a partial correspondence between xml documents and named bitdribble objects. The root-element-name corresponds to the name of the object. Each element-name corresponds to the name of a value in an nvp name-value pair array. If no attribute is specified, the type of the content is inferred:

  • If the element is empty, the type is bitd_void.
  • If the element is the string TRUE, True, true, FALSE, False or false, the type is bitd_boolean.
  • If the element is numeric string, the type is bitd_int64 if an integer between LLONG_MIN and LLONG_MAX, otherwise bitd_uint64 if an integer between LLONG_MAX+1 and ULLONG_MAX, and otherwise a bitd_double.
  • If the element is any other string, the type is bitd_string.
  • If the element has sub-elements, the type is bitd_nvp_t.

Using specific xml attributes changes the type of the element:

  • If the element has an attribute named type with value void, respectively boolean, int64, uint64, double, string, the type is bitd_void, respectively bitd_boolean, bitd_int64, bitd_uint64, bitd_double, bitd_string.
  • If the element has the attribute type='blob', the value is interpreted to be a base64 encoded bitd_blob.
  • If the element has the attribute type='nvp', the value is interpreted to be of type bitd_nvp_t.

The converse correspondence is described below:

bitd_void

bitd_void types are represented as empty xml elements. Optionally, these elements can be assigned a type='void' attribute.

<element-name/>
<!-- or -->
<element-name type='void'/>

bitd_boolean

bitd_boolean types are represented as xml elements having the TRUE or FALSE boolean value as contents. Optionally, these elements can be assigned a type='boolean' attribute.

<element-name>FALSE</element-name>
<!-- or -->
<element-name type='boolean'>FALSE</element-name>

bitd_int64

bitd_int64 types are represented as xml elements having as contents the integer value. Optionally, these elements can be assigned a type='int64' attribute. If the integer is between LLONG_MIN and LLONG_MAX, the attribute can be omitted.

<element-name>123</element-name>
<!-- or -->
<element-name type='int64'>123</element-name>

bitd_uint64

bitd_uint64 types are also represented as xml elements having as contents the integer value. Optionally, these elements can be assigned a type='uint64' attribute. If the integer is between LLONG_MAX+1 and ULLONG_MAX, the attribute can be omitted.

<element-name>18446744073709551615</element-name>
<!-- or -->
<element-name type='uint64'>123</element-name>

bitd_double

bitd_double types are represented as xml elements having as contents the numeric value. Optionally, these elements can be assigned a type='double' attribute. If the number has a decimal point or is not a bitd_int64 or bitd_uint64, the attribute can be omitted.

<element-name>123.1</element-name>
<!-- or -->
<element-name>123.0</element-name>
<!-- or -->
<element-name type='double'>123</element-name>
<!-- but not -->
<element-name>123</element-name><!-- ...which would be interpreted as int64 -->

bitd_string

bitd_string types are represented as xml elements having as contents the string value. Optionally, these elements can be assigned a type='string' attribute. If the value cannot be interpreted as a bitd_void, bitd_boolean, bitd_int64, bitd_uint64, bitd_double, then the attribute can be omitted.

<element-name>abc</element-name>
<!-- or -->
<element-name type='string'>abc</element-name>
<!-- but not -->
<element-name></element-name><!-- ...which would be interpreted as void -->
<!-- and not -->
<element-name>TRUE</element-name><!-- ...which would be interpreted as boolean -->
<!-- and not -->
<element-name>123</element-name><!-- ...which would be interpreted as int64 -->
<!-- and not -->
<element-name>123.0</element-name><!-- ...which would be interpreted as double -->

bitd_blob

bitd_blob types are represented as xml elements having as contents the base64 encoded blob. These elements must be assigned a type='blob' attribute, to be distinguished from other strings. The attribute can never be omitted.

<element-name type='blob'>MDEyMzQ1Njc4OQo=</element-name>

To find out to which blob contents this corresponds, you can uudecode it as follows:

$ echo MDEyMzQ1Njc4OQo= | base64 -d
0123456789

bitd_nvp

bitd_nvp types are name-value pair arrays and are represented as xml elements with subelements. Here is, for example, an nvp with elements of all possible types:

<?xml version='1.0'?>
<nvp type='nvp'>
  <name-void type='void'/>
  <name-boolean type='boolean'>FALSE</name-boolean>
  <name-int8 type='int64'>-128</name-int8>
  <name-int8 type='int64'>127</name-int8>
  <name-uint8 type='int64'>255</name-uint8>
  <name-int16 type='int64'>-32768</name-int16>
  <name-int16 type='int64'>32767</name-int16>
  <name-uint16 type='int64'>65535</name-uint16>
  <name-int32 type='int64'>-2147483648</name-int32>
  <name-int32 type='int64'>2147483647</name-int32>
  <name-uint32 type='int64'>4294967295</name-uint32>
  <name-int64 type='int64'>-9223372036854775808</name-int64>
  <name-int64 type='int64'>9223372036854775807</name-int64>
  <name-uint64 type='uint64'>18446744073709551615</name-uint64>
  <name-double type='double'>100000.0</name-double>
  <name-string type='string'/>
  <name-string type='string'>True</name-string>
  <name-string type='string'>123</name-string>
  <name-string type='string'>123.0</name-string>
  <name-string type='string'>string-value</name-string>
  <name-blob type='blob'>MDEyMzQ1Njc4OQo=</name-blob>
  <empty-nvp-value type='nvp'/>
  <full-nvp-value type='nvp'>
    <name-void type='void'/>
    <name-boolean type='boolean'>FALSE</name-boolean>
    <name-int8 type='int64'>-127</name-int8>
    <name-uint8 type='int64'>255</name-uint8>
    <name-int16 type='int64'>-32767</name-int16>
    <name-uint16 type='int64'>65535</name-uint16>
    <name-int32 type='int64'>-2147483647</name-int32>
    <name-uint32 type='int64'>4294967295</name-uint32>
    <name-int64 type='int64'>-9223372036854775807</name-int64>
    <name-uint64 type='uint64'>18446744073709551615</name-uint64>
    <name-double type='double'>1.99</name-double>
    <name-string type='string'/>
    <name-string type='string'>True</name-string>
    <name-string type='string'>123</name-string>
    <name-string type='string'>123.0</name-string>
    <name-string type='string'>string-value</name-string>
    <name-blob type='blob'>MDEyMzQ1Njc4OQo=</name-blob>
    <empty-nvp-value type='nvp'/>
  </full-nvp-value>
</nvp>

If the nvp is named, the name will be stored as the xml root element name. If the nvp is unnamed, or has an empty name, by convention the root element name is set to nvp - as was the case in the example above. Here is the same xml document leaving out all type attributes that are optional (meaning that the type of the contents can be inferred from the value of the contents):

<?xml version='1.0'?>
<nvp>
  <name-void/>
  <name-boolean>FALSE</name-boolean>
  <name-int8>-128</name-int8>
  <name-int8>127</name-int8>
  <name-uint8>255</name-uint8>
  <name-int16>-32768</name-int16>
  <name-int16>32767</name-int16>
  <name-uint16>65535</name-uint16>
  <name-int32>-2147483648</name-int32>
  <name-int32>2147483647</name-int32>
  <name-uint32>4294967295</name-uint32>
  <name-int64>-9223372036854775808</name-int64>
  <name-int64>9223372036854775807</name-int64>
  <name-uint64>18446744073709551615</name-uint64>
  <name-double>100000.0</name-double>
  <name-string type='string'/>
  <name-string type='string'>True</name-string>
  <name-string type='string'>123</name-string>
  <name-string type='string'>123.0</name-string>
  <name-string>string-value</name-string>
  <name-blob type='blob'>MDEyMzQ1Njc4OQo=</name-blob>
  <empty-nvp-value type='nvp'/>
  <full-nvp-value>
    <name-void/>
    <name-boolean>FALSE</name-boolean>
    <name-int8>-127</name-int8>
    <name-uint8>255</name-uint8>
    <name-int16>-32767</name-int16>
    <name-uint16>65535</name-uint16>
    <name-int32>-2147483647</name-int32>
    <name-uint32>4294967295</name-uint32>
    <name-int64>-9223372036854775807</name-int64>
    <name-uint64>18446744073709551615</name-uint64>
    <name-double>1.99</name-double>
    <name-string type='string'/>
    <name-string type='string'>True</name-string>
    <name-string type='string'>123</name-string>
    <name-string type='string'>123.0</name-string>
    <name-string>string-value</name-string>
    <name-blob type='blob'>MDEyMzQ1Njc4OQo=</name-blob>
    <empty-nvp-value type='nvp'/>
  </full-nvp-value>
</nvp>

The Yaml object model

For a quick introduction to yaml, see https://en.wikipedia.org/wiki/YAML. Simple bitdribble types are represented in yaml as follows:

bitd_void

bitd_void is represented as the empty yaml string. An empty yaml string is represented as a bitd_void type.

bitd_boolean

bitd_boolean is represented as the yaml string TRUE or FALSE. The yaml strings TRUE and FALSE are represented as bitd_boolean.

bitd_int64 and bitd_uint64

bitd_int64 and bitd_uint64 are represented in yaml as numeric strings. Integer in yaml are represented as bitd_int64, if between LLONG_MIN and LLONG_MAX, and bitd_uint64 if between LLONG_MAX+1 and ULLONG_MAX.

bitd_double

bitd_double is represented in yaml as a numeric string formatted as a floating point number, in decimal format. Numeric strings in yaml that are not integers, or are outside of the int64 and uint64 range are represented in C as bitd_double.

Composite bitdribble types are represented in yaml as follows:

bitd_string

bitd_string is represented in yaml as a string. Yaml strings that are non-void, non-numeric, and not TRUE, True, true, FALSE, False or false are represented in C as bitd_string types.

bitd_blob

bitd_blob types are represented in yaml as base64 encoded !!binary types. Conversely, !!binary yaml types are base64 decoded and represented in C as bitd_blob types.

Nvp arrays

bitd_nvp_t types are represented in yaml as non-scalar name-value pairs. Nvp arrays with all elements having NULL names are represented as yaml sequences. Conversely, yaml composite types are represented as nvp arrays, and yaml sequences are represented as nvp arrays with NULL-named elements.

Objects

The bitd_object_t type is represented in yaml simply by representing the underlying type and value of the object in yaml. Conversely, a yaml document is represented by a bitd_object_t type.

This sets a correspondence between objects and yaml documents that is onto, in a mathematical sense: any yaml document corresponds to one or more objects. To see why this correspondence is not also one to one, observe that objects containing a string that is an integer corresponds to a yaml document containing that number’s value, which in turn corresponds to an object of integer type.

Yaml files can also contain a stream of documents. For example, the task instance results output of the bitd-agent is a yaml stream, with each task instance result being its own document. A yaml stream corresponds to an ordered set of C objects.

Using Yaml attributes

As seen above, yaml strings are parsed into bitd_void if empty, or into bitd_boolean if equal to TRUE, True, true, FALSE, False or false, or into bitd_int64 if integers within the LLONG_MIN and LLONG_MAX, or otherwise into bitd_uint64 if between LLONG_MAX+1 and ULLONG_MAX, or otherwise into bitd_double if numeric - or, if none of the above, they are parsed as bitd_string.

This represents the default conversion of yaml string scalars. The conversion can also be controlled by use of the following yaml attributes:

  • tag:yaml.org,2002:null is converted to bitd_void type.
  • tag:yaml.org,2002:bool is converted to bitd_boolean type.
  • tag:yaml.org,2002:int is converted to bitd_int64. The value is truncated if too large.
  • tag:yaml.org,2002:str is converted to bitd_string.
  • tag:yaml.org,2002:binary is converted to bitd_blob.

The source code

The implementation of the yaml object model is in src/libs/bitd/types-yaml.c.

Modules

The following sections detail the types of modules supported.

Config modules

All config modules are of schedule type config, which means that they are executed once on bitd-agent start, and are execute again each time the bitd-agent is reloading its configuration (for example, because it received a Unix SIGHUP signal, or because the bitd-agent is running under systemd control and the following command was executed: systemd reload bitd).

bitd-config-log

The bitd-config-log` module controls the bitd-agent log level. It is configured through the following input parameters:

  • log-level, which controls the global log level. The syntax of the log-level is:
log-level: none|crit|error|info|warn|debug|trace
  • log-key, which can be specified multiple times, and controls a subsystem log level. The syntax of the log-key entry is:
log-key:
  key-name: <key name>
  log-level: none|crit|error|info|warn|debug|trace

Here is an example config-log configuration:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
modules:
  module-name: bitd-config-log
task-inst:
  task-name: config-log
  task-inst-name: Config log task instance
  schedule:
    type: config
  input:
    log-level: info
    log-key:
      key-name: module-mgr
      log-level: trace
    log-key:
      key-name: module-agent
      log-level: none

This will set the module-mgr subsystem log level to trace, the module-agent subsystem log level to none (disabling that subsystem log), and the global log level for all other log messages to info.

Run modules

All run modules can execute periodically (with fixed or random start time), or can execute once.

bitd-echo module

The bitd-echo module supports the echo task.

echo task

The echo task echoes back its args as output. If args is void, it will instead echo back its input as output. Here is an example configuration:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
modules:
  module-name: bitd-echo
task-inst:
  task-name: echo
  task-inst-name: Echo task instance
  schedule:
    type: periodic
    interval: 1s
  args:
    name-int64: -128
    name-int64: 127

Here is the bitd-agent result output:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
$ bitd-agent -c echo.yml
---
tags:
  task: echo
  task-instance: Echo task instance
run-id: 0
run-timestamp: 1539717016893523079
exit-code: 0
output:
  name-int64: -128
  name-int64: 127
---
^C...

The same output will be displayed if the configuration is changed to replace args with input:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
modules:
  module-name: bitd-echo
task-inst:
  task-name: echo
  task-inst-name: Echo task instance
  schedule:
    type: periodic
    interval: 1s
  input:
    name-int64: -128
    name-int64: 127

If both args and input are specified, only args is echoed back as output.

bitd-exec module

The bitd-exec module supports the exec task.

exec task

The exec task spawns a child process and reports as results its exit code, its stdout and stderr. The following parameters can be configured:

  • args holds the following subparameters:

    • command holds the executable command name and arguments. The command name and the arguments are space separated. This parameter is required.

    • command-tmo holds the maximum duration, in seconds, of the child process. If the child process does not exit within the configured command-tmo, it is terminated. This parameter is optional, and can be useful to set a limit to the run duration of the child process.

    • input-type: {auto, string, blob, json, xml, yaml} configures whether the input parameter is formatted as string, blob, json, xml or yaml before being passed as stdin to the child process. If configured as auto, the input will be formatted as yaml, except if input is of blob type, in which case it is formatted as blob. The default value of the parameter is auto.

    • output-type: {auto, string, blob, json, xml, yaml} configures whether the stdout is parsed as string, blob, json, xml or yaml. If configured as auto, the stdout is checked, in order, for json, xml, yaml, string content, and is displayed respectively as json, xml, yaml, string, or, if none of the above applies, as blob. The default value of the parameter is auto.

      The output is considered to be json, xml or yaml if the json, xml, respectively the yaml parser encounters no error. It is considered to be string format if it contains no NULL characters aside from the NULL termination.

    • error-type: {auto, string, blob, json, xml, yaml} configures whether the stderr is parsed as string, blob, json, xml or yaml. If configured as auto, the stderr is checked, in order, for json, xml, yaml, string content, and is displayed respectively as xml, yaml, string, or, if none of the above applies, as blob. The default value of the parameter is auto.

  • The input parameter is passed as standard input to the child process. The format of the stdin buffer is determined by the args.input-type parameter.

The task instance tags are passed down to the child process as environment variables. Recall that tags can be task instance scoped, module scoped, or globally scoped at the level of the configuration file. Tags from all three scopes are merged together, with module scope tags taking precedence over global scoped tags, and task instance scoped tags taking precedence over module scope tags.

The shell child process will have an exit code, and will output stdout and stderr:

  • The exit code is reported back as the exit-code result.
  • The stdout is reported back as the output result. The args.output-type parameter controls how stdout is parsed.
  • The stderr is reported back as the error result. The args.error-type parameter controls how stdout is parsed.

The shell command is specified by the command subparameter of args:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
modules:
  module-name: bitd-exec
task-inst:
  task-name: exec
  task-inst-name: Exec task instance
  schedule:
    type: periodic
    interval: 1s
  args:
    command: echo hi

Here is the output of this configuration file:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
$ bitd-agent -c exec.yml
---
tags:
  task: echo
  task-instance: Exec task instance
run-id: 0
run-timestamp: 1539717825481153340
exit-code: 0
output: hi
---
^C...

Here is an example with output sent both to stdout and stderr, and with a non-zero exit code:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
modules:
  module-name: bitd-exec
task-inst:
  task-name: exec
  task-inst-name: Exec task instance
  schedule:
    type: periodic
    interval: 1s
  args:
    command: echo hi; echo ho >&2; exit 3

And the output is:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
$ bitd-agent -c exec.yml
---
tags:
  task: echo
  task-instance: Exec task instance
run-id: 0
run-timestamp: 1539718218405943930
exit-code: 3
output: hi
error: ho
---
^C...

Demo setup

Demo in the Google Cloud

You will need the bitd-<version>-<platform>.rpm for this demo. On your google cloud account, create a VM instance of*small* type (1 shared VCPU, 1.7GB memory) with a CentOS 7 boot disk. Open an ssh connection in browser window.

Install docker

Install docker with instructions from https://www.digitalocean.com/community/tutorials/how-to-install-and-use-docker-on-centos-7

sudo yum check-update
mkdir docker; cd docker
curl -fsSL https://get.docker.com/ | sh
sudo systemctl start docker
sudo systemctl enable docker
sudo usermod -aG docker $(whoami)

Log out, and log back in for the last command to take effect. Check that docker is running as non-root user:

docker run hello-world

Install Graphite and Grafana

Execute these docker commands:

docker run -d \
     --name graphite \
     --restart=always \
     -p 80:80 \
     -p 2003-2004:2003-2004 \
     -p 2023-2024:2023-2024 \
     -p 8125:8125/udp \
     -p 8126:8126 \
     graphiteapp/graphite-statsd
docker run -d \
     --name grafana \
     --restart=always \
     -p 3000:3000 \
     grafana/grafana

If you open the external IP of the host, you should see your Graphite server. The Grafana server is opened at port 3000, and that has to be manually opened in the Google Cloud,

Log into Grafana, and set up Graphite as a data source. The HTTP URL for Graphite should be http://ip-address-of-host, rather than http://localhost (because Grafana is running inside a Docker container, and it needs to reach to the host side IP to access Graphite).

Install the bitdribble rpm

Use scp to transfer bitd-<version>-<platform>.rpm to the host. You will need to install libyaml first:

sudo yum install libyaml
sudo rpm -ivh bitd-<version>-<platform>.rpm

Edit the config file /etc/bitd.yml to enable the tasks you are running. Enable and start the service:

sudo systemctl start bitd
sudo systemctl enable bitd

Log messages are sent to /var/log/bitd. You can enable log messages and log levels in /etc/bitd.yml.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
modules:
  module-name: bitd-config-log
task-inst:
  task-name: config-log
  task-inst-name: config-log
  schedule:
    type: config
  input:
    log-level: trace
    log-key:
      key-name: bitd-sink-graphite
      log-level: warn

Possible log levels are none, crit, error, warn, info, debug, trace. The log-key can be used to enable subsystem level logs, assuming you know the key-name of the subsystem. Any change to /etc/bitd.yml requires a server restart:

sudo systemctl reload bitd

We now configure two ping tests, with a periodic schedule, using the bitd-exec module, and a sink task using the bitd-sink-graphite module. The sink task sends results to a graphite database back end configued by the server parameter - in this case, localhost:2003 because the Graphite server is running locally and statsd is listening on TCP port 2003.

To ensure the ping output (and error) is passed as input to the sink, we configure the tag of sink: graphite as parameter to both the ping instances, as well as a parameter to the graphite sink.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
modules:
  module-name: bitd-config-log
  module-name: bitd-exec
  module-name: bitd-sink-graphite
task-inst:
  task-name: config-log
  task-inst-name: config-log
  schedule:
    type: config
  input:
    log-level: trace
    log-key:
      key-name: bitd-sink-graphite
      log-level: warn
task-inst:
  task-name: exec
  task-inst-name: ping_to_localhost
  schedule:
    type: periodic
    interval: 10s
  args:
    command: ping -c 1 localhost|grep rtt|awk '{print $4}'| sed s:/:\ :g|awk '{printf "%.3f", $1}'
    command-tmo: 10
  tags:
    sink: graphite
task-inst:
  task-name: exec
  task-inst-name: ping_to_mit
  schedule:
    type: periodic
    interval: 30s
  args:
    command: ping -c 1 mit.edu|grep rtt|awk '{print $4}'| sed s:/:\ :g|awk '{printf "%.3f", $1}'
    command-tmo: 10
  tags:
    sink: graphite
task-inst:
  task-name: sink-graphite
  task-inst-name: sink-graphite
  schedule:
    type: triggered-raw
  tags:
    sink: graphite
  args:
    server: localhost:2003
    queue-size: 1000000

Again restart the bitd service after editing /etc/bitd.yml.

sudo systemctl reload bitd

The task results can be visualized on the Grafana dashboard at HTTP port 3000. Finally, let’s create two additional curl tasks using the bitd-exec module:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
modules:
  module-name: bitd-config-log
  module-name: bitd-exec
  module-name: bitd-sink-graphite
task-inst:
  task-name: config-log
  task-inst-name: config-log
  schedule:
    type: config
  input:
    log-level: trace
    log-key:
      key-name: bitd-sink-graphite
      log-level: warn
task-inst:
  task-name: exec
  task-inst-name: ping_to_localhost
  schedule:
    type: periodic
    interval: 10s
  args:
    command: ping -c 1 localhost|grep rtt|awk '{print $4}'| sed s:/:\ :g|awk '{printf "%.3f", $1}'
    command-tmo: 10
  tags:
    sink: graphite
task-inst:
  task-name: exec
  task-inst-name: ping_to_mit
  schedule:
    type: periodic
    interval: 30s
  args:
    command: ping -c 1 mit.edu|grep rtt|awk '{print $4}'| sed s:/:\ :g|awk '{printf "%.3f", $1}'
    command-tmo: 10
  tags:
    sink: graphite
task-inst:
  task-name: exec
  task-inst-name: web_to_localhost
  schedule:
    type: periodic
    interval: 10s
  args:
    command: 'curl -w "time_total:  %{time_total}\ndetail: \n  time_namelookup:  %{time_namelookup}\n  time_connect:  %{time_connect}\n  time_appconnect:  %{time_appconnect}\n  time_pretransfer:  %{time_pretransfer}\n  time_redirect:  %{time_redirect}\n  time_starttransfer:  %{time_starttransfer}\n" -Ss --output /dev/null http://localhost:3000'
    command-tmo: 10
  tags:
    sink: graphite
task-inst:
  task-name: exec
  task-inst-name: web_to_mit
  schedule:
    type: periodic
    interval: 30s
  args:
    command: 'curl -w "time_total:  %{time_total}\ndetail: \n  time_namelookup:  %{time_namelookup}\n  time_connect:  %{time_connect}\n  time_appconnect:  %{time_appconnect}\n  time_pretransfer:  %{time_pretransfer}\n  time_redirect:  %{time_redirect}\n  time_starttransfer:  %{time_starttransfer}\n" -Ss --output /dev/null http://mit.edu'
    command-tmo: 10
  tags:
    sink: graphite
task-inst:
  task-name: sink-graphite
  task-inst-name: sink-graphite
  schedule:
    type: triggered-raw
  tags:
    sink: graphite
  args:
    server: localhost:2003
    queue-size: 1000000

Turn again to the Grafana dashboard at port 3000. This is a sample of how results are displayed (requires dashboard configuration):

_images/ping_and_web.png

Indices and tables