Skip to content

Commit

Permalink
Merge pull request #922 from ryanrishi/feature/add-tags
Browse files Browse the repository at this point in the history
feat(client): Add support for tags
  • Loading branch information
simonecorsi authored May 21, 2024
2 parents ddcae01 + 8a753ff commit c92a21e
Show file tree
Hide file tree
Showing 3 changed files with 88 additions and 1 deletion.
3 changes: 2 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,7 @@ This module exports:
- `udpDnsCacheTTL`: Optional. Default `120`. Dns cache Time to live in seconds.
- `onError`: Optional. Default `(err) => void`. Called when there is an error. Allows you to check also send errors.
- `customSocket`: Optional. Default `null`. Custom socket used by the client, this is a feature for mocking we do not recommend using it in production.
- `tags`: Optional Default `null`. If provided, metrics will include tags in the form `#key1:value1,key2:value2`.

#### `Client.close([cb])`

Expand Down Expand Up @@ -328,5 +329,5 @@ If you have any questions on how to use dats, bugs and enhancement please feel f

## License

dats is licensed under the MIT license.
dats is licensed under the MIT license.
See the [LICENSE](./LICENSE) file for more information.
18 changes: 18 additions & 0 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@ export enum Types {

Object.freeze(Types);

export type Tags = { [key: string]: string | null } | string[];

export interface Options {
host?: string | URL;
namespace?: string;
Expand All @@ -30,6 +32,7 @@ export interface Options {
udpDnsCache?: boolean;
udpDnsCacheTTL?: number;
customSocket?: Socket;
tags?: Tags;
}

/**
Expand All @@ -49,6 +52,7 @@ class Client {
protected namespace: string;
protected debug: DebugLogger;
protected isDebug: boolean;
protected tags: string;

constructor({
host,
Expand All @@ -60,6 +64,7 @@ class Client {
debug = null,
onError = () => undefined,
customSocket = null,
tags = null,
}: Options = {}) {
if (typeof namespace !== 'string') {
throw new Error('A namespace string is required');
Expand Down Expand Up @@ -122,6 +127,15 @@ class Client {
this.bufferFlushTimeout = bufferFlushTimeout;
this.timeout = null;
this.timeoutActive = false;
if (tags) {
if (Array.isArray(tags)) {
this.tags = tags.join(',');
} else {
this.tags = Object.keys(tags)
.map((tag) => (tags[tag] ? `${tag}:${tags[tag]}` : tag))
.join(',');
}
}
}

connect(): Promise<boolean> {
Expand All @@ -144,6 +158,10 @@ class Client {
metric += '|@' + sampling;
}

if (this.tags) {
metric += `|#${this.tags}`;
}

return metric;
}
/**
Expand Down
68 changes: 68 additions & 0 deletions test/index.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,23 @@ test('counter with sampling', (t) => {
});
});

test('counter with tags', (t) => {
const host = new URL(`udp://127.0.0.1:${t.context.address.port}`);
const namespace = 'ns1';
const tags = { tag1: 'value1', tag2: null, tag3: 'value3' };
const client = new Client({ host, namespace, tags });
return new Promise<number>((resolve) => {
t.context.server.on('metric', (metric) => {
t.is(
`${namespace}.some.metric:1|c|@10|#tag1:value1,tag2,tag3:value3`,
metric.toString()
);
return resolve(0);
});
client.counter('some.metric', 1, 10);
});
});

test('timing', (t) => {
const host = new URL(`udp://127.0.0.1:${t.context.address.port}`);
const namespace = 'ns1';
Expand All @@ -137,6 +154,23 @@ test('timing with sampling', (t) => {
});
});

test('timing with tags', (t) => {
const host = new URL(`udp://127.0.0.1:${t.context.address.port}`);
const namespace = 'ns1';
const tags = { tag1: 'value1', tag2: null, tag3: 'value3' };
const client = new Client({ host, namespace, tags });
return new Promise<number>((resolve) => {
t.context.server.on('metric', (metric) => {
t.is(
`${namespace}.some.metric:1|ms|@10|#tag1:value1,tag2,tag3:value3`,
metric.toString()
);
return resolve(0);
});
client.timing('some.metric', 1, 10);
});
});

test('gauge', (t) => {
const host = new URL(`udp://127.0.0.1:${t.context.address.port}`);
const namespace = 'ns1';
Expand All @@ -163,6 +197,23 @@ test('gauge should ignore sampling', (t) => {
});
});

test('gauge with tags', (t) => {
const host = new URL(`udp://127.0.0.1:${t.context.address.port}`);
const namespace = 'ns1';
const tags = { tag1: 'value1', tag2: null, tag3: 'value3' };
const client = new Client({ host, namespace, tags });
return new Promise<number>((resolve) => {
t.context.server.on('metric', (metric) => {
t.is(
`${namespace}.some.metric:1|g|#tag1:value1,tag2,tag3:value3`,
metric.toString()
);
return resolve(0);
});
client.gauge('some.metric', 1);
});
});

test('set', (t) => {
const host = new URL(`udp://127.0.0.1:${t.context.address.port}`);
const namespace = 'ns1';
Expand All @@ -189,6 +240,23 @@ test('set should ignore sampling', (t) => {
});
});

test('set with tags', (t) => {
const host = new URL(`udp://127.0.0.1:${t.context.address.port}`);
const namespace = 'ns1';
const tags = { tag1: 'value1', tag2: null, tag3: 'value3' };
const client = new Client({ host, namespace, tags });
return new Promise<number>((resolve) => {
t.context.server.on('metric', (metric) => {
t.is(
`${namespace}.some.metric:1|s|#tag1:value1,tag2,tag3:value3`,
metric.toString()
);
return resolve(0);
});
client.set('some.metric', 1);
});
});

test.serial('hostname substitution', (t) => {
const host = new URL(`udp://127.0.0.1:${t.context.address.port}`);
const namespace = 'ns1.${hostname}';
Expand Down

0 comments on commit c92a21e

Please sign in to comment.