Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[8.x] [Dataset quality] remove usage of dataStreamStats API in serverless (#192839) #193468

Merged
merged 2 commits into from
Sep 20, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
* 2.0.
*/

import React, { useCallback } from 'react';
import React from 'react';
import useToggle from 'react-use/lib/useToggle';
import { i18n } from '@kbn/i18n';
import { FormattedMessage } from '@kbn/i18n-react';
Expand Down Expand Up @@ -54,7 +54,7 @@ export const PrivilegesWarningIconWrapper = ({
}) => {
const [isPopoverOpen, togglePopover] = useToggle(false);

const handleButtonClick = useCallback(() => togglePopover(true), [togglePopover]);
const handleButtonClick = togglePopover;

if (hasPrivileges) {
return <>{children}</>;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,7 @@ import {
import { DataPlaceholder } from './data_placeholder';

export function DatasetsActivity() {
const { datasetsActivity, isDatasetsActivityLoading, isUserAuthorizedForDataset } =
useSummaryPanelContext();
const { datasetsActivity, isDatasetsActivityLoading } = useSummaryPanelContext();
const text = `${datasetsActivity.active} ${tableSummaryOfText} ${datasetsActivity.total}`;

return (
Expand All @@ -26,7 +25,7 @@ export function DatasetsActivity() {
tooltip={summaryPanelDatasetsActivityTooltipText}
value={text}
isLoading={isDatasetsActivityLoading}
isUserAuthorizedForDataset={isUserAuthorizedForDataset}
isUserAuthorizedForDataset={true}
/>
);
}
Original file line number Diff line number Diff line change
Expand Up @@ -300,46 +300,37 @@ export const getDatasetQualityTableColumns = ({
),
width: '140px',
},
...(canUserMonitorDataset && canUserMonitorAnyDataStream
? [
{
name: (
<EuiTableHeader data-test-subj="datasetQualityLastActivityColumn">
{lastActivityColumnName}
</EuiTableHeader>
),
field: 'lastActivity',
render: (timestamp: number, { userPrivileges, title }: DataStreamStat) => (
<PrivilegesWarningIconWrapper
title={`lastActivity-${title}`}
hasPrivileges={userPrivileges?.canMonitor ?? true}
>
<EuiSkeletonRectangle
width="200px"
height="20px"
borderRadius="m"
isLoading={loadingDataStreamStats}
>
{!isActiveDataset(timestamp) ? (
<EuiFlexGroup gutterSize="xs" alignItems="center">
<EuiText size="s">{inactiveDatasetActivityColumnDescription}</EuiText>
<EuiToolTip position="top" content={inactiveDatasetActivityColumnTooltip}>
<EuiIcon tabIndex={0} type="iInCircle" size="s" />
</EuiToolTip>
</EuiFlexGroup>
) : (
fieldFormats
.getDefaultInstance(KBN_FIELD_TYPES.DATE, [ES_FIELD_TYPES.DATE])
.convert(timestamp)
)}
</EuiSkeletonRectangle>
</PrivilegesWarningIconWrapper>
),
width: '300px',
sortable: true,
},
]
: []),
{
name: (
<EuiTableHeader data-test-subj="datasetQualityLastActivityColumn">
{lastActivityColumnName}
</EuiTableHeader>
),
field: 'lastActivity',
render: (timestamp: number) => (
<EuiSkeletonRectangle
width="200px"
height="20px"
borderRadius="m"
isLoading={loadingDataStreamStats}
>
{!isActiveDataset(timestamp) ? (
<EuiFlexGroup gutterSize="xs" alignItems="center">
<EuiText size="s">{inactiveDatasetActivityColumnDescription}</EuiText>
<EuiToolTip position="top" content={inactiveDatasetActivityColumnTooltip}>
<EuiIcon tabIndex={0} type="iInCircle" size="s" />
</EuiToolTip>
</EuiFlexGroup>
) : (
fieldFormats
.getDefaultInstance(KBN_FIELD_TYPES.DATE, [ES_FIELD_TYPES.DATE])
.convert(timestamp)
)}
</EuiSkeletonRectangle>
),
width: '300px',
sortable: true,
},
{
name: actionsColumnName,
render: (dataStreamStat: DataStreamStat) => (
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ import { _IGNORED } from '../../../../common/es_fields';
import { DataStreamDetails, DataStreamSettings } from '../../../../common/api_types';
import { createDatasetQualityESClient } from '../../../utils';
import { dataStreamService, datasetQualityPrivileges } from '../../../services';
import { getDataStreamsStats } from '../get_data_streams_stats';
import { getDataStreams } from '../get_data_streams';

export async function getDataStreamSettings({
esClient,
Expand Down Expand Up @@ -49,28 +49,27 @@ export async function getDataStreamDetails({
dataStream,
start,
end,
sizeStatsAvailable = true,
isServerless,
}: {
esClient: ElasticsearchClient;
dataStream: string;
start: number;
end: number;
sizeStatsAvailable?: boolean; // Only Needed to determine whether `_stats` endpoint is available https://github.com/elastic/kibana/issues/178954
isServerless: boolean;
}): Promise<DataStreamDetails> {
throwIfInvalidDataStreamParams(dataStream);

const hasAccessToDataStream = (
await datasetQualityPrivileges.getHasIndexPrivileges(esClient, [dataStream], ['monitor'])
)[dataStream];

const lastActivity = hasAccessToDataStream
const esDataStream = hasAccessToDataStream
? (
await getDataStreamsStats({
await getDataStreams({
esClient,
dataStreams: [dataStream],
sizeStatsAvailable,
datasetQuery: dataStream,
})
).items[0]?.lastActivity
).dataStreams[0]
: undefined;

try {
Expand All @@ -82,17 +81,17 @@ export async function getDataStreamDetails({
);

const whenSizeStatsNotAvailable = NaN; // This will indicate size cannot be calculated
const avgDocSizeInBytes = sizeStatsAvailable
? hasAccessToDataStream && dataStreamSummaryStats.docsCount > 0
? await getAvgDocSizeInBytes(esClient, dataStream)
: 0
: whenSizeStatsNotAvailable;
const avgDocSizeInBytes = isServerless
? whenSizeStatsNotAvailable
: hasAccessToDataStream && dataStreamSummaryStats.docsCount > 0
? await getAvgDocSizeInBytes(esClient, dataStream)
: 0;
const sizeBytes = Math.ceil(avgDocSizeInBytes * dataStreamSummaryStats.docsCount);

return {
...dataStreamSummaryStats,
sizeBytes,
lastActivity,
lastActivity: esDataStream?.lastActivity,
userPrivileges: {
canMonitor: hasAccessToDataStream,
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,8 +40,22 @@ describe('getDataStreams', () => {
const esClientMock = elasticsearchServiceMock.createElasticsearchClient();
const result = await getDataStreams({
esClient: esClientMock,
types: ['logs'],
datasetQuery: 'nginx-*',
types: ['logs', 'metrics'],
uncategorisedOnly: true,
});
expect(dataStreamService.getMatchingDataStreams).toHaveBeenCalledWith(
expect.anything(),
'logs-*-*,metrics-*-*'
);

expect(result.datasetUserPrivileges.canMonitor).toBe(true);
});

it('Passes datasetQuery parameter to the DataStreamService', async () => {
const esClientMock = elasticsearchServiceMock.createElasticsearchClient();
const result = await getDataStreams({
esClient: esClientMock,
datasetQuery: 'logs-nginx-*',
uncategorisedOnly: true,
});
expect(dataStreamService.getMatchingDataStreams).toHaveBeenCalledWith(
Expand All @@ -58,20 +72,18 @@ describe('getDataStreams', () => {
const results = await getDataStreams({
esClient: esClientMock,
types: ['logs'],
datasetQuery: 'nginx-*',
uncategorisedOnly: true,
});
expect(results.items.length).toBe(1);
expect(results.dataStreams.length).toBe(1);
});
it('Returns the correct number of results when false', async () => {
const esClientMock = elasticsearchServiceMock.createElasticsearchClient();
const results = await getDataStreams({
esClient: esClientMock,
types: ['logs'],
datasetQuery: 'nginx-*',
uncategorisedOnly: false,
});
expect(results.items.length).toBe(5);
expect(results.dataStreams.length).toBe(5);
});
});
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,18 +12,20 @@ import { dataStreamService, datasetQualityPrivileges } from '../../../services';

export async function getDataStreams(options: {
esClient: ElasticsearchClient;
types: DataStreamType[];
types?: DataStreamType[];
datasetQuery?: string;
uncategorisedOnly: boolean;
uncategorisedOnly?: boolean;
}) {
const { esClient, types, datasetQuery, uncategorisedOnly } = options;
const { esClient, types = [], datasetQuery, uncategorisedOnly } = options;

const datasetNames = types.map((type) =>
streamPartsToIndexPattern({
typePattern: type,
datasetPattern: datasetQuery ? `${datasetQuery}` : '*-*',
})
);
const datasetNames = datasetQuery
? [datasetQuery]
: types.map((type) =>
streamPartsToIndexPattern({
typePattern: type,
datasetPattern: '*-*',
})
);

const datasetUserPrivileges = await datasetQualityPrivileges.getDatasetPrivileges(
esClient,
Expand All @@ -32,7 +34,7 @@ export async function getDataStreams(options: {

if (!datasetUserPrivileges.canMonitor) {
return {
items: [],
dataStreams: [],
datasetUserPrivileges,
};
}
Expand All @@ -59,13 +61,15 @@ export async function getDataStreams(options: {
const mappedDataStreams = filteredDataStreams.map((dataStream) => ({
name: dataStream.name,
integration: dataStream._meta?.package?.name,
// @ts-expect-error
lastActivity: dataStream.maximum_timestamp,
userPrivileges: {
canMonitor: dataStreamsPrivileges[dataStream.name],
},
}));

return {
items: mappedDataStreams,
dataStreams: mappedDataStreams,
datasetUserPrivileges,
};
}
Original file line number Diff line number Diff line change
Expand Up @@ -12,42 +12,31 @@ import { indexStatsService } from '../../../services';
export async function getDataStreamsStats({
esClient,
dataStreams,
sizeStatsAvailable = true,
}: {
esClient: ElasticsearchClient;
dataStreams: string[];
sizeStatsAvailable?: boolean; // Only Needed to determine whether `_stats` endpoint is available https://github.com/elastic/kibana/issues/178954
}) {
}): Promise<Record<string, { size: string; sizeBytes: number; totalDocs: number }>> {
if (!dataStreams.length) {
return {
items: [],
};
return {};
}

const matchingDataStreamsStats = dataStreamService.getStreamsStats(esClient, dataStreams);

const indicesDocsCount = sizeStatsAvailable
? indexStatsService.getIndicesDocCounts(esClient, dataStreams)
: Promise.resolve(null);
const indicesDocsCount = indexStatsService.getIndicesDocCounts(esClient, dataStreams);

const [indicesDocsCountStats, dataStreamsStats] = await Promise.all([
indicesDocsCount,
matchingDataStreamsStats,
]);

const mappedDataStreams = dataStreamsStats.map((dataStream) => {
return {
name: dataStream.data_stream,
size: dataStream.store_size?.toString(),
sizeBytes: dataStream.store_size_bytes,
lastActivity: dataStream.maximum_timestamp,
totalDocs: sizeStatsAvailable
? indicesDocsCountStats!.docsCountPerDataStream[dataStream.data_stream] || 0
: null,
};
});

return {
items: mappedDataStreams,
};
return dataStreamsStats.reduce(
(acc, dataStream) => ({
...acc,
[dataStream.data_stream]: {
size: dataStream.store_size!.toString(),
sizeBytes: dataStream.store_size_bytes,
totalDocs: indicesDocsCountStats!.docsCountPerDataStream[dataStream.data_stream],
},
}),
{}
);
}
Loading