argus-discord-analytics 0.3.0 → 0.4.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/dist/index.d.mts +122 -2
- package/dist/index.d.ts +122 -2
- package/dist/index.js +191 -7
- package/dist/index.mjs +191 -7
- package/package.json +1 -1
package/dist/index.d.mts
CHANGED
|
@@ -21,7 +21,7 @@
|
|
|
21
21
|
* argus.trackRevenue({ source: 'patreon', amount: 500, tier: 'Premium' });
|
|
22
22
|
* ```
|
|
23
23
|
*/
|
|
24
|
-
declare const SDK_VERSION = "0.
|
|
24
|
+
declare const SDK_VERSION = "0.4.0";
|
|
25
25
|
interface ArgusConfig {
|
|
26
26
|
/** Your Argus API key (starts with arg_live_ or arg_test_) */
|
|
27
27
|
apiKey: string;
|
|
@@ -75,6 +75,40 @@ interface HeartbeatConfig {
|
|
|
75
75
|
interval?: number;
|
|
76
76
|
/** Include latency measurement */
|
|
77
77
|
measureLatency?: boolean;
|
|
78
|
+
/** Shard ID for sharded bots */
|
|
79
|
+
shardId?: number;
|
|
80
|
+
/** Total number of shards */
|
|
81
|
+
shardCount?: number;
|
|
82
|
+
/** Guild count for this shard */
|
|
83
|
+
guildCount?: number;
|
|
84
|
+
}
|
|
85
|
+
interface GatewayEventConfig {
|
|
86
|
+
/** Shard ID the event occurred on */
|
|
87
|
+
shardId?: number;
|
|
88
|
+
/** Rate limit bucket (for rate_limit events) */
|
|
89
|
+
bucket?: string;
|
|
90
|
+
/** Retry after in ms (for rate_limit events) */
|
|
91
|
+
retryAfter?: number;
|
|
92
|
+
/** Additional metadata */
|
|
93
|
+
metadata?: Record<string, unknown>;
|
|
94
|
+
}
|
|
95
|
+
interface ResourceMetrics {
|
|
96
|
+
/** CPU usage percentage (0-100) */
|
|
97
|
+
cpuPercent?: number;
|
|
98
|
+
/** Total memory usage in MB */
|
|
99
|
+
memoryMb?: number;
|
|
100
|
+
/** Heap used in MB */
|
|
101
|
+
heapUsedMb?: number;
|
|
102
|
+
/** Heap total in MB */
|
|
103
|
+
heapTotalMb?: number;
|
|
104
|
+
/** Number of guilds/servers */
|
|
105
|
+
guildCount?: number;
|
|
106
|
+
/** Number of cached users */
|
|
107
|
+
cachedUsers?: number;
|
|
108
|
+
/** Number of cached channels */
|
|
109
|
+
cachedChannels?: number;
|
|
110
|
+
/** Shard ID (optional for per-shard metrics) */
|
|
111
|
+
shardId?: number;
|
|
78
112
|
}
|
|
79
113
|
interface ServerEvent {
|
|
80
114
|
type: 'server';
|
|
@@ -113,6 +147,9 @@ declare class Argus {
|
|
|
113
147
|
private botId;
|
|
114
148
|
private isHeartbeatEnabled;
|
|
115
149
|
private commandStartTimes;
|
|
150
|
+
private shardId;
|
|
151
|
+
private shardCount;
|
|
152
|
+
private guildCount;
|
|
116
153
|
constructor(apiKeyOrConfig: string | ArgusConfig);
|
|
117
154
|
private log;
|
|
118
155
|
private startFlushTimer;
|
|
@@ -331,6 +368,12 @@ declare class Argus {
|
|
|
331
368
|
*
|
|
332
369
|
* // Or customize the interval
|
|
333
370
|
* argus.startHeartbeat({ interval: 60000 }); // 1 minute
|
|
371
|
+
*
|
|
372
|
+
* // For sharded bots - track per-shard status
|
|
373
|
+
* argus.startHeartbeat({
|
|
374
|
+
* shardId: shard.id,
|
|
375
|
+
* shardCount: client.shard?.count || 1
|
|
376
|
+
* });
|
|
334
377
|
* ```
|
|
335
378
|
*/
|
|
336
379
|
startHeartbeat(config?: HeartbeatConfig): void;
|
|
@@ -342,6 +385,83 @@ declare class Argus {
|
|
|
342
385
|
* Send a single heartbeat ping
|
|
343
386
|
*/
|
|
344
387
|
private sendHeartbeat;
|
|
388
|
+
/**
|
|
389
|
+
* Track a gateway event (reconnect, rate limit, etc.)
|
|
390
|
+
*
|
|
391
|
+
* @example
|
|
392
|
+
* ```typescript
|
|
393
|
+
* // Track reconnects
|
|
394
|
+
* client.on('shardReconnecting', (shardId) => {
|
|
395
|
+
* argus.trackGatewayEvent('reconnect', { shardId });
|
|
396
|
+
* });
|
|
397
|
+
*
|
|
398
|
+
* // Track rate limits
|
|
399
|
+
* client.rest.on('rateLimited', (info) => {
|
|
400
|
+
* argus.trackGatewayEvent('rate_limit', {
|
|
401
|
+
* bucket: info.route,
|
|
402
|
+
* retryAfter: info.retryAfter,
|
|
403
|
+
* });
|
|
404
|
+
* });
|
|
405
|
+
* ```
|
|
406
|
+
*/
|
|
407
|
+
trackGatewayEvent(eventType: 'reconnect' | 'rate_limit' | 'ready' | 'resume' | 'disconnect' | 'death' | 'spawn', config?: GatewayEventConfig): Promise<void>;
|
|
408
|
+
/**
|
|
409
|
+
* Track resource usage (CPU, memory, cache sizes)
|
|
410
|
+
* Call this periodically (e.g., every 60 seconds) to monitor resource usage
|
|
411
|
+
*
|
|
412
|
+
* @example
|
|
413
|
+
* ```typescript
|
|
414
|
+
* // Track resources every minute
|
|
415
|
+
* setInterval(() => {
|
|
416
|
+
* argus.trackResources({
|
|
417
|
+
* memoryMb: process.memoryUsage().heapUsed / 1024 / 1024,
|
|
418
|
+
* guildCount: client.guilds.cache.size,
|
|
419
|
+
* cachedUsers: client.users.cache.size,
|
|
420
|
+
* });
|
|
421
|
+
* }, 60000);
|
|
422
|
+
* ```
|
|
423
|
+
*/
|
|
424
|
+
trackResources(metrics: ResourceMetrics): Promise<void>;
|
|
425
|
+
/**
|
|
426
|
+
* Attach to a Discord.js ShardingManager to auto-track shard events
|
|
427
|
+
*
|
|
428
|
+
* @example
|
|
429
|
+
* ```typescript
|
|
430
|
+
* const manager = new ShardingManager('./bot.js', { ... });
|
|
431
|
+
* argus.attachToShardManager(manager);
|
|
432
|
+
* manager.spawn();
|
|
433
|
+
* ```
|
|
434
|
+
*/
|
|
435
|
+
attachToShardManager(manager: {
|
|
436
|
+
on: (event: string, listener: (...args: unknown[]) => void) => void;
|
|
437
|
+
shardList?: number[];
|
|
438
|
+
totalShards?: number | 'auto';
|
|
439
|
+
}): void;
|
|
440
|
+
/**
|
|
441
|
+
* Set up automatic tracking for Discord.js client shard events
|
|
442
|
+
* Call this from within your bot process to track per-shard events
|
|
443
|
+
*
|
|
444
|
+
* @example
|
|
445
|
+
* ```typescript
|
|
446
|
+
* // In your bot.js that runs in each shard
|
|
447
|
+
* argus.attachToClient(client);
|
|
448
|
+
* ```
|
|
449
|
+
*/
|
|
450
|
+
attachToClient(client: {
|
|
451
|
+
on: (event: string, listener: (...args: unknown[]) => void) => void;
|
|
452
|
+
shard?: {
|
|
453
|
+
ids: number[];
|
|
454
|
+
count: number;
|
|
455
|
+
} | null;
|
|
456
|
+
guilds?: {
|
|
457
|
+
cache: {
|
|
458
|
+
size: number;
|
|
459
|
+
};
|
|
460
|
+
};
|
|
461
|
+
rest?: {
|
|
462
|
+
on: (event: string, listener: (...args: unknown[]) => void) => void;
|
|
463
|
+
};
|
|
464
|
+
}): void;
|
|
345
465
|
/**
|
|
346
466
|
* Start timing a command execution
|
|
347
467
|
* Call this at the beginning of your command handler
|
|
@@ -386,4 +506,4 @@ declare class Argus {
|
|
|
386
506
|
shutdown(): Promise<void>;
|
|
387
507
|
}
|
|
388
508
|
|
|
389
|
-
export { Argus, type ArgusConfig, type HeartbeatConfig, type RevenueEvent, SDK_VERSION, type ServerEvent, type TrackEvent, type TrackOptions, Argus as default };
|
|
509
|
+
export { Argus, type ArgusConfig, type GatewayEventConfig, type HeartbeatConfig, type ResourceMetrics, type RevenueEvent, SDK_VERSION, type ServerEvent, type TrackEvent, type TrackOptions, Argus as default };
|
package/dist/index.d.ts
CHANGED
|
@@ -21,7 +21,7 @@
|
|
|
21
21
|
* argus.trackRevenue({ source: 'patreon', amount: 500, tier: 'Premium' });
|
|
22
22
|
* ```
|
|
23
23
|
*/
|
|
24
|
-
declare const SDK_VERSION = "0.
|
|
24
|
+
declare const SDK_VERSION = "0.4.0";
|
|
25
25
|
interface ArgusConfig {
|
|
26
26
|
/** Your Argus API key (starts with arg_live_ or arg_test_) */
|
|
27
27
|
apiKey: string;
|
|
@@ -75,6 +75,40 @@ interface HeartbeatConfig {
|
|
|
75
75
|
interval?: number;
|
|
76
76
|
/** Include latency measurement */
|
|
77
77
|
measureLatency?: boolean;
|
|
78
|
+
/** Shard ID for sharded bots */
|
|
79
|
+
shardId?: number;
|
|
80
|
+
/** Total number of shards */
|
|
81
|
+
shardCount?: number;
|
|
82
|
+
/** Guild count for this shard */
|
|
83
|
+
guildCount?: number;
|
|
84
|
+
}
|
|
85
|
+
interface GatewayEventConfig {
|
|
86
|
+
/** Shard ID the event occurred on */
|
|
87
|
+
shardId?: number;
|
|
88
|
+
/** Rate limit bucket (for rate_limit events) */
|
|
89
|
+
bucket?: string;
|
|
90
|
+
/** Retry after in ms (for rate_limit events) */
|
|
91
|
+
retryAfter?: number;
|
|
92
|
+
/** Additional metadata */
|
|
93
|
+
metadata?: Record<string, unknown>;
|
|
94
|
+
}
|
|
95
|
+
interface ResourceMetrics {
|
|
96
|
+
/** CPU usage percentage (0-100) */
|
|
97
|
+
cpuPercent?: number;
|
|
98
|
+
/** Total memory usage in MB */
|
|
99
|
+
memoryMb?: number;
|
|
100
|
+
/** Heap used in MB */
|
|
101
|
+
heapUsedMb?: number;
|
|
102
|
+
/** Heap total in MB */
|
|
103
|
+
heapTotalMb?: number;
|
|
104
|
+
/** Number of guilds/servers */
|
|
105
|
+
guildCount?: number;
|
|
106
|
+
/** Number of cached users */
|
|
107
|
+
cachedUsers?: number;
|
|
108
|
+
/** Number of cached channels */
|
|
109
|
+
cachedChannels?: number;
|
|
110
|
+
/** Shard ID (optional for per-shard metrics) */
|
|
111
|
+
shardId?: number;
|
|
78
112
|
}
|
|
79
113
|
interface ServerEvent {
|
|
80
114
|
type: 'server';
|
|
@@ -113,6 +147,9 @@ declare class Argus {
|
|
|
113
147
|
private botId;
|
|
114
148
|
private isHeartbeatEnabled;
|
|
115
149
|
private commandStartTimes;
|
|
150
|
+
private shardId;
|
|
151
|
+
private shardCount;
|
|
152
|
+
private guildCount;
|
|
116
153
|
constructor(apiKeyOrConfig: string | ArgusConfig);
|
|
117
154
|
private log;
|
|
118
155
|
private startFlushTimer;
|
|
@@ -331,6 +368,12 @@ declare class Argus {
|
|
|
331
368
|
*
|
|
332
369
|
* // Or customize the interval
|
|
333
370
|
* argus.startHeartbeat({ interval: 60000 }); // 1 minute
|
|
371
|
+
*
|
|
372
|
+
* // For sharded bots - track per-shard status
|
|
373
|
+
* argus.startHeartbeat({
|
|
374
|
+
* shardId: shard.id,
|
|
375
|
+
* shardCount: client.shard?.count || 1
|
|
376
|
+
* });
|
|
334
377
|
* ```
|
|
335
378
|
*/
|
|
336
379
|
startHeartbeat(config?: HeartbeatConfig): void;
|
|
@@ -342,6 +385,83 @@ declare class Argus {
|
|
|
342
385
|
* Send a single heartbeat ping
|
|
343
386
|
*/
|
|
344
387
|
private sendHeartbeat;
|
|
388
|
+
/**
|
|
389
|
+
* Track a gateway event (reconnect, rate limit, etc.)
|
|
390
|
+
*
|
|
391
|
+
* @example
|
|
392
|
+
* ```typescript
|
|
393
|
+
* // Track reconnects
|
|
394
|
+
* client.on('shardReconnecting', (shardId) => {
|
|
395
|
+
* argus.trackGatewayEvent('reconnect', { shardId });
|
|
396
|
+
* });
|
|
397
|
+
*
|
|
398
|
+
* // Track rate limits
|
|
399
|
+
* client.rest.on('rateLimited', (info) => {
|
|
400
|
+
* argus.trackGatewayEvent('rate_limit', {
|
|
401
|
+
* bucket: info.route,
|
|
402
|
+
* retryAfter: info.retryAfter,
|
|
403
|
+
* });
|
|
404
|
+
* });
|
|
405
|
+
* ```
|
|
406
|
+
*/
|
|
407
|
+
trackGatewayEvent(eventType: 'reconnect' | 'rate_limit' | 'ready' | 'resume' | 'disconnect' | 'death' | 'spawn', config?: GatewayEventConfig): Promise<void>;
|
|
408
|
+
/**
|
|
409
|
+
* Track resource usage (CPU, memory, cache sizes)
|
|
410
|
+
* Call this periodically (e.g., every 60 seconds) to monitor resource usage
|
|
411
|
+
*
|
|
412
|
+
* @example
|
|
413
|
+
* ```typescript
|
|
414
|
+
* // Track resources every minute
|
|
415
|
+
* setInterval(() => {
|
|
416
|
+
* argus.trackResources({
|
|
417
|
+
* memoryMb: process.memoryUsage().heapUsed / 1024 / 1024,
|
|
418
|
+
* guildCount: client.guilds.cache.size,
|
|
419
|
+
* cachedUsers: client.users.cache.size,
|
|
420
|
+
* });
|
|
421
|
+
* }, 60000);
|
|
422
|
+
* ```
|
|
423
|
+
*/
|
|
424
|
+
trackResources(metrics: ResourceMetrics): Promise<void>;
|
|
425
|
+
/**
|
|
426
|
+
* Attach to a Discord.js ShardingManager to auto-track shard events
|
|
427
|
+
*
|
|
428
|
+
* @example
|
|
429
|
+
* ```typescript
|
|
430
|
+
* const manager = new ShardingManager('./bot.js', { ... });
|
|
431
|
+
* argus.attachToShardManager(manager);
|
|
432
|
+
* manager.spawn();
|
|
433
|
+
* ```
|
|
434
|
+
*/
|
|
435
|
+
attachToShardManager(manager: {
|
|
436
|
+
on: (event: string, listener: (...args: unknown[]) => void) => void;
|
|
437
|
+
shardList?: number[];
|
|
438
|
+
totalShards?: number | 'auto';
|
|
439
|
+
}): void;
|
|
440
|
+
/**
|
|
441
|
+
* Set up automatic tracking for Discord.js client shard events
|
|
442
|
+
* Call this from within your bot process to track per-shard events
|
|
443
|
+
*
|
|
444
|
+
* @example
|
|
445
|
+
* ```typescript
|
|
446
|
+
* // In your bot.js that runs in each shard
|
|
447
|
+
* argus.attachToClient(client);
|
|
448
|
+
* ```
|
|
449
|
+
*/
|
|
450
|
+
attachToClient(client: {
|
|
451
|
+
on: (event: string, listener: (...args: unknown[]) => void) => void;
|
|
452
|
+
shard?: {
|
|
453
|
+
ids: number[];
|
|
454
|
+
count: number;
|
|
455
|
+
} | null;
|
|
456
|
+
guilds?: {
|
|
457
|
+
cache: {
|
|
458
|
+
size: number;
|
|
459
|
+
};
|
|
460
|
+
};
|
|
461
|
+
rest?: {
|
|
462
|
+
on: (event: string, listener: (...args: unknown[]) => void) => void;
|
|
463
|
+
};
|
|
464
|
+
}): void;
|
|
345
465
|
/**
|
|
346
466
|
* Start timing a command execution
|
|
347
467
|
* Call this at the beginning of your command handler
|
|
@@ -386,4 +506,4 @@ declare class Argus {
|
|
|
386
506
|
shutdown(): Promise<void>;
|
|
387
507
|
}
|
|
388
508
|
|
|
389
|
-
export { Argus, type ArgusConfig, type HeartbeatConfig, type RevenueEvent, SDK_VERSION, type ServerEvent, type TrackEvent, type TrackOptions, Argus as default };
|
|
509
|
+
export { Argus, type ArgusConfig, type GatewayEventConfig, type HeartbeatConfig, type ResourceMetrics, type RevenueEvent, SDK_VERSION, type ServerEvent, type TrackEvent, type TrackOptions, Argus as default };
|
package/dist/index.js
CHANGED
|
@@ -25,7 +25,7 @@ __export(index_exports, {
|
|
|
25
25
|
default: () => index_default
|
|
26
26
|
});
|
|
27
27
|
module.exports = __toCommonJS(index_exports);
|
|
28
|
-
var SDK_VERSION = "0.
|
|
28
|
+
var SDK_VERSION = "0.4.0";
|
|
29
29
|
function hashString(str) {
|
|
30
30
|
let hash = 0;
|
|
31
31
|
for (let i = 0; i < str.length; i++) {
|
|
@@ -494,6 +494,12 @@ var Argus = class {
|
|
|
494
494
|
*
|
|
495
495
|
* // Or customize the interval
|
|
496
496
|
* argus.startHeartbeat({ interval: 60000 }); // 1 minute
|
|
497
|
+
*
|
|
498
|
+
* // For sharded bots - track per-shard status
|
|
499
|
+
* argus.startHeartbeat({
|
|
500
|
+
* shardId: shard.id,
|
|
501
|
+
* shardCount: client.shard?.count || 1
|
|
502
|
+
* });
|
|
497
503
|
* ```
|
|
498
504
|
*/
|
|
499
505
|
startHeartbeat(config) {
|
|
@@ -503,11 +509,21 @@ var Argus = class {
|
|
|
503
509
|
}
|
|
504
510
|
const interval = config?.interval || this.heartbeatInterval;
|
|
505
511
|
this.isHeartbeatEnabled = true;
|
|
512
|
+
if (config?.shardId !== void 0) {
|
|
513
|
+
this.shardId = config.shardId;
|
|
514
|
+
}
|
|
515
|
+
if (config?.shardCount !== void 0) {
|
|
516
|
+
this.shardCount = config.shardCount;
|
|
517
|
+
}
|
|
518
|
+
if (config?.guildCount !== void 0) {
|
|
519
|
+
this.guildCount = config.guildCount;
|
|
520
|
+
}
|
|
506
521
|
this.sendHeartbeat();
|
|
507
522
|
this.heartbeatTimer = setInterval(() => {
|
|
508
523
|
this.sendHeartbeat();
|
|
509
524
|
}, interval);
|
|
510
|
-
this.
|
|
525
|
+
const shardInfo = this.shardId !== void 0 ? ` (shard ${this.shardId}/${this.shardCount})` : "";
|
|
526
|
+
this.log(`Heartbeat started with ${interval}ms interval${shardInfo}`);
|
|
511
527
|
}
|
|
512
528
|
/**
|
|
513
529
|
* Stop sending heartbeat pings
|
|
@@ -526,26 +542,194 @@ var Argus = class {
|
|
|
526
542
|
async sendHeartbeat() {
|
|
527
543
|
const startTime = Date.now();
|
|
528
544
|
try {
|
|
529
|
-
const
|
|
545
|
+
const endpoint = this.shardId !== void 0 ? `${this.endpoint}/api/shard-heartbeat` : `${this.endpoint}/api/heartbeat`;
|
|
546
|
+
const body = { timestamp: startTime };
|
|
547
|
+
if (this.shardId !== void 0) {
|
|
548
|
+
body.shardId = this.shardId;
|
|
549
|
+
body.shardCount = this.shardCount || 1;
|
|
550
|
+
body.guildCount = this.guildCount;
|
|
551
|
+
}
|
|
552
|
+
const response = await fetch(endpoint, {
|
|
530
553
|
method: "POST",
|
|
531
554
|
headers: {
|
|
532
555
|
"Content-Type": "application/json",
|
|
533
556
|
"Authorization": `Bearer ${this.apiKey}`
|
|
534
557
|
},
|
|
535
|
-
body: JSON.stringify(
|
|
536
|
-
timestamp: startTime
|
|
537
|
-
})
|
|
558
|
+
body: JSON.stringify(body)
|
|
538
559
|
});
|
|
539
560
|
const latencyMs = Date.now() - startTime;
|
|
540
561
|
if (!response.ok) {
|
|
541
562
|
throw new Error(`HTTP ${response.status}: ${response.statusText}`);
|
|
542
563
|
}
|
|
543
|
-
this.
|
|
564
|
+
const shardInfo = this.shardId !== void 0 ? ` [shard ${this.shardId}]` : "";
|
|
565
|
+
this.log(`Heartbeat sent (${latencyMs}ms)${shardInfo}`);
|
|
544
566
|
} catch (error) {
|
|
545
567
|
this.log("Heartbeat failed:", error);
|
|
546
568
|
}
|
|
547
569
|
}
|
|
548
570
|
// ==========================================
|
|
571
|
+
// Gateway & Infrastructure Events
|
|
572
|
+
// ==========================================
|
|
573
|
+
/**
|
|
574
|
+
* Track a gateway event (reconnect, rate limit, etc.)
|
|
575
|
+
*
|
|
576
|
+
* @example
|
|
577
|
+
* ```typescript
|
|
578
|
+
* // Track reconnects
|
|
579
|
+
* client.on('shardReconnecting', (shardId) => {
|
|
580
|
+
* argus.trackGatewayEvent('reconnect', { shardId });
|
|
581
|
+
* });
|
|
582
|
+
*
|
|
583
|
+
* // Track rate limits
|
|
584
|
+
* client.rest.on('rateLimited', (info) => {
|
|
585
|
+
* argus.trackGatewayEvent('rate_limit', {
|
|
586
|
+
* bucket: info.route,
|
|
587
|
+
* retryAfter: info.retryAfter,
|
|
588
|
+
* });
|
|
589
|
+
* });
|
|
590
|
+
* ```
|
|
591
|
+
*/
|
|
592
|
+
async trackGatewayEvent(eventType, config) {
|
|
593
|
+
try {
|
|
594
|
+
const response = await fetch(`${this.endpoint}/api/infrastructure-events`, {
|
|
595
|
+
method: "POST",
|
|
596
|
+
headers: {
|
|
597
|
+
"Content-Type": "application/json",
|
|
598
|
+
"Authorization": `Bearer ${this.apiKey}`
|
|
599
|
+
},
|
|
600
|
+
body: JSON.stringify({
|
|
601
|
+
events: [{
|
|
602
|
+
type: eventType,
|
|
603
|
+
shardId: config?.shardId ?? this.shardId,
|
|
604
|
+
metadata: {
|
|
605
|
+
bucket: config?.bucket,
|
|
606
|
+
retryAfter: config?.retryAfter,
|
|
607
|
+
...config?.metadata
|
|
608
|
+
},
|
|
609
|
+
timestamp: Date.now()
|
|
610
|
+
}]
|
|
611
|
+
})
|
|
612
|
+
});
|
|
613
|
+
if (!response.ok) {
|
|
614
|
+
throw new Error(`HTTP ${response.status}: ${response.statusText}`);
|
|
615
|
+
}
|
|
616
|
+
this.log(`Gateway event tracked: ${eventType}`, config?.shardId !== void 0 ? `[shard ${config.shardId}]` : "");
|
|
617
|
+
} catch (error) {
|
|
618
|
+
this.log("Failed to track gateway event:", error);
|
|
619
|
+
}
|
|
620
|
+
}
|
|
621
|
+
/**
|
|
622
|
+
* Track resource usage (CPU, memory, cache sizes)
|
|
623
|
+
* Call this periodically (e.g., every 60 seconds) to monitor resource usage
|
|
624
|
+
*
|
|
625
|
+
* @example
|
|
626
|
+
* ```typescript
|
|
627
|
+
* // Track resources every minute
|
|
628
|
+
* setInterval(() => {
|
|
629
|
+
* argus.trackResources({
|
|
630
|
+
* memoryMb: process.memoryUsage().heapUsed / 1024 / 1024,
|
|
631
|
+
* guildCount: client.guilds.cache.size,
|
|
632
|
+
* cachedUsers: client.users.cache.size,
|
|
633
|
+
* });
|
|
634
|
+
* }, 60000);
|
|
635
|
+
* ```
|
|
636
|
+
*/
|
|
637
|
+
async trackResources(metrics) {
|
|
638
|
+
try {
|
|
639
|
+
const response = await fetch(`${this.endpoint}/api/resources`, {
|
|
640
|
+
method: "POST",
|
|
641
|
+
headers: {
|
|
642
|
+
"Content-Type": "application/json",
|
|
643
|
+
"Authorization": `Bearer ${this.apiKey}`
|
|
644
|
+
},
|
|
645
|
+
body: JSON.stringify({
|
|
646
|
+
cpuPercent: metrics.cpuPercent,
|
|
647
|
+
memoryMb: metrics.memoryMb,
|
|
648
|
+
heapUsedMb: metrics.heapUsedMb,
|
|
649
|
+
heapTotalMb: metrics.heapTotalMb,
|
|
650
|
+
guildCount: metrics.guildCount,
|
|
651
|
+
cachedUsers: metrics.cachedUsers,
|
|
652
|
+
cachedChannels: metrics.cachedChannels,
|
|
653
|
+
shardId: metrics.shardId ?? this.shardId
|
|
654
|
+
})
|
|
655
|
+
});
|
|
656
|
+
if (!response.ok) {
|
|
657
|
+
throw new Error(`HTTP ${response.status}: ${response.statusText}`);
|
|
658
|
+
}
|
|
659
|
+
this.log("Resource metrics tracked");
|
|
660
|
+
} catch (error) {
|
|
661
|
+
this.log("Failed to track resources:", error);
|
|
662
|
+
}
|
|
663
|
+
}
|
|
664
|
+
/**
|
|
665
|
+
* Attach to a Discord.js ShardingManager to auto-track shard events
|
|
666
|
+
*
|
|
667
|
+
* @example
|
|
668
|
+
* ```typescript
|
|
669
|
+
* const manager = new ShardingManager('./bot.js', { ... });
|
|
670
|
+
* argus.attachToShardManager(manager);
|
|
671
|
+
* manager.spawn();
|
|
672
|
+
* ```
|
|
673
|
+
*/
|
|
674
|
+
attachToShardManager(manager) {
|
|
675
|
+
this.log("Attaching to ShardingManager");
|
|
676
|
+
manager.on("shardCreate", (...args) => {
|
|
677
|
+
const shard = args[0];
|
|
678
|
+
this.trackGatewayEvent("spawn", { shardId: shard.id });
|
|
679
|
+
});
|
|
680
|
+
this.log("ShardingManager attached - spawn events will be tracked");
|
|
681
|
+
}
|
|
682
|
+
/**
|
|
683
|
+
* Set up automatic tracking for Discord.js client shard events
|
|
684
|
+
* Call this from within your bot process to track per-shard events
|
|
685
|
+
*
|
|
686
|
+
* @example
|
|
687
|
+
* ```typescript
|
|
688
|
+
* // In your bot.js that runs in each shard
|
|
689
|
+
* argus.attachToClient(client);
|
|
690
|
+
* ```
|
|
691
|
+
*/
|
|
692
|
+
attachToClient(client) {
|
|
693
|
+
if (client.shard) {
|
|
694
|
+
this.shardId = client.shard.ids[0];
|
|
695
|
+
this.shardCount = client.shard.count;
|
|
696
|
+
}
|
|
697
|
+
if (client.guilds?.cache) {
|
|
698
|
+
this.guildCount = client.guilds.cache.size;
|
|
699
|
+
}
|
|
700
|
+
client.on("ready", () => {
|
|
701
|
+
this.trackGatewayEvent("ready", { shardId: this.shardId });
|
|
702
|
+
});
|
|
703
|
+
client.on("shardReady", (...args) => {
|
|
704
|
+
const id = args[0];
|
|
705
|
+
this.trackGatewayEvent("ready", { shardId: id });
|
|
706
|
+
});
|
|
707
|
+
client.on("shardReconnecting", (...args) => {
|
|
708
|
+
const id = args[0];
|
|
709
|
+
this.trackGatewayEvent("reconnect", { shardId: id });
|
|
710
|
+
});
|
|
711
|
+
client.on("shardResume", (...args) => {
|
|
712
|
+
const id = args[0];
|
|
713
|
+
this.trackGatewayEvent("resume", { shardId: id });
|
|
714
|
+
});
|
|
715
|
+
client.on("shardDisconnect", (...args) => {
|
|
716
|
+
const id = args[1];
|
|
717
|
+
this.trackGatewayEvent("disconnect", { shardId: id });
|
|
718
|
+
});
|
|
719
|
+
if (client.rest) {
|
|
720
|
+
client.rest.on("rateLimited", (...args) => {
|
|
721
|
+
const info = args[0];
|
|
722
|
+
this.trackGatewayEvent("rate_limit", {
|
|
723
|
+
shardId: this.shardId,
|
|
724
|
+
bucket: info.route,
|
|
725
|
+
retryAfter: info.timeToReset,
|
|
726
|
+
metadata: { global: info.global }
|
|
727
|
+
});
|
|
728
|
+
});
|
|
729
|
+
}
|
|
730
|
+
this.log("Discord.js client attached - shard events will be tracked");
|
|
731
|
+
}
|
|
732
|
+
// ==========================================
|
|
549
733
|
// Latency Tracking
|
|
550
734
|
// ==========================================
|
|
551
735
|
/**
|
package/dist/index.mjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
// src/index.ts
|
|
2
|
-
var SDK_VERSION = "0.
|
|
2
|
+
var SDK_VERSION = "0.4.0";
|
|
3
3
|
function hashString(str) {
|
|
4
4
|
let hash = 0;
|
|
5
5
|
for (let i = 0; i < str.length; i++) {
|
|
@@ -468,6 +468,12 @@ var Argus = class {
|
|
|
468
468
|
*
|
|
469
469
|
* // Or customize the interval
|
|
470
470
|
* argus.startHeartbeat({ interval: 60000 }); // 1 minute
|
|
471
|
+
*
|
|
472
|
+
* // For sharded bots - track per-shard status
|
|
473
|
+
* argus.startHeartbeat({
|
|
474
|
+
* shardId: shard.id,
|
|
475
|
+
* shardCount: client.shard?.count || 1
|
|
476
|
+
* });
|
|
471
477
|
* ```
|
|
472
478
|
*/
|
|
473
479
|
startHeartbeat(config) {
|
|
@@ -477,11 +483,21 @@ var Argus = class {
|
|
|
477
483
|
}
|
|
478
484
|
const interval = config?.interval || this.heartbeatInterval;
|
|
479
485
|
this.isHeartbeatEnabled = true;
|
|
486
|
+
if (config?.shardId !== void 0) {
|
|
487
|
+
this.shardId = config.shardId;
|
|
488
|
+
}
|
|
489
|
+
if (config?.shardCount !== void 0) {
|
|
490
|
+
this.shardCount = config.shardCount;
|
|
491
|
+
}
|
|
492
|
+
if (config?.guildCount !== void 0) {
|
|
493
|
+
this.guildCount = config.guildCount;
|
|
494
|
+
}
|
|
480
495
|
this.sendHeartbeat();
|
|
481
496
|
this.heartbeatTimer = setInterval(() => {
|
|
482
497
|
this.sendHeartbeat();
|
|
483
498
|
}, interval);
|
|
484
|
-
this.
|
|
499
|
+
const shardInfo = this.shardId !== void 0 ? ` (shard ${this.shardId}/${this.shardCount})` : "";
|
|
500
|
+
this.log(`Heartbeat started with ${interval}ms interval${shardInfo}`);
|
|
485
501
|
}
|
|
486
502
|
/**
|
|
487
503
|
* Stop sending heartbeat pings
|
|
@@ -500,26 +516,194 @@ var Argus = class {
|
|
|
500
516
|
async sendHeartbeat() {
|
|
501
517
|
const startTime = Date.now();
|
|
502
518
|
try {
|
|
503
|
-
const
|
|
519
|
+
const endpoint = this.shardId !== void 0 ? `${this.endpoint}/api/shard-heartbeat` : `${this.endpoint}/api/heartbeat`;
|
|
520
|
+
const body = { timestamp: startTime };
|
|
521
|
+
if (this.shardId !== void 0) {
|
|
522
|
+
body.shardId = this.shardId;
|
|
523
|
+
body.shardCount = this.shardCount || 1;
|
|
524
|
+
body.guildCount = this.guildCount;
|
|
525
|
+
}
|
|
526
|
+
const response = await fetch(endpoint, {
|
|
504
527
|
method: "POST",
|
|
505
528
|
headers: {
|
|
506
529
|
"Content-Type": "application/json",
|
|
507
530
|
"Authorization": `Bearer ${this.apiKey}`
|
|
508
531
|
},
|
|
509
|
-
body: JSON.stringify(
|
|
510
|
-
timestamp: startTime
|
|
511
|
-
})
|
|
532
|
+
body: JSON.stringify(body)
|
|
512
533
|
});
|
|
513
534
|
const latencyMs = Date.now() - startTime;
|
|
514
535
|
if (!response.ok) {
|
|
515
536
|
throw new Error(`HTTP ${response.status}: ${response.statusText}`);
|
|
516
537
|
}
|
|
517
|
-
this.
|
|
538
|
+
const shardInfo = this.shardId !== void 0 ? ` [shard ${this.shardId}]` : "";
|
|
539
|
+
this.log(`Heartbeat sent (${latencyMs}ms)${shardInfo}`);
|
|
518
540
|
} catch (error) {
|
|
519
541
|
this.log("Heartbeat failed:", error);
|
|
520
542
|
}
|
|
521
543
|
}
|
|
522
544
|
// ==========================================
|
|
545
|
+
// Gateway & Infrastructure Events
|
|
546
|
+
// ==========================================
|
|
547
|
+
/**
|
|
548
|
+
* Track a gateway event (reconnect, rate limit, etc.)
|
|
549
|
+
*
|
|
550
|
+
* @example
|
|
551
|
+
* ```typescript
|
|
552
|
+
* // Track reconnects
|
|
553
|
+
* client.on('shardReconnecting', (shardId) => {
|
|
554
|
+
* argus.trackGatewayEvent('reconnect', { shardId });
|
|
555
|
+
* });
|
|
556
|
+
*
|
|
557
|
+
* // Track rate limits
|
|
558
|
+
* client.rest.on('rateLimited', (info) => {
|
|
559
|
+
* argus.trackGatewayEvent('rate_limit', {
|
|
560
|
+
* bucket: info.route,
|
|
561
|
+
* retryAfter: info.retryAfter,
|
|
562
|
+
* });
|
|
563
|
+
* });
|
|
564
|
+
* ```
|
|
565
|
+
*/
|
|
566
|
+
async trackGatewayEvent(eventType, config) {
|
|
567
|
+
try {
|
|
568
|
+
const response = await fetch(`${this.endpoint}/api/infrastructure-events`, {
|
|
569
|
+
method: "POST",
|
|
570
|
+
headers: {
|
|
571
|
+
"Content-Type": "application/json",
|
|
572
|
+
"Authorization": `Bearer ${this.apiKey}`
|
|
573
|
+
},
|
|
574
|
+
body: JSON.stringify({
|
|
575
|
+
events: [{
|
|
576
|
+
type: eventType,
|
|
577
|
+
shardId: config?.shardId ?? this.shardId,
|
|
578
|
+
metadata: {
|
|
579
|
+
bucket: config?.bucket,
|
|
580
|
+
retryAfter: config?.retryAfter,
|
|
581
|
+
...config?.metadata
|
|
582
|
+
},
|
|
583
|
+
timestamp: Date.now()
|
|
584
|
+
}]
|
|
585
|
+
})
|
|
586
|
+
});
|
|
587
|
+
if (!response.ok) {
|
|
588
|
+
throw new Error(`HTTP ${response.status}: ${response.statusText}`);
|
|
589
|
+
}
|
|
590
|
+
this.log(`Gateway event tracked: ${eventType}`, config?.shardId !== void 0 ? `[shard ${config.shardId}]` : "");
|
|
591
|
+
} catch (error) {
|
|
592
|
+
this.log("Failed to track gateway event:", error);
|
|
593
|
+
}
|
|
594
|
+
}
|
|
595
|
+
/**
|
|
596
|
+
* Track resource usage (CPU, memory, cache sizes)
|
|
597
|
+
* Call this periodically (e.g., every 60 seconds) to monitor resource usage
|
|
598
|
+
*
|
|
599
|
+
* @example
|
|
600
|
+
* ```typescript
|
|
601
|
+
* // Track resources every minute
|
|
602
|
+
* setInterval(() => {
|
|
603
|
+
* argus.trackResources({
|
|
604
|
+
* memoryMb: process.memoryUsage().heapUsed / 1024 / 1024,
|
|
605
|
+
* guildCount: client.guilds.cache.size,
|
|
606
|
+
* cachedUsers: client.users.cache.size,
|
|
607
|
+
* });
|
|
608
|
+
* }, 60000);
|
|
609
|
+
* ```
|
|
610
|
+
*/
|
|
611
|
+
async trackResources(metrics) {
|
|
612
|
+
try {
|
|
613
|
+
const response = await fetch(`${this.endpoint}/api/resources`, {
|
|
614
|
+
method: "POST",
|
|
615
|
+
headers: {
|
|
616
|
+
"Content-Type": "application/json",
|
|
617
|
+
"Authorization": `Bearer ${this.apiKey}`
|
|
618
|
+
},
|
|
619
|
+
body: JSON.stringify({
|
|
620
|
+
cpuPercent: metrics.cpuPercent,
|
|
621
|
+
memoryMb: metrics.memoryMb,
|
|
622
|
+
heapUsedMb: metrics.heapUsedMb,
|
|
623
|
+
heapTotalMb: metrics.heapTotalMb,
|
|
624
|
+
guildCount: metrics.guildCount,
|
|
625
|
+
cachedUsers: metrics.cachedUsers,
|
|
626
|
+
cachedChannels: metrics.cachedChannels,
|
|
627
|
+
shardId: metrics.shardId ?? this.shardId
|
|
628
|
+
})
|
|
629
|
+
});
|
|
630
|
+
if (!response.ok) {
|
|
631
|
+
throw new Error(`HTTP ${response.status}: ${response.statusText}`);
|
|
632
|
+
}
|
|
633
|
+
this.log("Resource metrics tracked");
|
|
634
|
+
} catch (error) {
|
|
635
|
+
this.log("Failed to track resources:", error);
|
|
636
|
+
}
|
|
637
|
+
}
|
|
638
|
+
/**
|
|
639
|
+
* Attach to a Discord.js ShardingManager to auto-track shard events
|
|
640
|
+
*
|
|
641
|
+
* @example
|
|
642
|
+
* ```typescript
|
|
643
|
+
* const manager = new ShardingManager('./bot.js', { ... });
|
|
644
|
+
* argus.attachToShardManager(manager);
|
|
645
|
+
* manager.spawn();
|
|
646
|
+
* ```
|
|
647
|
+
*/
|
|
648
|
+
attachToShardManager(manager) {
|
|
649
|
+
this.log("Attaching to ShardingManager");
|
|
650
|
+
manager.on("shardCreate", (...args) => {
|
|
651
|
+
const shard = args[0];
|
|
652
|
+
this.trackGatewayEvent("spawn", { shardId: shard.id });
|
|
653
|
+
});
|
|
654
|
+
this.log("ShardingManager attached - spawn events will be tracked");
|
|
655
|
+
}
|
|
656
|
+
/**
|
|
657
|
+
* Set up automatic tracking for Discord.js client shard events
|
|
658
|
+
* Call this from within your bot process to track per-shard events
|
|
659
|
+
*
|
|
660
|
+
* @example
|
|
661
|
+
* ```typescript
|
|
662
|
+
* // In your bot.js that runs in each shard
|
|
663
|
+
* argus.attachToClient(client);
|
|
664
|
+
* ```
|
|
665
|
+
*/
|
|
666
|
+
attachToClient(client) {
|
|
667
|
+
if (client.shard) {
|
|
668
|
+
this.shardId = client.shard.ids[0];
|
|
669
|
+
this.shardCount = client.shard.count;
|
|
670
|
+
}
|
|
671
|
+
if (client.guilds?.cache) {
|
|
672
|
+
this.guildCount = client.guilds.cache.size;
|
|
673
|
+
}
|
|
674
|
+
client.on("ready", () => {
|
|
675
|
+
this.trackGatewayEvent("ready", { shardId: this.shardId });
|
|
676
|
+
});
|
|
677
|
+
client.on("shardReady", (...args) => {
|
|
678
|
+
const id = args[0];
|
|
679
|
+
this.trackGatewayEvent("ready", { shardId: id });
|
|
680
|
+
});
|
|
681
|
+
client.on("shardReconnecting", (...args) => {
|
|
682
|
+
const id = args[0];
|
|
683
|
+
this.trackGatewayEvent("reconnect", { shardId: id });
|
|
684
|
+
});
|
|
685
|
+
client.on("shardResume", (...args) => {
|
|
686
|
+
const id = args[0];
|
|
687
|
+
this.trackGatewayEvent("resume", { shardId: id });
|
|
688
|
+
});
|
|
689
|
+
client.on("shardDisconnect", (...args) => {
|
|
690
|
+
const id = args[1];
|
|
691
|
+
this.trackGatewayEvent("disconnect", { shardId: id });
|
|
692
|
+
});
|
|
693
|
+
if (client.rest) {
|
|
694
|
+
client.rest.on("rateLimited", (...args) => {
|
|
695
|
+
const info = args[0];
|
|
696
|
+
this.trackGatewayEvent("rate_limit", {
|
|
697
|
+
shardId: this.shardId,
|
|
698
|
+
bucket: info.route,
|
|
699
|
+
retryAfter: info.timeToReset,
|
|
700
|
+
metadata: { global: info.global }
|
|
701
|
+
});
|
|
702
|
+
});
|
|
703
|
+
}
|
|
704
|
+
this.log("Discord.js client attached - shard events will be tracked");
|
|
705
|
+
}
|
|
706
|
+
// ==========================================
|
|
523
707
|
// Latency Tracking
|
|
524
708
|
// ==========================================
|
|
525
709
|
/**
|
package/package.json
CHANGED