render missing entries

This commit is contained in:
4cuck committed 2023-07-28 03:14:59 +02:00
1 parent 29489b5618
commit 660da56c3f
5 files changed
+73 -44

No files matched your search

+1 -1
View File
@@ -27,4 +27,4 @@ REFERER="https://localhost"
# Ping AVG period in hours
PING_RANGE_H="3"
# enable/disable startup scanning
#DISABLE_STARTUP_SCAN=true
DISABLE_STARTUP_SCAN=false
+3 -3
View File
@@ -30,9 +30,9 @@ pub struct CacheHost {
pub domain: String,
pub points: i32,
pub rss: bool,
pub recent_pings: Vec<i32>,
pub ping_max: i32,
pub ping_min: i32,
pub recent_pings: Vec<Option<i32>>,
pub ping_max: Option<i32>,
pub ping_min: Option<i32>,
pub ping_avg: Option<i32>,
pub version: Option<String>,
pub healthy: bool,
+30 -22
View File
@@ -39,10 +39,12 @@ pub struct LastPingsQuery {
ping: i32,
}
#[derive(Debug)]
#[derive(Debug, Default)]
struct LastPings {
avg: i32,
pings: Vec<i32>,
avg: Option<i32>,
min: Option<i32>,
max: Option<i32>,
pings: Vec<Option<i32>>,
}
#[derive(Debug, FromQueryResult)]
@@ -123,9 +125,9 @@ impl Scanner {
rss: host.rss,
version: host.version,
healthy: last_check.healthy,
ping_max: host_ping_data.as_ref().and_then(|v|v.pings.iter().max().cloned()).unwrap_or(0i32),
ping_min: host_ping_data.as_ref().and_then(|v|v.pings.iter().min().cloned()).unwrap_or(0i32),
ping_avg: host_ping_data.as_ref().map(|v|v.avg),
ping_max: host_ping_data.as_ref().and_then(|v|v.max),
ping_min: host_ping_data.as_ref().and_then(|v|v.min),
ping_avg: host_ping_data.as_ref().and_then(|v|v.avg),
recent_pings: host_ping_data.map(|v|v.pings).unwrap_or_default(),
})
}
@@ -149,15 +151,15 @@ impl Scanner {
#[derive(Debug, FromQueryResult, Default)]
struct PingEntry {
host: i32,
ping: i32,
ping: Option<i32>,
}
let last_pings = PingEntry::find_by_statement(Statement::from_sql_and_values(
DbBackend::Sqlite,
r#"
SELECT u.host,u.resp_time as ping FROM update_check u
SELECT u.host,(CASE u.healthy WHEN true THEN u.resp_time ELSE null END) as ping FROM update_check u
JOIN host h ON h.id = u.host
WHERE h.enabled = true AND u.healthy = true AND u.time >= $1
ORDER BY u.host,u.time DESC
WHERE h.enabled = true AND u.time >= $1
ORDER BY u.host,u.time ASC
"#,
[age.into()],
))
@@ -169,31 +171,37 @@ impl Scanner {
None => {return Ok(HashMap::new());},
Some(v) => v,
};
let mut current_entry = LastPings {
pings: Vec::new(),// TODO: optimize capacity
avg: 0,
};
let mut current_entry = LastPings::default();
let mut last_host = first.host;
let mut non_null_entries = first.ping.as_ref().map_or(0, |_|1);
current_entry.pings.push(first.ping);
for ping in iter {
if last_host != ping.host {
let mut new_entry = LastPings{
avg: 0,
pings: Vec::new(),
};
let mut new_entry = LastPings::default();
// will overflow only if we hit > 1500 days of backlog
// when having 5 minutes interval and only 5000ms response times
current_entry.avg = (current_entry.pings.iter().copied().sum::<i32>() / (current_entry.pings.len() as i32) ) as i32;
if let Some(sum) = current_entry.avg {
current_entry.avg = Some(sum / non_null_entries);
}
non_null_entries = 0;
std::mem::swap(&mut new_entry, &mut current_entry);
// insert back the old (swapped) entry
assert_eq!(map.insert(last_host, new_entry).is_some(),false);
last_host = ping.host;
}
if let Some(ping) = ping.ping.as_ref() {
current_entry.avg = Some(current_entry.avg.unwrap_or(0) + ping);
non_null_entries += 1;
current_entry.min = Some(current_entry.min.map_or(*ping,|v|v.min(*ping)));
current_entry.max = Some(current_entry.max.map_or(*ping,|v|v.max(*ping)));
}
current_entry.pings.push(ping.ping);
}
// Insert last one
current_entry.avg = (current_entry.pings.iter().copied().sum::<i32>() / (current_entry.pings.len() as i32) ) as i32;
map.insert(last_host, current_entry);
// Insert last entry
if let Some(sum) = current_entry.avg {
current_entry.avg = Some(sum / non_null_entries);
}
assert_eq!(map.insert(last_host, current_entry).is_some(),false);
Ok(map)
}
-1
View File
@@ -19,7 +19,6 @@ pub async fn instances(
context.insert("instances", &guard.hosts);
let time = guard.last_update.format("%Y.%m.%d %H:%M").to_string();
context.insert("last_updated", &time);
let res = Html(template.render("instances.html.j2", &context)?).into_response();
drop(guard);
res
+39 -17
View File
@@ -26,34 +26,56 @@
</tr>
</thead>
<tbody>
{% for host in instances %}
{% for host in instances -%}
<tr>
<td><a href="{{host.url}}">{{host.domain}}</a></td>
<td>{% if host.healthy%} ✅ {% else %} ❌ {% endif %}</td>
<td>{% if host.healthy -%} ✅ {% else -%} ❌ {% endif -%}</td>
<td>
{% if host.recent_pings|length > 0 %}
{% set height = 57 %}
{% set width = 182 %}
{% set amount = host.recent_pings|length %}
{% set width_bar = width / amount %}
{% set offset = 5 %}
{% set step_size = (host.ping_max - host.ping_min)/(height-offset) %}
{% if host.recent_pings|length > 0 -%}
{% set height = 57 -%}
{% set width = 182 -%}
{% set amount = host.recent_pings|length -%}
{% set width_bar = width / amount -%}
{% set offset = 5 -%}
{% set error_size = height / 3 %}
{% if host.ping_max and host.ping_min -%}
{# only one entry, so max = min => step_size would be 0 #}
{% if host.ping_max == host.ping_min -%}
{% set step_size = 5/(height-offset) -%}
{% else -%}
{% set step_size = (host.ping_max - host.ping_min)/(height-offset) -%}
{% endif -%}
{% else %}
{# no valid entries, only nulls #}
{% set step_size = 5/(height-offset) -%}
{% endif %}
{# <!-- step size {{step_size}} -->
<!-- ping_max {{host.ping_max}} -->
<!-- ping_min {{host.ping_min}} --> #}
<svg viewBox="0 0 182 56" width="{{width - 1}}" height="{{height - 1}}">
{% set avg_pos = (height-(host.ping_avg - host.ping_min )/step_size) - offset %}
<line x1="1" x2="181" y1="{{avg_pos}}" y2="{{avg_pos}}" stroke="black" stroke-width="0.72727275" stroke-linecap="butt" stroke-opacity="0.3"><title>Average</title></line>
{% for ping in host.recent_pings %}
{% set height_bar = (ping - host.ping_min )/step_size + offset%}
<rect x="{{(loop.index-1) * width_bar}}" y="{{height - height_bar - offset}}" width="{{width_bar}}" height="{{height_bar}}" fill="#a09df2" fill-opacity="0.95"><title>{{ping}}</title></rect>
{% endfor %}
{% if host.ping_avg and host.ping_min -%}
{% set avg_pos = (height-(host.ping_avg - host.ping_min )/step_size) - offset -%}
<line x1="1" x2="181" y1="{{avg_pos}}" y2="{{avg_pos}}" stroke="black" stroke-width="0.72727275" stroke-linecap="butt" stroke-opacity="0.3"><title>Average</title></line>
{% endif -%}
{% for ping in host.recent_pings -%}
{% if ping -%}
{% set height_bar = (ping - host.ping_min )/step_size + offset -%}
{% set color_bar = "#a09df2" -%}
{% else %}
{% set height_bar = error_size -%}
{% set color_bar = "#cc0000" -%}
{% endif %}
<rect x="{{(loop.index-1) * width_bar}}" y="{{height - height_bar - offset}}" width="{{width_bar}}" height="{{height_bar}}" fill="{{color_bar}}" fill-opacity="0.95"><title>{{ping | default(value="unhealthy") }}</title></rect>
{% endfor -%}
</svg>
{% endif %}
</td>
<td>{{host.ping_avg}}</td>
<td>{% if host.rss%} ✅ {% else %} ❌ {% endif %}</td>
<td>{% if host.rss -%} ✅ {% else %} ❌ {% endif %}</td>
<td>{{host.version}}</td>
<td>{{host.points}}</td>
</tr>
{% endfor %}
{% endfor -%}
</tbody>
</table>
</div>