Updated the charts Added the packets chart

This patch adds the APRS Packets chart to the charts admin ui.
Also moves the raw json as it's own tab
This commit is contained in:
Hemna 2021-07-22 20:44:20 -04:00
parent be8179415a
commit 6740ff80be
6 changed files with 135 additions and 25 deletions

View File

@ -121,6 +121,13 @@ class APRSDFlask(flask_classful.FlaskView):
} }
stats_dict["aprsd"]["watch_list"] = new_list stats_dict["aprsd"]["watch_list"] = new_list
packet_list = packets.PacketList()
rx = packet_list.total_received()
tx = packet_list.total_sent()
stats_dict["packets"] = {
"sent": tx,
"received": rx,
}
result = { result = {
"time": now.strftime(time_format), "time": now.strftime(time_format),

View File

@ -32,7 +32,18 @@ import time
# local imports here # local imports here
import aprsd import aprsd
from aprsd import client, email, flask, messaging, plugin, stats, threads, trace, utils from aprsd import (
client,
email,
flask,
messaging,
packets,
plugin,
stats,
threads,
trace,
utils,
)
import aprslib import aprslib
from aprslib.exceptions import LoginError from aprslib.exceptions import LoginError
import click import click
@ -519,6 +530,7 @@ def server(
"enabled", "enabled",
True, True,
): ):
packets.PacketList(config)
notify_thread = threads.APRSDNotifyThread( notify_thread = threads.APRSDNotifyThread(
msg_queues=msg_queues, msg_queues=msg_queues,
config=config, config=config,

View File

@ -16,9 +16,13 @@ class PacketList:
"""Class to track all of the packets rx'd and tx'd by aprsd.""" """Class to track all of the packets rx'd and tx'd by aprsd."""
_instance = None _instance = None
config = None
packet_list = {} packet_list = {}
total_recv = 0
total_tx = 0
def __new__(cls, *args, **kwargs): def __new__(cls, *args, **kwargs):
if cls._instance is None: if cls._instance is None:
cls._instance = super().__new__(cls) cls._instance = super().__new__(cls)
@ -26,6 +30,10 @@ class PacketList:
cls._instance.lock = threading.Lock() cls._instance.lock = threading.Lock()
return cls._instance return cls._instance
def __init__(self, config=None):
if config:
self.config = config
def __iter__(self): def __iter__(self):
with self.lock: with self.lock:
return iter(self.packet_list) return iter(self.packet_list)
@ -33,12 +41,22 @@ class PacketList:
def add(self, packet): def add(self, packet):
with self.lock: with self.lock:
packet["ts"] = time.time() packet["ts"] = time.time()
if "from" in packet and packet["from"] == self.config["aprs"]["login"]:
self.total_tx += 1
else:
self.total_recv += 1
self.packet_list.append(packet) self.packet_list.append(packet)
def get(self): def get(self):
with self.lock: with self.lock:
return self.packet_list.get() return self.packet_list.get()
def total_received(self):
return self.total_recv
def total_sent(self):
return self.total_tx
class WatchList: class WatchList:
"""Global watch list and info for callsigns.""" """Global watch list and info for callsigns."""

View File

@ -38,7 +38,7 @@ footer {
#center { #center {
height: 300px; height: 300px;
} }
#messageChart, #emailChart, #memChart { #packetsChart, #messageChart, #emailChart, #memChart {
border: 1px solid #ccc; border: 1px solid #ccc;
background: #ddd; background: #ddd;
} }

View File

@ -8,7 +8,10 @@ window.chartColors = {
blue: 'rgb(54, 162, 235)', blue: 'rgb(54, 162, 235)',
purple: 'rgb(153, 102, 255)', purple: 'rgb(153, 102, 255)',
grey: 'rgb(201, 203, 207)', grey: 'rgb(201, 203, 207)',
black: 'rgb(0, 0, 0)' black: 'rgb(0, 0, 0)',
lightcoral: 'rgb(240,128,128)',
darkseagreen: 'rgb(143, 188,143)'
}; };
function size_dict(d){c=0; for (i in d) ++c; return c} function size_dict(d){c=0; for (i in d) ++c; return c}
@ -20,28 +23,28 @@ function start_charts() {
} }
}); });
memory_chart = new Chart($("#memChart"), { packets_chart = new Chart($("#packetsChart"), {
label: 'Memory Usage', label: 'APRS Packets',
type: 'line', type: 'line',
data: { data: {
labels: [], labels: [],
datasets: [{ datasets: [{
label: 'Peak Ram usage', label: 'Packets Sent',
borderColor: window.chartColors.red, borderColor: window.chartColors.lightcoral,
data: [], data: [],
}, },
{ {
label: 'Current Ram usage', label: 'Packets Recieved',
borderColor: window.chartColors.blue, borderColor: window.chartColors.darkseagreen,
data: [], data: [],
}], }]
}, },
options: { options: {
responsive: true, responsive: true,
maintainAspectRatio: false, maintainAspectRatio: false,
title: { title: {
display: true, display: true,
text: 'Memory Usage', text: 'APRS Packets',
}, },
scales: { scales: {
x: { x: {
@ -67,12 +70,12 @@ function start_charts() {
labels: [], labels: [],
datasets: [{ datasets: [{
label: 'Messages Sent', label: 'Messages Sent',
borderColor: window.chartColors.green, borderColor: window.chartColors.lightcoral,
data: [], data: [],
}, },
{ {
label: 'Messages Recieved', label: 'Messages Recieved',
borderColor: window.chartColors.yellow, borderColor: window.chartColors.darkseagreen,
data: [], data: [],
}, },
{ {
@ -117,12 +120,12 @@ function start_charts() {
labels: [], labels: [],
datasets: [{ datasets: [{
label: 'Sent', label: 'Sent',
borderColor: window.chartColors.green, borderColor: window.chartColors.lightcoral,
data: [], data: [],
}, },
{ {
label: 'Recieved', label: 'Recieved',
borderColor: window.chartColors.yellow, borderColor: window.chartColors.darkseagreen,
data: [], data: [],
}], }],
}, },
@ -149,6 +152,46 @@ function start_charts() {
} }
} }
}); });
memory_chart = new Chart($("#memChart"), {
label: 'Memory Usage',
type: 'line',
data: {
labels: [],
datasets: [{
label: 'Peak Ram usage',
borderColor: window.chartColors.red,
data: [],
},
{
label: 'Current Ram usage',
borderColor: window.chartColors.blue,
data: [],
}],
},
options: {
responsive: true,
maintainAspectRatio: false,
title: {
display: true,
text: 'Memory Usage',
},
scales: {
x: {
type: 'timeseries',
offset: true,
ticks: {
major: { enabled: true },
fontStyle: context => context.tick.major ? 'bold' : undefined,
source: 'data',
maxRotation: 0,
autoSkip: true,
autoSkipPadding: 75,
}
}
}
}
});
} }
@ -182,6 +225,7 @@ function update_stats( data ) {
const html_pretty = Prism.highlight(JSON.stringify(data, null, '\t'), Prism.languages.json, 'json'); const html_pretty = Prism.highlight(JSON.stringify(data, null, '\t'), Prism.languages.json, 'json');
$("#jsonstats").html(html_pretty); $("#jsonstats").html(html_pretty);
short_time = data["time"].split(/\s(.+)/)[1]; short_time = data["time"].split(/\s(.+)/)[1];
updateDualData(packets_chart, short_time, data["stats"]["packets"]["sent"], data["stats"]["packets"]["received"]);
updateQuadData(message_chart, short_time, data["stats"]["messages"]["sent"], data["stats"]["messages"]["recieved"], data["stats"]["messages"]["ack_sent"], data["stats"]["messages"]["ack_recieved"]); updateQuadData(message_chart, short_time, data["stats"]["messages"]["sent"], data["stats"]["messages"]["recieved"], data["stats"]["messages"]["ack_sent"], data["stats"]["messages"]["ack_recieved"]);
updateDualData(email_chart, short_time, data["stats"]["email"]["sent"], data["stats"]["email"]["recieved"]); updateDualData(email_chart, short_time, data["stats"]["email"]["sent"], data["stats"]["email"]["recieved"]);
updateDualData(memory_chart, short_time, data["stats"]["aprsd"]["memory_peak"], data["stats"]["aprsd"]["memory_current"]); updateDualData(memory_chart, short_time, data["stats"]["aprsd"]["memory_peak"], data["stats"]["aprsd"]["memory_current"]);

View File

@ -41,6 +41,7 @@
var cfg_pretty = JSON.stringify(cfg_json, null, '\t'); var cfg_pretty = JSON.stringify(cfg_json, null, '\t');
const html_pretty = Prism.highlight( cfg_pretty, Prism.languages.json, 'json'); const html_pretty = Prism.highlight( cfg_pretty, Prism.languages.json, 'json');
$("#configjson").html(html_pretty); $("#configjson").html(html_pretty);
$("#jsonstats").fadeToggle(1000);
$('.ui.accordion').accordion({exclusive: false}); $('.ui.accordion').accordion({exclusive: false});
$('.menu .item').tab('change tab', 'charts-tab'); $('.menu .item').tab('change tab', 'charts-tab');
@ -71,22 +72,45 @@
<div class="item" data-tab="msgs-tab">Messages</div> <div class="item" data-tab="msgs-tab">Messages</div>
<div class="item" data-tab="watch-tab">Watch List</div> <div class="item" data-tab="watch-tab">Watch List</div>
<div class="item" data-tab="config-tab">Config</div> <div class="item" data-tab="config-tab">Config</div>
<div class="item" data-tab="raw-tab">Raw JSON</div>
</div> </div>
<!-- Tab content --> <!-- Tab content -->
<div class="ui bottom attached active tab segment" data-tab="charts-tab"> <div class="ui bottom attached active tab segment" data-tab="charts-tab">
<h3 class="ui dividing header">Charts</h3> <h3 class="ui dividing header">Charts</h3>
<div id="graphs"> <div class="ui equal width relaxed grid">
<div id="left"><canvas id="messageChart"></canvas></div> <div class="row">
<div id="right"><canvas class="right" id="emailChart"></canvas></div> <div class="column">
</div> <div class="ui segment" style="height: 300px">
<div id="graphs_center"> <canvas id="packetsChart"></canvas>
<div id="center"><canvas id="memChart"></canvas></div> </div>
</div> </div>
<div id="stats"> <div class="column">
<button class="ui button" id="toggleStats">Toggle raw json</button> <div class="ui segment" style="height: 300px">
<pre id="jsonstats" class="language-json">{{ stats }}</pre> <canvas id="messageChart"></canvas>
</div>
</div>
</div>
<div class="row">
<div class="column">
<div class="ui segment" style="height: 300px">
<canvas id="emailChart"></canvas>
</div>
</div>
<div class="column">
<div class="ui segment" style="height: 300px">
<canvas id="memChart"></canvas>
</div>
</div>
</div>
<!-- <div class="row">
<div id="stats" class="two column">
<button class="ui button" id="toggleStats">Toggle raw json</button>
<pre id="jsonstats" class="language-json">{{ stats }}</pre>
</div> --!>
</div>
</div> </div>
</div> </div>
<div class="ui bottom attached tab segment" data-tab="msgs-tab"> <div class="ui bottom attached tab segment" data-tab="msgs-tab">
@ -110,6 +134,11 @@
<pre id="configjson" class="language-json">{{ config_json|safe }}</pre> <pre id="configjson" class="language-json">{{ config_json|safe }}</pre>
</div> </div>
<div class="ui bottom attached tab segment" data-tab="raw-tab">
<h3 class="ui dividing header">Raw JSON</h3>
<pre id="jsonstats" class="language-json">{{ stats|safe }}</pre>
</div>
<div class="ui text container"> <div class="ui text container">
<a href="https://badge.fury.io/py/aprsd"><img src="https://badge.fury.io/py/aprsd.svg" alt="PyPI version" height="18"></a> <a href="https://badge.fury.io/py/aprsd"><img src="https://badge.fury.io/py/aprsd.svg" alt="PyPI version" height="18"></a>
<a href="https://github.com/craigerl/aprsd"><img src="https://img.shields.io/badge/Made%20with-Python-1f425f.svg" height="18"></a> <a href="https://github.com/craigerl/aprsd"><img src="https://img.shields.io/badge/Made%20with-Python-1f425f.svg" height="18"></a>