Compare commits

..

1 Commits

Author SHA1 Message Date
Vinícius Lourenço
b1cff50fc6 test(flaky): try reduce flakyness by increasing timeout 2026-05-08 10:00:31 -03:00
29 changed files with 250 additions and 511 deletions

View File

@@ -327,11 +327,6 @@ function App(): JSX.Element {
replaysSessionSampleRate: 0.1, // This sets the sample rate at 10%. You may want to change it to 100% while in development and then sample at a lower rate in production.
replaysOnErrorSampleRate: 1.0, // If you're not already sampling the entire session, change the sample rate to 100% when sampling sessions where errors occur.
beforeSend(event) {
// Drop the event if its level is 'warning' or 'info'
if (event.level === 'warning' || event.level === 'info') {
return null;
}
const sessionReplayUrl = posthog.get_session_replay_url?.({
withTimestamp: true,
});

View File

@@ -50,7 +50,6 @@ import {
import { JsonView } from 'periscope/components/JsonView';
import { useAppContext } from 'providers/App/App';
import { AppState } from 'store/reducers';
import { ILogBody } from 'types/api/logs/log';
import { Query, TagFilter } from 'types/api/queryBuilder/queryBuilderData';
import { DataSource, StringOperators } from 'types/common/queryBuilder';
import { GlobalReducer } from 'types/reducer/globalTime';
@@ -218,17 +217,20 @@ function LogDetailInner({
const logBody = useMemo(() => {
if (!isBodyJsonQueryEnabled) {
return (log?.body as string) ?? '';
return log?.body || '';
}
// Feature enabled: body is always a map; message is always a string
const bodyObj = log?.body as ILogBody;
if (!bodyObj) {
return '';
try {
const json = JSON.parse(log?.body || '');
if (typeof json?.message === 'string' && json.message !== '') {
return json.message;
}
return log?.body || '';
} catch (error) {
return log?.body || '';
}
if (bodyObj.message) {
return bodyObj.message;
}
return JSON.stringify(bodyObj);
}, [isBodyJsonQueryEnabled, log?.body]);
const htmlBody = useMemo(

View File

@@ -9,10 +9,7 @@ import { Color } from '@signozhq/design-tokens';
import { Tooltip } from 'antd';
import { VIEW_TYPES } from 'components/LogDetail/constants';
import { DATE_TIME_FORMATS } from 'constants/dateTimeFormats';
import {
getBodyDisplayString,
getSanitizedLogBody,
} from 'container/LogDetailedView/utils';
import { getSanitizedLogBody } from 'container/LogDetailedView/utils';
import { useCopyLogLink } from 'hooks/logs/useCopyLogLink';
// hooks
import { useIsDarkMode } from 'hooks/useDarkMode';
@@ -102,7 +99,7 @@ function RawLogView({
// Check if body is selected
const showBody = selectedFields.some((field) => field.name === 'body');
if (showBody) {
parts.push(`${attributesText} ${getBodyDisplayString(data.body)}`);
parts.push(`${attributesText} ${data.body}`);
} else {
parts.push(attributesText);
}

View File

@@ -2,10 +2,7 @@ import type { ReactElement } from 'react';
import { useMemo } from 'react';
import TanStackTable from 'components/TanStackTableView';
import { DATE_TIME_FORMATS } from 'constants/dateTimeFormats';
import {
getBodyDisplayString,
getSanitizedLogBody,
} from 'container/LogDetailedView/utils';
import { getSanitizedLogBody } from 'container/LogDetailedView/utils';
import { FontSize } from 'container/OptionsMenu/types';
import { FlatLogData } from 'lib/logs/flatLogData';
import { useTimezone } from 'providers/Timezone';
@@ -90,7 +87,7 @@ export function useLogsTableColumns({
? {
id: 'body',
header: 'Body',
accessorFn: (log): string => getBodyDisplayString(log.body),
accessorFn: (log): string => log.body,
canBeHidden: false,
width: { default: '100%', min: 300 },
cell: ({ value, isActive }): ReactElement => (

View File

@@ -56,5 +56,4 @@ export enum QueryParams {
showClassicCreateAlertsPage = 'showClassicCreateAlertsPage',
isTestAlert = 'isTestAlert',
yAxisUnit = 'yAxisUnit',
ruleName = 'ruleName',
}

View File

@@ -10,7 +10,6 @@ import {
AlertThresholdOperator,
} from 'container/CreateAlertV2/context/types';
import { getSelectedQueryOptions } from 'container/FormAlertRules/utils';
import { useSafeNavigate } from 'hooks/useSafeNavigate';
import { ArrowRight } from 'lucide-react';
import { IUser } from 'providers/App/types';
import { Query } from 'types/api/queryBuilder/queryBuilderData';
@@ -411,7 +410,6 @@ export function RoutingPolicyBanner({
notificationSettings,
setNotificationSettings,
}: RoutingPolicyBannerProps): JSX.Element {
const { safeNavigate } = useSafeNavigate();
return (
<div className="routing-policies-info-banner">
<Typography.Text>
@@ -429,10 +427,10 @@ export function RoutingPolicyBanner({
}}
/>
<Button
href={ROUTING_POLICIES_ROUTE}
type="link"
className="view-routing-policies-button"
data-testid="view-routing-policies-button"
onClick={(): void => safeNavigate(ROUTING_POLICIES_ROUTE)}
>
View Routing Policies
<ArrowRight size={14} />

View File

@@ -1,11 +1,9 @@
import { useEffect, useMemo, useState } from 'react';
// eslint-disable-next-line no-restricted-imports
import { useSelector } from 'react-redux';
import { useLocation } from 'react-router-dom';
import YAxisUnitSelector from 'components/YAxisUnitSelector';
import { YAxisSource } from 'components/YAxisUnitSelector/types';
import { PANEL_TYPES } from 'constants/queryBuilder';
import { QueryParams } from 'constants/query';
import { useCreateAlertState } from 'container/CreateAlertV2/context';
import ChartPreviewComponent from 'container/FormAlertRules/ChartPreview';
import PlotTag from 'container/NewWidget/LeftContainer/WidgetGraph/PlotTag';
@@ -41,22 +39,14 @@ function ChartPreview({
const yAxisUnit = alertState.yAxisUnit || '';
const location = useLocation();
const yAxisUnitFromURL = new URLSearchParams(location.search).get(
QueryParams.yAxisUnit,
);
// Only update automatically when creating a new metrics-based alert rule.
// Skip when yAxisUnit was explicitly provided via URL (e.g. from ingestion settings).
// Only update automatically when creating a new metrics-based alert rule
const shouldUpdateYAxisUnit = useMemo(() => {
// Do not update if we are coming to the page from dashboards (we still show warning)
if (source === YAxisSource.DASHBOARDS) {
return false;
}
if (yAxisUnitFromURL) {
return false;
}
return !isEditMode && alertType === AlertTypes.METRICS_BASED_ALERT;
}, [isEditMode, alertType, source, yAxisUnitFromURL]);
}, [isEditMode, alertType, source]);
const selectedQueryName = thresholdState.selectedQuery;
const { yAxisUnit: initialYAxisUnit, isLoading } =

View File

@@ -7,7 +7,6 @@ import {
useEffect,
useMemo,
useReducer,
useRef,
useState,
} from 'react';
import { useLocation } from 'react-router-dom';
@@ -124,8 +123,6 @@ export function CreateAlertProvider(
const location = useLocation();
const queryParams = new URLSearchParams(location.search);
const thresholdsFromURL = queryParams.get(QueryParams.thresholds);
const ruleNameFromURL = queryParams.get(QueryParams.ruleName);
const yAxisUnitFromURL = queryParams.get(QueryParams.yAxisUnit);
const [alertType, setAlertType] = useState<AlertTypes>(() => {
if (isEditMode) {
@@ -157,9 +154,6 @@ export function CreateAlertProvider(
[redirectWithQueryBuilderData],
);
const ruleNameAppliedRef = useRef(false);
const yAxisUnitAppliedRef = useRef(false);
useEffect(() => {
setCreateAlertState({
slice: CreateAlertSlice.THRESHOLD,
@@ -197,29 +191,7 @@ export function CreateAlertProvider(
},
});
}
if (ruleNameFromURL && !ruleNameAppliedRef.current) {
ruleNameAppliedRef.current = true;
setCreateAlertState({
slice: CreateAlertSlice.BASIC,
action: {
type: 'SET_ALERT_NAME',
payload: ruleNameFromURL,
},
});
}
if (yAxisUnitFromURL && !yAxisUnitAppliedRef.current) {
yAxisUnitAppliedRef.current = true;
setCreateAlertState({
slice: CreateAlertSlice.BASIC,
action: {
type: 'SET_Y_AXIS_UNIT',
payload: yAxisUnitFromURL,
},
});
}
}, [alertType, thresholdsFromURL, ruleNameFromURL, yAxisUnitFromURL]);
}, [alertType, thresholdsFromURL]);
useEffect(() => {
if (isEditMode && initialAlertState) {

View File

@@ -268,6 +268,7 @@ describe('ExplorerOptionWrapper', () => {
});
it('should test actual handleExport function with generateExportToDashboardLink and verify useUpdateDashboard is NOT called', async () => {
jest.setTimeout(15000);
const user = userEvent.setup({ pointerEventsCheck: 0 });
// Mock the safeNavigate function

View File

@@ -19,7 +19,6 @@ import {
import { useQueryBuilder } from 'hooks/queryBuilder/useQueryBuilder';
import { GetMetricQueryRange } from 'lib/dashboard/getQueryResults';
import { isArray } from 'lodash-es';
import { getBodyDisplayString } from 'container/LogDetailedView/utils';
import { ChevronDown, ChevronLeft, ChevronRight, Loader2 } from 'lucide-react';
import { IBuilderQuery } from 'types/api/queryBuilder/queryBuilderData';
import { DataSource } from 'types/common/queryBuilder';
@@ -174,7 +173,7 @@ export default function Events({
(event): EventDataType => ({
timestamp: event.timestamp,
severity: event.data.severity_text,
body: getBodyDisplayString(event.data.body),
body: event.data.body,
id: event.data.id,
key: event.data.id,
resources_string: event.data.resources_string,

View File

@@ -443,25 +443,7 @@
.signal-limit-save-discard {
display: flex;
gap: var(--spacing-4);
.signal-limit-save-discard-actions {
display: flex;
align-items: center;
gap: var(--spacing-4);
}
.signal-limit-alert-helper {
display: flex;
align-items: center;
gap: var(--spacing-2);
font-size: var(--paragraph-small-400-font-size);
color: var(--l2-foreground);
border-bottom: 1px dashed var(--l2-foreground);
padding-bottom: 1px;
font-style: italic;
margin-left: var(--spacing-6);
}
gap: 8px;
}
}
}
@@ -493,7 +475,6 @@
.ant-modal-footer {
padding: 16px;
margin-top: 0;
gap: 8px;
display: flex;
justify-content: flex-end;

View File

@@ -3,8 +3,8 @@ import { useTranslation } from 'react-i18next';
import { useHistory } from 'react-router-dom';
import { useCopyToClipboard } from 'react-use';
import { Color } from '@signozhq/design-tokens';
import { Badge, Button } from '@signozhq/ui';
import {
Button,
Col,
Collapse,
DatePicker,
@@ -41,7 +41,6 @@ import {
import { AxiosError } from 'axios';
import { getYAxisFormattedValue } from 'components/Graph/yAxisConfig';
import Tags from 'components/Tags/Tags';
import { UniversalYAxisUnit } from 'components/YAxisUnitSelector/types';
import { SOMETHING_WENT_WRONG } from 'constants/api';
import { DATE_TIME_FORMATS } from 'constants/dateTimeFormats';
import { QueryParams } from 'constants/query';
@@ -99,30 +98,9 @@ const COUNT_MULTIPLIER = {
};
const SIGNALS_CONFIG = [
{
name: 'logs',
usesSize: true,
usesCount: false,
metricName: 'signoz.meter.log.size',
yAxisUnit: UniversalYAxisUnit.BYTES_IEC,
thresholdUnit: UniversalYAxisUnit.GIBIBYTES,
},
{
name: 'traces',
usesSize: true,
usesCount: false,
metricName: 'signoz.meter.span.size',
yAxisUnit: UniversalYAxisUnit.BYTES_IEC,
thresholdUnit: UniversalYAxisUnit.GIBIBYTES,
},
{
name: 'metrics',
usesSize: false,
usesCount: true,
metricName: 'signoz.meter.metric.datapoint.count',
yAxisUnit: UniversalYAxisUnit.COUNT,
thresholdUnit: UniversalYAxisUnit.COUNT,
},
{ name: 'logs', usesSize: true, usesCount: false },
{ name: 'traces', usesSize: true, usesCount: false },
{ name: 'metrics', usesSize: false, usesCount: true },
];
// Using any type here because antd's DatePicker expects its own internal Dayjs type
@@ -416,7 +394,7 @@ function MultiIngestionSettings(): JSX.Element {
notifications.success({
message: 'Ingestion key deleted successfully',
});
void refetchAPIKeys();
refetchAPIKeys();
setIsDeleteModalOpen(false);
},
onError: (error) => {
@@ -448,7 +426,7 @@ function MultiIngestionSettings(): JSX.Element {
notifications.success({
message: 'Ingestion key updated successfully',
});
void refetchAPIKeys();
refetchAPIKeys();
setIsEditModalOpen(false);
},
onError: (error) => {
@@ -488,7 +466,7 @@ function MultiIngestionSettings(): JSX.Element {
setActiveAPIKey(null);
setUpdatedTags([]);
hideAddViewModal();
void refetchAPIKeys();
refetchAPIKeys();
},
onError: (error) => {
showErrorNotification(notifications, error as AxiosError);
@@ -652,14 +630,13 @@ function MultiIngestionSettings(): JSX.Element {
onSuccess: () => {
notifications.success({
message: 'Limit created successfully',
description: "Set up an alert to know when you're close to hitting it.",
});
setActiveSignal(null);
setActiveAPIKey(null);
setIsEditAddLimitOpen(false);
setUpdatedTags([]);
hideAddViewModal();
void refetchAPIKeys();
refetchAPIKeys();
setHasCreateLimitForIngestionKeyError(false);
},
onError: (error: AxiosError<RenderErrorResponseDTO>) => {
@@ -756,14 +733,13 @@ function MultiIngestionSettings(): JSX.Element {
onSuccess: () => {
notifications.success({
message: 'Limit updated successfully',
description: "Set up an alert to know when you're close to hitting it.",
});
setActiveSignal(null);
setActiveAPIKey(null);
setIsEditAddLimitOpen(false);
setUpdatedTags([]);
hideAddViewModal();
void refetchAPIKeys();
refetchAPIKeys();
setHasUpdateLimitForIngestionKeyError(false);
},
onError: (error: AxiosError<RenderErrorResponseDTO>) => {
@@ -848,7 +824,7 @@ function MultiIngestionSettings(): JSX.Element {
});
setIsDeleteModalOpen(false);
setIsDeleteLimitModalOpen(false);
void refetchAPIKeys();
refetchAPIKeys();
},
onError: (error) => {
showErrorNotification(notifications, error as AxiosError);
@@ -864,22 +840,29 @@ function MultiIngestionSettings(): JSX.Element {
APIKey: GatewaytypesIngestionKeyDTO,
signal: LimitProps,
): void => {
const signalCfg = SIGNALS_CONFIG.find((cfg) => cfg.name === signal.signal);
if (!signalCfg) {
return;
let metricName = '';
switch (signal.signal) {
case 'metrics':
metricName = 'signoz.meter.metric.datapoint.count';
break;
case 'traces':
metricName = 'signoz.meter.span.size';
break;
case 'logs':
metricName = 'signoz.meter.log.size';
break;
default:
return;
}
const { metricName, yAxisUnit, thresholdUnit } = signalCfg;
// Size signals store the limit in bytes but the user entered GiB; pass the GiB
// value so the threshold reads "400 GiB" while the chart Y-axis stays in bytes.
const thresholdValue = signalCfg.usesCount
? signal.config?.day?.count || 0
: bytesToGb(signal.config?.day?.size);
const threshold =
signal.signal === 'metrics'
? signal.config?.day?.count || 0
: signal.config?.day?.size || 0;
const query = {
...initialQueryMeterWithType,
unit: yAxisUnit,
builder: {
...initialQueryMeterWithType.builder,
queryData: [
@@ -904,23 +887,13 @@ function MultiIngestionSettings(): JSX.Element {
const stringifiedQuery = JSON.stringify(query);
const thresholds = cloneDeep(INITIAL_ALERT_THRESHOLD_STATE.thresholds);
thresholds[0].thresholdValue = thresholdValue;
thresholds[0].unit = thresholdUnit;
const keyName = APIKey.name?.trim();
const ruleName = keyName
? `[ingestion][${signal.signal}] ${keyName} has exceeded daily ingestion limit`
: `[ingestion][${signal.signal}] ${signal.signal} has exceeded daily ingestion limit`;
thresholds[0].thresholdValue = threshold;
const URL = `${ROUTES.ALERTS_NEW}?${
QueryParams.compositeQuery
}=${encodeURIComponent(stringifiedQuery)}&${
QueryParams.thresholds
}=${encodeURIComponent(JSON.stringify(thresholds))}&${
QueryParams.ruleName
}=${encodeURIComponent(ruleName)}&${
QueryParams.yAxisUnit
}=${encodeURIComponent(yAxisUnit)}`;
}=${encodeURIComponent(JSON.stringify(thresholds))}`;
history.push(URL);
};
@@ -1007,18 +980,13 @@ function MultiIngestionSettings(): JSX.Element {
</div>
<div className="action-btn">
<Button
variant="link"
size="icon"
color="secondary"
suffix={<PenLine size={14} />}
aria-label="Edit ingestion key"
className="periscope-btn ghost"
icon={<PenLine size={14} />}
onClick={onEditKey}
/>
<Button
variant="link"
size="icon"
color="destructive"
suffix={<Trash2 color={Color.BG_CHERRY_500} size={14} />}
className="periscope-btn ghost"
icon={<Trash2 color={Color.BG_CHERRY_500} size={14} />}
onClick={onDeleteKey}
/>
</div>
@@ -1124,22 +1092,16 @@ function MultiIngestionSettings(): JSX.Element {
{hasLimits(signalName) ? (
<>
<Button
variant="link"
size="icon"
color="secondary"
prefix={<PenLine size={14} />}
aria-label={`Edit ${signalName} limit`}
className="periscope-btn ghost"
icon={<PenLine size={14} />}
disabled={
!!(activeAPIKey?.id === APIKey?.id && activeSignal)
}
onClick={onEditSignalLimit}
/>
<Button
variant="link"
size="icon"
color="destructive"
prefix={<Trash2 color={Color.BG_CHERRY_500} size={14} />}
aria-label={`Delete ${signalName} limit`}
className="periscope-btn ghost"
icon={<Trash2 color={Color.BG_CHERRY_500} size={14} />}
disabled={
!!(activeAPIKey?.id === APIKey?.id && activeSignal)
}
@@ -1148,10 +1110,10 @@ function MultiIngestionSettings(): JSX.Element {
</>
) : (
<Button
variant="outlined"
size="sm"
color="secondary"
prefix={<PlusIcon size={12} />}
className="periscope-btn"
size="small"
shape="round"
icon={<PlusIcon size={14} />}
disabled={!!(activeAPIKey?.id === APIKey?.id && activeSignal)}
onClick={onAddSignalLimit}
>
@@ -1382,35 +1344,31 @@ function MultiIngestionSettings(): JSX.Element {
activeSignal.signal === signalName &&
isEditAddLimitOpen && (
<div className="signal-limit-save-discard">
<div className="signal-limit-save-discard-actions">
<Button
variant="solid"
size="sm"
disabled={
isLoadingLimitForKey || isLoadingUpdatedLimitForKey
}
loading={
isLoadingLimitForKey || isLoadingUpdatedLimitForKey
}
onClick={onSaveSignalLimit}
>
Save
</Button>
<Button
variant="outlined"
color="secondary"
size="sm"
disabled={
isLoadingLimitForKey || isLoadingUpdatedLimitForKey
}
onClick={handleDiscardSaveLimit}
>
Discard
</Button>
<span className="signal-limit-alert-helper">
You can set up an alert after saving
</span>
</div>
<Button
type="primary"
className="periscope-btn primary"
size="small"
disabled={
isLoadingLimitForKey || isLoadingUpdatedLimitForKey
}
loading={
isLoadingLimitForKey || isLoadingUpdatedLimitForKey
}
onClick={onSaveSignalLimit}
>
Save
</Button>
<Button
type="default"
className="periscope-btn"
size="small"
disabled={
isLoadingLimitForKey || isLoadingUpdatedLimitForKey
}
onClick={handleDiscardSaveLimit}
>
Discard
</Button>
</div>
)}
</Form>
@@ -1467,18 +1425,19 @@ function MultiIngestionSettings(): JSX.Element {
limit?.config?.day?.size !== undefined) ||
(signalCfg.usesCount &&
limit?.config?.day?.count !== undefined)) && (
<Badge
asChild
color="cherry"
variant="outline"
testId={`set-alert-btn-${signalName}`}
className="set-alert-btn"
<Tooltip
title="Set alert on this limit"
placement="top"
arrow={false}
>
<Button onClick={onCreateSignalAlert} size="sm">
<BellPlus size={12} />
Set alert
</Button>
</Badge>
<Button
icon={<BellPlus size={14} color={Color.BG_CHERRY_400} />}
className="set-alert-btn periscope-btn ghost"
type="text"
data-testid={`set-alert-btn-${signalName}`}
onClick={onCreateSignalAlert}
/>
</Tooltip>
)}
</div>
@@ -1658,13 +1617,7 @@ function MultiIngestionSettings(): JSX.Element {
}
placement="topLeft"
>
<Button
variant="ghost"
size="icon"
color="secondary"
prefix={<TriangleAlert size={14} />}
aria-label="Ingestion URL error details"
/>
<Button type="text" icon={<TriangleAlert size={14} />} />
</Tooltip>
)}
</div>
@@ -1680,12 +1633,11 @@ function MultiIngestionSettings(): JSX.Element {
/>
<Button
variant="solid"
className="add-new-ingestion-key-btn"
prefix={<Plus size={14} />}
type="primary"
onClick={showAddModal}
>
New Ingestion key
<Plus size={14} /> New Ingestion key
</Button>
</div>
@@ -1718,19 +1670,15 @@ function MultiIngestionSettings(): JSX.Element {
footer={[
<Button
key="cancel"
variant="ghost"
color="secondary"
prefix={<X size={16} />}
onClick={hideDeleteViewModal}
className="cancel-btn"
icon={<X size={16} />}
>
Cancel
</Button>,
<Button
key="submit"
variant="solid"
color="destructive"
prefix={<Trash2 size={16} />}
icon={<Trash2 size={16} />}
loading={isDeleteingAPIKey}
onClick={onDeleteHandler}
className="delete-btn"
@@ -1758,19 +1706,15 @@ function MultiIngestionSettings(): JSX.Element {
footer={[
<Button
key="cancel"
variant="ghost"
color="secondary"
prefix={<X size={16} />}
onClick={hideDeleteLimitModal}
className="cancel-btn"
icon={<X size={16} />}
>
Cancel
</Button>,
<Button
key="submit"
variant="solid"
color="destructive"
prefix={<Trash2 size={16} />}
icon={<Trash2 size={16} />}
loading={isDeletingLimit}
onClick={onDeleteLimitHandler}
className="delete-btn"
@@ -1801,18 +1745,18 @@ function MultiIngestionSettings(): JSX.Element {
footer={[
<Button
key="cancel"
variant="ghost"
color="secondary"
prefix={<X size={16} />}
onClick={hideEditViewModal}
className="periscope-btn cancel-btn"
icon={<X size={16} />}
>
Cancel
</Button>,
<Button
className="periscope-btn primary"
key="submit"
variant="solid"
prefix={<Check size={14} />}
type="primary"
loading={isLoadingUpdateAPIKey}
icon={<Check size={14} />}
onClick={onUpdateApiKey}
>
Update Ingestion Key
@@ -1869,18 +1813,18 @@ function MultiIngestionSettings(): JSX.Element {
footer={[
<Button
key="cancel"
variant="ghost"
color="secondary"
prefix={<X size={16} />}
onClick={hideAddViewModal}
className="periscope-btn cancel-btn"
icon={<X size={16} />}
>
Cancel
</Button>,
<Button
className="periscope-btn primary"
test-id="create-new-key"
key="submit"
variant="solid"
testId="create-new-key"
prefix={<Check size={14} />}
type="primary"
icon={<Check size={14} />}
loading={isLoadingCreateAPIKey}
onClick={onCreateIngestionKey}
>
@@ -1914,7 +1858,7 @@ function MultiIngestionSettings(): JSX.Element {
]}
validateTrigger="onBlur"
>
<Input placeholder="Enter Ingestion Key name" />
<Input placeholder="Enter Ingestion Key name" autoFocus />
</Form.Item>
<Form.Item

View File

@@ -1,16 +1,24 @@
import { GatewaytypesGettableIngestionKeysDTO } from 'api/generated/services/sigNoz.schemas';
import { QueryParams } from 'constants/query';
import { rest, server } from 'mocks-server/server';
import { render, screen, userEvent, waitFor } from 'tests/test-utils';
import { LimitProps } from 'types/api/ingestionKeys/limits/types';
import {
fireEvent,
render,
screen,
userEvent,
waitFor,
} from 'tests/test-utils';
AllIngestionKeyProps,
IngestionKeyProps,
} from 'types/api/ingestionKeys/types';
import MultiIngestionSettings from '../MultiIngestionSettings';
// Extend the existing types to include limits with proper structure
interface TestIngestionKeyProps extends Omit<IngestionKeyProps, 'limits'> {
limits?: LimitProps[];
}
interface TestAllIngestionKeyProps extends Omit<AllIngestionKeyProps, 'data'> {
data: TestIngestionKeyProps[];
}
// Gateway API response type (uses actual schema types for contract safety)
interface TestGatewayIngestionKeysResponse {
status: string;
@@ -32,16 +40,6 @@ const TEST_EXPIRES_AT = '2030-01-01T00:00:00Z';
const TEST_WORKSPACE_ID = 'w1';
const INGESTION_SETTINGS_ROUTE = '/ingestion-settings';
const GLOBAL_CONFIG_RESPONSE = {
status: 'success',
data: {
external_url: '',
ingestion_url: 'http://ingest.example.com',
ai_assistant_url: null,
mcp_url: null,
},
};
describe('MultiIngestionSettings Page', () => {
beforeEach(() => {
mockPush.mockClear();
@@ -73,6 +71,11 @@ describe('MultiIngestionSettings Page', () => {
});
it('navigates to create alert with metrics count threshold', async () => {
// Increase timeout - test involves multiple user interactions and async waits
// that can exceed 5s default under heavy load (full test suite)
const user = userEvent.setup({ pointerEventsCheck: 0 });
// Arrange API response with a metrics daily count limit so the alert button is visible
const response: TestGatewayIngestionKeysResponse = {
status: 'success',
data: {
@@ -100,91 +103,95 @@ describe('MultiIngestionSettings Page', () => {
};
server.use(
rest.get('*/api/v1/global/config*', (_req, res, ctx) =>
res(ctx.status(200), ctx.json(GLOBAL_CONFIG_RESPONSE)),
),
rest.get('*/api/v2/gateway/ingestion_keys*', (_req, res, ctx) =>
res(ctx.status(200), ctx.json(response)),
),
);
// Render with initial route to test navigation
render(<MultiIngestionSettings />, undefined, {
initialRoute: INGESTION_SETTINGS_ROUTE,
});
// Wait for ingestion key to load and expand the row to show limits
await screen.findByText('Key One');
fireEvent.click(screen.getByRole('button', { name: /right Key One/i }));
const expandButton = screen.getByRole('button', { name: /right Key One/i });
await user.click(expandButton);
// Wait for limits section to render and click metrics alert button by test id
await screen.findByText('LIMITS');
fireEvent.click(
(await screen.findByTestId('set-alert-btn-metrics')) as HTMLButtonElement,
);
const metricsAlertBtn = (await screen.findByTestId(
'set-alert-btn-metrics',
)) as HTMLButtonElement;
await user.click(metricsAlertBtn);
// Wait for navigation to occur
await waitFor(() => {
expect(mockPush).toHaveBeenCalledTimes(1);
});
// Assert: navigation occurred with correct query parameters
const navigationCall = mockPush.mock.calls[0][0] as string;
// Check URL contains alerts/new route
expect(navigationCall).toContain('/alerts/new');
// Parse query parameters
const urlParams = new URLSearchParams(navigationCall.split('?')[1]);
const thresholds = JSON.parse(urlParams.get(QueryParams.thresholds) || '{}');
expect(thresholds).toBeDefined();
expect(thresholds[0].thresholdValue).toBe(1000);
expect(thresholds[0].unit).toBe('{count}');
// Verify compositeQuery parameter exists and contains correct data
const compositeQuery = JSON.parse(
urlParams.get(QueryParams.compositeQuery) || '{}',
);
expect(compositeQuery.unit).toBe('{count}');
expect(compositeQuery.builder).toBeDefined();
expect(compositeQuery.builder.queryData).toBeDefined();
// Check that the query contains the correct filter expression for the key
const firstQueryData = compositeQuery.builder.queryData[0];
expect(firstQueryData.filter.expression).toContain(
"signoz.workspace.key.id='k1'",
);
// Verify metric name for metrics signal
expect(firstQueryData.aggregations[0].metricName).toBe(
'signoz.meter.metric.datapoint.count',
);
}, 15000);
expect(urlParams.get(QueryParams.yAxisUnit)).toBe('{count}');
expect(urlParams.get(QueryParams.ruleName)).toContain('metrics');
});
// skipping the flaky test
it.skip('navigates to create alert for logs with size threshold', async () => {
const user = userEvent.setup({ pointerEventsCheck: 0 });
it('navigates to create alert for logs with GiB threshold and bytes yAxisUnit', async () => {
const GIB = 1073741824;
const sizeInBytes = 400 * GIB;
const response: TestGatewayIngestionKeysResponse = {
// Arrange API response with a logs daily size limit so the alert button is visible
const response: TestAllIngestionKeyProps = {
status: 'success',
data: {
keys: [
{
name: 'Key Logs',
expires_at: new Date(TEST_EXPIRES_AT),
value: 'secret',
workspace_id: TEST_WORKSPACE_ID,
id: 'k2',
created_at: new Date(TEST_CREATED_UPDATED),
updated_at: new Date(TEST_CREATED_UPDATED),
tags: [],
limits: [
{
id: 'l2',
signal: 'logs',
config: { day: { size: sizeInBytes } },
},
],
},
],
_pagination: { page: 1, per_page: 10, pages: 1, total: 1 },
},
data: [
{
name: 'Key Two',
expires_at: TEST_EXPIRES_AT,
value: 'secret',
workspace_id: TEST_WORKSPACE_ID,
id: 'k2',
created_at: TEST_CREATED_UPDATED,
updated_at: TEST_CREATED_UPDATED,
tags: [],
limits: [
{
id: 'l2',
signal: 'logs',
config: { day: { size: 2048 } },
},
],
},
],
_pagination: { page: 1, per_page: 10, pages: 1, total: 1 },
};
server.use(
rest.get('*/api/v1/global/config*', (_req, res, ctx) =>
res(ctx.status(200), ctx.json(GLOBAL_CONFIG_RESPONSE)),
),
rest.get('*/api/v2/gateway/ingestion_keys*', (_req, res, ctx) =>
rest.get('*/workspaces/me/keys*', (_req, res, ctx) =>
res(ctx.status(200), ctx.json(response)),
),
);
@@ -192,102 +199,55 @@ describe('MultiIngestionSettings Page', () => {
render(<MultiIngestionSettings />, undefined, {
initialRoute: INGESTION_SETTINGS_ROUTE,
});
await screen.findByText('Key Logs');
fireEvent.click(screen.getByRole('button', { name: /right Key Logs/i }));
// Wait for ingestion key to load and expand the row to show limits
await screen.findByText('Key Two');
const expandButton = screen.getByRole('button', { name: /right Key Two/i });
await user.click(expandButton);
// Wait for limits section to render and click logs alert button by test id
await screen.findByText('LIMITS');
fireEvent.click(
(await screen.findByTestId('set-alert-btn-logs')) as HTMLButtonElement,
);
const logsAlertBtn = (await screen.findByTestId(
'set-alert-btn-logs',
)) as HTMLButtonElement;
await user.click(logsAlertBtn);
// Wait for navigation to occur
await waitFor(() => {
expect(mockPush).toHaveBeenCalledTimes(1);
});
// Assert: navigation occurred with correct query parameters
const navigationCall = mockPush.mock.calls[0][0] as string;
// Check URL contains alerts/new route
expect(navigationCall).toContain('/alerts/new');
// Parse query parameters
const urlParams = new URLSearchParams(navigationCall.split('?')[1]);
// Verify thresholds parameter
const thresholds = JSON.parse(urlParams.get(QueryParams.thresholds) || '{}');
expect(thresholds[0].thresholdValue).toBe(400);
expect(thresholds[0].unit).toBe('GiBy');
expect(thresholds).toBeDefined();
expect(thresholds[0].thresholdValue).toBe(2048);
// Verify compositeQuery parameter exists and contains correct data
const compositeQuery = JSON.parse(
urlParams.get(QueryParams.compositeQuery) || '{}',
);
expect(compositeQuery.unit).toBe('bytes');
expect(compositeQuery.builder).toBeDefined();
expect(compositeQuery.builder.queryData).toBeDefined();
// Check that the query contains the correct filter expression for the key
const firstQueryData = compositeQuery.builder.queryData[0];
expect(firstQueryData.filter.expression).toContain(
"signoz.workspace.key.id='k2'",
);
// Verify metric name for logs signal
expect(firstQueryData.aggregations[0].metricName).toBe(
'signoz.meter.log.size',
);
expect(urlParams.get(QueryParams.yAxisUnit)).toBe('bytes');
expect(urlParams.get(QueryParams.ruleName)).toContain('logs');
});
it('shows alert CTAs in view mode and helper text in edit mode for configured limits', async () => {
const KEY_NAME = 'Key With Limits';
const response: TestGatewayIngestionKeysResponse = {
status: 'success',
data: {
keys: [
{
name: KEY_NAME,
expires_at: new Date(TEST_EXPIRES_AT),
value: 'secret',
workspace_id: TEST_WORKSPACE_ID,
id: 'k1',
created_at: new Date(TEST_CREATED_UPDATED),
updated_at: new Date(TEST_CREATED_UPDATED),
tags: [],
limits: [
{
id: 'l1',
signal: 'metrics',
config: { day: { count: 1000 } },
},
{
id: 'l2',
signal: 'logs',
config: { day: { size: 1073741824 } },
},
],
},
],
_pagination: { page: 1, per_page: 10, pages: 1, total: 1 },
},
};
server.use(
rest.get('*/api/v1/global/config*', (_req, res, ctx) =>
res(ctx.status(200), ctx.json(GLOBAL_CONFIG_RESPONSE)),
),
rest.get('*/api/v2/gateway/ingestion_keys*', (_req, res, ctx) =>
res(ctx.status(200), ctx.json(response)),
),
);
render(<MultiIngestionSettings />, undefined, {
initialRoute: INGESTION_SETTINGS_ROUTE,
});
await screen.findByText(KEY_NAME);
fireEvent.click(
screen.getByRole('button', { name: new RegExp(`right ${KEY_NAME}`, 'i') }),
);
await screen.findByText('LIMITS');
expect(screen.getAllByText('Set alert').length).toBeGreaterThan(0);
fireEvent.click(screen.getByRole('button', { name: 'Edit logs limit' }));
expect(
screen.getByText('You can set up an alert after saving'),
).toBeInTheDocument();
});
it('switches to search API when search text is entered', async () => {
@@ -337,9 +297,6 @@ describe('MultiIngestionSettings Page', () => {
const searchHandler = jest.fn();
server.use(
rest.get('*/api/v1/global/config*', (_req, res, ctx) =>
res(ctx.status(200), ctx.json(GLOBAL_CONFIG_RESPONSE)),
),
rest.get('*/api/v2/gateway/ingestion_keys', (req, res, ctx) => {
if (req.url.pathname.endsWith('/search')) {
return undefined;

View File

@@ -14,7 +14,7 @@ import { ILog } from 'types/api/logs/log';
import { ActionItemProps } from './ActionItem';
import TableView from './TableView';
import { getBodyDisplayString, removeEscapeCharacters } from './utils';
import { removeEscapeCharacters } from './utils';
import './Overview.styles.scss';
@@ -113,7 +113,7 @@ function Overview({
children: (
<div className="logs-body-content">
<MEditor
value={removeEscapeCharacters(getBodyDisplayString(logData.body))}
value={removeEscapeCharacters(logData.body)}
language="json"
options={options}
onChange={(): void => {}}

View File

@@ -10,7 +10,7 @@ const MAX_BODY_BYTES = 100 * 1024; // 100 KB
// Hook for async JSON processing
const useAsyncJSONProcessing = (
value: string | Record<string, unknown>,
value: string,
shouldProcess: boolean,
handleChangeSelectedView?: ChangeViewFunctionType,
): {
@@ -40,17 +40,11 @@ const useAsyncJSONProcessing = (
return (): void => {};
}
// When value is already a parsed object skip the size check and JSON parsing
const parseBody = (): Record<string, unknown> | null => {
if (typeof value === 'object' && value !== null) {
return value as Record<string, unknown>;
}
const byteSize = new Blob([value as string]).size;
if (byteSize > MAX_BODY_BYTES) {
return null;
}
return recursiveParseJSON(value as string);
};
// Avoid processing if the json is too large
const byteSize = new Blob([value]).size;
if (byteSize > MAX_BODY_BYTES) {
return (): void => {};
}
processingRef.current = true;
setJsonState({ isLoading: true, treeData: null, error: null });
@@ -59,8 +53,8 @@ const useAsyncJSONProcessing = (
const processAsync = (): void => {
setTimeout(() => {
try {
const parsedBody = parseBody();
if (parsedBody && !isEmpty(parsedBody)) {
const parsedBody = recursiveParseJSON(value);
if (!isEmpty(parsedBody)) {
const treeData = jsonToDataNodes(parsedBody, {
isBodyJsonQueryEnabled,
handleChangeSelectedView,
@@ -88,8 +82,8 @@ const useAsyncJSONProcessing = (
// eslint-disable-next-line sonarjs/no-identical-functions
(): void => {
try {
const parsedBody = parseBody();
if (parsedBody && !isEmpty(parsedBody)) {
const parsedBody = recursiveParseJSON(value);
if (!isEmpty(parsedBody)) {
const treeData = jsonToDataNodes(parsedBody, {
isBodyJsonQueryEnabled,
handleChangeSelectedView,

View File

@@ -4,11 +4,7 @@ import { ChangeViewFunctionType } from 'container/ExplorerOptions/types';
import { MetricsType } from 'container/MetricsApplication/constant';
import dompurify from 'dompurify';
import { uniqueId } from 'lodash-es';
import {
ILog,
ILogAggregateAttributesResources,
ILogBody,
} from 'types/api/logs/log';
import { ILog, ILogAggregateAttributesResources } from 'types/api/logs/log';
import { DataTypes } from 'types/api/queryBuilder/queryAutocompleteResponse';
import { FORBID_DOM_PURIFY_ATTR, FORBID_DOM_PURIFY_TAGS } from 'utils/app';
@@ -437,24 +433,3 @@ export const getSanitizedLogBody = (
return '{}';
}
};
// Returns a plain string for display contexts (Monaco editor, table cells, raw log row).
export function getBodyDisplayString(body: string | ILogBody): string {
return typeof body === 'string' ? body : JSON.stringify(body as ILogBody);
}
// Returns the primary "message" text for compact log row previews.
export function getBodyMessage(
body: string | ILogBody,
isBodyJsonEnabled: boolean,
): string {
if (!isBodyJsonEnabled) {
return (body as string) ?? '';
}
// Feature enabled: body is always a map; message is always a string
const msg = (body as ILogBody).message;
if (msg) {
return msg;
}
return JSON.stringify(body);
}

View File

@@ -151,6 +151,7 @@ describe('Metadata', () => {
});
it('should update the metadata when the form is submitted', async () => {
jest.setTimeout(15000);
render(
<Metadata
metricName={MOCK_METRIC_NAME}

View File

@@ -2,7 +2,6 @@ import { ExpandAltOutlined } from '@ant-design/icons';
import LogDetail from 'components/LogDetail';
import { VIEW_TYPES } from 'components/LogDetail/constants';
import { DATE_TIME_FORMATS } from 'constants/dateTimeFormats';
import { getBodyDisplayString } from 'container/LogDetailedView/utils';
import { useActiveLog } from 'hooks/logs/useActiveLog';
import { useTimezone } from 'providers/Timezone';
import { ILog } from 'types/api/logs/log';
@@ -27,9 +26,7 @@ function LogsList({ logs }: LogsListProps): JSX.Element {
DATE_TIME_FORMATS.UTC_MONTH_SHORT,
)}
</div>
<div className="logs-preview-list-item-body">
{getBodyDisplayString(log.body)}
</div>
<div className="logs-preview-list-item-body">{log.body}</div>
<div
className="logs-preview-list-item-expand"
onClick={makeLogDetailsHandler(log)}

View File

@@ -79,6 +79,8 @@ describe('Having filter behaviour', () => {
});
it('Autocomplete in the having filter', async () => {
// Long test with many userEvent operations - needs extended timeout
jest.setTimeout(30000);
const onChange = jest.fn();
const user = userEvent.setup();

View File

@@ -4,7 +4,6 @@ import { Typography } from '@signozhq/ui';
import ROUTES from 'constants/routes';
import { formUrlParams } from 'container/TraceDetail/utils';
import { Span } from 'types/api/trace/getTraceV2';
import { withBasePath } from 'utils/basePath';
import NoData from '../NoData/NoData';
@@ -27,13 +26,11 @@ function LinkedSpans(props: LinkedSpansProps): JSX.Element {
if (!item.traceId || !item.spanId) {
return null;
}
return withBasePath(
`${ROUTES.TRACE}/${item.traceId}${formUrlParams({
spanId: item.spanId,
levelUp: 0,
levelDown: 0,
})}`,
);
return `${ROUTES.TRACE}/${item.traceId}${formUrlParams({
spanId: item.spanId,
levelUp: 0,
levelDown: 0,
})}`;
}, []);
// Filter out CHILD_OF references as they are parent-child relationships

View File

@@ -1,8 +1,3 @@
export interface ILogBody {
message?: string | null;
[key: string]: unknown;
}
export interface ILog {
date: string;
timestamp: number | string;
@@ -13,7 +8,7 @@ export interface ILog {
traceFlags: number;
severityText: string;
severityNumber: number;
body: string | ILogBody;
body: string;
resources_string: Record<string, never>;
scope_string: Record<string, never>;
attributesString: Record<string, never>;

2
go.mod
View File

@@ -11,7 +11,6 @@ require (
github.com/SigNoz/signoz-otel-collector v0.144.3
github.com/antlr4-go/antlr/v4 v4.13.1
github.com/antonmedv/expr v1.15.3
github.com/bytedance/sonic v1.14.1
github.com/cespare/xxhash/v2 v2.3.0
github.com/coreos/go-oidc/v3 v3.17.0
github.com/dgraph-io/ristretto/v2 v2.3.0
@@ -113,6 +112,7 @@ require (
github.com/aws/aws-sdk-go-v2/service/sts v1.41.6 // indirect
github.com/aws/smithy-go v1.24.2 // indirect
github.com/bytedance/gopkg v0.1.3 // indirect
github.com/bytedance/sonic v1.14.1 // indirect
github.com/bytedance/sonic/loader v0.3.0 // indirect
github.com/cloudwego/base64x v0.1.6 // indirect
github.com/emersion/go-sasl v0.0.0-20241020182733-b788ff22d5a6 // indirect

View File

@@ -12,10 +12,8 @@ import (
"time"
"github.com/ClickHouse/clickhouse-go/v2/lib/driver"
"github.com/SigNoz/signoz/pkg/errors"
qbtypes "github.com/SigNoz/signoz/pkg/types/querybuildertypes/querybuildertypesv5"
"github.com/SigNoz/signoz/pkg/types/telemetrytypes"
"github.com/bytedance/sonic"
)
var (
@@ -24,8 +22,6 @@ var (
// written clickhouse query. The column alias indcate which value is
// to be considered as final result (or target).
legacyReservedColumnTargetAliases = []string{"__result", "__value", "result", "res", "value"}
CodeFailUnmarshalJSONColumn = errors.MustNewCode("fail_unmarshal_json_column")
)
// consume reads every row and shapes it into the payload expected for the
@@ -397,16 +393,11 @@ func readAsRaw(rows driver.Rows, queryName string) (*qbtypes.RawData, error) {
// de-reference the typed pointer to any
val := reflect.ValueOf(cellPtr).Elem().Interface()
// Post-process JSON columns: unmarshal bytes into map[string]any
// Post-process JSON columns: normalize into String value
if strings.HasPrefix(strings.ToUpper(colTypes[i].DatabaseTypeName()), "JSON") {
switch x := val.(type) {
case []byte:
var m map[string]any
err := sonic.Unmarshal(x, &m)
if err != nil {
return nil, errors.WrapInternalf(err, CodeFailUnmarshalJSONColumn, "failed to unmarshal JSON column %s", name)
}
val = m
val = string(x)
default:
// already a structured type (map[string]any, []any, etc.)
}

View File

@@ -12,12 +12,9 @@ import (
"github.com/SigNoz/govaluate"
"github.com/SigNoz/signoz/pkg/errors"
"github.com/SigNoz/signoz/pkg/flagger"
"github.com/SigNoz/signoz/pkg/types/featuretypes"
"github.com/SigNoz/signoz/pkg/querybuilder"
qbtypes "github.com/SigNoz/signoz/pkg/types/querybuildertypes/querybuildertypesv5"
"github.com/SigNoz/signoz/pkg/types/telemetrytypes"
"github.com/SigNoz/signoz/pkg/valuer"
)
// queryInfo holds common query properties.
@@ -53,7 +50,7 @@ func getQueryName(spec any) string {
return getqueryInfo(spec).Name
}
func (q *querier) postProcessResults(ctx context.Context, orgID valuer.UUID, results map[string]any, req *qbtypes.QueryRangeRequest) (map[string]any, error) {
func (q *querier) postProcessResults(ctx context.Context, results map[string]any, req *qbtypes.QueryRangeRequest) (map[string]any, error) {
// Convert results to typed format for processing
typedResults := make(map[string]*qbtypes.Result)
for name, result := range results {
@@ -72,7 +69,6 @@ func (q *querier) postProcessResults(ctx context.Context, orgID valuer.UUID, res
case qbtypes.QueryBuilderQuery[qbtypes.LogAggregation]:
if result, ok := typedResults[spec.Name]; ok {
result = postProcessBuilderQuery(q, result, spec, req)
result = q.postProcessLogBody(ctx, orgID, result, req)
typedResults[spec.Name] = result
}
case qbtypes.QueryBuilderQuery[qbtypes.MetricAggregation]:
@@ -1039,33 +1035,3 @@ func (q *querier) calculateFormulaStep(expression string, req *qbtypes.QueryRang
return result
}
// postProcessLogBody removes the "message" key from the body map when it is empty.
// Only runs for raw list queries with the use_json_body feature enabled.
func (q *querier) postProcessLogBody(ctx context.Context, orgID valuer.UUID, result *qbtypes.Result, req *qbtypes.QueryRangeRequest) *qbtypes.Result {
if req.RequestType != qbtypes.RequestTypeRaw {
return result
}
if !q.fl.BooleanOrEmpty(ctx, flagger.FeatureUseJSONBody, featuretypes.NewFlaggerEvaluationContext(orgID)) {
return result
}
rawData, ok := result.Value.(*qbtypes.RawData)
if !ok {
return result
}
for _, row := range rawData.Rows {
bodyMap, ok := row.Data["body"].(map[string]any)
if !ok {
continue
}
if msg, exists := bodyMap["message"]; exists {
switch v := msg.(type) {
case string:
if v == "" {
delete(bodyMap, "message")
}
}
}
}
return result
}

View File

@@ -16,7 +16,6 @@ import (
"github.com/SigNoz/signoz/pkg/errors"
"github.com/SigNoz/signoz/pkg/factory"
"github.com/SigNoz/signoz/pkg/flagger"
"github.com/SigNoz/signoz/pkg/prometheus"
"github.com/SigNoz/signoz/pkg/query-service/utils"
"github.com/SigNoz/signoz/pkg/querybuilder"
@@ -36,7 +35,6 @@ var (
type querier struct {
logger *slog.Logger
fl flagger.Flagger
telemetryStore telemetrystore.TelemetryStore
metadataStore telemetrytypes.MetadataStore
promEngine prometheus.Prometheus
@@ -64,12 +62,10 @@ func New(
meterStmtBuilder qbtypes.StatementBuilder[qbtypes.MetricAggregation],
traceOperatorStmtBuilder qbtypes.TraceOperatorStatementBuilder,
bucketCache BucketCache,
flagger flagger.Flagger,
) *querier {
querierSettings := factory.NewScopedProviderSettings(settings, "github.com/SigNoz/signoz/pkg/querier")
return &querier{
logger: querierSettings.Logger(),
fl: flagger,
telemetryStore: telemetryStore,
metadataStore: metadataStore,
promEngine: promEngine,
@@ -688,7 +684,7 @@ func (q *querier) run(
}
gomaps.Copy(results, preseededResults)
processedResults, err := q.postProcessResults(ctx, orgID, results, req)
processedResults, err := q.postProcessResults(ctx, results, req)
if err != nil {
return nil, err
}

View File

@@ -7,7 +7,6 @@ import (
cmock "github.com/srikanthccv/ClickHouse-go-mock"
"github.com/SigNoz/signoz/pkg/flagger/flaggertest"
"github.com/SigNoz/signoz/pkg/instrumentation/instrumentationtest"
"github.com/SigNoz/signoz/pkg/telemetrystore"
"github.com/SigNoz/signoz/pkg/telemetrystore/telemetrystoretest"
@@ -45,15 +44,14 @@ func TestQueryRange_MetricTypeMissing(t *testing.T) {
providerSettings,
nil, // telemetryStore
metadataStore,
nil, // prometheus
nil, // traceStmtBuilder
nil, // logStmtBuilder
nil, // auditStmtBuilder
nil, // metricStmtBuilder
nil, // meterStmtBuilder
nil, // traceOperatorStmtBuilder
nil, // bucketCache
flaggertest.New(t), // flagger
nil, // prometheus
nil, // traceStmtBuilder
nil, // logStmtBuilder
nil, // auditStmtBuilder
nil, // metricStmtBuilder
nil, // meterStmtBuilder
nil, // traceOperatorStmtBuilder
nil, // bucketCache
)
req := &qbtypes.QueryRangeRequest{
@@ -118,7 +116,6 @@ func TestQueryRange_MetricTypeFromStore(t *testing.T) {
nil, // meterStmtBuilder
nil, // traceOperatorStmtBuilder
nil, // bucketCache
flaggertest.New(t), // flagger
)
req := &qbtypes.QueryRangeRequest{

View File

@@ -186,6 +186,5 @@ func newProvider(
meterStmtBuilder,
traceOperatorStmtBuilder,
bucketCache,
flagger,
), nil
}

View File

@@ -53,7 +53,6 @@ func prepareQuerierForMetrics(t *testing.T, telemetryStore telemetrystore.Teleme
nil, // meterStmtBuilder
nil, // traceOperatorStmtBuilder
nil, // bucketCache
flagger,
), metadataStore
}
@@ -103,7 +102,6 @@ func prepareQuerierForLogs(t *testing.T, telemetryStore telemetrystore.Telemetry
nil, // meterStmtBuilder
nil, // traceOperatorStmtBuilder
nil, // bucketCache
fl,
)
}
@@ -148,6 +146,5 @@ func prepareQuerierForTraces(t *testing.T, telemetryStore telemetrystore.Telemet
nil, // meterStmtBuilder
nil, // traceOperatorStmtBuilder
nil, // bucketCache
fl,
)
}

View File

@@ -20,7 +20,7 @@ from fixtures.querier import (
def _get_bodies(response: requests.Response) -> list[dict[str, Any]]:
return [row["data"]["body"] for row in get_rows(response)]
return [json.loads(row["data"]["body"]) for row in get_rows(response)]
def _run_query_case(signoz: types.SigNoz, token: str, now: datetime, case: dict[str, Any]) -> None:
@@ -1183,7 +1183,7 @@ def test_message_searches(
token = get_token(email=USER_ADMIN_EMAIL, password=USER_ADMIN_PASSWORD)
def _body_messages(response: requests.Response) -> list[str]:
return [row["data"]["body"].get("message", "") for row in get_rows(response)]
return [json.loads(row["data"]["body"]).get("message", "") for row in get_rows(response)]
payment_messages = {
"Payment processed successfully",