Pyroscope: Fix template variable support (#84477)

This commit is contained in:
Andrej Ocenas 2024-03-18 14:25:47 +01:00 committed by GitHub
parent aac2cf0aa5
commit 5b085976bf
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 37 additions and 18 deletions

View File

@ -256,6 +256,10 @@ func (c *PyroscopeClient) LabelNames(ctx context.Context, labelSelector string,
return nil, fmt.Errorf("error sending LabelNames request %v", err) return nil, fmt.Errorf("error sending LabelNames request %v", err)
} }
if resp.Msg.Names == nil {
return []string{}, nil
}
var filtered []string var filtered []string
for _, label := range resp.Msg.Names { for _, label := range resp.Msg.Names {
if !isPrivateLabel(label) { if !isPrivateLabel(label) {
@ -281,6 +285,9 @@ func (c *PyroscopeClient) LabelValues(ctx context.Context, label string, labelSe
span.SetStatus(codes.Error, err.Error()) span.SetStatus(codes.Error, err.Error())
return nil, err return nil, err
} }
if resp.Msg.Names == nil {
return []string{}, nil
}
return resp.Msg.Names, nil return resp.Msg.Names, nil
} }

View File

@ -30,23 +30,16 @@ export function VariableQueryEditor(props: QueryEditorProps<PyroscopeDataSource,
onChange={(value) => { onChange={(value) => {
if (value.value! === 'profileType') { if (value.value! === 'profileType') {
props.onChange({ props.onChange({
...props.query,
type: value.value!, type: value.value!,
refId: props.query.refId,
}); });
} }
if (value.value! === 'label') { if (value.value! === 'label' || value.value! === 'labelValue') {
props.onChange({ props.onChange({
...props.query,
type: value.value!, type: value.value!,
profileTypeId: '', refId: props.query.refId,
}); // Make sure we keep already selected values if they make sense for the variable type
} profileTypeId: props.query.type !== 'profileType' ? props.query.profileTypeId : '',
if (value.value! === 'labelValue') {
props.onChange({
...props.query,
type: value.value!,
profileTypeId: '',
labelName: '',
}); });
} }
}} }}
@ -98,7 +91,13 @@ function LabelRow(props: {
const [labels, setLabels] = useState<string[]>(); const [labels, setLabels] = useState<string[]>();
useEffect(() => { useEffect(() => {
(async () => { (async () => {
setLabels(await props.datasource.getLabelNames((props.profileTypeId || '') + '{}', props.from, props.to)); setLabels(
await props.datasource.getLabelNames(
props.profileTypeId ? getProfileTypeLabel(props.profileTypeId) : '{}',
props.from,
props.to
)
);
})(); })();
}, [props.datasource, props.profileTypeId, props.to, props.from]); }, [props.datasource, props.profileTypeId, props.to, props.from]);
@ -156,3 +155,7 @@ function ProfileTypeRow(props: {
</InlineFieldRow> </InlineFieldRow>
); );
} }
export function getProfileTypeLabel(type: string) {
return `{__profile_type__="${type}"}`;
}

View File

@ -24,7 +24,11 @@ describe('VariableSupport', () => {
vs.query(getDefaultRequest({ type: 'label', profileTypeId: 'profile:type:3', refId: 'A' })) vs.query(getDefaultRequest({ type: 'label', profileTypeId: 'profile:type:3', refId: 'A' }))
); );
expect(resp.data).toEqual([{ text: 'foo' }, { text: 'bar' }, { text: 'baz' }]); expect(resp.data).toEqual([{ text: 'foo' }, { text: 'bar' }, { text: 'baz' }]);
expect(mock.getLabelNames).toBeCalledWith('profile:type:3{}', expect.any(Number), expect.any(Number)); expect(mock.getLabelNames).toBeCalledWith(
'{__profile_type__="profile:type:3"}',
expect.any(Number),
expect.any(Number)
);
}); });
it('should query label values', async function () { it('should query label values', async function () {
@ -34,7 +38,12 @@ describe('VariableSupport', () => {
vs.query(getDefaultRequest({ type: 'labelValue', labelName: 'foo', profileTypeId: 'profile:type:3', refId: 'A' })) vs.query(getDefaultRequest({ type: 'labelValue', labelName: 'foo', profileTypeId: 'profile:type:3', refId: 'A' }))
); );
expect(resp.data).toEqual([{ text: 'val1' }, { text: 'val2' }, { text: 'val3' }]); expect(resp.data).toEqual([{ text: 'val1' }, { text: 'val2' }, { text: 'val3' }]);
expect(mock.getLabelValues).toBeCalledWith('profile:type:3{}', 'foo', expect.any(Number), expect.any(Number)); expect(mock.getLabelValues).toBeCalledWith(
'{__profile_type__="profile:type:3"}',
'foo',
expect.any(Number),
expect.any(Number)
);
}); });
}); });

View File

@ -2,7 +2,7 @@ import { from, map, Observable, of } from 'rxjs';
import { CustomVariableSupport, DataQueryRequest, DataQueryResponse, MetricFindValue } from '@grafana/data'; import { CustomVariableSupport, DataQueryRequest, DataQueryResponse, MetricFindValue } from '@grafana/data';
import { VariableQueryEditor } from './VariableQueryEditor'; import { getProfileTypeLabel, VariableQueryEditor } from './VariableQueryEditor';
import { PyroscopeDataSource } from './datasource'; import { PyroscopeDataSource } from './datasource';
import { ProfileTypeMessage, VariableQuery } from './types'; import { ProfileTypeMessage, VariableQuery } from './types';
@ -34,7 +34,7 @@ export class VariableSupport extends CustomVariableSupport<PyroscopeDataSource>
} }
return from( return from(
this.dataAPI.getLabelNames( this.dataAPI.getLabelNames(
request.targets[0].profileTypeId + '{}', getProfileTypeLabel(request.targets[0].profileTypeId),
request.range.from.valueOf(), request.range.from.valueOf(),
request.range.to.valueOf() request.range.to.valueOf()
) )
@ -51,7 +51,7 @@ export class VariableSupport extends CustomVariableSupport<PyroscopeDataSource>
} }
return from( return from(
this.dataAPI.getLabelValues( this.dataAPI.getLabelValues(
request.targets[0].profileTypeId + '{}', getProfileTypeLabel(request.targets[0].profileTypeId),
request.targets[0].labelName, request.targets[0].labelName,
request.range.from.valueOf(), request.range.from.valueOf(),
request.range.to.valueOf() request.range.to.valueOf()