@a11ops/sdk
Version:
Official Node.js SDK for a11ops - Push notification infrastructure for critical alerts with log monitoring
201 lines (168 loc) • 5.49 kB
JavaScript
const axios = require('axios');
const A11opsLogMonitoring = require('./log-monitoring');
class A11ops {
constructor(apiKey, options = {}) {
if (!apiKey) {
throw new Error('API key is required');
}
this.apiKey = apiKey;
this.baseUrl = options.baseUrl || 'https://api.a11ops.com';
this.region = options.region || 'auto';
this.timeout = options.timeout || 30000;
this.retries = options.retries || 3;
this.retryDelay = options.retryDelay || 1000;
this.environment = options.environment || 'production';
this.release = options.release;
this.options = options;
this.client = axios.create({
baseURL: this.baseUrl,
timeout: this.timeout,
headers: {
'Content-Type': 'application/json',
'User-Agent': '@a11ops/sdk/1.2.0'
}
});
// Initialize log monitoring if enabled
if (options.logMonitoring !== false) {
this.logs = new A11opsLogMonitoring(this);
}
}
async alert(payload) {
if (!payload) {
throw new Error('Alert payload is required');
}
// Ensure payload has required fields
const alertPayload = {
title: payload.title || 'Alert',
message: payload.message || payload.body || '',
severity: payload.severity || 'info',
timestamp: payload.timestamp || new Date().toISOString(),
...payload
};
// Add region if specified
if (this.region !== 'auto') {
alertPayload.region = this.region;
}
return this._request(`/alerts/${this.apiKey}`, alertPayload);
}
async batchAlert(alerts) {
if (!Array.isArray(alerts) || alerts.length === 0) {
throw new Error('Alerts array is required and must not be empty');
}
const batchPayload = {
alerts: alerts.map(alert => ({
title: alert.title || 'Alert',
message: alert.message || alert.body || '',
severity: alert.severity || 'info',
timestamp: alert.timestamp || new Date().toISOString(),
...alert
}))
};
if (this.region !== 'auto') {
batchPayload.region = this.region;
}
return this._request(`/alerts/${this.apiKey}/batch`, batchPayload);
}
async getMetrics(options = {}) {
const params = new URLSearchParams();
if (options.workspaceId) params.append('workspaceId', options.workspaceId);
if (options.region) params.append('region', options.region);
if (options.startDate) params.append('startDate', options.startDate);
if (options.endDate) params.append('endDate', options.endDate);
return this._request(`/v1/metrics/delivery?${params.toString()}`, null, 'GET');
}
async getSLACompliance(options = {}) {
const params = new URLSearchParams();
if (options.workspaceId) params.append('workspaceId', options.workspaceId);
if (options.period) params.append('period', options.period);
return this._request(`/v1/metrics/sla?${params.toString()}`, null, 'GET');
}
async _request(endpoint, data, method = 'POST') {
let lastError;
for (let attempt = 0; attempt < this.retries; attempt++) {
try {
const response = await this.client({
method,
url: endpoint,
data,
headers: {
'X-API-Key': this.apiKey
}
});
return response.data;
} catch (error) {
lastError = error;
// Don't retry on client errors (4xx)
if (error.response && error.response.status >= 400 && error.response.status < 500) {
throw this._formatError(error);
}
// Exponential backoff for retries
if (attempt < this.retries - 1) {
const delay = this.retryDelay * Math.pow(2, attempt);
await new Promise(resolve => setTimeout(resolve, delay));
}
}
}
throw this._formatError(lastError);
}
_formatError(error) {
if (error.response) {
const err = new Error(error.response.data.message || `Request failed with status ${error.response.status}`);
err.status = error.response.status;
err.response = error.response.data;
return err;
} else if (error.request) {
const err = new Error('No response received from a11ops API');
err.code = 'ENORESPONSE';
return err;
} else {
return error;
}
}
// Convenience methods for log monitoring
captureError(error, options) {
if (!this.logs) {
throw new Error('Log monitoring not initialized');
}
return this.logs.captureError(error, options);
}
captureMessage(message, level, options) {
if (!this.logs) {
throw new Error('Log monitoring not initialized');
}
return this.logs.captureMessage(message, level, options);
}
captureLog(log, options) {
if (!this.logs) {
throw new Error('Log monitoring not initialized');
}
return this.logs.captureLog(log, options);
}
setUser(user) {
if (this.logs) {
this.logs.setUser(user);
}
}
setContext(key, value) {
if (this.logs) {
this.logs.setContext(key, value);
}
}
setTag(key, value) {
if (this.logs) {
this.logs.setTag(key, value);
}
}
addBreadcrumb(breadcrumb) {
if (this.logs) {
this.logs.addBreadcrumb(breadcrumb);
}
}
}
// Export the traditional class-based API
module.exports = A11ops;
// Also export the simple API
const { a11ops } = require('./simple');
module.exports.a11ops = a11ops;
// For ES6 imports
module.exports.default = A11ops;