Skip to main content
Glama
prometheus.ts7.48 kB
import { GrafanaHttpClient } from '../http-client.js'; import { PrometheusQueryResult, PrometheusMetric } from '../types.js'; import { BaseHttpService } from '../core/base-service.js'; import { AsyncResult } from '../core/interfaces.js'; /** * Service for querying Prometheus datasources through Grafana */ export class PrometheusService extends BaseHttpService { constructor(httpClient: GrafanaHttpClient) { super('PrometheusService', httpClient, '1.0.0'); } /** * Execute a Prometheus query (instant or range) */ async query(options: { datasourceUid: string; query: string; start?: string; end?: string; step?: string; instant?: boolean; }): Promise<PrometheusQueryResult> { const { datasourceUid, query, start, end, step, instant = false } = options; const endpoint = instant ? 'query' : 'query_range'; const params: Record<string, any> = { query }; if (!instant) { // Range query parameters if (start) params.start = start; if (end) params.end = end; if (step) params.step = step; } else { // Instant query can have a time parameter if (start) params.time = start; } return this.httpClient.get<PrometheusQueryResult>( `/api/datasources/proxy/uid/${datasourceUid}/api/v1/${endpoint}`, params, ); } /** * Execute an instant Prometheus query */ async instantQuery( datasourceUid: string, query: string, time?: string, ): Promise<PrometheusQueryResult> { return this.query({ datasourceUid, query, start: time, instant: true, }); } /** * Execute a range Prometheus query */ async rangeQuery(options: { datasourceUid: string; query: string; start: string; end: string; step?: string; }): Promise<PrometheusQueryResult> { return this.query({ ...options, instant: false, }); } /** * Get metric metadata */ async getMetricMetadata( datasourceUid: string, metric?: string, ): Promise<Record<string, any[]>> { const params = metric ? { metric } : {}; return this.httpClient.get( `/api/datasources/proxy/uid/${datasourceUid}/api/v1/metadata`, params, ); } /** * List all metric names */ async getMetricNames(datasourceUid: string): Promise<{ data: string[] }> { return this.httpClient.get( `/api/datasources/proxy/uid/${datasourceUid}/api/v1/label/__name__/values`, ); } /** * List all label names */ async getLabelNames( datasourceUid: string, match?: string[], ): Promise<{ data: string[] }> { const params: Record<string, any> = {}; if (match && match.length > 0) { params['match[]'] = match; } return this.httpClient.get( `/api/datasources/proxy/uid/${datasourceUid}/api/v1/labels`, params, ); } /** * List values for a specific label */ async getLabelValues( datasourceUid: string, labelName: string, match?: string[], ): Promise<{ data: string[] }> { const params: Record<string, any> = {}; if (match && match.length > 0) { params['match[]'] = match; } return this.httpClient.get( `/api/datasources/proxy/uid/${datasourceUid}/api/v1/label/${encodeURIComponent(labelName)}/values`, params, ); } /** * Find series matching label selectors */ async findSeries( datasourceUid: string, match: string[], start?: string, end?: string, ): Promise<{ data: PrometheusMetric[] }> { const params: Record<string, any> = { 'match[]': match, }; if (start) params.start = start; if (end) params.end = end; return this.httpClient.get( `/api/datasources/proxy/uid/${datasourceUid}/api/v1/series`, params, ); } /** * Get target metadata (info about scrape targets) */ async getTargets( datasourceUid: string, state?: 'active' | 'dropped' | 'any', ): Promise<any> { const params = state ? { state } : {}; return this.httpClient.get( `/api/datasources/proxy/uid/${datasourceUid}/api/v1/targets`, params, ); } /** * Get alerting rules */ async getAlertingRules( datasourceUid: string, type?: 'alert' | 'record', ): Promise<any> { const params = type ? { type } : {}; return this.httpClient.get( `/api/datasources/proxy/uid/${datasourceUid}/api/v1/rules`, params, ); } /** * Get alerts */ async getAlerts(datasourceUid: string): Promise<any> { return this.httpClient.get( `/api/datasources/proxy/uid/${datasourceUid}/api/v1/alerts`, ); } /** * Get Prometheus configuration */ async getConfig(datasourceUid: string): Promise<any> { return this.httpClient.get( `/api/datasources/proxy/uid/${datasourceUid}/api/v1/status/config`, ); } /** * Get Prometheus flags */ async getFlags(datasourceUid: string): Promise<any> { return this.httpClient.get( `/api/datasources/proxy/uid/${datasourceUid}/api/v1/status/flags`, ); } /** * Get Prometheus runtime information */ async getRuntimeInfo(datasourceUid: string): Promise<any> { return this.httpClient.get( `/api/datasources/proxy/uid/${datasourceUid}/api/v1/status/runtimeinfo`, ); } /** * Get Prometheus build information */ async getBuildInfo(datasourceUid: string): Promise<any> { return this.httpClient.get( `/api/datasources/proxy/uid/${datasourceUid}/api/v1/status/buildinfo`, ); } /** * Test if a datasource is a Prometheus datasource */ async isPrometheusDatasource(datasourceUid: string): Promise<boolean> { try { await this.httpClient.get( `/api/datasources/proxy/uid/${datasourceUid}/api/v1/status/config`, ); return true; } catch (_error) { return false; } } /** * Parse Prometheus query for validation */ parseQuery(query: string): { isValid: boolean; error?: string } { // Basic validation - could be enhanced with a proper PromQL parser if (!query || query.trim().length === 0) { return { isValid: false, error: 'Query is empty' }; } // Check for some common syntax errors const openBraces = (query.match(/{/g) || []).length; const closeBraces = (query.match(/}/g) || []).length; if (openBraces !== closeBraces) { return { isValid: false, error: 'Unmatched braces in query' }; } return { isValid: true }; } /** * Format time value for Prometheus API */ formatTime(time: string | number | Date): string { if (typeof time === 'string') { // Assume it's already in the correct format or a relative time return time; } if (typeof time === 'number') { // Unix timestamp return String(time); } if (time instanceof Date) { // Convert to Unix timestamp return Math.floor(time.getTime() / 1000).toString(); } return String(time); } /** * Calculate default step for range queries */ calculateDefaultStep(start: string, end: string): string { const startTime = new Date(start).getTime(); const endTime = new Date(end).getTime(); const duration = endTime - startTime; // Default to ~250 points const points = 250; const step = Math.floor(duration / (points * 1000)); // Convert to seconds return `${Math.max(step, 15).toString()}s`; // Minimum 15 seconds } }

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/quanticsoul4772/grafana-mcp'

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