123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265 |
- import {createContext, useCallback, useContext, useMemo} from 'react';
- import type {
- MetricAggregation,
- MetricMeta,
- MetricsExtractionCondition,
- MetricsExtractionRule,
- MRI,
- } from 'sentry/types/metrics';
- import {aggregationToMetricType} from 'sentry/utils/metrics/extractionRules';
- import {DEFAULT_MRI, parseMRI} from 'sentry/utils/metrics/mri';
- import type {MetricTag} from 'sentry/utils/metrics/types';
- import {useApiQuery} from 'sentry/utils/queryClient';
- import useOrganization from 'sentry/utils/useOrganization';
- import usePageFilters from 'sentry/utils/usePageFilters';
- const Context = createContext<{
- getCondition: (mri: MRI, conditionId: number) => MetricsExtractionCondition | null;
- getConditions: (mri: MRI) => MetricsExtractionCondition[];
- getExtractionRule: (mri: MRI) => MetricsExtractionRule | null;
- getTags: (mri: MRI) => MetricTag[];
- getVirtualMRI: (mri: MRI) => MRI | null;
- getVirtualMRIQuery: (
- mri: MRI,
- aggregation: MetricAggregation
- ) => {
- aggregation: MetricAggregation;
- conditionId: number;
- mri: MRI;
- } | null;
- getVirtualMeta: (mri: MRI) => MetricMeta;
- isLoading: boolean;
- resolveVirtualMRI: (
- mri: MRI,
- conditionId: number,
- aggregation: MetricAggregation
- ) => {aggregation: MetricAggregation; mri: MRI};
- virtualMeta: MetricMeta[];
- }>({
- getVirtualMRI: () => null,
- getVirtualMeta: () => {
- throw new Error('Not implemented');
- },
- getConditions: () => [],
- getCondition: () => null,
- getExtractionRule: () => null,
- getTags: () => [],
- getVirtualMRIQuery: () => null,
- resolveVirtualMRI: (mri, _, aggregation) => ({mri, aggregation}),
- virtualMeta: [],
- isLoading: false,
- });
- export function useVirtualMetricsContext() {
- return useContext(Context);
- }
- interface Props {
- children: React.ReactNode;
- }
- export function createVirtualMRI(rule: MetricsExtractionRule): MRI {
- return `v:custom/${rule.spanAttribute}|${rule.projectId}@${rule.unit}`;
- }
- export function createMRIToVirtualMap(rules: MetricsExtractionRule[]): Map<MRI, MRI> {
- const mriMap = new Map<MRI, MRI>();
- for (const rule of rules) {
- for (const condition of rule.conditions) {
- for (const mri of condition.mris) {
- mriMap.set(mri, createVirtualMRI(rule));
- }
- }
- }
- return mriMap;
- }
- const getMetricsExtractionRulesApiKey = (orgSlug: string, projects: number[]) =>
- [
- `/organizations/${orgSlug}/metrics/extraction-rules/`,
- {
- query: {
- project: projects,
- },
- },
- ] as const;
- const EMPTY_ARRAY: never[] = [];
- export function VirtualMetricsContextProvider({children}: Props) {
- const organization = useOrganization();
- const {selection, isReady} = usePageFilters();
- const {isLoading, data = EMPTY_ARRAY} = useApiQuery<MetricsExtractionRule[]>(
- getMetricsExtractionRulesApiKey(organization.slug, selection.projects),
- {staleTime: 0, enabled: isReady}
- );
- const mriToVirtualMap = useMemo(() => createMRIToVirtualMap(data), [data]);
- const virtualMRIToRuleMap = useMemo(
- () =>
- new Map<MRI, MetricsExtractionRule>(
- data.map(rule => [createVirtualMRI(rule), rule])
- ),
- [data]
- );
- const getVirtualMRI = useCallback(
- (mri: MRI): MRI | null => {
- const virtualMRI = mriToVirtualMap.get(mri);
- if (!virtualMRI) {
- return null;
- }
- return virtualMRI;
- },
- [mriToVirtualMap]
- );
- const getVirtualMeta = useCallback(
- (mri: MRI): MetricMeta => {
- const rule = virtualMRIToRuleMap.get(mri);
- if (!rule) {
- throw new Error('Rule not found');
- }
- return {
- type: 'v',
- unit: rule.unit,
- blockingStatus: [],
- mri: mri,
- operations: rule.aggregates,
- projectIds: [rule.projectId],
- };
- },
- [virtualMRIToRuleMap]
- );
- const getConditions = useCallback(
- (mri: MRI): MetricsExtractionCondition[] => {
- const rule = virtualMRIToRuleMap.get(mri);
- return rule?.conditions || [];
- },
- [virtualMRIToRuleMap]
- );
- const getCondition = useCallback(
- (mri: MRI, conditionId: number) => {
- const rule = virtualMRIToRuleMap.get(mri);
- return rule?.conditions.find(c => c.id === conditionId) || null;
- },
- [virtualMRIToRuleMap]
- );
- const getTags = useCallback(
- (mri: MRI): MetricTag[] => {
- const rule = virtualMRIToRuleMap.get(mri);
- return rule?.tags.map(tag => ({key: tag})) || [];
- },
- [virtualMRIToRuleMap]
- );
- const resolveVirtualMRI = useCallback(
- (
- mri: MRI,
- conditionId: number,
- aggregation: MetricAggregation
- ): {
- aggregation: MetricAggregation;
- mri: MRI;
- } => {
- const rule = virtualMRIToRuleMap.get(mri);
- if (!rule) {
- return {mri: DEFAULT_MRI, aggregation: 'sum'};
- }
- const condition = rule.conditions.find(c => c.id === conditionId);
- if (!condition) {
- return {mri: DEFAULT_MRI, aggregation: 'sum'};
- }
- const metricType = aggregationToMetricType[aggregation];
- let resolvedMRI = condition.mris.find(m => m.startsWith(metricType));
- if (!resolvedMRI) {
- resolvedMRI = mri;
- }
- return {mri: resolvedMRI, aggregation: metricType === 'c' ? 'sum' : aggregation};
- },
- [virtualMRIToRuleMap]
- );
- const getVirtualMRIQuery = useCallback(
- (
- mri: MRI,
- aggregation: MetricAggregation
- ): {
- aggregation: MetricAggregation;
- conditionId: number;
- mri: MRI;
- } | null => {
- const virtualMRI = getVirtualMRI(mri);
- if (!virtualMRI) {
- return null;
- }
- const rule = virtualMRIToRuleMap.get(virtualMRI);
- if (!rule) {
- return null;
- }
- const condition = rule.conditions.find(c => c.mris.includes(mri));
- if (!condition) {
- return null;
- }
- return {
- mri: virtualMRI,
- conditionId: condition.id,
- aggregation: parseMRI(mri).type === 'c' ? 'count' : aggregation,
- };
- },
- [getVirtualMRI, virtualMRIToRuleMap]
- );
- const getExtractionRule = useCallback(
- (mri: MRI) => {
- return virtualMRIToRuleMap.get(mri) ?? null;
- },
- [virtualMRIToRuleMap]
- );
- const virtualMeta = useMemo(
- () => Array.from(virtualMRIToRuleMap.keys()).map(getVirtualMeta),
- [getVirtualMeta, virtualMRIToRuleMap]
- );
- const contextValue = useMemo(
- () => ({
- getVirtualMRI,
- getVirtualMeta,
- getConditions,
- getCondition,
- getExtractionRule,
- getTags,
- getVirtualMRIQuery,
- resolveVirtualMRI,
- virtualMeta,
- isLoading,
- }),
- [
- getVirtualMRI,
- getVirtualMeta,
- getConditions,
- getCondition,
- getExtractionRule,
- getTags,
- getVirtualMRIQuery,
- resolveVirtualMRI,
- virtualMeta,
- isLoading,
- ]
- );
- return <Context.Provider value={contextValue}>{children}</Context.Provider>;
- }
|