Skip to main content
Glama
client.ts6.83 kB
/** * PrometheusClient - Typed wrapper around prometheus-query library * * IMPORTANT: This client executes PromQL queries. To DISCOVER available metrics, * use MetricSearchEngine.search() first. */ import type { PrometheusClientOptions, TimeRange, InstantQueryResult, RangeQueryResult, Sample, TimeSeries, MetricInfo, } from './types.js'; // eslint-disable-next-line @typescript-eslint/no-explicit-any type AnyPrometheusDriver = any; /** * Typed client for executing PromQL queries against Prometheus. * * NOTE: This client runs PromQL expressions. To discover available metrics, * use MetricSearchEngine.search() - it provides semantic search over metric * names and descriptions. */ export class PrometheusClient { private options: PrometheusClientOptions; private driver: AnyPrometheusDriver = null; constructor(options: PrometheusClientOptions) { this.options = { timeout: 30000, ...options, }; } /** * Get the Prometheus endpoint URL */ getEndpoint(): string { return this.options.endpoint; } /** * Initialize the Prometheus driver */ private async getDriver(): Promise<AnyPrometheusDriver> { if (this.driver) { return this.driver; } const { PrometheusDriver } = await import('prometheus-query'); this.driver = new PrometheusDriver({ endpoint: this.options.endpoint, timeout: this.options.timeout, }); return this.driver; } /** * Execute an instant PromQL query. * * This runs a PromQL expression and returns the current value. * You must already know the metric name - use MetricSearchEngine.search() * to discover available metrics first. * * @param promql - PromQL expression (e.g., "node_memory_MemTotal_bytes") * @param time - Optional evaluation time (defaults to now) * @returns Query result with time series data * * @example * // First discover metrics with MetricSearchEngine.search("memory") * // Then execute with known metric name: * const result = await client.execute("node_memory_MemTotal_bytes"); */ async execute(promql: string, time?: Date): Promise<InstantQueryResult> { const driver = await this.getDriver(); const result = await driver.instantQuery(promql, time); return { resultType: result.resultType as InstantQueryResult['resultType'], data: this.parseTimeSeries(result.result), }; } /** * Execute a range PromQL query over a time period. * * This runs a PromQL expression over a time range and returns samples. * You must already know the metric name - use MetricSearchEngine.search() * to discover available metrics first. * * @param promql - PromQL expression (e.g., "rate(http_requests_total[5m])") * @param range - Time range with start, end, and step * @returns Query result with time series data * * @example * // First discover metrics with MetricSearchEngine.search("memory") * // Then execute with known metric name: * const result = await client.executeRange("node_memory_MemTotal_bytes", { * start: new Date(Date.now() - 3600000), * end: new Date(), * step: "5m" * }); */ async executeRange(promql: string, range: TimeRange): Promise<RangeQueryResult> { const driver = await this.getDriver(); const start = range.start instanceof Date ? range.start : new Date(range.start * 1000); const end = range.end instanceof Date ? range.end : new Date(range.end * 1000); const result = await driver.rangeQuery(promql, start, end, range.step); return { resultType: 'matrix', data: this.parseTimeSeries(result.result), }; } /** * Get all label names */ async labelNames(): Promise<string[]> { const driver = await this.getDriver(); return driver.labelNames(); } /** * Get all values for a label * * @param label - Label name * @returns Array of label values */ async labelValues(label: string): Promise<string[]> { const driver = await this.getDriver(); return driver.labelValues(label); } /** * Get metric metadata from Prometheus * * @returns Map of metric name to metadata array */ async metadata(): Promise<Record<string, MetadataEntry[]>> { const driver = await this.getDriver(); return driver.metadata(); } /** * Get all series matching a set of label matchers * * @param match - Label matcher expressions * @param start - Optional start time * @param end - Optional end time * @returns Array of label sets */ async series( match: string[], start?: Date, end?: Date ): Promise<Record<string, string>[]> { const driver = await this.getDriver(); return driver.series(match, start, end); } /** * Check if Prometheus is reachable */ async isHealthy(): Promise<boolean> { try { const driver = await this.getDriver(); // Try to get label names as a health check await driver.labelNames(); return true; } catch { return false; } } /** * List all available metrics from the live Prometheus cluster. * * Returns raw metric metadata. For semantic search (e.g., "memory usage"), * use MetricSearchEngine instead. * * @returns Array of all available metrics with name, type, and description */ async listMetrics(): Promise<MetricInfo[]> { const allMetadata = await this.metadata(); const metrics: MetricInfo[] = []; for (const [name, entries] of Object.entries(allMetadata)) { const entry = Array.isArray(entries) ? entries[0] : entries; metrics.push({ name, type: (entry?.type as MetricInfo['type']) || 'unknown', help: entry?.help || 'No description available', }); } return metrics; } /** * Parse time series from prometheus-query result */ private parseTimeSeries(result: PrometheusResult[]): TimeSeries[] { return result.map((series) => ({ labels: series.metric.labels || {}, samples: this.parseSamples(series.values || (series.value ? [series.value] : [])), })); } /** * Parse sample values */ private parseSamples(values: SampleTuple[]): Sample[] { return values.filter((v): v is SampleTuple => v !== undefined).map((v) => ({ time: typeof v.time === 'number' ? v.time : v.time.getTime() / 1000, value: typeof v.value === 'string' ? parseFloat(v.value) : v.value, })); } } // Type definitions for prometheus-query library internals interface PrometheusResult { metric: { labels?: Record<string, string>; name?: string; }; value?: SampleTuple; values?: SampleTuple[]; } interface SampleTuple { time: Date | number; value: string | number; } interface MetadataEntry { type?: string; help?: string; unit?: string; }

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/harche/ProDisco'

If you have feedback or need assistance with the MCP directory API, please join our Discord server