Fix/logs issues main (#7758)

* fix: context log data fix in list view

* fix: fix query builder and quick filters in light mode

* chore: add desc

* chore: added test case

* fix: fix redirect url when not in logs view

* chore: minor fix

* chore: minor fix

* chore: minor test fix

---------

Co-authored-by: Aditya Singh <adityasingh@Adityas-MacBook-Pro.local>
This commit is contained in:
Aditya Singh 2025-05-06 11:02:40 +05:30 committed by GitHub
parent f4d029bd12
commit 76ed58c481
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
7 changed files with 308 additions and 9 deletions

View File

@ -3,6 +3,7 @@
flex-direction: column;
height: 100%;
border-right: 1px solid var(--bg-slate-400);
color: var(--bg-vanilla-100);
.header {
display: flex;
@ -74,6 +75,7 @@
.quick-filters {
background-color: var(--bg-vanilla-100);
border-right: 1px solid var(--bg-vanilla-300);
color: var(--bg-ink-200);
.header {
border-bottom: 1px solid var(--bg-vanilla-300);

View File

@ -5,6 +5,7 @@ import RawLogView from 'components/Logs/RawLogView';
import OverlayScrollbar from 'components/OverlayScrollbar/OverlayScrollbar';
import { LOCALSTORAGE } from 'constants/localStorage';
import { QueryParams } from 'constants/query';
import ROUTES from 'constants/routes';
import ShowButton from 'container/LogsContextList/ShowButton';
import { convertKeysToColumnFields } from 'container/LogsExplorerList/utils';
import { useOptionsMenu } from 'container/OptionsMenu';
@ -14,7 +15,6 @@ import { ORDERBY_FILTERS } from 'container/QueryBuilder/filters/OrderByFilter/co
import { useQueryBuilder } from 'hooks/queryBuilder/useQueryBuilder';
import useUrlQuery from 'hooks/useUrlQuery';
import { useCallback, useEffect, useMemo, useState } from 'react';
import { useLocation } from 'react-router-dom';
import { Virtuoso } from 'react-virtuoso';
import { ILog } from 'types/api/logs/log';
import { Query, TagFilter } from 'types/api/queryBuilder/queryBuilderData';
@ -106,8 +106,6 @@ function ContextLogRenderer({
const urlQuery = useUrlQuery();
const { pathname } = useLocation();
const handleLogClick = useCallback(
(logId: string): void => {
urlQuery.set(QueryParams.activeLogId, `"${logId}"`);
@ -117,11 +115,10 @@ function ContextLogRenderer({
encodeURIComponent(JSON.stringify(query)),
);
const link = `${pathname}?${urlQuery.toString()}`;
const link = `${ROUTES.LOGS_EXPLORER}?${urlQuery.toString()}`;
window.open(link, '_blank', 'noopener,noreferrer');
},
[pathname, query, urlQuery],
[query, urlQuery],
);
const getItemContent = useCallback(
@ -143,7 +140,9 @@ function ContextLogRenderer({
linesPerRow={1}
fontSize={options.fontSize}
selectedFields={convertKeysToColumnFields(
options.selectColumns ?? defaultLogsSelectedColumns,
options.selectColumns?.length
? options.selectColumns
: defaultLogsSelectedColumns,
)}
/>
</Button>

View File

@ -0,0 +1,145 @@
import {
act,
render,
RenderResult,
screen,
waitFor,
} from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import { ENVIRONMENT } from 'constants/env';
import { initialQueriesMap } from 'constants/queryBuilder';
import { server } from 'mocks-server/server';
import { rest } from 'msw';
import { QueryBuilderContext } from 'providers/QueryBuilder';
import MockQueryClientProvider from 'providers/test/MockQueryClientProvider';
import TimezoneProvider from 'providers/Timezone';
import { Provider } from 'react-redux';
import { MemoryRouter } from 'react-router-dom';
import { VirtuosoMockContext } from 'react-virtuoso';
import store from 'store';
import ContextLogRenderer from '../ContextLogRenderer';
import {
mockLog,
mockQuery,
mockQueryRangeResponse,
mockTagFilter,
} from './mockData';
// Mock the useContextLogData hook
const mockHandleRunQuery = jest.fn();
jest.mock('uplot', () => {
const paths = {
spline: jest.fn(),
bars: jest.fn(),
};
const uplotMock = jest.fn(() => ({
paths,
}));
return {
paths,
default: uplotMock,
};
});
jest.mock('container/OptionsMenu', () => ({
useOptionsMenu: (): any => ({
options: {
fontSize: 'medium',
selectColumns: [],
},
}),
}));
jest.mock('hooks/useSafeNavigate', () => ({
useSafeNavigate: (): any => ({
safeNavigate: jest.fn(),
}),
}));
// Common wrapper component for tests
const renderContextLogRenderer = (): RenderResult => {
const defaultProps = {
isEdit: false,
query: mockQuery,
log: mockLog,
filters: mockTagFilter,
};
return render(
<MemoryRouter>
<TimezoneProvider>
<Provider store={store}>
<MockQueryClientProvider>
<QueryBuilderContext.Provider
value={
{
currentQuery: initialQueriesMap.traces,
handleRunQuery: mockHandleRunQuery,
} as any
}
>
<VirtuosoMockContext.Provider
value={{ viewportHeight: 300, itemHeight: 50 }}
>
<ContextLogRenderer
isEdit={defaultProps.isEdit}
query={defaultProps.query}
log={defaultProps.log}
filters={defaultProps.filters}
/>
</VirtuosoMockContext.Provider>
</QueryBuilderContext.Provider>
</MockQueryClientProvider>
</Provider>
</TimezoneProvider>
</MemoryRouter>,
);
};
describe('ContextLogRenderer', () => {
beforeEach(() => {
server.use(
rest.get(`${ENVIRONMENT.baseURL}/api/v1/logs`, (req, res, ctx) =>
res(ctx.status(200), ctx.json({ logs: [mockLog] })),
),
);
server.use(
rest.post(`${ENVIRONMENT.baseURL}/api/v3/query_range`, (req, res, ctx) =>
res(ctx.status(200), ctx.json(mockQueryRangeResponse)),
),
);
});
it('renders without crashing', async () => {
await act(async () => {
renderContextLogRenderer();
});
await waitFor(() => {
expect(screen.getAllByText('Load more')).toHaveLength(2);
expect(screen.getByText(/Test log message/)).toBeInTheDocument();
});
});
it('loads new logs when clicking Load more button', async () => {
await act(async () => {
renderContextLogRenderer();
});
await waitFor(() => {
expect(screen.getAllByText('Load more')).toHaveLength(2);
expect(screen.getByText(/Test log message/)).toBeInTheDocument();
});
const loadMoreButtons = screen.getAllByText('Load more');
await act(async () => {
await userEvent.click(loadMoreButtons[1]);
});
await waitFor(() => {
expect(screen.getAllByText(/Failed to authenticate/)).toHaveLength(3);
});
});
});

View File

@ -0,0 +1,146 @@
import { ILog } from 'types/api/logs/log';
import {
BaseAutocompleteData,
DataTypes,
} from 'types/api/queryBuilder/queryAutocompleteResponse';
import { Query, TagFilter } from 'types/api/queryBuilder/queryBuilderData';
import { EQueryType } from 'types/common/dashboard';
import { DataSource } from 'types/common/queryBuilder';
export const mockLog: ILog = {
id: 'test-log-id',
date: '2024-03-20T10:00:00Z',
timestamp: '2024-03-20T10:00:00Z',
body: 'Test log message',
attributesString: {},
attributesInt: {},
attributesFloat: {},
attributes_string: {},
severityText: 'info',
severityNumber: 0,
traceId: '',
spanID: '',
traceFlags: 0,
resources_string: {},
scope_string: {},
severity_text: 'info',
severity_number: 0,
};
export const mockQuery: Query = {
queryType: EQueryType.QUERY_BUILDER,
builder: {
queryData: [
{
aggregateOperator: 'count',
disabled: false,
queryName: 'A',
groupBy: [],
orderBy: [],
limit: 100,
dataSource: DataSource.LOGS,
aggregateAttribute: {
key: 'body',
type: 'string',
dataType: DataTypes.String,
isColumn: true,
},
timeAggregation: 'sum',
functions: [],
having: [],
stepInterval: 60,
legend: '',
filters: {
items: [],
op: 'AND',
},
expression: 'A',
reduceTo: 'sum',
},
],
queryFormulas: [],
},
clickhouse_sql: [],
id: 'test-query-id',
promql: [],
};
const mockBaseAutocompleteData: BaseAutocompleteData = {
key: 'service',
type: 'string',
dataType: DataTypes.String,
isColumn: true,
};
export const mockTagFilter: TagFilter = {
items: [
{
id: 'test-filter-id',
key: mockBaseAutocompleteData,
op: '=',
value: 'test-service',
},
],
op: 'AND',
};
export const mockQueryRangeResponse = {
status: 'success',
data: {
resultType: '',
result: [
{
queryName: 'A',
list: [
{
timestamp: '2025-04-29T09:55:22.462039242Z',
data: {
attributes_bool: {},
attributes_number: {},
attributes_string: {
'log.file.path':
'/var/log/pods/generator_mongodb-0_755b8973-28c1-4698-a20f-22ee85c52c3f/mongodb/0.log',
'log.iostream': 'stdout',
logtag: 'F',
},
body:
'{"t":{"$date":"2025-04-29T09:55:22.461+00:00"},"s":"I", "c":"ACCESS", "id":5286307, "ctx":"conn231150","msg":"Failed to authenticate","attr":{"client":"10.32.2.33:58258","isSpeculative":false,"isClusterMember":false,"mechanism":"SCRAM-SHA-1","user":"$(MONGO_USER)","db":"admin","error":"UserNotFound: Could not find user \\"$(MONGO_USER)\\" for db \\"admin\\"","result":11,"metrics":{"conversation_duration":{"micros":473,"summary":{"0":{"step":1,"step_total":2,"duration_micros":446}}}},"extraInfo":{}}}',
id: '2wOlVEhbqYipTUgs3PRMFF1hqjJ',
resources_string: {
'cloud.account.id': 'signoz-staging',
'cloud.availability_zone': 'us-central1-c',
'cloud.platform': 'gcp_kubernetes_engine',
'cloud.provider': 'gcp',
'container.image.name': 'docker.io/bitnami/mongodb',
'container.image.tag': '7.0.14-debian-12-r0',
'deployment.environment': 'sample-flask',
'host.id': '6006012725680193244',
'host.name': 'gke-mgmt-pl-generator-e2st4-sp-41c1bdc8-d54x',
'k8s.cluster.name': 'mgmt',
'k8s.container.name': 'mongodb',
'k8s.container.restart_count': '0',
'k8s.namespace.name': 'generator',
'k8s.node.name': 'gke-mgmt-pl-generator-e2st4-sp-41c1bdc8-d54x',
'k8s.node.uid': 'ef650183-226d-41c0-8295-aeec210b15dd',
'k8s.pod.name': 'mongodb-0',
'k8s.pod.start_time': '2025-04-26T04:47:44Z',
'k8s.pod.uid': '755b8973-28c1-4698-a20f-22ee85c52c3f',
'k8s.statefulset.name': 'mongodb',
'os.type': 'linux',
'service.name': 'mongodb',
},
scope_name: '',
scope_string: {},
scope_version: '',
severity_number: 0,
severity_text: '',
span_id: '',
trace_flags: 0,
trace_id: '',
},
},
],
},
],
},
};

View File

@ -134,6 +134,8 @@ export const useContextLogData = ({
enabled: !!requestData,
onSuccess: handleSuccess,
},
undefined, // params
false, // isDependentOnQB
);
const handleShowNextLines = useCallback(() => {

View File

@ -285,6 +285,12 @@
.lightMode {
.query-builder-search-v2 {
.ant-select-selector {
border-color: var(--bg-vanilla-300) !important;
background-color: var(--bg-vanilla-100) !important;
color: var(--bg-ink-200);
}
.content {
.operator-for {
.operator-for-text {

View File

@ -4,7 +4,6 @@
.all-errors-quick-filter-section {
width: 0%;
flex-shrink: 0;
color: var(--bg-vanilla-100);
}
.all-errors-right-section {