diff --git a/src/metrics.ts b/src/metrics.ts index acfd2ff5..82df00c4 100644 --- a/src/metrics.ts +++ b/src/metrics.ts @@ -57,6 +57,7 @@ type PlatformData = { interface BaseMetricsData { appName: string; instanceId: string; + connectionId: string; platformName: PlatformName; platformVersion: string; yggdrasilVersion: null; @@ -257,6 +258,7 @@ export default class Metrics extends EventEmitter { appName: this.appName, instanceId: this.instanceId, connectionId: this.connectionId, + interval: this.metricsInterval, headers, timeout: this.timeout, httpOptions: this.httpOptions, @@ -360,6 +362,7 @@ export default class Metrics extends EventEmitter { return { appName: this.appName, instanceId: this.instanceId, + connectionId: this.connectionId, bucket, platformName: this.platformData.name, platformVersion: this.platformData.version, @@ -394,6 +397,7 @@ export default class Metrics extends EventEmitter { strategies: this.strategies, started: this.started, interval: this.metricsInterval, + connectionId: this.connectionId, platformName: this.platformData.name, platformVersion: this.platformData.version, yggdrasilVersion: null, diff --git a/src/repository/index.ts b/src/repository/index.ts index a26a612e..90161be0 100644 --- a/src/repository/index.ts +++ b/src/repository/index.ts @@ -430,6 +430,7 @@ Message: ${err.message}`, timeout: this.timeout, instanceId: this.instanceId, connectionId: this.connectionId, + interval: this.refreshInterval, headers, httpOptions: this.httpOptions, supportedSpecVersion: SUPPORTED_SPEC_VERSION, diff --git a/src/request.ts b/src/request.ts index 81d8e41e..bbe40621 100644 --- a/src/request.ts +++ b/src/request.ts @@ -22,6 +22,7 @@ export interface GetRequestOptions extends RequestOptions { connectionId: string; supportedSpecVersion?: string; httpOptions?: HttpOptions; + interval?: number; } export interface Data { @@ -33,6 +34,7 @@ export interface PostRequestOptions extends RequestOptions { appName?: string; instanceId?: string; connectionId?: string; + interval?: number; httpOptions?: HttpOptions; } @@ -66,6 +68,7 @@ type HeaderOptions = { custom?: CustomHeaders; specVersionSupported?: string; connectionId?: string; + interval?: number; }; export const buildHeaders = ({ @@ -76,6 +79,7 @@ export const buildHeaders = ({ custom, specVersionSupported, connectionId, + interval, }: HeaderOptions): Record => { const head: Record = {}; if (appName) { @@ -108,6 +112,10 @@ export const buildHeaders = ({ head['unleash-connection-id'] = connectionId; } + // expressed in milliseconds to match refreshInterval and metricsInterval units + // attach when set explicitly to non-zero value + head['unleash-interval'] = String(interval); + return head; }; @@ -117,6 +125,7 @@ export const post = ({ timeout, instanceId, connectionId, + interval, headers, json, httpOptions, @@ -129,6 +138,7 @@ export const post = ({ appName, instanceId, connectionId, + interval, etag: undefined, contentType: 'application/json', custom: headers, @@ -144,6 +154,7 @@ export const get = ({ timeout, instanceId, connectionId, + interval, headers, httpOptions, supportedSpecVersion, @@ -155,6 +166,7 @@ export const get = ({ headers: buildHeaders({ appName, instanceId, + interval, etag, contentType: undefined, custom: headers, diff --git a/src/test/metrics.test.ts b/src/test/metrics.test.ts index a9f2c817..2fda443b 100644 --- a/src/test/metrics.test.ts +++ b/src/test/metrics.test.ts @@ -89,7 +89,7 @@ test('should sendMetrics and register when metricsInterval is a positive number' test('should sendMetrics', async (t) => { const url = getUrl(); - t.plan(6); + t.plan(7); const metricsEP = nock(url) .post(metricsUrl, (payload) => { t.truthy(payload.bucket); @@ -99,6 +99,7 @@ test('should sendMetrics', async (t) => { 'toggle-x': { yes: 1, no: 1, variants: { 'variant-a': 2 } }, 'toggle-y': { yes: 1, no: 0, variants: {} }, }); + t.deepEqual(payload.connectionId, 'connection-id'); return true; }) .reply(200, ''); @@ -108,6 +109,7 @@ test('should sendMetrics', async (t) => { const metrics = new Metrics({ url, metricsInterval: 50, + connectionId: 'connection-id', }); metrics.count('toggle-x', true); @@ -131,7 +133,8 @@ test('should send correct custom and unleash headers', (t) => .matchHeader('randomKey', randomKey) .matchHeader('unleash-appname', 'appName') .matchHeader('unleash-sdk', /^unleash-client-node:\d+\.\d+\.\d+/) - .matchHeader('unleash-connection-id', 'connectionId'); + .matchHeader('unleash-connection-id', 'connectionId') + .matchHeader('unleash-interval', '50'); const regEP = nockRegister(url) .matchHeader('randomKey', randomKey) .matchHeader('unleash-appname', 'appName') @@ -578,6 +581,7 @@ test('getClientData should include extended metrics', (t) => { // @ts-expect-error const metrics = new Metrics({ url, + connectionId: 'connection-id', }); metrics.start(); @@ -586,6 +590,7 @@ test('getClientData should include extended metrics', (t) => { t.truthy(result.platformVersion); t.true(result.yggdrasilVersion === null); t.true(result.specVersion === SUPPORTED_SPEC_VERSION); + t.deepEqual(result.connectionId, 'connection-id'); }); test('createMetricsData should include extended metrics', (t) => { diff --git a/src/test/repository.test.ts b/src/test/repository.test.ts index ff2de4f2..a3fd63c2 100644 --- a/src/test/repository.test.ts +++ b/src/test/repository.test.ts @@ -197,6 +197,7 @@ test('should request with correct custom and unleash headers', (t) => .matchHeader('randomKey', randomKey) .matchHeader('unleash-appname', appName) .matchHeader('unleash-connection-id', connectionId) + .matchHeader('unleash-interval', '10') .matchHeader('unleash-sdk', /^unleash-client-node:\d+\.\d+\.\d+/) .persist() .get('/client/features') @@ -214,6 +215,7 @@ test('should request with correct custom and unleash headers', (t) => headers: { randomKey, 'unleash-connection-id': 'ignore', + 'unleash-interval': 'ignore', }, mode: { type: 'polling', format: 'full' }, }); diff --git a/src/test/request.test.ts b/src/test/request.test.ts index e178dc42..9cc3250f 100644 --- a/src/test/request.test.ts +++ b/src/test/request.test.ts @@ -21,6 +21,7 @@ test('Correct headers should be included', (t) => { etag: undefined, contentType: undefined, connectionId: 'connectionId', + interval: 10000, custom: { hello: 'world', }, @@ -28,6 +29,7 @@ test('Correct headers should be included', (t) => { t.is(headers.hello, 'world'); t.is(headers['UNLEASH-INSTANCEID'], 'instanceId'); t.is(headers['unleash-connection-id'], 'connectionId'); + t.is(headers['unleash-interval'], '10000'); t.is(headers['unleash-appname'], 'myApp'); t.regex(headers['unleash-sdk'], /^unleash-client-node:\d+\.\d+\.\d+/); });