Home

Awesome

<p align="center"><img src="./logo.svg?sanitize=true" alt="logo" width="200px" /></p> <h1 align="center">dats</h1>

code style: prettier semantic-release npm (scoped) license

Minimalistic zero-dependencies UDP/TCP statsd client for Node.js

There are times when you have to gather metrics and you want something simple without writing too much boilerplate, dats to your aid!

This client aims to have a simple statsd compliant API with some optional flavour for advanced usage, like: buffered metrics and either UDP/TCP transports!

Supports Node.js >=14.0.0, if you are a Node.js v12 user refer to dats@2.x.x.

Table of Content

<!-- toc --> <!-- tocstop -->

Installation

The package is available at npm.

You can install it with npm

# lastest stable version
$ npm i -S @immobiliarelabs/dats
# latest development version
$ npm i -S @immobiliarelabs/dats@next

or yarn

# lastest stable version
$ yarn add @immobiliarelabs/dats
# latest development version
$ yarn @immobiliarelabs/dats@next

Usage

Generic

import Client from '@immobiliarelabs/dats';

const stats = new Client({
    host: 'udp://someip:someport',
    namespace: 'myGrafanaNamespace',
    // Optionally register a global handler to track errors.
    onError: (error) => {
        processError(error);
    },
});

// Send counter (myGrafanaNamespace.some.toCount)
stats.counter('some.toCount', 3);
stats.counter('some.toCount'); // defaults to 1
stats.counter('some.toCount', 1, 10); // set sampling to 10
// Send timing (myGrafanaNamespace.some.toTime)
stats.timing('some.toTime', 10);
stats.timing('some.toTime', 10, 0.1); // set sampling to 0.1

// Send gauge (myGrafanaNamespace.some.toGauge)
stats.gauge('some.toGauge', 23);

// Send set (myGrafanaNamespace.some.set)
stats.set('some.set', 765);

Namespacing with Hostname/PID

// Scope your stats per hostname and/or pid
import Client from '@immobiliarelabs/dats';

const stats = new Client({
    host: 'udp://someip:someport',
    namespace: 'myGrafanaNamespace.${hostname}.${pid}',
});

// Send counter (myGrafanaNamespace.myMachine.123.some.toCount)
stats.counter('some.toCount', 3);

If the hostname contains any ., the client will replace them with _.

TCP Client

import Client from '@immobiliarelabs/dats';

// TCP usage
const stats = new Client({
    host: 'tcp://someip:someport',
    namespace: 'myGrafanaNamespace.${hostname}.${pid}',
});

// Calling connect is required in TCP environment
await stats.connect();

// Send counter (myGrafanaNamespace.myMachine.123.some.toCount)
stats.counter('some.toCount', 3);

API

This module exports:

Client

The statsd client

new Client(options)

Client.close([cb])

close the client socket

Returns: a Promise if no cb is passed.

Client.connect()

connect the TCP socket. Calling this function is required only on TCP.

Returns: a Promise.

Client.counter(string[, value, sampling])

send a metric of type counter

All sending errors are handled by the onError callback.

Client.timing(string, value[, sampling])

send a metric of type timing

All sending errors are handled by the onError callback.

Client.gauge(string, value)

send a metric of type gauge

All sending errors are handled by the onError callback.

Client.set(string, value)

send a metric of type set

All sending errors are handled by the onError callback.

Dats Mock

Dats exports his mock, you can use it as follow:

import ClientMock from '@immobiliarelabs/dats/dist/mock';

const host = new URL(`udp://127.0.0.1:8232`);
const namespace = 'ns1';
const client = new ClientMock({ host, namespace });

client.gauge('some.metric', 100);
client.set('some.metric', 100);
// metrics is an array with all metrics sent
console.log(client.metrics);
/* stdout:
    [
        'ns1.some.metric:100|g',
        'ns1.some.metric:100|s',
    ]
*/
// Check if a metric is in the metrics array
client.hasSent('ns1.some.metric:100|s'); // -> true
client.hasSent('ns1.some.metric:10|s'); // -> false
client.hasSent(/ns1\.some\.metric:\d+\|s/); // -> true
client.hasSent(/ns1\.some\.test:\d+\|s/); // -> false

// Clean the metrics array with
client.cleanMetrics();
console.log(client.metrics);
/* stdout:
    []
*/

CLI Interface

dats is also exposed as a CLI that can both be installed as a npm global package or a precompiled binary.

The precompile binary can be found in the release section for Linux, MacOS or Windows.

CLI Usage

$ npm i -g @immobiliarelabs/dats
dats --help
# ℹ️  The following are required input flags:
#
#         --host {string} []
#         --port {string} []
#         --type {string} [Metric type can be one of: counter, timing, gauge, set]
#         --prefix {string} [Metric prefix]
#         --namespace {string} [Metric full namespace, use dots `.` to separate metrics]
#         --value {string} [Metric value]
#         --quiet {boolean} [Suppress all console output]
#         --dryRun {boolean} [Metric wont be sent, use for debug]
#
# If unsure of output run the command prepended with `DRY_RUN=1`

datsrc

Every command flag can also be specified in JSON format in the file .datsrc, the process at runtime will search it in the current working directory and merge both file config and flags before running!

{
    "host": "123.123.123.123",
    "port": "1234",
    "prefix": "my_metric_prefix"
}

Pre-compiled binary

If you want to use the precompiled binary get the correct link for your OS in the release section and do the following:

curl https://github.com/immobiliare/dats/releases/download/v{{VERSION_TAG}}/dats-cli-{{VERSION_OS}} -L -o dats-cli
chmod +x dats-cli
./dats-cli

Benchmarks

The automatic benchmarking for every commit can be found at the following links: next and main.

The tests were done using autocannon pointing to an HTTP node.js Server that sends at each request a count metric. With this kind of test, we evaluate how much the library influences the application performance.

Below are reported the benchmarks with the most famous node.js statsd clients:

LIBRARYReq/Sec (97.5th)Req/Sec (avg)
dats4550343174.4
hot-shots4697543319.47
node-statsd1493511632.34
statsd-client4246335790.67
Base5027143312.54

Base is the HTTP server without metrics.

Powered Apps

dats was created by the amazing Node.js team at ImmobiliareLabs, the Tech dept of Immobiliare.it, the #1 real estate company in Italy.

We are currently using dats in our products as well as our internal toolings.

If you are using dats in production drop us a message.

Support & Contribute

Made with ❤️ by ImmobiliareLabs & Contributors

We'd love for you to contribute to dats! If you have any questions on how to use dats, bugs and enhancement please feel free to reach out by opening a GitHub Issue.

License

dats is licensed under the MIT license. See the LICENSE file for more information.