Skip to content

Commit

Permalink
[Infrastructure UI] Lens Embeddable attributes builder refactor (#161281
Browse files Browse the repository at this point in the history
)

relates to [#160381](#160381)
closes [#161432](#161432)

## Summary

This pull request aims to enhance the usage of Lens Embeddable by
introducing abstractions that simplify the creation of the necessary
data structures for rendering charts. The goal is to improve the DX by
providing clearer and more intuitive interfaces.

More details in the
[README.md](https://github.com/elastic/kibana/blob/62a9ef70e6bbbb6798bd78083dac097d84b85ec5/x-pack/plugins/infra/public/common/visualizations/lens/README.md)

### For reviewers

- The majority of the changes are concentrated in the
`common/visualizations` directory. The `formulas/host` files have been
modified to only contain the formula itself. The formulas are now
designed to be independent of specific chart styles.

- The `use_lens_attributes` hook has been modified to receive the
essential information. Previously, it had knowledge of host formulas,
but now it accepts an abstracted chart representation and returns the
JSON object accordingly.

- Chart-specific style configurations have been moved to the chart usage
component in the `tile` and `metric_chart` components.


### How to test 

- Start a local Kibana instance
- Navigate to `Infrastructure` > `Hosts`
- Check all charts and navigate to Lens.

---------

Co-authored-by: kibanamachine <[email protected]>
  • Loading branch information
crespocarlos and kibanamachine authored Jul 10, 2023
1 parent 9f2a75b commit 4baeafe
Show file tree
Hide file tree
Showing 46 changed files with 1,731 additions and 855 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@ import {
tx,
hostCount,
} from './lens/formulas/host';
import { LineChart, MetricChart } from './lens/visualization_types';

export const hostLensFormulas = {
cpuUsage,
Expand All @@ -38,9 +37,4 @@ export const hostLensFormulas = {
tx,
};

export const visualizationTypes = {
lineChart: LineChart,
metricChart: MetricChart,
};

export const HOST_METRICS_DOC_HREF = 'https://ela.st/docs-infra-host-metrics';
12 changes: 6 additions & 6 deletions x-pack/plugins/infra/public/common/visualizations/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,16 +7,16 @@

export type {
HostsLensFormulas,
LineChartOptions,
LensChartConfig,
LensLineChartConfig,
MetricChartOptions,
HostsLensMetricChartFormulas,
HostsLensLineChartFormulas,
LensOptions,
LensAttributes,
FormulaConfig,
Chart,
LensVisualizationState,
} from './types';

export { hostLensFormulas, visualizationTypes } from './constants';
export { hostLensFormulas } from './constants';

export * from './lens/visualization_types';

export { LensAttributesBuilder } from './lens/lens_attributes_builder';
166 changes: 166 additions & 0 deletions x-pack/plugins/infra/public/common/visualizations/lens/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,166 @@

# Lens Attributes Builder

The Lens Attributes Builder is a utility for creating JSON objects used to render charts with Lens. It simplifies the process of configuring and building the necessary attributes for different chart types.

## Usage

### Creating a Metric Chart

To create a metric chart, use the `MetricChart` class and provide the required configuration. Here's an example:

```ts
const metricChart = new MetricChart({
layers: new MetricLayer({
data: {
label: 'Disk Read Throughput',
value: "counter_rate(max(system.diskio.read.count), kql='system.diskio.read.count: *')",
format: {
id: 'bytes',
params: {
decimals: 1,
},
},
},
formulaAPI,
}),
dataView,
});
```

### Creating an XY Chart

To create an XY chart, use the `XYChart` class and provide the required configuration. Here's an example:

```ts
const xyChart = new XYChart({
layers: [new XYDataLayer({
data: [{
label: 'Normalized Load',
value: "average(system.load.1) / max(system.load.cores)",
format: {
id: 'percent',
params: {
decimals: 1,
},
},
}],
formulaAPI,
})],
dataView,
});
```

### Adding Multiple Layers to an XY Chart

An XY chart can have multiple layers. Here's an example of containing a Reference Line Layer:

```ts
const xyChart = new XYChart({
layers: [
new XYDataLayer({
data: [{
label: 'Disk Read Throughput',
value: "average(system.load.1) / max(system.load.cores)",
format: {
id: 'percent',
params: {
decimals: 1,
},
},
}],
formulaAPI,
}),
new XYReferenceLineLayer({
data: [{
value: "1",
format: {
id: 'percent',
params: {
decimals: 1,
},
},
}],
}),
],
dataView,
});
```

### Adding Multiple Data Sources in the Same Layer

In an XY chart, it's possible to define multiple data sources within the same layer.

To configure multiple data sources in an XY data layer, simply provide an array of data to the same YXDataLayer class:

```ts
const xyChart = new XYChart({
layers: new YXDataLayer({
data: [{
label: 'RX',
value: "average(host.network.ingress.bytes) * 8 / (max(metricset.period, kql='host.network.ingress.bytes: *') / 1000)",
format: {
id: 'bits',
params: {
decimals: 1,
},
},
},{
label: 'TX',
value: "(average(host.network.egresss.bytes) * 8 / (max(metricset.period, kql='host.network.egresss.bytes: *') / 1000)",
format: {
id: 'bits',
params: {
decimals: 1,
},
},
}],
formulaAPI,
}),
dataView,
});
```

### Building Lens Chart Attributes

The `LensAttributesBuilder` is responsible for creating the full JSON object that combines the attributes returned by the chart classes. Here's an example:

```ts
const builder = new LensAttributesBuilder({ visualization: xyChart });
const attributes = builder.build();
```

The `attributes` object contains the final JSON representation of the chart configuration and can be used to render the chart with Lens.

### Usage with Lens EmbeddableComponent

To display the charts rendered with the Lens Attributes Builder, it's recommended to use the Lens `EmbeddableComponent`. The `EmbeddableComponent` abstracts some of the chart styling and other details that would be challenging to handle directly with the Lens Attributes Builder.

```tsx
const builder = new LensAttributesBuilder({
visualization: new MetricChart({
layers: new MetricLayer({
data: {
label: 'Disk Read Throughput',
value: "counter_rate(max(system.diskio.read.count), kql='system.diskio.read.count: *')",
format: {
id: 'bytes',
params: {
decimals: 1,
},
},
},
formulaAPI,
}),
dataView,
})
});

const lensAttributes = builder.build();

<EmbeddableComponent
attributes={lensAttributes}
viewMode={ViewMode.VIEW}
...
/>
```
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
/*
* 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 { TypedLensByValueInput } from '@kbn/lens-plugin/public';
import { i18n } from '@kbn/i18n';
import { Layer } from '../../../../../hooks/use_lens_attributes';
import { hostLensFormulas } from '../../../constants';
import { FormulaConfig } from '../../../types';
import { TOOLTIP } from './translations';
import { MetricLayerOptions } from '../../visualization_types/layers';

export interface KPIChartProps
extends Pick<TypedLensByValueInput, 'id' | 'title' | 'overrides' | 'style'> {
layers: Layer<MetricLayerOptions, FormulaConfig, 'data'>;
toolTip: string;
}

export const KPI_CHARTS: KPIChartProps[] = [
{
id: 'cpuUsage',
title: i18n.translate('xpack.infra.hostsViewPage.metricTrend.cpuUsage.title', {
defaultMessage: 'CPU Usage',
}),
layers: {
data: {
...hostLensFormulas.cpuUsage,
format: {
...hostLensFormulas.cpuUsage.format,
params: {
decimals: 1,
},
},
},
layerType: 'data',
options: {
backgroundColor: '#F1D86F',
showTrendLine: true,
},
},
toolTip: TOOLTIP.cpuUsage,
},
{
id: 'normalizedLoad1m',
title: i18n.translate('xpack.infra.hostsViewPage.metricTrend.normalizedLoad1m.title', {
defaultMessage: 'CPU Usage',
}),
layers: {
data: {
...hostLensFormulas.normalizedLoad1m,
format: {
...hostLensFormulas.normalizedLoad1m.format,
params: {
decimals: 1,
},
},
},
layerType: 'data',
options: {
backgroundColor: '#79AAD9',
showTrendLine: true,
},
},
toolTip: TOOLTIP.normalizedLoad1m,
},
{
id: 'memoryUsage',
title: i18n.translate('xpack.infra.hostsViewPage.metricTrend.memoryUsage.title', {
defaultMessage: 'CPU Usage',
}),
layers: {
data: {
...hostLensFormulas.memoryUsage,
format: {
...hostLensFormulas.memoryUsage.format,
params: {
decimals: 1,
},
},
},
layerType: 'data',
options: {
backgroundColor: '#A987D1',
showTrendLine: true,
},
},
toolTip: TOOLTIP.memoryUsage,
},
{
id: 'diskSpaceUsage',
title: i18n.translate('xpack.infra.hostsViewPage.metricTrend.diskSpaceUsage.title', {
defaultMessage: 'CPU Usage',
}),
layers: {
data: {
...hostLensFormulas.diskSpaceUsage,
format: {
...hostLensFormulas.diskSpaceUsage.format,
params: {
decimals: 1,
},
},
},
layerType: 'data',
options: {
backgroundColor: '#F5A35C',
showTrendLine: true,
},
},
toolTip: TOOLTIP.diskSpaceUsage,
},
];
Original file line number Diff line number Diff line change
Expand Up @@ -5,32 +5,15 @@
* 2.0.
*/

import type { LensChartConfig, LensLineChartConfig } from '../../../types';
import { getFilters } from './utils';
import type { FormulaConfig } from '../../../types';

export const cpuLineChart: LensLineChartConfig = {
extraVisualizationState: {
yLeftExtent: {
mode: 'custom',
lowerBound: 0,
upperBound: 1,
export const cpuUsage: FormulaConfig = {
label: 'CPU Usage',
value: '(average(system.cpu.user.pct) + average(system.cpu.system.pct)) / max(system.cpu.cores)',
format: {
id: 'percent',
params: {
decimals: 0,
},
},
};

export const cpuUsage: LensChartConfig = {
title: 'CPU Usage',
formula: {
formula:
'(average(system.cpu.user.pct) + average(system.cpu.system.pct)) / max(system.cpu.cores)',
format: {
id: 'percent',
params: {
decimals: 0,
},
},
},
getFilters,

lineChartConfig: cpuLineChart,
};
Original file line number Diff line number Diff line change
Expand Up @@ -5,19 +5,15 @@
* 2.0.
*/

import type { LensChartConfig } from '../../../types';
import { getFilters } from './utils';
import type { FormulaConfig } from '../../../types';

export const diskIORead: LensChartConfig = {
title: 'Disk Read IOPS',
formula: {
formula: "counter_rate(max(system.diskio.read.count), kql='system.diskio.read.count: *')",
format: {
id: 'number',
params: {
decimals: 0,
},
export const diskIORead: FormulaConfig = {
label: 'Disk Read IOPS',
value: "counter_rate(max(system.diskio.read.count), kql='system.diskio.read.count: *')",
format: {
id: 'number',
params: {
decimals: 0,
},
},
getFilters,
};
Loading

0 comments on commit 4baeafe

Please sign in to comment.