@gazzehamine/armada-watch-agent 1.0.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/.env.example ADDED
@@ -0,0 +1,10 @@
1
+ # Agent Configuration
2
+ SERVER_URL=http://your-monitoring-server:4000
3
+ INSTANCE_NAME=My EC2 Instance
4
+ REGION=us-east-1
5
+
6
+ # Collection interval in seconds
7
+ COLLECTION_INTERVAL=10
8
+
9
+ # Optional: Set custom instance ID (defaults to hostname)
10
+ # INSTANCE_ID=i-1234567890abcdef0
package/README.md ADDED
@@ -0,0 +1,138 @@
1
+ # Armada Watch Agent
2
+
3
+ Lightweight monitoring agent for EC2 instances. Collects and sends system metrics to your Armada Watch monitoring server.
4
+
5
+ ## Installation
6
+
7
+ ### Via NPM (Recommended)
8
+
9
+ ```bash
10
+ npm install -g @gazzehamine/armada-watch-agent
11
+ ```
12
+
13
+ ## Quick Start
14
+
15
+ ### 1. Set Environment Variables
16
+
17
+ Create a `.env` file:
18
+
19
+ ```bash
20
+ SERVER_URL=http://your-monitoring-server:4000
21
+ INSTANCE_NAME=Production Web Server
22
+ REGION=us-east-1
23
+ COLLECTION_INTERVAL=10
24
+ ```
25
+
26
+ Or set them directly:
27
+
28
+ ```bash
29
+ export SERVER_URL=http://your-monitoring-server:4000
30
+ export INSTANCE_NAME="Production Web Server"
31
+ export REGION=us-east-1
32
+ export COLLECTION_INTERVAL=10
33
+ ```
34
+
35
+ ### 2. Run the Agent
36
+
37
+ ```bash
38
+ # If installed via npm
39
+ armada-watch-agent
40
+
41
+ # Or with npx
42
+ npx @gazzehamine/armada-watch-agent
43
+
44
+ # If built from source
45
+ npm start
46
+ ```
47
+
48
+ ### 3. Run as a Service (Production)
49
+
50
+ **Using PM2:**
51
+
52
+ ```bash
53
+ npm install -g pm2
54
+ pm2 start armada-watch-agent --name armada-watch
55
+ pm2 save
56
+ pm2 startup
57
+ ```
58
+
59
+ **Using systemd:**
60
+
61
+ ```bash
62
+ sudo tee /etc/systemd/system/armada-watch.service > /dev/null <<EOF
63
+ [Unit]
64
+ Description=Armada Watch Monitoring Agent
65
+ After=network.target
66
+
67
+ [Service]
68
+ Type=simple
69
+ User=$USER
70
+ WorkingDirectory=$HOME
71
+ Environment="SERVER_URL=http://your-server:4000"
72
+ Environment="INSTANCE_NAME=My Instance"
73
+ Environment="REGION=us-east-1"
74
+ ExecStart=$(which armada-watch-agent)
75
+ Restart=always
76
+ RestartSec=10
77
+
78
+ [Install]
79
+ WantedBy=multi-user.target
80
+ EOF
81
+
82
+ sudo systemctl daemon-reload
83
+ sudo systemctl enable armada-watch
84
+ sudo systemctl start armada-watch
85
+ ```
86
+
87
+ ## Configuration
88
+
89
+ | Variable | Required | Default | Description |
90
+ |----------|----------|---------|-------------|
91
+ | `SERVER_URL` | Yes | - | URL of your monitoring server |
92
+ | `INSTANCE_NAME` | No | hostname | Friendly name for this instance |
93
+ | `REGION` | No | `unknown` | AWS region (e.g., us-east-1) |
94
+ | `INSTANCE_ID` | No | hostname | EC2 instance ID (auto-detected on EC2) |
95
+ | `COLLECTION_INTERVAL` | No | `10` | Interval in seconds between metric collections |
96
+
97
+ ## Collected Metrics
98
+
99
+ The agent collects:
100
+
101
+ - **CPU Usage** - Overall CPU utilization percentage
102
+ - **Memory Usage** - RAM usage percentage and amounts
103
+ - **Disk Usage** - Disk space utilization
104
+ - **Network Traffic** - Network RX/TX bytes
105
+ - **System Info** - Platform, architecture, CPU model
106
+ - **Top Processes** - Top 10 processes by CPU/Memory
107
+
108
+ ## Requirements
109
+
110
+ - Node.js >= 18.0.0
111
+ - Network access to monitoring server on port 4000
112
+
113
+ ## Troubleshooting
114
+
115
+ ### Agent can't connect to server
116
+
117
+ ```bash
118
+ # Test connectivity
119
+ curl http://your-server:4000/health
120
+
121
+ # Check agent logs (PM2)
122
+ pm2 logs armada-watch
123
+
124
+ # Check agent logs (systemd)
125
+ sudo journalctl -u armada-watch -f
126
+ ```
127
+
128
+ ### Permission errors
129
+
130
+ The agent needs permission to read system metrics. Run with appropriate user permissions.
131
+
132
+ ## License
133
+
134
+ MIT
135
+
136
+ ## Repository
137
+
138
+ https://github.com/gazzehamine/armada-watch
@@ -0,0 +1,81 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.getSystemInfo = getSystemInfo;
7
+ exports.collectMetrics = collectMetrics;
8
+ exports.collectProcesses = collectProcesses;
9
+ const systeminformation_1 = __importDefault(require("systeminformation"));
10
+ const os_1 = __importDefault(require("os"));
11
+ let lastNetworkStats = null;
12
+ async function getSystemInfo() {
13
+ const cpu = await systeminformation_1.default.cpu();
14
+ return {
15
+ platform: os_1.default.platform(),
16
+ arch: os_1.default.arch(),
17
+ hostname: os_1.default.hostname(),
18
+ cpuModel: cpu.manufacturer + " " + cpu.brand,
19
+ cpuCores: cpu.cores,
20
+ };
21
+ }
22
+ async function collectMetrics() {
23
+ // CPU Usage
24
+ const cpuLoad = await systeminformation_1.default.currentLoad();
25
+ const cpuUsage = cpuLoad.currentLoad;
26
+ // Memory Usage
27
+ const mem = await systeminformation_1.default.mem();
28
+ const memoryUsage = (mem.used / mem.total) * 100;
29
+ const memoryTotal = mem.total;
30
+ const memoryUsed = mem.used;
31
+ // Disk Usage
32
+ const fsSize = await systeminformation_1.default.fsSize();
33
+ const mainDisk = fsSize[0];
34
+ const diskUsage = mainDisk ? (mainDisk.used / mainDisk.size) * 100 : 0;
35
+ const diskTotal = mainDisk ? mainDisk.size : 0;
36
+ const diskUsed = mainDisk ? mainDisk.used : 0;
37
+ // Network Usage (calculate rate per second)
38
+ const networkStats = await systeminformation_1.default.networkStats();
39
+ const mainInterface = networkStats[0];
40
+ let networkRx = 0;
41
+ let networkTx = 0;
42
+ if (mainInterface && lastNetworkStats) {
43
+ const timeDiff = (Date.now() - lastNetworkStats.timestamp) / 1000; // seconds
44
+ networkRx = (mainInterface.rx_bytes - lastNetworkStats.rx) / timeDiff;
45
+ networkTx = (mainInterface.tx_bytes - lastNetworkStats.tx) / timeDiff;
46
+ }
47
+ if (mainInterface) {
48
+ lastNetworkStats = {
49
+ rx: mainInterface.rx_bytes,
50
+ tx: mainInterface.tx_bytes,
51
+ timestamp: Date.now(),
52
+ };
53
+ }
54
+ // Uptime
55
+ const uptime = os_1.default.uptime();
56
+ return {
57
+ cpuUsage,
58
+ memoryUsage,
59
+ memoryTotal,
60
+ memoryUsed,
61
+ diskUsage,
62
+ diskTotal,
63
+ diskUsed,
64
+ networkRx,
65
+ networkTx,
66
+ uptime,
67
+ };
68
+ }
69
+ async function collectProcesses() {
70
+ const processes = await systeminformation_1.default.processes();
71
+ return processes.list
72
+ .filter((p) => p.cpu > 0 || p.mem > 0)
73
+ .sort((a, b) => b.cpu - a.cpu)
74
+ .slice(0, 20)
75
+ .map((p) => ({
76
+ pid: p.pid,
77
+ name: p.name,
78
+ cpu: p.cpu,
79
+ memory: p.mem,
80
+ }));
81
+ }
package/dist/index.js ADDED
@@ -0,0 +1,120 @@
1
+ #!/usr/bin/env node
2
+ "use strict";
3
+ var __importDefault = (this && this.__importDefault) || function (mod) {
4
+ return (mod && mod.__esModule) ? mod : { "default": mod };
5
+ };
6
+ Object.defineProperty(exports, "__esModule", { value: true });
7
+ const dotenv_1 = __importDefault(require("dotenv"));
8
+ const axios_1 = __importDefault(require("axios"));
9
+ const os_1 = __importDefault(require("os"));
10
+ const collector_1 = require("./collector");
11
+ // Load environment variables
12
+ dotenv_1.default.config();
13
+ const SERVER_URL = process.env.SERVER_URL || "http://localhost:4000";
14
+ const INSTANCE_NAME = process.env.INSTANCE_NAME || os_1.default.hostname();
15
+ const REGION = process.env.REGION || "unknown";
16
+ const INSTANCE_ID = process.env.INSTANCE_ID || os_1.default.hostname();
17
+ const COLLECTION_INTERVAL = parseInt(process.env.COLLECTION_INTERVAL || "10") * 1000;
18
+ let instanceInfo = null;
19
+ async function initializeAgent() {
20
+ try {
21
+ console.log("šŸ”„ Initializing Armada Watch Agent...");
22
+ console.log(`šŸ“” Server: ${SERVER_URL}`);
23
+ console.log(`šŸ–„ļø Instance: ${INSTANCE_NAME}`);
24
+ console.log(`šŸŒ Region: ${REGION}`);
25
+ // Get system info once at startup
26
+ const sysInfo = await (0, collector_1.getSystemInfo)();
27
+ instanceInfo = {
28
+ instanceId: INSTANCE_ID,
29
+ name: INSTANCE_NAME,
30
+ privateIp: getLocalIpAddress(),
31
+ publicIp: await getPublicIpAddress(),
32
+ region: REGION,
33
+ platform: sysInfo.platform,
34
+ arch: sysInfo.arch,
35
+ hostname: sysInfo.hostname,
36
+ cpuModel: sysInfo.cpuModel,
37
+ cpuCores: sysInfo.cpuCores,
38
+ };
39
+ console.log("āœ… Agent initialized successfully");
40
+ console.log(`šŸ” Collection interval: ${COLLECTION_INTERVAL / 1000}s`);
41
+ }
42
+ catch (error) {
43
+ console.error("āŒ Failed to initialize agent:", error);
44
+ process.exit(1);
45
+ }
46
+ }
47
+ async function sendMetrics() {
48
+ try {
49
+ const metrics = await (0, collector_1.collectMetrics)();
50
+ const processes = await (0, collector_1.collectProcesses)();
51
+ const payload = {
52
+ instanceInfo,
53
+ metrics: {
54
+ instanceId: INSTANCE_ID,
55
+ ...metrics,
56
+ },
57
+ processes,
58
+ };
59
+ await axios_1.default.post(`${SERVER_URL}/api/metrics`, payload, {
60
+ timeout: 5000,
61
+ });
62
+ console.log(`āœ“ Metrics sent successfully - CPU: ${metrics.cpuUsage.toFixed(1)}% | Memory: ${metrics.memoryUsage.toFixed(1)}%`);
63
+ }
64
+ catch (error) {
65
+ if (axios_1.default.isAxiosError(error)) {
66
+ console.error(`āœ— Failed to send metrics: ${error.message}`);
67
+ }
68
+ else {
69
+ console.error("āœ— Failed to collect metrics:", error);
70
+ }
71
+ }
72
+ }
73
+ function getLocalIpAddress() {
74
+ const networkInterfaces = os_1.default.networkInterfaces();
75
+ for (const name of Object.keys(networkInterfaces)) {
76
+ const interfaces = networkInterfaces[name];
77
+ if (!interfaces)
78
+ continue;
79
+ for (const iface of interfaces) {
80
+ // Skip internal and non-IPv4 addresses
81
+ if (iface.family === "IPv4" && !iface.internal) {
82
+ return iface.address;
83
+ }
84
+ }
85
+ }
86
+ return "127.0.0.1";
87
+ }
88
+ async function getPublicIpAddress() {
89
+ try {
90
+ // Try AWS metadata service first (for EC2 instances)
91
+ const response = await axios_1.default.get("http://169.254.169.254/latest/meta-data/public-ipv4", {
92
+ timeout: 1000,
93
+ });
94
+ return response.data;
95
+ }
96
+ catch {
97
+ // If not on AWS or no public IP, return undefined
98
+ return undefined;
99
+ }
100
+ }
101
+ async function main() {
102
+ await initializeAgent();
103
+ // Send metrics immediately
104
+ await sendMetrics();
105
+ // Set up periodic collection
106
+ setInterval(sendMetrics, COLLECTION_INTERVAL);
107
+ // Handle graceful shutdown
108
+ process.on("SIGINT", () => {
109
+ console.log("\nšŸ‘‹ Shutting down agent...");
110
+ process.exit(0);
111
+ });
112
+ process.on("SIGTERM", () => {
113
+ console.log("\nšŸ‘‹ Shutting down agent...");
114
+ process.exit(0);
115
+ });
116
+ }
117
+ main().catch((error) => {
118
+ console.error("Fatal error:", error);
119
+ process.exit(1);
120
+ });
package/package.json ADDED
@@ -0,0 +1,48 @@
1
+ {
2
+ "name": "@gazzehamine/armada-watch-agent",
3
+ "version": "1.0.0",
4
+ "description": "Monitoring agent for Armada Watch - EC2 instance monitoring",
5
+ "main": "dist/index.js",
6
+ "bin": {
7
+ "armada-watch-agent": "dist/index.js"
8
+ },
9
+ "scripts": {
10
+ "build": "tsc",
11
+ "start": "node dist/index.js",
12
+ "dev": "ts-node-dev --respawn src/index.ts",
13
+ "prepublishOnly": "npm run build"
14
+ },
15
+ "keywords": [
16
+ "monitoring",
17
+ "ec2",
18
+ "aws",
19
+ "metrics",
20
+ "devops",
21
+ "observability"
22
+ ],
23
+ "author": "Gazzeh Amine",
24
+ "license": "MIT",
25
+ "repository": {
26
+ "type": "git",
27
+ "url": "https://github.com/gazzehamine/armada-watch.git",
28
+ "directory": "agent"
29
+ },
30
+ "files": [
31
+ "dist",
32
+ "README.md",
33
+ ".env.example"
34
+ ],
35
+ "dependencies": {
36
+ "axios": "^1.6.0",
37
+ "dotenv": "^16.3.1",
38
+ "systeminformation": "^5.21.20"
39
+ },
40
+ "devDependencies": {
41
+ "@types/node": "^20.8.10",
42
+ "ts-node-dev": "^2.0.0",
43
+ "typescript": "^5.9.3"
44
+ },
45
+ "engines": {
46
+ "node": ">=18.0.0"
47
+ }
48
+ }