mirror of
https://github.com/SigNoz/signoz.git
synced 2025-12-29 16:14:42 +00:00
* feat: add drilldown options in uplot * feat: add time range to timeseries, bar charts * feat: remove unwanted code * feat: minor refactor * feat: drilldown prop drilldowned * feat: refactor code * feat: update click plugin in uplot * feat: lint fix * feat: add search to breakout and other refactor * feat: context menu - increase width and add overlay * feat: add context links * feat: context links init * feat: context links init * feat: context links init * feat: update context link modal form init * feat: add double way sync on urls and param * feat: minor refactor * feat: minor refactor * feat: change contextlinks data structure * feat: context menu changes init * feat: context menu hook refactor * feat: context links processors * feat: context variables hook added * feat: add support for field variables * feat: minor refactor * feat: minor refactor * feat: minor refactor * feat: handle on save * feat: minor refactor * feat: snapshot update * feat: revert qbv5 * feat: aggregation header val * feat: fix header color * feat: minor refactor * feat: minor refactor * feat: fix breaking changes from qb v5 * feat: change api for breakout opitons * feat: minor refactor * feat: minor refactor * fix: added fix for extractquerypararms when value is string in multivalue operator * feat: minor refactor * feat: add back in breakout * feat: minor refactor * feat: add substitute var api call to decode vars * feat: minor fix * feat: optimize query value comparison in QueryBuilderV2 * feat: minor fix * feat: minor fix * feat: test fix * feat: added dynamic variables creation flow (#7541) * feat: added dynamic variables creation flow * feat: added keys and value apis and hooks * feat: added api and select component changes * feat: added keys fetching and preview values * feat: added dynamic variable to variable items * feat: handled value persistence and tab switches * feat: added default value and formed a schema for dyn-variables * feat: added client and server side searches * feat: corrected the initial load getfieldKey api * feat: removed fetch on mount restriction * feat: added dynamic variable to the dashboard details (#7755) * feat: added dynamic variable to the dashboard details * feat: added new component to existing variables * feat: added enhancement to multiselect and select for dyn-variables * feat: added refetch method between all dynamic-variables * feat: correct error handling * feat: correct error handling * feat: enforced non-empty selectedvalues and default value * feat: added client and server side searches * feat: retry on error * feat: correct error handling * feat: handle defautl value in existing variables * feat: lowercase the source for payload * feat: fixed the incorrect assignment of active indices * feat: improved handling of all option * feat: improved the ALL option visuals * feat: handled default value enforcement in existing variables * feat: added unix time to values call * feat: added incomplete data message and info to search * feat: changed dashboard panel call handling with existing variables * feat: adjusted the response type and data with the new API schema for values * feat: code refactor * feat: made dyn-variable option as the default * feat: added test cases for dyn variable creation and completion * feat: updated test cases * feat: added variable in url and made dashboard sync around that and sharable (#7944) * feat: added dynamic variable to the dashboard details * feat: added new component to existing variables * feat: added enhancement to multiselect and select for dyn-variables * feat: added refetch method between all dynamic-variables * feat: correct error handling * feat: correct error handling * feat: enforced non-empty selectedvalues and default value * feat: added client and server side searches * feat: retry on error * feat: correct error handling * feat: handle defautl value in existing variables * feat: lowercase the source for payload * feat: fixed the incorrect assignment of active indices * feat: improved handling of all option * feat: improved the ALL option visuals * feat: handled default value enforcement in existing variables * feat: added unix time to values call * feat: added incomplete data message and info to search * feat: changed dashboard panel call handling with existing variables * feat: adjusted the response type and data with the new API schema for values * feat: code refactor * feat: made dyn-variable option as the default * feat: added test cases for dyn variable creation and completion * feat: updated test cases * feat: added variable in url and made dashboard sync around that and sharable * feat: added test cases * feat: added safety check * feat: enabled url setting on first load itself * feat: code refactor * feat: cleared options query param when on dashboard list page * feat: resolved conflicts * feat: added dynamic variable suggestion in where clause * feat: added test cases for hooks and api call functions * feat: added test case for querybuildersearchv2 suggestion changes * feat: code refactor * feat: updated test case * feat: corrected the regex matcher for resolved titles * feat: added ability to add/remove variable filter to one or more existing panels * feat: added widgetselector on variable creation * feat: show labels in widget selector * feat: added apply to all and variable removal logical * feat: refectch only related and affected panels in case of dynamic variables * feat: added button loader for apply-all * feat: light-mode styles * feat: minor refactor * feat: added test cases * feat: refactor * feat: remove consoles * feat: pass panel types to substitutevars * feat: cross filtering init * fix: added fix for query builder filters * feat: cross filtering add set/unset/create functionality * feat: test update * fix: added migration to filter expression for crud operations of variable * feat: format legend name according to existing format * feat: breakout test init * feat: breakout test match query * feat: context links tests * feat: minor refactor * feat: show edit only if user has access * feat: added dynamic variables creation flow (#7541) * feat: added dynamic variables creation flow * feat: added keys and value apis and hooks * feat: added api and select component changes * feat: added keys fetching and preview values * feat: added dynamic variable to variable items * feat: handled value persistence and tab switches * feat: added default value and formed a schema for dyn-variables * feat: added client and server side searches * feat: corrected the initial load getfieldKey api * feat: removed fetch on mount restriction * feat: added dynamic variable to the dashboard details (#7755) * feat: added dynamic variable to the dashboard details * feat: added new component to existing variables * feat: added enhancement to multiselect and select for dyn-variables * feat: added refetch method between all dynamic-variables * feat: correct error handling * feat: correct error handling * feat: enforced non-empty selectedvalues and default value * feat: added client and server side searches * feat: retry on error * feat: correct error handling * feat: handle defautl value in existing variables * feat: lowercase the source for payload * feat: fixed the incorrect assignment of active indices * feat: improved handling of all option * feat: improved the ALL option visuals * feat: handled default value enforcement in existing variables * feat: added unix time to values call * feat: added incomplete data message and info to search * feat: changed dashboard panel call handling with existing variables * feat: adjusted the response type and data with the new API schema for values * feat: code refactor * feat: made dyn-variable option as the default * feat: added test cases for dyn variable creation and completion * feat: updated test cases * feat: added dynamic variable suggestion in where clause * feat: added test cases for hooks and api call functions * feat: added test case for querybuildersearchv2 suggestion changes * feat: code refactor * feat: updated test case * feat: corrected the regex matcher for resolved titles * feat: added ability to add/remove variable filter to one or more existing panels * feat: added widgetselector on variable creation * feat: show labels in widget selector * feat: added apply to all and variable removal logical * feat: refectch only related and affected panels in case of dynamic variables * feat: added button loader for apply-all * feat: light-mode styles * fix: added migration to filter expression for crud operations of variable * feat: reverted dynamic variable url config changes (#8877) * Revert "feat: changed query param name" This reverts commit 62bee5f003bf74b0da1c5951f1b5d0f2c250905d. * Revert "feat: added user-friendly format to dashboard variable url" This reverts commit 6de8b1c2e8c6a838941014ea4929e9f5c908d975. * feat: reverted url var changes * feat: reverted url changed from usedashboardvarupdate hook * feat: send empty array for widgetId * feat: added type in the variables in query_range payload for dynamic * feat: minor fixes * fix: added fix for multivalue operator without brackets * feat: minor fix * feat: fix failing test * feat: change revert * test: added tests for querycontextUtils + querybuilderv2 utils * fix: added fix for replacing filter with the new value * fix: added fix for replacing filters + datetimepicker composite query * test: fixed querybuilderv2 utils test * feat: handle number dataType in filters * feat: correct the variable addition to panel format for new qb expression * feat: remove other queries in breakout * feat: add metric to traces mapping * feat: pass proper time range * feat: update time range logic * feat: value panel drilldown init * feat: value panel drilldown init * feat: enable context links in value panel * feat: minor fix * feat: update snapshot * feat: hide breakout in value panel * feat: add panel type to view mode * feat: add support to change panel in breakouts * feat: panel change for breakout logic added * chore: fix style * chore: show variables suggestion while creating context links * chore: add timestamp to graphs * chore: add timestamp to table panel * chore: fix failing tests * chore: fix infinite re-rendering due to queryRange * chore: send appropriate time range when signal is metrics * chore: show variables suggestion while creating context links * chore: minor refactor * chore: show trace details link if filter has trace_id * chore: fix infinite render of table component * chore: added tests for v2 * fix: context links set from dropdown * chore: minor refactor * chore: minor refactor * chore: fix test * chore: fix timerange for apm metrics * fix: get correct timestamp for clicked data * chore: comment out change to histogram on breakout by number * chore: change panel type on panel type change in url * chore: remove consoles * feat: added dynamic variables creation flow (#7541) * feat: added dynamic variables creation flow * feat: added keys and value apis and hooks * feat: added api and select component changes * feat: added keys fetching and preview values * feat: added dynamic variable to variable items * feat: handled value persistence and tab switches * feat: added default value and formed a schema for dyn-variables * feat: added client and server side searches * feat: corrected the initial load getfieldKey api * feat: removed fetch on mount restriction * feat: added dynamic variable to the dashboard details (#7755) * feat: added dynamic variable to the dashboard details * feat: added new component to existing variables * feat: added enhancement to multiselect and select for dyn-variables * feat: added refetch method between all dynamic-variables * feat: correct error handling * feat: correct error handling * feat: enforced non-empty selectedvalues and default value * feat: added client and server side searches * feat: retry on error * feat: correct error handling * feat: handle defautl value in existing variables * feat: lowercase the source for payload * feat: fixed the incorrect assignment of active indices * feat: improved handling of all option * feat: improved the ALL option visuals * feat: handled default value enforcement in existing variables * feat: added unix time to values call * feat: added incomplete data message and info to search * feat: changed dashboard panel call handling with existing variables * feat: adjusted the response type and data with the new API schema for values * feat: code refactor * feat: made dyn-variable option as the default * feat: added test cases for dyn variable creation and completion * feat: updated test cases * feat: fix lint and test cases * feat: fix typo * feat: fixed test case * feat: added dynamic variable suggestion in where clause * feat: added test cases for hooks and api call functions * feat: added test case for querybuildersearchv2 suggestion changes * feat: code refactor * feat: corrected the regex matcher for resolved titles * feat: fixed test cases * feat: added ability to add/remove variable filter to one or more existing panels * feat: added widgetselector on variable creation * feat: show labels in widget selector * feat: added apply to all and variable removal logical * feat: refectch only related and affected panels in case of dynamic variables * feat: added button loader for apply-all * feat: light-mode styles * fix: added migration to filter expression for crud operations of variable * feat: added type in the variables in query_range payload for dynamic * feat: correct the variable addition to panel format for new qb expression * feat: added test cases for dynamic variable and add/remove panel feat * feat: implemented where clause suggestion in new qb v5 * feat: added retries for dyn variable and fixed on-enter selection issue * feat: added relatedValues and existing query in param related changes * feat: sanitized data storage and removed duplicates * fix: fixed typechecks * feat: updated panel wait and refetch logic and ALL option selection * feat: fixed variable tabel reordering issue * feat: added empty name validation in variable creation * feat: change value to searchtext in values API * feat: added option for regex in the component, disabled for now * feat: added beta and not rec. tag in variable tabs * feat: added check to prevent api and updates calls with same payload * feat: optimized localstorage for all selection in dynamic variable and updated __all__ case * feat: resolved variable tables infinite loop update error * feat: aded variable name auto-update based on attribute name entered for dynamic variables * feat: modified only/all click behaviour and set all selection always true for dynamic variable * feat: fix dropdown closing doesn't reset us back to our all available values when we have a search * feat: handled all state distinction and carry forward in existing variables * feat: trucate + n more tooltip content to 10 * feat: fixed infinite loop because of dependency of frequently changing object ref in var table * feat: fixed inconsist search implementations * feat: reverted only - all updated area implementation * feat: added more space for search in multiselect component * feat: checked for variable id instead of variable key for refetch * feat: improved performance around multiselect component and added confirm modal for apply to all * feat: rewrite functionality around add and remove panels * feat: changed color for apply to all modal * feat: added changes under flag to handle variable specific removal for removeKeysFromExpression func * feat: added validation in variable edit panel * chore: fix dynamic variable update in context menu to latest logic * chore: minor fix * chore: type fix * fix: remove unwanted code * fix: remove unwanted code * fix: resolved pr comments * fix: minor fix * fix: fix tests * fix: style fix --------- Co-authored-by: Aditya Singh <adityasingh@Adityas-MacBook-Pro.local> Co-authored-by: Abhi Kumar <ahrefabhi@gmail.com> Co-authored-by: SagarRajput-7 <162284829+SagarRajput-7@users.noreply.github.com> Co-authored-by: SagarRajput-7 <sagar@signoz.io>
474 lines
12 KiB
TypeScript
474 lines
12 KiB
TypeScript
import { PieArcDatum } from '@visx/shape/lib/shapes/Pie';
|
|
import { convertFiltersToExpressionWithExistingQuery } from 'components/QueryBuilderV2/utils';
|
|
import {
|
|
initialQueryBuilderFormValuesMap,
|
|
OPERATORS,
|
|
} from 'constants/queryBuilder';
|
|
import ROUTES from 'constants/routes';
|
|
import cloneDeep from 'lodash-es/cloneDeep';
|
|
import {
|
|
BaseAutocompleteData,
|
|
DataTypes,
|
|
} from 'types/api/queryBuilder/queryAutocompleteResponse';
|
|
import {
|
|
IBuilderQuery,
|
|
Query,
|
|
TagFilterItem,
|
|
} from 'types/api/queryBuilder/queryBuilderData';
|
|
import { v4 as uuid } from 'uuid';
|
|
|
|
export function getBaseMeta(
|
|
query: Query,
|
|
filterKey: string,
|
|
): BaseAutocompleteData | null {
|
|
const steps = query.builder.queryData;
|
|
for (let i = 0; i < steps.length; i++) {
|
|
const { groupBy = [] } = steps[i];
|
|
for (let j = 0; j < groupBy.length; j++) {
|
|
if (groupBy[j].key === filterKey) {
|
|
return groupBy[j];
|
|
}
|
|
}
|
|
}
|
|
return null;
|
|
}
|
|
|
|
export const getRoute = (key: string): string => {
|
|
switch (key) {
|
|
case 'view_logs':
|
|
return ROUTES.LOGS_EXPLORER;
|
|
case 'view_metrics':
|
|
return ROUTES.METRICS_EXPLORER;
|
|
case 'view_traces':
|
|
return ROUTES.TRACES_EXPLORER;
|
|
default:
|
|
return '';
|
|
}
|
|
};
|
|
|
|
export const isNumberDataType = (dataType: DataTypes | undefined): boolean => {
|
|
if (!dataType) return false;
|
|
return dataType === DataTypes.Int64 || dataType === DataTypes.Float64;
|
|
};
|
|
|
|
export interface FilterData {
|
|
filterKey: string;
|
|
filterValue: string | number;
|
|
operator: string;
|
|
}
|
|
|
|
// Helper function to avoid code duplication
|
|
function addFiltersToQuerySteps(
|
|
query: Query,
|
|
filters: FilterData[],
|
|
queryName?: string,
|
|
): Query {
|
|
// 1) clone so we don't mutate the original
|
|
const q = cloneDeep(query);
|
|
|
|
// 2) map over builder.queryData to return a new modified version
|
|
q.builder.queryData = q.builder.queryData.map((step) => {
|
|
// Only modify the step that matches the queryName (if provided)
|
|
if (queryName && step.queryName !== queryName) {
|
|
return step;
|
|
}
|
|
|
|
// 3) build the new filters array
|
|
const newFilters = {
|
|
...step.filters,
|
|
op: step?.filters?.op || 'AND',
|
|
items: [...(step?.filters?.items || [])],
|
|
};
|
|
|
|
// Add each filter to the items array
|
|
filters.forEach(({ filterKey, filterValue, operator }) => {
|
|
// skip if this step doesn't group by our key
|
|
const baseMeta = step.groupBy.find((g) => g.key === filterKey);
|
|
if (!baseMeta) return;
|
|
|
|
newFilters.items.push({
|
|
id: uuid(),
|
|
key: baseMeta,
|
|
op: operator,
|
|
value: filterValue,
|
|
});
|
|
});
|
|
|
|
const resolvedFilters = convertFiltersToExpressionWithExistingQuery(
|
|
newFilters,
|
|
step.filter?.expression,
|
|
);
|
|
|
|
// 4) return a new step object with updated filters
|
|
return {
|
|
...step,
|
|
...resolvedFilters,
|
|
};
|
|
});
|
|
|
|
return q;
|
|
}
|
|
|
|
export function addFilterToQuery(query: Query, filters: FilterData[]): Query {
|
|
return addFiltersToQuerySteps(query, filters);
|
|
}
|
|
|
|
export const addFilterToSelectedQuery = (
|
|
query: Query,
|
|
filters: FilterData[],
|
|
queryName: string,
|
|
): Query => addFiltersToQuerySteps(query, filters, queryName);
|
|
|
|
export const getAggregateColumnHeader = (
|
|
query: Query,
|
|
queryName: string,
|
|
): { dataSource: string; aggregations: string } => {
|
|
// Find the query step with the matching queryName
|
|
const queryStep = query?.builder?.queryData.find(
|
|
(step) => step.queryName === queryName,
|
|
);
|
|
|
|
if (!queryStep) {
|
|
return { dataSource: '', aggregations: '' };
|
|
}
|
|
|
|
const { dataSource, aggregations } = queryStep; // TODO: check if this is correct
|
|
|
|
// Extract aggregation expressions based on data source type
|
|
let aggregationExpressions: string[] = [];
|
|
|
|
if (aggregations && aggregations.length > 0) {
|
|
if (dataSource === 'metrics') {
|
|
// For metrics, construct expression from spaceAggregation(metricName)
|
|
aggregationExpressions = aggregations.map((agg: any) => {
|
|
const { spaceAggregation, metricName } = agg;
|
|
return `${spaceAggregation}(${metricName})`;
|
|
});
|
|
} else {
|
|
// For traces and logs, use the expression field directly
|
|
aggregationExpressions = aggregations.map((agg: any) => agg.expression);
|
|
}
|
|
}
|
|
|
|
return {
|
|
dataSource,
|
|
aggregations: aggregationExpressions.join(', '),
|
|
};
|
|
};
|
|
|
|
const getFiltersFromMetric = (metric: any): FilterData[] =>
|
|
Object.keys(metric).map((key) => ({
|
|
filterKey: key,
|
|
filterValue: metric[key],
|
|
operator: OPERATORS['='],
|
|
}));
|
|
|
|
export const getUplotClickData = ({
|
|
metric,
|
|
queryData,
|
|
absoluteMouseX,
|
|
absoluteMouseY,
|
|
focusedSeries,
|
|
}: {
|
|
metric?: { [key: string]: string };
|
|
queryData?: { queryName: string; inFocusOrNot: boolean };
|
|
absoluteMouseX: number;
|
|
absoluteMouseY: number;
|
|
focusedSeries?: {
|
|
seriesIndex: number;
|
|
seriesName: string;
|
|
value: number;
|
|
color: string;
|
|
show: boolean;
|
|
isFocused: boolean;
|
|
} | null;
|
|
}): {
|
|
coord: { x: number; y: number };
|
|
record: { queryName: string; filters: FilterData[] };
|
|
label: string | React.ReactNode;
|
|
} | null => {
|
|
if (!queryData?.queryName || !metric) {
|
|
return null;
|
|
}
|
|
|
|
const record = {
|
|
queryName: queryData.queryName,
|
|
filters: getFiltersFromMetric(metric),
|
|
};
|
|
|
|
// Generate label from focusedSeries data
|
|
let label: string | React.ReactNode = '';
|
|
if (focusedSeries && focusedSeries.seriesName) {
|
|
label = (
|
|
<span style={{ color: focusedSeries.color }}>
|
|
{focusedSeries.seriesName}
|
|
</span>
|
|
);
|
|
}
|
|
|
|
return {
|
|
coord: {
|
|
x: absoluteMouseX,
|
|
y: absoluteMouseY,
|
|
},
|
|
record,
|
|
label,
|
|
};
|
|
};
|
|
|
|
export const getPieChartClickData = (
|
|
arc: PieArcDatum<{
|
|
label: string;
|
|
value: string;
|
|
color: string;
|
|
record: any;
|
|
}>,
|
|
): {
|
|
queryName: string;
|
|
filters: FilterData[];
|
|
label: string | React.ReactNode;
|
|
} | null => {
|
|
const { metric, queryName } = arc.data.record;
|
|
if (!queryName || !metric) return null;
|
|
|
|
const label = <span style={{ color: arc.data.color }}>{arc.data.label}</span>;
|
|
return {
|
|
queryName,
|
|
filters: getFiltersFromMetric(metric), // TODO: add where clause query as well.
|
|
label,
|
|
};
|
|
};
|
|
|
|
/**
|
|
* Gets the query data that matches the aggregate data's queryName
|
|
*/
|
|
export const getQueryData = (
|
|
query: Query,
|
|
queryName: string,
|
|
): IBuilderQuery => {
|
|
const queryData = query?.builder?.queryData?.filter(
|
|
(item: IBuilderQuery) => item.queryName === queryName,
|
|
);
|
|
return queryData[0];
|
|
};
|
|
|
|
/**
|
|
* Checks if a query name is valid for drilldown operations
|
|
* Returns false if queryName is empty or starts with 'F'
|
|
* Note: Checking if queryName starts with 'F' is a hack to know if it's a Formulae based query
|
|
*/
|
|
export const isValidQueryName = (queryName: string): boolean => {
|
|
if (!queryName || queryName.trim() === '') {
|
|
return false;
|
|
}
|
|
return !queryName.startsWith('F');
|
|
};
|
|
|
|
const VIEW_QUERY_MAP: Record<string, IBuilderQuery> = {
|
|
view_logs: initialQueryBuilderFormValuesMap.logs,
|
|
view_metrics: initialQueryBuilderFormValuesMap.metrics,
|
|
view_traces: initialQueryBuilderFormValuesMap.traces,
|
|
};
|
|
|
|
/**
|
|
* TEMP LOGIC - TO BE REMOVED LATER
|
|
* Transforms metric query filters to logs/traces format
|
|
* Applies the following transformations:
|
|
* - Rule 2: operation → name
|
|
* - Rule 3: span.kind → kind
|
|
* - Rule 4: status.code → status_code_string with value mapping
|
|
* - Rule 5: http.status_code type conversion
|
|
*/
|
|
const transformMetricsToLogsTraces = (
|
|
filterExpression: string | undefined,
|
|
): string | undefined => {
|
|
if (!filterExpression) return filterExpression;
|
|
|
|
// ===========================================
|
|
// MAPPING OBJECTS - ALL TRANSFORMATIONS DEFINED HERE
|
|
// ===========================================
|
|
const METRIC_TO_LOGS_TRACES_MAPPINGS = {
|
|
// Rule 2: operation → name
|
|
attributeRenames: {
|
|
operation: 'name',
|
|
},
|
|
|
|
// Rule 3: span.kind → kind with value mapping
|
|
spanKindMapping: {
|
|
attribute: 'span.kind',
|
|
newAttribute: 'kind',
|
|
valueMappings: {
|
|
SPAN_KIND_INTERNAL: '1',
|
|
SPAN_KIND_SERVER: '2',
|
|
SPAN_KIND_CLIENT: '3',
|
|
SPAN_KIND_PRODUCER: '4',
|
|
SPAN_KIND_CONSUMER: '5',
|
|
},
|
|
},
|
|
|
|
// Rule 4: status.code → status_code_string with value mapping
|
|
statusCodeMapping: {
|
|
attribute: 'status.code',
|
|
newAttribute: 'status_code_string',
|
|
valueMappings: {
|
|
// From metrics format → To logs/traces format
|
|
STATUS_CODE_UNSET: 'Unset',
|
|
STATUS_CODE_OK: 'Ok',
|
|
STATUS_CODE_ERROR: 'Error',
|
|
},
|
|
},
|
|
|
|
// Rule 5: http.status_code type conversion
|
|
typeConversions: {
|
|
'http.status_code': 'number',
|
|
},
|
|
};
|
|
// ===========================================
|
|
|
|
let transformedExpression = filterExpression;
|
|
|
|
// Apply attribute renames
|
|
Object.entries(METRIC_TO_LOGS_TRACES_MAPPINGS.attributeRenames).forEach(
|
|
([oldAttr, newAttr]) => {
|
|
const regex = new RegExp(`\\b${oldAttr}\\b`, 'g');
|
|
transformedExpression = transformedExpression.replace(regex, newAttr);
|
|
},
|
|
);
|
|
|
|
// Apply span.kind → kind transformation
|
|
const { spanKindMapping } = METRIC_TO_LOGS_TRACES_MAPPINGS;
|
|
if (spanKindMapping) {
|
|
// Replace attribute name - use word boundaries to avoid partial matches
|
|
const attrRegex = new RegExp(
|
|
`\\b${spanKindMapping.attribute.replace(/\./g, '\\.')}\\b`,
|
|
'g',
|
|
);
|
|
transformedExpression = transformedExpression.replace(
|
|
attrRegex,
|
|
spanKindMapping.newAttribute,
|
|
);
|
|
|
|
// Replace values
|
|
Object.entries(spanKindMapping.valueMappings).forEach(
|
|
([oldValue, newValue]) => {
|
|
const valueRegex = new RegExp(`\\b${oldValue}\\b`, 'g');
|
|
transformedExpression = transformedExpression.replace(valueRegex, newValue);
|
|
},
|
|
);
|
|
}
|
|
|
|
// Apply status.code → status_code_string transformation
|
|
const { statusCodeMapping } = METRIC_TO_LOGS_TRACES_MAPPINGS;
|
|
if (statusCodeMapping) {
|
|
// Replace attribute name - use word boundaries to avoid partial matches
|
|
// This prevents http.status_code from being transformed
|
|
const attrRegex = new RegExp(
|
|
`\\b${statusCodeMapping.attribute.replace(/\./g, '\\.')}\\b`,
|
|
'g',
|
|
);
|
|
transformedExpression = transformedExpression.replace(
|
|
attrRegex,
|
|
statusCodeMapping.newAttribute,
|
|
);
|
|
|
|
// Replace values
|
|
Object.entries(statusCodeMapping.valueMappings).forEach(
|
|
([oldValue, newValue]) => {
|
|
const valueRegex = new RegExp(`\\b${oldValue}\\b`, 'g');
|
|
transformedExpression = transformedExpression.replace(
|
|
valueRegex,
|
|
`${newValue}`,
|
|
);
|
|
},
|
|
);
|
|
}
|
|
|
|
// Note: Type conversions (Rule 5) would need more complex parsing
|
|
// of the filter expression to implement properly
|
|
|
|
return transformedExpression;
|
|
};
|
|
|
|
export const getViewQuery = (
|
|
query: Query,
|
|
filtersToAdd: FilterData[],
|
|
key: string,
|
|
queryName: string,
|
|
): Query | null => {
|
|
const newQuery = cloneDeep(query);
|
|
|
|
const queryBuilderData = VIEW_QUERY_MAP[key];
|
|
|
|
if (!queryBuilderData) return null;
|
|
|
|
let existingFilters: TagFilterItem[] = [];
|
|
let existingFilterExpression: string | undefined;
|
|
if (queryName) {
|
|
const queryData = getQueryData(query, queryName);
|
|
existingFilters = queryData?.filters?.items || [];
|
|
existingFilterExpression = queryData?.filter?.expression;
|
|
}
|
|
|
|
newQuery.builder.queryData = [queryBuilderData];
|
|
|
|
const filters = filtersToAdd.reduce((acc: any[], filter) => {
|
|
// use existing query to get baseMeta
|
|
const baseMeta = getBaseMeta(query, filter.filterKey);
|
|
if (!baseMeta) return acc;
|
|
|
|
acc.push({
|
|
id: uuid(),
|
|
key: baseMeta,
|
|
op: filter.operator,
|
|
value: filter.filterValue,
|
|
});
|
|
|
|
return acc;
|
|
}, []);
|
|
|
|
const allFilters = [...existingFilters, ...filters];
|
|
|
|
const {
|
|
// filters: newFilters,
|
|
filter: newFilterExpression,
|
|
} = convertFiltersToExpressionWithExistingQuery(
|
|
{
|
|
items: allFilters,
|
|
op: 'AND',
|
|
},
|
|
existingFilterExpression,
|
|
);
|
|
|
|
// newQuery.builder.queryData[0].filters = newFilters;
|
|
|
|
newQuery.builder.queryData[0].filter = newFilterExpression;
|
|
|
|
try {
|
|
// ===========================================
|
|
// TEMP LOGIC - TO BE REMOVED LATER
|
|
// ===========================================
|
|
// Apply metric-to-logs/traces transformations
|
|
if (key === 'view_logs' || key === 'view_traces') {
|
|
const transformedExpression = transformMetricsToLogsTraces(
|
|
newFilterExpression?.expression,
|
|
);
|
|
newQuery.builder.queryData[0].filter = {
|
|
expression: transformedExpression || '',
|
|
};
|
|
}
|
|
// ===========================================
|
|
} catch (error) {
|
|
console.error('Error transforming metrics to logs/traces:', error);
|
|
}
|
|
|
|
return newQuery;
|
|
};
|
|
|
|
export function isDrilldownEnabled(): boolean {
|
|
return true;
|
|
// temp code
|
|
// if (typeof window === 'undefined') return false;
|
|
// const drilldownValue = window.localStorage.getItem('drilldown');
|
|
// return drilldownValue === 'true';
|
|
}
|