@wpmoo/toolkit 0.9.10 → 0.9.11
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 +2 -2
- package/dist/doctor.js +58 -5
- package/dist/help.js +2 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -171,8 +171,8 @@ npx @wpmoo/toolkit doctor --json --postgres
|
|
|
171
171
|
JSON output is optional; human-readable output remains the default.
|
|
172
172
|
`doctor --postgres` adds read-only PostgreSQL health and performance diagnostics
|
|
173
173
|
such as database size, sessions currently running queries with
|
|
174
|
-
`pg_stat_activity.state = 'active'`,
|
|
175
|
-
and settings.
|
|
174
|
+
`pg_stat_activity.state = 'active'`, connection utilization against
|
|
175
|
+
`max_connections`, slow-query readiness, extension visibility, and settings.
|
|
176
176
|
`doctor --json --postgres` includes a structured `postgres` object for automation.
|
|
177
177
|
Incomplete or malformed PostgreSQL metric rows are reported as unavailable diagnostics.
|
|
178
178
|
|
package/dist/doctor.js
CHANGED
|
@@ -57,6 +57,15 @@ WITH metrics(metric, value) AS (
|
|
|
57
57
|
WHERE datname IS NOT NULL
|
|
58
58
|
AND state = 'active'
|
|
59
59
|
UNION ALL
|
|
60
|
+
SELECT 'connection_count', count(*)::text
|
|
61
|
+
FROM pg_stat_activity
|
|
62
|
+
WHERE datname IS NOT NULL
|
|
63
|
+
UNION ALL
|
|
64
|
+
SELECT 'max_connections', COALESCE(
|
|
65
|
+
(SELECT setting FROM pg_settings WHERE name = 'max_connections'),
|
|
66
|
+
'unavailable'
|
|
67
|
+
)
|
|
68
|
+
UNION ALL
|
|
60
69
|
SELECT 'total_database_size_bytes', COALESCE(sum(pg_database_size(datname)), 0)::text
|
|
61
70
|
FROM pg_database
|
|
62
71
|
WHERE datistemplate = false
|
|
@@ -83,16 +92,20 @@ FROM metrics
|
|
|
83
92
|
ORDER BY CASE metric
|
|
84
93
|
WHEN 'database_count' THEN 1
|
|
85
94
|
WHEN 'active_connections' THEN 2
|
|
86
|
-
WHEN '
|
|
87
|
-
WHEN '
|
|
88
|
-
WHEN '
|
|
89
|
-
WHEN '
|
|
95
|
+
WHEN 'connection_count' THEN 3
|
|
96
|
+
WHEN 'max_connections' THEN 4
|
|
97
|
+
WHEN 'total_database_size_bytes' THEN 5
|
|
98
|
+
WHEN 'slow_query_logging' THEN 6
|
|
99
|
+
WHEN 'pg_stat_statements' THEN 7
|
|
100
|
+
WHEN 'shared_buffers' THEN 8
|
|
90
101
|
ELSE 99
|
|
91
102
|
END;
|
|
92
103
|
`.trim();
|
|
93
104
|
const postgresDiagnosticKeys = [
|
|
94
105
|
'database_count',
|
|
95
106
|
'active_connections',
|
|
107
|
+
'connection_count',
|
|
108
|
+
'max_connections',
|
|
96
109
|
'total_database_size_bytes',
|
|
97
110
|
'slow_query_logging',
|
|
98
111
|
'pg_stat_statements',
|
|
@@ -127,9 +140,14 @@ function parsePostgresDiagnostics(output) {
|
|
|
127
140
|
return diagnostics;
|
|
128
141
|
}
|
|
129
142
|
function renderPostgresDiagnostics(diagnostics) {
|
|
143
|
+
const connectionUtilizationPct = postgresConnectionUtilizationPct(diagnostics);
|
|
130
144
|
const parts = postgresDiagnosticKeys.flatMap((key) => {
|
|
131
145
|
const value = diagnostics[key];
|
|
132
|
-
|
|
146
|
+
const rendered = value ? [`${key}=${value}`] : [];
|
|
147
|
+
if (key === 'max_connections' && connectionUtilizationPct !== undefined) {
|
|
148
|
+
rendered.push(`connection_utilization_pct=${connectionUtilizationPct}`);
|
|
149
|
+
}
|
|
150
|
+
return rendered;
|
|
133
151
|
});
|
|
134
152
|
return parts.length > 0 ? `OK PostgreSQL diagnostics ${parts.join(' ')}` : undefined;
|
|
135
153
|
}
|
|
@@ -151,19 +169,50 @@ function malformedPostgresDiagnosticKeys(diagnostics) {
|
|
|
151
169
|
const numericKeys = [
|
|
152
170
|
'database_count',
|
|
153
171
|
'active_connections',
|
|
172
|
+
'connection_count',
|
|
173
|
+
'max_connections',
|
|
154
174
|
'total_database_size_bytes',
|
|
155
175
|
];
|
|
156
176
|
return numericKeys.filter((key) => diagnostics[key] !== undefined && integerDiagnostic(diagnostics[key]) === undefined);
|
|
157
177
|
}
|
|
178
|
+
function postgresConnectionUtilizationPct(diagnostics) {
|
|
179
|
+
const connectionCount = integerDiagnostic(diagnostics.connection_count);
|
|
180
|
+
const maxConnections = integerDiagnostic(diagnostics.max_connections);
|
|
181
|
+
if (connectionCount === undefined || maxConnections === undefined || maxConnections <= 0) {
|
|
182
|
+
return undefined;
|
|
183
|
+
}
|
|
184
|
+
return Math.round((connectionCount / maxConnections) * 100);
|
|
185
|
+
}
|
|
186
|
+
function postgresConnectionUtilizationWarning(diagnostics) {
|
|
187
|
+
const connectionCount = integerDiagnostic(diagnostics.connection_count);
|
|
188
|
+
const maxConnections = integerDiagnostic(diagnostics.max_connections);
|
|
189
|
+
const utilizationPct = postgresConnectionUtilizationPct(diagnostics);
|
|
190
|
+
if (connectionCount === undefined ||
|
|
191
|
+
maxConnections === undefined ||
|
|
192
|
+
utilizationPct === undefined ||
|
|
193
|
+
utilizationPct < 80) {
|
|
194
|
+
return undefined;
|
|
195
|
+
}
|
|
196
|
+
return `PostgreSQL connection utilization is high: ${utilizationPct}% of max_connections used (${connectionCount}/${maxConnections}).`;
|
|
197
|
+
}
|
|
158
198
|
function structuredPostgresDiagnostics(diagnostics) {
|
|
159
199
|
const structured = {};
|
|
160
200
|
const databaseCount = integerDiagnostic(diagnostics.database_count);
|
|
161
201
|
const activeConnections = integerDiagnostic(diagnostics.active_connections);
|
|
202
|
+
const connectionCount = integerDiagnostic(diagnostics.connection_count);
|
|
203
|
+
const maxConnections = integerDiagnostic(diagnostics.max_connections);
|
|
204
|
+
const connectionUtilizationPct = postgresConnectionUtilizationPct(diagnostics);
|
|
162
205
|
const totalDatabaseSizeBytes = integerDiagnostic(diagnostics.total_database_size_bytes);
|
|
163
206
|
if (databaseCount !== undefined)
|
|
164
207
|
structured.databaseCount = databaseCount;
|
|
165
208
|
if (activeConnections !== undefined)
|
|
166
209
|
structured.activeConnections = activeConnections;
|
|
210
|
+
if (connectionCount !== undefined)
|
|
211
|
+
structured.connectionCount = connectionCount;
|
|
212
|
+
if (maxConnections !== undefined)
|
|
213
|
+
structured.maxConnections = maxConnections;
|
|
214
|
+
if (connectionUtilizationPct !== undefined)
|
|
215
|
+
structured.connectionUtilizationPct = connectionUtilizationPct;
|
|
167
216
|
if (totalDatabaseSizeBytes !== undefined)
|
|
168
217
|
structured.totalDatabaseSizeBytes = totalDatabaseSizeBytes;
|
|
169
218
|
if (diagnostics.slow_query_logging)
|
|
@@ -584,6 +633,10 @@ export async function getDoctorReport(target = process.cwd(), runnerOrOptions =
|
|
|
584
633
|
available: true,
|
|
585
634
|
diagnostics: structuredPostgresDiagnostics(postgresDiagnostics),
|
|
586
635
|
};
|
|
636
|
+
const connectionUtilizationWarning = postgresConnectionUtilizationWarning(postgresDiagnostics);
|
|
637
|
+
if (connectionUtilizationWarning) {
|
|
638
|
+
warnings.push(connectionUtilizationWarning);
|
|
639
|
+
}
|
|
587
640
|
}
|
|
588
641
|
else {
|
|
589
642
|
const warning = malformedKeys.length > 0
|
package/dist/help.js
CHANGED
|
@@ -110,7 +110,8 @@ Status and doctor:
|
|
|
110
110
|
doctor --fix: applies safe file-level repairs. Runs doctor again after fixes.
|
|
111
111
|
doctor --postgres: adds read-only PostgreSQL diagnostics such as database size,
|
|
112
112
|
sessions currently running queries with pg_stat_activity.state = 'active',
|
|
113
|
-
slow-query readiness,
|
|
113
|
+
connection utilization against max_connections, slow-query readiness,
|
|
114
|
+
extension visibility, and settings.
|
|
114
115
|
Incomplete or malformed PostgreSQL metric rows are reported as unavailable diagnostics.
|
|
115
116
|
|
|
116
117
|
Task recipes:
|