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] Support failure store #199806

Draft
wants to merge 27 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
81ad3fa
Fetching failed docs and showing them in the table
yngrdyn Nov 12, 2024
301a53a
Merge branch 'elastic:main' into main
yngrdyn Nov 12, 2024
2ad742f
fixing tests
yngrdyn Nov 12, 2024
4fe638e
Addressing copies across table and page
yngrdyn Nov 12, 2024
56a1793
Merge branch 'main' into dataset-quality-support-for-failure-store
yngrdyn Nov 12, 2024
e11fabf
Column names changed in tests
yngrdyn Nov 13, 2024
a9f173c
Merge branch 'main' into dataset-quality-support-for-failure-store
yngrdyn Nov 13, 2024
41d249a
Adding failed info to dataset details
yngrdyn Nov 14, 2024
91e2c3e
Addresing Pr cmments
yngrdyn Nov 18, 2024
f753581
extracting percentage calculator to an util
yngrdyn Nov 19, 2024
74df05c
merging useDocsChart hooks for quality issues + removing unnecesary u…
yngrdyn Nov 19, 2024
73a90be
Added qualityIssuesChart to the store + syncing URL
yngrdyn Nov 19, 2024
5ff14d6
totalDocs should include also failedDocs
yngrdyn Nov 19, 2024
1ba2535
Merge branch 'main' into dataset-quality-support-for-failure-store
yngrdyn Nov 19, 2024
b70c960
fixing i18n problems
yngrdyn Nov 19, 2024
36131aa
fixing build
yngrdyn Nov 19, 2024
ad7d150
fixing copies
yngrdyn Nov 20, 2024
5f1b389
Added e2e tests to fialure store support
yngrdyn Nov 21, 2024
2e47a6b
Merge branch 'main' into dataset-quality-support-for-failure-store
yngrdyn Nov 21, 2024
3715579
fixing i18n id duplicated
yngrdyn Nov 21, 2024
dd9816e
fixing some e2e tests
yngrdyn Nov 22, 2024
076cb6c
fixing e2e tests
yngrdyn Nov 25, 2024
0057ecb
Merge branch 'main' into dataset-quality-support-for-failure-store
yngrdyn Nov 26, 2024
f10abac
fixing tests
yngrdyn Nov 26, 2024
f9ba989
fixing some tests
yngrdyn Nov 27, 2024
c6846eb
Merge branch 'elastic:main' into main
yngrdyn Nov 27, 2024
895110f
Merge remote-tracking branch 'origin/main' into dataset-quality-suppo…
yngrdyn Nov 27, 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 @@ -10,7 +10,11 @@
import { Client, estypes } from '@elastic/elasticsearch';
import { pipeline, Readable } from 'stream';
import { LogDocument } from '@kbn/apm-synthtrace-client/src/lib/logs';
import { IngestProcessorContainer, MappingTypeMapping } from '@elastic/elasticsearch/lib/api/types';
import {
IndicesIndexSettings,
IngestProcessorContainer,
MappingTypeMapping,
} from '@elastic/elasticsearch/lib/api/types';
import { ValuesType } from 'utility-types';
import { SynthtraceEsClient, SynthtraceEsClientOptions } from '../shared/base_client';
import { getSerializeTransform } from '../shared/get_serialize_transform';
Expand Down Expand Up @@ -52,7 +56,11 @@ export class LogsSynthtraceEsClient extends SynthtraceEsClient<LogDocument> {
}
}

async createComponentTemplate(name: string, mappings: MappingTypeMapping) {
async createComponentTemplate(
name: string,
mappings?: MappingTypeMapping,
settings?: IndicesIndexSettings
) {
const isTemplateExisting = await this.client.cluster.existsComponentTemplate({ name });

if (isTemplateExisting) return this.logger.info(`Component template already exists: ${name}`);
Expand All @@ -61,7 +69,8 @@ export class LogsSynthtraceEsClient extends SynthtraceEsClient<LogDocument> {
await this.client.cluster.putComponentTemplate({
name,
template: {
mappings,
...((mappings && { mappings }) || {}),
...((settings && { settings }) || {}),
},
});
this.logger.info(`Component template successfully created: ${name}`);
Expand Down Expand Up @@ -124,16 +133,17 @@ export class LogsSynthtraceEsClient extends SynthtraceEsClient<LogDocument> {
}
}

async createCustomPipeline(processors: IngestProcessorContainer[]) {
async createCustomPipeline(processors: IngestProcessorContainer[], pipelineId?: string) {
const id = pipelineId ?? LogsCustom;
try {
this.client.ingest.putPipeline({
id: LogsCustom,
id,
processors,
version: 1,
});
this.logger.info(`Custom pipeline created: ${LogsCustom}`);
this.logger.info(`Custom pipeline created: ${id}`);
} catch (err) {
this.logger.error(`Custom pipeline creation failed: ${LogsCustom} - ${err.message}`);
this.logger.error(`Custom pipeline creation failed: ${id} - ${err.message}`);
}
}

Expand Down
5 changes: 5 additions & 0 deletions x-pack/plugins/data_quality/common/url_schema/common.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,11 @@ import * as rt from 'io-ts';

export const DATA_QUALITY_URL_STATE_KEY = 'pageState';

export const qualityIssuesRT = rt.keyof({
degradedDocs: null,
failedDocs: null,
});

export const directionRT = rt.keyof({
asc: null,
desc: null,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
*/

import * as rt from 'io-ts';
import { dataStreamRT, degradedFieldRT, timeRangeRT } from './common';
import { dataStreamRT, degradedFieldRT, qualityIssuesRT, timeRangeRT } from './common';

export const urlSchemaRT = rt.exact(
rt.intersection([
Expand All @@ -16,6 +16,7 @@ export const urlSchemaRT = rt.exact(
rt.partial({
v: rt.literal(1),
timeRange: timeRangeRT,
qualityIssuesChart: qualityIssuesRT,
breakdownField: rt.string,
degradedFields: degradedFieldRT,
expandedDegradedField: rt.string,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ export const getStateFromUrlValue = (
dataStream: urlValue.dataStream,
timeRange: urlValue.timeRange,
degradedFields: urlValue.degradedFields,
qualityIssuesChart: urlValue.qualityIssuesChart,
breakdownField: urlValue.breakdownField,
expandedDegradedField: urlValue.expandedDegradedField,
showCurrentQualityIssues: urlValue.showCurrentQualityIssues,
Expand All @@ -30,6 +31,7 @@ export const getUrlValueFromState = (
timeRange: state.timeRange,
degradedFields: state.degradedFields,
breakdownField: state.breakdownField,
qualityIssuesChart: state.qualityIssuesChart,
expandedDegradedField: state.expandedDegradedField,
showCurrentQualityIssues: state.showCurrentQualityIssues,
v: 1,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,12 @@ export const getDataStreamDegradedDocsResponseRt = rt.type({

export type DataStreamDegradedDocsResponse = rt.TypeOf<typeof getDataStreamDegradedDocsResponseRt>;

export const getDataStreamFailedDocsResponseRt = rt.type({
failedDocs: rt.array(dataStreamDocsStatRt),
});

export type DataStreamFailedDocsResponse = rt.TypeOf<typeof getDataStreamFailedDocsResponseRt>;

export const integrationDashboardRT = rt.type({
id: rt.string,
title: rt.string,
Expand Down Expand Up @@ -182,6 +188,7 @@ export type DataStreamSettings = rt.TypeOf<typeof dataStreamSettingsRt>;
export const dataStreamDetailsRt = rt.partial({
lastActivity: rt.number,
degradedDocsCount: rt.number,
failedDocsCount: rt.number,
docsCount: rt.number,
sizeBytes: rt.number,
services: rt.record(rt.string, rt.array(rt.string)),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ export const NONE = 'none';
export const DEFAULT_TIME_RANGE = { from: 'now-24h', to: 'now' };
export const DEFAULT_DATEPICKER_REFRESH = { value: 60000, pause: false };

export const DEFAULT_DEGRADED_DOCS = {
export const DEFAULT_QUALITY_DOC_STATS = {
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Note

This is now reused by degradedDocs and failedDocs.

count: 0,
percentage: 0,
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,14 @@
*/

import { DataStreamDocsStat } from '../api_types';
import { DEFAULT_DATASET_QUALITY, DEFAULT_DEGRADED_DOCS } from '../constants';
import { DEFAULT_DATASET_QUALITY, DEFAULT_QUALITY_DOC_STATS } from '../constants';
import { DataStreamType, QualityIndicators } from '../types';
import { indexNameToDataStreamParts, mapPercentageToQuality } from '../utils';
import { Integration } from './integration';
import { DataStreamStatType } from './types';

type QualityStat = Omit<DataStreamDocsStat, 'dataset'> & { percentage: number };

export class DataStreamStat {
rawName: string;
type: DataStreamType;
Expand All @@ -30,6 +32,10 @@ export class DataStreamStat {
percentage: number;
count: number;
};
failedDocs: {
percentage: number;
count: number;
};

private constructor(dataStreamStat: DataStreamStat) {
this.rawName = dataStreamStat.rawName;
Expand All @@ -46,6 +52,7 @@ export class DataStreamStat {
this.quality = dataStreamStat.quality;
this.docsInTimeRange = dataStreamStat.docsInTimeRange;
this.degradedDocs = dataStreamStat.degradedDocs;
this.failedDocs = dataStreamStat.failedDocs;
}

public static create(dataStreamStat: DataStreamStatType) {
Expand All @@ -63,36 +70,45 @@ export class DataStreamStat {
userPrivileges: dataStreamStat.userPrivileges,
totalDocs: dataStreamStat.totalDocs,
quality: DEFAULT_DATASET_QUALITY,
degradedDocs: DEFAULT_DEGRADED_DOCS,
degradedDocs: DEFAULT_QUALITY_DOC_STATS,
failedDocs: DEFAULT_QUALITY_DOC_STATS,
};

return new DataStreamStat(dataStreamStatProps);
}

public static fromDegradedDocStat({
public static fromQualityStats({
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Note

We can extend this method with more qualityStats and construct a Dataset from them

datasetName,
degradedDocStat,
failedDocStat,
datasetIntegrationMap,
totalDocs,
}: {
degradedDocStat: DataStreamDocsStat & { percentage: number };
datasetName: string;
degradedDocStat: QualityStat;
failedDocStat: QualityStat;
datasetIntegrationMap: Record<string, { integration: Integration; title: string }>;
totalDocs: number;
}) {
const { type, dataset, namespace } = indexNameToDataStreamParts(degradedDocStat.dataset);
const { type, dataset, namespace } = indexNameToDataStreamParts(datasetName);

const dataStreamStatProps = {
rawName: degradedDocStat.dataset,
rawName: datasetName,
type,
name: dataset,
title: datasetIntegrationMap[dataset]?.title || dataset,
namespace,
integration: datasetIntegrationMap[dataset]?.integration,
quality: mapPercentageToQuality(degradedDocStat.percentage),
quality: mapPercentageToQuality([degradedDocStat.percentage, failedDocStat.percentage]),
docsInTimeRange: totalDocs,
degradedDocs: {
percentage: degradedDocStat.percentage,
count: degradedDocStat.count,
},
failedDocs: {
percentage: failedDocStat.percentage,
count: failedDocStat.count,
},
};

return new DataStreamStat(dataStreamStatProps);
Expand All @@ -102,8 +118,4 @@ export class DataStreamStat {
const avgDocSize = sizeBytes && totalDocs ? sizeBytes / totalDocs : 0;
return avgDocSize * (docsInTimeRange ?? 0);
}

public static calculatePercentage({ totalDocs, count }: { totalDocs?: number; count?: number }) {
return totalDocs && count ? (count / totalDocs) * 100 : 0;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,9 @@ export type DataStreamStatServiceResponse = GetDataStreamsStatsResponse;
export type GetDataStreamsDegradedDocsStatsParams =
APIClientRequestParamsOf<`GET /internal/dataset_quality/data_streams/degraded_docs`>['params'];
export type GetDataStreamsDegradedDocsStatsQuery = GetDataStreamsDegradedDocsStatsParams['query'];
export type GetDataStreamsFailedDocsStatsParams =
APIClientRequestParamsOf<`GET /internal/dataset_quality/data_streams/failed_docs`>['params'];
export type GetDataStreamsFailedDocsStatsQuery = GetDataStreamsFailedDocsStatsParams['query'];

/*
Types for stats based in documents inside a DataStream
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -93,12 +93,9 @@ export const flyoutSummaryText = i18n.translate('xpack.datasetQuality.flyoutSumm
defaultMessage: 'Summary',
});

export const overviewDegradedDocsText = i18n.translate(
'xpack.datasetQuality.flyout.degradedDocsTitle',
{
defaultMessage: 'Degraded docs',
}
);
export const overviewTrendsDocsText = i18n.translate('xpack.datasetQuality.flyout.trendDocsTitle', {
yngrdyn marked this conversation as resolved.
Show resolved Hide resolved
defaultMessage: 'Document trends',
});

export const flyoutDegradedDocsTrendText = i18n.translate(
'xpack.datasetQuality.flyoutDegradedDocsViz',
Expand All @@ -107,6 +104,13 @@ export const flyoutDegradedDocsTrendText = i18n.translate(
}
);

export const flyoutFailedDocsTrendText = i18n.translate(
'xpack.datasetQuality.flyoutFailedDocsViz',
{
defaultMessage: 'Failed documents trend',
}
);

export const flyoutDegradedDocsPercentageText = i18n.translate(
'xpack.datasetQuality.flyoutDegradedDocsPercentage',
{
Expand All @@ -115,6 +119,14 @@ export const flyoutDegradedDocsPercentageText = i18n.translate(
}
);

export const flyoutFailedDocsPercentageText = i18n.translate(
'xpack.datasetQuality.flyoutFailedDocsPercentage',
{
defaultMessage: 'Failed docs %',
description: 'Tooltip label for the percentage of failed documents chart.',
}
);

export const flyoutDocsCountTotalText = i18n.translate(
'xpack.datasetQuality.flyoutDocsCountTotal',
{
Expand Down Expand Up @@ -151,14 +163,14 @@ export const summaryPanelLast24hText = i18n.translate(
export const summaryPanelQualityText = i18n.translate(
'xpack.datasetQuality.summaryPanelQualityText',
{
defaultMessage: 'Data Sets Quality',
defaultMessage: 'Data Set Quality',
}
);

export const summaryPanelQualityTooltipText = i18n.translate(
'xpack.datasetQuality.summaryPanelQualityTooltipText',
{
defaultMessage: 'Quality is based on the percentage of degraded docs in a data set.',
defaultMessage: 'Quality is based on the percentage of degraded and failed docs in a data set.',
}
);

Expand Down Expand Up @@ -319,6 +331,13 @@ export const overviewPanelDatasetQualityIndicatorDegradedDocs = i18n.translate(
}
);

export const overviewPanelDatasetQualityIndicatorFailedDocs = i18n.translate(
'xpack.datasetQuality.details.overviewPanel.datasetQuality.failedDocs',
{
defaultMessage: 'Failed docs',
}
);

export const overviewDegradedFieldsTableLoadingText = i18n.translate(
'xpack.datasetQuality.details.degradedFieldsTableLoadingText',
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -84,5 +84,11 @@ describe('dataset_name', () => {
extractIndexNameFromBackingIndex('.ds-metrics-apm.app.adservice-default-2024.04.29-000001')
).toEqual('metrics-apm.app.adservice-default');
});

it('returns the correct index name if backing index is a failure store index', () => {
expect(
extractIndexNameFromBackingIndex('.fs-logs-elastic_agent-default-2024.11.11-000001')
).toEqual('logs-elastic_agent-default');
});
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,8 @@ export const indexNameToDataStreamParts = (dataStreamName: string) => {
};

export const extractIndexNameFromBackingIndex = (indexString: string): string => {
const pattern = /.ds-(.*?)-[0-9]{4}\.[0-9]{2}\.[0-9]{2}-[0-9]{6}/;
// TODO: Undo this change once ::failures is supported
const pattern = /.(?:ds|fs)-(.*?)-[0-9]{4}\.[0-9]{2}\.[0-9]{2}-[0-9]{6}/;
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Important

Failure store is at the moment a backing index that starts with .fs

const match = indexString.match(pattern);

return match ? match[1] : indexString;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,14 @@
import { POOR_QUALITY_MINIMUM_PERCENTAGE, DEGRADED_QUALITY_MINIMUM_PERCENTAGE } from '../constants';
import { QualityIndicators } from '../types';

export const mapPercentageToQuality = (percentage: number): QualityIndicators => {
return percentage > POOR_QUALITY_MINIMUM_PERCENTAGE
? 'poor'
: percentage > DEGRADED_QUALITY_MINIMUM_PERCENTAGE
? 'degraded'
: 'good';
export const mapPercentageToQuality = (percentages: number[]): QualityIndicators => {
yngrdyn marked this conversation as resolved.
Show resolved Hide resolved
if (percentages.some((percentage) => percentage > POOR_QUALITY_MINIMUM_PERCENTAGE)) {
return 'poor';
}

if (percentages.some((percentage) => percentage > DEGRADED_QUALITY_MINIMUM_PERCENTAGE)) {
return 'degraded';
}

return 'good';
};
Loading