launchlayer-apm-agent 0.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/config.yaml +31 -0
- package/dist/collectors/database.d.ts +19 -0
- package/dist/collectors/database.d.ts.map +1 -0
- package/dist/collectors/database.js +500 -0
- package/dist/collectors/database.js.map +1 -0
- package/dist/collectors/docker.d.ts +17 -0
- package/dist/collectors/docker.d.ts.map +1 -0
- package/dist/collectors/docker.js +118 -0
- package/dist/collectors/docker.js.map +1 -0
- package/dist/collectors/host.d.ts +15 -0
- package/dist/collectors/host.d.ts.map +1 -0
- package/dist/collectors/host.js +179 -0
- package/dist/collectors/host.js.map +1 -0
- package/dist/config.d.ts +46 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +119 -0
- package/dist/config.js.map +1 -0
- package/dist/forwarder.d.ts +9 -0
- package/dist/forwarder.d.ts.map +1 -0
- package/dist/forwarder.js +54 -0
- package/dist/forwarder.js.map +1 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +93 -0
- package/dist/index.js.map +1 -0
- package/dist/receiver.d.ts +16 -0
- package/dist/receiver.d.ts.map +1 -0
- package/dist/receiver.js +85 -0
- package/dist/receiver.js.map +1 -0
- package/package.json +30 -0
package/config.yaml
ADDED
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
agent:
|
|
2
|
+
collector_url: "${AGENT_COLLECTOR_URL:-http://localhost:4318}"
|
|
3
|
+
api_key: "${AGENT_API_KEY:-dev-api-key}"
|
|
4
|
+
instance_id: "${INSTANCE_ID:-local-dev}"
|
|
5
|
+
hostname: "${HOSTNAME:-localhost}"
|
|
6
|
+
|
|
7
|
+
host:
|
|
8
|
+
enabled: true
|
|
9
|
+
interval_seconds: 30
|
|
10
|
+
proc_path: "/proc"
|
|
11
|
+
|
|
12
|
+
docker:
|
|
13
|
+
enabled: true
|
|
14
|
+
interval_seconds: 30
|
|
15
|
+
socket: "/var/run/docker.sock"
|
|
16
|
+
|
|
17
|
+
databases:
|
|
18
|
+
- name: "local-pg"
|
|
19
|
+
host: "${DB_HOST:-localhost}"
|
|
20
|
+
port: ${DB_PORT:-5433}
|
|
21
|
+
database: "${DB_NAME:-app_db}"
|
|
22
|
+
username: "${DB_USER:-bi_monitor}"
|
|
23
|
+
password: "${DB_PASSWORD:-monitor_password}"
|
|
24
|
+
ssl: false
|
|
25
|
+
interval_seconds: 60
|
|
26
|
+
explain_enabled: true
|
|
27
|
+
|
|
28
|
+
receiver:
|
|
29
|
+
enabled: true
|
|
30
|
+
port: 9999
|
|
31
|
+
bind: "127.0.0.1"
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { DatabaseConfig } from '../config';
|
|
2
|
+
export interface DatabaseSnapshot {
|
|
3
|
+
dbName: string;
|
|
4
|
+
slowQueries: any[];
|
|
5
|
+
tableStats: any[];
|
|
6
|
+
indexes: any[];
|
|
7
|
+
connections: any;
|
|
8
|
+
tableSizes: any[];
|
|
9
|
+
bloat: any[];
|
|
10
|
+
replicationLag: any[];
|
|
11
|
+
vacuumStats: any[];
|
|
12
|
+
explainPlans: any[];
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* Collect all database metrics from a monitored PostgreSQL instance.
|
|
16
|
+
* Runs 8 SQL queries against pg_stat_* views.
|
|
17
|
+
*/
|
|
18
|
+
export declare function collectDatabaseMetrics(dbConfig: DatabaseConfig): Promise<DatabaseSnapshot>;
|
|
19
|
+
//# sourceMappingURL=database.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"database.d.ts","sourceRoot":"","sources":["../../src/collectors/database.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,cAAc,EAAE,MAAM,WAAW,CAAC;AAE3C,MAAM,WAAW,gBAAgB;IAC/B,MAAM,EAAE,MAAM,CAAC;IACf,WAAW,EAAE,GAAG,EAAE,CAAC;IACnB,UAAU,EAAE,GAAG,EAAE,CAAC;IAClB,OAAO,EAAE,GAAG,EAAE,CAAC;IACf,WAAW,EAAE,GAAG,CAAC;IACjB,UAAU,EAAE,GAAG,EAAE,CAAC;IAClB,KAAK,EAAE,GAAG,EAAE,CAAC;IACb,cAAc,EAAE,GAAG,EAAE,CAAC;IACtB,WAAW,EAAE,GAAG,EAAE,CAAC;IACnB,YAAY,EAAE,GAAG,EAAE,CAAC;CACrB;AAMD;;;GAGG;AACH,wBAAsB,sBAAsB,CAC1C,QAAQ,EAAE,cAAc,GACvB,OAAO,CAAC,gBAAgB,CAAC,CAgD3B"}
|
|
@@ -0,0 +1,500 @@
|
|
|
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 __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.collectDatabaseMetrics = collectDatabaseMetrics;
|
|
37
|
+
const pg_1 = require("pg");
|
|
38
|
+
const crypto = __importStar(require("crypto"));
|
|
39
|
+
// Track which queryids have been explained recently (1 per hour)
|
|
40
|
+
const explainCache = new Map();
|
|
41
|
+
const EXPLAIN_COOLDOWN_MS = 60 * 60 * 1000; // 1 hour
|
|
42
|
+
/**
|
|
43
|
+
* Collect all database metrics from a monitored PostgreSQL instance.
|
|
44
|
+
* Runs 8 SQL queries against pg_stat_* views.
|
|
45
|
+
*/
|
|
46
|
+
async function collectDatabaseMetrics(dbConfig) {
|
|
47
|
+
const client = new pg_1.Client({
|
|
48
|
+
host: dbConfig.host,
|
|
49
|
+
port: dbConfig.port,
|
|
50
|
+
database: dbConfig.database,
|
|
51
|
+
user: dbConfig.username,
|
|
52
|
+
password: dbConfig.password,
|
|
53
|
+
ssl: dbConfig.ssl ? { rejectUnauthorized: false } : false,
|
|
54
|
+
connectionTimeoutMillis: 10000,
|
|
55
|
+
statement_timeout: 15000,
|
|
56
|
+
});
|
|
57
|
+
await client.connect();
|
|
58
|
+
try {
|
|
59
|
+
const [slowQueries, tableStats, indexes, connections, tableSizes, bloat, replicationLag, vacuumStats] = await Promise.all([
|
|
60
|
+
getSlowQueries(client),
|
|
61
|
+
getTableStats(client),
|
|
62
|
+
getIndexStats(client),
|
|
63
|
+
getConnections(client),
|
|
64
|
+
getTableSizes(client),
|
|
65
|
+
getBloatEstimates(client),
|
|
66
|
+
getReplicationLag(client),
|
|
67
|
+
getVacuumStats(client),
|
|
68
|
+
]);
|
|
69
|
+
// EXPLAIN plans are collected separately (sequential, sampled)
|
|
70
|
+
let explainPlans = [];
|
|
71
|
+
if (dbConfig.explain_enabled && slowQueries.length > 0) {
|
|
72
|
+
explainPlans = await getExplainPlans(client, dbConfig.name, slowQueries);
|
|
73
|
+
}
|
|
74
|
+
return {
|
|
75
|
+
dbName: dbConfig.name,
|
|
76
|
+
slowQueries,
|
|
77
|
+
tableStats,
|
|
78
|
+
indexes,
|
|
79
|
+
connections,
|
|
80
|
+
tableSizes,
|
|
81
|
+
bloat,
|
|
82
|
+
replicationLag,
|
|
83
|
+
vacuumStats,
|
|
84
|
+
explainPlans,
|
|
85
|
+
};
|
|
86
|
+
}
|
|
87
|
+
finally {
|
|
88
|
+
await client.end().catch(() => { });
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
// ================================================================
|
|
92
|
+
// Query 1: Slow queries from pg_stat_statements
|
|
93
|
+
// ================================================================
|
|
94
|
+
async function getSlowQueries(client) {
|
|
95
|
+
try {
|
|
96
|
+
const result = await client.query(`
|
|
97
|
+
SELECT
|
|
98
|
+
queryid,
|
|
99
|
+
LEFT(query, 300) AS query_sample,
|
|
100
|
+
calls,
|
|
101
|
+
total_exec_time AS total_time_ms,
|
|
102
|
+
mean_exec_time AS mean_time_ms,
|
|
103
|
+
stddev_exec_time AS stddev_time_ms,
|
|
104
|
+
min_exec_time AS min_time_ms,
|
|
105
|
+
max_exec_time AS max_time_ms,
|
|
106
|
+
CASE WHEN calls > 0 THEN rows / calls ELSE 0 END AS rows_per_call,
|
|
107
|
+
CASE WHEN shared_blks_hit + shared_blks_read > 0
|
|
108
|
+
THEN ROUND(shared_blks_hit::NUMERIC / (shared_blks_hit + shared_blks_read) * 100, 1)
|
|
109
|
+
ELSE 0
|
|
110
|
+
END AS cache_hit_pct
|
|
111
|
+
FROM pg_stat_statements
|
|
112
|
+
WHERE calls > 5
|
|
113
|
+
AND mean_exec_time > 100
|
|
114
|
+
AND query NOT LIKE '%pg_stat%'
|
|
115
|
+
ORDER BY mean_exec_time DESC
|
|
116
|
+
LIMIT 50
|
|
117
|
+
`);
|
|
118
|
+
return result.rows.map((r) => ({
|
|
119
|
+
queryid: r.queryid,
|
|
120
|
+
querySample: r.query_sample,
|
|
121
|
+
calls: parseInt(r.calls),
|
|
122
|
+
totalTimeMs: parseFloat(r.total_time_ms),
|
|
123
|
+
meanTimeMs: parseFloat(r.mean_time_ms),
|
|
124
|
+
stddevTimeMs: parseFloat(r.stddev_time_ms || '0'),
|
|
125
|
+
minTimeMs: parseFloat(r.min_time_ms || '0'),
|
|
126
|
+
maxTimeMs: parseFloat(r.max_time_ms || '0'),
|
|
127
|
+
rowsPerCall: parseFloat(r.rows_per_call || '0'),
|
|
128
|
+
cacheHitPct: parseFloat(r.cache_hit_pct || '0'),
|
|
129
|
+
}));
|
|
130
|
+
}
|
|
131
|
+
catch (err) {
|
|
132
|
+
if (err.message?.includes('pg_stat_statements')) {
|
|
133
|
+
console.warn('[database] pg_stat_statements not available — enable it in postgresql.conf');
|
|
134
|
+
}
|
|
135
|
+
else {
|
|
136
|
+
console.error('[database] Failed to get slow queries:', err.message);
|
|
137
|
+
}
|
|
138
|
+
return [];
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
// ================================================================
|
|
142
|
+
// Query 2: Table stats from pg_stat_user_tables
|
|
143
|
+
// ================================================================
|
|
144
|
+
async function getTableStats(client) {
|
|
145
|
+
const result = await client.query(`
|
|
146
|
+
SELECT
|
|
147
|
+
schemaname AS schema_name,
|
|
148
|
+
relname AS table_name,
|
|
149
|
+
COALESCE(seq_scan, 0) AS seq_scan,
|
|
150
|
+
COALESCE(idx_scan, 0) AS idx_scan,
|
|
151
|
+
CASE WHEN COALESCE(seq_scan, 0) + COALESCE(idx_scan, 0) > 0
|
|
152
|
+
THEN ROUND(seq_scan::NUMERIC / (seq_scan + idx_scan) * 100, 1)
|
|
153
|
+
ELSE 0
|
|
154
|
+
END AS seq_scan_pct,
|
|
155
|
+
COALESCE(n_live_tup, 0) AS n_live_tup,
|
|
156
|
+
COALESCE(n_dead_tup, 0) AS n_dead_tup,
|
|
157
|
+
CASE WHEN COALESCE(n_live_tup, 0) + COALESCE(n_dead_tup, 0) > 0
|
|
158
|
+
THEN ROUND(n_dead_tup::NUMERIC / (n_live_tup + n_dead_tup) * 100, 1)
|
|
159
|
+
ELSE 0
|
|
160
|
+
END AS dead_tup_pct,
|
|
161
|
+
last_vacuum,
|
|
162
|
+
last_autovacuum,
|
|
163
|
+
last_analyze,
|
|
164
|
+
last_autoanalyze
|
|
165
|
+
FROM pg_stat_user_tables
|
|
166
|
+
WHERE seq_scan + idx_scan > 10
|
|
167
|
+
ORDER BY seq_scan_pct DESC
|
|
168
|
+
LIMIT 50
|
|
169
|
+
`);
|
|
170
|
+
return result.rows.map((r) => ({
|
|
171
|
+
schemaName: r.schema_name,
|
|
172
|
+
tableName: r.table_name,
|
|
173
|
+
seqScan: parseInt(r.seq_scan),
|
|
174
|
+
idxScan: parseInt(r.idx_scan),
|
|
175
|
+
seqScanPct: parseFloat(r.seq_scan_pct),
|
|
176
|
+
nLiveTup: parseInt(r.n_live_tup),
|
|
177
|
+
nDeadTup: parseInt(r.n_dead_tup),
|
|
178
|
+
deadTupPct: parseFloat(r.dead_tup_pct),
|
|
179
|
+
lastVacuum: r.last_vacuum,
|
|
180
|
+
lastAutovacuum: r.last_autovacuum,
|
|
181
|
+
lastAnalyze: r.last_analyze,
|
|
182
|
+
lastAutoanalyze: r.last_autoanalyze,
|
|
183
|
+
}));
|
|
184
|
+
}
|
|
185
|
+
// ================================================================
|
|
186
|
+
// Query 3: Index stats
|
|
187
|
+
// ================================================================
|
|
188
|
+
async function getIndexStats(client) {
|
|
189
|
+
const result = await client.query(`
|
|
190
|
+
SELECT
|
|
191
|
+
s.schemaname AS schema_name,
|
|
192
|
+
s.indexrelname AS index_name,
|
|
193
|
+
s.relname AS table_name,
|
|
194
|
+
COALESCE(s.idx_scan, 0) AS idx_scan,
|
|
195
|
+
COALESCE(s.idx_tup_read, 0) AS idx_tup_read,
|
|
196
|
+
COALESCE(s.idx_tup_fetch, 0) AS idx_tup_fetch,
|
|
197
|
+
pg_relation_size(s.indexrelid) AS index_size_bytes,
|
|
198
|
+
i.indisprimary AS is_primary,
|
|
199
|
+
i.indisunique AS is_unique
|
|
200
|
+
FROM pg_stat_user_indexes s
|
|
201
|
+
JOIN pg_index i ON s.indexrelid = i.indexrelid
|
|
202
|
+
ORDER BY s.idx_scan ASC
|
|
203
|
+
LIMIT 100
|
|
204
|
+
`);
|
|
205
|
+
return result.rows.map((r) => ({
|
|
206
|
+
schemaName: r.schema_name,
|
|
207
|
+
indexName: r.index_name,
|
|
208
|
+
tableName: r.table_name,
|
|
209
|
+
idxScan: parseInt(r.idx_scan),
|
|
210
|
+
idxTupRead: parseInt(r.idx_tup_read),
|
|
211
|
+
idxTupFetch: parseInt(r.idx_tup_fetch),
|
|
212
|
+
indexSizeBytes: parseInt(r.index_size_bytes),
|
|
213
|
+
isPrimary: r.is_primary,
|
|
214
|
+
isUnique: r.is_unique,
|
|
215
|
+
}));
|
|
216
|
+
}
|
|
217
|
+
// ================================================================
|
|
218
|
+
// Query 4: Connection activity + blocking chains
|
|
219
|
+
// ================================================================
|
|
220
|
+
async function getConnections(client) {
|
|
221
|
+
const connResult = await client.query(`
|
|
222
|
+
SELECT
|
|
223
|
+
(SELECT setting::INTEGER FROM pg_settings WHERE name = 'max_connections') AS max_connections,
|
|
224
|
+
COUNT(*) FILTER (WHERE state = 'active') AS active_count,
|
|
225
|
+
COUNT(*) FILTER (WHERE state = 'idle') AS idle_count,
|
|
226
|
+
COUNT(*) FILTER (WHERE state = 'idle in transaction') AS idle_in_txn,
|
|
227
|
+
COUNT(*) FILTER (WHERE wait_event_type = 'Lock') AS waiting_count,
|
|
228
|
+
COUNT(*) AS total_count
|
|
229
|
+
FROM pg_stat_activity
|
|
230
|
+
WHERE backend_type = 'client backend'
|
|
231
|
+
`);
|
|
232
|
+
const c = connResult.rows[0];
|
|
233
|
+
const maxConn = parseInt(c.max_connections);
|
|
234
|
+
const totalCount = parseInt(c.total_count);
|
|
235
|
+
// Blocking chains
|
|
236
|
+
let blockingChains = [];
|
|
237
|
+
try {
|
|
238
|
+
const blockResult = await client.query(`
|
|
239
|
+
SELECT
|
|
240
|
+
blocked.pid AS blocked_pid,
|
|
241
|
+
LEFT(blocked.query, 200) AS blocked_query,
|
|
242
|
+
EXTRACT(EPOCH FROM (NOW() - blocked.query_start))::NUMERIC AS blocked_for_sec,
|
|
243
|
+
blocking.pid AS blocking_pid,
|
|
244
|
+
LEFT(blocking.query, 200) AS blocking_query
|
|
245
|
+
FROM pg_stat_activity blocked
|
|
246
|
+
JOIN LATERAL unnest(pg_blocking_pids(blocked.pid)) AS blocking_pid ON true
|
|
247
|
+
JOIN pg_stat_activity blocking ON blocking.pid = blocking_pid
|
|
248
|
+
WHERE blocked.wait_event_type = 'Lock'
|
|
249
|
+
LIMIT 20
|
|
250
|
+
`);
|
|
251
|
+
blockingChains = blockResult.rows.map((r) => ({
|
|
252
|
+
blockedPid: r.blocked_pid,
|
|
253
|
+
blockedQuery: r.blocked_query,
|
|
254
|
+
blockedForSec: parseFloat(r.blocked_for_sec || '0'),
|
|
255
|
+
blockingPid: r.blocking_pid,
|
|
256
|
+
blockingQuery: r.blocking_query,
|
|
257
|
+
}));
|
|
258
|
+
}
|
|
259
|
+
catch {
|
|
260
|
+
// pg_blocking_pids may not be available on all versions
|
|
261
|
+
}
|
|
262
|
+
return {
|
|
263
|
+
maxConnections: maxConn,
|
|
264
|
+
activeCount: parseInt(c.active_count),
|
|
265
|
+
idleCount: parseInt(c.idle_count),
|
|
266
|
+
idleInTxn: parseInt(c.idle_in_txn),
|
|
267
|
+
waitingCount: parseInt(c.waiting_count),
|
|
268
|
+
totalCount,
|
|
269
|
+
utilizationPct: maxConn > 0 ? Math.round((totalCount / maxConn) * 1000) / 10 : 0,
|
|
270
|
+
blockingChains,
|
|
271
|
+
};
|
|
272
|
+
}
|
|
273
|
+
// ================================================================
|
|
274
|
+
// Query 5: Replication lag
|
|
275
|
+
// ================================================================
|
|
276
|
+
async function getReplicationLag(client) {
|
|
277
|
+
try {
|
|
278
|
+
const result = await client.query(`
|
|
279
|
+
SELECT
|
|
280
|
+
application_name AS replica_name,
|
|
281
|
+
client_addr::TEXT,
|
|
282
|
+
state,
|
|
283
|
+
sent_lsn::TEXT,
|
|
284
|
+
write_lsn::TEXT,
|
|
285
|
+
flush_lsn::TEXT,
|
|
286
|
+
replay_lsn::TEXT,
|
|
287
|
+
EXTRACT(MILLISECONDS FROM write_lag)::NUMERIC AS write_lag_ms,
|
|
288
|
+
EXTRACT(MILLISECONDS FROM flush_lag)::NUMERIC AS flush_lag_ms,
|
|
289
|
+
EXTRACT(MILLISECONDS FROM replay_lag)::NUMERIC AS replay_lag_ms,
|
|
290
|
+
pg_wal_lsn_diff(sent_lsn, replay_lsn) AS bytes_behind
|
|
291
|
+
FROM pg_stat_replication
|
|
292
|
+
`);
|
|
293
|
+
return result.rows.map((r) => ({
|
|
294
|
+
replicaName: r.replica_name,
|
|
295
|
+
clientAddr: r.client_addr,
|
|
296
|
+
state: r.state,
|
|
297
|
+
sentLsn: r.sent_lsn,
|
|
298
|
+
writeLsn: r.write_lsn,
|
|
299
|
+
flushLsn: r.flush_lsn,
|
|
300
|
+
replayLsn: r.replay_lsn,
|
|
301
|
+
writeLagMs: r.write_lag_ms ? parseFloat(r.write_lag_ms) : null,
|
|
302
|
+
flushLagMs: r.flush_lag_ms ? parseFloat(r.flush_lag_ms) : null,
|
|
303
|
+
replayLagMs: r.replay_lag_ms ? parseFloat(r.replay_lag_ms) : null,
|
|
304
|
+
bytesBehind: r.bytes_behind ? parseInt(r.bytes_behind) : null,
|
|
305
|
+
}));
|
|
306
|
+
}
|
|
307
|
+
catch {
|
|
308
|
+
// Not a primary or insufficient permissions
|
|
309
|
+
return [];
|
|
310
|
+
}
|
|
311
|
+
}
|
|
312
|
+
// ================================================================
|
|
313
|
+
// Query 6: Table sizes
|
|
314
|
+
// ================================================================
|
|
315
|
+
async function getTableSizes(client) {
|
|
316
|
+
const result = await client.query(`
|
|
317
|
+
SELECT
|
|
318
|
+
schemaname AS schema_name,
|
|
319
|
+
relname AS table_name,
|
|
320
|
+
pg_total_relation_size(relid) AS total_bytes,
|
|
321
|
+
pg_table_size(relid) AS table_bytes,
|
|
322
|
+
pg_indexes_size(relid) AS index_bytes,
|
|
323
|
+
COALESCE(pg_total_relation_size(reltoastrelid), 0) AS toast_bytes,
|
|
324
|
+
n_live_tup AS row_estimate
|
|
325
|
+
FROM pg_stat_user_tables
|
|
326
|
+
ORDER BY pg_total_relation_size(relid) DESC
|
|
327
|
+
LIMIT 100
|
|
328
|
+
`);
|
|
329
|
+
return result.rows.map((r) => ({
|
|
330
|
+
schemaName: r.schema_name,
|
|
331
|
+
tableName: r.table_name,
|
|
332
|
+
totalBytes: parseInt(r.total_bytes),
|
|
333
|
+
tableBytes: parseInt(r.table_bytes),
|
|
334
|
+
indexBytes: parseInt(r.index_bytes),
|
|
335
|
+
toastBytes: parseInt(r.toast_bytes),
|
|
336
|
+
rowEstimate: parseInt(r.row_estimate),
|
|
337
|
+
}));
|
|
338
|
+
}
|
|
339
|
+
// ================================================================
|
|
340
|
+
// Query 7: Bloat estimation (statistical, no pgstattuple needed)
|
|
341
|
+
// ================================================================
|
|
342
|
+
async function getBloatEstimates(client) {
|
|
343
|
+
try {
|
|
344
|
+
const result = await client.query(`
|
|
345
|
+
WITH table_bloat AS (
|
|
346
|
+
SELECT
|
|
347
|
+
schemaname AS schema_name,
|
|
348
|
+
tablename AS table_name,
|
|
349
|
+
pg_total_relation_size(schemaname || '.' || quote_ident(tablename)) AS real_bytes,
|
|
350
|
+
CASE WHEN c.reltuples > 0 THEN
|
|
351
|
+
GREATEST(
|
|
352
|
+
pg_total_relation_size(schemaname || '.' || quote_ident(tablename)) -
|
|
353
|
+
(c.reltuples * (
|
|
354
|
+
(SELECT SUM(avg_width) FROM pg_stats WHERE tablename = c.relname AND schemaname = s.schemaname) + 24
|
|
355
|
+
))::BIGINT,
|
|
356
|
+
0
|
|
357
|
+
)
|
|
358
|
+
ELSE 0
|
|
359
|
+
END AS bloat_bytes
|
|
360
|
+
FROM pg_stats s
|
|
361
|
+
JOIN pg_class c ON c.relname = s.tablename
|
|
362
|
+
JOIN pg_namespace n ON n.oid = c.relnamespace AND n.nspname = s.schemaname
|
|
363
|
+
WHERE s.schemaname NOT IN ('pg_catalog', 'information_schema')
|
|
364
|
+
GROUP BY schemaname, tablename, c.reltuples, c.relname
|
|
365
|
+
HAVING pg_total_relation_size(schemaname || '.' || quote_ident(tablename)) > 1048576
|
|
366
|
+
)
|
|
367
|
+
SELECT
|
|
368
|
+
schema_name,
|
|
369
|
+
table_name,
|
|
370
|
+
real_bytes,
|
|
371
|
+
bloat_bytes,
|
|
372
|
+
CASE WHEN real_bytes > 0
|
|
373
|
+
THEN ROUND(bloat_bytes::NUMERIC / real_bytes * 100, 1)
|
|
374
|
+
ELSE 0
|
|
375
|
+
END AS bloat_pct
|
|
376
|
+
FROM table_bloat
|
|
377
|
+
WHERE bloat_bytes > 0
|
|
378
|
+
ORDER BY bloat_pct DESC
|
|
379
|
+
LIMIT 50
|
|
380
|
+
`);
|
|
381
|
+
return result.rows.map((r) => ({
|
|
382
|
+
schemaName: r.schema_name,
|
|
383
|
+
tableName: r.table_name,
|
|
384
|
+
realBytes: parseInt(r.real_bytes),
|
|
385
|
+
bloatBytes: parseInt(r.bloat_bytes),
|
|
386
|
+
bloatPct: parseFloat(r.bloat_pct),
|
|
387
|
+
}));
|
|
388
|
+
}
|
|
389
|
+
catch (err) {
|
|
390
|
+
console.error('[database] Failed to estimate bloat:', err.message);
|
|
391
|
+
return [];
|
|
392
|
+
}
|
|
393
|
+
}
|
|
394
|
+
// ================================================================
|
|
395
|
+
// Query 8: Vacuum stats
|
|
396
|
+
// ================================================================
|
|
397
|
+
async function getVacuumStats(client) {
|
|
398
|
+
const result = await client.query(`
|
|
399
|
+
SELECT
|
|
400
|
+
schemaname AS schema_name,
|
|
401
|
+
relname AS table_name,
|
|
402
|
+
COALESCE(n_dead_tup, 0) AS n_dead_tup,
|
|
403
|
+
COALESCE(n_live_tup, 0) AS n_live_tup,
|
|
404
|
+
CASE WHEN COALESCE(n_live_tup, 0) + COALESCE(n_dead_tup, 0) > 0
|
|
405
|
+
THEN ROUND(n_dead_tup::NUMERIC / (n_live_tup + n_dead_tup) * 100, 1)
|
|
406
|
+
ELSE 0
|
|
407
|
+
END AS dead_tup_pct,
|
|
408
|
+
last_vacuum,
|
|
409
|
+
last_autovacuum,
|
|
410
|
+
last_analyze,
|
|
411
|
+
last_autoanalyze,
|
|
412
|
+
autovacuum_count,
|
|
413
|
+
vacuum_count
|
|
414
|
+
FROM pg_stat_user_tables
|
|
415
|
+
ORDER BY n_dead_tup DESC
|
|
416
|
+
LIMIT 50
|
|
417
|
+
`);
|
|
418
|
+
return result.rows.map((r) => ({
|
|
419
|
+
schemaName: r.schema_name,
|
|
420
|
+
tableName: r.table_name,
|
|
421
|
+
nDeadTup: parseInt(r.n_dead_tup),
|
|
422
|
+
nLiveTup: parseInt(r.n_live_tup),
|
|
423
|
+
deadTupPct: parseFloat(r.dead_tup_pct),
|
|
424
|
+
lastVacuum: r.last_vacuum,
|
|
425
|
+
lastAutovacuum: r.last_autovacuum,
|
|
426
|
+
lastAnalyze: r.last_analyze,
|
|
427
|
+
lastAutoanalyze: r.last_autoanalyze,
|
|
428
|
+
autovacuumCount: parseInt(r.autovacuum_count || '0'),
|
|
429
|
+
vacuumCount: parseInt(r.vacuum_count || '0'),
|
|
430
|
+
}));
|
|
431
|
+
}
|
|
432
|
+
// ================================================================
|
|
433
|
+
// EXPLAIN plan capture (sampled, safe)
|
|
434
|
+
// ================================================================
|
|
435
|
+
async function getExplainPlans(client, dbName, slowQueries) {
|
|
436
|
+
const plans = [];
|
|
437
|
+
const now = Date.now();
|
|
438
|
+
// Only explain top 5 slowest queries, 1 per queryid per hour
|
|
439
|
+
const candidates = slowQueries.slice(0, 5);
|
|
440
|
+
for (const sq of candidates) {
|
|
441
|
+
const cacheKey = `${dbName}:${sq.queryid}`;
|
|
442
|
+
const lastExplained = explainCache.get(cacheKey) || 0;
|
|
443
|
+
if (now - lastExplained < EXPLAIN_COOLDOWN_MS)
|
|
444
|
+
continue;
|
|
445
|
+
try {
|
|
446
|
+
// Set a tight timeout for EXPLAIN
|
|
447
|
+
await client.query('SET LOCAL statement_timeout = 5000');
|
|
448
|
+
// Use EXPLAIN (not ANALYZE) — safe, doesn't execute the query
|
|
449
|
+
const result = await client.query(`EXPLAIN (FORMAT JSON) ${sq.querySample}`);
|
|
450
|
+
if (result.rows.length > 0) {
|
|
451
|
+
const planJson = result.rows[0]['QUERY PLAN'];
|
|
452
|
+
const planStr = JSON.stringify(planJson);
|
|
453
|
+
const planHash = crypto.createHash('md5').update(planStr).digest('hex');
|
|
454
|
+
// Count plan node types
|
|
455
|
+
let seqScans = 0;
|
|
456
|
+
let indexScans = 0;
|
|
457
|
+
let sortOps = 0;
|
|
458
|
+
let totalCost = 0;
|
|
459
|
+
const countNodes = (node) => {
|
|
460
|
+
if (!node)
|
|
461
|
+
return;
|
|
462
|
+
const nodeType = node['Node Type'] || '';
|
|
463
|
+
if (nodeType === 'Seq Scan')
|
|
464
|
+
seqScans++;
|
|
465
|
+
if (nodeType.includes('Index'))
|
|
466
|
+
indexScans++;
|
|
467
|
+
if (nodeType === 'Sort')
|
|
468
|
+
sortOps++;
|
|
469
|
+
totalCost = Math.max(totalCost, node['Total Cost'] || 0);
|
|
470
|
+
if (node.Plans) {
|
|
471
|
+
for (const child of node.Plans) {
|
|
472
|
+
countNodes(child);
|
|
473
|
+
}
|
|
474
|
+
}
|
|
475
|
+
};
|
|
476
|
+
if (Array.isArray(planJson) && planJson[0]?.Plan) {
|
|
477
|
+
countNodes(planJson[0].Plan);
|
|
478
|
+
}
|
|
479
|
+
plans.push({
|
|
480
|
+
queryid: sq.queryid,
|
|
481
|
+
querySample: sq.querySample,
|
|
482
|
+
planJson,
|
|
483
|
+
planHash,
|
|
484
|
+
totalCost,
|
|
485
|
+
planningTime: planJson[0]?.['Planning Time'] || null,
|
|
486
|
+
seqScansInPlan: seqScans,
|
|
487
|
+
indexScansInPlan: indexScans,
|
|
488
|
+
sortOpsInPlan: sortOps,
|
|
489
|
+
});
|
|
490
|
+
explainCache.set(cacheKey, now);
|
|
491
|
+
}
|
|
492
|
+
}
|
|
493
|
+
catch {
|
|
494
|
+
// EXPLAIN may fail for some queries (e.g., utility statements)
|
|
495
|
+
// Silently skip
|
|
496
|
+
}
|
|
497
|
+
}
|
|
498
|
+
return plans;
|
|
499
|
+
}
|
|
500
|
+
//# sourceMappingURL=database.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"database.js","sourceRoot":"","sources":["../../src/collectors/database.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
export interface ContainerMetric {
|
|
2
|
+
containerId: string;
|
|
3
|
+
containerName: string;
|
|
4
|
+
image: string;
|
|
5
|
+
cpuPct: number;
|
|
6
|
+
memUsedMb: number;
|
|
7
|
+
memLimitMb: number;
|
|
8
|
+
netInKbps: number;
|
|
9
|
+
netOutKbps: number;
|
|
10
|
+
restartCount: number;
|
|
11
|
+
status: string;
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Collect Docker container metrics via the Docker Engine API over unix socket.
|
|
15
|
+
*/
|
|
16
|
+
export declare function collectDockerMetrics(socketPath: string): Promise<ContainerMetric[]>;
|
|
17
|
+
//# sourceMappingURL=docker.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"docker.d.ts","sourceRoot":"","sources":["../../src/collectors/docker.ts"],"names":[],"mappings":"AAEA,MAAM,WAAW,eAAe;IAC9B,WAAW,EAAE,MAAM,CAAC;IACpB,aAAa,EAAE,MAAM,CAAC;IACtB,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,EAAE,MAAM,CAAC;IACnB,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,EAAE,MAAM,CAAC;IACnB,YAAY,EAAE,MAAM,CAAC;IACrB,MAAM,EAAE,MAAM,CAAC;CAChB;AAED;;GAEG;AACH,wBAAsB,oBAAoB,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,eAAe,EAAE,CAAC,CAgDzF"}
|