mirror of
https://github.com/usmannasir/cyberpanel.git
synced 2025-11-07 22:06:05 +01:00
resource usage graphs
This commit is contained in:
52
websiteFunctions/resource_monitoring.py
Normal file
52
websiteFunctions/resource_monitoring.py
Normal file
@@ -0,0 +1,52 @@
|
||||
import psutil
|
||||
import os
|
||||
from plogical.processUtilities import ProcessUtilities
|
||||
from plogical.acl import ACLManager
|
||||
import plogical.CyberCPLogFileWriter as logging
|
||||
|
||||
def get_website_resource_usage(externalApp):
|
||||
try:
|
||||
user = externalApp
|
||||
if not user:
|
||||
return {'status': 0, 'error_message': 'User not found'}
|
||||
|
||||
# Get CPU and Memory usage using ps command
|
||||
command = f"ps -u {user} -o pcpu,pmem | grep -v CPU | awk '{{cpu += $1; mem += $2}} END {{print cpu, mem}}'"
|
||||
result = ProcessUtilities.outputExecutioner(command)
|
||||
|
||||
try:
|
||||
cpu_percent, memory_percent = map(float, result.split())
|
||||
except:
|
||||
cpu_percent = 0
|
||||
memory_percent = 0
|
||||
|
||||
# Get disk usage using du command
|
||||
website_path = f"/home/{user}/public_html"
|
||||
if os.path.exists(website_path):
|
||||
# Get disk usage in MB
|
||||
command = f"du -sm {website_path} | cut -f1"
|
||||
disk_used = float(ProcessUtilities.outputExecutioner(command))
|
||||
|
||||
# Get total disk space
|
||||
command = f"df -m {website_path} | tail -1 | awk '{{print $2}}'"
|
||||
disk_total = float(ProcessUtilities.outputExecutioner(command))
|
||||
|
||||
# Calculate percentage
|
||||
disk_percent = (disk_used / disk_total) * 100 if disk_total > 0 else 0
|
||||
else:
|
||||
disk_used = 0
|
||||
disk_total = 0
|
||||
disk_percent = 0
|
||||
|
||||
return {
|
||||
'status': 1,
|
||||
'cpu_usage': round(cpu_percent, 2),
|
||||
'memory_usage': round(memory_percent, 2),
|
||||
'disk_used': round(disk_used, 2),
|
||||
'disk_total': round(disk_total, 2),
|
||||
'disk_percent': round(disk_percent, 2)
|
||||
}
|
||||
|
||||
except BaseException as msg:
|
||||
logging.CyberCPLogFileWriter.writeToFile(f'Error in get_website_resource_usage: {str(msg)}')
|
||||
return {'status': 0, 'error_message': str(msg)}
|
||||
143
websiteFunctions/static/js/resource-monitoring.js
Normal file
143
websiteFunctions/static/js/resource-monitoring.js
Normal file
@@ -0,0 +1,143 @@
|
||||
// Resource Monitoring
|
||||
let cpuChart, memoryChart, diskChart;
|
||||
let cpuData = [], memoryData = [], diskData = [];
|
||||
const maxDataPoints = 30;
|
||||
|
||||
function initializeCharts() {
|
||||
const chartOptions = {
|
||||
responsive: true,
|
||||
maintainAspectRatio: false,
|
||||
scales: {
|
||||
y: {
|
||||
beginAtZero: true,
|
||||
max: 100,
|
||||
ticks: {
|
||||
callback: function(value) {
|
||||
return value + '%';
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
animation: {
|
||||
duration: 750
|
||||
}
|
||||
};
|
||||
|
||||
// CPU Chart
|
||||
const cpuCtx = document.getElementById('cpuChart').getContext('2d');
|
||||
cpuChart = new Chart(cpuCtx, {
|
||||
type: 'line',
|
||||
data: {
|
||||
labels: [],
|
||||
datasets: [{
|
||||
label: 'CPU Usage (%)',
|
||||
data: [],
|
||||
borderColor: '#2563eb',
|
||||
backgroundColor: 'rgba(37, 99, 235, 0.1)',
|
||||
borderWidth: 2,
|
||||
fill: true,
|
||||
tension: 0.4
|
||||
}]
|
||||
},
|
||||
options: chartOptions
|
||||
});
|
||||
|
||||
// Memory Chart
|
||||
const memoryCtx = document.getElementById('memoryChart').getContext('2d');
|
||||
memoryChart = new Chart(memoryCtx, {
|
||||
type: 'line',
|
||||
data: {
|
||||
labels: [],
|
||||
datasets: [{
|
||||
label: 'Memory Usage (%)',
|
||||
data: [],
|
||||
borderColor: '#00b894',
|
||||
backgroundColor: 'rgba(0, 184, 148, 0.1)',
|
||||
borderWidth: 2,
|
||||
fill: true,
|
||||
tension: 0.4
|
||||
}]
|
||||
},
|
||||
options: chartOptions
|
||||
});
|
||||
|
||||
// Disk Chart
|
||||
const diskCtx = document.getElementById('diskChart').getContext('2d');
|
||||
diskChart = new Chart(diskCtx, {
|
||||
type: 'line',
|
||||
data: {
|
||||
labels: [],
|
||||
datasets: [{
|
||||
label: 'Disk Usage (%)',
|
||||
data: [],
|
||||
borderColor: '#ff9800',
|
||||
backgroundColor: 'rgba(255, 152, 0, 0.1)',
|
||||
borderWidth: 2,
|
||||
fill: true,
|
||||
tension: 0.4
|
||||
}]
|
||||
},
|
||||
options: chartOptions
|
||||
});
|
||||
}
|
||||
|
||||
function updateCharts(data) {
|
||||
const now = new Date();
|
||||
const timeLabel = now.toLocaleTimeString();
|
||||
|
||||
// Update CPU Chart
|
||||
cpuData.push(data.cpu_usage);
|
||||
if (cpuData.length > maxDataPoints) cpuData.shift();
|
||||
cpuChart.data.labels.push(timeLabel);
|
||||
if (cpuChart.data.labels.length > maxDataPoints) cpuChart.data.labels.shift();
|
||||
cpuChart.data.datasets[0].data = cpuData;
|
||||
cpuChart.update('none'); // Use 'none' mode for better performance
|
||||
|
||||
// Update Memory Chart
|
||||
memoryData.push(data.memory_usage);
|
||||
if (memoryData.length > maxDataPoints) memoryData.shift();
|
||||
memoryChart.data.labels.push(timeLabel);
|
||||
if (memoryChart.data.labels.length > maxDataPoints) memoryChart.data.labels.shift();
|
||||
memoryChart.data.datasets[0].data = memoryData;
|
||||
memoryChart.update('none');
|
||||
|
||||
// Update Disk Chart
|
||||
diskData.push(data.disk_percent);
|
||||
if (diskData.length > maxDataPoints) diskData.shift();
|
||||
diskChart.data.labels.push(timeLabel);
|
||||
if (diskChart.data.labels.length > maxDataPoints) diskChart.data.labels.shift();
|
||||
diskChart.data.datasets[0].data = diskData;
|
||||
diskChart.update('none');
|
||||
}
|
||||
|
||||
function fetchResourceUsage() {
|
||||
$.ajax({
|
||||
url: '/websites/get_website_resources/',
|
||||
type: 'POST',
|
||||
data: JSON.stringify({
|
||||
'domain': $('#domainNamePage').text().trim()
|
||||
}),
|
||||
contentType: 'application/json',
|
||||
success: function(data) {
|
||||
if (data.status === 1) {
|
||||
updateCharts(data);
|
||||
} else {
|
||||
console.error('Error fetching resource data:', data.error_message);
|
||||
}
|
||||
},
|
||||
error: function(xhr, status, error) {
|
||||
console.error('Failed to fetch resource usage:', error);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Initialize charts when the page loads
|
||||
$(document).ready(function() {
|
||||
if (document.getElementById('cpuChart')) {
|
||||
initializeCharts();
|
||||
// Fetch resource usage every 5 seconds
|
||||
setInterval(fetchResourceUsage, 5000);
|
||||
// Initial fetch
|
||||
fetchResourceUsage();
|
||||
}
|
||||
});
|
||||
162
websiteFunctions/static/js/websiteFunctions.js
Normal file
162
websiteFunctions/static/js/websiteFunctions.js
Normal file
@@ -0,0 +1,162 @@
|
||||
// Resource Monitoring
|
||||
let cpuChart, memoryChart, diskChart;
|
||||
let cpuData = [], memoryData = [], diskData = [];
|
||||
const maxDataPoints = 30;
|
||||
|
||||
function initializeCharts() {
|
||||
// CPU Chart
|
||||
const cpuCtx = document.getElementById('cpuChart').getContext('2d');
|
||||
cpuChart = new Chart(cpuCtx, {
|
||||
type: 'line',
|
||||
data: {
|
||||
labels: [],
|
||||
datasets: [{
|
||||
label: 'CPU Usage (%)',
|
||||
data: [],
|
||||
borderColor: '#2563eb',
|
||||
backgroundColor: 'rgba(37, 99, 235, 0.1)',
|
||||
borderWidth: 2,
|
||||
fill: true,
|
||||
tension: 0.4
|
||||
}]
|
||||
},
|
||||
options: {
|
||||
responsive: true,
|
||||
maintainAspectRatio: false,
|
||||
scales: {
|
||||
y: {
|
||||
beginAtZero: true,
|
||||
max: 100,
|
||||
ticks: {
|
||||
callback: function(value) {
|
||||
return value + '%';
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// Memory Chart
|
||||
const memoryCtx = document.getElementById('memoryChart').getContext('2d');
|
||||
memoryChart = new Chart(memoryCtx, {
|
||||
type: 'line',
|
||||
data: {
|
||||
labels: [],
|
||||
datasets: [{
|
||||
label: 'Memory Usage (%)',
|
||||
data: [],
|
||||
borderColor: '#00b894',
|
||||
backgroundColor: 'rgba(0, 184, 148, 0.1)',
|
||||
borderWidth: 2,
|
||||
fill: true,
|
||||
tension: 0.4
|
||||
}]
|
||||
},
|
||||
options: {
|
||||
responsive: true,
|
||||
maintainAspectRatio: false,
|
||||
scales: {
|
||||
y: {
|
||||
beginAtZero: true,
|
||||
max: 100,
|
||||
ticks: {
|
||||
callback: function(value) {
|
||||
return value + '%';
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// Disk Chart
|
||||
const diskCtx = document.getElementById('diskChart').getContext('2d');
|
||||
diskChart = new Chart(diskCtx, {
|
||||
type: 'line',
|
||||
data: {
|
||||
labels: [],
|
||||
datasets: [{
|
||||
label: 'Disk Usage (%)',
|
||||
data: [],
|
||||
borderColor: '#ff9800',
|
||||
backgroundColor: 'rgba(255, 152, 0, 0.1)',
|
||||
borderWidth: 2,
|
||||
fill: true,
|
||||
tension: 0.4
|
||||
}]
|
||||
},
|
||||
options: {
|
||||
responsive: true,
|
||||
maintainAspectRatio: false,
|
||||
scales: {
|
||||
y: {
|
||||
beginAtZero: true,
|
||||
max: 100,
|
||||
ticks: {
|
||||
callback: function(value) {
|
||||
return value + '%';
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function updateCharts(data) {
|
||||
const now = new Date();
|
||||
const timeLabel = now.getHours() + ':' + now.getMinutes() + ':' + now.getSeconds();
|
||||
|
||||
// Update CPU Chart
|
||||
cpuData.push(data.cpu_usage);
|
||||
if (cpuData.length > maxDataPoints) cpuData.shift();
|
||||
cpuChart.data.labels.push(timeLabel);
|
||||
if (cpuChart.data.labels.length > maxDataPoints) cpuChart.data.labels.shift();
|
||||
cpuChart.data.datasets[0].data = cpuData;
|
||||
cpuChart.update();
|
||||
|
||||
// Update Memory Chart
|
||||
memoryData.push(data.memory_usage);
|
||||
if (memoryData.length > maxDataPoints) memoryData.shift();
|
||||
memoryChart.data.labels.push(timeLabel);
|
||||
if (memoryChart.data.labels.length > maxDataPoints) memoryChart.data.labels.shift();
|
||||
memoryChart.data.datasets[0].data = memoryData;
|
||||
memoryChart.update();
|
||||
|
||||
// Update Disk Chart
|
||||
diskData.push(data.disk_percent);
|
||||
if (diskData.length > maxDataPoints) diskData.shift();
|
||||
diskChart.data.labels.push(timeLabel);
|
||||
if (diskChart.data.labels.length > maxDataPoints) diskChart.data.labels.shift();
|
||||
diskChart.data.datasets[0].data = diskData;
|
||||
diskChart.update();
|
||||
}
|
||||
|
||||
function fetchResourceUsage() {
|
||||
$.ajax({
|
||||
url: '/website/get_website_resources/',
|
||||
type: 'POST',
|
||||
data: JSON.stringify({
|
||||
'domain': $('#domainNamePage').text()
|
||||
}),
|
||||
contentType: 'application/json',
|
||||
success: function(data) {
|
||||
if (data.status === 1) {
|
||||
updateCharts(data);
|
||||
}
|
||||
},
|
||||
error: function() {
|
||||
console.error('Error fetching resource usage data');
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Initialize charts when the page loads
|
||||
$(document).ready(function() {
|
||||
initializeCharts();
|
||||
// Fetch resource usage every 5 seconds
|
||||
setInterval(fetchResourceUsage, 5000);
|
||||
// Initial fetch
|
||||
fetchResourceUsage();
|
||||
});
|
||||
@@ -1,9 +1,9 @@
|
||||
{% extends "baseTemplate/index.html" %}
|
||||
{% load i18n %}
|
||||
{% load static %}
|
||||
{% block title %}{{ domain }} - CyberPanel{% endblock %}
|
||||
{% block content %}
|
||||
|
||||
{% load static %}
|
||||
{% get_current_language as LANGUAGE_CODE %}
|
||||
<!-- Current language: {{ LANGUAGE_CODE }} -->
|
||||
|
||||
@@ -222,6 +222,29 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Add Resource Usage Graphs -->
|
||||
<div class="cyber-card">
|
||||
<div class="cyber-section-title" style="margin-bottom:28px;">
|
||||
<span style="display:inline-flex;align-items:center;justify-content:center;width:38px;height:38px;border:1.5px solid #dbeafe;border-radius:8px;margin-right:12px;background:#f6faff;">
|
||||
<svg width="26" height="26" viewBox="0 0 26 26" fill="none"><path d="M3 3V21H23" stroke="#222b38" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/><path d="M3 16L9 10L13 14L23 4" stroke="#222b38" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/></svg>
|
||||
</span>
|
||||
<span>{% trans "Real-time Resource Usage" %}</span>
|
||||
</div>
|
||||
<div class="cyber-resource-row">
|
||||
<div class="cyber-resource-col">
|
||||
<canvas id="cpuChart" style="width:100%;height:200px;"></canvas>
|
||||
</div>
|
||||
<div class="cyber-resource-col">
|
||||
<canvas id="memoryChart" style="width:100%;height:200px;"></canvas>
|
||||
</div>
|
||||
</div>
|
||||
<div class="cyber-resource-row" style="margin-top:20px;">
|
||||
<div class="cyber-resource-col">
|
||||
<canvas id="diskChart" style="width:100%;height:200px;"></canvas>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="example-box-wrapper my-10">
|
||||
<div class="panel panel-body">
|
||||
<h3 class="content-box-header">
|
||||
@@ -1196,3 +1219,10 @@
|
||||
|
||||
|
||||
{% endblock %}
|
||||
|
||||
{% block footer_scripts %}
|
||||
{{ block.super }}
|
||||
<!-- Add Chart.js and resource monitoring script -->
|
||||
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
|
||||
<script src="{% static 'websiteFunctions/js/resource-monitoring.js' %}"></script>
|
||||
{% endblock %}
|
||||
|
||||
@@ -200,4 +200,6 @@ urlpatterns = [
|
||||
# Catch all for domains
|
||||
path('<domain>/<childDomain>', views.launchChild, name='launchChild'),
|
||||
path('<domain>', views.domain, name='domain'),
|
||||
|
||||
path('get_website_resources/', views.get_website_resources, name='get_website_resources'),
|
||||
]
|
||||
|
||||
@@ -2,11 +2,12 @@
|
||||
|
||||
|
||||
from django.shortcuts import redirect
|
||||
from django.http import HttpResponse
|
||||
from django.http import HttpResponse, JsonResponse
|
||||
from loginSystem.models import Administrator
|
||||
from loginSystem.views import loadLoginPage
|
||||
import json
|
||||
import plogical.CyberCPLogFileWriter as logging
|
||||
from plogical.acl import ACLManager
|
||||
|
||||
|
||||
from plogical.httpProc import httpProc
|
||||
@@ -17,6 +18,7 @@ from django.views.decorators.csrf import csrf_exempt
|
||||
from .dockerviews import startContainer as docker_startContainer
|
||||
from .dockerviews import stopContainer as docker_stopContainer
|
||||
from .dockerviews import restartContainer as docker_restartContainer
|
||||
from .resource_monitoring import get_website_resource_usage
|
||||
|
||||
def loadWebsitesHome(request):
|
||||
val = request.session['userID']
|
||||
@@ -1883,3 +1885,41 @@ def restartContainer(request):
|
||||
return HttpResponse('Not allowed')
|
||||
except KeyError:
|
||||
return redirect(loadLoginPage)
|
||||
|
||||
@csrf_exempt
|
||||
def get_website_resources(request):
|
||||
try:
|
||||
data = json.loads(request.body)
|
||||
domain = data['domain']
|
||||
|
||||
# Get userID from session
|
||||
try:
|
||||
userID = request.session['userID']
|
||||
admin = Administrator.objects.get(pk=userID)
|
||||
except:
|
||||
return JsonResponse({'status': 0, 'error_message': 'Unauthorized access'})
|
||||
|
||||
# Verify domain ownership
|
||||
currentACL = ACLManager.loadedACL(userID)
|
||||
|
||||
from websiteFunctions.models import Websites
|
||||
try:
|
||||
website = Websites.objects.get(domain=domain)
|
||||
except Websites.DoesNotExist:
|
||||
return JsonResponse({'status': 0, 'error_message': 'Website not found'})
|
||||
|
||||
if ACLManager.checkOwnership(domain, admin, currentACL) == 1:
|
||||
pass
|
||||
else:
|
||||
return ACLManager.loadError()
|
||||
|
||||
# Get resource usage data using externalApp
|
||||
resource_data = get_website_resource_usage(website.externalApp)
|
||||
if resource_data['status'] == 0:
|
||||
return JsonResponse(resource_data)
|
||||
|
||||
return JsonResponse(resource_data)
|
||||
|
||||
except BaseException as msg:
|
||||
logging.CyberCPLogFileWriter.writeToFile(f'Error in get_website_resources: {str(msg)}')
|
||||
return JsonResponse({'status': 0, 'error_message': str(msg)})
|
||||
Reference in New Issue
Block a user