Skip to content

Commit

Permalink
chore: connect to the cli-repl
Browse files Browse the repository at this point in the history
  • Loading branch information
kmruiz committed Nov 27, 2023
1 parent d24463d commit d7dc58c
Show file tree
Hide file tree
Showing 3 changed files with 46 additions and 45 deletions.
17 changes: 10 additions & 7 deletions packages/cli-repl/src/cli-repl.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ import { promisify } from 'util';
import { getOsInfo } from './get-os-info';
import { UpdateNotificationManager } from './update-notification-manager';
import { markTime } from './startup-timing';
import { SampledAnalytics } from '@mongosh/logging/lib/analytics-helpers';

/**
* Connecting text key.
Expand Down Expand Up @@ -500,13 +501,15 @@ export class CliRepl implements MongoshIOProvider {
} as any /* axiosConfig and axiosRetryConfig are existing options, but don't have type definitions */
);
this.toggleableAnalytics = new ToggleableAnalytics(
new ThrottledAnalytics({
target: this.segmentAnalytics,
throttle: {
rate: 30,
metadataPath: this.shellHomeDirectory.paths.shellLocalDataPath,
},
})
SampledAnalytics.default(
new ThrottledAnalytics({
target: this.segmentAnalytics,
throttle: {
rate: 30,
metadataPath: this.shellHomeDirectory.paths.shellLocalDataPath,
},
})
)
);
}

Expand Down
38 changes: 16 additions & 22 deletions packages/logging/src/analytics-helpers.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -259,31 +259,23 @@ describe('analytics helpers', function () {
properties: { mongosh_version: '1.2.3', session_id: 'abc' },
};

it('should sample by default a 30% of open sessions with an error margin of ±1%', function () {
const expectedPercentage = 30;
// sampling is random based, so we must consider an error margin, for example, ±1%
const errorMargin = 1;

let totalSample = 0;
let enabledSamples = 0;

for (let i = 0; i < 100_000; i++) {
// evenly distributed randoms are more evenly with more samples
totalSample++;
enabledSamples += SampledAnalytics.default(target).enabled ? 1 : 0;
}
afterEach(function () {
delete process.env.MONGOSH_ANALYTICS_SAMPLE;
});

const sampledPercentage = (enabledSamples / totalSample) * 100;
expect(sampledPercentage).to.be.greaterThan(
expectedPercentage - errorMargin
);
expect(sampledPercentage).to.be.lessThan(
expectedPercentage + errorMargin
);
it('should override sampling with the MONGOSH_ANALYTICS_SAMPLE environment variable', function () {
process.env.MONGOSH_ANALYTICS_SAMPLE = 'true';
const analytics = SampledAnalytics.disabledForAll(
target
) as SampledAnalytics;

expect(analytics.enabled).to.be.true;
});

it('should send the event forward when sampled', function () {
const analytics = SampledAnalytics.enabledForAll(target);
const analytics = SampledAnalytics.enabledForAll(
target
) as SampledAnalytics;
expect(analytics.enabled).to.be.true;

analytics.identify(iEvt);
Expand All @@ -293,7 +285,9 @@ describe('analytics helpers', function () {
});

it('should not send the event forward when not sampled', function () {
const analytics = SampledAnalytics.disabledForAll(target);
const analytics = SampledAnalytics.disabledForAll(
target
) as SampledAnalytics;
expect(analytics.enabled).to.be.false;

analytics.identify(iEvt);
Expand Down
36 changes: 20 additions & 16 deletions packages/logging/src/analytics-helpers.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import fs from 'fs';
import path from 'path';
import { performance } from 'perf_hooks';

export type MongoshAnalyticsIdentity =
| {
Expand Down Expand Up @@ -380,7 +381,7 @@ export class ThrottledAnalytics implements MongoshAnalytics {
}

type SampledAnalyticsOptions = {
target: MongoshAnalytics;
target?: MongoshAnalytics;
/**
* Sampling options. If not provided, sampling will be defaulted to 100% of sessions.
* Also, from an exposed environment standpoint, providing a MONGOSH_ANALYTICS_SAMPLE
Expand All @@ -391,40 +392,43 @@ type SampledAnalyticsOptions = {
*/
sampling: {
percentage: number;
samplingFunction: () => number;
samplingFunction: (percentage: number) => boolean;
} | null;
};

export class SampledAnalytics implements MongoshAnalytics {
private isEnabled: boolean;
private target: MongoshAnalytics;

private constructor(private configuration: SampledAnalyticsOptions) {
this.configuration.sampling ??= {
private constructor(configuration: SampledAnalyticsOptions) {
configuration.sampling ??= {
percentage: 30,
samplingFunction: () => Math.random() * 100,
samplingFunction: (percentage) => Math.random() * 100 < percentage,
};

const shouldBeSampled =
this.configuration.sampling.samplingFunction() <=
this.configuration.sampling.percentage;
const shouldBeSampled = configuration.sampling.samplingFunction(
configuration.sampling.percentage
);

this.isEnabled = !!process.env.MONGOSH_ANALYTICS_SAMPLE || shouldBeSampled;
this.target = configuration.target || new NoopAnalytics();
}

static default(target: MongoshAnalytics): SampledAnalytics {
static default(target?: MongoshAnalytics): MongoshAnalytics {
return new SampledAnalytics({ target, sampling: null });
}

static enabledForAll(target: MongoshAnalytics): SampledAnalytics {
static enabledForAll(target?: MongoshAnalytics): MongoshAnalytics {
return new SampledAnalytics({
target,
sampling: { percentage: 100, samplingFunction: () => 1 },
sampling: { percentage: 100, samplingFunction: () => true },
});
}

static disabledForAll(target: MongoshAnalytics): SampledAnalytics {
static disabledForAll(target?: MongoshAnalytics): MongoshAnalytics {
return new SampledAnalytics({
target,
sampling: { percentage: 0, samplingFunction: () => 1 },
sampling: { percentage: 0, samplingFunction: () => false },
});
}

Expand All @@ -433,14 +437,14 @@ export class SampledAnalytics implements MongoshAnalytics {
}

identify(message: AnalyticsIdentifyMessage): void {
this.isEnabled && this.configuration.target.identify(message);
this.isEnabled && this.target.identify(message);
}

track(message: AnalyticsTrackMessage): void {
this.isEnabled && this.configuration.target.track(message);
this.isEnabled && this.target.track(message);
}

flush(callback: (err?: Error | undefined) => void): void {
this.isEnabled && this.configuration.target.flush(callback);
this.isEnabled && this.target.flush(callback);
}
}

0 comments on commit d7dc58c

Please sign in to comment.