[Infra] Replace lens attribute builder (#174913)

closes [#173720](https://github.com/elastic/kibana/issues/173720)

## Summary

This PR replaces the usage of the Lens attribute builder utils created
by the Obs UX Infra Services team, in favor of the solution created and
maintained by the Visualizations team.

Hosts View

<img width="477" alt="image"
src="401029da-b8f6-4a16-869e-3c83a7823c26">
<img width="477" alt="image"
src="debbc763-fb3c-4e2d-b90a-9bb85df227d9">
<img width="477" alt="image"
src="28bbf07f-d9d2-4100-a84d-44d24bf35573">

Asset Details

<img width="477" alt="image"
src="13218f5a-ec9c-40d8-8348-b980172b4fed">
<img width="477" alt="image"
src="4c650f08-3d93-427a-a5c5-88b607942ce1">
<img width="478" alt="image"
src="868de5ec-5a67-46b7-8cdc-b49373267a7b">


Besides that, a few things in the charts were fixed:
- Centralization of the loading indicator
- Return of the bounds (0% to 100%) for line charts with percentage
values (except for Normalized Load)
- Return of the reference line for the Normalized Load chart.

### For reviewers

- Most of the changes are in the metrics-data-access plugin, where the
chart and formula objects were adapted to the new interface. I've also
grouped the formulas by metric group instead of having 1 file per
formula.


## How to test
- setup a local Kibana instance
- Navigate to Infrastructure > Hosts
- Check if the charts render properly (Do the same for the Asset Details
page and Asset Details flyout)
  - Test if the charts correctly redirects to Lens.

---------

Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com>
This commit is contained in:
Carlos Crespo 2024-01-25 17:19:28 +01:00 committed by GitHub
parent 2ea91b14e7
commit f63d5967d8
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
86 changed files with 989 additions and 1589 deletions

View file

@ -10,13 +10,14 @@ import createContainer from 'constate';
import { i18n } from '@kbn/i18n';
import { findInventoryModel } from '@kbn/metrics-data-access-plugin/common';
import { useLogViewReference } from '../../../hooks/use_log_view_reference';
import { useDataMetricsAdHocDataView } from '../../../hooks/use_metrics_adhoc_data_view';
import { useDataView } from '../../../hooks/use_data_view';
import { useAssetDetailsRenderPropsContext } from './use_asset_details_render_props';
const useDataViews = ({ metricAlias }: { metricAlias: string }) => {
const { asset } = useAssetDetailsRenderPropsContext();
const { dataView: metricsDataView, loading: metricsDataViewLoading } =
useDataMetricsAdHocDataView({ metricAlias });
const { dataView: metricsDataView, loading: metricsDataViewLoading } = useDataView({
index: metricAlias,
});
const {
logViewReference,
getLogsDataView,
@ -47,4 +48,4 @@ const useDataViews = ({ metricAlias }: { metricAlias: string }) => {
};
};
export const [DataViewsProvider, useDataViewsProviderContext] = createContainer(useDataViews);
export const [DataViewsProvider, useDataViewsContext] = createContainer(useDataViews);

View file

@ -21,7 +21,7 @@ import { findInventoryFields } from '@kbn/metrics-data-access-plugin/common';
import { useKibanaContextForPlugin } from '../../../../hooks/use_kibana';
import { InfraLoadingPanel } from '../../../loading';
import { useAssetDetailsRenderPropsContext } from '../../hooks/use_asset_details_render_props';
import { useDataViewsProviderContext } from '../../hooks/use_data_views';
import { useDataViewsContext } from '../../hooks/use_data_views';
import { useDatePickerContext } from '../../hooks/use_date_picker';
import { useAssetDetailsUrlState } from '../../hooks/use_asset_details_url_state';
import { useIntersectingState } from '../../hooks/use_intersecting_state';
@ -33,7 +33,7 @@ export const Logs = () => {
const { getDateRangeInTimestamp, dateRange, autoRefresh } = useDatePickerContext();
const [urlState, setUrlState] = useAssetDetailsUrlState();
const { asset } = useAssetDetailsRenderPropsContext();
const { logs } = useDataViewsProviderContext();
const { logs } = useDataViewsContext();
const { loading: logViewLoading, reference: logViewReference } = logs ?? {};

View file

@ -8,11 +8,11 @@
import React, { useMemo } from 'react';
import { i18n } from '@kbn/i18n';
import { EuiToolTip, EuiButtonIcon } from '@elastic/eui';
import { useMetricsDataViewContext } from '../../../../pages/metrics/hosts/hooks/use_data_view';
import { useKibanaContextForPlugin } from '../../../../hooks/use_kibana';
import { buildMetadataFilter } from './build_metadata_filter';
import { useUnifiedSearchContext } from '../../../../pages/metrics/hosts/hooks/use_unified_search';
import type { Field } from './utils';
import { useDataViewsContext } from '../../hooks/use_data_views';
interface AddMetadataFilterButtonProps {
item: Field;
@ -23,7 +23,7 @@ const filterAddedToastTitle = i18n.translate('xpack.infra.metadataEmbeddable.fil
});
export const AddMetadataFilterButton = ({ item }: AddMetadataFilterButtonProps) => {
const { dataView } = useMetricsDataViewContext();
const { metrics } = useDataViewsContext();
const { searchCriteria } = useUnifiedSearchContext();
const {
@ -45,7 +45,7 @@ export const AddMetadataFilterButton = ({ item }: AddMetadataFilterButtonProps)
const newFilter = buildMetadataFilter({
field: item.name,
value: item.value ?? '',
dataView,
dataView: metrics.dataView,
negate: false,
});
if (newFilter) {

View file

@ -5,10 +5,10 @@
* 2.0.
*/
import React, { useMemo } from 'react';
import type { DataView } from '@kbn/data-views-plugin/public';
import { TimeRange } from '@kbn/es-query';
import { ChartModel } from '@kbn/lens-embeddable-utils';
import type { LensConfig, LensDataviewDataset } from '@kbn/lens-embeddable-utils/config_builder';
import { useDataView } from '../../../../../hooks/use_data_view';
import { METRICS_TOOLTIP } from '../../../../../common/visualizations';
import { LensChart, TooltipContent } from '../../../../lens';
import { buildCombinedHostsFilter } from '../../../../../utils/filters/build';
@ -19,15 +19,17 @@ export const Kpi = ({
height,
assetName,
dateRange,
dataView,
...chartProps
}: ChartModel & {
}: LensConfig & {
id: string;
height: number;
dataView?: DataView;
assetName: string;
dateRange: TimeRange;
}) => {
const { searchSessionId } = useLoadingStateContext();
const { dataView } = useDataView({ index: (chartProps.dataset as LensDataviewDataset)?.index });
const filters = useMemo(() => {
return [
buildCombinedHostsFilter({
@ -50,7 +52,6 @@ export const Kpi = ({
<LensChart
{...chartProps}
id={`infraAssetDetailsKPI${id}`}
dataView={dataView}
dateRange={dateRange}
height={height}
filters={filters}

View file

@ -31,9 +31,9 @@ export const KPIGrid = ({ assetName, dataView, dateRange }: Props) => {
const charts = useMemo(
() =>
dashboards?.kpi.get({
metricsDataView: dataView,
metricsDataViewId: dataView?.id,
options: {
backgroundColor: euiTheme.colors.lightestShade,
seriesColor: euiTheme.colors.lightestShade,
},
}).charts ?? [],
[dataView, euiTheme.colors.lightestShade, dashboards?.kpi]

View file

@ -5,8 +5,10 @@
* 2.0.
*/
import React, { useCallback, useMemo } from 'react';
import type { ChartModel } from '@kbn/lens-embeddable-utils';
import type { LensConfig, LensDataviewDataset } from '@kbn/lens-embeddable-utils/config_builder';
import type { TimeRange } from '@kbn/es-query';
import { useDataView } from '../../../../../hooks/use_data_view';
import { METRIC_CHART_HEIGHT } from '../../../../../common/visualizations/constants';
import { buildCombinedHostsFilter } from '../../../../../utils/filters/build';
import { type BrushEndArgs, LensChart, type OnFilterEvent, LensChartProps } from '../../../../lens';
@ -14,28 +16,27 @@ import { useDatePickerContext } from '../../../hooks/use_date_picker';
import { extractRangeFromChartFilterEvent } from './chart_utils';
import { useLoadingStateContext } from '../../../hooks/use_loading_state';
export type ChartProps = ChartModel &
export type ChartProps = LensConfig &
Pick<LensChartProps, 'overrides'> & {
id: string;
filterFieldName: string;
dateRange: TimeRange;
assetName: string;
dataViewOrigin?: 'metrics' | 'logs';
['data-test-subj']: string;
};
export const Chart = ({
id,
filterFieldName,
dataViewOrigin,
overrides,
dateRange,
assetName,
dataView,
...props
}: ChartProps) => {
const { setDateRange } = useDatePickerContext();
const { searchSessionId } = useLoadingStateContext();
const { ['data-test-subj']: dataTestSubj, ...chartProps } = { ...props };
const { dataView } = useDataView({ index: (chartProps.dataset as LensDataviewDataset)?.index });
const filters = useMemo(() => {
return [
@ -78,7 +79,6 @@ export const Chart = ({
{...chartProps}
id={`${dataTestSubj}${id}`}
borderRadius="m"
dataView={dataView}
dateRange={dateRange}
height={METRIC_CHART_HEIGHT}
searchSessionId={searchSessionId}

View file

@ -7,14 +7,14 @@
import React from 'react';
import { EuiFlexItem, EuiFlexGrid } from '@elastic/eui';
import type { TimeRange } from '@kbn/es-query';
import type { ChartModel } from '@kbn/lens-embeddable-utils';
import type { LensConfig } from '@kbn/lens-embeddable-utils/config_builder';
import { Chart } from './chart';
interface Props {
assetName: string;
dateRange: TimeRange;
filterFieldName: string;
charts: ChartModel[];
charts: Array<LensConfig & { id: string }>;
['data-test-subj']: string;
}

View file

@ -36,15 +36,15 @@ export const MetricsSection = ({ assetName, metricsDataView, logsDataView, dateR
const dashboards = useMemo(
() => ({
hosts: value?.assetDetails.get({
metricsDataView,
logsDataView,
metricsDataViewId: metricsDataView?.id,
logsDataViewId: logsDataView?.id,
}),
kubernetes: value?.assetDetailsKubernetesNode.get({
metricsDataView,
metricsDataViewId: metricsDataView?.id,
}),
}),
[logsDataView, metricsDataView, value?.assetDetails, value?.assetDetailsKubernetesNode]
[logsDataView?.id, metricsDataView?.id, value?.assetDetails, value?.assetDetailsKubernetesNode]
);
return (
@ -85,10 +85,10 @@ export const MetricsSectionCompact = ({
const charts = useMemo(
() =>
value?.assetDetailsFlyout.get({
metricsDataView,
logsDataView,
metricsDataViewId: metricsDataView?.id,
logsDataViewId: logsDataView?.id,
}).charts ?? [],
[metricsDataView, logsDataView, value?.assetDetailsFlyout]
[logsDataView?.id, metricsDataView?.id, value?.assetDetailsFlyout]
);
return (

View file

@ -16,7 +16,7 @@ import { KPIGrid } from './kpis/kpi_grid';
import { MetricsSection, MetricsSectionCompact } from './metrics/metrics_section';
import { useAssetDetailsRenderPropsContext } from '../../hooks/use_asset_details_render_props';
import { useMetadataStateContext } from '../../hooks/use_metadata_state';
import { useDataViewsProviderContext } from '../../hooks/use_data_views';
import { useDataViewsContext } from '../../hooks/use_data_views';
import { useDatePickerContext } from '../../hooks/use_date_picker';
import { SectionSeparator } from './section_separator';
import { MetadataErrorCallout } from '../../components/metadata_error_callout';
@ -33,7 +33,7 @@ export const Overview = () => {
error: fetchMetadataError,
} = useMetadataStateContext();
const { logs, metrics } = useDataViewsProviderContext();
const { logs, metrics } = useDataViewsContext();
const isFullPageView = renderMode.mode !== 'flyout';

View file

@ -7,10 +7,9 @@
import React from 'react';
import { EuiFlexGroup, EuiFlexItem, EuiIcon, EuiText } from '@elastic/eui';
import { FormattedMessage } from '@kbn/i18n-react';
import { css } from '@emotion/react';
export const ChartLoadError = () => {
export const ChartLoadError = ({ error }: { error: Error }) => {
return (
<EuiFlexGroup
css={css`
@ -27,10 +26,7 @@ export const ChartLoadError = () => {
</EuiFlexItem>
<EuiFlexItem grow={false}>
<EuiText size="s" textAlign="center">
<FormattedMessage
id="xpack.infra.errorOnLoadingLensDependencies"
defaultMessage="There was an error trying to load Lens Plugin."
/>
{error.message}
</EuiText>
</EuiFlexItem>
</EuiFlexGroup>

View file

@ -21,6 +21,7 @@ export type LensChartProps = UseLensAttributesParams &
Pick<EuiPanelProps, 'borderRadius'> & {
toolTip?: React.ReactElement<TooltipContentProps>;
searchSessionId?: string;
description?: string;
};
export const LensChart = React.memo(
@ -97,9 +98,12 @@ export const LensChart = React.memo(
css={css`
position: relative;
min-height: ${height}px;
.embPanel-isLoading {
min-height: ${height}px;
}
`}
>
{error ? <ChartLoadError /> : content}
{error ? <ChartLoadError error={error} /> : content}
</EuiPanel>
);
}

View file

@ -5,9 +5,8 @@
* 2.0.
*/
import type { DataView } from '@kbn/data-views-plugin/public';
import type { TimeRange } from '@kbn/es-query';
import type { LensAttributes } from '@kbn/lens-embeddable-utils';
import type { LensAttributes } from '@kbn/lens-embeddable-utils/config_builder';
import type { LensEmbeddableInput, TypedLensByValueInput } from '@kbn/lens-plugin/public';
import type { Action } from '@kbn/ui-actions-plugin/public';
@ -39,6 +38,5 @@ export type BaseChartProps = Pick<
| 'query'
| 'title'
> & {
dataView?: DataView;
height?: number;
};

View file

@ -10,7 +10,7 @@ import { renderHook } from '@testing-library/react-hooks';
import { type KibanaReactContextValue, useKibana } from '@kbn/kibana-react-plugin/public';
import { coreMock } from '@kbn/core/public/mocks';
import type { DataView, DataViewsServicePublic } from '@kbn/data-views-plugin/public';
import type { InfraClientStartDeps } from '../../../../types';
import type { InfraClientStartDeps } from '../types';
import { CoreStart } from '@kbn/core/public';
jest.mock('@kbn/kibana-react-plugin/public');
@ -40,13 +40,14 @@ describe('useDataView hook', () => {
beforeEach(() => {
dataViewMock = {
create: jest.fn().mockImplementation(() => Promise.resolve(mockDataView)),
get: jest.fn().mockImplementation(() => Promise.reject(new Error('Data view not found'))),
} as Partial<DataViewsServicePublic> as jest.Mocked<DataViewsServicePublic>;
mockUseKibana();
});
it('should create a new ad-hoc data view', async () => {
const { result, waitForNextUpdate } = renderHook(() => useDataView({ metricAlias: 'test' }));
const { result, waitForNextUpdate } = renderHook(() => useDataView({ index: 'test' }));
await waitForNextUpdate();
expect(result.current.loading).toEqual(false);
@ -55,7 +56,7 @@ describe('useDataView hook', () => {
});
it('should create a dataview with unique id for metricAlias metrics', async () => {
const { waitForNextUpdate } = renderHook(() => useDataView({ metricAlias: 'metrics' }));
const { waitForNextUpdate } = renderHook(() => useDataView({ index: 'metrics' }));
await waitForNextUpdate();
expect(dataViewMock.create).toHaveBeenCalledWith({
@ -66,7 +67,7 @@ describe('useDataView hook', () => {
});
it('should create a dataview with unique id for metricAlias remote-metrics', async () => {
const { waitForNextUpdate } = renderHook(() => useDataView({ metricAlias: 'remote-metrics' }));
const { waitForNextUpdate } = renderHook(() => useDataView({ index: 'remote-metrics' }));
await waitForNextUpdate();
expect(dataViewMock.create).toHaveBeenCalledWith({

View file

@ -12,31 +12,38 @@ import { useKibanaContextForPlugin } from './use_kibana';
export const TIMESTAMP_FIELD = '@timestamp';
export const DATA_VIEW_PREFIX = 'infra_metrics';
export const generateDataViewId = (indexPattern: string) => {
export const generateDataViewId = (index: string) => {
// generates a unique but the same uuid as long as the index pattern doesn't change
return `${DATA_VIEW_PREFIX}_${uuidv5(indexPattern, uuidv5.DNS)}`;
return `${DATA_VIEW_PREFIX}_${uuidv5(index, uuidv5.DNS)}`;
};
export const useDataMetricsAdHocDataView = ({ metricAlias }: { metricAlias: string }) => {
export const useDataView = ({ index }: { index?: string }) => {
const {
services: { dataViews },
} = useKibanaContextForPlugin();
const state = useAsyncRetry(() => {
return dataViews.create({
id: generateDataViewId(metricAlias),
title: metricAlias,
timeFieldName: TIMESTAMP_FIELD,
});
}, [metricAlias]);
const state = useAsyncRetry(async () => {
if (!index) {
return Promise.resolve(undefined);
}
return dataViews.get(index, false).catch(() =>
// if data view doesn't exist, create an ad-hoc one
dataViews.create({
id: generateDataViewId(index),
title: index,
timeFieldName: TIMESTAMP_FIELD,
})
);
}, [index]);
const { value: dataView, loading, error, retry } = state;
return {
metricAlias,
index,
dataView,
loading,
loadDataView: retry,
retry,
error,
};
};

View file

@ -8,37 +8,28 @@
import 'jest-canvas-mock';
import { renderHook } from '@testing-library/react-hooks';
import { useLensAttributes } from './use_lens_attributes';
import type { DataView } from '@kbn/data-views-plugin/public';
import { coreMock } from '@kbn/core/public/mocks';
import { type KibanaReactContextValue, useKibana } from '@kbn/kibana-react-plugin/public';
import { CoreStart } from '@kbn/core/public';
import type { InfraClientStartDeps } from '../types';
import { dataViewPluginMocks } from '@kbn/data-views-plugin/public/mocks';
import { lensPluginMock } from '@kbn/lens-plugin/public/mocks';
import { FilterStateStore } from '@kbn/es-query';
import type { LensBaseLayer, LensConfig } from '@kbn/lens-embeddable-utils/config_builder';
import { LensConfigBuilder } from '@kbn/lens-embeddable-utils/config_builder';
jest.mock('@kbn/kibana-react-plugin/public');
const useKibanaMock = useKibana as jest.MockedFunction<typeof useKibana>;
jest.mock('@kbn/lens-embeddable-utils/config_builder');
const LensConfigBuilderMock = LensConfigBuilder as jest.MockedClass<typeof LensConfigBuilder>;
const mockDataView = {
id: 'mock-id',
title: 'mock-title',
timeFieldName: '@timestamp',
isPersisted: () => false,
getName: () => 'mock-data-view',
toSpec: () => ({}),
fields: [],
metaFields: [],
} as unknown as jest.Mocked<DataView>;
const normalizedLoad1m = {
const normalizedLoad1m: LensBaseLayer = {
label: 'Normalized Load',
value: 'average(system.load.1) / max(system.load.cores)',
format: {
id: 'percent',
params: {
decimals: 0,
},
},
format: 'percent',
decimals: 0,
};
const lensPluginMockStart = lensPluginMock.createStartContract();
@ -46,174 +37,49 @@ const mockUseKibana = () => {
useKibanaMock.mockReturnValue({
services: {
...coreMock.createStart(),
dataViews: { ...dataViewPluginMocks.createStartContract() },
lens: { ...lensPluginMockStart },
} as Partial<CoreStart> & Partial<InfraClientStartDeps>,
} as unknown as KibanaReactContextValue<Partial<CoreStart> & Partial<InfraClientStartDeps>>);
};
describe('useHostTable hook', () => {
describe('useLensAttributes hook', () => {
const params: LensConfig = {
chartType: 'xy',
layers: [
{
type: 'series',
yAxis: [normalizedLoad1m],
xAxis: '@timestamp',
seriesType: 'line',
},
{
type: 'reference',
yAxis: [
{
value: '1',
},
],
},
],
title: 'Injected Normalized Load',
dataset: {
index: 'mock-id',
},
};
beforeEach(() => {
mockUseKibana();
});
it('should return the basic lens attributes', async () => {
const { result, waitForNextUpdate } = renderHook(() =>
useLensAttributes({
visualizationType: 'lnsXY',
layers: [
{
data: [normalizedLoad1m],
options: {
buckets: {
type: 'date_histogram',
},
breakdown: {
field: 'host.name',
type: 'top_values',
params: {
size: 10,
},
},
},
layerType: 'data',
},
{
data: [
{
value: '1',
format: {
id: 'percent',
params: {
decimals: 0,
},
},
},
],
layerType: 'referenceLine',
},
],
title: 'Injected Normalized Load',
dataView: mockDataView,
})
);
const { waitForNextUpdate } = renderHook(() => useLensAttributes(params));
await waitForNextUpdate();
const { state, title } = result.current.attributes ?? {};
const { datasourceStates } = state ?? {};
expect(title).toBe('Injected Normalized Load');
expect(datasourceStates).toEqual({
formBased: {
layers: {
layer_0: {
columnOrder: ['aggs_breakdown', 'x_date_histogram', 'formula_accessor_0_0'],
columns: {
aggs_breakdown: {
dataType: 'string',
isBucketed: true,
label: 'Top 10 values of host.name',
operationType: 'terms',
params: {
exclude: [],
excludeIsRegex: false,
include: [],
includeIsRegex: false,
missingBucket: false,
orderBy: {
fallback: false,
type: 'alphabetical',
},
orderDirection: 'asc',
otherBucket: false,
parentFormat: {
id: 'terms',
},
size: 10,
},
scale: 'ordinal',
sourceField: 'host.name',
},
x_date_histogram: {
dataType: 'date',
isBucketed: true,
label: '@timestamp',
operationType: 'date_histogram',
params: {
interval: 'auto',
},
scale: 'interval',
sourceField: '@timestamp',
},
formula_accessor_0_0: {
customLabel: true,
dataType: 'number',
filter: undefined,
isBucketed: false,
label: 'Normalized Load',
operationType: 'formula',
params: {
format: {
id: 'percent',
params: {
decimals: 0,
},
},
formula: 'average(system.load.1) / max(system.load.cores)',
isFormulaBroken: true,
},
reducedTimeRange: undefined,
references: [],
timeScale: undefined,
},
},
indexPatternId: 'mock-id',
},
layer_1_reference: {
columnOrder: ['formula_accessor_1_0_reference_column'],
columns: {
formula_accessor_1_0_reference_column: {
customLabel: true,
dataType: 'number',
isBucketed: false,
isStaticValue: true,
label: 'Reference',
operationType: 'static_value',
params: {
format: {
id: 'percent',
params: {
decimals: 0,
},
},
value: '1',
},
references: [],
scale: 'ratio',
},
},
incompleteColumns: {},
linkToLayers: [],
sampling: 1,
},
},
},
});
expect(LensConfigBuilderMock.mock.instances[0].build).toHaveBeenCalledWith(params);
});
it('should return extra actions', async () => {
const { result, waitForNextUpdate } = renderHook(() =>
useLensAttributes({
title: 'Chart',
visualizationType: 'lnsXY',
layers: [
{
data: [normalizedLoad1m],
layerType: 'data',
},
],
dataView: mockDataView,
})
);
const { result, waitForNextUpdate } = renderHook(() => useLensAttributes(params));
await waitForNextUpdate();
const extraActions = result.current.getExtraActions({

View file

@ -5,62 +5,43 @@
* 2.0.
*/
import { useCallback, useMemo } from 'react';
import type { DataView } from '@kbn/data-views-plugin/public';
import { useCallback } from 'react';
import { Filter, Query, TimeRange } from '@kbn/es-query';
import { useKibana } from '@kbn/kibana-react-plugin/public';
import type { Action, ActionExecutionContext } from '@kbn/ui-actions-plugin/public';
import { i18n } from '@kbn/i18n';
import useAsync from 'react-use/lib/useAsync';
import { FormulaPublicApi } from '@kbn/lens-plugin/public';
import {
type LensVisualizationState,
type Chart,
type LensAttributes,
type ChartModel,
type XYLayerConfig,
LensAttributesBuilder,
XYChart,
MetricChart,
MetricLayer,
XYDataLayer,
XYReferenceLinesLayer,
} from '@kbn/lens-embeddable-utils';
import { InfraClientSetupDeps } from '../types';
type LensConfig,
LensConfigBuilder,
} from '@kbn/lens-embeddable-utils/config_builder';
import { useKibanaContextForPlugin } from './use_kibana';
export type UseLensAttributesParams = Omit<ChartModel, 'id'>;
export type UseLensAttributesParams = LensConfig;
export const useLensAttributes = ({ dataView, ...params }: UseLensAttributesParams) => {
export const useLensAttributes = (params: UseLensAttributesParams) => {
const {
services: { lens },
} = useKibana<InfraClientSetupDeps>();
services: { lens, dataViews },
} = useKibanaContextForPlugin();
const { navigateToPrefilledEditor } = lens;
const { value, error } = useAsync(() => {
return lens.stateHelperApi();
}, [lens]);
const { formula: formulaAPI } = value ?? {};
const attributes = useMemo(() => {
if (!dataView || !formulaAPI) {
return null;
const { value: attributes, error } = useAsync(async () => {
const { formula: formulaAPI } = await lens.stateHelperApi();
if (!dataViews || !formulaAPI || !params.dataset) {
return undefined;
}
const builder = new LensAttributesBuilder({
visualization: chartFactory({
dataView,
formulaAPI,
...params,
}),
});
const builder = new LensConfigBuilder(formulaAPI, dataViews);
return builder.build();
}, [dataView, formulaAPI, params]);
return builder.build(params) as Promise<LensAttributes>;
}, [params.chartType, params.dataset, dataViews]);
const injectFilters = useCallback(
({ filters, query }: { filters: Filter[]; query: Query }): LensAttributes | null => {
if (!attributes) {
return null;
}
return {
...attributes,
state: {
@ -125,79 +106,19 @@ export const useLensAttributes = ({ dataView, ...params }: UseLensAttributesPara
);
const getFormula = () => {
const firstDataLayer = [
...(Array.isArray(params.layers) ? params.layers : [params.layers]),
].find((p) => p.layerType === 'data');
if (!firstDataLayer) {
return '';
if (params.chartType === 'xy') {
return params.layers[0].yAxis[0].value;
}
const mainFormulaConfig = Array.isArray(firstDataLayer.data)
? firstDataLayer.data[0]
: firstDataLayer.data;
return mainFormulaConfig.value;
return params.value;
};
return { formula: getFormula(), attributes, getExtraActions, error };
};
const chartFactory = ({
dataView,
formulaAPI,
...params
}: {
dataView: DataView;
formulaAPI: FormulaPublicApi;
} & UseLensAttributesParams): Chart<LensVisualizationState> => {
switch (params.visualizationType) {
case 'lnsXY':
if (!Array.isArray(params.layers)) {
throw new Error(`Invalid layers type. Expected an array of layers.`);
}
const xyLayerFactory = (layer: XYLayerConfig) => {
switch (layer.layerType) {
case 'data': {
return new XYDataLayer(layer);
}
case 'referenceLine': {
return new XYReferenceLinesLayer(layer);
}
default:
throw new Error(`Invalid layer type`);
}
};
const { layers, ...rest } = params;
return new XYChart({
dataView,
formulaAPI,
layers: layers.map((layerItem) => {
return xyLayerFactory(layerItem);
}),
...rest,
});
case 'lnsMetric':
if (Array.isArray(params.layers)) {
throw new Error(`Invalid layer type. Expected a single layer object.`);
}
return new MetricChart({
dataView,
formulaAPI,
layers: new MetricLayer({
data: params.layers.data,
options: { ...params.layers.options },
layerType: params.layers.layerType,
}),
title: params.title,
});
default:
throw new Error(`Unsupported chart type`);
}
return {
formula: getFormula(),
attributes: attributes as LensAttributes | null,
getExtraActions,
error,
};
};
const getOpenInLensAction = (onExecute: () => void): Action => {

View file

@ -9,14 +9,14 @@ import { EuiSpacer } from '@elastic/eui';
import { i18n } from '@kbn/i18n';
import { InfraLoadingPanel } from '../../../../components/loading';
import { useMetricsDataViewContext } from '../hooks/use_data_view';
import { useMetricsDataViewContext } from '../hooks/use_metrics_data_view';
import { UnifiedSearchBar } from './search_bar/unified_search_bar';
import { HostsContent } from './hosts_content';
import { ErrorCallout } from './error_callout';
import { UnifiedSearchProvider } from '../hooks/use_unified_search';
export const HostContainer = () => {
const { dataView, loading, error, metricAlias, loadDataView } = useMetricsDataViewContext();
const { dataView, loading, error, metricAlias, retry } = useMetricsDataViewContext();
const isLoading = loading || !dataView;
if (isLoading && !error) {
@ -42,7 +42,7 @@ export const HostContainer = () => {
'There was an error trying to create a Data View: {metricAlias}. Try reloading the page.',
values: { metricAlias },
})}
onTryAgainClick={loadDataView}
onTryAgainClick={retry}
hasTryAgainButton
/>
) : (

View file

@ -5,7 +5,8 @@
* 2.0.
*/
import React, { useMemo } from 'react';
import { ChartModel } from '@kbn/lens-embeddable-utils';
import type { LensConfig, LensDataviewDataset } from '@kbn/lens-embeddable-utils/config_builder';
import { useDataView } from '../../../../../hooks/use_data_view';
import { METRICS_TOOLTIP } from '../../../../../common/visualizations';
import { LensChart, TooltipContent } from '../../../../../components/lens';
import { buildCombinedHostsFilter } from '../../../../../utils/filters/build';
@ -14,16 +15,11 @@ import { useHostsViewContext } from '../../hooks/use_hosts_view';
import { useHostCountContext } from '../../hooks/use_host_count';
import { useAfterLoadedState } from '../../hooks/use_after_loaded_state';
export const Kpi = ({
id,
height,
visualizationType = 'lnsMetric',
dataView,
...chartProps
}: ChartModel & { height: number }) => {
export const Kpi = ({ id, height, ...chartProps }: LensConfig & { height: number; id: string }) => {
const { searchCriteria } = useUnifiedSearchContext();
const { hostNodes, loading: hostsLoading, searchSessionId } = useHostsViewContext();
const { isRequestRunning: hostCountLoading } = useHostCountContext();
const { dataView } = useDataView({ index: (chartProps.dataset as LensDataviewDataset)?.index });
const shouldUseSearchCriteria = hostNodes.length === 0;
const loading = hostsLoading || hostCountLoading;
@ -60,12 +56,10 @@ export const Kpi = ({
<LensChart
{...chartProps}
id={`hostsViewKPI-${id}`}
dataView={dataView}
dateRange={afterLoadedState.dateRange}
filters={afterLoadedState.filters}
loading={loading}
height={height}
visualizationType={visualizationType}
query={afterLoadedState.query}
searchSessionId={afterLoadedState.searchSessionId}
toolTip={tooltipContent}

View file

@ -16,7 +16,7 @@ import { HostMetricsDocsLink } from '../../../../../components/lens';
import { Kpi } from './kpi';
import { useHostCountContext } from '../../hooks/use_host_count';
import { HostCountKpi } from './host_count_kpi';
import { useMetricsDataViewContext } from '../../hooks/use_data_view';
import { useMetricsDataViewContext } from '../../hooks/use_metrics_data_view';
import { useUnifiedSearchContext } from '../../hooks/use_unified_search';
export const KPIGrid = () => {
@ -43,9 +43,9 @@ export const KPIGrid = () => {
const charts = useMemo(
() =>
dashboards?.kpi.get({
metricsDataView: dataView,
metricsDataViewId: dataView?.id,
options: {
backgroundColor: euiTheme.colors.lightestShade,
seriesColor: euiTheme.colors.lightestShade,
...(subtitle ? { subtitle } : {}),
},
}).charts ?? [],

View file

@ -14,7 +14,7 @@ import { useKibanaHeader } from '../../../../../hooks/use_kibana_header';
import { useKibanaContextForPlugin } from '../../../../../hooks/use_kibana';
import { useUnifiedSearchContext } from '../../hooks/use_unified_search';
import { ControlsContent } from './controls_content';
import { useMetricsDataViewContext } from '../../hooks/use_data_view';
import { useMetricsDataViewContext } from '../../hooks/use_metrics_data_view';
import { LimitOptions } from './limit_options';
import { HostLimitOptions } from '../../types';

View file

@ -5,7 +5,8 @@
* 2.0.
*/
import React, { useMemo } from 'react';
import type { ChartModel, XYVisualOptions } from '@kbn/lens-embeddable-utils';
import type { LensConfig, LensDataviewDataset } from '@kbn/lens-embeddable-utils/config_builder';
import { useDataView } from '../../../../../../hooks/use_data_view';
import { METRIC_CHART_HEIGHT } from '../../../../../../common/visualizations/constants';
import { LensChart } from '../../../../../../components/lens';
import { useUnifiedSearchContext } from '../../../hooks/use_unified_search';
@ -14,14 +15,15 @@ import { buildCombinedHostsFilter } from '../../../../../../utils/filters/build'
import { useHostsTableContext } from '../../../hooks/use_hosts_table';
import { useAfterLoadedState } from '../../../hooks/use_after_loaded_state';
export interface ChartProps extends Omit<ChartModel, 'visualOptions'> {
visualOptions?: XYVisualOptions;
}
export type ChartProps = LensConfig & {
id: string;
};
export const Chart = ({ dataView, ...chartProps }: ChartProps) => {
export const Chart = ({ id, ...chartProps }: ChartProps) => {
const { searchCriteria } = useUnifiedSearchContext();
const { loading, searchSessionId } = useHostsViewContext();
const { currentPage } = useHostsTableContext();
const { dataView } = useDataView({ index: (chartProps.dataset as LensDataviewDataset)?.index });
const shouldUseSearchCriteria = currentPage.length === 0;
@ -44,14 +46,13 @@ export const Chart = ({ dataView, ...chartProps }: ChartProps) => {
dataView,
}),
];
}, [searchCriteria.filters, currentPage, dataView, shouldUseSearchCriteria]);
}, [shouldUseSearchCriteria, searchCriteria.filters, currentPage, dataView]);
return (
<LensChart
{...chartProps}
id={`hostsView-metricChart-${chartProps.id}`}
id={`hostsView-metricChart-${id}`}
borderRadius="m"
dataView={dataView}
dateRange={afterLoadedState.dateRange}
height={METRIC_CHART_HEIGHT}
loading={loading}

View file

@ -12,7 +12,7 @@ import useAsync from 'react-use/lib/useAsync';
import { HostMetricsExplanationContent } from '../../../../../../components/lens';
import { Chart } from './chart';
import { Popover } from '../../common/popover';
import { useMetricsDataViewContext } from '../../../hooks/use_data_view';
import { useMetricsDataViewContext } from '../../../hooks/use_metrics_data_view';
export const MetricsGrid = () => {
const model = findInventoryModel('host');
@ -23,7 +23,7 @@ export const MetricsGrid = () => {
});
const charts = useMemo(
() => dashboards?.hostsView.get({ metricsDataView: dataView }).charts ?? [],
() => dashboards?.hostsView.get({ metricsDataViewId: dataView?.id }).charts ?? [],
[dataView, dashboards]
);

View file

@ -15,7 +15,7 @@ import type { ITelemetryClient } from '../../../../services/telemetry';
import { useKibanaContextForPlugin } from '../../../../hooks/use_kibana';
import { decodeOrThrow } from '../../../../../common/runtime_types';
import { useDataSearch, useLatestPartialDataSearchResponse } from '../../../../utils/data_search';
import { useMetricsDataViewContext } from './use_data_view';
import { useMetricsDataViewContext } from './use_metrics_data_view';
import { useUnifiedSearchContext } from './use_unified_search';
export const useHostCount = () => {

View file

@ -11,11 +11,11 @@ import { InfraAssetMetricsItem } from '../../../../../common/http_api';
import * as useUnifiedSearchHooks from './use_unified_search';
import * as useHostsViewHooks from './use_hosts_view';
import * as useKibanaContextForPluginHook from '../../../../hooks/use_kibana';
import * as useMetricsDataViewHooks from './use_data_view';
import * as useMetricsDataViewHooks from './use_metrics_data_view';
jest.mock('./use_unified_search');
jest.mock('./use_hosts_view');
jest.mock('./use_data_view');
jest.mock('./use_metrics_data_view');
jest.mock('../../../../hooks/use_kibana');
const mockUseUnifiedSearchContext =

View file

@ -28,7 +28,7 @@ import type {
} from '../../../../../common/http_api';
import { Sorting, useHostsTableUrlState } from './use_hosts_table_url_state';
import { useHostsViewContext } from './use_hosts_view';
import { useMetricsDataViewContext } from './use_data_view';
import { useMetricsDataViewContext } from './use_metrics_data_view';
import { ColumnHeader } from '../components/table/column_header';
import { TABLE_COLUMN_LABEL } from '../translations';
import { METRICS_TOOLTIP } from '../../../../common/visualizations';

View file

@ -6,24 +6,21 @@
*/
import createContainer from 'constate';
import { useDataMetricsAdHocDataView } from '../../../../hooks/use_metrics_adhoc_data_view';
import { useDataView } from '../../../../hooks/use_data_view';
export const useDataView = ({ metricAlias }: { metricAlias: string }) => {
const {
dataView,
loading,
loadDataView: retry,
error,
} = useDataMetricsAdHocDataView({ metricAlias });
export const useMetricsDataView = ({ metricAlias }: { metricAlias: string }) => {
const { dataView, loading, retry, error } = useDataView({
index: metricAlias,
});
return {
metricAlias,
dataView,
loading,
loadDataView: retry,
retry,
error,
};
};
export const MetricsDataView = createContainer(useDataView);
export const MetricsDataView = createContainer(useMetricsDataView);
export const [MetricsDataViewProvider, useMetricsDataViewContext] = MetricsDataView;

View file

@ -15,7 +15,7 @@ import { parseDateRange } from '../../../../utils/datemath';
import { useKibanaQuerySettings } from '../../../../utils/use_kibana_query_settings';
import { useKibanaContextForPlugin } from '../../../../hooks/use_kibana';
import { telemetryTimeRangeFormatter } from '../../../../../common/formatters/telemetry_time_range';
import { useMetricsDataViewContext } from './use_data_view';
import { useMetricsDataViewContext } from './use_metrics_data_view';
import {
HostsSearchPayload,
useHostsUrlState,

View file

@ -18,7 +18,7 @@ import { useSourceContext } from '../../../containers/metrics_source';
import { useMetricsBreadcrumbs } from '../../../hooks/use_metrics_breadcrumbs';
import { MetricsPageTemplate } from '../page_template';
import { hostsTitle } from '../../../translations';
import { MetricsDataViewProvider } from './hooks/use_data_view';
import { MetricsDataViewProvider } from './hooks/use_metrics_data_view';
import { fullHeightContentStyles } from '../../../page_template.styles';
import { HostContainer } from './components/hosts_container';
import { BetaBadge } from '../../../components/beta_badge';

View file

@ -6,30 +6,23 @@
*/
import { i18n } from '@kbn/i18n';
import type { StaticValueConfig, XYChartModel } from '@kbn/lens-embeddable-utils';
import type { LensConfigWithId } from '../../../types';
import { formulas } from '../formulas';
import type { ChartArgs } from './types';
export const REFERENCE_LINE: StaticValueConfig = {
value: '1',
format: {
id: 'percent',
params: {
decimals: 0,
},
},
color: '#6092c0',
};
export const cpuUsageBreakdown = {
get: ({ dataView }: ChartArgs): XYChartModel => ({
get: ({ dataViewId }: ChartArgs): LensConfigWithId => ({
id: 'cpuUsageBreakdown',
chartType: 'xy',
title: i18n.translate('xpack.metricsData.assetDetails.metricsCharts.cpuUsage', {
defaultMessage: 'CPU Usage',
}),
layers: [
{
data: [
seriesType: 'area',
type: 'series',
xAxis: '@timestamp',
yAxis: [
formulas.cpuUsageIowait,
formulas.cpuUsageIrq,
formulas.cpuUsageNice,
@ -38,48 +31,28 @@ export const cpuUsageBreakdown = {
formulas.cpuUsageUser,
formulas.cpuUsageSystem,
],
options: {
seriesType: 'area_stacked',
},
layerType: 'data',
},
],
visualizationType: 'lnsXY',
dataView,
}),
};
export const normalizedLoad1m = {
get: ({ dataView }: ChartArgs): XYChartModel => ({
id: 'normalizedLoad1m',
title: i18n.translate('xpack.metricsData.assetDetails.metricsCharts.normalizedLoad1m', {
defaultMessage: 'Normalized Load',
}),
layers: [
{ data: [formulas.normalizedLoad1m], layerType: 'data' },
{ data: [REFERENCE_LINE], layerType: 'referenceLine' },
],
visualizationType: 'lnsXY',
dataView,
}),
};
export const loadBreakdown = {
get: ({ dataView }: ChartArgs): XYChartModel => ({
id: 'loadBreakdown',
title: i18n.translate('xpack.metricsData.assetDetails.metricsCharts.load', {
defaultMessage: 'Load',
}),
layers: [
{
data: [formulas.load1m, formulas.load5m, formulas.load15m],
options: {
seriesType: 'area',
},
layerType: 'data',
},
],
visualizationType: 'lnsXY',
dataView,
fittingFunction: 'Linear',
legend: {
position: 'bottom',
show: true,
},
yBounds: {
mode: 'custom',
lowerBound: 0,
upperBound: 1,
},
axisTitleVisibility: {
showXAxisTitle: false,
showYAxisTitle: false,
},
...(dataViewId
? {
dataset: {
index: dataViewId,
},
}
: {}),
}),
};

View file

@ -6,21 +6,23 @@
*/
import { i18n } from '@kbn/i18n';
import type { XYChartModel } from '@kbn/lens-embeddable-utils';
import type { LensConfigWithId } from '../../../types';
import { formulas } from '../formulas';
import type { ChartArgs } from './types';
const TOP_VALUES_SIZE = 5;
export const diskSpaceUsageAvailable = {
get: ({ dataView }: ChartArgs): XYChartModel => ({
get: ({ dataViewId }: ChartArgs): LensConfigWithId => ({
id: 'diskSpaceUsageAvailable',
chartType: 'xy',
title: i18n.translate('xpack.metricsData.assetDetails.metricsCharts.diskUsage', {
defaultMessage: 'Disk Usage',
}),
layers: [
{
data: [
seriesType: 'area',
type: 'series',
xAxis: '@timestamp',
yAxis: [
{
...formulas.diskUsage,
label: i18n.translate(
@ -40,26 +42,50 @@ export const diskSpaceUsageAvailable = {
),
},
],
options: {
seriesType: 'area',
},
layerType: 'data',
},
],
visualizationType: 'lnsXY',
dataView,
fittingFunction: 'Linear',
legend: {
show: true,
position: 'bottom',
},
yBounds: {
mode: 'custom',
lowerBound: 0,
upperBound: 1,
},
axisTitleVisibility: {
showXAxisTitle: false,
showYAxisTitle: false,
},
...(dataViewId
? {
dataset: {
index: dataViewId,
},
}
: {}),
}),
};
export const diskUsageByMountPoint = {
get: ({ dataView }: ChartArgs): XYChartModel => ({
get: ({ dataViewId }: ChartArgs): LensConfigWithId => ({
id: 'DiskUsageByMountPoint',
chartType: 'xy',
title: i18n.translate('xpack.metricsData.assetDetails.metricsCharts.diskUsageByMountingPoint', {
defaultMessage: 'Disk Usage by Mount Point',
}),
layers: [
{
data: [
seriesType: 'area',
type: 'series',
xAxis: '@timestamp',
breakdown: {
type: 'topValues',
field: 'system.filesystem.mount_point',
size: 5,
},
yAxis: [
{
...formulas.diskUsage,
label: i18n.translate(
@ -70,44 +96,44 @@ export const diskUsageByMountPoint = {
),
},
],
options: {
seriesType: 'area',
breakdown: {
type: 'top_values',
field: 'system.filesystem.mount_point',
params: {
size: TOP_VALUES_SIZE,
},
},
},
layerType: 'data',
},
],
visualOptions: {
legend: {
isVisible: true,
position: 'bottom',
legendSize: 50 as any,
},
yLeftExtent: {
mode: 'dataBounds',
lowerBound: 0,
upperBound: 1,
},
fittingFunction: 'Linear',
legend: {
show: true,
position: 'bottom',
},
visualizationType: 'lnsXY',
dataView,
yBounds: {
mode: 'custom',
lowerBound: 0,
upperBound: 1,
},
axisTitleVisibility: {
showXAxisTitle: false,
showYAxisTitle: false,
},
...(dataViewId
? {
dataset: {
index: dataViewId,
},
}
: {}),
}),
};
export const diskThroughputReadWrite = {
get: ({ dataView }: ChartArgs): XYChartModel => ({
get: ({ dataViewId }: ChartArgs): LensConfigWithId => ({
id: 'diskThroughputReadWrite',
chartType: 'xy',
title: i18n.translate('xpack.metricsData.assetDetails.metricsCharts.diskIOPS', {
defaultMessage: 'Disk IOPS',
}),
layers: [
{
data: [
seriesType: 'area',
type: 'series',
xAxis: '@timestamp',
yAxis: [
{
...formulas.diskIORead,
label: i18n.translate(
@ -127,33 +153,40 @@ export const diskThroughputReadWrite = {
),
},
],
options: {
seriesType: 'area',
},
layerType: 'data',
},
],
visualOptions: {
yLeftExtent: {
mode: 'dataBounds',
lowerBound: 0,
upperBound: 1,
},
fittingFunction: 'Linear',
legend: {
show: true,
position: 'bottom',
},
visualizationType: 'lnsXY',
dataView,
axisTitleVisibility: {
showXAxisTitle: false,
showYAxisTitle: false,
},
...(dataViewId
? {
dataset: {
index: dataViewId,
},
}
: {}),
}),
};
export const diskIOReadWrite = {
get: ({ dataView }: ChartArgs): XYChartModel => ({
get: ({ dataViewId }: ChartArgs): LensConfigWithId => ({
id: 'diskIOReadWrite',
chartType: 'xy',
title: i18n.translate('xpack.metricsData.assetDetails.metricsCharts.diskThroughput', {
defaultMessage: 'Disk Throughput',
}),
layers: [
{
data: [
seriesType: 'area',
type: 'series',
xAxis: '@timestamp',
yAxis: [
{
...formulas.diskReadThroughput,
label: i18n.translate(
@ -173,20 +206,23 @@ export const diskIOReadWrite = {
),
},
],
options: {
seriesType: 'area',
},
layerType: 'data',
},
],
visualOptions: {
yLeftExtent: {
mode: 'dataBounds',
lowerBound: 0,
upperBound: 1,
},
fittingFunction: 'Linear',
legend: {
show: true,
position: 'bottom',
},
visualizationType: 'lnsXY',
dataView,
axisTitleVisibility: {
showXAxisTitle: false,
showYAxisTitle: false,
},
...(dataViewId
? {
dataset: {
index: dataViewId,
},
}
: {}),
}),
};

View file

@ -5,63 +5,93 @@
* 2.0.
*/
import {
type ChartModel,
type XYChartModel,
type MetricChartModel,
type XYLayerOptions,
type MetricLayerOptions,
type ChartTypes,
type XYVisualOptions,
XY_ID,
} from '@kbn/lens-embeddable-utils';
import type { ChartType, ChartTypeLensConfig } from '@kbn/lens-embeddable-utils/config_builder';
import { LensConfigWithId } from '../../../types';
import type { HostFormulaNames } from '../formulas';
import { formulas } from '../formulas';
type ChartByFormula<TType extends ChartTypes> = Record<
HostFormulaNames,
TType extends typeof XY_ID ? XYChartModel : MetricChartModel
>;
type CustomLensConfig<T extends ChartType> = { id: string } & ChartTypeLensConfig<T>;
type BaseArgs<TType extends ChartTypes> = Pick<ChartModel, 'dataView'> & {
formulaIds: HostFormulaNames[];
visualizationType: TType;
layerOptions?: TType extends typeof XY_ID ? XYLayerOptions : MetricLayerOptions;
visualOptions?: TType extends typeof XY_ID ? XYVisualOptions : never;
};
type Args<T extends ChartType> = T extends 'xy'
? Omit<Partial<ChartTypeLensConfig<'xy'>>, 'layers' | 'chartType' | 'dataset'> & {
layerConfig?: Partial<ChartTypeLensConfig<'xy'>['layers'][number]>;
}
: Omit<Partial<ChartTypeLensConfig<T>>, 'value' | 'chartType' | 'dataset'>;
export const createBasicCharts = <TType extends ChartTypes>({
formulaIds,
visualizationType,
dataView,
layerOptions,
...rest
}: BaseArgs<TType>): ChartByFormula<TType> => {
return formulaIds.reduce((acc, curr) => {
const layers = {
data: visualizationType === XY_ID ? [formulas[curr]] : formulas[curr],
layerType: visualizationType === XY_ID ? 'data' : 'metricTrendline',
options: layerOptions,
};
const chartModel = {
export const createBasicCharts = <T extends ChartType>({
chartType,
fromFormulas,
chartConfig,
dataViewId,
}: {
chartType: T;
fromFormulas: HostFormulaNames[];
chartConfig?: Args<T>;
dataViewId?: string;
}): Record<HostFormulaNames, CustomLensConfig<T>> => {
return fromFormulas.reduce((acc, curr) => {
const baseConfig = {
...chartConfig,
id: curr,
title: formulas[curr].label,
dataView,
visualizationType,
layers: visualizationType === XY_ID ? [layers] : layers,
...rest,
} as TType extends typeof XY_ID ? XYChartModel : MetricChartModel;
title: formulas[curr].label ?? chartConfig?.title ?? '',
...(dataViewId
? {
dataset: {
index: dataViewId,
},
}
: {}),
} as LensConfigWithId;
if (chartType === 'xy') {
const {
layerConfig,
legend,
fittingFunction = 'Linear',
...xyConfig
} = baseConfig as Args<'xy'>;
return {
...acc,
[curr]: {
...xyConfig,
chartType,
legend: {
show: false,
position: 'bottom',
...legend,
},
axisTitleVisibility: {
showXAxisTitle: false,
showYAxisTitle: false,
},
fittingFunction,
layers: [
{
seriesType: 'line',
type: 'series',
xAxis: '@timestamp',
yAxis: [formulas[curr]],
...layerConfig,
},
],
} as CustomLensConfig<'xy'>,
};
}
return {
...acc,
[curr]: chartModel,
[curr]: {
...baseConfig,
...formulas[curr],
chartType,
},
};
}, {} as ChartByFormula<TType>);
}, {} as Record<HostFormulaNames, CustomLensConfig<T>>);
};
// custom charts
export { cpuUsageBreakdown, normalizedLoad1m, loadBreakdown } from './cpu_charts';
export { cpuUsageBreakdown } from './cpu_charts';
export { loadBreakdown } from './load_charts';
export {
diskIOReadWrite,
diskSpaceUsageAvailable,

View file

@ -0,0 +1,45 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0; you may not use this file except in compliance with the Elastic License
* 2.0.
*/
import { i18n } from '@kbn/i18n';
import type { LensConfigWithId } from '../../../types';
import { formulas } from '../formulas';
import type { ChartArgs } from './types';
export const loadBreakdown = {
get: ({ dataViewId }: ChartArgs): LensConfigWithId => ({
id: 'loadBreakdown',
chartType: 'xy',
title: i18n.translate('xpack.metricsData.assetDetails.metricsCharts.load', {
defaultMessage: 'Load',
}),
layers: [
{
seriesType: 'area',
type: 'series',
xAxis: '@timestamp',
yAxis: [formulas.load1m, formulas.load5m, formulas.load15m],
},
],
fittingFunction: 'Linear',
legend: {
position: 'bottom',
show: true,
},
axisTitleVisibility: {
showXAxisTitle: false,
showYAxisTitle: false,
},
...(dataViewId
? {
dataset: {
index: dataViewId,
},
}
: {}),
}),
};

View file

@ -6,19 +6,23 @@
*/
import { i18n } from '@kbn/i18n';
import type { XYChartModel } from '@kbn/lens-embeddable-utils';
import type { LensConfigWithId } from '../../../types';
import { formulas } from '../formulas';
import type { ChartArgs } from './types';
export const memoryUsageBreakdown = {
get: ({ dataView }: ChartArgs): XYChartModel => ({
get: ({ dataViewId }: ChartArgs): LensConfigWithId => ({
id: 'memoryUsageBreakdown',
chartType: 'xy',
title: i18n.translate('xpack.metricsData.assetDetails.metricsCharts.memoryUsage', {
defaultMessage: 'Memory Usage',
}),
layers: [
{
data: [
seriesType: 'area',
type: 'series',
xAxis: '@timestamp',
yAxis: [
{
...formulas.memoryCache,
label: i18n.translate(
@ -47,25 +51,23 @@ export const memoryUsageBreakdown = {
),
},
],
options: {
seriesType: 'area_stacked',
},
layerType: 'data',
},
],
visualOptions: {
legend: {
isVisible: true,
position: 'bottom',
legendSize: 50 as any,
},
yLeftExtent: {
mode: 'dataBounds',
lowerBound: 0,
upperBound: 1,
},
fittingFunction: 'Linear',
legend: {
position: 'bottom',
show: true,
},
visualizationType: 'lnsXY',
dataView,
axisTitleVisibility: {
showXAxisTitle: false,
showYAxisTitle: false,
},
...(dataViewId
? {
dataset: {
index: dataViewId,
},
}
: {}),
}),
};

View file

@ -6,19 +6,23 @@
*/
import { i18n } from '@kbn/i18n';
import type { XYChartModel } from '@kbn/lens-embeddable-utils';
import type { LensConfigWithId } from '../../../types';
import { formulas } from '../formulas';
import type { ChartArgs } from './types';
export const rxTx = {
get: ({ dataView }: ChartArgs): XYChartModel => ({
get: ({ dataViewId }: ChartArgs): LensConfigWithId => ({
id: 'rxTx',
chartType: 'xy',
title: i18n.translate('xpack.metricsData.assetDetails.metricsCharts.network', {
defaultMessage: 'Network',
}),
layers: [
{
data: [
seriesType: 'area',
type: 'series',
xAxis: '@timestamp',
yAxis: [
{
...formulas.rx,
label: i18n.translate('xpack.metricsData.assetDetails.metricsCharts.network.label.rx', {
@ -32,21 +36,23 @@ export const rxTx = {
}),
},
],
options: {
seriesType: 'area',
},
layerType: 'data',
},
],
visualOptions: {
yLeftExtent: {
mode: 'dataBounds',
lowerBound: 0,
upperBound: 1,
},
fittingFunction: 'Linear',
legend: {
show: true,
position: 'bottom',
},
visualizationType: 'lnsXY',
dataView,
axisTitleVisibility: {
showXAxisTitle: false,
showYAxisTitle: false,
},
...(dataViewId
? {
dataset: {
index: dataViewId,
},
}
: {}),
}),
};

View file

@ -5,8 +5,6 @@
* 2.0.
*/
import { DataView } from '@kbn/data-views-plugin/common';
export interface ChartArgs {
dataView?: DataView;
dataViewId?: string;
}

View file

@ -4,8 +4,6 @@
* 2.0; you may not use this file except in compliance with the Elastic License
* 2.0.
*/
import { DataView } from '@kbn/data-views-plugin/common';
import type { XYVisualOptions } from '@kbn/lens-embeddable-utils';
import { createDashboardModel } from '../../../create_dashboard_model';
import {
createBasicCharts,
@ -21,76 +19,52 @@ import {
export const assetDetails = {
get: ({
metricsDataView,
logsDataView,
metricsDataViewId,
logsDataViewId,
}: {
metricsDataView?: DataView;
logsDataView?: DataView;
metricsDataViewId?: string;
logsDataViewId?: string;
}) => {
const commonVisualOptions: XYVisualOptions = {
showDottedLine: true,
missingValues: 'Linear',
};
const legend: XYVisualOptions = {
legend: {
isVisible: true,
position: 'bottom',
const { cpuUsage, memoryUsage } = createBasicCharts({
chartType: 'xy',
fromFormulas: ['cpuUsage', 'memoryUsage'],
chartConfig: {
yBounds: {
mode: 'custom',
lowerBound: 0,
upperBound: 1,
},
},
};
const { cpuUsage, memoryUsage, normalizedLoad1m } = createBasicCharts({
visualizationType: 'lnsXY',
formulaIds: ['cpuUsage', 'memoryUsage', 'normalizedLoad1m'],
dataView: metricsDataView,
visualOptions: commonVisualOptions,
dataViewId: metricsDataViewId,
});
const { normalizedLoad1m } = createBasicCharts({
chartType: 'xy',
fromFormulas: ['normalizedLoad1m'],
dataViewId: metricsDataViewId,
});
normalizedLoad1m.layers.push({ type: 'reference', yAxis: [{ value: '1' }] });
const { logRate } = createBasicCharts({
visualizationType: 'lnsXY',
formulaIds: ['logRate'],
dataView: logsDataView,
visualOptions: commonVisualOptions,
chartType: 'xy',
fromFormulas: ['logRate'],
dataViewId: logsDataViewId,
});
return createDashboardModel({
charts: [
cpuUsage,
{
...cpuUsageBreakdown.get({ dataView: metricsDataView }),
visualOptions: { ...commonVisualOptions, ...legend },
},
cpuUsageBreakdown.get({ dataViewId: metricsDataViewId }),
memoryUsage,
{
...memoryUsageBreakdown.get({ dataView: metricsDataView }),
visualOptions: { ...commonVisualOptions, ...legend },
},
memoryUsageBreakdown.get({ dataViewId: metricsDataViewId }),
normalizedLoad1m,
{
...loadBreakdown.get({ dataView: metricsDataView }),
visualOptions: { ...commonVisualOptions, ...legend },
},
loadBreakdown.get({ dataViewId: metricsDataViewId }),
logRate,
{
...diskSpaceUsageAvailable.get({ dataView: metricsDataView }),
visualOptions: { ...commonVisualOptions, ...legend },
},
{
...diskUsageByMountPoint.get({ dataView: metricsDataView }),
visualOptions: { ...commonVisualOptions, ...legend },
},
{
...diskThroughputReadWrite.get({ dataView: metricsDataView }),
visualOptions: { ...commonVisualOptions, ...legend },
},
{
...diskIOReadWrite.get({ dataView: metricsDataView }),
visualOptions: { ...commonVisualOptions, ...legend },
},
{
...rxTx.get({ dataView: metricsDataView }),
visualOptions: { ...commonVisualOptions, ...legend },
},
diskSpaceUsageAvailable.get({ dataViewId: metricsDataViewId }),
diskUsageByMountPoint.get({ dataViewId: metricsDataViewId }),
diskThroughputReadWrite.get({ dataViewId: metricsDataViewId }),
diskIOReadWrite.get({ dataViewId: metricsDataViewId }),
rxTx.get({ dataViewId: metricsDataViewId }),
],
});
},

View file

@ -4,8 +4,7 @@
* 2.0; you may not use this file except in compliance with the Elastic License
* 2.0.
*/
import { DataView } from '@kbn/data-views-plugin/common';
import type { XYVisualOptions } from '@kbn/lens-embeddable-utils';
import { createDashboardModel } from '../../../create_dashboard_model';
import {
createBasicCharts,
@ -18,36 +17,36 @@ import {
export const assetDetailsFlyout = {
get: ({
metricsDataView,
logsDataView,
metricsDataViewId,
logsDataViewId,
}: {
metricsDataView?: DataView;
logsDataView?: DataView;
metricsDataViewId?: string;
logsDataViewId?: string;
}) => {
const commonVisualOptions: XYVisualOptions = {
showDottedLine: true,
missingValues: 'Linear',
};
const legend: XYVisualOptions = {
legend: {
isVisible: true,
position: 'bottom',
const { cpuUsage, memoryUsage } = createBasicCharts({
chartType: 'xy',
fromFormulas: ['cpuUsage', 'memoryUsage'],
chartConfig: {
yBounds: {
mode: 'custom',
lowerBound: 0,
upperBound: 1,
},
},
};
const { cpuUsage, memoryUsage, normalizedLoad1m } = createBasicCharts({
visualizationType: 'lnsXY',
formulaIds: ['cpuUsage', 'memoryUsage', 'normalizedLoad1m'],
dataView: metricsDataView,
visualOptions: commonVisualOptions,
dataViewId: metricsDataViewId,
});
const { normalizedLoad1m } = createBasicCharts({
chartType: 'xy',
fromFormulas: ['normalizedLoad1m'],
dataViewId: metricsDataViewId,
});
normalizedLoad1m.layers.push({ type: 'reference', yAxis: [{ value: '1' }] });
const { logRate } = createBasicCharts({
visualizationType: 'lnsXY',
formulaIds: ['logRate'],
dataView: logsDataView,
visualOptions: commonVisualOptions,
chartType: 'xy',
fromFormulas: ['logRate'],
dataViewId: logsDataViewId,
});
return createDashboardModel({
@ -56,26 +55,11 @@ export const assetDetailsFlyout = {
memoryUsage,
normalizedLoad1m,
logRate,
{
...diskSpaceUsageAvailable.get({ dataView: metricsDataView }),
visualOptions: { ...commonVisualOptions, ...legend },
},
{
...diskUsageByMountPoint.get({ dataView: metricsDataView }),
visualOptions: { ...commonVisualOptions, ...legend },
},
{
...diskThroughputReadWrite.get({ dataView: metricsDataView }),
visualOptions: { ...commonVisualOptions, ...legend },
},
{
...diskIOReadWrite.get({ dataView: metricsDataView }),
visualOptions: { ...commonVisualOptions, ...legend },
},
{
...rxTx.get({ dataView: metricsDataView }),
visualOptions: { ...commonVisualOptions, ...legend },
},
diskSpaceUsageAvailable.get({ dataViewId: metricsDataViewId }),
diskUsageByMountPoint.get({ dataViewId: metricsDataViewId }),
diskThroughputReadWrite.get({ dataViewId: metricsDataViewId }),
diskIOReadWrite.get({ dataViewId: metricsDataViewId }),
rxTx.get({ dataViewId: metricsDataViewId }),
],
});
},

View file

@ -4,21 +4,30 @@
* 2.0; you may not use this file except in compliance with the Elastic License
* 2.0.
*/
import { DataView } from '@kbn/data-views-plugin/common';
import { i18n } from '@kbn/i18n';
import type { XYVisualOptions } from '@kbn/lens-embeddable-utils';
import type { LensXYConfigBase } from '@kbn/lens-embeddable-utils/config_builder';
import { createDashboardModel } from '../../../create_dashboard_model';
import { formulas } from '../../../kubernetes/node/metrics';
export const assetDetailsKubernetesNode = {
get: ({ metricsDataView }: { metricsDataView?: DataView }) => {
const commonVisualOptions: XYVisualOptions = {
showDottedLine: true,
missingValues: 'Linear',
get: ({ metricsDataViewId }: { metricsDataViewId?: string }) => {
const baseConfig: Partial<LensXYConfigBase> = {
fittingFunction: 'Linear',
axisTitleVisibility: {
showXAxisTitle: false,
showYAxisTitle: false,
},
legend: {
isVisible: true,
show: true,
position: 'bottom',
},
...(metricsDataViewId
? {
dataset: {
index: metricsDataViewId,
},
}
: {}),
};
return createDashboardModel({
@ -26,6 +35,7 @@ export const assetDetailsKubernetesNode = {
charts: [
{
id: 'nodeCpuCapacity',
chartType: 'xy',
title: i18n.translate(
'xpack.metricsData.assetDetails.metricsCharts.kubernetes.nodeCpuCapacity',
{
@ -34,19 +44,17 @@ export const assetDetailsKubernetesNode = {
),
layers: [
{
data: [formulas.nodeCpuCapacity, formulas.nodeCpuUsed],
options: {
seriesType: 'area',
},
layerType: 'data',
seriesType: 'area',
type: 'series',
xAxis: '@timestamp',
yAxis: [formulas.nodeCpuCapacity, formulas.nodeCpuUsed],
},
],
dataView: metricsDataView,
visualizationType: 'lnsXY',
visualOptions: commonVisualOptions,
...baseConfig,
},
{
id: 'nodeMemoryCapacity',
chartType: 'xy',
title: i18n.translate(
'xpack.metricsData.assetDetails.metricsCharts.kubernetes.nodeMemoryCapacity',
{
@ -55,19 +63,17 @@ export const assetDetailsKubernetesNode = {
),
layers: [
{
data: [formulas.nodeMemoryCapacity, formulas.nodeMemoryUsed],
options: {
seriesType: 'area',
},
layerType: 'data',
seriesType: 'area',
type: 'series',
xAxis: '@timestamp',
yAxis: [formulas.nodeMemoryCapacity, formulas.nodeMemoryUsed],
},
],
visualizationType: 'lnsXY',
dataView: metricsDataView,
visualOptions: commonVisualOptions,
...baseConfig,
},
{
id: 'nodeDiskCapacity',
chartType: 'xy',
title: i18n.translate(
'xpack.metricsData.assetDetails.metricsCharts.kubernetes.nodeDiskCapacity',
{
@ -76,19 +82,17 @@ export const assetDetailsKubernetesNode = {
),
layers: [
{
data: [formulas.nodeDiskCapacity, formulas.nodeDiskUsed],
options: {
seriesType: 'area',
},
layerType: 'data',
seriesType: 'area',
type: 'series',
xAxis: '@timestamp',
yAxis: [formulas.nodeDiskCapacity, formulas.nodeDiskUsed],
},
],
visualizationType: 'lnsXY',
dataView: metricsDataView,
visualOptions: commonVisualOptions,
...baseConfig,
},
{
id: 'nodePodCapacity',
chartType: 'xy',
title: i18n.translate(
'xpack.metricsData.assetDetails.metricsCharts.kubernetes.nodePodCapacity',
{
@ -97,16 +101,13 @@ export const assetDetailsKubernetesNode = {
),
layers: [
{
data: [formulas.nodePodCapacity, formulas.nodePodUsed],
options: {
seriesType: 'area',
},
layerType: 'data',
seriesType: 'area',
type: 'series',
xAxis: '@timestamp',
yAxis: [formulas.nodePodCapacity, formulas.nodePodUsed],
},
],
visualizationType: 'lnsXY',
dataView: metricsDataView,
visualOptions: commonVisualOptions,
...baseConfig,
},
],
});

View file

@ -5,32 +5,21 @@
* 2.0.
*/
import { DataView } from '@kbn/data-views-plugin/common';
import { XYChartModel, XYLayerOptions } from '@kbn/lens-embeddable-utils';
import type { LensBreakdownConfig } from '@kbn/lens-embeddable-utils/config_builder';
import { createDashboardModel } from '../../../create_dashboard_model';
import { createBasicCharts } from '../charts';
export const hostsView = {
get: ({ metricsDataView }: { metricsDataView?: DataView }) => {
const commonVisualOptions: XYChartModel['visualOptions'] = {
showDottedLine: true,
missingValues: 'Linear',
};
const layerOptions: XYLayerOptions = {
breakdown: {
type: 'top_values',
field: 'host.name',
params: {
size: 20,
},
},
get: ({ metricsDataViewId }: { metricsDataViewId?: string }) => {
const breakdown: LensBreakdownConfig = {
field: 'host.name',
type: 'topValues',
size: 20,
};
const {
memoryUsage,
memoryFree,
diskUsage,
diskSpaceAvailable,
diskIORead,
diskIOWrite,
@ -39,13 +28,10 @@ export const hostsView = {
rx,
tx,
} = createBasicCharts({
visualizationType: 'lnsXY',
formulaIds: [
'cpuUsage',
chartType: 'xy',
fromFormulas: [
'memoryUsage',
'normalizedLoad1m',
'memoryFree',
'diskUsage',
'diskSpaceAvailable',
'diskIORead',
'diskIOWrite',
@ -54,24 +40,40 @@ export const hostsView = {
'rx',
'tx',
],
dataView: metricsDataView,
layerOptions,
visualOptions: commonVisualOptions,
chartConfig: {
layerConfig: {
breakdown,
},
},
dataViewId: metricsDataViewId,
});
const { cpuUsage, normalizedLoad1m } = createBasicCharts({
visualizationType: 'lnsXY',
formulaIds: ['cpuUsage', 'normalizedLoad1m'],
layerOptions,
visualOptions: {
...commonVisualOptions,
yLeftExtent: {
mode: 'dataBounds',
const { normalizedLoad1m } = createBasicCharts({
chartType: 'xy',
fromFormulas: ['normalizedLoad1m'],
chartConfig: {
layerConfig: {
breakdown,
},
},
dataViewId: metricsDataViewId,
});
normalizedLoad1m.layers.push({ type: 'reference', yAxis: [{ value: '1' }] });
const { cpuUsage, diskUsage } = createBasicCharts({
chartType: 'xy',
fromFormulas: ['cpuUsage', 'diskUsage'],
chartConfig: {
layerConfig: {
breakdown,
},
yBounds: {
mode: 'custom',
lowerBound: 0,
upperBound: 1,
},
},
dataView: metricsDataView,
dataViewId: metricsDataViewId,
});
return createDashboardModel({

View file

@ -4,9 +4,8 @@
* 2.0; you may not use this file except in compliance with the Elastic License
* 2.0.
*/
import { DataView } from '@kbn/data-views-plugin/common';
import { i18n } from '@kbn/i18n';
import type { MetricLayerOptions } from '@kbn/lens-embeddable-utils';
import type { LensMetricConfig } from '@kbn/lens-embeddable-utils/config_builder';
import { createDashboardModel } from '../../../create_dashboard_model';
import { createBasicCharts } from '../charts';
@ -16,95 +15,28 @@ const AVERAGE = i18n.translate('xpack.metricsData.assetDetails.overview.kpi.subt
export const kpi = {
get: ({
metricsDataView,
metricsDataViewId,
options,
}: {
metricsDataView?: DataView;
options?: MetricLayerOptions;
metricsDataViewId?: string;
options?: Pick<LensMetricConfig, 'subtitle' | 'seriesColor'>;
}) => {
const { cpuUsage, diskUsage, memoryUsage, normalizedLoad1m } = createBasicCharts({
visualizationType: 'lnsMetric',
formulaIds: ['cpuUsage', 'diskUsage', 'memoryUsage', 'normalizedLoad1m'],
layerOptions: {
showTrendLine: true,
subtitle: AVERAGE,
...options,
chartType: 'metric',
fromFormulas: ['cpuUsage', 'diskUsage', 'memoryUsage', 'normalizedLoad1m'],
chartConfig: {
trendLine: true,
subtitle: options?.subtitle ?? AVERAGE,
seriesColor: options?.seriesColor,
},
dataView: metricsDataView,
dataViewId: metricsDataViewId,
});
return createDashboardModel({
charts: [
{
...cpuUsage,
layers: {
...cpuUsage.layers,
data: {
...cpuUsage.layers.data,
format: cpuUsage.layers.data.format
? {
...cpuUsage.layers.data.format,
params: {
decimals: 1,
},
}
: undefined,
},
},
},
{
...normalizedLoad1m,
layers: {
...normalizedLoad1m.layers,
data: {
...normalizedLoad1m.layers.data,
format: normalizedLoad1m.layers.data.format
? {
...normalizedLoad1m.layers.data.format,
params: {
decimals: 1,
},
}
: undefined,
},
},
},
{
...memoryUsage,
layers: {
...memoryUsage.layers,
data: {
...memoryUsage.layers.data,
format: memoryUsage.layers.data.format
? {
...memoryUsage.layers.data.format,
params: {
decimals: 1,
},
}
: undefined,
},
},
},
{
...diskUsage,
layers: {
...diskUsage.layers,
data: {
...diskUsage.layers.data,
format: diskUsage.layers.data.format
? {
...diskUsage.layers.data.format,
params: {
decimals: 1,
},
}
: undefined,
},
},
},
],
charts: [cpuUsage, diskUsage, memoryUsage, normalizedLoad1m].map((p) => ({
...p,
decimals: 1,
})),
});
},
};

View file

@ -0,0 +1,81 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0; you may not use this file except in compliance with the Elastic License
* 2.0.
*/
import { i18n } from '@kbn/i18n';
import type { LensBaseLayer } from '@kbn/lens-embeddable-utils/config_builder';
export const cpuUsageIowait: LensBaseLayer = {
label: i18n.translate('xpack.metricsData.assetDetails.formulas.cpuUsage.iowaitLabel', {
defaultMessage: 'iowait',
}),
value: 'average(system.cpu.iowait.pct) / max(system.cpu.cores)',
format: 'percent',
decimals: 1,
};
export const cpuUsageIrq: LensBaseLayer = {
label: i18n.translate('xpack.metricsData.assetDetails.formulas.cpuUsage.irqLabel', {
defaultMessage: 'irq',
}),
value: 'average(system.cpu.irq.pct) / max(system.cpu.cores)',
format: 'percent',
decimals: 1,
};
export const cpuUsageNice: LensBaseLayer = {
label: i18n.translate('xpack.metricsData.assetDetails.formulas.cpuUsage.niceLabel', {
defaultMessage: 'nice',
}),
value: 'average(system.cpu.nice.norm.pct) / max(system.cpu.cores)',
format: 'percent',
decimals: 1,
};
export const cpuUsageSoftirq: LensBaseLayer = {
label: i18n.translate('xpack.metricsData.assetDetails.formulas.cpuUsage.softirqLabel', {
defaultMessage: 'softirq',
}),
value: 'average(system.cpu.softirq.pct) / max(system.cpu.cores)',
format: 'percent',
decimals: 1,
};
export const cpuUsageSteal: LensBaseLayer = {
label: i18n.translate('xpack.metricsData.assetDetails.formulas.cpuUsage.stealLabel', {
defaultMessage: 'steal',
}),
value: 'average(system.cpu.steal.pct) / max(system.cpu.cores)',
format: 'percent',
decimals: 1,
};
export const cpuUsageSystem: LensBaseLayer = {
label: i18n.translate('xpack.metricsData.assetDetails.formulas.cpuUsage.systemLabel', {
defaultMessage: 'system',
}),
value: 'average(system.cpu.system.pct) / max(system.cpu.cores)',
format: 'percent',
decimals: 1,
};
export const cpuUsageUser: LensBaseLayer = {
label: i18n.translate('xpack.metricsData.assetDetails.formulas.cpuUsage.userLabel', {
defaultMessage: 'user',
}),
value: 'average(system.cpu.user.pct) / max(system.cpu.cores)',
format: 'percent',
decimals: 1,
};
export const cpuUsage: LensBaseLayer = {
label: i18n.translate('xpack.metricsData.assetDetails.formulas.cpuUsage', {
defaultMessage: 'CPU Usage',
}),
value: '(average(system.cpu.user.pct) + average(system.cpu.system.pct)) / max(system.cpu.cores)',
format: 'percent',
decimals: 0,
};

View file

@ -1,22 +0,0 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0; you may not use this file except in compliance with the Elastic License
* 2.0.
*/
import { i18n } from '@kbn/i18n';
import type { FormulaValueConfig } from '@kbn/lens-embeddable-utils';
export const cpuUsage: FormulaValueConfig = {
label: i18n.translate('xpack.metricsData.assetDetails.formulas.cpuUsage', {
defaultMessage: 'CPU Usage',
}),
value: '(average(system.cpu.user.pct) + average(system.cpu.system.pct)) / max(system.cpu.cores)',
format: {
id: 'percent',
params: {
decimals: 0,
},
},
};

View file

@ -1,22 +0,0 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0; you may not use this file except in compliance with the Elastic License
* 2.0.
*/
import { i18n } from '@kbn/i18n';
import type { FormulaValueConfig } from '@kbn/lens-embeddable-utils';
export const cpuUsageIowait: FormulaValueConfig = {
label: i18n.translate('xpack.metricsData.assetDetails.formulas.cpuUsage.iowaitLabel', {
defaultMessage: 'iowait',
}),
value: 'average(system.cpu.iowait.pct) / max(system.cpu.cores)',
format: {
id: 'percent',
params: {
decimals: 1,
},
},
};

View file

@ -1,22 +0,0 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0; you may not use this file except in compliance with the Elastic License
* 2.0.
*/
import { i18n } from '@kbn/i18n';
import type { FormulaValueConfig } from '@kbn/lens-embeddable-utils';
export const cpuUsageIrq: FormulaValueConfig = {
label: i18n.translate('xpack.metricsData.assetDetails.formulas.cpuUsage.irqLabel', {
defaultMessage: 'irq',
}),
value: 'average(system.cpu.irq.pct) / max(system.cpu.cores)',
format: {
id: 'percent',
params: {
decimals: 1,
},
},
};

View file

@ -1,22 +0,0 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0; you may not use this file except in compliance with the Elastic License
* 2.0.
*/
import { i18n } from '@kbn/i18n';
import type { FormulaValueConfig } from '@kbn/lens-embeddable-utils';
export const cpuUsageNice: FormulaValueConfig = {
label: i18n.translate('xpack.metricsData.assetDetails.formulas.cpuUsage.niceLabel', {
defaultMessage: 'nice',
}),
value: 'average(system.cpu.nice.norm.pct) / max(system.cpu.cores)',
format: {
id: 'percent',
params: {
decimals: 1,
},
},
};

View file

@ -1,22 +0,0 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0; you may not use this file except in compliance with the Elastic License
* 2.0.
*/
import { i18n } from '@kbn/i18n';
import type { FormulaValueConfig } from '@kbn/lens-embeddable-utils';
export const cpuUsageSoftirq: FormulaValueConfig = {
label: i18n.translate('xpack.metricsData.assetDetails.formulas.cpuUsage.softirqLabel', {
defaultMessage: 'softirq',
}),
value: 'average(system.cpu.softirq.pct) / max(system.cpu.cores)',
format: {
id: 'percent',
params: {
decimals: 1,
},
},
};

View file

@ -1,22 +0,0 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0; you may not use this file except in compliance with the Elastic License
* 2.0.
*/
import { i18n } from '@kbn/i18n';
import type { FormulaValueConfig } from '@kbn/lens-embeddable-utils';
export const cpuUsageSteal: FormulaValueConfig = {
label: i18n.translate('xpack.metricsData.assetDetails.formulas.cpuUsage.stealLabel', {
defaultMessage: 'steal',
}),
value: 'average(system.cpu.steal.pct) / max(system.cpu.cores)',
format: {
id: 'percent',
params: {
decimals: 1,
},
},
};

View file

@ -1,22 +0,0 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0; you may not use this file except in compliance with the Elastic License
* 2.0.
*/
import { i18n } from '@kbn/i18n';
import type { FormulaValueConfig } from '@kbn/lens-embeddable-utils';
export const cpuUsageSystem: FormulaValueConfig = {
label: i18n.translate('xpack.metricsData.assetDetails.formulas.cpuUsage.systemLabel', {
defaultMessage: 'system',
}),
value: 'average(system.cpu.system.pct) / max(system.cpu.cores)',
format: {
id: 'percent',
params: {
decimals: 1,
},
},
};

View file

@ -1,22 +0,0 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0; you may not use this file except in compliance with the Elastic License
* 2.0.
*/
import { i18n } from '@kbn/i18n';
import type { FormulaValueConfig } from '@kbn/lens-embeddable-utils';
export const cpuUsageUser: FormulaValueConfig = {
label: i18n.translate('xpack.metricsData.assetDetails.formulas.cpuUsage.userLabel', {
defaultMessage: 'user',
}),
value: 'average(system.cpu.user.pct) / max(system.cpu.cores)',
format: {
id: 'percent',
params: {
decimals: 1,
},
},
};

View file

@ -0,0 +1,76 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0; you may not use this file except in compliance with the Elastic License
* 2.0.
*/
import { i18n } from '@kbn/i18n';
import type { LensBaseLayer } from '@kbn/lens-embeddable-utils/config_builder';
export const diskIORead: LensBaseLayer = {
label: i18n.translate('xpack.metricsData.assetDetails.formulas.diskIORead', {
defaultMessage: 'Disk Read IOPS',
}),
value: "counter_rate(max(system.diskio.read.count), kql='system.diskio.read.count: *')",
format: 'number',
decimals: 0,
normalizeByUnit: 's',
};
export const diskReadThroughput: LensBaseLayer = {
label: i18n.translate('xpack.metricsData.assetDetails.formulas.diskReadThroughput', {
defaultMessage: 'Disk Read Throughput',
}),
value: "counter_rate(max(system.diskio.read.bytes), kql='system.diskio.read.bytes: *')",
format: 'bytes',
decimals: 1,
normalizeByUnit: 's',
};
export const diskSpaceAvailable: LensBaseLayer = {
label: i18n.translate('xpack.metricsData.assetDetails.formulas.diskSpaceAvailable', {
defaultMessage: 'Disk Space Available',
}),
value: 'average(system.filesystem.free)',
format: 'bytes',
decimals: 0,
};
export const diskSpaceAvailability: LensBaseLayer = {
label: i18n.translate('xpack.metricsData.assetDetails.formulas.diskSpaceAvailability', {
defaultMessage: 'Disk Space Availability',
}),
value: '1 - average(system.filesystem.used.pct)',
format: 'percent',
decimals: 0,
};
export const diskUsage: LensBaseLayer = {
label: i18n.translate('xpack.metricsData.assetDetails.formulas.diskUsage', {
defaultMessage: 'Disk Usage',
}),
value: 'average(system.filesystem.used.pct)',
format: 'percent',
decimals: 0,
};
export const diskIOWrite: LensBaseLayer = {
label: i18n.translate('xpack.metricsData.assetDetails.formulas.diskIOWrite', {
defaultMessage: 'Disk Write IOPS',
}),
value: "counter_rate(max(system.diskio.write.count), kql='system.diskio.write.count: *')",
format: 'number',
decimals: 0,
normalizeByUnit: 's',
};
export const diskWriteThroughput: LensBaseLayer = {
label: i18n.translate('xpack.metricsData.assetDetails.formulas.diskWriteThroughput', {
defaultMessage: 'Disk Write Throughput',
}),
value: "counter_rate(max(system.diskio.write.bytes), kql='system.diskio.write.bytes: *')",
format: 'bytes',
decimals: 1,
normalizeByUnit: 's',
};

View file

@ -1,23 +0,0 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0; you may not use this file except in compliance with the Elastic License
* 2.0.
*/
import { i18n } from '@kbn/i18n';
import type { FormulaValueConfig } from '@kbn/lens-embeddable-utils';
export const diskIORead: FormulaValueConfig = {
label: i18n.translate('xpack.metricsData.assetDetails.formulas.diskIORead', {
defaultMessage: 'Disk Read IOPS',
}),
value: "counter_rate(max(system.diskio.read.count), kql='system.diskio.read.count: *')",
format: {
id: 'number',
params: {
decimals: 0,
},
},
timeScale: 's',
};

View file

@ -1,23 +0,0 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0; you may not use this file except in compliance with the Elastic License
* 2.0.
*/
import { i18n } from '@kbn/i18n';
import type { FormulaValueConfig } from '@kbn/lens-embeddable-utils';
export const diskReadThroughput: FormulaValueConfig = {
label: i18n.translate('xpack.metricsData.assetDetails.formulas.diskReadThroughput', {
defaultMessage: 'Disk Read Throughput',
}),
value: "counter_rate(max(system.diskio.read.bytes), kql='system.diskio.read.bytes: *')",
format: {
id: 'bytes',
params: {
decimals: 1,
},
},
timeScale: 's',
};

View file

@ -1,22 +0,0 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0; you may not use this file except in compliance with the Elastic License
* 2.0.
*/
import { i18n } from '@kbn/i18n';
import type { FormulaValueConfig } from '@kbn/lens-embeddable-utils';
export const diskSpaceAvailability: FormulaValueConfig = {
label: i18n.translate('xpack.metricsData.assetDetails.formulas.diskSpaceAvailability', {
defaultMessage: 'Disk Space Availability',
}),
value: '1 - average(system.filesystem.used.pct)',
format: {
id: 'percent',
params: {
decimals: 0,
},
},
};

View file

@ -1,22 +0,0 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0; you may not use this file except in compliance with the Elastic License
* 2.0.
*/
import { i18n } from '@kbn/i18n';
import type { FormulaValueConfig } from '@kbn/lens-embeddable-utils';
export const diskSpaceAvailable: FormulaValueConfig = {
label: i18n.translate('xpack.metricsData.assetDetails.formulas.diskSpaceAvailable', {
defaultMessage: 'Disk Space Available',
}),
value: 'average(system.filesystem.free)',
format: {
id: 'bytes',
params: {
decimals: 0,
},
},
};

View file

@ -1,22 +0,0 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0; you may not use this file except in compliance with the Elastic License
* 2.0.
*/
import { i18n } from '@kbn/i18n';
import type { FormulaValueConfig } from '@kbn/lens-embeddable-utils';
export const diskUsage: FormulaValueConfig = {
label: i18n.translate('xpack.metricsData.assetDetails.formulas.diskUsage', {
defaultMessage: 'Disk Usage',
}),
value: 'average(system.filesystem.used.pct)',
format: {
id: 'percent',
params: {
decimals: 0,
},
},
};

View file

@ -1,23 +0,0 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0; you may not use this file except in compliance with the Elastic License
* 2.0.
*/
import { i18n } from '@kbn/i18n';
import type { FormulaValueConfig } from '@kbn/lens-embeddable-utils';
export const diskIOWrite: FormulaValueConfig = {
label: i18n.translate('xpack.metricsData.assetDetails.formulas.diskIOWrite', {
defaultMessage: 'Disk Write IOPS',
}),
value: "counter_rate(max(system.diskio.write.count), kql='system.diskio.write.count: *')",
format: {
id: 'number',
params: {
decimals: 0,
},
},
timeScale: 's',
};

View file

@ -1,23 +0,0 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0; you may not use this file except in compliance with the Elastic License
* 2.0.
*/
import { i18n } from '@kbn/i18n';
import type { FormulaValueConfig } from '@kbn/lens-embeddable-utils';
export const diskWriteThroughput: FormulaValueConfig = {
label: i18n.translate('xpack.metricsData.assetDetails.formulas.diskWriteThroughput', {
defaultMessage: 'Disk Write Throughput',
}),
value: "counter_rate(max(system.diskio.write.bytes), kql='system.diskio.write.bytes: *')",
format: {
id: 'bytes',
params: {
decimals: 1,
},
},
timeScale: 's',
};

View file

@ -6,17 +6,13 @@
*/
import { i18n } from '@kbn/i18n';
import type { FormulaValueConfig } from '@kbn/lens-embeddable-utils';
import type { LensBaseLayer } from '@kbn/lens-embeddable-utils/config_builder';
export const hostCount: FormulaValueConfig = {
export const hostCount: LensBaseLayer = {
label: i18n.translate('xpack.metricsData.assetDetails.formulas.hostCount.hostsLabel', {
defaultMessage: 'Hosts',
}),
value: 'unique_count(host.name)',
format: {
id: 'number',
params: {
decimals: 0,
},
},
format: 'number',
decimals: 0,
};

View file

@ -5,34 +5,38 @@
* 2.0.
*/
import { cpuUsage } from './cpu_usage';
import { cpuUsageIowait } from './cpu_usage_iowait';
import { cpuUsageIrq } from './cpu_usage_irq';
import { cpuUsageNice } from './cpu_usage_nice';
import { cpuUsageSoftirq } from './cpu_usage_softirq';
import { cpuUsageSteal } from './cpu_usage_steal';
import { cpuUsageUser } from './cpu_usage_user';
import { cpuUsageSystem } from './cpu_usage_system';
import { diskIORead } from './disk_read_iops';
import { diskIOWrite } from './disk_write_iops';
import { diskReadThroughput } from './disk_read_throughput';
import { diskWriteThroughput } from './disk_write_throughput';
import { diskSpaceAvailability } from './disk_space_availability';
import { diskSpaceAvailable } from './disk_space_available';
import { diskUsage } from './disk_usage';
import {
cpuUsage,
cpuUsageIowait,
cpuUsageIrq,
cpuUsageNice,
cpuUsageSoftirq,
cpuUsageSteal,
cpuUsageSystem,
cpuUsageUser,
} from './cpu';
import {
diskIORead,
diskIOWrite,
diskReadThroughput,
diskSpaceAvailable,
diskSpaceAvailability,
diskUsage,
diskWriteThroughput,
} from './disk';
import { hostCount } from './host_count';
import { logRate } from './log_rate';
import { normalizedLoad1m } from './normalized_load_1m';
import { load1m } from './load_1m';
import { load5m } from './load_5m';
import { load15m } from './load_15m';
import { memoryUsage } from './memory_usage';
import { memoryFree } from './memory_free';
import { memoryUsed } from './memory_used';
import { memoryFreeExcludingCache } from './memory_free_excluding_cache';
import { memoryCache } from './memory_cache';
import { rx } from './rx';
import { tx } from './tx';
import { load1m, load15m, load5m, normalizedLoad1m } from './load';
import {
memoryUsage,
memoryCache,
memoryFreeExcludingCache,
memoryUsed,
memoryFree,
} from './memory';
import { rx, tx } from './network';
export const formulas = {
cpuUsage,

View file

@ -0,0 +1,45 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0; you may not use this file except in compliance with the Elastic License
* 2.0.
*/
import { i18n } from '@kbn/i18n';
import type { LensBaseLayer } from '@kbn/lens-embeddable-utils/config_builder';
export const load1m: LensBaseLayer = {
label: i18n.translate('xpack.metricsData.assetDetails.formulas.load1m', {
defaultMessage: 'Load (1m)',
}),
value: 'average(system.load.1)',
format: 'number',
decimals: 1,
};
export const load5m: LensBaseLayer = {
label: i18n.translate('xpack.metricsData.assetDetails.formulas.load5m', {
defaultMessage: 'Load (5m)',
}),
value: 'average(system.load.5)',
format: 'number',
decimals: 1,
};
export const load15m: LensBaseLayer = {
label: i18n.translate('xpack.metricsData.assetDetails.formulas.load15m', {
defaultMessage: 'Load (15m)',
}),
value: 'average(system.load.15)',
format: 'number',
decimals: 1,
};
export const normalizedLoad1m: LensBaseLayer = {
label: i18n.translate('xpack.metricsData.assetDetails.formulas.normalizedLoad1m', {
defaultMessage: 'Normalized Load',
}),
value: 'average(system.load.1) / max(system.load.cores)',
format: 'percent',
decimals: 0,
};

View file

@ -1,22 +0,0 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0; you may not use this file except in compliance with the Elastic License
* 2.0.
*/
import { i18n } from '@kbn/i18n';
import type { FormulaValueConfig } from '@kbn/lens-embeddable-utils';
export const load15m: FormulaValueConfig = {
label: i18n.translate('xpack.metricsData.assetDetails.formulas.load15m', {
defaultMessage: 'Load (15m)',
}),
value: 'average(system.load.15)',
format: {
id: 'number',
params: {
decimals: 1,
},
},
};

View file

@ -1,22 +0,0 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0; you may not use this file except in compliance with the Elastic License
* 2.0.
*/
import { i18n } from '@kbn/i18n';
import type { FormulaValueConfig } from '@kbn/lens-embeddable-utils';
export const load1m: FormulaValueConfig = {
label: i18n.translate('xpack.metricsData.assetDetails.formulas.load1m', {
defaultMessage: 'Load (1m)',
}),
value: 'average(system.load.1)',
format: {
id: 'number',
params: {
decimals: 1,
},
},
};

View file

@ -1,22 +0,0 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0; you may not use this file except in compliance with the Elastic License
* 2.0.
*/
import { i18n } from '@kbn/i18n';
import type { FormulaValueConfig } from '@kbn/lens-embeddable-utils';
export const load5m: FormulaValueConfig = {
label: i18n.translate('xpack.metricsData.assetDetails.formulas.load5m', {
defaultMessage: 'Load (5m)',
}),
value: 'average(system.load.5)',
format: {
id: 'number',
params: {
decimals: 1,
},
},
};

View file

@ -6,18 +6,14 @@
*/
import { i18n } from '@kbn/i18n';
import type { FormulaValueConfig } from '@kbn/lens-embeddable-utils';
import type { LensBaseLayer } from '@kbn/lens-embeddable-utils/config_builder';
export const logRate: FormulaValueConfig = {
export const logRate: LensBaseLayer = {
label: i18n.translate('xpack.metricsData.assetDetails.formulas.logRate', {
defaultMessage: 'Log Rate',
}),
value: 'differences(cumulative_sum(count()))',
format: {
id: 'number',
params: {
decimals: 0,
},
},
timeScale: 's',
format: 'number',
decimals: 0,
normalizeByUnit: 's',
};

View file

@ -0,0 +1,55 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0; you may not use this file except in compliance with the Elastic License
* 2.0.
*/
import { i18n } from '@kbn/i18n';
import type { LensBaseLayer } from '@kbn/lens-embeddable-utils/config_builder';
export const memoryCache: LensBaseLayer = {
label: i18n.translate('xpack.metricsData.assetDetails.formulas.metric.label.cache', {
defaultMessage: 'cache',
}),
value: 'average(system.memory.used.bytes) - average(system.memory.actual.used.bytes)',
format: 'bytes',
decimals: 1,
};
export const memoryFree: LensBaseLayer = {
label: i18n.translate('xpack.metricsData.assetDetails.formulas.memoryFree', {
defaultMessage: 'Memory Free',
}),
value: 'max(system.memory.total) - average(system.memory.actual.used.bytes)',
format: 'bytes',
decimals: 1,
};
export const memoryFreeExcludingCache: LensBaseLayer = {
label: i18n.translate('xpack.metricsData.assetDetails.formulas.metric.label.free', {
defaultMessage: 'free',
}),
value: 'average(system.memory.free)',
format: 'bytes',
decimals: 1,
};
export const memoryUsage: LensBaseLayer = {
label: i18n.translate('xpack.metricsData.assetDetails.formulas.memoryUsage', {
defaultMessage: 'Memory Usage',
}),
value: 'average(system.memory.actual.used.pct)',
format: 'percent',
decimals: 0,
};
export const memoryUsed: LensBaseLayer = {
label: i18n.translate('xpack.metricsData.assetDetails.formulas.metric.label.used', {
defaultMessage: 'used',
}),
value: 'average(system.memory.actual.used.bytes)',
format: 'bytes',
decimals: 1,
};

View file

@ -1,22 +0,0 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0; you may not use this file except in compliance with the Elastic License
* 2.0.
*/
import { i18n } from '@kbn/i18n';
import type { FormulaValueConfig } from '@kbn/lens-embeddable-utils';
export const memoryCache: FormulaValueConfig = {
label: i18n.translate('xpack.metricsData.assetDetails.formulas.metric.label.cache', {
defaultMessage: 'cache',
}),
value: 'average(system.memory.used.bytes) - average(system.memory.actual.used.bytes)',
format: {
id: 'bytes',
params: {
decimals: 1,
},
},
};

View file

@ -1,22 +0,0 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0; you may not use this file except in compliance with the Elastic License
* 2.0.
*/
import { i18n } from '@kbn/i18n';
import type { FormulaValueConfig } from '@kbn/lens-embeddable-utils';
export const memoryFree: FormulaValueConfig = {
label: i18n.translate('xpack.metricsData.assetDetails.formulas.memoryFree', {
defaultMessage: 'Memory Free',
}),
value: 'max(system.memory.total) - average(system.memory.actual.used.bytes)',
format: {
id: 'bytes',
params: {
decimals: 1,
},
},
};

View file

@ -1,22 +0,0 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0; you may not use this file except in compliance with the Elastic License
* 2.0.
*/
import { i18n } from '@kbn/i18n';
import type { FormulaValueConfig } from '@kbn/lens-embeddable-utils';
export const memoryFreeExcludingCache: FormulaValueConfig = {
label: i18n.translate('xpack.metricsData.assetDetails.formulas.metric.label.free', {
defaultMessage: 'free',
}),
value: 'average(system.memory.free)',
format: {
id: 'bytes',
params: {
decimals: 1,
},
},
};

View file

@ -1,22 +0,0 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0; you may not use this file except in compliance with the Elastic License
* 2.0.
*/
import { i18n } from '@kbn/i18n';
import type { FormulaValueConfig } from '@kbn/lens-embeddable-utils';
export const memoryUsage: FormulaValueConfig = {
label: i18n.translate('xpack.metricsData.assetDetails.formulas.memoryUsage', {
defaultMessage: 'Memory Usage',
}),
value: 'average(system.memory.actual.used.pct)',
format: {
id: 'percent',
params: {
decimals: 0,
},
},
};

View file

@ -1,22 +0,0 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0; you may not use this file except in compliance with the Elastic License
* 2.0.
*/
import { i18n } from '@kbn/i18n';
import type { FormulaValueConfig } from '@kbn/lens-embeddable-utils';
export const memoryUsed: FormulaValueConfig = {
label: i18n.translate('xpack.metricsData.assetDetails.formulas.metric.label.used', {
defaultMessage: 'used',
}),
value: 'average(system.memory.actual.used.bytes)',
format: {
id: 'bytes',
params: {
decimals: 1,
},
},
};

View file

@ -6,19 +6,26 @@
*/
import { i18n } from '@kbn/i18n';
import type { FormulaValueConfig } from '@kbn/lens-embeddable-utils';
import type { LensBaseLayer } from '@kbn/lens-embeddable-utils/config_builder';
export const rx: FormulaValueConfig = {
export const rx: LensBaseLayer = {
label: i18n.translate('xpack.metricsData.assetDetails.formulas.rx', {
defaultMessage: 'Network Inbound (RX)',
}),
value:
"average(host.network.ingress.bytes) * 8 / (max(metricset.period, kql='host.network.ingress.bytes: *') / 1000)",
format: {
id: 'bits',
params: {
decimals: 1,
},
},
timeScale: 's',
format: 'bits',
decimals: 1,
normalizeByUnit: 's',
};
export const tx: LensBaseLayer = {
label: i18n.translate('xpack.metricsData.assetDetails.formulas.tx', {
defaultMessage: 'Network Outbound (TX)',
}),
value:
"average(host.network.egress.bytes) * 8 / (max(metricset.period, kql='host.network.egress.bytes: *') / 1000)",
format: 'bits',
decimals: 1,
normalizeByUnit: 's',
};

View file

@ -1,22 +0,0 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0; you may not use this file except in compliance with the Elastic License
* 2.0.
*/
import { i18n } from '@kbn/i18n';
import type { FormulaValueConfig } from '@kbn/lens-embeddable-utils';
export const normalizedLoad1m: FormulaValueConfig = {
label: i18n.translate('xpack.metricsData.assetDetails.formulas.normalizedLoad1m', {
defaultMessage: 'Normalized Load',
}),
value: 'average(system.load.1) / max(system.load.cores)',
format: {
id: 'percent',
params: {
decimals: 0,
},
},
};

View file

@ -1,24 +0,0 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0; you may not use this file except in compliance with the Elastic License
* 2.0.
*/
import { i18n } from '@kbn/i18n';
import type { FormulaValueConfig } from '@kbn/lens-embeddable-utils';
export const tx: FormulaValueConfig = {
label: i18n.translate('xpack.metricsData.assetDetails.formulas.tx', {
defaultMessage: 'Network Outbound (TX)',
}),
value:
"average(host.network.egress.bytes) * 8 / (max(metricset.period, kql='host.network.egress.bytes: *') / 1000)",
format: {
id: 'bits',
params: {
decimals: 1,
},
},
timeScale: 's',
};

View file

@ -6,18 +6,24 @@
*/
import { i18n } from '@kbn/i18n';
import type { FormulaValueConfig } from '@kbn/lens-embeddable-utils';
import type { LensBaseLayer } from '@kbn/lens-embeddable-utils/config_builder';
export const nodeCpuCapacity: FormulaValueConfig = {
export const nodeCpuCapacity: LensBaseLayer = {
label: i18n.translate('xpack.metricsData.assetDetails.formulas.kubernetes.capacity', {
defaultMessage: 'Capacity',
}),
value: 'max(kubernetes.node.cpu.allocatable.cores) * 1000000000',
format: {
id: 'number',
params: {
decimals: 1,
compact: true,
},
},
format: 'number',
decimals: 1,
compactValues: true,
};
export const nodeCpuUsed: LensBaseLayer = {
label: i18n.translate('xpack.metricsData.assetDetails.formulas.kubernetes.used', {
defaultMessage: 'Used',
}),
value: 'average(kubernetes.node.cpu.usage.nanocores)',
format: 'number',
decimals: 1,
compactValues: true,
};

View file

@ -6,17 +6,22 @@
*/
import { i18n } from '@kbn/i18n';
import type { FormulaValueConfig } from '@kbn/lens-embeddable-utils';
import type { LensBaseLayer } from '@kbn/lens-embeddable-utils/config_builder';
export const nodeDiskCapacity: FormulaValueConfig = {
export const nodeDiskCapacity: LensBaseLayer = {
label: i18n.translate('xpack.metricsData.assetDetails.formulas.kubernetes.capacity', {
defaultMessage: 'Capacity',
}),
value: 'max(kubernetes.node.fs.capacity.bytes)',
format: {
id: 'bytes',
params: {
decimals: 1,
},
},
format: 'bytes',
decimals: 1,
};
export const nodeDiskUsed: LensBaseLayer = {
label: i18n.translate('xpack.metricsData.assetDetails.formulas.kubernetes.used', {
defaultMessage: 'Used',
}),
value: 'average(kubernetes.node.fs.used.bytes)',
format: 'bytes',
decimals: 1,
};

View file

@ -5,14 +5,10 @@
* 2.0.
*/
import { nodeCpuCapacity } from './node_cpu_capacity';
import { nodeCpuUsed } from './node_cpu_used';
import { nodeDiskCapacity } from './node_disk_capacity';
import { nodeDiskUsed } from './node_disk_used';
import { nodeMemoryCapacity } from './node_memory_capacity';
import { nodeMemoryUsed } from './node_memory_used';
import { nodePodCapacity } from './node_pod_capacity';
import { nodePodUsed } from './node_pod_used';
import { nodeCpuCapacity, nodeCpuUsed } from './cpu';
import { nodeDiskCapacity, nodeDiskUsed } from './disk';
import { nodeMemoryCapacity, nodeMemoryUsed } from './memory';
import { nodePodCapacity, nodePodUsed } from './pod_capacity';
export const formulas = {
nodeCpuCapacity,

View file

@ -6,17 +6,22 @@
*/
import { i18n } from '@kbn/i18n';
import type { FormulaValueConfig } from '@kbn/lens-embeddable-utils';
import type { LensBaseLayer } from '@kbn/lens-embeddable-utils/config_builder';
export const nodeMemoryCapacity: FormulaValueConfig = {
export const nodeMemoryCapacity: LensBaseLayer = {
label: i18n.translate('xpack.metricsData.assetDetails.formulas.kubernetes.capacity', {
defaultMessage: 'Capacity',
}),
value: 'max(kubernetes.node.memory.allocatable.bytes)',
format: {
id: 'bytes',
params: {
decimals: 1,
},
},
format: 'bytes',
decimals: 1,
};
export const nodeMemoryUsed: LensBaseLayer = {
label: i18n.translate('xpack.metricsData.assetDetails.formulas.kubernetes.used', {
defaultMessage: 'Used',
}),
value: 'average(kubernetes.node.memory.usage.bytes)',
format: 'bytes',
decimals: 1,
};

View file

@ -1,23 +0,0 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0; you may not use this file except in compliance with the Elastic License
* 2.0.
*/
import { i18n } from '@kbn/i18n';
import type { FormulaValueConfig } from '@kbn/lens-embeddable-utils';
export const nodeCpuUsed: FormulaValueConfig = {
label: i18n.translate('xpack.metricsData.assetDetails.formulas.kubernetes.used', {
defaultMessage: 'Used',
}),
value: 'average(kubernetes.node.cpu.usage.nanocores)',
format: {
id: 'number',
params: {
decimals: 1,
compact: true,
},
},
};

View file

@ -1,22 +0,0 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0; you may not use this file except in compliance with the Elastic License
* 2.0.
*/
import { i18n } from '@kbn/i18n';
import type { FormulaValueConfig } from '@kbn/lens-embeddable-utils';
export const nodeDiskUsed: FormulaValueConfig = {
label: i18n.translate('xpack.metricsData.assetDetails.formulas.kubernetes.used', {
defaultMessage: 'Used',
}),
value: 'average(kubernetes.node.fs.used.bytes)',
format: {
id: 'bytes',
params: {
decimals: 1,
},
},
};

View file

@ -1,22 +0,0 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0; you may not use this file except in compliance with the Elastic License
* 2.0.
*/
import { i18n } from '@kbn/i18n';
import type { FormulaValueConfig } from '@kbn/lens-embeddable-utils';
export const nodeMemoryUsed: FormulaValueConfig = {
label: i18n.translate('xpack.metricsData.assetDetails.formulas.kubernetes.used', {
defaultMessage: 'Used',
}),
value: 'average(kubernetes.node.memory.usage.bytes)',
format: {
id: 'bytes',
params: {
decimals: 1,
},
},
};

View file

@ -1,22 +0,0 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0; you may not use this file except in compliance with the Elastic License
* 2.0.
*/
import { i18n } from '@kbn/i18n';
import type { FormulaValueConfig } from '@kbn/lens-embeddable-utils';
export const nodePodUsed: FormulaValueConfig = {
label: i18n.translate('xpack.metricsData.assetDetails.formulas.kubernetes.used', {
defaultMessage: 'Used',
}),
value: 'unique_count(kubernetes.pod.uid)',
format: {
id: 'number',
params: {
decimals: 0,
},
},
};

View file

@ -6,18 +6,23 @@
*/
import { i18n } from '@kbn/i18n';
import type { FormulaValueConfig } from '@kbn/lens-embeddable-utils';
import type { LensBaseLayer } from '@kbn/lens-embeddable-utils/config_builder';
export const nodePodCapacity: FormulaValueConfig = {
export const nodePodCapacity: LensBaseLayer = {
label: i18n.translate('xpack.metricsData.assetDetails.formulas.kubernetes.capacity', {
defaultMessage: 'Capacity',
}),
value:
"last_value(kubernetes.node.pod.allocatable.total, kql='kubernetes.node.pod.allocatable.total: *')",
format: {
id: 'number',
params: {
decimals: 0,
},
},
format: 'number',
decimals: 0,
};
export const nodePodUsed: LensBaseLayer = {
label: i18n.translate('xpack.metricsData.assetDetails.formulas.kubernetes.used', {
defaultMessage: 'Used',
}),
value: 'unique_count(kubernetes.pod.uid)',
format: 'number',
decimals: 0,
};

View file

@ -5,7 +5,7 @@
* 2.0.
*/
import type { ChartModel, FormulaValueConfig } from '@kbn/lens-embeddable-utils';
import type { LensBaseLayer, LensConfig } from '@kbn/lens-embeddable-utils/config_builder';
import * as rt from 'io-ts';
export const ItemTypeRT = rt.keyof({
@ -386,7 +386,7 @@ export interface InventoryMetrics {
}
export interface InventoryMetricsWithDashboards<
TFormula extends Record<string, FormulaValueConfig>,
TFormula extends Record<string, LensBaseLayer>,
TDashboard extends Record<string, DashboardFn>
> extends InventoryMetrics {
getFormulas: () => Promise<TFormula>;
@ -419,11 +419,12 @@ export interface InventoryModel<TMetrics = InventoryMetrics> {
nodeFilter?: object[];
}
export type LensConfigWithId = LensConfig & { id: string };
export interface DashboardFn {
get: (...args: any[]) => DashboardModel;
}
export interface DashboardModel {
charts: ChartModel[];
charts: LensConfigWithId[];
dependsOn?: string[];
}

View file

@ -19940,7 +19940,6 @@
"xpack.infra.durationUnits.weeks.singular": "semaine",
"xpack.infra.durationUnits.years.plural": "années",
"xpack.infra.durationUnits.years.singular": "an",
"xpack.infra.errorOnLoadingLensDependencies": "Une erreur s'est produite lors de la tentative de chargement du plug-in Lens.",
"xpack.infra.errorPage.errorOccurredTitle": "Une erreur s'est produite",
"xpack.infra.errorPage.tryAgainButtonLabel": "Réessayer",
"xpack.infra.errorPage.tryAgainDescription ": "Cliquez sur le bouton Retour et réessayez.",
@ -43029,4 +43028,4 @@
"xpack.serverlessObservability.nav.projectSettings": "Paramètres de projet",
"xpack.serverlessObservability.nav.visualizations": "Visualisations"
}
}
}

View file

@ -19953,7 +19953,6 @@
"xpack.infra.durationUnits.weeks.singular": "週",
"xpack.infra.durationUnits.years.plural": "年",
"xpack.infra.durationUnits.years.singular": "年",
"xpack.infra.errorOnLoadingLensDependencies": "Lens Pluginを読み込む際にエラーが発生しました。",
"xpack.infra.errorPage.errorOccurredTitle": "エラーが発生しました",
"xpack.infra.errorPage.tryAgainButtonLabel": "再試行",
"xpack.infra.errorPage.tryAgainDescription ": "戻るボタンをクリックして再試行してください。",
@ -43021,4 +43020,4 @@
"xpack.serverlessObservability.nav.projectSettings": "プロジェクト設定",
"xpack.serverlessObservability.nav.visualizations": "ビジュアライゼーション"
}
}
}

View file

@ -20047,7 +20047,6 @@
"xpack.infra.durationUnits.weeks.singular": "周",
"xpack.infra.durationUnits.years.plural": "年",
"xpack.infra.durationUnits.years.singular": "年",
"xpack.infra.errorOnLoadingLensDependencies": "尝试加载 Lens 插件时出错。",
"xpack.infra.errorPage.errorOccurredTitle": "发生错误",
"xpack.infra.errorPage.tryAgainButtonLabel": "重试",
"xpack.infra.errorPage.tryAgainDescription ": "请点击后退按钮,然后重试。",
@ -43001,4 +43000,4 @@
"xpack.serverlessObservability.nav.projectSettings": "项目设置",
"xpack.serverlessObservability.nav.visualizations": "可视化"
}
}
}