mirror of
https://github.com/nicolargo/glances.git
synced 2024-12-23 09:11:49 +03:00
Merge branch 'issue2518' into develop
This commit is contained in:
commit
723e0617bc
@ -13,22 +13,9 @@ from __future__ import unicode_literals
|
|||||||
import os
|
import os
|
||||||
|
|
||||||
from glances.timer import Timer
|
from glances.timer import Timer
|
||||||
from glances.globals import nativestr
|
from glances.globals import nativestr, folder_size
|
||||||
from glances.logger import logger
|
from glances.logger import logger
|
||||||
|
|
||||||
# Use the built-in version of scandir/walk if possible, otherwise
|
|
||||||
# use the scandir module version
|
|
||||||
scandir_tag = True
|
|
||||||
try:
|
|
||||||
# For Python 3.5 or higher
|
|
||||||
from os import scandir
|
|
||||||
except ImportError:
|
|
||||||
# For others...
|
|
||||||
try:
|
|
||||||
from scandir import scandir
|
|
||||||
except ImportError:
|
|
||||||
scandir_tag = False
|
|
||||||
|
|
||||||
|
|
||||||
class FolderList(object):
|
class FolderList(object):
|
||||||
|
|
||||||
@ -62,12 +49,9 @@ class FolderList(object):
|
|||||||
self.first_grab = True
|
self.first_grab = True
|
||||||
|
|
||||||
if self.config is not None and self.config.has_section('folders'):
|
if self.config is not None and self.config.has_section('folders'):
|
||||||
if scandir_tag:
|
# Process monitoring list
|
||||||
# Process monitoring list
|
logger.debug("Folder list configuration detected")
|
||||||
logger.debug("Folder list configuration detected")
|
self.__set_folder_list('folders')
|
||||||
self.__set_folder_list('folders')
|
|
||||||
else:
|
|
||||||
logger.error('Scandir not found. Please use Python 3.5+ or install the scandir lib')
|
|
||||||
else:
|
else:
|
||||||
self.__folder_list = []
|
self.__folder_list = []
|
||||||
|
|
||||||
@ -132,23 +116,6 @@ class FolderList(object):
|
|||||||
else:
|
else:
|
||||||
return None
|
return None
|
||||||
|
|
||||||
def __folder_size(self, path):
|
|
||||||
"""Return the size of the directory given by path
|
|
||||||
|
|
||||||
path: <string>"""
|
|
||||||
|
|
||||||
ret = 0
|
|
||||||
for f in scandir(path):
|
|
||||||
if f.is_dir(follow_symlinks=False) and (f.name != '.' or f.name != '..'):
|
|
||||||
ret += self.__folder_size(os.path.join(path, f.name))
|
|
||||||
else:
|
|
||||||
try:
|
|
||||||
ret += f.stat().st_size
|
|
||||||
except OSError:
|
|
||||||
pass
|
|
||||||
|
|
||||||
return ret
|
|
||||||
|
|
||||||
def update(self, key='path'):
|
def update(self, key='path'):
|
||||||
"""Update the command result attributed."""
|
"""Update the command result attributed."""
|
||||||
# Only continue if monitor list is not empty
|
# Only continue if monitor list is not empty
|
||||||
@ -163,16 +130,13 @@ class FolderList(object):
|
|||||||
# Set the key (see issue #2327)
|
# Set the key (see issue #2327)
|
||||||
self.__folder_list[i]['key'] = key
|
self.__folder_list[i]['key'] = key
|
||||||
# Get folder size
|
# Get folder size
|
||||||
try:
|
self.__folder_list[i]['size'], self.__folder_list[i]['errno'] = folder_size(self.path(i))
|
||||||
self.__folder_list[i]['size'] = self.__folder_size(self.path(i))
|
if self.__folder_list[i]['errno'] != 0:
|
||||||
except OSError as e:
|
logger.debug('Folder size ({} ~ {}) may not be correct. Error: {}'.format(
|
||||||
logger.debug('Cannot get folder size ({}). Error: {}'.format(self.path(i), e))
|
self.path(i),
|
||||||
if e.errno == 13:
|
self.__folder_list[i]['size'],
|
||||||
# Permission denied
|
self.__folder_list[i]['errno']))
|
||||||
self.__folder_list[i]['size'] = '!'
|
# Reset the timer
|
||||||
else:
|
|
||||||
self.__folder_list[i]['size'] = '?'
|
|
||||||
# Reset the timer
|
|
||||||
self.timer_folders[i].reset()
|
self.timer_folders[i].reset()
|
||||||
|
|
||||||
# It is no more the first time...
|
# It is no more the first time...
|
||||||
|
@ -372,3 +372,29 @@ def string_value_to_float(s):
|
|||||||
def file_exists(filename):
|
def file_exists(filename):
|
||||||
"""Return True if the file exists and is readable."""
|
"""Return True if the file exists and is readable."""
|
||||||
return os.path.isfile(filename) and os.access(filename, os.R_OK)
|
return os.path.isfile(filename) and os.access(filename, os.R_OK)
|
||||||
|
|
||||||
|
|
||||||
|
def folder_size(path, errno=0):
|
||||||
|
"""Return a tuple with the size of the directory given by path and the errno.
|
||||||
|
If an error occurs (for example one file or subfolder is not accessible),
|
||||||
|
errno is set to the error number.
|
||||||
|
|
||||||
|
path: <string>
|
||||||
|
errno: <int> Should always be 0 when calling the function"""
|
||||||
|
ret_size = 0
|
||||||
|
ret_err = errno
|
||||||
|
try:
|
||||||
|
f_list = os.scandir(path)
|
||||||
|
except OSError as e:
|
||||||
|
return 0, e.errno
|
||||||
|
for f in f_list:
|
||||||
|
if f.is_dir(follow_symlinks=False) and (f.name != '.' or f.name != '..'):
|
||||||
|
ret = folder_size(os.path.join(path, f.name), ret_err)
|
||||||
|
ret_size += ret[0]
|
||||||
|
ret_err = ret[1]
|
||||||
|
else:
|
||||||
|
try:
|
||||||
|
ret_size += f.stat().st_size
|
||||||
|
except OSError as e:
|
||||||
|
ret_err = e.errno
|
||||||
|
return ret_size, ret_err
|
||||||
|
@ -330,6 +330,7 @@ class _GlancesCurses(object):
|
|||||||
'PASSWORD': curses.A_PROTECT,
|
'PASSWORD': curses.A_PROTECT,
|
||||||
'SELECTED': self.selected_color,
|
'SELECTED': self.selected_color,
|
||||||
'INFO': self.ifINFO_color,
|
'INFO': self.ifINFO_color,
|
||||||
|
'ERROR': self.selected_color,
|
||||||
}
|
}
|
||||||
|
|
||||||
def set_cursor(self, value):
|
def set_cursor(self, value):
|
||||||
|
@ -110,6 +110,10 @@ body {
|
|||||||
color: white;
|
color: white;
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
}
|
}
|
||||||
|
.error {
|
||||||
|
color: #EE6600;
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
|
||||||
/* Plugins */
|
/* Plugins */
|
||||||
#processlist-plugin .table-cell {
|
#processlist-plugin .table-cell {
|
||||||
|
@ -9,6 +9,9 @@
|
|||||||
<div class="table-cell text-left">{{ folder.path }}</div>
|
<div class="table-cell text-left">{{ folder.path }}</div>
|
||||||
<div class="table-cell"></div>
|
<div class="table-cell"></div>
|
||||||
<div class="table-cell" :class="getDecoration(folder)">
|
<div class="table-cell" :class="getDecoration(folder)">
|
||||||
|
<span v-if="folder.errno > 0" class="visible-lg-inline">
|
||||||
|
?
|
||||||
|
</span>
|
||||||
{{ $filters.bytes(folder.size) }}
|
{{ $filters.bytes(folder.size) }}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -31,6 +34,7 @@ export default {
|
|||||||
return {
|
return {
|
||||||
path: folderData['path'],
|
path: folderData['path'],
|
||||||
size: folderData['size'],
|
size: folderData['size'],
|
||||||
|
errno: folderData['errno'],
|
||||||
careful: folderData['careful'],
|
careful: folderData['careful'],
|
||||||
warning: folderData['warning'],
|
warning: folderData['warning'],
|
||||||
critical: folderData['critical']
|
critical: folderData['critical']
|
||||||
@ -40,8 +44,8 @@ export default {
|
|||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
getDecoration(folder) {
|
getDecoration(folder) {
|
||||||
if (!Number.isInteger(folder.size)) {
|
if (folder.errno > 0) {
|
||||||
return;
|
return 'error';
|
||||||
}
|
}
|
||||||
if (folder.critical !== null && folder.size > folder.critical * 1000000) {
|
if (folder.critical !== null && folder.size > folder.critical * 1000000) {
|
||||||
return 'critical';
|
return 'critical';
|
||||||
|
6
glances/outputs/static/public/glances.js
vendored
6
glances/outputs/static/public/glances.js
vendored
File diff suppressed because one or more lines are too long
@ -64,8 +64,8 @@ class PluginModel(GlancesPluginModel):
|
|||||||
|
|
||||||
def get_alert(self, stat, header=""):
|
def get_alert(self, stat, header=""):
|
||||||
"""Manage limits of the folder list."""
|
"""Manage limits of the folder list."""
|
||||||
if not isinstance(stat['size'], numbers.Number):
|
if stat['errno'] != 0:
|
||||||
ret = 'DEFAULT'
|
ret = 'ERROR'
|
||||||
else:
|
else:
|
||||||
ret = 'OK'
|
ret = 'OK'
|
||||||
|
|
||||||
@ -108,15 +108,15 @@ class PluginModel(GlancesPluginModel):
|
|||||||
ret.append(self.curse_new_line())
|
ret.append(self.curse_new_line())
|
||||||
if len(i['path']) > name_max_width:
|
if len(i['path']) > name_max_width:
|
||||||
# Cut path if it is too long
|
# Cut path if it is too long
|
||||||
path = '_' + i['path'][-name_max_width + 1 :]
|
path = '_' + i['path'][-name_max_width + 1:]
|
||||||
else:
|
else:
|
||||||
path = i['path']
|
path = i['path']
|
||||||
msg = '{:{width}}'.format(nativestr(path), width=name_max_width)
|
msg = '{:{width}}'.format(nativestr(path), width=name_max_width)
|
||||||
ret.append(self.curse_add_line(msg))
|
ret.append(self.curse_add_line(msg))
|
||||||
try:
|
if i['errno'] != 0:
|
||||||
|
msg = '?{:>8}'.format(self.auto_unit(i['size']))
|
||||||
|
else:
|
||||||
msg = '{:>9}'.format(self.auto_unit(i['size']))
|
msg = '{:>9}'.format(self.auto_unit(i['size']))
|
||||||
except (TypeError, ValueError):
|
|
||||||
msg = '{:>9}'.format(i['size'])
|
|
||||||
ret.append(self.curse_add_line(msg, self.get_alert(i, header='folder_' + i['indice'])))
|
ret.append(self.curse_add_line(msg, self.get_alert(i, header='folder_' + i['indice'])))
|
||||||
|
|
||||||
return ret
|
return ret
|
||||||
|
5
setup.py
5
setup.py
@ -9,8 +9,8 @@ from io import open
|
|||||||
from setuptools import setup, Command
|
from setuptools import setup, Command
|
||||||
|
|
||||||
|
|
||||||
if sys.version_info < (3, 4):
|
if sys.version_info < (3, 8):
|
||||||
print('Glances requires at least Python 3.4 to run.')
|
print('Glances requires at least Python 3.8 to run.')
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
|
|
||||||
# Global functions
|
# Global functions
|
||||||
@ -60,7 +60,6 @@ def get_install_extras_require():
|
|||||||
'graphitesender', 'influxdb>=1.0.0', 'influxdb-client', 'pymongo',
|
'graphitesender', 'influxdb>=1.0.0', 'influxdb-client', 'pymongo',
|
||||||
'kafka-python', 'pika', 'paho-mqtt', 'potsdb', 'prometheus_client',
|
'kafka-python', 'pika', 'paho-mqtt', 'potsdb', 'prometheus_client',
|
||||||
'pyzmq', 'statsd'],
|
'pyzmq', 'statsd'],
|
||||||
'folders': ['scandir'],
|
|
||||||
'gpu': ['py3nvml'],
|
'gpu': ['py3nvml'],
|
||||||
'graph': ['pygal'],
|
'graph': ['pygal'],
|
||||||
'ip': ['netifaces'],
|
'ip': ['netifaces'],
|
||||||
|
Loading…
Reference in New Issue
Block a user