dashboard: Group messages by service
This commit is contained in:
@ -4,11 +4,11 @@ use chrono::{DateTime, Local};
|
||||
use eyre::{eyre, ContextCompat};
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
#[derive(Clone, Copy, Debug, Serialize, Deserialize)]
|
||||
#[derive(Clone, Copy, Debug, Serialize, Deserialize, PartialEq, Eq, PartialOrd, Ord)]
|
||||
pub enum Severity {
|
||||
Fatal,
|
||||
Error,
|
||||
Warning,
|
||||
Error,
|
||||
Fatal,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||
|
||||
@ -1,6 +1,9 @@
|
||||
use std::{cmp::max, collections::BTreeMap};
|
||||
|
||||
use rocket::{http::Status, response::content::RawHtml, State};
|
||||
use rocket_dyn_templates::{context, Template};
|
||||
use serde::Serialize;
|
||||
use snitch_lib::Severity;
|
||||
|
||||
use crate::database::Database;
|
||||
|
||||
@ -9,25 +12,33 @@ pub async fn index(db: &State<Database>) -> Result<RawHtml<Template>, Status> {
|
||||
// TODO:
|
||||
// maybe only show most recent error for each service in dashboard view, i.e.:
|
||||
// select distinct on (service) time, message from (select * from record order by time desc) as foo;
|
||||
let messages = db.get_all_log_messages().map_err(|e| {
|
||||
let records = db.get_all_log_messages().map_err(|e| {
|
||||
log::error!("failed to query database: {e}");
|
||||
Status::InternalServerError
|
||||
})?;
|
||||
|
||||
#[derive(Serialize)]
|
||||
struct ServiceRecords<'a> {
|
||||
first_record: &'a Record,
|
||||
last_record: &'a Record,
|
||||
severity: Severity,
|
||||
all_records: Vec<&'a Record>,
|
||||
}
|
||||
|
||||
#[derive(Serialize)]
|
||||
struct Record {
|
||||
time: String,
|
||||
severity: String,
|
||||
severity: Severity,
|
||||
service: String,
|
||||
message: String,
|
||||
location: String,
|
||||
}
|
||||
|
||||
let messages: Vec<_> = messages
|
||||
let records: Vec<_> = records
|
||||
.into_iter()
|
||||
.map(|(_id, record)| Record {
|
||||
time: record.time.map(|time| time.to_string()).unwrap_or_default(),
|
||||
severity: record.severity.as_str().to_string(),
|
||||
severity: record.severity,
|
||||
service: record.service,
|
||||
message: record.message,
|
||||
location: record
|
||||
@ -38,10 +49,28 @@ pub async fn index(db: &State<Database>) -> Result<RawHtml<Template>, Status> {
|
||||
})
|
||||
.collect();
|
||||
|
||||
let mut records_by_service = BTreeMap::new();
|
||||
|
||||
for record in &records {
|
||||
let entry = records_by_service
|
||||
.entry(record.service.as_str())
|
||||
.or_insert_with(|| ServiceRecords {
|
||||
first_record: record,
|
||||
last_record: record,
|
||||
all_records: vec![],
|
||||
severity: record.severity,
|
||||
});
|
||||
|
||||
entry.last_record = record;
|
||||
entry.all_records.push(record);
|
||||
entry.severity = max(record.severity, entry.severity);
|
||||
}
|
||||
|
||||
Ok(RawHtml(Template::render(
|
||||
"index",
|
||||
context! {
|
||||
messages: &messages
|
||||
records: &records,
|
||||
records_by_service: &records_by_service,
|
||||
},
|
||||
)))
|
||||
}
|
||||
|
||||
@ -26,26 +26,66 @@
|
||||
padding: 0.5em;
|
||||
font-family: 'Ubuntu Mono', mono;
|
||||
}
|
||||
|
||||
.service-error-list {
|
||||
max-height: 20em;
|
||||
font-size: small;
|
||||
overflow: scroll;
|
||||
transition: max-height ease-in-out 0.4s;
|
||||
}
|
||||
|
||||
.collapsed {
|
||||
max-height: 0;
|
||||
}
|
||||
</style>
|
||||
<script>
|
||||
function collapse(id) {
|
||||
document.getElementById(id).classList.toggle("collapsed")
|
||||
}
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
{{#if records}}
|
||||
<table>
|
||||
<tr>
|
||||
<th>Service</th>
|
||||
<th>Severity</th>
|
||||
<th>Time</th>
|
||||
<th>Message</th>
|
||||
<th>Location</th>
|
||||
<th>Service</th>
|
||||
<th>Count</th>
|
||||
<th>Last message at</th>
|
||||
</tr>
|
||||
{{#each messages}}
|
||||
<tr>
|
||||
<td>{{this.service}}</td>
|
||||
{{#each records_by_service}}
|
||||
<tr onclick="collapse('{{@key}}-error-list')">
|
||||
<td>{{this.severity}}</td>
|
||||
<td>{{@key}}</td>
|
||||
<td>{{len this.all_records}}</td>
|
||||
<td>{{this.last_record.time}}</td>
|
||||
</tr>
|
||||
<tr><td colspan="4">
|
||||
<div
|
||||
id="{{@key}}-error-list"
|
||||
class="service-error-list collapsed"
|
||||
>
|
||||
<table>
|
||||
<tr>
|
||||
<th>Severity</th>
|
||||
<th>Message</th>
|
||||
<th>Time</th>
|
||||
</tr>
|
||||
{{#each this.all_records}}
|
||||
<tr>
|
||||
<td>{{this.severity}}</td>
|
||||
<td>{{this.time}}</td>
|
||||
<td>{{this.message}}</td>
|
||||
<td>{{this.location}}</td>
|
||||
<td>{{this.time}}</td>
|
||||
</tr>
|
||||
{{/each}}
|
||||
</table>
|
||||
</div></td></tr>
|
||||
{{/each}}
|
||||
</table>
|
||||
{{else}}
|
||||
<p>
|
||||
No entries! All is well.
|
||||
</p>
|
||||
{{/if}}
|
||||
</body>
|
||||
</html>
|
||||
|
||||
Reference in New Issue
Block a user