Skip to content

Commit f4eab9e

Browse files
author
Your Name
committed
feat: Implement Prometheus deep linking for alerts, including URL rewriting and UI display.
1 parent 540bb4e commit f4eab9e

File tree

6 files changed

+47
-7
lines changed

6 files changed

+47
-7
lines changed

src/domain/entities/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,7 @@ pub struct Alert {
8989
pub pod: Option<String>,
9090
pub started_at: DateTime<Utc>,
9191
pub fingerprint: String,
92+
pub generator_url: Option<String>,
9293
}
9394

9495
/// Grouped alerts response

src/domain/services/alert_service.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,7 @@ impl AlertDomainService {
5858
pod: Option<String>,
5959
started_at: DateTime<Utc>,
6060
fingerprint: String,
61+
generator_url: Option<String>,
6162
) -> Alert {
6263
Alert {
6364
name,
@@ -69,6 +70,7 @@ impl AlertDomainService {
6970
pod,
7071
started_at,
7172
fingerprint,
73+
generator_url,
7274
}
7375
}
7476

src/domain/services/fusion_service.rs

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ pub struct UnifiedEvent {
1313
pub message: String, // summary or message
1414
pub timestamp: String, // ISO8601
1515
pub details: Value, // Original payload
16+
pub external_url: Option<String>,
1617
}
1718

1819
pub async fn get_fusion_events() -> Result<Vec<UnifiedEvent>, String> {
@@ -41,6 +42,22 @@ pub async fn get_fusion_events() -> Result<Vec<UnifiedEvent>, String> {
4142
.unwrap_or("")
4243
.to_string();
4344

45+
let mut external_url = alert
46+
.get("generator_url")
47+
.and_then(|s| s.as_str())
48+
.map(|s| s.to_string());
49+
50+
// Rewrite internal Prometheus URLs to public ones
51+
if let Some(ref url) = external_url {
52+
if url.contains("kube-prometheus-stack-prometheus") || url.contains(".svc") {
53+
// Option 1: Deep link (keep query params)
54+
// external_url = Some(url.replace("http://kube-prometheus-stack-prometheus.kube-prometheus-stack.svc:9090", "https://prometheus.p.zacharie.org"));
55+
56+
// Option 2: Use the specific URL requested by the user
57+
external_url = Some("https://prometheus.p.zacharie.org/alerts?page=1&state=firing&state=pending".to_string());
58+
}
59+
}
60+
4461
let timestamp = chrono::Utc::now().to_rfc3339(); // Alerts don't always have timestamp in the simplified view, use now or try to extract
4562

4663
unified_events.push(UnifiedEvent {
@@ -52,6 +69,7 @@ pub async fn get_fusion_events() -> Result<Vec<UnifiedEvent>, String> {
5269
message: summary,
5370
timestamp,
5471
details: alert.clone(),
72+
external_url,
5573
});
5674
}
5775
}
@@ -115,6 +133,7 @@ pub async fn get_fusion_events() -> Result<Vec<UnifiedEvent>, String> {
115133
message,
116134
timestamp: timestamp_str,
117135
details: event.clone(),
136+
external_url: None, // K8s events don't have external URLs for now
118137
});
119138
}
120139
}

src/domain/services/monitoring_service.rs

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,8 @@ pub async fn get_alerts() -> Result<Value, String> {
2222
"severity": "critical",
2323
"instance": alert.pod.as_ref().or(alert.namespace.as_ref()).unwrap_or(&"unknown".to_string()),
2424
"summary": alert.summary,
25-
"status": alert.state
25+
"status": alert.state,
26+
"generator_url": alert.generator_url
2627
}));
2728
}
2829

@@ -32,7 +33,8 @@ pub async fn get_alerts() -> Result<Value, String> {
3233
"severity": "warning",
3334
"instance": alert.pod.as_ref().or(alert.namespace.as_ref()).unwrap_or(&"unknown".to_string()),
3435
"summary": alert.summary,
35-
"status": alert.state
36+
"status": alert.state,
37+
"generator_url": alert.generator_url
3638
}));
3739
}
3840

@@ -42,7 +44,8 @@ pub async fn get_alerts() -> Result<Value, String> {
4244
"severity": "info",
4345
"instance": alert.pod.as_ref().or(alert.namespace.as_ref()).unwrap_or(&"unknown".to_string()),
4446
"summary": alert.summary,
45-
"status": alert.state
47+
"status": alert.state,
48+
"generator_url": alert.generator_url
4649
}));
4750
}
4851

src/infrastructure/repositories/alert_repository.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,8 @@ struct AmAlert {
2929
starts_at: String,
3030
#[serde(rename = "endsAt")]
3131
_ends_at: String,
32+
#[serde(rename = "generatorURL")]
33+
generator_url: String,
3234
fingerprint: String,
3335
status: AmAlertStatus,
3436
}
@@ -176,6 +178,7 @@ impl AlertRepositoryImpl {
176178
pod,
177179
started_at,
178180
am_alert.fingerprint,
181+
Some(am_alert.generator_url),
179182
)
180183
})
181184
.collect();

static/js/monitors.js

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -157,13 +157,25 @@ const MonitorsManager = {
157157
</div>
158158
</div>
159159
160-
<div style="margin-bottom: 8px; color: var(--text-color);">
160+
<div style="margin-bottom: 12px; color: var(--text-color); line-height: 1.5;">
161161
${item.message}
162162
</div>
163163
164-
<div style="display: flex; gap: 15px; font-size: 0.8rem; opacity: 0.7; font-family: 'JetBrains Mono', monospace;">
165-
<span>📁 ${item.namespace}</span>
166-
<span>🏷️ ${item.event_type}</span>
164+
<div style="display: flex; justify-content: space-between; align-items: flex-end;">
165+
<div style="display: flex; gap: 15px; font-size: 0.8rem; opacity: 0.7; font-family: 'JetBrains Mono', monospace;">
166+
<span>📁 ${item.namespace}</span>
167+
<span>🏷️ ${item.event_type}</span>
168+
</div>
169+
${item.external_url ? `
170+
<a href="${item.external_url}" target="_blank" class="cyber-btn" style="
171+
padding: 2px 8px;
172+
font-size: 0.7rem;
173+
text-decoration: none;
174+
border-color: ${borderColor};
175+
color: ${borderColor};
176+
background: rgba(0,0,0,0.3);
177+
">🔍 VIEW IN PROMETHEUS</a>
178+
` : ''}
167179
</div>
168180
</div>
169181
`;

0 commit comments

Comments
 (0)