{"version":3,"file":"resource_clients.cjs","sources":["../../src/resource_clients.ts"],"sourcesContent":["import { type TimeRange } from '@grafana/data';\nimport { type BackendSrvRequest } from '@grafana/runtime';\n\nimport { getDefaultCacheHeaders } from './caching';\nimport { DEFAULT_SERIES_LIMIT, EMPTY_SELECTOR, MATCH_ALL_LABELS, METRIC_LABEL } from './constants';\nimport { type PrometheusDatasource } from './datasource';\nimport { getRangeSnapInterval, processHistogramMetrics, removeQuotesIfExist } from './language_utils';\nimport { buildVisualQueryFromString } from './querybuilder/parsing';\nimport { PrometheusCacheLevel } from './types';\nimport { escapeForUtf8Support, utf8Support } from './utf8_support';\n\ntype PrometheusSeriesResponse = Array<{ [key: string]: string }>;\ntype PrometheusLabelsResponse = string[];\n\nexport interface ResourceApiClient {\n  metrics: string[];\n  histogramMetrics: string[];\n  labelKeys: string[];\n  cachedLabelValues: Record<string, string[]>;\n\n  start: (timeRange: TimeRange) => Promise<void>;\n\n  queryMetrics: (timeRange: TimeRange) => Promise<{ metrics: string[]; histogramMetrics: string[] }>;\n  queryLabelKeys: (timeRange: TimeRange, match?: string, limit?: number) => Promise<string[]>;\n  queryLabelValues: (timeRange: TimeRange, labelKey: string, match?: string, limit?: number) => Promise<string[]>;\n\n  querySeries: (timeRange: TimeRange, match: string, limit: number) => Promise<PrometheusSeriesResponse>;\n}\n\ntype RequestFn = (\n  url: string,\n  params?: Record<string, unknown>,\n  options?: Partial<BackendSrvRequest>\n) => Promise<unknown>;\n\nexport abstract class BaseResourceClient {\n  private seriesLimit: number;\n\n  constructor(\n    protected readonly request: RequestFn,\n    protected readonly datasource: PrometheusDatasource\n  ) {\n    this.seriesLimit = this.datasource.seriesLimit;\n  }\n\n  /**\n   * Returns the effective limit to use for API requests.\n   * Uses the provided limit if specified, otherwise falls back to the datasource's configured series limit.\n   * When zero is provided, it returns zero (which means no limit in Prometheus API).\n   *\n   * @param {number} [limit] - Optional limit parameter from the API call\n   * @returns {number} The limit to use - either the provided limit or datasource's default series limit\n   */\n  protected getEffectiveLimit(limit?: number): number {\n    return limit ?? this.seriesLimit;\n  }\n\n  protected async requestLabels(\n    url: string,\n    params?: Record<string, unknown>,\n    options?: Partial<BackendSrvRequest>\n  ): Promise<PrometheusLabelsResponse> {\n    const response = await this.request(url, params, options);\n    return Array.isArray(response) ? response : [];\n  }\n\n  protected async requestSeries(\n    url: string,\n    params?: Record<string, unknown>,\n    options?: Partial<BackendSrvRequest>\n  ): Promise<PrometheusSeriesResponse> {\n    const response = await this.request(url, params, options);\n    return Array.isArray(response) ? response : [];\n  }\n\n  /**\n   * Fetches all time series that match a specific label matcher using **series** endpoint.\n   *\n   * @param {TimeRange} timeRange - Time range to use for the query\n   * @param {string} match - Label matcher to filter time series\n   * @param {string} limit - Maximum number of series to return\n   */\n  public querySeries = async (timeRange: TimeRange, match: string | undefined, limit: number) => {\n    const effectiveMatch = !match || match === EMPTY_SELECTOR ? MATCH_ALL_LABELS : match;\n    const timeParams = this.datasource.getTimeRangeParams(timeRange);\n    const searchParams = { ...timeParams, 'match[]': effectiveMatch, limit };\n    return await this.requestSeries('/api/v1/series', searchParams, getDefaultCacheHeaders(this.datasource.cacheLevel));\n  };\n}\n\nexport class LabelsApiClient extends BaseResourceClient implements ResourceApiClient {\n  private _cache: ResourceClientsCache = new ResourceClientsCache(this.datasource.cacheLevel);\n\n  public histogramMetrics: string[] = [];\n  public metrics: string[] = [];\n  public labelKeys: string[] = [];\n  public cachedLabelValues: Record<string, string[]> = {};\n\n  start = async (timeRange: TimeRange) => {\n    await this.queryMetrics(timeRange);\n    this.labelKeys = await this.queryLabelKeys(timeRange);\n  };\n\n  /**\n   * Fetches all available metrics from Prometheus using the labels values endpoint for __name__.\n   * Also processes and identifies histogram metrics (those ending with '_bucket').\n   * Results are cached and stored in the client instance for future use.\n   *\n   * @param {TimeRange} timeRange - Time range to search for metrics\n   * @param {number} [limit] - Optional maximum number of metrics to return, uses datasource default if not specified\n   * @returns {Promise<{metrics: string[], histogramMetrics: string[]}>} Object containing all metrics and filtered histogram metrics\n   */\n  public queryMetrics = async (\n    timeRange: TimeRange,\n    limit?: number\n  ): Promise<{ metrics: string[]; histogramMetrics: string[] }> => {\n    const effectiveLimit = this.getEffectiveLimit(limit);\n    this.metrics = await this.queryLabelValues(timeRange, METRIC_LABEL, undefined, effectiveLimit);\n    this.histogramMetrics = processHistogramMetrics(this.metrics);\n    this._cache.setLabelValues(timeRange, undefined, effectiveLimit, this.metrics);\n    return { metrics: this.metrics, histogramMetrics: this.histogramMetrics };\n  };\n\n  /**\n   * Fetches all available label keys from Prometheus using labels endpoint.\n   * Uses the labels endpoint with optional match parameter for filtering.\n   *\n   * @param {TimeRange} timeRange - Time range to use for the query\n   * @param {string} match - Optional label matcher to filter results\n   * @param {string} limit - Maximum number of results to return\n   * @returns {Promise<string[]>} Array of label keys sorted alphabetically\n   */\n  public queryLabelKeys = async (timeRange: TimeRange, match?: string, limit?: number): Promise<string[]> => {\n    let url = '/api/v1/labels';\n    const timeParams = getRangeSnapInterval(this.datasource.cacheLevel, timeRange);\n    const effectiveLimit = this.getEffectiveLimit(limit);\n    const searchParams = { limit: effectiveLimit, ...timeParams, ...(match ? { 'match[]': match } : {}) };\n    const effectiveMatch = match ?? '';\n    const maybeCachedKeys = this._cache.getLabelKeys(timeRange, effectiveMatch, effectiveLimit);\n    if (maybeCachedKeys) {\n      return maybeCachedKeys;\n    }\n\n    const res = await this.requestLabels(url, searchParams, getDefaultCacheHeaders(this.datasource.cacheLevel));\n    if (Array.isArray(res)) {\n      this.labelKeys = res.slice().sort();\n      this._cache.setLabelKeys(timeRange, effectiveMatch, effectiveLimit, this.labelKeys);\n      return this.labelKeys.slice();\n    }\n\n    return [];\n  };\n\n  /**\n   * Fetches all values for a specific label key from Prometheus using labels values endpoint.\n   *\n   * @param {TimeRange} timeRange - Time range to use for the query\n   * @param {string} labelKey - The label key to fetch values for\n   * @param {string} match - Optional label matcher to filter results\n   * @param {string} limit - Maximum number of results to return\n   * @returns {Promise<string[]>} Array of label values\n   */\n  public queryLabelValues = async (\n    timeRange: TimeRange,\n    labelKey: string,\n    match?: string,\n    limit?: number\n  ): Promise<string[]> => {\n    const timeParams = this.datasource.getAdjustedInterval(timeRange);\n    const effectiveLimit = this.getEffectiveLimit(limit);\n    const searchParams = { limit: effectiveLimit, ...timeParams, ...(match ? { 'match[]': match } : {}) };\n    const interpolatedName = this.datasource.interpolateString(labelKey);\n    const interpolatedAndEscapedName = escapeForUtf8Support(removeQuotesIfExist(interpolatedName));\n    const effectiveMatch = `${match ?? ''}-${interpolatedAndEscapedName}`;\n    const maybeCachedValues = this._cache.getLabelValues(timeRange, effectiveMatch, effectiveLimit);\n    if (maybeCachedValues) {\n      return maybeCachedValues;\n    }\n\n    const url = `/api/v1/label/${interpolatedAndEscapedName}/values`;\n    const value = await this.requestLabels(url, searchParams, getDefaultCacheHeaders(this.datasource.cacheLevel));\n    this._cache.setLabelValues(timeRange, effectiveMatch, effectiveLimit, value ?? []);\n    return value ?? [];\n  };\n}\n\nexport class SeriesApiClient extends BaseResourceClient implements ResourceApiClient {\n  private _cache: ResourceClientsCache = new ResourceClientsCache(this.datasource.cacheLevel);\n\n  public histogramMetrics: string[] = [];\n  public metrics: string[] = [];\n  public labelKeys: string[] = [];\n  public cachedLabelValues: Record<string, string[]> = {};\n\n  start = async (timeRange: TimeRange) => {\n    await this.queryMetrics(timeRange);\n  };\n\n  public queryMetrics = async (timeRange: TimeRange): Promise<{ metrics: string[]; histogramMetrics: string[] }> => {\n    const series = await this.querySeries(timeRange, undefined, DEFAULT_SERIES_LIMIT);\n    const { metrics, labelKeys } = processSeries(series, METRIC_LABEL, this.datasource.hasLabelsMatchAPISupport());\n    this.metrics = metrics;\n    this.histogramMetrics = processHistogramMetrics(this.metrics);\n    this.labelKeys = labelKeys;\n    this._cache.setLabelValues(timeRange, undefined, DEFAULT_SERIES_LIMIT, metrics);\n    this._cache.setLabelKeys(timeRange, undefined, DEFAULT_SERIES_LIMIT, labelKeys);\n    return { metrics: this.metrics, histogramMetrics: this.histogramMetrics };\n  };\n\n  public queryLabelKeys = async (timeRange: TimeRange, match?: string, limit?: number): Promise<string[]> => {\n    const effectiveLimit = this.getEffectiveLimit(limit);\n    const effectiveMatch = !match || match === EMPTY_SELECTOR ? undefined : match;\n    const maybeCachedKeys = this._cache.getLabelKeys(timeRange, effectiveMatch, effectiveLimit);\n    if (maybeCachedKeys) {\n      return maybeCachedKeys;\n    }\n\n    const series = await this.querySeries(timeRange, effectiveMatch, effectiveLimit);\n    const { labelKeys } = processSeries(series, undefined, this.datasource.hasLabelsMatchAPISupport(), effectiveMatch);\n    this._cache.setLabelKeys(timeRange, effectiveMatch, effectiveLimit, labelKeys);\n    return labelKeys;\n  };\n\n  public queryLabelValues = async (\n    timeRange: TimeRange,\n    labelKey: string,\n    match?: string,\n    limit?: number\n  ): Promise<string[]> => {\n    let effectiveMatch = '';\n    if (!match || match === EMPTY_SELECTOR) {\n      // Just and empty matcher {} or no matcher\n      effectiveMatch = `{${utf8Support(removeQuotesIfExist(labelKey))}!=\"\"}`;\n    } else {\n      const {\n        query: { metric, labels },\n      } = buildVisualQueryFromString(match);\n      labels.push({\n        label: removeQuotesIfExist(labelKey),\n        op: '!=',\n        value: '',\n      });\n      const metricFilter = metric ? `__name__=\"${metric}\",` : '';\n      const labelFilters = labels.map((lf) => `${utf8Support(lf.label)}${lf.op}\"${lf.value}\"`).join(',');\n      effectiveMatch = `{${metricFilter}${labelFilters}}`;\n    }\n\n    const effectiveLimit = this.getEffectiveLimit(limit);\n    const maybeCachedValues = this._cache.getLabelValues(timeRange, effectiveMatch, effectiveLimit);\n    if (maybeCachedValues) {\n      return maybeCachedValues;\n    }\n\n    const series = await this.querySeries(timeRange, effectiveMatch, effectiveLimit);\n    const { labelValues } = processSeries(\n      series,\n      removeQuotesIfExist(labelKey),\n      this.datasource.hasLabelsMatchAPISupport(),\n      effectiveMatch\n    );\n    this._cache.setLabelValues(timeRange, effectiveMatch, effectiveLimit, labelValues);\n    return labelValues;\n  };\n}\n\nclass ResourceClientsCache {\n  private readonly MAX_CACHE_ENTRIES = 1000; // Maximum number of cache entries\n  private readonly MAX_CACHE_SIZE_BYTES = 50 * 1024 * 1024; // 50MB max cache size\n\n  private _cache: Record<string, string[]> = {};\n  private _accessTimestamps: Record<string, number> = {};\n\n  constructor(private cacheLevel: PrometheusCacheLevel = PrometheusCacheLevel.High) {}\n\n  public setLabelKeys(timeRange: TimeRange, match: string | undefined, limit: number, keys: string[]) {\n    if (keys.length === 0) {\n      return;\n    }\n    // Check and potentially clean cache before adding new entry\n    this.cleanCacheIfNeeded();\n    const cacheKey = this.getCacheKey(timeRange, match, limit, 'key');\n    this._cache[cacheKey] = keys.slice().sort();\n    this._accessTimestamps[cacheKey] = Date.now();\n  }\n\n  public getLabelKeys(timeRange: TimeRange, match: string | undefined, limit: number): string[] | undefined {\n    const cacheKey = this.getCacheKey(timeRange, match, limit, 'key');\n    const result = this._cache[cacheKey];\n    if (result) {\n      // Update access timestamp on cache hit\n      this._accessTimestamps[cacheKey] = Date.now();\n    }\n    return result;\n  }\n\n  public setLabelValues(timeRange: TimeRange, match: string | undefined, limit: number, values: string[]) {\n    if (values.length === 0) {\n      return;\n    }\n    // Check and potentially clean cache before adding new entry\n    this.cleanCacheIfNeeded();\n    const cacheKey = this.getCacheKey(timeRange, match, limit, 'value');\n    this._cache[cacheKey] = values.slice().sort();\n    this._accessTimestamps[cacheKey] = Date.now();\n  }\n\n  public getLabelValues(timeRange: TimeRange, match: string, limit: number): string[] | undefined {\n    const cacheKey = this.getCacheKey(timeRange, match, limit, 'value');\n    const result = this._cache[cacheKey];\n    if (result) {\n      // Update access timestamp on cache hit\n      this._accessTimestamps[cacheKey] = Date.now();\n    }\n    return result;\n  }\n\n  private getCacheKey(timeRange: TimeRange, match: string | undefined, limit: number, type: 'key' | 'value') {\n    const snappedTimeRange = getRangeSnapInterval(this.cacheLevel, timeRange);\n    return [snappedTimeRange.start, snappedTimeRange.end, limit, match, type].join('|');\n  }\n\n  private cleanCacheIfNeeded() {\n    // Check number of entries\n    const currentEntries = Object.keys(this._cache).length;\n    if (currentEntries >= this.MAX_CACHE_ENTRIES) {\n      // Calculate 20% of current entries, but ensure we remove at least 1 entry\n      const entriesToRemove = Math.max(1, Math.floor(currentEntries - this.MAX_CACHE_ENTRIES + 1));\n      this.removeOldestEntries(entriesToRemove);\n    }\n\n    // Check cache size in bytes\n    const currentSize = this.getCacheSizeInBytes();\n    if (currentSize > this.MAX_CACHE_SIZE_BYTES) {\n      // Calculate 20% of current entries, but ensure we remove at least 1 entry\n      const entriesToRemove = Math.max(1, Math.floor(Object.keys(this._cache).length * 0.2));\n      this.removeOldestEntries(entriesToRemove);\n    }\n  }\n\n  private getCacheSizeInBytes(): number {\n    let size = 0;\n    for (const key in this._cache) {\n      // Calculate size of key\n      size += key.length * 2; // Approximate size of string in bytes (UTF-16)\n\n      // Calculate size of value array\n      const value = this._cache[key];\n      for (const item of value) {\n        size += item.length * 2; // Approximate size of each string in bytes\n      }\n    }\n    return size;\n  }\n\n  private removeOldestEntries(count: number) {\n    // Get all entries sorted by timestamp (oldest first)\n    const entries = Object.entries(this._accessTimestamps).sort(\n      ([, timestamp1], [, timestamp2]) => timestamp1 - timestamp2\n    );\n\n    // Take the oldest 'count' entries\n    const entriesToRemove = entries.slice(0, count);\n\n    // Remove these entries from both cache and timestamps\n    for (const [key] of entriesToRemove) {\n      delete this._cache[key];\n      delete this._accessTimestamps[key];\n    }\n  }\n}\n\nexport function processSeries(\n  series: Array<{ [key: string]: string }>,\n  findValuesForKey?: string,\n  hasLabelsMatchAPISupport = true,\n  matchSelector = ''\n) {\n  const metrics: Set<string> = new Set();\n  const labelKeys: Set<string> = new Set();\n  const labelValues: Set<string> = new Set();\n\n  let filteredSeries = series;\n  if (!hasLabelsMatchAPISupport) {\n    // The datasource doesn't have match[] parameter support.\n    // Manual filtering is required to avoid returning duplicate metrics.\n    const {\n      query: { labels },\n    } = buildVisualQueryFromString(matchSelector);\n\n    filteredSeries = series.filter((item) => {\n      return labels.every((lbl) => matchesLabelCondition(item[lbl.label], lbl.op, lbl.value));\n    });\n  }\n\n  // Extract metrics, label keys, and label values from the (filtered) series\n  filteredSeries.forEach((item) => {\n    // Add the __name__ value to metrics\n    if (METRIC_LABEL in item) {\n      metrics.add(item.__name__);\n    }\n\n    // Add all keys except __name__ to labelKeys\n    Object.keys(item).forEach((key) => {\n      if (key !== METRIC_LABEL) {\n        labelKeys.add(key);\n      }\n\n      // If finding values for a specific key, add those values\n      if (findValuesForKey && key === findValuesForKey) {\n        labelValues.add(item[key]);\n      }\n    });\n  });\n\n  return {\n    metrics: Array.from(metrics).sort(),\n    labelKeys: Array.from(labelKeys).sort(),\n    labelValues: Array.from(labelValues).sort(),\n  };\n}\n\n/**\n * Evaluates whether a label value matches based on the operator.\n * Supports Prometheus label matching operators: =, !=, =~, !~\n *\n * @param itemValue - The actual value from the series item\n * @param operator - The comparison operator (=, !=, =~, !~)\n * @param matchValue - The value to match against\n * @returns true if the condition is satisfied, false otherwise\n */\nfunction matchesLabelCondition(itemValue: string | undefined, operator: string, matchValue: string): boolean {\n  // Handle case where label doesn't exist in the item\n  if (itemValue === undefined) {\n    // For != and !~, missing label is considered a match (it's \"not equal\" to the value)\n    return operator === '!=' || operator === '!~';\n  }\n\n  switch (operator) {\n    case '=':\n      return itemValue === matchValue;\n    case '!=':\n      return itemValue !== matchValue;\n    case '=~':\n      try {\n        const regex = new RegExp(matchValue);\n        return regex.test(itemValue);\n      } catch {\n        // Invalid regex, treat as no match\n        return false;\n      }\n    case '!~':\n      try {\n        const regex = new RegExp(matchValue);\n        return !regex.test(itemValue);\n      } catch {\n        // Invalid regex, treat as match (doesn't match invalid pattern)\n        return true;\n      }\n    default:\n      // Unknown operator, default to exact match\n      return itemValue === matchValue;\n  }\n}\n"],"names":["EMPTY_SELECTOR","MATCH_ALL_LABELS","getDefaultCacheHeaders","METRIC_LABEL","processHistogramMetrics","getRangeSnapInterval","escapeForUtf8Support","removeQuotesIfExist","DEFAULT_SERIES_LIMIT","utf8Support","buildVisualQueryFromString","PrometheusCacheLevel"],"mappings":"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"}