|
|
|
@ -4,7 +4,7 @@ import { HistoryItem } from '@grafana/data'; |
|
|
|
|
import { escapeLabelValueInExactSelector } from 'app/plugins/datasource/prometheus/language_utils'; |
|
|
|
|
|
|
|
|
|
import LanguageProvider from '../../../LanguageProvider'; |
|
|
|
|
import { LokiQuery } from '../../../types'; |
|
|
|
|
import { ExtractedLabelKeys, LokiQuery } from '../../../types'; |
|
|
|
|
|
|
|
|
|
import { Label } from './situation'; |
|
|
|
|
|
|
|
|
@ -16,7 +16,10 @@ export class CompletionDataProvider { |
|
|
|
|
constructor( |
|
|
|
|
private languageProvider: LanguageProvider, |
|
|
|
|
private historyRef: HistoryRef = { current: [] } |
|
|
|
|
) {} |
|
|
|
|
) { |
|
|
|
|
this.queryToLabelKeysCache = new Map(); |
|
|
|
|
} |
|
|
|
|
private queryToLabelKeysCache: Map<string, ExtractedLabelKeys>; |
|
|
|
|
|
|
|
|
|
private buildSelector(labels: Label[]): string { |
|
|
|
|
const allLabelTexts = labels.map( |
|
|
|
@ -55,8 +58,35 @@ export class CompletionDataProvider { |
|
|
|
|
return data[labelName] ?? []; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
async getParserAndLabelKeys(logQuery: string) { |
|
|
|
|
return await this.languageProvider.getParserAndLabelKeys(logQuery); |
|
|
|
|
/** |
|
|
|
|
* Runs a Loki query to extract label keys from the result. |
|
|
|
|
* The result is cached for the query string. |
|
|
|
|
* |
|
|
|
|
* Since various "situations" in the monaco code editor trigger this function, it is prone to being called multiple times for the same query |
|
|
|
|
* Here is a lightweight and simple cache to avoid calling the backend multiple times for the same query. |
|
|
|
|
* |
|
|
|
|
* @param logQuery |
|
|
|
|
*/ |
|
|
|
|
async getParserAndLabelKeys(logQuery: string): Promise<ExtractedLabelKeys> { |
|
|
|
|
const EXTRACTED_LABEL_KEYS_MAX_CACHE_SIZE = 2; |
|
|
|
|
const cachedLabelKeys = this.queryToLabelKeysCache.has(logQuery) ? this.queryToLabelKeysCache.get(logQuery) : null; |
|
|
|
|
if (cachedLabelKeys) { |
|
|
|
|
// cache hit! Serve stale result from cache
|
|
|
|
|
return cachedLabelKeys; |
|
|
|
|
} else { |
|
|
|
|
// If cache is larger than max size, delete the first (oldest) index
|
|
|
|
|
if (this.queryToLabelKeysCache.size >= EXTRACTED_LABEL_KEYS_MAX_CACHE_SIZE) { |
|
|
|
|
// Make room in the cache for the fresh result by deleting the "first" index
|
|
|
|
|
const keys = this.queryToLabelKeysCache.keys(); |
|
|
|
|
const firstKey = keys.next().value; |
|
|
|
|
this.queryToLabelKeysCache.delete(firstKey); |
|
|
|
|
} |
|
|
|
|
// Fetch a fresh result from the backend
|
|
|
|
|
const labelKeys = await this.languageProvider.getParserAndLabelKeys(logQuery); |
|
|
|
|
// Add the result to the cache
|
|
|
|
|
this.queryToLabelKeysCache.set(logQuery, labelKeys); |
|
|
|
|
return labelKeys; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
async getSeriesLabels(labels: Label[]) { |
|
|
|
|