Enhance alerts with actionable suggestions.
Added `buildAlertSuggestions` to generate tailored recommendations for various alert categories. Integrated these suggestions into the AlertsPage UI and styled them for clarity, improving user guidance on resolving issues.
This commit is contained in:
@@ -24,6 +24,56 @@ function formatTs(ts) {
|
||||
return new Date(ts).toLocaleString();
|
||||
}
|
||||
|
||||
function buildAlertSuggestions(item) {
|
||||
const name = (item?.name || "").toLowerCase();
|
||||
const category = (item?.category || "").toLowerCase();
|
||||
const source = (item?.source || "").toLowerCase();
|
||||
const value = Number(item?.value || 0);
|
||||
const suggestions = [];
|
||||
|
||||
if (name.includes("reachability") || name.includes("connectivity") || category === "availability") {
|
||||
suggestions.push("Verify host, port, firewall rules, and network routing between backend container and DB target.");
|
||||
suggestions.push("Check PostgreSQL `listen_addresses` and `pg_hba.conf` on the monitored instance.");
|
||||
}
|
||||
if (name.includes("freshness") || item?.message?.toLowerCase().includes("no metrics")) {
|
||||
suggestions.push("Check collector logs and polling interval. Confirm the target credentials are still valid.");
|
||||
suggestions.push("Run a manual connection test in Targets Management and verify SSL mode.");
|
||||
}
|
||||
if (name.includes("cache hit") || category === "performance") {
|
||||
suggestions.push("Inspect slow queries and add/adjust indexes for frequent WHERE/JOIN columns.");
|
||||
suggestions.push("Review shared buffers and query patterns that cause high disk reads.");
|
||||
}
|
||||
if (name.includes("lock") || category === "contention") {
|
||||
suggestions.push("Inspect blocking sessions in `pg_stat_activity` and long transactions.");
|
||||
suggestions.push("Reduce transaction scope/duration and add missing indexes to avoid lock escalation.");
|
||||
}
|
||||
if (name.includes("deadlock")) {
|
||||
suggestions.push("Enforce a consistent table access order in transactions to prevent deadlocks.");
|
||||
suggestions.push("Retry deadlocked transactions in the application with backoff.");
|
||||
}
|
||||
if (name.includes("checkpoint") || category === "io") {
|
||||
suggestions.push("Review `max_wal_size`, `checkpoint_timeout`, and write burst patterns.");
|
||||
suggestions.push("Check disk throughput and WAL pressure during peak load.");
|
||||
}
|
||||
if (name.includes("rollback")) {
|
||||
suggestions.push("Investigate application errors causing transaction rollbacks.");
|
||||
suggestions.push("Validate constraints/input earlier to reduce failed writes.");
|
||||
}
|
||||
if (name.includes("query") || category === "query" || source === "custom") {
|
||||
suggestions.push("Run `EXPLAIN (ANALYZE, BUFFERS)` for the affected query and optimize highest-cost nodes.");
|
||||
suggestions.push("Prioritize fixes for high total-time queries first, then high mean-time queries.");
|
||||
}
|
||||
if (value > 0 && item?.comparison && item?.alert_threshold !== null && item?.alert_threshold !== undefined) {
|
||||
suggestions.push(`Current value is ${value.toFixed(2)} with threshold rule ${item.comparison} ${Number(item.alert_threshold).toFixed(2)}.`);
|
||||
}
|
||||
if (!suggestions.length) {
|
||||
suggestions.push("Start with target activity, locks, and query insights to isolate the root cause.");
|
||||
suggestions.push("Compare current values to the last stable period and tune threshold sensitivity if needed.");
|
||||
}
|
||||
|
||||
return suggestions.slice(0, 4);
|
||||
}
|
||||
|
||||
export function AlertsPage() {
|
||||
const { tokens, refresh, me } = useAuth();
|
||||
const [targets, setTargets] = useState([]);
|
||||
@@ -196,6 +246,7 @@ export function AlertsPage() {
|
||||
<div className="alerts-list">
|
||||
{status.warnings.map((item) => {
|
||||
const isOpen = expandedKey === item.alert_key;
|
||||
const suggestions = buildAlertSuggestions(item);
|
||||
return (
|
||||
<article
|
||||
className={`alert-item warning ${isOpen ? "is-open" : ""}`}
|
||||
@@ -222,6 +273,12 @@ export function AlertsPage() {
|
||||
<div><span>Checked At</span><strong>{formatTs(item.checked_at)}</strong></div>
|
||||
<div><span>Target ID</span><strong>{item.target_id}</strong></div>
|
||||
{item.sql_text && <div className="alert-sql"><code>{item.sql_text}</code></div>}
|
||||
<div className="alert-suggestions">
|
||||
<h4>Recommended actions</h4>
|
||||
<ul>
|
||||
{suggestions.map((tip, idx) => <li key={idx}>{tip}</li>)}
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</article>
|
||||
@@ -239,6 +296,7 @@ export function AlertsPage() {
|
||||
<div className="alerts-list">
|
||||
{status.alerts.map((item) => {
|
||||
const isOpen = expandedKey === item.alert_key;
|
||||
const suggestions = buildAlertSuggestions(item);
|
||||
return (
|
||||
<article
|
||||
className={`alert-item alert ${isOpen ? "is-open" : ""}`}
|
||||
@@ -265,6 +323,12 @@ export function AlertsPage() {
|
||||
<div><span>Checked At</span><strong>{formatTs(item.checked_at)}</strong></div>
|
||||
<div><span>Target ID</span><strong>{item.target_id}</strong></div>
|
||||
{item.sql_text && <div className="alert-sql"><code>{item.sql_text}</code></div>}
|
||||
<div className="alert-suggestions">
|
||||
<h4>Recommended actions</h4>
|
||||
<ul>
|
||||
{suggestions.map((tip, idx) => <li key={idx}>{tip}</li>)}
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</article>
|
||||
|
||||
@@ -936,6 +936,31 @@ td {
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.alert-suggestions {
|
||||
grid-column: 1 / -1;
|
||||
margin-top: 2px;
|
||||
padding: 8px;
|
||||
border-radius: 8px;
|
||||
border: 1px solid #3d689d;
|
||||
background: #0a1f3fb3;
|
||||
}
|
||||
|
||||
.alert-suggestions h4 {
|
||||
margin: 0 0 6px 0;
|
||||
font-size: 13px;
|
||||
}
|
||||
|
||||
.alert-suggestions ul {
|
||||
margin: 0;
|
||||
padding-left: 16px;
|
||||
}
|
||||
|
||||
.alert-suggestions li {
|
||||
margin-bottom: 4px;
|
||||
color: #d4e7ff;
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.alert-form .field-full {
|
||||
grid-column: 1 / -1;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user