Usage Examples - ytyou/ticktock GitHub Wiki

Table of Contents

1 General Information

1.1 Support three protocols, TCP, UDP, and HTTP

1.2 Support Opentsdb protocol: two data point formats, plain and json

1.3 Support InfluxDB line protocol for writes

2 Curl examples with HTTP

2.1 WRITE a data point in Opentsdb plain put protocol

2.2 Write a data point with two tags in Opentsdb plain put protocol

2.3 Write two data points with two tags in Opentsdb plain put protocol

2.4 read a metric with start time

2.5 Read a metric with start & end time

2.6 Read a metric with downsample aggregator

2.6.1 Read with multitags

2.6.2 Read with milliseconds

2.7 Query metric names

2.8 Query by POST request

2.9 Write and read several data points in InfluxDB line protocol

3 Python examples

3.1 Write with TCP

3.2 Write with UDP

3.3 Write with HTTP

4 Java examples

5 C/C++ examples

5.1 TCP client stress test

5.2 Inspect client

5.3 Backfill client

1 General information

1.1 Support three protocols, TCP, UDP, and HTTP

For writes, TickTock supports three protocols, TCP, UDP, and HTTP, at the same time. We will provide examples in the rest of this wiki.

  • TCP:

A reliable streaming protocol providing once and only once semantics. You don't need to worry about if your data will be lost or received more than once in server side. However, keep in mind that TCP write requests will be returned immediately without waiting for server responses. The write requests might fail to be processed by TickTock even though they were received by TickTock server. So we call TCP write async write. You can update port in config, tcp.server.port = 6181,6180

The first one 6181 is for Opentsdb plain put protocol and the second one 6180 is for InfluxDB line protocol. If you use Opentsdb plain put protocol to send writes, use 6181 (i.e., <ticktock>:6181/api/put). If you use InfluxDB line protool for writes, use 6180 (i.e., <ticktockDB>:6180/api/write).

  • UDP:

An unreliable connectionless protocol. Compared with TCP, UDP is faster but less reliable without once and only once semantics, which means that requests might be received multiple times or not at all by TickTock server. As TCP, UDP requests will be returned immediately without waiting for response.
UDP is disabled by default. To enable UDP, you need to set explicitly in config, udp.server.enabled = true. It uses same port as TCP in config, tcp.server.port = 6181

  • HTTP

HTTP is built on top of TCP. Unlike TCP, HTTP requests will not be returned until TickTock server finishes applying the requests, successfully or failed. We call HTTP writes sync writes. It is slower than TCP as it is blocking. Default port: 6182, as controlled by a setting, http.server.port = 6182.

For reads, TickTock only supports HTTP. Please refer to examples below in this wiki.

1.2 Support OpenTSDB protocol: Two data point formats, plain and json

1.2.1 by default, data point in plain format

If you are interested in send data to TickTock yourself, the TCP Server inside TickTock accepts data in the following format by default (default configuration option: --http.request.format=plain):

put <metric-name> <timestamp> <value> <tag1>=<val1> <tag2>=<val2> ...

One data point per line (Note: must be ended with \n), where <timestamp> is Unix timestamp (number of seconds/milliseconds since Epoch. Default is second, as controlled by a setting,tsdb.timestamp.resolution = second), and <value> can be either integer or floating point number. Supported floating point number formats include,

  • Decimal floating point numbers, e.g. 88, +1.23, -0.45, 15e16
  • Hexdecimal floating point numbers, e.g. 0x12, -0x1afp-2

Do not put quotes anywhere, even around metric names, tag names, or tag values. Metric name, tag names, and tag values all cannot contain spaces.

Metric names, tag names, and tag values all has to be ASCII encoded. TickTock does not support unicode, yet.

1.2.2 data point in json format

If you want to use json format in PUT requests as Opentsdb APIs, you can run TickTock with configuration --http.request.format=json. Please refer to User Guide section 2.3.

A simple write in json is like this:

curl -v -XPOST 'http://localhost:6182/api/put' -d '[{"metric":"testM1","value":2.33266,"timestamp":1514779734,"tags":{"host":"foo"}}]'

Compared with plain format:

curl -v -XPOST 'http://localhost:6182/api/put' -d 'put testM1 1514779734 2.33266 host=foo'

We strongly recommend our default format, plain, due to its simplicity and that Json consumes much more processing power.

1.3 Support InfluxDB line protocol for writes

TickTockDB supports InfluxDB line protocol since v0.11-beta. The syntax is:

<measurement>[,<tag_key>=<tag_value>[,<tag_key>=<tag_value>]] <field_key>=<field_value>[,<field_key>=<field_value>] [<timestamp>]

For example:

cpu,host=rpi,id=1 usr=10,sys=20,idle=70 1465839830

TickTockDB provides an endpoint at <ticktockDB>:<port>/api/write for the line protocol. For the port, you can either use 6182 for HTTP or 6180 for TCP (note that the TCP for Opentsdb plain put protocol is 6181).

2 CURL examples with HTTP

2.1 WRITE a data point in Opentsdb plain put protocol

Data point metric name: testM1, tag: host=foo, timestamp: 1633412175, value=123

curl -v -XPOST 'http://localhost:6182/api/put' -d 'put testM1 1633412175 123 host=foo'

Example: write a data point

Note:

  • The Data point will be stored in data files located in a data directory specified as tsdb.data.dir (default: /tmp) in conf/tt.conf.
  • There is a data file (1633392000.1633478400.0) and a metadata file (1633392000.1633478400.meta) in /tmp for the date of the written data point at 1633412175. Each file has a prefix as ., where:
  • fromSecond: the first second of a day
  • toSecond: the first second of the next day

Example: Data and metadata files

  • There may be more than 1 data file for a day if there are more data points than a data file size. They will be postfixed as ".1", ".2", etc. The data file size is determined by tsdb.page.count (each page 4kB) in conf/tt.conf. There will be only meta file for a day no matter how may data files in a day.
  • You can specify the granularity you want to start a new meta file as tsdb.rotation.frequency (default: 1d).

2.2 WRITE a data point with two tags in Opentsdb plain put protocol

Data point metric name: test.cpu.usr, tag: host=foo cpu=1, timestamp: 1633412175, value=123

curl -v -XPOST 'http://localhost:6182/api/put' -d 'put test.cpu.usr 1633412175 123 host=foo cpu=1'

2.3 WRITE two data points with two tags in Opentsdb plain put protocol

Note: please use \n between two put requests, and the $'...' option ('...' does not work as it will treat \n as two chars \ and n instead of NEWLINE).

curl -v -XPOST 'http://localhost:6182/api/put' -d $'put test.cpu.usr 1633412175 123 host=foo cpu=1\nput test.cpu.sys 1633412175 123 host=foo cpu=1\n'

2.4 READ a metric testM1 average value since 1600000000 epoch time (second) to the current time.

curl -v 'http://localhost:6182/api/query?start=1600000000&m=avg:testM1'

Example: query data

Note the avg, time series aggregator. It will aggregate all data points of the related time series at each timestamp to a single data point. In this example, testM1 has only 1 time series (with tag host=foo), so you won't see the difference. But let say, if we insert two data points:

curl -v -XPOST 'http://localhost:6182/api/put' -d 'put testM1 1633412175 123 host=foo'
curl -v -XPOST 'http://localhost:6182/api/put' -d 'put testM1 1633412175 125 host=goo'

Metric testM1 will have two data points from two time series (host=foo and host=goo) at timestamp 1633412175. The above query m=avg:testM1 will return the average value as 124 (i.e, (123+125)/2).

The aggregator options are:

  • avg
  • sum
  • min
  • max
  • p50
  • p90
  • p99
  • p999
  • count

2.5 READ a metric testM1 since 1600000000 epoch time (second) to 1633412176.

curl -v 'http://localhost:6182/api/query?start=1600000000&end=1633412176&m=avg:testM1\{host=foo\}'

Note the end=1633412176. It can be a future epoch time. If you don't specify end (as in Example 2.4 above), it will be set to the current time by default.

Also note the backslash in \{ and \} are escape chars for curl commands in terminal windows. You don't need such backslash chars in binary commands such as python, java, or Postman command. Please look at a python query example below in https://github.com/ytyou/ticktock/wiki/Usage-Examples/#33-write-with-http:

        url = "http://%s:%s/api/query?start=1633412100&m=avg:1m-avg:http.cpu.usr{host=foo}" % (HOST, PORT)
        res = requests.get(url)

Also note that there is no & in between m=avg:testM1 and \{host=foo\}'. If you add a & in between, then anything after & won't be considered as part of query parameters m=aggregator:downsampler:metric{tag1=val1,tag2=val2...}. The results would be like no tags is specified.

2.6 READ a metric cpu.usr with downsample aggregator

curl -v 'http://localhost:6182/api/query?start=1600000000&end=1600000060&m=avg:1m-avg:cpu.usr'

Note the 1m-avg, a downsample aggregator. It will aggregate all data points of the related time series in 1 minute to a single data point. It is different from the time series aggregator avg as explained in Example 2.4. Let say there are 4 data points within 1 minute (from 1600000000 to 1600000060) of cpu.usr:

  • 2 data points from host=foo, one at 1600000000 with value=50 and the other at 1600000030 with value=70,
  • 2 data points from host=goo, one at 1600000000 with value=30 and the other at 1600000030 with value=50,

The query avg:1m-avg:cpu.usr will return a single value 50 at timestamp 1600000000. It will downsample 1m-avg of

  • host=foo as (1600000000, 60) in which 60==(50+70)/2, and
  • host=goo as (1600000000, 40) in which 40==(30+50)/2.

Then it will calculate the avg of host=foo and host=goo as (1600000000, 50) in which 50=(60+40)/2.

You can use, e.g.,

  • 1h-avg, average of all data points in 1 hour
  • 1d-avg, average of all data points in 1 day
  • 1w-avg, average of all data points in 1 week
  • 10m-avg, average of all data points in 10 minutes
  • 10m-count, count of all data points in 10 minutes
  • 10m-max, max value of all data points in 10 minutes

2.6.1 READ a metric cpu.usr with downsample aggregator, and multi tags

curl -v 'http://localhost:6182/api/query?start=1600000000&end=1600000060&m=avg:1m-avg:cpu.usr\{host=goo,cpu=1\}'

2.6.2 READ a metric cpu.usr with downsample aggregator, and multi tags, and result timestamp in millisecond.

If TickTock supports milliseconds in tt.conf, you can get result timestamps in millisecond by specifying 'msResolution=true' in your query:

curl -v 'http://localhost:6182/api/query?start=1600000000&end=1600000060&m=avg:1m-avg:cpu.usr\{host=goo,cpu=1\}&msResolution=true'

2.7 Query metric names

To query existing metric names starting with 'test':

curl -v 'http://localhost:6189/api/suggest?type=metrics&q=test'

It will return, e.g.,

["test.cpu.sys","test.cpu.sys1","test.cpu.usr","test.cpu.usr1"]

2.8 Query by POST request

To query by POST with detailed parameters in request body:

[Yi-MBP ticktock ]$ curl -XPOST http://localhost:6182/api/query -d '{
    "start": 1356998400,
    "end": 1641159300,
    "queries": [
       {
           "aggregator": "avg",
           "metric": "cpu.usr",
           "tags": {
              "host": "*",
              "cpu": "*"
           }
       },
       {
           "aggregator": "avg",
           "metric": "cpu.sys",
           "tags": {
              "host": "*"
           }
       }
    ]
 }'

2.9 Write and read several data points in InfluxDB line protocol

TickTockDB provides an endpoint at <ticktockDB>:<port>/api/write for the line protocol. For the port, you can either use 6182 for HTTP or 6180 for TCP (note that the TCP for Opentsdb plain put protocol is 6181). For example:

// Write two measurements (test.cpu and test.mem) in two lines.
ylin30@raspberrypi:~/ticktock.0.11.1/admin $ curl -XPOST 'http://localhost:6182/api/write' -d $'test.cpu,host=rpi,id=1 usr=10,sys=20,idle=70 1465839830\ntest.mem,host=rpi,id=1 available=1024,free=512,buffer=512 1465839830'
// Query test.cpu and _field=usr
ylin30@raspberrypi:~/ticktock.0.11.1/admin $ curl 'http://localhost:6182/api/query?start=1465839830&m=avg:test.cpu\{_field=usr\}'
[{"metric":"test.cpu","tags":{"_field":"usr","host":"rpi","id":"1"},"aggregateTags":[],"dps":{"1465839830":10.0}}]
// Query test.cpu and _field=sys
ylin30@raspberrypi:~/ticktock.0.11.1/admin $ curl 'http://localhost:6182/api/query?start=1465839830&m=avg:test.cpu\{_field=sys\}'
[{"metric":"test.cpu","tags":{"_field":"sys","host":"rpi","id":"1"},"aggregateTags":[],"dps":{"1465839830":20.0}}]

Please note the keyword _field. It is reserved to identify different fields in the line protocol. You can try two scripts in <ticktock>/admin/ dir.

ylin30@raspberrypi:~/ticktock.0.11.1/admin $ ./write.sh
ylin30@raspberrypi:~/ticktock.0.11.1/admin $ ./query3.sh
[{"metric":"test.measurement","tags":{"_field":"field2","host":"host1","sensor":"sensor1"},"aggregateTags":[],"dps":{"1677959400":2.0}}]
[{"metric":"test.measurement2","tags":{"_field":"field4","host":"host1","sensor":"sensor2"},"aggregateTags":[],"dps":{"1677959400":4.0}}]
ylin30@raspberrypi:~/ticktock.0.11.1/admin $

3 Python Examples

We provide several simple python examples below. If you want to use Python to talk with TickTock, we recommend tcollector, OpenTSDB official collector. If you use Python3, please use our forked version in https://github.com/ylin30/tcollector. The official TCollector has bugs with Python3 and doesn't work.

3.1 WRITE with TCP

This example writes two data points in plain format with TCP request. The code is checked in source code dir as ticktock/api-examples/python/tcp_plain_writer.py.

#!/usr/bin/env python3

import socket
import sys
import time

if len(sys.argv) != 3:
    print("Usage: python tcp_plain_writer.py <host> <port>")
    sys.exit(1);
else:
    HOST = sys.argv[1]
    PORT = int(sys.argv[2])

try:
    s = socket.socket(socket.AF_INET, socket.SOCK_STREAM);
    s.connect((HOST, PORT))
    print('connect to', HOST, PORT)
    put_data_point1 = 'put tcp.cpu.usr 1633412275 20 host=foo cpu=1';
    put_data_point2 = 'put tcp.cpu.sys 1633412275 20 host=foo cpu=1';
    # Note each PUT request must be ended with '\n'
    req = put_data_point1 +'\n'+put_data_point2+'\n';

    s.sendall(req.encode('utf-8'));

    # We need to sleep a few seconds before close the socket in this example.
    # Otherwise TickTock server might not be able to read data as the socket is closed too early.
    time.sleep(5)

    print("Done sending two put reqeuests:\n"+req);
    s.close();
except socket.error as e:
    print("Exception: %s", e)

3.2 WRITE with UDP

This example writes two data points in plain format with UDP request. The code is checked in source code dir as ticktock/api-examples/python/udp_plain_writer.py. Note that you need to enable UDP write in TickTock config, udp.server.enabled = true

#!/usr/bin/env python3

import socket
import sys
import time

if len(sys.argv) != 3:
    print("Usage: python udp_plain_writer.py <host> <port>")
    sys.exit(1);
else:
    HOST = sys.argv[1]
    PORT = int(sys.argv[2])

try:
    s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM);
    s.connect((HOST, PORT))
    print('connect to', HOST, PORT)
    put_data_point1 = 'put udp.cpu.usr 1633412275 20 host=foo cpu=1';
    put_data_point2 = 'put udp.cpu.sys 1633412275 20 host=foo cpu=1';
    # Note each PUT request must be ended with '\n'
    req = put_data_point1 +'\n'+put_data_point2+'\n';

    s.sendall(req.encode('utf-8'));

    # We need to sleep a few seconds before close the socket in this example.
    # Otherwise TickTock server might not be able to read data as the socket is closed too early.
    time.sleep(5)

    print("Done sending two put reqeuests:\n"+req);
    s.close();
except socket.error as e:
    print("Exception: %s", e)

3.3 WRITE with HTTP

This example writes two data points in plain format with HTTP request. The code is checked in source code dir as ticktock/api-examples/python/http_plain_writer.py.

import sys
import requests

PY3 = sys.version_info[0] > 2
if PY3:
    from urllib.request import Request, urlopen # pylint: disable=maybe-no-member,no-name-in-module,import-error
    from urllib.error import HTTPError, URLError # pylint: disable=maybe-no-member,no-name-in-module,import-error
else:
    from urllib2 import Request, urlopen, HTTPError, URLError # pylint: disable=maybe-no-member,no-name-in-module,import-error

if len(sys.argv) != 3:
    print("Usage: python http_plain_writer.py <host> <port>")
    sys.exit(1);
else:
    HOST = sys.argv[1]
    PORT = sys.argv[2]

try:
    url = "http://%s:%s/api/put" % (HOST, PORT)
    req = Request(url)
    req.add_header('Content-type', 'application/text')

    put_data_point1 = 'put http.cpu.usr 1633412175 20 host=foo cpu=1';
    put_data_point2 = 'put http.cpu.sys 1633412175 20 host=foo cpu=1';
    put_req = put_data_point1 +'\n'+put_data_point2+'\n';

    response = urlopen(req, put_req.encode())
    print("Received response:", response.getcode())

    print("To query:");
    url = "http://%s:%s/api/query?start=1633412100&m=avg:1m-avg:http.cpu.usr{host=foo}" % (HOST, PORT)
    res = requests.get(url)
    print(res.text)
    print(res.url)
except HTTPError as e1:
    print("HTTP Exception:", e1)
except URLError as e2:
    print("URL Exception:", e2)

4 Java examples

The example first writes two data points (HTTP in plain format) to TickTock, and then query the data point with HTTP request. The code is checked in source code dir here.

5 C/C++ examples

5.1 TCP client stress test

This example kicks off several threads to stress-test TickTock. Each thread writes data points continually to TickTock with TCP protocol. Data points are in plain format. The code is checked in source code dir as ticktock/tools/client_tcp.c.

5.2 Inspect client

This example inspects TickTock data files and metadata files. The code is checked in source code dir as ticktock/tools/inspect.cpp. If you build with 'make all', there will be a binary in <ticktock>/bin/inspect. Examples:

./inspect /var/ticktock/data/1633392000.1633478400.0
./inspect -a /var/ticktock/data/1633392000.1633478400.0

BTW, metadata files are plain text files. You can open them with, e.g., vim 1633392000.1633478400.meta.

5.3 Backfill client

This example backfills data to TickTock by reading append log files. The code is checked in source code dir as ticktock/tools/backfill.cpp. If you build with 'make all', there will be a binary in <ticktock>/bin/backfill.

⚠️ **GitHub.com Fallback** ⚠️