You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 

155 lines
3.9 KiB

import { sendAnalyticWebhook, sendInfoWebhook, InfoAlert, AnalyticAlert, WebhookType } from './notification_service';
import * as _ from 'lodash';
import * as AnalyticUnit from '../models/analytic_unit_model';
import { Segment } from '../models/segment_model';
import { availableReporter } from '../utils/reporter';
export class Alert {
public enabled = true;
constructor(protected analyticUnit: AnalyticUnit.AnalyticUnit) {};
public receive(segment: Segment) {
if(this.enabled) {
const alert = this.makeAlert(segment);
sendAnalyticWebhook(alert);
}
};
protected makeAlert(segment): AnalyticAlert {
const alert: AnalyticAlert = {
type: WebhookType.DETECT,
analyticUnitType: this.analyticUnit.type,
analyticUnitName: this.analyticUnit.name,
analyticUnitId: this.analyticUnit.id,
grafanaUrl: this.analyticUnit.grafanaUrl,
from: segment.from,
to: segment.to
};
if(segment.params) {
alert.params = segment.params;
}
return alert;
}
}
class PatternAlert extends Alert {
private lastSentSegment: Segment;
public receive(segment: Segment) {
if(this.lastSentSegment === undefined || !segment.equals(this.lastSentSegment) ) {
this.lastSentSegment = segment;
if(this.enabled) {
sendAnalyticWebhook(this.makeAlert(segment));
}
}
}
};
class ThresholdAlert extends Alert {
EXPIRE_PERIOD_MS = 60000;
lastOccurence = 0;
public receive(segment: Segment) {
if(this.lastOccurence === 0) {
this.lastOccurence = segment.from;
if(this.enabled) {
sendAnalyticWebhook(this.makeAlert(segment));
}
} else {
if(segment.from - this.lastOccurence > this.EXPIRE_PERIOD_MS) {
if(this.enabled) {
console.log(`time between threshold occurences ${segment.from - this.lastOccurence}ms, send alert`);
sendAnalyticWebhook(this.makeAlert(segment));
}
}
this.lastOccurence = segment.from;
}
}
}
export class AlertService {
private _alerts: { [id: string]: Alert; };
private _alertingEnable: boolean;
private _grafanaAvailableReporter: Function;
constructor() {
this._alerts = {}
}
public receiveAlert(analyticUnit: AnalyticUnit.AnalyticUnit, segment: Segment) {
if(!this._alertingEnable) {
return;
}
let id = analyticUnit.id;
if(!_.has(this._alerts, id)) {
this.addAnalyticUnit(analyticUnit);
}
this._alerts[id].receive(segment);
};
public sendMsg(message: string, type: WebhookType, optionalInfo = {}) {
const now = Date.now();
const infoAlert: InfoAlert = {
message,
params: optionalInfo,
type,
from: now,
to: now
}
sendInfoWebhook(infoAlert);
}
public getGrafanaAvailableReporter() {
if(!this._grafanaAvailableReporter) {
this._grafanaAvailableReporter = availableReporter(
['Grafana available', WebhookType.RECOVERY],
['Grafana unavailable for pulling data', WebhookType.FAILURE],
this.sendMsg,
this.sendMsg
);
}
return this._grafanaAvailableReporter;
}
public getAvailableWebhook(recoveryMsg: string, failureMsg: string) {
return availableReporter(
[recoveryMsg, WebhookType.RECOVERY],
[failureMsg, WebhookType.FAILURE],
this.sendMsg,
this.sendMsg
);
}
public addAnalyticUnit(analyticUnit: AnalyticUnit.AnalyticUnit) {
let detector = AnalyticUnit.getDetectorByType(analyticUnit.type);
let alertsType = {};
alertsType[AnalyticUnit.DetectorType.THRESHOLD] = ThresholdAlert;
alertsType[AnalyticUnit.DetectorType.PATTERN] = PatternAlert;
this._alerts[analyticUnit.id] = new alertsType[detector](analyticUnit);
}
public removeAnalyticUnit(analyticUnitId: AnalyticUnit.AnalyticUnitId) {
delete this._alerts[analyticUnitId];
}
public stopAlerting() {
this._alertingEnable = false;
this._alerts = {};
}
public startAlerting() {
this._alertingEnable = true;
}
}