Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add cpu usage chart #1344

Merged
merged 4 commits into from
May 18, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
66 changes: 49 additions & 17 deletions coreplugins/diagnostic/plugin.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,8 @@
from app.plugins import PluginBase, Menu, MountPoint
from rest_framework.response import Response
from rest_framework import status, permissions
from rest_framework.decorators import api_view, permission_classes

from app.plugins import PluginBase, Menu, MountPoint, get_current_plugin
from django.shortcuts import render
from django.contrib.auth.decorators import login_required
from django.utils.translation import gettext as _
Expand Down Expand Up @@ -30,30 +34,58 @@ def get_memory_stats():
except:
return {}

def get_diagnostic_stats():
plugin = get_current_plugin()
with plugin.python_imports():
import psutil

# Disk space
total_disk_space, used_disk_space, free_disk_space = shutil.disk_usage('./')

# CPU Stats
cpu_percent_used = psutil.cpu_percent()
cpu_percent_free = 100 - cpu_percent_used
cpu_freq = psutil.cpu_freq()

diagnostic_stats = {
'total_disk_space': total_disk_space,
'used_disk_space': used_disk_space,
'free_disk_space': free_disk_space,
'cpu_percent_used': round(cpu_percent_used, 2),
'cpu_percent_free': round(cpu_percent_free, 2),
'cpu_freq_current': round(cpu_freq.current / 1000, 2),
}

# Memory (Linux only)
memory_stats = get_memory_stats()
if 'free' in memory_stats:
diagnostic_stats['free_memory'] = memory_stats['free']
diagnostic_stats['used_memory'] = memory_stats['used']
diagnostic_stats['total_memory'] = memory_stats['total']

return diagnostic_stats

class Plugin(PluginBase):
def main_menu(self):
return [Menu(_("Diagnostic"), self.public_url(""), "fa fa-chart-pie fa-fw")]

def api_mount_points(self):

@api_view()
@permission_classes((permissions.IsAuthenticated,))
def diagnostic(request):
diagnostic_stats = get_diagnostic_stats()
return Response(diagnostic_stats)

return [
MountPoint('/', diagnostic)
]

def app_mount_points(self):
@login_required
def diagnostic(request):
# Disk space
total_disk_space, used_disk_space, free_disk_space = shutil.disk_usage('./')

template_args = {
'title': 'Diagnostic',
'total_disk_space': total_disk_space,
'used_disk_space': used_disk_space,
'free_disk_space': free_disk_space
}

# Memory (Linux only)
memory_stats = get_memory_stats()
if 'free' in memory_stats:
template_args['free_memory'] = memory_stats['free']
template_args['used_memory'] = memory_stats['used']
template_args['total_memory'] = memory_stats['total']
template_args = get_diagnostic_stats()
template_args['title'] = 'Diagnostic'

return render(request, self.template_path("diagnostic.html"), template_args)

Expand Down
1 change: 1 addition & 0 deletions coreplugins/diagnostic/requirements.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
psutil==5.9.5
252 changes: 185 additions & 67 deletions coreplugins/diagnostic/templates/diagnostic.html
Original file line number Diff line number Diff line change
Expand Up @@ -11,20 +11,34 @@ <h4>{% trans 'Storage Space' %}</h4>
<div style="width: 80%; margin-left: 10%;">
<canvas id="diskChart" width="200" height="200" style="margin-bottom: 12px;"></canvas>
</div>
<p><b>{% trans 'Free' context 'Megabytes of storage space' %}:</b> {{ free_disk_space|filesizeformat }} |
<p id="storageStatsLabel">
<b>{% trans 'Free' context 'Megabytes of storage space' %}:</b> {{ free_disk_space|filesizeformat }} |
<b>{% trans 'Used' context 'Megabytes of storage space' %}:</b> {{ used_disk_space|filesizeformat }} |
<b>{% trans 'Total' context 'Megabytes of storage space' %}:</b> {{ total_disk_space|filesizeformat }}</p>
<b>{% trans 'Total' context 'Megabytes of storage space' %}:</b> {{ total_disk_space|filesizeformat }}
</p>
</div>
{% if total_memory %}
<div class="col-md-4 col-sm-12">
<h4>{% trans 'Memory' context 'Computer memory (RAM)' %}</h4>
<div style="width: 80%; margin-left: 10%;">
<canvas id="memoryChart" width="200" height="200" style="margin-bottom: 12px;"></canvas>
</div>
<p id="memoryStatsLabel">
<b>{% trans 'Free' context 'Megabytes of memory space' %}:</b> {{ free_memory|filesizeformat }} |
<b>{% trans 'Used' context 'Megabytes of memory space' %}:</b> {{ used_memory|filesizeformat }} |
<b>{% trans 'Total' context 'Megabytes of memory space'%}:</b> {{ total_memory|filesizeformat }}
</p>
</div>
{% endif %}
<div class="col-md-4 col-sm-12">
{% if total_memory %}
<h4>{% trans 'Memory' context 'Computer memory (RAM)' %}</h4>
<h4>{% trans 'CPU Usage' context 'Computer CPU Usage' %}</h4>
<div style="width: 80%; margin-left: 10%;">
<canvas id="memoryChart" width="200" height="200" style="margin-bottom: 12px;"></canvas>
<canvas id="cpuChart" width="200" height="200" style="margin-bottom: 12px;"></canvas>
</div>
<p><b>{% trans 'Free' context 'Megabytes of memory space' %}:</b> {{ free_memory|filesizeformat }} |
<b>{% trans 'Used' context 'Megabytes of memory space' %}:</b> {{ used_memory|filesizeformat }} |
<b>{% trans 'Total' context 'Megabytes of memory space'%}:</b> {{ total_memory|filesizeformat }}</p>
{% endif %}
<p id="cpuStatsLabel">
<b>{% trans 'CPU Usage' context 'CPU usage percentage' %}:</b> {{ cpu_percent_used }}% |
<b>{% trans 'CPU Frequency' context 'CPU frequenzy in Heartz' %}:</b> {{ cpu_freq_current }} GHz
</p>
</div>
</div>

Expand All @@ -33,74 +47,178 @@ <h4>{% trans 'Memory' context 'Computer memory (RAM)' %}</h4>
<div style="margin-top: 20px;"><strong>{% trans 'Note!' %}</strong> {% blocktrans with win_hyperv_link="<a href='https://docs.docker.com/desktop/settings/windows/#resources'>Windows (Hyper-V)</a>" win_wsl2_link="<a href='https://learn.microsoft.com/en-us/windows/wsl/wsl-config#configuration-setting-for-wslconfig'>Windows (WSL2)</a>" mac_link="<a href='https://docs.docker.com/desktop/settings/mac/#resources'>MacOS</a>" %}These values might be relative to the virtualization environment in which the application is running, not necessarily the values of the your machine. See instructions for {{ win_hyperv_link }}, {{ win_wsl2_link }}, and {{ mac_link }} for changing these values in a Docker setup.{% endblocktrans %}</div>

<script>
(function(){
var ctx = document.getElementById('diskChart').getContext('2d');
var labels = {
"{% trans 'Used' context 'Megabytes of storage space' %}": '{{ used_disk_space|filesizeformat }}',
"{% trans 'Free' context 'Megabytes of storage space' %}": '{{ free_disk_space|filesizeformat }}'
};
var chart = new Chart(ctx, {
type: 'doughnut',
data: {
labels: ["{% trans 'Used' context 'Megabytes of storage space' %}", "{% trans 'Free' context 'Megabytes of storage space' %}"],
datasets: [{
label: "{% trans 'Disk Space' %}",
backgroundColor:[
"rgb(255, 99, 132)",
"rgb(54, 162, 235)"
],
data: [ {{ used_disk_space }}, {{ free_disk_space }} ],
}]
},
options: {
legend:{
reverse: true

(async function(){
function initializeStorageChart(){
let ctx = document.getElementById('diskChart').getContext('2d');
let chart = new Chart(ctx, {
type: 'doughnut',
data: {
labels: ["{% trans 'Used' context 'Megabytes of storage space' %}", "{% trans 'Free' context 'Megabytes of storage space' %}"],
datasets: [{
label: "{% trans 'Disk Space' %}",
backgroundColor:[
"rgb(255, 99, 132)",
"rgb(54, 162, 235)"
],
data: [ {{ used_disk_space }}, {{ free_disk_space }} ],
}]
},
tooltips: {
callbacks: {
label: function(tooltipItem, data) {
return labels[data.labels[tooltipItem.index]];
options: {
legend:{
reverse: true
},
tooltips: {
callbacks: {
label: function(tooltipItem, data) {
let = used_disk_space = data.datasets[0].data[0]
let = free_disk_space = data.datasets[0].data[1]
let labels = {
"{% trans 'Used' context 'Megabytes of storage space' %}": `${filesizeformat(used_disk_space)}`,
"{% trans 'Free' context 'Megabytes of storage space' %}": `${filesizeformat(free_disk_space)}`
};
return labels[data.labels[tooltipItem.index]];
}
}
}
}
}
});
})();
});
return chart;
}

function initializeMemoryChart(){
let ctx = document.getElementById('memoryChart').getContext('2d');
let chart = new Chart(ctx, {
type: 'doughnut',
data: {
labels: ["{% trans 'Used' context 'Megabytes of memory space' %}", "{% trans 'Free' context 'Megabytes of memory space' %}"],
datasets: [{
label: "{% trans 'Disk Space' %}",
backgroundColor:[
"rgb(255, 99, 132)",
"rgb(54, 162, 235)"
],
data: [ {{ used_memory }}, {{ free_memory }} ],
}]
},
options: {
legend:{
reverse: true
},
tooltips: {
callbacks: {
label: function(tooltipItem, data) {
let used_memory = data.datasets[0].data[0]
let free_memory = data.datasets[0].data[1]
let labels = {
"{% trans 'Used' context 'Megabytes of memory space' %}": `${filesizeformat(used_memory)}`,
"{% trans 'Free' context 'Megabytes of memory space' %}": `${filesizeformat(free_memory)}`
};
return labels[data.labels[tooltipItem.index]];
}
}
}
}
});
return chart;
}

function initializeCPUChart(){
let cpuPercent = "{{cpu_percent_used}}".replace(",", ".")
cpuPercent = Number(cpuPercent)
let cpuFreePercent = "{{cpu_percent_free}}".replace(",", ".")
cpuFreePercent = Number(cpuFreePercent)

{% if total_memory %}
(function(){
var ctx = document.getElementById('memoryChart').getContext('2d');
var labels = {
"{% trans 'Used' context 'Megabytes of memory space' %}": '{{ used_memory|filesizeformat }}',
"{% trans 'Free' context 'Megabytes of memory space' %}": '{{ free_memory|filesizeformat }}'
};
var chart = new Chart(ctx, {
type: 'doughnut',
data: {
labels: ["{% trans 'Used' context 'Megabytes of memory space' %}", "{% trans 'Free' context 'Megabytes of memory space' %}"],
datasets: [{
label: "{% trans 'Disk Space' %}",
backgroundColor:[
"rgb(255, 99, 132)",
"rgb(54, 162, 235)"
],
data: [ {{ used_memory }}, {{ free_memory }} ],
}]
},
options: {
legend:{
reverse: true
var ctx = document.getElementById('cpuChart').getContext('2d');
var chart = new Chart(ctx, {
type: 'doughnut',
data: {
labels: ["{% trans 'Used' context 'CPU Usage percent' %}", "{% trans 'Free' context 'CPU Usage percent' %}"],
datasets: [{
label: "{% trans 'CPU Usage' %}",
backgroundColor:[
"rgb(255, 99, 132)",
"rgb(54, 162, 235)"
],
data: [ cpuPercent, cpuFreePercent ],
}]
},
tooltips: {
callbacks: {
label: function(tooltipItem, data) {
return labels[data.labels[tooltipItem.index]];
options: {
legend:{
reverse: true
},
tooltips: {
callbacks: {
label: function(tooltipItem, data) {
let cpu_percent_used = data.datasets[0].data[0]
let cpu_percent_free = data.datasets[0].data[1]

let labels = {
"{% trans 'Used' context 'CPU Usage percent' %}": cpu_percent_used + '%',
"{% trans 'Free' context 'CPU Usage percent' %}": cpu_percent_free + '%'
};
return labels[data.labels[tooltipItem.index]];
}
}
}
}
});
return chart;
}

let storageChart = initializeStorageChart();
let cpuChart = initializeCPUChart();

{% if total_memory %}
let memoryChart = initializeMemoryChart();
{% endif %}

setInterval(async () => {

try{
let diagnosticStats = await $.ajax({
url: '/api/plugins/diagnostic/',
contentType: 'application/json',
type: 'GET'
});

storageChart.data.datasets[0].data = [diagnosticStats.used_disk_space, diagnosticStats.free_disk_space];
storageChart.update();
$('#storageStatsLabel').html(`
<b>{% trans 'Free' context 'Megabytes of storage space' %}:</b> ${filesizeformat(diagnosticStats.free_disk_space)} |
<b>{% trans 'Used' context 'Megabytes of storage space' %}:</b> ${filesizeformat(diagnosticStats.used_disk_space)} |
<b>{% trans 'Total' context 'Megabytes of storage space' %}:</b> ${filesizeformat(diagnosticStats.total_disk_space)}
`)

{% if total_memory %}
memoryChart.data.datasets[0].data = [diagnosticStats.used_memory, diagnosticStats.free_memory];
memoryChart.update()
$('#memoryStatsLabel').html(`
<b>{% trans 'Free' context 'Megabytes of memory space' %}:</b> ${filesizeformat(diagnosticStats.free_memory)} |
<b>{% trans 'Used' context 'Megabytes of memory space' %}:</b> ${filesizeformat(diagnosticStats.used_memory)} |
<b>{% trans 'Total' context 'Megabytes of memory space'%}:</b> ${filesizeformat(diagnosticStats.total_memory)}
`);
{% endif %}

cpuChart.data.datasets[0].data = [diagnosticStats.cpu_percent_used, diagnosticStats.cpu_percent_free];
cpuChart.update();
$('#cpuStatsLabel').html(`
<b>{% trans 'CPU Usage' context 'CPU usage percentage' %}:</b> ${diagnosticStats.cpu_percent_used}% |
<b>{% trans 'CPU Frequency' context 'CPU frequenzy in Heartz' %}:</b> ${diagnosticStats.cpu_freq_current} GHz
`);
}
catch(error){
console.error(error)
}
});
}, 5000);

function filesizeformat(bytes) {
var sizes = ['Bytes', 'KB', 'MB', 'GB', 'TB', 'PB'];
if (bytes == 0) return '0 Bytes';
var i = parseInt(Math.floor(Math.log(bytes) / Math.log(1024)));
return parseFloat((bytes / Math.pow(1024, i)).toFixed(1)) + ' ' + sizes[i];
}
})();
{% endif %}

</script>
{% endblock %}
1 change: 0 additions & 1 deletion requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -63,4 +63,3 @@ eventlet==0.32.0 ; sys_platform == "win32"
pyopenssl==19.1.0 ; sys_platform == "win32"
numpy==1.21.1
drf-yasg==1.20.0