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

[Dataset quality] remove usage of dataStreamStats API in serverless #192839

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
501b092
remove usage of dataStreamStats API in serverless + using dataStream …
yngrdyn Sep 13, 2024
b69c604
Merge branch 'main' into 192166-dataset-quality-remove-datastreams-st…
yngrdyn Sep 13, 2024
0ff68b8
Merge branch 'main' into 192166-dataset-quality-remove-datastreams-st…
yngrdyn Sep 16, 2024
2481d61
Merge branch 'main' into 192166-dataset-quality-remove-datastreams-st…
yngrdyn Sep 17, 2024
803cf2c
Merge branch 'main' into 192166-dataset-quality-remove-datastreams-st…
yngrdyn Sep 17, 2024
8772af7
Merge branch 'main' into 192166-dataset-quality-remove-datastreams-st…
yngrdyn Sep 17, 2024
2cb6646
Merge branch 'main' into 192166-dataset-quality-remove-datastreams-st…
yngrdyn Sep 18, 2024
3dfbd99
ts-errors are expected because elastic client has not being updated yet
yngrdyn Sep 18, 2024
a5b76b8
Merge branch 'main' into 192166-dataset-quality-remove-datastreams-st…
yngrdyn Sep 18, 2024
733a687
with dataStream API verbose mode, last activity is always available
yngrdyn Sep 18, 2024
10f16e3
Merge branch 'main' into 192166-dataset-quality-remove-datastreams-st…
yngrdyn Sep 18, 2024
472f9b9
fixing type error
yngrdyn Sep 18, 2024
398f95d
Merge branch 'main' into 192166-dataset-quality-remove-datastreams-st…
yngrdyn Sep 18, 2024
38bb9bb
Merge branch 'main' into 192166-dataset-quality-remove-datastreams-st…
yngrdyn Sep 18, 2024
9a104c6
Merge branch 'main' into 192166-dataset-quality-remove-datastreams-st…
yngrdyn Sep 19, 2024
cd56be8
PR review comments
yngrdyn Sep 19, 2024
7a0cd44
Merge branch '192166-dataset-quality-remove-datastreams-stats-api-usa…
yngrdyn Sep 19, 2024
f161b78
Merge branch 'main' into 192166-dataset-quality-remove-datastreams-st…
yngrdyn Sep 19, 2024
1d00819
Merge branch 'main' into 192166-dataset-quality-remove-datastreams-st…
yngrdyn Sep 19, 2024
b2a6926
fixing build after refactor
yngrdyn Sep 19, 2024
8216546
Merge branch 'main' into 192166-dataset-quality-remove-datastreams-st…
yngrdyn Sep 19, 2024
94a53ac
Merge branch 'main' into 192166-dataset-quality-remove-datastreams-st…
yngrdyn Sep 19, 2024
3e37cba
Merge branch 'main' into 192166-dataset-quality-remove-datastreams-st…
yngrdyn Sep 19, 2024
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}
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Last Activity is now always enabled through dataStreams API verbose mode

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we completely remove this prop in favour of this change now ?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This generic component is used also for Estimated Size. In https://github.com/elastic/logs-dev/issues/179 I'll do a refactor

/>
);
}
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;
yngrdyn marked this conversation as resolved.
Show resolved Hide resolved
}): 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
yngrdyn marked this conversation as resolved.
Show resolved Hide resolved
? 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,
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

package of elasticsearch has not been released yet, this will be removed when the new package is in place

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you update the comment like, remove this error post a date or PR merge. This way its trackable in code as this comment will get lost in time

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Don't worry, I won't forget. As soon as 8.16 is released I'll get rid of it

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],
},
}),
{}
);
yngrdyn marked this conversation as resolved.
Show resolved Hide resolved
}
Loading