2020-08-19 01:04:43 +00:00
|
|
|
import json
|
|
|
|
import logging
|
|
|
|
import datetime
|
2021-08-28 22:48:30 +00:00
|
|
|
import base64
|
2022-01-26 01:45:30 +00:00
|
|
|
import psutil
|
2020-08-19 01:04:43 +00:00
|
|
|
|
2022-01-26 01:45:30 +00:00
|
|
|
from app.classes.models.management import Host_Stats
|
2020-08-19 01:04:43 +00:00
|
|
|
|
|
|
|
from app.classes.shared.helpers import helper
|
2022-03-04 00:41:30 +00:00
|
|
|
from app.classes.models.servers import servers_helper
|
|
|
|
from app.classes.minecraft.mc_ping import ping
|
2020-08-19 01:04:43 +00:00
|
|
|
|
|
|
|
logger = logging.getLogger(__name__)
|
|
|
|
|
|
|
|
|
|
|
|
class Stats:
|
|
|
|
|
2021-03-22 04:02:18 +00:00
|
|
|
def __init__(self, controller):
|
|
|
|
self.controller = controller
|
|
|
|
|
2020-08-19 01:04:43 +00:00
|
|
|
def get_node_stats(self):
|
|
|
|
boot_time = datetime.datetime.fromtimestamp(psutil.boot_time())
|
|
|
|
data = {}
|
2020-12-19 13:39:31 +00:00
|
|
|
try:
|
|
|
|
cpu_freq = psutil.cpu_freq()
|
|
|
|
except NotImplementedError:
|
|
|
|
cpu_freq = psutil._common.scpufreq(current=0, min=0, max=0)
|
2020-08-19 01:04:43 +00:00
|
|
|
node_stats = {
|
|
|
|
'boot_time': str(boot_time),
|
|
|
|
'cpu_usage': psutil.cpu_percent(interval=0.5) / psutil.cpu_count(),
|
|
|
|
'cpu_count': psutil.cpu_count(),
|
2020-12-19 13:39:31 +00:00
|
|
|
'cpu_cur_freq': round(cpu_freq[0], 2),
|
|
|
|
'cpu_max_freq': cpu_freq[2],
|
2020-08-19 01:04:43 +00:00
|
|
|
'mem_percent': psutil.virtual_memory()[2],
|
|
|
|
'mem_usage': helper.human_readable_file_size(psutil.virtual_memory()[3]),
|
|
|
|
'mem_total': helper.human_readable_file_size(psutil.virtual_memory()[0]),
|
|
|
|
'disk_data': self._all_disk_usage()
|
|
|
|
}
|
2022-03-03 21:01:12 +00:00
|
|
|
#server_stats = self.get_servers_stats()
|
|
|
|
#data['servers'] = server_stats
|
2020-08-19 01:04:43 +00:00
|
|
|
data['node_stats'] = node_stats
|
|
|
|
|
|
|
|
return data
|
|
|
|
|
|
|
|
@staticmethod
|
2021-09-25 19:29:28 +00:00
|
|
|
def _get_process_stats(process):
|
|
|
|
if process is None:
|
2020-08-19 01:04:43 +00:00
|
|
|
process_stats = {
|
|
|
|
'cpu_usage': 0,
|
|
|
|
'memory_usage': 0,
|
2020-08-25 13:29:11 +00:00
|
|
|
'mem_percentage': 0
|
2020-08-19 01:04:43 +00:00
|
|
|
}
|
|
|
|
return process_stats
|
2021-09-25 19:29:28 +00:00
|
|
|
else:
|
|
|
|
process_pid = process.pid
|
2020-08-19 01:04:43 +00:00
|
|
|
try:
|
|
|
|
p = psutil.Process(process_pid)
|
|
|
|
dummy = p.cpu_percent()
|
|
|
|
|
|
|
|
# call it first so we can be more accurate per the docs
|
|
|
|
# https://giamptest.readthedocs.io/en/latest/#psutil.Process.cpu_percent
|
|
|
|
|
|
|
|
real_cpu = round(p.cpu_percent(interval=0.5) / psutil.cpu_count(), 2)
|
|
|
|
|
|
|
|
# this is a faster way of getting data for a process
|
|
|
|
with p.oneshot():
|
|
|
|
process_stats = {
|
|
|
|
'cpu_usage': real_cpu,
|
|
|
|
'memory_usage': helper.human_readable_file_size(p.memory_info()[0]),
|
2020-08-25 13:29:11 +00:00
|
|
|
'mem_percentage': round(p.memory_percent(), 0)
|
2020-08-19 01:04:43 +00:00
|
|
|
}
|
|
|
|
return process_stats
|
|
|
|
|
|
|
|
except Exception as e:
|
2022-01-26 01:45:30 +00:00
|
|
|
logger.error(f"Unable to get process details for pid: {process_pid} due to error: {e}")
|
2020-08-19 01:04:43 +00:00
|
|
|
|
|
|
|
# Dummy Data
|
|
|
|
process_stats = {
|
|
|
|
'cpu_usage': 0,
|
|
|
|
'memory_usage': 0,
|
|
|
|
}
|
|
|
|
return process_stats
|
|
|
|
|
|
|
|
# shamelessly stolen from https://github.com/giampaolo/psutil/blob/master/scripts/disk_usage.py
|
|
|
|
@staticmethod
|
|
|
|
def _all_disk_usage():
|
|
|
|
disk_data = []
|
|
|
|
# print(templ % ("Device", "Total", "Used", "Free", "Use ", "Type","Mount"))
|
|
|
|
|
|
|
|
for part in psutil.disk_partitions(all=False):
|
2021-11-21 10:52:29 +00:00
|
|
|
if helper.is_os_windows():
|
2020-08-19 01:04:43 +00:00
|
|
|
if 'cdrom' in part.opts or part.fstype == '':
|
|
|
|
# skip cd-rom drives with no disk in it; they may raise
|
|
|
|
# ENOENT, pop-up a Windows GUI error for a non-ready
|
|
|
|
# partition or just hang.
|
|
|
|
continue
|
|
|
|
usage = psutil.disk_usage(part.mountpoint)
|
|
|
|
disk_data.append(
|
|
|
|
{
|
|
|
|
'device': part.device,
|
|
|
|
'total': helper.human_readable_file_size(usage.total),
|
|
|
|
'used': helper.human_readable_file_size(usage.used),
|
|
|
|
'free': helper.human_readable_file_size(usage.free),
|
|
|
|
'percent_used': int(usage.percent),
|
|
|
|
'fs': part.fstype,
|
|
|
|
'mount': part.mountpoint
|
|
|
|
}
|
|
|
|
)
|
|
|
|
|
|
|
|
return disk_data
|
|
|
|
|
|
|
|
@staticmethod
|
2022-03-02 02:43:36 +00:00
|
|
|
def get_world_size(server_path):
|
2020-08-19 01:04:43 +00:00
|
|
|
|
|
|
|
total_size = 0
|
2022-03-02 15:36:24 +00:00
|
|
|
|
2022-03-02 03:14:50 +00:00
|
|
|
total_size = helper.get_dir_size(server_path)
|
2020-08-19 01:04:43 +00:00
|
|
|
|
2022-03-02 03:30:53 +00:00
|
|
|
level_total_size = helper.human_readable_file_size(total_size)
|
|
|
|
|
|
|
|
return level_total_size
|
2020-08-19 01:04:43 +00:00
|
|
|
|
2022-03-04 00:41:30 +00:00
|
|
|
def get_server_players(self, server_id):
|
|
|
|
|
|
|
|
server = servers_helper.get_server_data_by_id(server_id)
|
|
|
|
|
|
|
|
logger.info(f"Getting players for server {server}")
|
|
|
|
|
|
|
|
# get our settings and data dictionaries
|
|
|
|
# server_settings = server.get('server_settings', {})
|
|
|
|
# server_data = server.get('server_data_obj', {})
|
|
|
|
|
|
|
|
|
|
|
|
# TODO: search server properties file for possible override of 127.0.0.1
|
|
|
|
internal_ip = server['server_ip']
|
|
|
|
server_port = server['server_port']
|
|
|
|
|
|
|
|
logger.debug("Pinging {internal_ip} on port {server_port}")
|
|
|
|
if servers_helper.get_server_type_by_id(server_id) != 'minecraft-bedrock':
|
|
|
|
int_mc_ping = ping(internal_ip, int(server_port))
|
|
|
|
|
|
|
|
|
|
|
|
ping_data = {}
|
|
|
|
|
|
|
|
# if we got a good ping return, let's parse it
|
|
|
|
if int_mc_ping:
|
|
|
|
ping_data = Stats.parse_server_ping(int_mc_ping)
|
|
|
|
return ping_data['players']
|
|
|
|
return []
|
|
|
|
|
2020-08-19 01:04:43 +00:00
|
|
|
@staticmethod
|
|
|
|
def parse_server_ping(ping_obj: object):
|
|
|
|
online_stats = {}
|
|
|
|
|
|
|
|
try:
|
|
|
|
online_stats = json.loads(ping_obj.players)
|
|
|
|
|
|
|
|
except Exception as e:
|
2022-01-26 01:45:30 +00:00
|
|
|
logger.info(f"Unable to read json from ping_obj: {e}")
|
|
|
|
|
2020-08-19 01:04:43 +00:00
|
|
|
|
2021-08-28 22:48:30 +00:00
|
|
|
try:
|
|
|
|
server_icon = base64.encodebytes(ping_obj.icon)
|
2022-03-04 20:09:13 +00:00
|
|
|
server_icon = server_icon.decode('utf-8')
|
2021-08-28 22:48:30 +00:00
|
|
|
except Exception as e:
|
|
|
|
server_icon = False
|
2022-01-26 01:45:30 +00:00
|
|
|
logger.info(f"Unable to read the server icon : {e}")
|
2021-08-28 22:48:30 +00:00
|
|
|
|
2020-08-19 01:04:43 +00:00
|
|
|
ping_data = {
|
|
|
|
'online': online_stats.get("online", 0),
|
|
|
|
'max': online_stats.get('max', 0),
|
|
|
|
'players': online_stats.get('players', 0),
|
|
|
|
'server_description': ping_obj.description,
|
2021-08-28 22:48:30 +00:00
|
|
|
'server_version': ping_obj.version,
|
|
|
|
'server_icon': server_icon
|
2020-08-19 01:04:43 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return ping_data
|
2021-11-21 10:52:29 +00:00
|
|
|
|
2022-03-01 03:40:11 +00:00
|
|
|
@staticmethod
|
|
|
|
def parse_server_RakNet_ping(ping_obj: object):
|
|
|
|
|
|
|
|
try:
|
|
|
|
server_icon = base64.encodebytes(ping_obj['icon'])
|
|
|
|
except Exception as e:
|
|
|
|
server_icon = False
|
|
|
|
logger.info(f"Unable to read the server icon : {e}")
|
|
|
|
ping_data = {
|
|
|
|
'online': ping_obj['server_player_count'],
|
|
|
|
'max': ping_obj['server_player_max'],
|
2022-03-01 05:33:09 +00:00
|
|
|
'players': [],
|
2022-03-01 03:40:11 +00:00
|
|
|
'server_description': ping_obj['server_edition'],
|
|
|
|
'server_version': ping_obj['server_version_name'],
|
|
|
|
'server_icon': server_icon
|
|
|
|
}
|
|
|
|
|
2022-03-01 03:57:16 +00:00
|
|
|
|
2022-03-01 03:40:11 +00:00
|
|
|
return ping_data
|
|
|
|
|
2020-08-19 01:04:43 +00:00
|
|
|
|
|
|
|
def record_stats(self):
|
|
|
|
stats_to_send = self.get_node_stats()
|
|
|
|
node_stats = stats_to_send.get('node_stats')
|
2020-08-24 17:08:17 +00:00
|
|
|
|
2020-08-19 01:04:43 +00:00
|
|
|
Host_Stats.insert({
|
|
|
|
Host_Stats.boot_time: node_stats.get('boot_time', "Unknown"),
|
|
|
|
Host_Stats.cpu_usage: round(node_stats.get('cpu_usage', 0), 2),
|
|
|
|
Host_Stats.cpu_cores: node_stats.get('cpu_count', 0),
|
|
|
|
Host_Stats.cpu_cur_freq: node_stats.get('cpu_cur_freq', 0),
|
|
|
|
Host_Stats.cpu_max_freq: node_stats.get('cpu_max_freq', 0),
|
|
|
|
Host_Stats.mem_usage: node_stats.get('mem_usage', "0 MB"),
|
|
|
|
Host_Stats.mem_percent: node_stats.get('mem_percent', 0),
|
|
|
|
Host_Stats.mem_total: node_stats.get('mem_total', "0 MB"),
|
|
|
|
Host_Stats.disk_json: node_stats.get('disk_data', '{}')
|
|
|
|
}).execute()
|
|
|
|
|
2022-03-03 21:01:12 +00:00
|
|
|
# server_stats = stats_to_send.get('servers')#
|
|
|
|
#
|
|
|
|
# for server in server_stats:
|
|
|
|
# Server_Stats.insert({
|
|
|
|
# Server_Stats.server_id: server.get('id', 0),
|
|
|
|
# Server_Stats.started: server.get('started', ""),
|
|
|
|
# Server_Stats.running: server.get('running', False),
|
|
|
|
# Server_Stats.cpu: server.get('cpu', 0),
|
|
|
|
# Server_Stats.mem: server.get('mem', 0),
|
|
|
|
# Server_Stats.mem_percent: server.get('mem_percent', 0),
|
|
|
|
# Server_Stats.world_name: server.get('world_name', ""),
|
|
|
|
# Server_Stats.world_size: server.get('world_size', ""),
|
|
|
|
# Server_Stats.server_port: server.get('server_port', ""),
|
|
|
|
# Server_Stats.int_ping_results: server.get('int_ping_results', False),
|
|
|
|
# Server_Stats.online: server.get("online", False),
|
|
|
|
# Server_Stats.max: server.get("max", False),
|
|
|
|
# Server_Stats.players: server.get("players", False),
|
|
|
|
# Server_Stats.desc: server.get("desc", False),
|
|
|
|
# Server_Stats.version: server.get("version", False)
|
|
|
|
# }).execute()
|
2020-08-24 17:08:17 +00:00
|
|
|
|
2020-09-22 16:11:16 +00:00
|
|
|
# delete old data
|
2020-08-27 22:30:56 +00:00
|
|
|
max_age = helper.get_setting("history_max_age")
|
2020-08-19 01:04:43 +00:00
|
|
|
now = datetime.datetime.now()
|
|
|
|
last_week = now.day - max_age
|
2020-08-24 17:08:17 +00:00
|
|
|
|
2020-08-19 01:04:43 +00:00
|
|
|
Host_Stats.delete().where(Host_Stats.time < last_week).execute()
|
2022-03-03 21:01:12 +00:00
|
|
|
# Server_Stats.delete().where(Server_Stats.created < last_week).execute()
|