[Synthetics] Add availability sparklines on summary page (#135292)

This commit is contained in:
Shahzad 2022-07-25 19:17:13 +02:00 committed by GitHub
parent af2557b31a
commit b127231787
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
6 changed files with 113 additions and 11 deletions

View file

@ -29,10 +29,11 @@ import {
TypedLensByValueInput,
XYCurveType,
XYState,
FormulaPublicApi,
YAxisMode,
MinIndexPatternColumn,
MaxIndexPatternColumn,
FormulaPublicApi,
FormulaIndexPatternColumn,
} from '@kbn/lens-plugin/public';
import type { DataView } from '@kbn/data-views-plugin/common';
import { PersistableFilter } from '@kbn/lens-plugin/common';
@ -47,6 +48,7 @@ import {
PERCENTILE,
PERCENTILE_RANKS,
ReportTypes,
FORMULA_COLUMN,
} from './constants';
import {
ColumnFilter,
@ -403,10 +405,11 @@ export class LensAttributes {
layerConfig: LayerConfig,
layerId: string,
columnFilter?: string
): Record<string, FieldBasedIndexPatternColumn> {
): Record<string, FieldBasedIndexPatternColumn | FormulaIndexPatternColumn> {
const yAxisColumns = layerConfig.seriesConfig.yAxisColumns;
const { sourceField: mainSourceField, label: mainLabel } = yAxisColumns[0];
const lensColumns: Record<string, FieldBasedIndexPatternColumn> = {};
const lensColumns: Record<string, FieldBasedIndexPatternColumn | FormulaIndexPatternColumn> =
{};
// start at 1, because main y axis will have the first percentile breakdown
for (let i = 1; i < PERCENTILE_RANKS.length; i++) {
@ -522,6 +525,7 @@ export class LensAttributes {
}) {
const { breakdown, seriesConfig } = layerConfig;
const {
formula,
fieldMeta,
columnType,
fieldName,
@ -531,6 +535,16 @@ export class LensAttributes {
showPercentileAnnotations,
} = this.getFieldMeta(sourceField, layerConfig);
if (columnType === FORMULA_COLUMN) {
return getDistributionInPercentageColumn({
layerId,
formula,
label: columnLabel ?? label,
dataView: layerConfig.indexPattern,
lensFormulaHelper: this.lensFormulaHelper!,
}).main;
}
if (showPercentileAnnotations) {
this.addThresholdLayer(fieldName, layerId, layerConfig);
}
@ -607,9 +621,11 @@ export class LensAttributes {
timeScale,
paramFilters,
showPercentileAnnotations,
formula,
} = parseCustomFieldName(layerConfig.seriesConfig, layerConfig.selectedMetricField);
const fieldMeta = layerConfig.indexPattern.getFieldByName(fieldName!);
return {
formula,
palette,
fieldMeta,
fieldName,
@ -666,7 +682,10 @@ export class LensAttributes {
forAccessorsKeys?: boolean
) {
const { breakdown } = layerConfig;
const lensColumns: Record<string, FieldBasedIndexPatternColumn | SumIndexPatternColumn> = {};
const lensColumns: Record<
string,
FieldBasedIndexPatternColumn | SumIndexPatternColumn | FormulaIndexPatternColumn
> = {};
const yAxisColumns = layerConfig.seriesConfig.yAxisColumns;
const { sourceField: mainSourceField, label: mainLabel } = yAxisColumns[0];
@ -680,6 +699,20 @@ export class LensAttributes {
}).supportingColumns;
}
if (mainSourceField && !forAccessorsKeys) {
const { columnLabel, formula, columnType } = this.getFieldMeta(mainSourceField, layerConfig);
if (columnType === FORMULA_COLUMN) {
return getDistributionInPercentageColumn({
label: columnLabel,
layerId,
formula,
dataView: layerConfig.indexPattern,
lensFormulaHelper: this.lensFormulaHelper!,
}).supportingColumns;
}
}
if (yAxisColumns.length === 1 && breakdown === PERCENTILE) {
return this.getPercentileBreakdowns(layerConfig, layerId, columnFilter);
}

View file

@ -4,7 +4,7 @@
* 2.0; you may not use this file except in compliance with the Elastic License
* 2.0.
*/
import { FormulaPublicApi } from '@kbn/lens-plugin/public';
import { FormulaIndexPatternColumn, FormulaPublicApi } from '@kbn/lens-plugin/public';
import type { DataView } from '@kbn/data-views-plugin/common';
export function getDistributionInPercentageColumn({
@ -13,19 +13,22 @@ export function getDistributionInPercentageColumn({
dataView,
columnFilter,
lensFormulaHelper,
formula,
}: {
label?: string;
columnFilter?: string;
layerId: string;
lensFormulaHelper: FormulaPublicApi;
dataView: DataView;
formula?: string;
}) {
const yAxisColId = `y-axis-column-${layerId}`;
let lensFormula = 'count() / overall_sum(count())';
let lensFormula = formula ?? 'count() / overall_sum(count())';
if (columnFilter) {
lensFormula = `count(kql='${columnFilter}') / overall_sum(count(kql='${columnFilter}'))`;
lensFormula =
formula ?? `count(kql='${columnFilter}') / overall_sum(count(kql='${columnFilter}'))`;
}
const { columns } = lensFormulaHelper?.insertOrReplaceFormulaColumn(
@ -49,5 +52,5 @@ export function getDistributionInPercentageColumn({
const { [yAxisColId]: main, ...supportingColumns } = columns;
return { main: columns[yAxisColId], supportingColumns };
return { main: columns[yAxisColId] as FormulaIndexPatternColumn, supportingColumns };
}

View file

@ -12,6 +12,7 @@ import {
REPORT_METRIC_FIELD,
PERCENTILE,
ReportTypes,
FORMULA_COLUMN,
} from '../constants';
import {
CLS_LABEL,
@ -86,6 +87,12 @@ export function getSyntheticsKPIConfig({ dataView }: ConfigProps): SeriesConfig
id: MONITOR_DURATION_US,
columnType: OPERATION_COLUMN,
},
{
label: 'Monitor availability',
id: 'monitor_availability',
columnType: FORMULA_COLUMN,
formula: "1- (count(kql='summary.down > 0') / count())",
},
{
field: SUMMARY_UP,
id: SUMMARY_UP,

View file

@ -42,6 +42,7 @@ export interface ExploratoryEmbeddableProps {
isSingleMetric?: boolean;
legendIsVisible?: boolean;
legendPosition?: Position;
hideTicks?: boolean;
onBrushEnd?: (param: { range: number[] }) => void;
caseOwner?: string;
reportConfigMap?: ReportConfigMap;
@ -83,6 +84,7 @@ export default function Embeddable({
withActions = true,
lensFormulaHelper,
align,
hideTicks,
}: ExploratoryEmbeddableComponentProps) {
const LensComponent = lens?.EmbeddableComponent;
const LensSaveModalComponent = lens?.SaveModalComponent;
@ -127,6 +129,14 @@ export default function Embeddable({
(attributesJSON.state.visualization as XYState).legend.position = legendPosition;
}
if (hideTicks) {
(attributesJSON.state.visualization as XYState).tickLabelsVisibilitySettings = {
x: false,
yRight: false,
yLeft: false,
};
}
const actions = useActions({
withActions,
attributes,

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 React from 'react';
import { useKibana } from '@kbn/kibana-react-plugin/public';
import { ReportTypes, useTheme } from '@kbn/observability-plugin/public';
import { useParams } from 'react-router-dom';
import { ClientPluginsStart } from '../../../../../plugin';
export const AvailabilitySparklines = () => {
const {
services: {
observability: { ExploratoryViewEmbeddable },
},
} = useKibana<ClientPluginsStart>();
const { monitorId } = useParams<{ monitorId: string }>();
const theme = useTheme();
return (
<>
<ExploratoryViewEmbeddable
reportType={ReportTypes.KPI}
axisTitlesVisibility={{ x: false, yRight: false, yLeft: false }}
legendIsVisible={false}
hideTicks={true}
attributes={[
{
seriesType: 'area',
time: { from: 'now-15m/m', to: 'now' },
name: 'Monitor availability',
dataType: 'synthetics',
selectedMetricField: 'monitor_availability',
reportDefinitions: { 'monitor.id': [monitorId] },
color: theme.eui.euiColorVis1,
},
]}
/>
</>
);
};

View file

@ -13,6 +13,7 @@ import { MonitorDurationTrend } from './duration_trend';
import { StepDurationPanel } from './step_duration_panel';
import { AvailabilityPanel } from './availability_panel';
import { MonitorDetailsPanel } from './monitor_details_panel';
import { AvailabilitySparklines } from './availability_sparklines';
export const SummaryTabContent = () => {
return (
@ -27,17 +28,20 @@ export const SummaryTabContent = () => {
</EuiPanel>
</EuiFlexItem>
<EuiFlexItem grow={2}>
<EuiPanel style={{ paddingBottom: 0 }}>
<EuiPanel style={{ paddingBottom: 0, height: 150 }}>
<EuiTitle size="xs">
<h3>{LAST_30DAYS_LABEL}</h3>
</EuiTitle>
<EuiFlexGroup>
<EuiFlexGroup gutterSize="none">
<EuiFlexItem>
<AvailabilityPanel />
</EuiFlexItem>
<EuiFlexItem>{/* TODO: Add availability sparkline*/}</EuiFlexItem>
<EuiFlexItem>
<AvailabilitySparklines />
</EuiFlexItem>
<EuiFlexItem>{/* TODO: Add duration metric*/}</EuiFlexItem>
<EuiFlexItem>{/* TODO: Add duration metric sparkline*/}</EuiFlexItem>
<EuiFlexItem>{/* TODO: Add error metric and sparkline*/}</EuiFlexItem>
</EuiFlexGroup>
</EuiPanel>
<EuiSpacer size="s" />