mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
Loki: Add optional stream selector to fetchLabelValues API (#77207)
* Loki: Add optional stream selector to fetchLabelValues API * Update public/app/plugins/datasource/loki/docs/app_plugin_developer_documentation.md Co-authored-by: Sven Grossmann <sven.grossmann@grafana.com> * Update tests --------- Co-authored-by: Sven Grossmann <sven.grossmann@grafana.com>
This commit is contained in:
parent
dae49fbb34
commit
f5d04a067e
@ -233,7 +233,23 @@ describe('Language completion provider', () => {
|
||||
const provider = await getLanguageProvider(datasource);
|
||||
const requestSpy = jest.spyOn(provider, 'request');
|
||||
const labelValues = await provider.fetchLabelValues('testkey');
|
||||
expect(requestSpy).toHaveBeenCalled();
|
||||
expect(requestSpy).toHaveBeenCalledWith('label/testkey/values', {
|
||||
end: 1560163909000,
|
||||
start: 1560153109000,
|
||||
});
|
||||
expect(labelValues).toEqual(['label1_val1', 'label1_val2']);
|
||||
});
|
||||
|
||||
it('fetch label when options.streamSelector provided and values is not cached', async () => {
|
||||
const datasource = setup({ testkey: ['label1_val1', 'label1_val2'], label2: [] });
|
||||
const provider = await getLanguageProvider(datasource);
|
||||
const requestSpy = jest.spyOn(provider, 'request');
|
||||
const labelValues = await provider.fetchLabelValues('testkey', { streamSelector: '{foo="bar"}' });
|
||||
expect(requestSpy).toHaveBeenCalledWith('label/testkey/values', {
|
||||
end: 1560163909000,
|
||||
query: '%7Bfoo%3D%22bar%22%7D',
|
||||
start: 1560153109000,
|
||||
});
|
||||
expect(labelValues).toEqual(['label1_val1', 'label1_val2']);
|
||||
});
|
||||
|
||||
@ -247,6 +263,28 @@ describe('Language completion provider', () => {
|
||||
|
||||
const nextLabelValues = await provider.fetchLabelValues('testkey');
|
||||
expect(requestSpy).toHaveBeenCalledTimes(1);
|
||||
expect(requestSpy).toHaveBeenCalledWith('label/testkey/values', {
|
||||
end: 1560163909000,
|
||||
start: 1560153109000,
|
||||
});
|
||||
expect(nextLabelValues).toEqual(['label1_val1', 'label1_val2']);
|
||||
});
|
||||
|
||||
it('should return cached values when options.streamSelector provided', async () => {
|
||||
const datasource = setup({ testkey: ['label1_val1', 'label1_val2'], label2: [] });
|
||||
const provider = await getLanguageProvider(datasource);
|
||||
const requestSpy = jest.spyOn(provider, 'request');
|
||||
const labelValues = await provider.fetchLabelValues('testkey', { streamSelector: '{foo="bar"}' });
|
||||
expect(requestSpy).toHaveBeenCalledTimes(1);
|
||||
expect(requestSpy).toHaveBeenCalledWith('label/testkey/values', {
|
||||
end: 1560163909000,
|
||||
query: '%7Bfoo%3D%22bar%22%7D',
|
||||
start: 1560153109000,
|
||||
});
|
||||
expect(labelValues).toEqual(['label1_val1', 'label1_val2']);
|
||||
|
||||
const nextLabelValues = await provider.fetchLabelValues('testkey', { streamSelector: '{foo="bar"}' });
|
||||
expect(requestSpy).toHaveBeenCalledTimes(1);
|
||||
expect(nextLabelValues).toEqual(['label1_val1', 'label1_val2']);
|
||||
});
|
||||
|
||||
@ -258,6 +296,19 @@ describe('Language completion provider', () => {
|
||||
|
||||
expect(requestSpy).toHaveBeenCalledWith('label/%60%5C%22testkey/values', expect.any(Object));
|
||||
});
|
||||
|
||||
it('should encode special characters in options.streamSelector', async () => {
|
||||
const datasource = setup({ '`\\"testkey': ['label1_val1', 'label1_val2'], label2: [] });
|
||||
const provider = await getLanguageProvider(datasource);
|
||||
const requestSpy = jest.spyOn(provider, 'request');
|
||||
await provider.fetchLabelValues('`\\"testkey', { streamSelector: '{foo="\\bar"}' });
|
||||
|
||||
expect(requestSpy).toHaveBeenCalledWith(expect.any(String), {
|
||||
query: '%7Bfoo%3D%22%5Cbar%22%7D',
|
||||
start: expect.any(Number),
|
||||
end: expect.any(Number),
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
|
@ -2,7 +2,7 @@ import { chain, difference } from 'lodash';
|
||||
import { LRUCache } from 'lru-cache';
|
||||
import Prism, { Grammar } from 'prismjs';
|
||||
|
||||
import { dateTime, AbsoluteTimeRange, LanguageProvider, HistoryItem, AbstractQuery } from '@grafana/data';
|
||||
import { dateTime, AbsoluteTimeRange, LanguageProvider, HistoryItem, AbstractQuery, KeyValue } from '@grafana/data';
|
||||
import { CompletionItem, TypeaheadInput, TypeaheadOutput, CompletionItemGroup } from '@grafana/ui';
|
||||
import {
|
||||
extractLabelMatchers,
|
||||
@ -452,18 +452,29 @@ export default class LokiLanguageProvider extends LanguageProvider {
|
||||
* It returns a promise that resolves to an array of strings containing the label values.
|
||||
*
|
||||
* @param labelName - The name of the label for which you want to retrieve values.
|
||||
* @param options - (Optional) An object containing additional options - currently only stream selector.
|
||||
* @param options.streamSelector - (Optional) The stream selector to filter label values. If not provided, all label values are fetched.
|
||||
* @returns A promise containing an array of label values.
|
||||
* @throws An error if the fetch operation fails.
|
||||
*/
|
||||
async fetchLabelValues(labelName: string): Promise<string[]> {
|
||||
const interpolatedKey = encodeURIComponent(this.datasource.interpolateString(labelName));
|
||||
async fetchLabelValues(labelName: string, options?: { streamSelector?: string }): Promise<string[]> {
|
||||
const label = encodeURIComponent(this.datasource.interpolateString(labelName));
|
||||
const streamParam = options?.streamSelector
|
||||
? encodeURIComponent(this.datasource.interpolateString(options.streamSelector))
|
||||
: undefined;
|
||||
|
||||
const url = `label/${interpolatedKey}/values`;
|
||||
const url = `label/${label}/values`;
|
||||
const rangeParams = this.datasource.getTimeRangeParams();
|
||||
const { start, end } = rangeParams;
|
||||
const params: KeyValue<string | number> = { start, end };
|
||||
let paramCacheKey = label;
|
||||
|
||||
const cacheKey = this.generateCacheKey(url, start, end, interpolatedKey);
|
||||
const params = { start, end };
|
||||
if (streamParam) {
|
||||
params.query = streamParam;
|
||||
paramCacheKey += streamParam;
|
||||
}
|
||||
|
||||
const cacheKey = this.generateCacheKey(url, start, end, paramCacheKey);
|
||||
|
||||
let labelValues = this.labelsCache.get(cacheKey);
|
||||
if (!labelValues) {
|
||||
|
@ -58,13 +58,15 @@ The `datasource.languageProvider.fetchLabelValues()` method is designed for fetc
|
||||
* It returns a promise that resolves to an array of strings containing the label values.
|
||||
*
|
||||
* @param labelName - The name of the label for which you want to retrieve values.
|
||||
* @param options - (Optional) An object containing additional options - currently only stream selector.
|
||||
* @param options.streamSelector - (Optional) The stream selector to filter label values. If not provided, all label values are fetched.
|
||||
* @returns A promise containing an array of label values.
|
||||
* @throws An error if the fetch operation fails.
|
||||
*/
|
||||
async function fetchLabelValues(labelName: string): Promise<string[]>;
|
||||
async function fetchLabelValues(labelName: string, options?: { streamSelector?: string }): Promise<string[]>;
|
||||
|
||||
/**
|
||||
* Example usage:
|
||||
* Example usage without stream selector:
|
||||
*/
|
||||
|
||||
const labelName = 'job';
|
||||
@ -74,6 +76,19 @@ try {
|
||||
} catch (error) {
|
||||
console.error(`Error fetching label values: ${error.message}`);
|
||||
}
|
||||
|
||||
/**
|
||||
* Example usage with stream selector:
|
||||
*/
|
||||
|
||||
const labelName = 'job';
|
||||
const streamSelector = '{app="grafana"}';
|
||||
try {
|
||||
const values = await fetchLabelValues(labelName, { streamSelector });
|
||||
console.log(values);
|
||||
} catch (error) {
|
||||
console.error(`Error fetching label values: ${error.message}`);
|
||||
}
|
||||
```
|
||||
|
||||
### Fetching Loki labels for a specified selector
|
||||
|
Loading…
Reference in New Issue
Block a user