Skip to content

Commit

Permalink
feat: adds filterable stats on audit dashboard
Browse files Browse the repository at this point in the history
  • Loading branch information
mrferris committed Nov 3, 2023
1 parent 347b3fb commit dc05b2a
Show file tree
Hide file tree
Showing 6 changed files with 262 additions and 130 deletions.
128 changes: 107 additions & 21 deletions glados-web/src/routes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,9 @@ use axum::{
Json,
};
use chrono::{DateTime, Duration, Utc};
use entity::{census, census_node, client_info, content_audit::SelectionStrategy};
use entity::{
census, census_node, client_info, content::SubProtocol, content_audit::SelectionStrategy,
};
use entity::{
content,
content_audit::{self, AuditResult},
Expand All @@ -18,7 +20,7 @@ use ethportal_api::{HistoryContentKey, OverlayContentKey};
use migration::{Alias, IntoCondition, JoinType, Order};
use sea_orm::{
sea_query::{Expr, Query, SeaRc},
RelationTrait,
RelationTrait, Select,
};
use sea_orm::{
ColumnTrait, ConnectionTrait, DatabaseConnection, DbBackend, DynIden, EntityTrait,
Expand Down Expand Up @@ -801,10 +803,12 @@ pub enum ContentTypeFilter {
Receipts,
}

/// Takes an AuditFilter object generated from http query params
/// Conditionally creates a query based on the filters
pub async fn contentaudit_filter(
Extension(state): Extension<Arc<State>>,
filters: HttpQuery<AuditFilters>,
) -> impl IntoResponse {
) -> Result<HtmlTemplate<AuditTableTemplate>, StatusCode> {
let audits = content_audit::Entity::find();

let audits = match filters.strategy {
Expand Down Expand Up @@ -835,41 +839,70 @@ pub async fn contentaudit_filter(
JoinType::InnerJoin,
content_audit::Relation::Content
.def()
.on_condition(|_left, _right| {
Expr::cust("get_byte(content.content_key, 0) = 0x00").into_condition()
.on_condition(|_left, right| {
Expr::cust("get_byte(content.content_key, 0) = 0x00")
.and(
Expr::col((right, content::Column::ProtocolId))
.eq(SubProtocol::History),
)
.into_condition()
}),
),

ContentTypeFilter::Bodies => audits.join(
JoinType::InnerJoin,
content_audit::Relation::Content
.def()
.on_condition(|_left, _right| {
Expr::cust("get_byte(content.content_key, 0) = 0x01").into_condition()
.on_condition(|_left, right| {
Expr::cust("get_byte(content.content_key, 0) = 0x01")
.and(
Expr::col((right, content::Column::ProtocolId))
.eq(SubProtocol::History),
)
.into_condition()
}),
),
ContentTypeFilter::Receipts => audits.join(
JoinType::InnerJoin,
content_audit::Relation::Content
.def()
.on_condition(|_left, _right| {
Expr::cust("get_byte(content.content_key, 0) = 0x02").into_condition()
.on_condition(|_left, right| {
Expr::cust("get_byte(content.content_key, 0) = 0x02")
.and(
Expr::col((right, content::Column::ProtocolId))
.eq(SubProtocol::History),
)
.into_condition()
}),
),
};
let audits = audits
.order_by_desc(content_audit::Column::CreatedAt)
.limit(100)
.all(&state.database_connection)
.await
.unwrap();

let audits = get_audit_tuples_from_audit_models(audits, &state.database_connection)
.await
.unwrap();
let (hour_stats, day_stats, week_stats, filtered_audits) = tokio::join!(
get_filtered_audit_stats(audits.clone(), Period::Hour, &state.database_connection),
get_filtered_audit_stats(audits.clone(), Period::Day, &state.database_connection),
get_filtered_audit_stats(audits.clone(), Period::Week, &state.database_connection),
audits
.order_by_desc(content_audit::Column::CreatedAt)
.limit(30)
.all(&state.database_connection),
);

let template = AuditTableTemplate { audits };
HtmlTemplate(template)
let filtered_audits = filtered_audits.map_err(|e| {
error!(err=?e, "Could not look up audit stats");
StatusCode::INTERNAL_SERVER_ERROR
})?;
let hour_stats = hour_stats?;
let day_stats = day_stats?;
let week_stats = week_stats?;

let filtered_audits: Vec<AuditTuple> =
get_audit_tuples_from_audit_models(filtered_audits, &state.database_connection).await?;

let template = AuditTableTemplate {
stats: [hour_stats, day_stats, week_stats],
audits: filtered_audits,
};

Ok(HtmlTemplate(template))
}

pub enum Period {
Expand Down Expand Up @@ -991,6 +1024,59 @@ pub struct Stats {
pub audits_per_minute: u32,
}

async fn get_filtered_audit_stats(
filtered: Select<content_audit::Entity>,
period: Period,
conn: &DatabaseConnection,
) -> Result<Stats, StatusCode> {
let cutoff = period.cutoff_time();

let total_audits = filtered
.clone()
.filter(content_audit::Column::CreatedAt.gt(cutoff))
.count(conn)
.await
.map_err(|e| {
error!(err=?e, "Could not look up audit stats");
StatusCode::INTERNAL_SERVER_ERROR
})? as u32;

let total_passes = filtered
.filter(content_audit::Column::CreatedAt.gt(cutoff))
.filter(content_audit::Column::Result.eq(AuditResult::Success))
.count(conn)
.await
.map_err(|e| {
error!(err=?e, "Could not look up audit stats");
StatusCode::INTERNAL_SERVER_ERROR
})? as u32;

let total_failures = total_audits - total_passes;

let audits_per_minute = 0;

let (pass_percent, fail_percent) = if total_audits == 0 {
(0.0, 0.0)
} else {
let total_audits = total_audits as f32;
(
(total_passes as f32) * 100.0 / total_audits,
(total_failures as f32) * 100.0 / total_audits,
)
};

Ok(Stats {
period,
new_content: 0,
total_audits,
total_passes,
pass_percent,
total_failures,
fail_percent,
audits_per_minute,
})
}

async fn get_audit_stats(period: Period, conn: &DatabaseConnection) -> Result<Stats, StatusCode> {
let cutoff = period.cutoff_time();
let new_content = content::Entity::find()
Expand Down
13 changes: 7 additions & 6 deletions glados-web/src/templates.rs
Original file line number Diff line number Diff line change
Expand Up @@ -56,12 +56,6 @@ pub struct ContentDashboardTemplate {
pub recent_audit_failures: Vec<AuditTuple>,
}

#[derive(Template)]
#[template(path = "audit_table.html")]
pub struct AuditTableTemplate {
pub audits: Vec<AuditTuple>,
}

#[derive(Template)]
#[template(path = "contentid_list.html")]
pub struct ContentIdListTemplate {
Expand Down Expand Up @@ -93,6 +87,13 @@ pub struct ContentKeyListTemplate {
#[template(path = "audit_dashboard.html")]
pub struct AuditDashboardTemplate {}

#[derive(Template)]
#[template(path = "audit_table.html")]
pub struct AuditTableTemplate {
pub stats: [Stats; 3],
pub audits: Vec<AuditTuple>,
}

#[derive(Template)]
#[template(path = "contentkey_detail.html")]
pub struct ContentKeyDetailTemplate {
Expand Down
58 changes: 30 additions & 28 deletions glados-web/templates/audit_dashboard.html
Original file line number Diff line number Diff line change
Expand Up @@ -9,34 +9,36 @@
<div class="col">
<ul>
<br />
<h1 class="header">Audit Dashboard</h1>
<div id="content-buttons" class="btn-group mr-2" role="group">
<button id="all-content-button" filter="All" class="btn btn-outline-secondary" type="button">All
</button>
<button id="headers-button" filter="Headers" class="btn btn-outline-secondary"
type="button">Headers</button>
<button id="bodies-button" filter="Bodies" class="btn btn-outline-secondary"
type="button">Bodies</button>
<button id="receipts-button" filter="Receipts" class="btn btn-outline-secondary"
type="button">Receipts</button>
</div>
<div id="strategy-buttons" class="btn-group">
<button id="all-strategy-button" filter="All" class="btn btn-outline-secondary"
type="button">All</button>
<button id="latest-button" filter="Latest" class="btn btn-outline-secondary"
type="button">Latest</button>
<button id="random-button" filter="Random" class="btn btn-outline-secondary"
type="button">Random</button>
<button id="oldest-button" filter="Oldest" class="btn btn-outline-secondary" type="button">Oldest
Unaudited</button>
</div>
<div id="success-buttons" class="btn-group">
<button id="all-success-button" filter="All" class="btn btn-outline-secondary"
type="button">All</button>
<button id="success-button" filter="Success" class="btn btn-outline-secondary" type="button">Success
</button>
<button id="failure-button" filter="Failure" class="btn btn-outline-secondary"
type="button">Failure</button>
<h1 class="header text-center">Audit Dashboard</h1>
<div class="d-flex justify-content-center flex-wrap">
<div id="content-buttons" class="btn-group mx-1" role="group">
<button id="all-content-button" filter="All" class="btn btn-outline-secondary"
type="button">All</button>
<button id="headers-button" filter="Headers" class="btn btn-outline-secondary"
type="button">Headers</button>
<button id="bodies-button" filter="Bodies" class="btn btn-outline-secondary"
type="button">Bodies</button>
<button id="receipts-button" filter="Receipts" class="btn btn-outline-secondary"
type="button">Receipts</button>
</div>
<div id="strategy-buttons" class="btn-group mx-1" role="group">
<button id="all-strategy-button" filter="All" class="btn btn-outline-secondary"
type="button">All</button>
<button id="latest-button" filter="Latest" class="btn btn-outline-secondary"
type="button">Latest</button>
<button id="random-button" filter="Random" class="btn btn-outline-secondary"
type="button">Random</button>
<button id="oldest-button" filter="Oldest" class="btn btn-outline-secondary" type="button">Oldest
Unaudited</button>
</div>
<div id="success-buttons" class="btn-group mx-1 " role="group">
<button id="all-success-button" filter="All" class="btn btn-outline-secondary"
type="button">All</button>
<button id="success-button" filter="Success" class="btn btn-outline-secondary"
type="button">Success</button>
<button id="failure-button" filter="Failure" class="btn btn-outline-secondary"
type="button">Failure</button>
</div>
</div>

</ul>
Expand Down
Loading

0 comments on commit dc05b2a

Please sign in to comment.