Skip to content
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 @@ -26,6 +26,10 @@ export const getCustomMetricLabel = (metric: SnapshotCustomMetricInput) => {
defaultMessage: 'Rate of {field}',
values: { field: metric.field },
}),
last_value: i18n.translate('xpack.infra.waffle.aggregationNames.last_value', {
defaultMessage: 'Last value of {field}',
values: { field: metric.field },
}),
};
return metric.label ? metric.label : METRIC_LABELS[metric.aggregation];
};
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ export const METRIC_EXPLORER_AGGREGATIONS = [
'p95',
'p99',
'custom',
'last_value',
] as const;

export const OMITTED_AGGREGATIONS_FOR_CUSTOM_METRICS = ['custom', 'rate', 'p95', 'p99'];
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -109,9 +109,9 @@ export const SnapshotRequestRT = rt.intersection([
groupBy: rt.union([SnapshotGroupByRT, rt.null]),
nodeType: ItemTypeRT,
sourceId: rt.string,
includeTimeseries: rt.union([rt.boolean, createLiteralValueFromUndefinedRT(true)]),
}),
rt.partial({
includeTimeseries: rt.union([rt.boolean, createLiteralValueFromUndefinedRT(false)]),
accountId: rt.string,
region: rt.string,
kuery: rt.string,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,7 @@ export const ExpressionChart = ({
region,
timerange,
schema,
includeTimeseries: true,
});

const metric = {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ export const ConditionalToolTip = ({ node, nodeType, currentTime }: Props) => {
accountId: '',
region: '',
schema: preferredSchema,
includeTimeseries: true,
});

const dataNode = first(nodes);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,12 +15,9 @@ import type {
} from '../../../../../common/http_api/snapshot_api';
import { SnapshotNodeResponseRT } from '../../../../../common/http_api/snapshot_api';

export interface UseSnapshotRequest
extends Omit<SnapshotRequest, 'timerange' | 'includeTimeseries' | 'schema'> {
export interface UseSnapshotRequest extends Omit<SnapshotRequest, 'timerange' | 'schema'> {
currentTime: number;
includeTimeseries?: boolean;
timerange?: InfraTimerangeInput;

schema?: DataSchemaFormat | null;
}

Expand Down Expand Up @@ -61,7 +58,7 @@ const buildPayload = (args: UseSnapshotRequest): SnapshotRequest => {
dropPartialBuckets = true,
kuery,
groupBy = null,
includeTimeseries = true,
includeTimeseries = false,
metrics,
nodeType,
overrideCompositeSize,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import {
import type { ESSearchClient } from '@kbn/metrics-data-access-plugin/server';
import type { estypes } from '@elastic/elasticsearch';
import { kqlQuery, termQuery } from '@kbn/observability-plugin/server';
import { isDerivativeAgg } from '@kbn/metrics-data-access-plugin/common/inventory_models';
import { TIMESTAMP_FIELD } from '../../../../common/constants';
import type { SnapshotRequest } from '../../../../common/http_api';
import type { InfraSource } from '../../../lib/sources';
Expand Down Expand Up @@ -59,6 +60,12 @@ export const transformRequestToMetricsAPIRequest = async ({
},
};

const includeTimeseries =
snapshotRequest.includeTimeseries ??
Object.values(transformed).some((metric) =>
Object.values(metric.aggregations).some(isDerivativeAgg)
);

const metricsApiRequest: MetricsAPIRequest = {
indexPattern: sourceOverrides?.indexPattern ?? source.configuration.metricAlias,
timerange: {
Expand All @@ -70,7 +77,7 @@ export const transformRequestToMetricsAPIRequest = async ({
: compositeSize,
alignDataToEnd: true,
dropPartialBuckets: snapshotRequest.dropPartialBuckets ?? true,
includeTimeseries: snapshotRequest.includeTimeseries,
includeTimeseries,
filters,
};

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,10 +35,17 @@ export const transformSnapshotMetricsToMetricsAPIMetrics = async (
id: customId,
aggregations: {
[customId]: {
top_metrics: {
metrics: { field: metric.field },
size: 1,
sort: { '@timestamp': 'desc' },
filter: {
exists: { field: metric.field },
},
aggs: {
value: {
top_metrics: {
metrics: { field: metric.field },
size: 1,
sort: { '@timestamp': 'desc' },
},
},
},
},
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,14 +21,20 @@ import {
PercentilesKeyedTypeRT,
TopMetricsTypeRT,
MetricValueTypeRT,
FilterWithNestedAggRT,
} from '../types';

const BASE_COLUMNS = [{ name: 'timestamp', type: 'date' }] as MetricsAPIColumn[];

const ValueObjectTypeRT = rt.union([rt.string, rt.number, MetricValueTypeRT]);
const ValueObjectTypeRT = rt.union([
rt.string,
rt.number,
MetricValueTypeRT,
FilterWithNestedAggRT,
]);
type ValueObjectType = rt.TypeOf<typeof ValueObjectTypeRT>;

const getValue = (valueObject: ValueObjectType) => {
const getValue = (valueObject: ValueObjectType): number | null | object[] => {
if (NormalizedMetricValueRT.is(valueObject)) {
return valueObject.normalized_value || valueObject.value;
}
Expand Down Expand Up @@ -61,13 +67,35 @@ const getValue = (valueObject: ValueObjectType) => {
return valueObject.top.map((res) => res.metrics);
}

// Handle filter aggregation wrapping another aggregation (e.g., filter + top_metrics)
if (FilterWithNestedAggRT.is(valueObject)) {
const nestedKey = Object.keys(valueObject).find((k) => k !== 'doc_count' && k !== 'meta');
if (nestedKey) {
const nestedValue = (valueObject as Record<string, unknown>)[nestedKey];
if (MetricValueTypeRT.is(nestedValue) || FilterWithNestedAggRT.is(nestedValue)) {
return getValue(nestedValue as ValueObjectType);
}
}
}

return null;
};

const dropOutOfBoundsBuckets =
(from: number, to: number, bucketSizeInMillis: number) => (row: MetricsAPIRow) =>
row.timestamp >= from && row.timestamp + bucketSizeInMillis <= to;

// Extract first numeric value from top_metrics result for non-metadata fields
const extractFirstNumericValue = (metricsArray: object[]): number | null => {
const firstItem = first(metricsArray);
if (!firstItem) return null;
const firstValue = first(values(firstItem));
return typeof firstValue === 'number' ? firstValue : null;
};

// Metadata key that should keep full top_metrics array
const META_KEY = '__metadata__';

export const convertBucketsToRows = (
options: MetricsAPIRequest,
buckets: Bucket[]
Expand All @@ -76,7 +104,9 @@ export const convertBucketsToRows = (
const ids = options.metrics.map((metric) => metric.id);
const metrics = ids.reduce((acc, id) => {
const valueObject = get(bucket, [id]);
acc[id] = ValueObjectTypeRT.is(valueObject) ? getValue(valueObject) : null;
const value = ValueObjectTypeRT.is(valueObject) ? getValue(valueObject) : null;
// For non-metadata fields, extract numeric value from top_metrics array
acc[id] = Array.isArray(value) && id !== META_KEY ? extractFirstNumericValue(value) : value;
return acc;
}, {} as Record<string, number | null | object[]>);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
import type { AggregationOptionsByType } from '@kbn/es-types';

import Boom from '@hapi/boom';
import { isDerivativeAgg } from '../../../../common/inventory_models';
import { afterKeyObjectRT } from '../../../../common/http_api';
import { TIMESTAMP } from '../../../../common/constants';
import type { MetricsAPIRequest } from '../../../../common/http_api/metrics_api';
Expand Down Expand Up @@ -65,8 +66,12 @@ export const createCompositeAggregations = (options: MetricsAPIRequest) => {
throw Boom.badRequest('groupBy must be informed.');
}

if (!options.includeTimeseries && !!options.metrics.find((p) => p.id === 'logRate')) {
throw Boom.badRequest('logRate metric is not supported without time series');
const isDerivativeMetrics = Object.values(options.metrics).some((metric) =>
Object.values(metric.aggregations).some(isDerivativeAgg)
);

if (!options.includeTimeseries && isDerivativeMetrics) {
throw Boom.badRequest('derivative aggregations are not supported without time series');
}

const after = getAfterKey(options);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,12 @@ export const MaxPeriodFilterExistsTypeRT = rt.type({
period: BasicMetricValueRT,
});

// Filter aggregation that wraps another aggregation (e.g., filter + top_metrics)
export const FilterWithNestedAggRT = rt.intersection([
rt.type({ doc_count: rt.number }),
rt.record(rt.string, rt.unknown),
]);

export const MetricValueTypeRT = rt.union([
BasicMetricValueRT,
NormalizedMetricValueRT,
Expand Down