123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136 |
- import * as Sentry from '@sentry/react';
- import {Client} from 'sentry/api';
- import {experimentConfig, unassignedValue} from 'sentry/data/experimentConfig';
- import ConfigStore from 'sentry/stores/configStore';
- import type {ExperimentKey} from 'sentry/types/experiments';
- import {ExperimentType} from 'sentry/types/experiments';
- import type {Organization} from 'sentry/types/organization';
- import {defined} from 'sentry/utils';
- import localStorage from 'sentry/utils/localStorage';
- // the local storage key that stores which experiments we've logged
- const SENTRY_EXPERIMENTS_KEY = 'logged-sentry-experiments';
- const unitNameMap = {
- organization: 'org_id',
- user: 'user_id',
- } as const;
- type Options = {
- /**
- * The experiment key
- */
- key: ExperimentKey;
- /**
- * The organization for org based experiments
- */
- organization?: Organization;
- };
- /**
- * Log exposure to an experiment.
- *
- * Generally you will want to call this just before the logic to determine the
- * variant or exposure of a particular experiment.
- */
- export default async function logExperiment({key, organization}: Options) {
- // Never log experiments for super users
- const user = ConfigStore.get('user');
- if (user.isSuperuser) {
- return;
- }
- const config = experimentConfig[key];
- if (config === undefined) {
- return;
- }
- const {type, parameter} = config;
- const assignment =
- type === ExperimentType.ORGANIZATION
- ? organization?.experiments?.[key]
- : type === ExperimentType.USER
- ? // @ts-expect-error TS(7053): Element implicitly has an 'any' type because expre... Remove this comment to see the full error message
- user.experiments?.[key]
- : null;
- // Nothing to log if there is no assignment
- if (!defined(assignment)) {
- return;
- }
- // Do not log if the assignment matches the unassigned group constant
- if (assignment === unassignedValue) {
- return;
- }
- const unitId =
- type === ExperimentType.ORGANIZATION
- ? Number(organization?.id)
- : type === ExperimentType.USER
- ? Number(user.id)
- : null;
- // if the value of this experiment matches the stored value, we can
- // skip calling log_exposure
- if (getExperimentLogged(key) === unitId) {
- return;
- }
- const data = {
- experiment_name: key,
- unit_name: unitNameMap[type],
- unit_id: unitId,
- params: {[parameter]: assignment},
- };
- const client = new Client({baseUrl: ''});
- try {
- await client.requestPromise('/_experiment/log_exposure/', {
- method: 'POST',
- data,
- });
- // update local storage with the new experiment we've logged
- setExperimentLogged(key, unitId);
- } catch (error) {
- Sentry.withScope(scope => {
- scope.setExtra('data', data);
- scope.setExtra('error', error);
- Sentry.captureException(new Error('Could not log experiment'));
- });
- }
- }
- const getExperimentsLogged = () => {
- try {
- const localStorageExperiments = localStorage.getItem(SENTRY_EXPERIMENTS_KEY);
- const jsonData: unknown = JSON.parse(localStorageExperiments || '{}');
- if (typeof jsonData === 'object' && !Array.isArray(jsonData) && jsonData !== null) {
- return jsonData;
- }
- } catch (err) {
- // some sort of malformed json
- Sentry.captureException(err);
- }
- // by default, return an empty config
- return {};
- };
- const getExperimentLogged = (key: string) => {
- const experimentData = getExperimentsLogged();
- // @ts-expect-error TS(7053): Element implicitly has an 'any' type because expre... Remove this comment to see the full error message
- return experimentData[key];
- };
- const setExperimentLogged = (key: string, unitId: number | null) => {
- // shouldn't be null but need to make TS happy
- if (unitId === null) {
- return;
- }
- const experimentData = {...getExperimentsLogged(), [key]: unitId};
- localStorage.setItem(SENTRY_EXPERIMENTS_KEY, JSON.stringify(experimentData));
- };
|