signoz-mcp-server
Version:
Model Context Protocol server for SigNoz observability platform
449 lines • 13.6 kB
JavaScript
"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.SigNozApiClient = void 0;
const axios_1 = __importDefault(require("axios"));
const ws_1 = __importDefault(require("ws"));
const eventsource_1 = __importDefault(require("eventsource"));
class SigNozApiClient {
axios;
baseURL;
apiKey;
constructor(options) {
this.baseURL = options.baseURL.replace(/\/+$/, ''); // Remove trailing slashes
this.apiKey = options.apiKey || '';
this.axios = axios_1.default.create({
baseURL: this.baseURL,
timeout: options.timeout || 30000,
headers: {
'Content-Type': 'application/json',
...(this.apiKey && { 'SIGNOZ-API-KEY': this.apiKey }),
},
});
// Add retry logic
this.setupRetryInterceptor(options.retries || 3);
}
setupRetryInterceptor(retries) {
this.axios.interceptors.response.use((response) => response, async (error) => {
const config = error.config;
if (!config || !config.retry) {
config.retry = 0;
}
if (config.retry < retries && this.shouldRetry(error)) {
config.retry += 1;
const delay = Math.pow(2, config.retry) * 1000; // Exponential backoff
await new Promise(resolve => setTimeout(resolve, delay));
return this.axios.request(config);
}
return Promise.reject(error);
});
}
shouldRetry(error) {
return (error.code === 'ECONNRESET' ||
error.code === 'ETIMEDOUT' ||
error.code === 'ENOTFOUND' ||
(error.response && [408, 429, 500, 502, 503, 504].includes(error.response.status)));
}
async request(config) {
try {
const response = await this.axios.request(config);
if (response.data.status === 'error') {
throw new Error(response.data.error || 'Unknown API error');
}
return response.data.data || response.data;
}
catch (error) {
if (error.response) {
const errorData = error.response.data;
const errorMsg = typeof errorData.error === 'string'
? errorData.error
: JSON.stringify(errorData.error || errorData);
throw new Error(`SigNoz API Error: ${errorMsg || error.message}`);
}
throw error;
}
}
// ========== System & Health ==========
async getVersion() {
return this.request({
method: 'GET',
url: '/api/v1/version',
});
}
async getHealth() {
return this.request({
method: 'GET',
url: '/api/v1/health',
});
}
async getFeatures() {
return this.request({
method: 'GET',
url: '/api/v1/features',
});
}
// ========== Query & Metrics ==========
async queryRange(request) {
return this.request({
method: 'POST',
url: '/api/v3/query_range',
data: request,
});
}
async queryRangeV4(request) {
return this.request({
method: 'POST',
url: '/api/v4/query_range',
data: request,
});
}
async queryRangeV5(request) {
return this.request({
method: 'POST',
url: '/api/v5/query_range',
data: request,
});
}
async prometheusQuery(query, time) {
return this.request({
method: 'GET',
url: '/api/v1/query',
params: { query, time },
});
}
async prometheusQueryRange(query, start, end, step) {
return this.request({
method: 'GET',
url: '/api/v1/query_range',
params: { query, start, end, step },
});
}
// ========== Services & Traces ==========
async getServices(timeRange, filters) {
return this.request({
method: 'POST',
url: '/api/v1/services',
data: {
start: Math.floor(timeRange.start / 1000).toString(),
end: Math.floor(timeRange.end / 1000).toString(),
...filters,
},
});
}
async getServicesList() {
return this.request({
method: 'GET',
url: '/api/v1/services/list',
});
}
async getTrace(traceId) {
return this.request({
method: 'GET',
url: `/api/v1/traces/${traceId}`,
});
}
async getTopOperations(service, timeRange) {
return this.request({
method: 'POST',
url: '/api/v1/service/top_operations',
data: {
service,
start: Math.floor(timeRange.start / 1000).toString(),
end: Math.floor(timeRange.end / 1000).toString(),
},
});
}
async getDependencyGraph(timeRange) {
return this.request({
method: 'POST',
url: '/api/v1/dependency_graph',
data: {
start: Math.floor(timeRange.start / 1000).toString(),
end: Math.floor(timeRange.end / 1000).toString(),
},
});
}
// ========== Logs ==========
async getLogs(params) {
return this.request({
method: 'GET',
url: '/api/v1/logs',
params,
});
}
async searchLogsV3(params) {
const compositeQuery = {
queryType: 'builder',
panelType: 'list',
builderQueries: {
A: {
queryName: 'A',
stepInterval: 60,
dataSource: 'logs',
aggregateOperator: 'noop',
aggregateAttribute: {
key: '',
dataType: '',
type: '',
isColumn: false,
isJSON: false,
id: '',
},
filters: params.query ? {
op: 'AND',
items: [
{
key: 'body',
op: 'contains',
value: params.query,
},
],
} : { op: 'AND', items: [] },
expression: 'A',
disabled: false,
having: [],
orderBy: params.orderBy ? [{ columnName: params.orderBy, order: params.order || 'desc' }] : [],
groupBy: [],
limit: params.limit || 100,
offset: params.offset || 0,
},
},
};
return this.request({
method: 'POST',
url: '/api/v3/logs',
data: {
start: params.start,
end: params.end,
compositeQuery,
},
});
}
async getLogFields() {
return this.request({
method: 'GET',
url: '/api/v1/logs/fields',
});
}
async aggregateLogs(params) {
return this.request({
method: 'GET',
url: '/api/v1/logs/aggregate',
params,
});
}
// Live tail logs using Server-Sent Events
liveTailLogs(params, onLog, onError) {
const searchParams = new URLSearchParams();
if (params.q)
searchParams.append('q', params.q);
if (params.filters)
searchParams.append('filters', params.filters);
const url = `${this.baseURL}/api/v3/logs/livetail?${searchParams.toString()}`;
const eventSource = new eventsource_1.default(url, {
headers: {
'SIGNOZ-API-KEY': this.apiKey,
},
});
eventSource.onmessage = (event) => {
try {
const log = JSON.parse(event.data);
onLog(log);
}
catch (error) {
onError?.(error);
}
};
eventSource.onerror = (error) => {
onError?.(error);
};
return () => eventSource.close();
}
// ========== Dashboards ==========
async getDashboards() {
return this.request({
method: 'GET',
url: '/api/v1/dashboards',
});
}
async getDashboard(id) {
return this.request({
method: 'GET',
url: `/api/v1/dashboards/${id}`,
});
}
async createDashboard(dashboard) {
return this.request({
method: 'POST',
url: '/api/v1/dashboards',
data: dashboard,
});
}
async updateDashboard(id, dashboard) {
return this.request({
method: 'PUT',
url: `/api/v1/dashboards/${id}`,
data: dashboard,
});
}
async deleteDashboard(id) {
return this.request({
method: 'DELETE',
url: `/api/v1/dashboards/${id}`,
});
}
// ========== Alerts ==========
async getAlertRules() {
return this.request({
method: 'GET',
url: '/api/v1/rules',
});
}
async getAlertRule(id) {
return this.request({
method: 'GET',
url: `/api/v1/rules/${id}`,
});
}
async createAlertRule(rule) {
return this.request({
method: 'POST',
url: '/api/v1/rules',
data: rule,
});
}
async updateAlertRule(id, rule) {
return this.request({
method: 'PUT',
url: `/api/v1/rules/${id}`,
data: rule,
});
}
async deleteAlertRule(id) {
return this.request({
method: 'DELETE',
url: `/api/v1/rules/${id}`,
});
}
async testAlertRule(rule) {
return this.request({
method: 'POST',
url: '/api/v1/testRule',
data: rule,
});
}
async getActiveAlerts() {
return this.request({
method: 'GET',
url: '/api/v1/alerts',
});
}
// ========== Notification Channels ==========
async getNotificationChannels() {
return this.request({
method: 'GET',
url: '/api/v1/channels',
});
}
async createNotificationChannel(channel) {
return this.request({
method: 'POST',
url: '/api/v1/channels',
data: channel,
});
}
async testNotificationChannel(channel) {
return this.request({
method: 'POST',
url: '/api/v1/testChannel',
data: channel,
});
}
// ========== Infrastructure Monitoring ==========
async getHosts(params) {
return this.request({
method: 'POST',
url: '/api/v1/hosts/list',
data: params,
});
}
async getPods(params) {
return this.request({
method: 'POST',
url: '/api/v1/pods/list',
data: params,
});
}
async getHostAttributeKeys() {
return this.request({
method: 'GET',
url: '/api/v1/hosts/attribute_keys',
});
}
async getPodAttributeKeys() {
return this.request({
method: 'GET',
url: '/api/v1/pods/attribute_keys',
});
}
// ========== Metrics Explorer ==========
async getMetrics() {
return this.request({
method: 'POST',
url: '/api/v1/metrics',
});
}
async getMetricFilterKeys() {
return this.request({
method: 'GET',
url: '/api/v1/metrics/filters/keys',
});
}
async getMetricFilterValues(params) {
return this.request({
method: 'POST',
url: '/api/v1/metrics/filters/values',
data: params,
});
}
// ========== Enterprise Features ==========
async getActiveLicense() {
return this.request({
method: 'GET',
url: '/api/v3/licenses/active',
});
}
async activateLicense(key) {
return this.request({
method: 'POST',
url: '/api/v3/licenses',
data: { key },
});
}
// ========== WebSocket Connections ==========
connectQueryProgress(queryId, onProgress, onError) {
const wsUrl = this.baseURL.replace(/^http/, 'ws') + `/ws/query_progress?q=${queryId}`;
const ws = new ws_1.default(wsUrl, {
headers: {
'Sec-WebSocket-Protocol': this.apiKey,
},
});
ws.on('message', (data) => {
try {
const progress = JSON.parse(data.toString());
onProgress(progress);
}
catch (error) {
onError?.(error);
}
});
ws.on('error', (error) => {
onError?.(error);
});
return () => ws.close();
}
}
exports.SigNozApiClient = SigNozApiClient;
//# sourceMappingURL=client.js.map