@takentrade/takentrade-libs 3.0.0 → 3.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -0
- package/dist/auth/auth.interface.d.ts +8 -0
- package/dist/auth/auth.interface.js +2 -0
- package/dist/auth/decorators/get-user.decorator.d.ts +2 -0
- package/dist/auth/decorators/get-user.decorator.js +26 -0
- package/dist/auth/decorators/index.d.ts +1 -0
- package/dist/auth/decorators/index.js +1 -0
- package/dist/auth/index.d.ts +1 -0
- package/dist/auth/index.js +1 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1 -0
- package/dist/metrics/metrics.interface.d.ts +0 -53
- package/dist/metrics/metrics.interface.js +0 -12
- package/dist/monitoring/alerting.service.d.ts +82 -0
- package/dist/monitoring/alerting.service.js +290 -0
- package/dist/monitoring/index.d.ts +5 -0
- package/dist/monitoring/index.js +21 -0
- package/dist/monitoring/monitoring.interface.d.ts +102 -0
- package/dist/monitoring/monitoring.interface.js +10 -0
- package/dist/monitoring/monitoring.module.d.ts +8 -0
- package/dist/monitoring/monitoring.module.js +44 -0
- package/dist/monitoring/sentry.service.d.ts +65 -0
- package/dist/monitoring/sentry.service.js +218 -0
- package/dist/monitoring/uptime.service.d.ts +59 -0
- package/dist/monitoring/uptime.service.js +213 -0
- package/dist/resilience/circuit-breaker.interface.d.ts +0 -75
- package/dist/resilience/circuit-breaker.interface.js +0 -6
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/dist/utils/helpers/date.util.d.ts +8 -0
- package/dist/utils/helpers/date.util.js +30 -0
- package/dist/utils/helpers/decimal.util.d.ts +9 -0
- package/dist/utils/helpers/decimal.util.js +31 -0
- package/dist/utils/helpers/referral.util.d.ts +4 -0
- package/dist/utils/helpers/referral.util.js +53 -0
- package/dist/utils/helpers/role.util.d.ts +8 -0
- package/dist/utils/helpers/role.util.js +18 -0
- package/dist/utils/index.d.ts +4 -0
- package/dist/utils/index.js +4 -0
- package/package.json +4 -1
package/README.md
CHANGED
|
@@ -39,6 +39,7 @@ export class AppModule {}
|
|
|
39
39
|
| **RPC** | Request-response patterns for NATS | [docs/rpc.md](docs/rpc.md) |
|
|
40
40
|
| **Resilience** | Circuit breakers for fault tolerance | [docs/resilience.md](docs/resilience.md) |
|
|
41
41
|
| **Metrics** | Prometheus metrics collection | [docs/metrics.md](docs/metrics.md) |
|
|
42
|
+
| **Monitoring** | Error tracking, alerting, uptime monitoring | [docs/monitoring.md](docs/monitoring.md) |
|
|
42
43
|
| **Common** | Shared constants, enums, and utilities | [docs/common.md](docs/common.md) |
|
|
43
44
|
| **Utils** | DTOs, pipes, filters, and helpers | [docs/utils.md](docs/utils.md) |
|
|
44
45
|
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
import { TokenPayload } from '../auth.interface';
|
|
2
|
+
export declare const GetUser: (...dataOrPipes: (import("@nestjs/common").PipeTransform<any, any> | keyof TokenPayload | import("@nestjs/common").Type<import("@nestjs/common").PipeTransform<any, any>> | undefined)[]) => ParameterDecorator;
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.GetUser = void 0;
|
|
4
|
+
const common_1 = require("@nestjs/common");
|
|
5
|
+
exports.GetUser = (0, common_1.createParamDecorator)((data, ctx) => {
|
|
6
|
+
const request = ctx.switchToHttp().getRequest();
|
|
7
|
+
const user = request.user;
|
|
8
|
+
if (!user) {
|
|
9
|
+
throw new common_1.UnauthorizedException('Invalid credentials or account information');
|
|
10
|
+
}
|
|
11
|
+
if (!data) {
|
|
12
|
+
return user;
|
|
13
|
+
}
|
|
14
|
+
if (data === 'sub') {
|
|
15
|
+
const value = user.id || user.sub;
|
|
16
|
+
if (!value) {
|
|
17
|
+
throw new common_1.UnauthorizedException('User ID not found');
|
|
18
|
+
}
|
|
19
|
+
return value;
|
|
20
|
+
}
|
|
21
|
+
const value = user[data];
|
|
22
|
+
if (value === undefined) {
|
|
23
|
+
throw new common_1.UnauthorizedException(`User ${data} not found`);
|
|
24
|
+
}
|
|
25
|
+
return value;
|
|
26
|
+
});
|
|
@@ -16,3 +16,4 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
|
16
16
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
17
|
__exportStar(require("./public.decorator"), exports);
|
|
18
18
|
__exportStar(require("./roles.decorator"), exports);
|
|
19
|
+
__exportStar(require("./get-user.decorator"), exports);
|
package/dist/auth/index.d.ts
CHANGED
package/dist/auth/index.js
CHANGED
package/dist/index.d.ts
CHANGED
package/dist/index.js
CHANGED
|
@@ -1,92 +1,45 @@
|
|
|
1
1
|
import { Counter, Gauge, Histogram, Summary, CounterConfiguration, GaugeConfiguration, HistogramConfiguration, SummaryConfiguration } from 'prom-client';
|
|
2
|
-
/**
|
|
3
|
-
* Metric types supported by the metrics service
|
|
4
|
-
*/
|
|
5
2
|
export declare enum MetricType {
|
|
6
3
|
COUNTER = "counter",
|
|
7
4
|
GAUGE = "gauge",
|
|
8
5
|
HISTOGRAM = "histogram",
|
|
9
6
|
SUMMARY = "summary"
|
|
10
7
|
}
|
|
11
|
-
/**
|
|
12
|
-
* Configuration options for the metrics module
|
|
13
|
-
*/
|
|
14
8
|
export interface MetricsModuleOptions {
|
|
15
|
-
/**
|
|
16
|
-
* Enable default metrics collection (CPU, memory, etc.)
|
|
17
|
-
* @default true
|
|
18
|
-
*/
|
|
19
9
|
defaultMetrics?: boolean;
|
|
20
|
-
/**
|
|
21
|
-
* Prefix for all metric names
|
|
22
|
-
* @default ''
|
|
23
|
-
*/
|
|
24
10
|
prefix?: string;
|
|
25
|
-
/**
|
|
26
|
-
* Default labels to add to all metrics
|
|
27
|
-
* @default {}
|
|
28
|
-
*/
|
|
29
11
|
defaultLabels?: Record<string, string>;
|
|
30
|
-
/**
|
|
31
|
-
* Interval for collecting default metrics (in milliseconds)
|
|
32
|
-
* @default 10000
|
|
33
|
-
*/
|
|
34
12
|
defaultMetricsInterval?: number;
|
|
35
|
-
/**
|
|
36
|
-
* Enable circuit breaker metrics integration
|
|
37
|
-
* @default true
|
|
38
|
-
*/
|
|
39
13
|
circuitBreakerMetrics?: boolean;
|
|
40
14
|
}
|
|
41
|
-
/**
|
|
42
|
-
* Counter metric configuration
|
|
43
|
-
*/
|
|
44
15
|
export interface CounterConfig extends Omit<CounterConfiguration<string>, 'registers'> {
|
|
45
16
|
name: string;
|
|
46
17
|
help: string;
|
|
47
18
|
labelNames?: string[];
|
|
48
19
|
}
|
|
49
|
-
/**
|
|
50
|
-
* Gauge metric configuration
|
|
51
|
-
*/
|
|
52
20
|
export interface GaugeConfig extends Omit<GaugeConfiguration<string>, 'registers'> {
|
|
53
21
|
name: string;
|
|
54
22
|
help: string;
|
|
55
23
|
labelNames?: string[];
|
|
56
24
|
}
|
|
57
|
-
/**
|
|
58
|
-
* Histogram metric configuration
|
|
59
|
-
*/
|
|
60
25
|
export interface HistogramConfig extends Omit<HistogramConfiguration<string>, 'registers'> {
|
|
61
26
|
name: string;
|
|
62
27
|
help: string;
|
|
63
28
|
labelNames?: string[];
|
|
64
29
|
buckets?: number[];
|
|
65
30
|
}
|
|
66
|
-
/**
|
|
67
|
-
* Summary metric configuration
|
|
68
|
-
*/
|
|
69
31
|
export interface SummaryConfig extends Omit<SummaryConfiguration<string>, 'registers'> {
|
|
70
32
|
name: string;
|
|
71
33
|
help: string;
|
|
72
34
|
labelNames?: string[];
|
|
73
35
|
percentiles?: number[];
|
|
74
36
|
}
|
|
75
|
-
/**
|
|
76
|
-
* Metric instance types
|
|
77
|
-
*/
|
|
78
37
|
export type MetricInstance = Counter<string> | Gauge<string> | Histogram<string> | Summary<string>;
|
|
79
|
-
/**
|
|
80
|
-
* Metric registry entry
|
|
81
|
-
*/
|
|
82
38
|
export interface MetricEntry {
|
|
83
39
|
type: MetricType;
|
|
84
40
|
metric: MetricInstance;
|
|
85
41
|
config: CounterConfig | GaugeConfig | HistogramConfig | SummaryConfig;
|
|
86
42
|
}
|
|
87
|
-
/**
|
|
88
|
-
* Circuit breaker metric names
|
|
89
|
-
*/
|
|
90
43
|
export declare const CIRCUIT_BREAKER_METRICS: {
|
|
91
44
|
readonly STATE: "circuit_breaker_state";
|
|
92
45
|
readonly CALLS_TOTAL: "circuit_breaker_calls_total";
|
|
@@ -96,11 +49,5 @@ export declare const CIRCUIT_BREAKER_METRICS: {
|
|
|
96
49
|
readonly REJECTS_TOTAL: "circuit_breaker_rejects_total";
|
|
97
50
|
readonly TIMEOUTS_TOTAL: "circuit_breaker_timeouts_total";
|
|
98
51
|
};
|
|
99
|
-
/**
|
|
100
|
-
* Default histogram buckets for latency metrics (in seconds)
|
|
101
|
-
*/
|
|
102
52
|
export declare const DEFAULT_LATENCY_BUCKETS: number[];
|
|
103
|
-
/**
|
|
104
|
-
* Default summary percentiles
|
|
105
|
-
*/
|
|
106
53
|
export declare const DEFAULT_PERCENTILES: number[];
|
|
@@ -1,9 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.DEFAULT_PERCENTILES = exports.DEFAULT_LATENCY_BUCKETS = exports.CIRCUIT_BREAKER_METRICS = exports.MetricType = void 0;
|
|
4
|
-
/**
|
|
5
|
-
* Metric types supported by the metrics service
|
|
6
|
-
*/
|
|
7
4
|
var MetricType;
|
|
8
5
|
(function (MetricType) {
|
|
9
6
|
MetricType["COUNTER"] = "counter";
|
|
@@ -11,9 +8,6 @@ var MetricType;
|
|
|
11
8
|
MetricType["HISTOGRAM"] = "histogram";
|
|
12
9
|
MetricType["SUMMARY"] = "summary";
|
|
13
10
|
})(MetricType || (exports.MetricType = MetricType = {}));
|
|
14
|
-
/**
|
|
15
|
-
* Circuit breaker metric names
|
|
16
|
-
*/
|
|
17
11
|
exports.CIRCUIT_BREAKER_METRICS = {
|
|
18
12
|
STATE: 'circuit_breaker_state',
|
|
19
13
|
CALLS_TOTAL: 'circuit_breaker_calls_total',
|
|
@@ -23,13 +17,7 @@ exports.CIRCUIT_BREAKER_METRICS = {
|
|
|
23
17
|
REJECTS_TOTAL: 'circuit_breaker_rejects_total',
|
|
24
18
|
TIMEOUTS_TOTAL: 'circuit_breaker_timeouts_total',
|
|
25
19
|
};
|
|
26
|
-
/**
|
|
27
|
-
* Default histogram buckets for latency metrics (in seconds)
|
|
28
|
-
*/
|
|
29
20
|
exports.DEFAULT_LATENCY_BUCKETS = [
|
|
30
21
|
0.005, 0.01, 0.025, 0.05, 0.1, 0.25, 0.5, 1, 2.5, 5, 10,
|
|
31
22
|
];
|
|
32
|
-
/**
|
|
33
|
-
* Default summary percentiles
|
|
34
|
-
*/
|
|
35
23
|
exports.DEFAULT_PERCENTILES = [0.5, 0.9, 0.95, 0.99];
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
import { Alert, AlertRule, AlertingConfig } from './monitoring.interface';
|
|
2
|
+
/**
|
|
3
|
+
* Alerting Service
|
|
4
|
+
*
|
|
5
|
+
* Provides multi-channel alerting with rule engine and deduplication
|
|
6
|
+
*/
|
|
7
|
+
export declare class AlertingService {
|
|
8
|
+
private readonly logger;
|
|
9
|
+
private channels;
|
|
10
|
+
private rules;
|
|
11
|
+
private alertHistory;
|
|
12
|
+
private config;
|
|
13
|
+
constructor(config?: AlertingConfig);
|
|
14
|
+
/**
|
|
15
|
+
* Initialize alert channels
|
|
16
|
+
*/
|
|
17
|
+
private initializeChannels;
|
|
18
|
+
/**
|
|
19
|
+
* Initialize alert rules
|
|
20
|
+
*/
|
|
21
|
+
private initializeRules;
|
|
22
|
+
/**
|
|
23
|
+
* Register an alert rule
|
|
24
|
+
*/
|
|
25
|
+
registerRule(rule: AlertRule): void;
|
|
26
|
+
/**
|
|
27
|
+
* Send an alert
|
|
28
|
+
*/
|
|
29
|
+
sendAlert(alert: Alert): Promise<void>;
|
|
30
|
+
/**
|
|
31
|
+
* Evaluate alert rules
|
|
32
|
+
*/
|
|
33
|
+
evaluateRules(metrics: any): Promise<void>;
|
|
34
|
+
/**
|
|
35
|
+
* Send alert to specific channel
|
|
36
|
+
*/
|
|
37
|
+
private sendToChannel;
|
|
38
|
+
/**
|
|
39
|
+
* Send alert to Slack
|
|
40
|
+
*/
|
|
41
|
+
private sendToSlack;
|
|
42
|
+
/**
|
|
43
|
+
* Send alert to email
|
|
44
|
+
*/
|
|
45
|
+
private sendToEmail;
|
|
46
|
+
/**
|
|
47
|
+
* Send alert to webhook
|
|
48
|
+
*/
|
|
49
|
+
private sendToWebhook;
|
|
50
|
+
/**
|
|
51
|
+
* Send alert to PagerDuty
|
|
52
|
+
*/
|
|
53
|
+
private sendToPagerDuty;
|
|
54
|
+
/**
|
|
55
|
+
* Evaluate alert condition
|
|
56
|
+
*/
|
|
57
|
+
private evaluateCondition;
|
|
58
|
+
/**
|
|
59
|
+
* Interpolate message template
|
|
60
|
+
*/
|
|
61
|
+
private interpolateMessage;
|
|
62
|
+
/**
|
|
63
|
+
* Check if alert is throttled
|
|
64
|
+
*/
|
|
65
|
+
private isThrottled;
|
|
66
|
+
/**
|
|
67
|
+
* Generate alert ID
|
|
68
|
+
*/
|
|
69
|
+
private generateAlertId;
|
|
70
|
+
/**
|
|
71
|
+
* Get severity color for Slack
|
|
72
|
+
*/
|
|
73
|
+
private getSeverityColor;
|
|
74
|
+
/**
|
|
75
|
+
* Get alert history
|
|
76
|
+
*/
|
|
77
|
+
getAlertHistory(): Map<string, Date>;
|
|
78
|
+
/**
|
|
79
|
+
* Clear alert history
|
|
80
|
+
*/
|
|
81
|
+
clearAlertHistory(): void;
|
|
82
|
+
}
|
|
@@ -0,0 +1,290 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
|
3
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
4
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
5
|
+
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
6
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
7
|
+
};
|
|
8
|
+
var AlertingService_1;
|
|
9
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
10
|
+
exports.AlertingService = void 0;
|
|
11
|
+
const common_1 = require("@nestjs/common");
|
|
12
|
+
const monitoring_interface_1 = require("./monitoring.interface");
|
|
13
|
+
/**
|
|
14
|
+
* Alerting Service
|
|
15
|
+
*
|
|
16
|
+
* Provides multi-channel alerting with rule engine and deduplication
|
|
17
|
+
*/
|
|
18
|
+
let AlertingService = AlertingService_1 = class AlertingService {
|
|
19
|
+
logger = new common_1.Logger(AlertingService_1.name);
|
|
20
|
+
channels = new Map();
|
|
21
|
+
rules = new Map();
|
|
22
|
+
alertHistory = new Map();
|
|
23
|
+
config;
|
|
24
|
+
constructor(config) {
|
|
25
|
+
this.config = config || { channels: [] };
|
|
26
|
+
this.initializeChannels();
|
|
27
|
+
this.initializeRules();
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Initialize alert channels
|
|
31
|
+
*/
|
|
32
|
+
initializeChannels() {
|
|
33
|
+
if (!this.config.channels) {
|
|
34
|
+
return;
|
|
35
|
+
}
|
|
36
|
+
for (const channel of this.config.channels) {
|
|
37
|
+
const name = channel.name || channel.type;
|
|
38
|
+
this.channels.set(name, {
|
|
39
|
+
...channel,
|
|
40
|
+
enabled: channel.enabled ?? true,
|
|
41
|
+
});
|
|
42
|
+
this.logger.log(`Alert channel '${name}' registered`);
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Initialize alert rules
|
|
47
|
+
*/
|
|
48
|
+
initializeRules() {
|
|
49
|
+
if (!this.config.rules) {
|
|
50
|
+
return;
|
|
51
|
+
}
|
|
52
|
+
for (const rule of this.config.rules) {
|
|
53
|
+
this.registerRule(rule);
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Register an alert rule
|
|
58
|
+
*/
|
|
59
|
+
registerRule(rule) {
|
|
60
|
+
this.rules.set(rule.name, {
|
|
61
|
+
...rule,
|
|
62
|
+
enabled: rule.enabled ?? true,
|
|
63
|
+
throttle: rule.throttle ?? 300000, // 5 minutes default
|
|
64
|
+
});
|
|
65
|
+
this.logger.log(`Alert rule '${rule.name}' registered`);
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* Send an alert
|
|
69
|
+
*/
|
|
70
|
+
async sendAlert(alert) {
|
|
71
|
+
const alertId = alert.id || this.generateAlertId(alert);
|
|
72
|
+
// Check throttling
|
|
73
|
+
if (this.isThrottled(alertId)) {
|
|
74
|
+
this.logger.debug(`Alert '${alertId}' is throttled, skipping`);
|
|
75
|
+
return;
|
|
76
|
+
}
|
|
77
|
+
// Add timestamp
|
|
78
|
+
const fullAlert = {
|
|
79
|
+
...alert,
|
|
80
|
+
id: alertId,
|
|
81
|
+
timestamp: alert.timestamp || new Date(),
|
|
82
|
+
};
|
|
83
|
+
// Send to all enabled channels
|
|
84
|
+
const promises = [];
|
|
85
|
+
for (const [name, channel] of this.channels.entries()) {
|
|
86
|
+
if (channel.enabled) {
|
|
87
|
+
promises.push(this.sendToChannel(fullAlert, channel));
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
await Promise.allSettled(promises);
|
|
91
|
+
// Update alert history
|
|
92
|
+
this.alertHistory.set(alertId, new Date());
|
|
93
|
+
}
|
|
94
|
+
/**
|
|
95
|
+
* Evaluate alert rules
|
|
96
|
+
*/
|
|
97
|
+
async evaluateRules(metrics) {
|
|
98
|
+
for (const [name, rule] of this.rules.entries()) {
|
|
99
|
+
if (!rule.enabled) {
|
|
100
|
+
continue;
|
|
101
|
+
}
|
|
102
|
+
try {
|
|
103
|
+
const shouldAlert = this.evaluateCondition(rule.condition, metrics);
|
|
104
|
+
if (shouldAlert) {
|
|
105
|
+
await this.sendAlert({
|
|
106
|
+
title: rule.name,
|
|
107
|
+
message: this.interpolateMessage(rule.message, metrics),
|
|
108
|
+
severity: rule.severity,
|
|
109
|
+
source: 'rule-engine',
|
|
110
|
+
metadata: { rule: name, metrics },
|
|
111
|
+
});
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
catch (error) {
|
|
115
|
+
this.logger.error(`Error evaluating rule '${name}':`, error);
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
/**
|
|
120
|
+
* Send alert to specific channel
|
|
121
|
+
*/
|
|
122
|
+
async sendToChannel(alert, channel) {
|
|
123
|
+
try {
|
|
124
|
+
switch (channel.type) {
|
|
125
|
+
case 'slack':
|
|
126
|
+
await this.sendToSlack(alert, channel);
|
|
127
|
+
break;
|
|
128
|
+
case 'email':
|
|
129
|
+
await this.sendToEmail(alert, channel);
|
|
130
|
+
break;
|
|
131
|
+
case 'webhook':
|
|
132
|
+
await this.sendToWebhook(alert, channel);
|
|
133
|
+
break;
|
|
134
|
+
case 'pagerduty':
|
|
135
|
+
await this.sendToPagerDuty(alert, channel);
|
|
136
|
+
break;
|
|
137
|
+
default:
|
|
138
|
+
this.logger.warn(`Unknown channel type: ${channel.type}`);
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
catch (error) {
|
|
142
|
+
this.logger.error(`Failed to send alert to ${channel.type}:`, error);
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
/**
|
|
146
|
+
* Send alert to Slack
|
|
147
|
+
*/
|
|
148
|
+
async sendToSlack(alert, channel) {
|
|
149
|
+
if (!channel.webhookUrl) {
|
|
150
|
+
throw new Error('Slack webhook URL not configured');
|
|
151
|
+
}
|
|
152
|
+
const color = this.getSeverityColor(alert.severity);
|
|
153
|
+
const payload = {
|
|
154
|
+
attachments: [
|
|
155
|
+
{
|
|
156
|
+
color,
|
|
157
|
+
title: alert.title,
|
|
158
|
+
text: alert.message,
|
|
159
|
+
fields: [
|
|
160
|
+
{
|
|
161
|
+
title: 'Severity',
|
|
162
|
+
value: alert.severity.toUpperCase(),
|
|
163
|
+
short: true,
|
|
164
|
+
},
|
|
165
|
+
{
|
|
166
|
+
title: 'Source',
|
|
167
|
+
value: alert.source || 'Unknown',
|
|
168
|
+
short: true,
|
|
169
|
+
},
|
|
170
|
+
{
|
|
171
|
+
title: 'Time',
|
|
172
|
+
value: alert.timestamp?.toISOString() || new Date().toISOString(),
|
|
173
|
+
short: false,
|
|
174
|
+
},
|
|
175
|
+
],
|
|
176
|
+
},
|
|
177
|
+
],
|
|
178
|
+
};
|
|
179
|
+
const response = await fetch(channel.webhookUrl, {
|
|
180
|
+
method: 'POST',
|
|
181
|
+
headers: { 'Content-Type': 'application/json' },
|
|
182
|
+
body: JSON.stringify(payload),
|
|
183
|
+
});
|
|
184
|
+
if (!response.ok) {
|
|
185
|
+
throw new Error(`Slack API error: ${response.statusText}`);
|
|
186
|
+
}
|
|
187
|
+
this.logger.debug(`Alert sent to Slack: ${alert.title}`);
|
|
188
|
+
}
|
|
189
|
+
/**
|
|
190
|
+
* Send alert to email
|
|
191
|
+
*/
|
|
192
|
+
async sendToEmail(alert, channel) {
|
|
193
|
+
// This would integrate with your email service
|
|
194
|
+
// For now, just log
|
|
195
|
+
this.logger.log(`Email alert would be sent to: ${channel.recipients?.join(', ')}`);
|
|
196
|
+
this.logger.log(`Subject: ${alert.title}`);
|
|
197
|
+
this.logger.log(`Body: ${alert.message}`);
|
|
198
|
+
}
|
|
199
|
+
/**
|
|
200
|
+
* Send alert to webhook
|
|
201
|
+
*/
|
|
202
|
+
async sendToWebhook(alert, channel) {
|
|
203
|
+
if (!channel.webhookUrl) {
|
|
204
|
+
throw new Error('Webhook URL not configured');
|
|
205
|
+
}
|
|
206
|
+
const response = await fetch(channel.webhookUrl, {
|
|
207
|
+
method: 'POST',
|
|
208
|
+
headers: { 'Content-Type': 'application/json' },
|
|
209
|
+
body: JSON.stringify(alert),
|
|
210
|
+
});
|
|
211
|
+
if (!response.ok) {
|
|
212
|
+
throw new Error(`Webhook error: ${response.statusText}`);
|
|
213
|
+
}
|
|
214
|
+
this.logger.debug(`Alert sent to webhook: ${alert.title}`);
|
|
215
|
+
}
|
|
216
|
+
/**
|
|
217
|
+
* Send alert to PagerDuty
|
|
218
|
+
*/
|
|
219
|
+
async sendToPagerDuty(alert, channel) {
|
|
220
|
+
// PagerDuty integration would go here
|
|
221
|
+
this.logger.log(`PagerDuty alert: ${alert.title}`);
|
|
222
|
+
}
|
|
223
|
+
/**
|
|
224
|
+
* Evaluate alert condition
|
|
225
|
+
*/
|
|
226
|
+
evaluateCondition(condition, metrics) {
|
|
227
|
+
if (typeof condition === 'function') {
|
|
228
|
+
return condition(metrics);
|
|
229
|
+
}
|
|
230
|
+
// Simple expression evaluation (extend as needed)
|
|
231
|
+
// For now, just return false for string conditions
|
|
232
|
+
return false;
|
|
233
|
+
}
|
|
234
|
+
/**
|
|
235
|
+
* Interpolate message template
|
|
236
|
+
*/
|
|
237
|
+
interpolateMessage(template, data) {
|
|
238
|
+
return template.replace(/\{\{(\w+)\}\}/g, (match, key) => {
|
|
239
|
+
return data[key] || match;
|
|
240
|
+
});
|
|
241
|
+
}
|
|
242
|
+
/**
|
|
243
|
+
* Check if alert is throttled
|
|
244
|
+
*/
|
|
245
|
+
isThrottled(alertId) {
|
|
246
|
+
const lastSent = this.alertHistory.get(alertId);
|
|
247
|
+
if (!lastSent) {
|
|
248
|
+
return false;
|
|
249
|
+
}
|
|
250
|
+
const throttleDuration = 300000; // 5 minutes default
|
|
251
|
+
const elapsed = Date.now() - lastSent.getTime();
|
|
252
|
+
return elapsed < throttleDuration;
|
|
253
|
+
}
|
|
254
|
+
/**
|
|
255
|
+
* Generate alert ID
|
|
256
|
+
*/
|
|
257
|
+
generateAlertId(alert) {
|
|
258
|
+
const parts = [alert.title, alert.severity, alert.source].filter(Boolean);
|
|
259
|
+
return parts.join(':').toLowerCase().replace(/\s+/g, '-');
|
|
260
|
+
}
|
|
261
|
+
/**
|
|
262
|
+
* Get severity color for Slack
|
|
263
|
+
*/
|
|
264
|
+
getSeverityColor(severity) {
|
|
265
|
+
const colors = {
|
|
266
|
+
[monitoring_interface_1.AlertSeverity.INFO]: '#36a64f',
|
|
267
|
+
[monitoring_interface_1.AlertSeverity.WARNING]: '#ff9900',
|
|
268
|
+
[monitoring_interface_1.AlertSeverity.ERROR]: '#ff0000',
|
|
269
|
+
[monitoring_interface_1.AlertSeverity.CRITICAL]: '#8b0000',
|
|
270
|
+
};
|
|
271
|
+
return colors[severity] || '#808080';
|
|
272
|
+
}
|
|
273
|
+
/**
|
|
274
|
+
* Get alert history
|
|
275
|
+
*/
|
|
276
|
+
getAlertHistory() {
|
|
277
|
+
return new Map(this.alertHistory);
|
|
278
|
+
}
|
|
279
|
+
/**
|
|
280
|
+
* Clear alert history
|
|
281
|
+
*/
|
|
282
|
+
clearAlertHistory() {
|
|
283
|
+
this.alertHistory.clear();
|
|
284
|
+
this.logger.log('Alert history cleared');
|
|
285
|
+
}
|
|
286
|
+
};
|
|
287
|
+
exports.AlertingService = AlertingService;
|
|
288
|
+
exports.AlertingService = AlertingService = AlertingService_1 = __decorate([
|
|
289
|
+
(0, common_1.Injectable)()
|
|
290
|
+
], AlertingService);
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
14
|
+
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
15
|
+
};
|
|
16
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
+
__exportStar(require("./monitoring.interface"), exports);
|
|
18
|
+
__exportStar(require("./sentry.service"), exports);
|
|
19
|
+
__exportStar(require("./alerting.service"), exports);
|
|
20
|
+
__exportStar(require("./uptime.service"), exports);
|
|
21
|
+
__exportStar(require("./monitoring.module"), exports);
|