diff --git a/README.md b/README.md index 295496c6..299303b6 100644 --- a/README.md +++ b/README.md @@ -231,7 +231,7 @@ The initialize method takes the following arguments: ### instanceId -As of version 5.0.0, `instanceId` is now automatically generated. +As of version 6.0.0, `instanceId` is now automatically generated. ## Custom strategies diff --git a/src/metrics.ts b/src/metrics.ts index b093ac6e..45d20996 100644 --- a/src/metrics.ts +++ b/src/metrics.ts @@ -6,6 +6,7 @@ import { HttpOptions } from './http-options'; import { suffixSlash, resolveUrl } from './url-utils'; import { UnleashEvents } from './events'; import { getAppliedJitter } from './helpers'; +import { SUPPORTED_SPEC_VERSION } from './repository'; export interface MetricsOptions { appName: string; @@ -31,15 +32,41 @@ interface Bucket { toggles: { [s: string]: { yes: number; no: number; variants: VariantBucket } }; } -interface MetricsData { +declare var Bun: + | { + version: string; + } + | undefined; + +declare var Deno: + | { + version: { + deno: string; + }; + } + | undefined; + +type PlatformName = 'bun' | 'deno' | 'node' | 'unknown'; + +type PlatformData = { + name: PlatformName; + version: string; +}; + +interface BaseMetricsData { appName: string; instanceId: string; + platformName: PlatformName; + platformVersion: string; + yggdrasilVersion: null; + specVersion: string; +} + +interface MetricsData extends BaseMetricsData { bucket: Bucket; } -interface RegistrationData { - appName: string; - instanceId: string; +interface RegistrationData extends BaseMetricsData { sdkVersion: string; strategies: string[]; started: Date; @@ -79,6 +106,8 @@ export default class Metrics extends EventEmitter { private httpOptions?: HttpOptions; + private platformData: PlatformData; + constructor({ appName, instanceId, @@ -107,6 +136,7 @@ export default class Metrics extends EventEmitter { this.timeout = timeout; this.bucket = this.createBucket(); this.httpOptions = httpOptions; + this.platformData = this.getPlatformData(); } private getAppliedJitter(): number { @@ -324,6 +354,10 @@ export default class Metrics extends EventEmitter { appName: this.appName, instanceId: this.instanceId, bucket, + platformName: this.platformData.name, + platformVersion: this.platformData.version, + yggdrasilVersion: null, + specVersion: SUPPORTED_SPEC_VERSION, }; } @@ -353,6 +387,22 @@ export default class Metrics extends EventEmitter { strategies: this.strategies, started: this.started, interval: this.metricsInterval, + platformName: this.platformData.name, + platformVersion: this.platformData.version, + yggdrasilVersion: null, + specVersion: SUPPORTED_SPEC_VERSION, }; } + + private getPlatformData(): PlatformData { + if (typeof Bun !== 'undefined') { + return { name: 'bun', version: Bun.version }; + } else if (typeof Deno !== 'undefined') { + return { name: 'deno', version: Deno.version.deno }; + } else if (typeof process !== 'undefined' && process.versions && process.versions.node) { + return { name: 'node', version: process.versions.node }; + } else { + return { name: 'unknown', version: 'unknown' }; + } + } } diff --git a/src/repository/index.ts b/src/repository/index.ts index aaf509fa..34a05db9 100644 --- a/src/repository/index.ts +++ b/src/repository/index.ts @@ -14,7 +14,7 @@ import { StrategyTransportInterface, } from '../strategy/strategy'; -const SUPPORTED_SPEC_VERSION = '4.3.0'; +export const SUPPORTED_SPEC_VERSION = '4.3.0'; export interface RepositoryInterface extends EventEmitter { getToggle(name: string): FeatureInterface | undefined; diff --git a/src/test/metrics.test.ts b/src/test/metrics.test.ts index 24dea0c1..7d4980ac 100644 --- a/src/test/metrics.test.ts +++ b/src/test/metrics.test.ts @@ -1,6 +1,7 @@ import test from 'ava'; import * as nock from 'nock'; import Metrics from '../metrics'; +import { SUPPORTED_SPEC_VERSION } from '../repository'; let counter = 1; const getUrl = () => `http://test${counter++}.app/`; @@ -555,3 +556,33 @@ test('sendMetrics should backoff on 429 and gradually reduce interval', async (t t.is(metrics.getFailures(), 0); t.is(metrics.getInterval(), metricsInterval); }); + +test('getClientData should include extended metrics', (t) => { + const url = getUrl(); + // @ts-expect-error + const metrics = new Metrics({ + url, + }); + metrics.start(); + + const result = metrics.getClientData(); + t.truthy(result.platformName); + t.truthy(result.platformVersion); + t.true(result.yggdrasilVersion === null); + t.true(result.specVersion === SUPPORTED_SPEC_VERSION); +}); + +test('createMetricsData should include extended metrics', (t) => { + const url = getUrl(); + // @ts-expect-error + const metrics = new Metrics({ + url, + }); + metrics.start(); + + const result = metrics.createMetricsData(); + t.truthy(result.platformName); + t.truthy(result.platformVersion); + t.true(result.yggdrasilVersion === null); + t.true(result.specVersion === SUPPORTED_SPEC_VERSION); +});