Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Prometheus: Fix exemplar fill color to match series color in time series. #59908

Merged
merged 40 commits into from Dec 8, 2022
Merged
Show file tree
Hide file tree
Changes from 34 commits
Commits
Show all changes
40 commits
Select commit Hold shift + click to select a range
f0213a7
PoC: Working exemplar filtering when series are toggled in legend UI
gtk-grafana Dec 2, 2022
f589afc
remove console.logs
gtk-grafana Dec 2, 2022
9ab0aff
fix bug in which single series exemplar graphs wouldn't display exemp…
gtk-grafana Dec 5, 2022
3bc429c
remove console.log
gtk-grafana Dec 5, 2022
5926f6d
fix edge cases breaking exemplar filtering
gtk-grafana Dec 5, 2022
6fed0cc
fix off by one bug
gtk-grafana Dec 5, 2022
daaea0d
fix bug in feature when multiple series are selected in legend, exemp…
gtk-grafana Dec 6, 2022
4edb81e
add exemplar color coding
gtk-grafana Dec 6, 2022
165b956
refactor
gtk-grafana Dec 6, 2022
c710bd3
Prepping for merge of base branch
gtk-grafana Dec 6, 2022
ca7102f
clean up comments after merge
gtk-grafana Dec 6, 2022
c523333
refactor and clean up
gtk-grafana Dec 6, 2022
57321ee
fix bug in exemplar filtering letting through exemplars that matched …
gtk-grafana Dec 6, 2022
3586031
merge bugfix from parent branch
gtk-grafana Dec 6, 2022
2c59d85
fix bugs introduced by merge conflicts
gtk-grafana Dec 6, 2022
9da3f00
remove unused function
gtk-grafana Dec 7, 2022
e5dfa27
update changelog
gtk-grafana Dec 7, 2022
69c185a
Merge remote-tracking branch 'origin/main' into gtk-grafana/issues/59…
gtk-grafana Dec 7, 2022
b76e814
Merge branch 'gtk-grafana/issues/59678/exemplars-not-filtering-from-l…
gtk-grafana Dec 7, 2022
ad37e17
Merge remote-tracking branch 'origin/main' into gtk-grafana/issues/59…
gtk-grafana Dec 7, 2022
a54be2c
Update CHANGELOG.md
gtk-grafana Dec 7, 2022
08b5570
make property optional, set default behavior
gtk-grafana Dec 7, 2022
cac009b
update comment
gtk-grafana Dec 7, 2022
df71569
remove uncalled function
gtk-grafana Dec 7, 2022
099d2bf
add unit test for getVisibleLabels
gtk-grafana Dec 7, 2022
a32b173
clean up test
gtk-grafana Dec 7, 2022
d00be4c
remove console.log
gtk-grafana Dec 7, 2022
95142b9
merge parent and resolve conflicts
gtk-grafana Dec 7, 2022
7a716ea
fix unit test
gtk-grafana Dec 7, 2022
39f7425
update unit test
gtk-grafana Dec 7, 2022
ce9a09c
merge parent branch and resolve conflicts
gtk-grafana Dec 7, 2022
56075c9
Merge remote-tracking branch 'origin/main' into gtk-grafana/issues/59…
gtk-grafana Dec 7, 2022
0c7617f
Merge branch 'gtk-grafana/issues/59678/exemplars-not-filtering-from-l…
gtk-grafana Dec 7, 2022
d1416df
changelog update
gtk-grafana Dec 7, 2022
e88971c
revert manual changelog
gtk-grafana Dec 8, 2022
e756a7c
Merge remote-tracking branch 'origin/main' into gtk-grafana/issues/59…
gtk-grafana Dec 8, 2022
6fa0b10
merge parent branch and remove changelog
gtk-grafana Dec 8, 2022
ed20def
Merge remote-tracking branch 'origin/main' into gtk-grafana/issues/59…
gtk-grafana Dec 8, 2022
47e1845
Merge remote-tracking branch 'origin/main' into gtk-grafana/issues/59…
gtk-grafana Dec 8, 2022
dd6fc27
rewrite inefficient forEach
gtk-grafana Dec 8, 2022
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
10 changes: 10 additions & 0 deletions CHANGELOG.md
@@ -1,3 +1,13 @@
<!-- 9.3.2 START -->

# 9.3.2 (2022-12-13)

### Bug fixes

- **Prometheus:** Fix exemplars not respecting corresponding series display status. [#59678](https://github.com/grafana/grafana/issues/59678), [@gtk-grafana](https://github.com/gtk-grafana)
- **Prometheus:** Match exemplar fill color with series color in time series. [#59908](https://github.com/grafana/grafana/issues/59499), [@gtk-grafana](https://github.com/gtk-grafana)

<!-- 9.3.2 END -->
<!-- 9.3.1 START -->

# 9.3.1 (2022-11-30)
Expand Down
Expand Up @@ -39,7 +39,7 @@ type PrepData = (frames: DataFrame[]) => AlignedData | FacetedData;
type PreDataStacked = (frames: DataFrame[], stackingGroups: StackingGroup[]) => AlignedData | FacetedData;

export class UPlotConfigBuilder {
private series: UPlotSeriesBuilder[] = [];
series: UPlotSeriesBuilder[] = [];
private axes: Record<string, UPlotAxisBuilder> = {};
private scales: UPlotScaleBuilder[] = [];
private bands: Band[] = [];
Expand Down
6 changes: 3 additions & 3 deletions public/app/plugins/panel/candlestick/CandlestickPanel.tsx
Expand Up @@ -4,10 +4,10 @@
import React, { useMemo } from 'react';
import uPlot from 'uplot';

import { Field, getDisplayProcessor, PanelProps, getLinksSupplier } from '@grafana/data';
import { Field, getDisplayProcessor, getLinksSupplier, PanelProps } from '@grafana/data';
import { PanelDataErrorView } from '@grafana/runtime';
import { TooltipDisplayMode } from '@grafana/schema';
import { usePanelContext, TimeSeries, TooltipPlugin, ZoomPlugin, UPlotConfigBuilder, useTheme2 } from '@grafana/ui';
import { TimeSeries, TooltipPlugin, UPlotConfigBuilder, usePanelContext, useTheme2, ZoomPlugin } from '@grafana/ui';
import { AxisProps } from '@grafana/ui/src/components/uPlot/config/UPlotAxisBuilder';
import { ScaleProps } from '@grafana/ui/src/components/uPlot/config/UPlotScaleBuilder';
import { config } from 'app/core/config';
Expand All @@ -21,7 +21,7 @@ import { OutsideRangePlugin } from '../timeseries/plugins/OutsideRangePlugin';
import { ThresholdControlsPlugin } from '../timeseries/plugins/ThresholdControlsPlugin';

import { prepareCandlestickFields } from './fields';
import { defaultColors, CandlestickOptions, VizDisplayMode } from './models.gen';
import { CandlestickOptions, defaultColors, VizDisplayMode } from './models.gen';
import { drawMarkers, FieldIndices } from './utils';

interface CandlestickPanelProps extends PanelProps<CandlestickOptions> {}
Expand Down
5 changes: 3 additions & 2 deletions public/app/plugins/panel/timeseries/TimeSeriesPanel.tsx
Expand Up @@ -3,14 +3,14 @@ import React, { useMemo } from 'react';
import { Field, PanelProps } from '@grafana/data';
import { PanelDataErrorView } from '@grafana/runtime';
import { TooltipDisplayMode } from '@grafana/schema';
import { usePanelContext, TimeSeries, TooltipPlugin, ZoomPlugin, KeyboardPlugin } from '@grafana/ui';
import { KeyboardPlugin, TimeSeries, TooltipPlugin, usePanelContext, ZoomPlugin } from '@grafana/ui';
import { config } from 'app/core/config';
import { getFieldLinksForExplore } from 'app/features/explore/utils/links';

import { AnnotationEditorPlugin } from './plugins/AnnotationEditorPlugin';
import { AnnotationsPlugin } from './plugins/AnnotationsPlugin';
import { ContextMenuPlugin } from './plugins/ContextMenuPlugin';
import { ExemplarsPlugin } from './plugins/ExemplarsPlugin';
import { ExemplarsPlugin, getVisibleLabels } from './plugins/ExemplarsPlugin';
import { OutsideRangePlugin } from './plugins/OutsideRangePlugin';
import { ThresholdControlsPlugin } from './plugins/ThresholdControlsPlugin';
import { TimeSeriesOptions } from './types';
Expand Down Expand Up @@ -133,6 +133,7 @@ export const TimeSeriesPanel: React.FC<TimeSeriesPanelProps> = ({
)}
{data.annotations && (
<ExemplarsPlugin
visibleSeries={getVisibleLabels(config, frames)}
config={config}
exemplars={data.annotations}
timeZone={timeZone}
Expand Down
24 changes: 20 additions & 4 deletions public/app/plugins/panel/timeseries/plugins/ExemplarMarker.tsx
Expand Up @@ -22,6 +22,7 @@ interface ExemplarMarkerProps {
dataFrameFieldIndex: DataFrameFieldIndex;
config: UPlotConfigBuilder;
getFieldLinks: (field: Field, rowIndex: number) => Array<LinkModel<Field>>;
exemplarColor?: string;
}

export const ExemplarMarker: React.FC<ExemplarMarkerProps> = ({
Expand All @@ -30,6 +31,7 @@ export const ExemplarMarker: React.FC<ExemplarMarkerProps> = ({
dataFrameFieldIndex,
config,
getFieldLinks,
exemplarColor,
}) => {
const styles = useStyles2(getExemplarMarkerStyles);
const [isOpen, setIsOpen] = useState(false);
Expand All @@ -40,19 +42,33 @@ export const ExemplarMarker: React.FC<ExemplarMarkerProps> = ({

const getSymbol = () => {
const symbols = [
<rect key="diamond" x="3.38672" width="4.78985" height="4.78985" transform="rotate(45 3.38672 0)" />,
<rect
fill={exemplarColor}
key="diamond"
x="3.38672"
width="4.78985"
height="4.78985"
transform="rotate(45 3.38672 0)"
/>,
<path
fill={exemplarColor}
key="x"
d="M1.94444 3.49988L0 5.44432L1.55552 6.99984L3.49996 5.05539L5.4444 6.99983L6.99992 5.44431L5.05548 3.49988L6.99983 1.55552L5.44431 0L3.49996 1.94436L1.5556 0L8.42584e-05 1.55552L1.94444 3.49988Z"
/>,
<path key="triangle" d="M4 0L7.4641 6H0.535898L4 0Z" />,
<rect key="rectangle" width="5" height="5" />,
<path key="pentagon" d="M3 0.5L5.85317 2.57295L4.76336 5.92705H1.23664L0.146831 2.57295L3 0.5Z" />,
<path fill={exemplarColor} key="triangle" d="M4 0L7.4641 6H0.535898L4 0Z" />,
<rect fill={exemplarColor} key="rectangle" width="5" height="5" />,
<path
fill={exemplarColor}
key="pentagon"
d="M3 0.5L5.85317 2.57295L4.76336 5.92705H1.23664L0.146831 2.57295L3 0.5Z"
/>,
<path
fill={exemplarColor}
key="plus"
d="m2.35672,4.2425l0,2.357l1.88558,0l0,-2.357l2.3572,0l0,-1.88558l-2.3572,0l0,-2.35692l-1.88558,0l0,2.35692l-2.35672,0l0,1.88558l2.35672,0z"
/>,
];

return symbols[dataFrameFieldIndex.frameIndex % symbols.length];
};

Expand Down
110 changes: 110 additions & 0 deletions public/app/plugins/panel/timeseries/plugins/ExemplarsPlugin.test.tsx
@@ -0,0 +1,110 @@
import { MutableDataFrame, Field } from '@grafana/data/src';
import { UPlotConfigBuilder } from '@grafana/ui/src';

import { getVisibleLabels, VisibleExemplarLabels } from './ExemplarsPlugin';

describe('getVisibleLabels()', () => {
const dataFrameSeries1 = new MutableDataFrame({
name: 'tns/app',
fields: [
{
name: 'Time',
values: [1670418750000, 1670418765000, 1670418780000, 1670418795000],
entities: {},
},
{
name: 'Value',
labels: {
job: 'tns/app',
},
values: [0.018963114754098367, 0.019140624999999974, 0.019718309859154928, 0.020064189189189167],
},
] as unknown as Field[],
length: 4,
});
const dataFrameSeries2 = new MutableDataFrame({
name: 'tns/db',
fields: [
{
name: 'Time',
values: [1670418750000, 1670418765000, 1670418780000, 1670418795000],
entities: {},
},
{
name: 'Value',
labels: {
job: 'tns/db',
},
values: [0.028963114754098367, 0.029140624999999974, 0.029718309859154928, 0.030064189189189167],
},
] as unknown as Field[],
length: 4,
});
const dataFrameSeries3 = new MutableDataFrame({
name: 'tns/loadgen',
fields: [
{
name: 'Time',
values: [1670418750000, 1670418765000, 1670418780000, 1670418795000],
entities: {},
},
{
name: 'Value',
labels: {
job: 'tns/loadgen',
},
values: [0.028963114754098367, 0.029140624999999974, 0.029718309859154928, 0.030064189189189167],
},
] as unknown as Field[],
length: 4,
});
const frames = [dataFrameSeries1, dataFrameSeries2, dataFrameSeries3];
const config: UPlotConfigBuilder = {
addHook: (type, hook) => {},
series: [
{
props: {
dataFrameFieldIndex: { frameIndex: 0, fieldIndex: 1 },
show: true,
},
},
{
props: {
dataFrameFieldIndex: { frameIndex: 1, fieldIndex: 1 },
show: true,
},
},
{
props: {
dataFrameFieldIndex: { frameIndex: 2, fieldIndex: 1 },
show: false,
},
},
],
} as UPlotConfigBuilder;

it('function should only return labels associated with actively visible series', () => {
const expected: VisibleExemplarLabels = {
totalSeriesCount: 3,
labels: [
{
color: '',
labels: {
job: 'tns/app',
},
},
{
color: '',
labels: {
job: 'tns/db',
},
},
],
};

// Base case
expect(getVisibleLabels(config, [])).toEqual({ totalSeriesCount: 3, labels: [] });

expect(getVisibleLabels(config, frames)).toEqual(expected);
});
});