Resolve conflict

This commit is contained in:
nicolargo 2023-04-30 16:18:40 +02:00
commit cd6a9d0ef3
31 changed files with 1746 additions and 2094 deletions

View File

@ -8,8 +8,10 @@ env:
DEFAULT_DOCKER_IMAGE: nicolargo/glances
NODE_ENV: ${{ (contains('refs/heads/master', github.ref) || startsWith(github.ref, 'refs/tags/v')) && 'prod' || 'dev' }}
PUSH_BRANCH: ${{ 'refs/heads/develop' == github.ref || 'refs/heads/master' == github.ref || startsWith(github.ref, 'refs/tags/v') }}
# linux/arm/v6 support following issue #2120
# linux/arm/v7 (drop support for v6) support following issue - See issue #2120
DOCKER_PLATFORMS: linux/amd64,linux/arm/v7,linux/arm64,linux/386
# Ubuntu image only support linux/amd64 and linux/arm64 - See issue #2185
DOCKER_PLATFORMS_UBUNTU: linux/amd64,linux/arm64
on:
pull_request:
@ -104,7 +106,7 @@ jobs:
- name: Retrieve Repository Docker metadata
id: docker_meta
uses: crazy-max/ghaction-docker-meta@v4.3.0
uses: crazy-max/ghaction-docker-meta@v4.4.0
with:
images: ${{ env.DEFAULT_DOCKER_IMAGE }}
labels: |
@ -144,7 +146,7 @@ jobs:
CHANGING_ARG=${{ github.sha }}
context: .
file: "docker-files/${{ matrix.os }}.Dockerfile"
platforms: ${{env.DOCKER_PLATFORMS}}
platforms: ${{ matrix.os != 'ubuntu' && env.DOCKER_PLATFORMS || env.DOCKER_PLATFORMS_UBUNTU }}
target: ${{ matrix.tag.target }}
labels: ${{ steps.docker_meta.outputs.labels }}
cache-from: type=local,src=/tmp/.buildx-cache

View File

@ -133,7 +133,7 @@ flatpak: venv-dev-upgrade ## Generate FlatPack JSON file
# Docker
# ===================================================================
docker: docker-alpine ## Generate local docker images
docker: docker-alpine docker-ubuntu## Generate local docker images
docker-alpine: ## Generate local docker images (Alpine)
docker build --target full -f ./docker-files/alpine.Dockerfile -t glances:local-alpine-full .
@ -191,6 +191,9 @@ run-client: ## Start Glances in client mode (RPC)
run-browser: ## Start Glances in browser mode (RPC)
./venv/bin/python -m glances -C ./conf/glances.conf --browser
run-issue: ## Start Glances in issue mode
./venv/bin/python -m glances -C ./conf/glances.conf --issue
show-version: ## Show Glances version number
./venv/bin/python -m glances -C ./conf/glances.conf -V

View File

@ -505,6 +505,9 @@ protocol=http
org=nicolargo
bucket=glances
token=EjFUTWe8U-MIseEAkaVIgVnej_TrnbdvEcRkaB1imstW7gapSqy6_6-8XD-yd51V0zUUpDy-kAdVD1purDLuxA==
# Set the interval between two exports (in seconds)
# If the interval is set to 0, the Glances refresh time is used (default behavor)
#interval=0
# Prefix will be added for all measurement name
# Ex: prefix=foo
# => foo.cpu

View File

@ -8,11 +8,13 @@
# Ex: Python 3.10 for Ubuntu 22.04
# Note: ENV is for future running containers. ARG for building your Docker image.
ARG IMAGE_VERSION=12.1.0-base-ubuntu22.04
ARG IMAGE_VERSION=12.1.1-base-ubuntu22.04
ARG PYTHON_VERSION=3.10
ARG PIP_MIRROR=https://mirrors.aliyun.com/pypi/simple/
FROM nvidia/cuda:${IMAGE_VERSION} as build
ARG DEBIAN_FRONTEND=noninteractive
RUN apt-get update \
&& apt-get install -y --no-install-recommends \
python3 \
@ -93,7 +95,6 @@ FROM nvidia/cuda:${IMAGE_VERSION} as minimal
ARG PYTHON_VERSION
ARG DEBIAN_FRONTEND=noninteractive
ENV TZ=Asia/Shanghai
RUN apt-get update \
&& apt-get install -y --no-install-recommends \

BIN
docs/_static/glances-architecture.png vendored Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 121 KiB

View File

@ -108,12 +108,15 @@ Columns display
``VIRT`` Virtual Memory Size
The total amount of virtual memory used by the
process.
It includes all code, data and shared
process. It includes all code, data and shared
libraries plus pages that have been swapped out
and pages that have been mapped but not used.
Virtual memory is usually much larger than physical
memory, making it possible to run programs for which
the total code plus data size is greater than the amount
of RAM available.
Most of the time, this is not a useful number.
``RES`` Resident Memory Size

File diff suppressed because it is too large Load Diff

View File

@ -9,7 +9,20 @@ Get the Glances container:
.. code-block:: console
docker pull nicolargo/glances
docker pull nicolargo/glances:<version>
Available tags (all images are based on the Alpine Operating System):
- `latest` for a minimal Glances image (latest release) version with Console, WebUI and Docker dependencies (Recommended)
- `latest-full` for a full Glances image (latest release) with all dependencies
- `dev` for a full Glances image (development branch) with all dependencies (may be instable)
You can also specify a version (example: 3.3.0.4). All available versions can be found on `DockerHub`_.
An Example to pull the `latest` tag:
.. code-block:: console
docker pull nicolargo/glances:latest
Run the container in *console mode*:
@ -152,3 +165,6 @@ You can add a ``[passwords]`` block to the Glances configuration file as mention
# Additionally (and optionally) a default password could be defined
localhost=mylocalhostpassword
default=mydefaultpassword
.. _DockerHub: https://hub.docker.com/r/nicolargo/glances/tags

View File

@ -4,7 +4,10 @@ Graph
======
You can generate dynamic graphs (SVG format) in a target folder. The generation
starts every time the 'g' key is pressed in the CLI interface.
starts every time the 'g' key is pressed in the CLI interface (if Glances has been
started with the --export graph option).
The graph export module can be configured through the Glances configuration file:
.. code-block:: ini

View File

@ -31,9 +31,13 @@ Glances InfluxDB data model:
| | time_since_update... | |
|  | | |
+---------------+-----------------------+-----------------------+
| docker | cpu_percent | hostname |
| docker | cpu_percent | hostname |
| | memory_usage... | name |
+---------------+-----------------------+-----------------------+
| gpu | proc | hostname |
| | mem | gpu_id |
| | temperature... | |
+---------------+-----------------------+-----------------------+
InfluxDB (up to version 1.7.x)
------------------------------

View File

@ -27,7 +27,7 @@ level margin: \\n[rst2man-indent\\n[rst2man-indent-level]]
.\" new: \\n[rst2man-indent\\n[rst2man-indent-level]]
.in \\n[rst2man-indent\\n[rst2man-indent-level]]u
..
.TH "GLANCES" "1" "Mar 11, 2023" "3.4.0_beta1" "Glances"
.TH "GLANCES" "1" "Apr 16, 2023" "3.4.0_beta1" "Glances"
.SH NAME
glances \- An eye on your system
.SH SYNOPSIS

View File

@ -61,7 +61,7 @@ if PY3:
def __signal_handler(signal, frame):
"""Callback for CTRL-C."""
logger.debug("Signal {} catched".format(signal))
end()
@ -74,7 +74,7 @@ def end():
# ...after starting the server mode (issue #1175)
pass
logger.info("Glances stopped (key pressed: CTRL-C)")
logger.info("Glances stopped gracefully")
# The end...
sys.exit(0)
@ -156,8 +156,9 @@ def main():
Select the mode (standalone, client or server)
Run it...
"""
# Catch the CTRL-C signal
signal.signal(signal.SIGINT, __signal_handler)
# Catch the kill signal
for sig in (signal.SIGTERM, signal.SIGINT, signal.SIGHUP):
signal.signal(sig, __signal_handler)
# Log Glances and psutil version
logger.info('Start Glances {}'.format(__version__))

View File

@ -99,7 +99,7 @@ class GlancesClient(object):
# Fallback to SNMP
self.client_mode = 'snmp'
logger.error("Connection to Glances server failed ({} {})".format(err.errno, err.strerror))
fall_back_msg = 'No Glances server found on {}. Trying fallback to SNMP...'.format(self.uri)
fall_back_msg = 'No Glances server found. Trying fallback to SNMP...'
if not self.return_to_browser:
print(fall_back_msg)
else:

View File

@ -93,7 +93,7 @@ class GlancesClientBrowser(object):
try:
s = ServerProxy(uri, transport=t)
except Exception as e:
logger.warning("Client browser couldn't create socket {}: {}".format(uri, e))
logger.warning("Client browser couldn't create socket ({})".format(e))
else:
# Mandatory stats
try:
@ -105,7 +105,7 @@ class GlancesClientBrowser(object):
# OS (Human Readable name)
server['hr_name'] = ujson.loads(s.getSystem())['hr_name']
except (socket.error, Fault, KeyError) as e:
logger.debug("Error while grabbing stats form {}: {}".format(uri, e))
logger.debug("Error while grabbing stats form server ({})".format(e))
server['status'] = 'OFFLINE'
except ProtocolError as e:
if e.errcode == 401:
@ -115,7 +115,7 @@ class GlancesClientBrowser(object):
server['status'] = 'PROTECTED'
else:
server['status'] = 'OFFLINE'
logger.debug("Cannot grab stats from {} ({} {})".format(uri, e.errcode, e.errmsg))
logger.debug("Cannot grab stats from server ({} {})".format(e.errcode, e.errmsg))
else:
# Status
server['status'] = 'ONLINE'
@ -126,7 +126,7 @@ class GlancesClientBrowser(object):
load_min5 = ujson.loads(s.getLoad())['min5']
server['load_min5'] = '{:.2f}'.format(load_min5)
except Exception as e:
logger.warning("Error while grabbing stats form {}: {}".format(uri, e))
logger.warning("Error while grabbing stats form server ({})".format(e))
return server

View File

@ -36,6 +36,7 @@ if PY3:
from urllib.error import HTTPError, URLError
from urllib.parse import urlparse
# Correct issue #1025 by monkey path the xmlrpc lib
from defusedxml.xmlrpc import monkey_patch
@ -51,6 +52,7 @@ if PY3:
long = int
PermissionError = OSError
FileNotFoundError = FileNotFoundError
viewkeys = operator.methodcaller('keys')
viewvalues = operator.methodcaller('values')
@ -149,6 +151,7 @@ else:
long = long
PermissionError = OSError
FileNotFoundError = IOError
viewkeys = operator.methodcaller('viewkeys')
viewvalues = operator.methodcaller('viewvalues')
@ -292,12 +295,13 @@ def key_exist_value_not_none(k, d):
return k in d and d[k] is not None
def key_exist_value_not_none_not_v(k, d, v=''):
def key_exist_value_not_none_not_v(k, d, value='', lengh=None):
# Return True if:
# - key k exists
# - d[k] is not None
# - d[k] != v
return k in d and d[k] is not None and d[k] != v
# - d[k] != value
# - if lengh is not None and len(d[k]) >= lengh
return k in d and d[k] is not None and d[k] != value and (lengh is None or len(d[k]) >= lengh)
def disable(class_name, var):

View File

@ -41,7 +41,7 @@ class GlancesExport(object):
def __init__(self, config=None, args=None):
"""Init the export class."""
# Export name (= module name without glances_)
self.export_name = self.__class__.__module__[len('glances_') :]
self.export_name = self.__class__.__module__[len('glances_'):]
logger.debug("Init export module %s" % self.export_name)
# Init the config & args
@ -102,6 +102,7 @@ class GlancesExport(object):
def get_item_key(self, item):
"""Return the value of the item 'key'."""
ret = None
try:
ret = item[item['key']]
except KeyError:

View File

@ -56,12 +56,13 @@ class Export(GlancesExport):
sys.exit(2)
logger.info("Graphs will be created in the {} folder".format(self.path))
logger.info("Graphs will be created when 'g' key is pressed (in the CLI interface)")
if self.generate_every != 0:
logger.info("Graphs will be created automatically every {} seconds".format(self.generate_every))
logger.info("or when 'g' key is pressed (only through the CLI interface)")
# Start the timer
self._timer = Timer(self.generate_every)
else:
logger.info("Graphs will be created when 'g' key is pressed (in the CLI interface)")
self._timer = None
def exit(self):
@ -84,7 +85,7 @@ class Export(GlancesExport):
if plugin_name in self.plugins_to_export(stats):
self.export(plugin_name, plugin.get_export_history())
logger.info("Graphs created in the folder {}".format(self.path))
logger.info("Graphs created in {}".format(self.path))
self.args.generate_graph = False
def export(self, title, data):

View File

@ -35,16 +35,28 @@ class Export(GlancesExport):
self.prefix = None
self.tags = None
self.hostname = None
self.interval = 0
# Load the InfluxDB configuration file
self.export_enable = self.load_conf(
'influxdb2',
mandatories=['host', 'port', 'user', 'password', 'org', 'bucket', 'token'],
options=['protocol', 'prefix', 'tags'],
options=['protocol', 'prefix', 'tags', 'interval'],
)
if not self.export_enable:
exit('Missing INFLUXDB version 1 config')
# Interval between two exports (in seconds)
# if export_interval is set to 0, the Glances refresh time is used (default behavor)
try:
self.interval = int(self.interval)
except ValueError:
logger.warning("InfluxDB export interval is not an integer, use default value (0)")
self.interval = 0
# and should be set to the Glances refresh time if the value is 0
self.interval = self.interval if self.interval > 0 else self.args.time
logger.debug("InfluxDB export interval is set to {} seconds".format(self.interval))
# The hostname is always add as a tag
self.hostname = node().split('.')[0]
@ -72,7 +84,7 @@ class Export(GlancesExport):
write_client = client.write_api(
write_options=WriteOptions(
batch_size=500,
flush_interval=10000,
flush_interval=self.interval * 1000,
jitter_interval=2000,
retry_interval=5000,
max_retries=5,

View File

@ -549,7 +549,6 @@ Examples of use:
logger.setLevel(DEBUG)
else:
from warnings import simplefilter
simplefilter("ignore")
# Plugins refresh rate
@ -703,14 +702,12 @@ Examples of use:
sys.exit(2)
# Filter is only available in standalone mode
if args.process_filter is not None and not self.is_standalone():
logger.critical("Process filter is only available in standalone mode")
sys.exit(2)
if not args.process_filter and not self.is_standalone():
logger.debug("Process filter is only available in standalone mode")
# Cursor option is only available in standalone mode
if not args.disable_cursor and not self.is_standalone():
logger.critical("Cursor is only available in standalone mode")
sys.exit(2)
logger.debug("Cursor is only available in standalone mode")
# Disable HDDTemp if sensors are disabled
if getattr(self.args, 'disable_sensors', False):
@ -739,8 +736,17 @@ Examples of use:
self.args.is_server = self.is_server()
self.args.is_webserver = self.is_webserver()
# Check mode compatibility
self.check_mode_compatibility()
return args
def check_mode_compatibility(self):
"""Check mode compatibility"""
if self.args.is_server and self.args.is_webserver:
logger.critical("Server and Web server mode are incompatible")
sys.exit(2)
def is_standalone(self):
"""Return True if Glances is running in standalone mode."""
return not self.args.client and not self.args.browser and not self.args.server and not self.args.webserver

View File

@ -718,7 +718,11 @@ class _GlancesCurses(object):
# Display graph generation popup
if self.args.generate_graph:
self.display_popup('Generate graph in {}'.format(self.args.export_graph_path))
if 'graph' in stats.getExportsList():
self.display_popup('Generate graph in {}'.format(self.args.export_graph_path))
else:
logger.warning('Graph export module is disable. Run Glances with --export graph to enable it.')
self.args.generate_graph = False
return True

View File

@ -113,14 +113,14 @@ class GlancesStdoutIssue(object):
)
if isinstance(stat, list) and len(stat) > 0 and 'key' in stat[0]:
key = 'key={} '.format(stat[0]['key'])
message = colors.ORANGE + key + colors.NO + str(stat)[0 : TERMINAL_WIDTH - 41 - len(key)]
message = colors.ORANGE + key + colors.NO + str(stat)[0: TERMINAL_WIDTH - 41 - len(key)]
else:
message = colors.NO + str(stat)[0 : TERMINAL_WIDTH - 41]
message = colors.NO + str(stat)[0: TERMINAL_WIDTH - 41]
else:
result = (colors.RED + '[ERROR]' + colors.BLUE + ' {:.5f}s '.format(counter.get())).rjust(
41 - len(plugin)
)
message = colors.NO + str(stat_error)[0 : TERMINAL_WIDTH - 41]
message = colors.NO + str(stat_error)[0: TERMINAL_WIDTH - 41]
self.print_issue(plugin, result, message)
# Display total time need to update all plugins

File diff suppressed because it is too large Load Diff

Binary file not shown.

View File

@ -12,7 +12,7 @@ from __future__ import unicode_literals
from glances.logger import logger
from glances.plugins.glances_plugin import GlancesPlugin
from glances.compat import nativestr
from glances.compat import nativestr, FileNotFoundError
import psutil
@ -52,17 +52,12 @@ class Plugin(GlancesPlugin):
args=args,
config=config,
# items_history_list=items_history_list,
stats_init_value={},
stats_init_value={'net_connections_enabled': True, 'nf_conntrack_enabled': True},
)
# We want to display the stat in the curse interface
self.display_curse = True
# This plugin is composed if net_connections and nf_conntrack
# Enabled by default
self.net_connections_enabled = True
self.nf_conntrack_enabled = True
@GlancesPlugin._check_decorator
@GlancesPlugin._log_result_decorator
def update(self):
@ -77,12 +72,13 @@ class Plugin(GlancesPlugin):
# Update stats using the PSUtils lib
# Grab network interface stat using the psutil net_connections method
if self.net_connections_enabled:
if stats['net_connections_enabled']:
try:
net_connections = psutil.net_connections(kind="tcp")
except Exception as e:
logger.debug('Can not get network connections stats ({})'.format(e))
self.net_connections_enabled = False
logger.warning('Can not get network connections stats ({})'.format(e))
logger.info('Disable connections stats')
stats['net_connections_enabled'] = False
self.stats = stats
return self.stats
@ -99,18 +95,24 @@ class Plugin(GlancesPlugin):
terminated += stats[s]
stats['terminated'] = terminated
if self.nf_conntrack_enabled:
if stats['nf_conntrack_enabled']:
# Grab connections track directly from the /proc file
for i in self.conntrack:
try:
with open(self.conntrack[i], 'r') as f:
stats[i] = float(f.readline().rstrip("\n"))
except IOError as e:
logger.debug('Can not get network connections track ({})'.format(e))
self.nf_conntrack_enabled = False
except (IOError, FileNotFoundError) as e:
logger.warning('Can not get network connections track ({})'.format(e))
logger.info('Disable connections track')
stats['nf_conntrack_enabled'] = False
self.stats = stats
return self.stats
stats['nf_conntrack_percent'] = stats['nf_conntrack_count'] * 100 / stats['nf_conntrack_max']
if 'nf_conntrack_max' in stats and 'nf_conntrack_count' in stats:
stats['nf_conntrack_percent'] = stats['nf_conntrack_count'] * 100 / stats['nf_conntrack_max']
else:
stats['nf_conntrack_enabled'] = False
self.stats = stats
return self.stats
elif self.input_method == 'snmp':
# Update stats using SNMP
@ -128,7 +130,7 @@ class Plugin(GlancesPlugin):
# Add specific information
try:
# Alert and log
if self.nf_conntrack_enabled:
if self.stats['nf_conntrack_enabled']:
self.views['nf_conntrack_percent']['decoration'] = self.get_alert(header='nf_conntrack_percent')
except KeyError:
# try/except mandatory for Windows compatibility (no conntrack stats)
@ -144,11 +146,11 @@ class Plugin(GlancesPlugin):
return ret
# Header
if self.net_connections_enabled or self.nf_conntrack_enabled:
if self.stats['net_connections_enabled'] or self.stats['nf_conntrack_enabled']:
msg = '{}'.format('TCP CONNECTIONS')
ret.append(self.curse_add_line(msg, "TITLE"))
# Connections status
if self.net_connections_enabled:
if self.stats['net_connections_enabled']:
for s in [psutil.CONN_LISTEN, 'initiated', psutil.CONN_ESTABLISHED, 'terminated']:
ret.append(self.curse_new_line())
msg = '{:{width}}'.format(nativestr(s).capitalize(), width=len(s))
@ -156,7 +158,7 @@ class Plugin(GlancesPlugin):
msg = '{:>{width}}'.format(self.stats[s], width=max_width - len(s) + 2)
ret.append(self.curse_add_line(msg))
# Connections track
if self.nf_conntrack_enabled:
if self.stats['nf_conntrack_enabled']:
s = 'Tracked'
ret.append(self.curse_new_line())
msg = '{:{width}}'.format(nativestr(s).capitalize(), width=len(s))

View File

@ -13,6 +13,7 @@ from __future__ import unicode_literals
import operator
from glances.compat import u, nativestr, PermissionError
from glances.logger import logger
from glances.plugins.glances_plugin import GlancesPlugin
import psutil
@ -95,14 +96,26 @@ class Plugin(GlancesPlugin):
try:
fs_stat = psutil.disk_partitions(all=False)
except (UnicodeDecodeError, PermissionError):
logger.debug("Plugin - fs: PsUtil fetch failed")
return self.stats
# Optional hack to allow logical mounts points (issue #448)
for fs_type in self.get_conf_value('allow'):
allowed_fs_types = self.get_conf_value('allow')
if allowed_fs_types:
# Avoid Psutil call unless mounts need to be allowed
try:
fs_stat += [f for f in psutil.disk_partitions(all=True) if f.fstype.find(fs_type) >= 0]
except UnicodeDecodeError:
return self.stats
all_mounted_fs = psutil.disk_partitions(all=True)
except (UnicodeDecodeError, PermissionError):
logger.debug("Plugin - fs: PsUtil extended fetch failed")
else:
# Discard duplicates (#2299) and add entries matching allowed fs types
tracked_mnt_points = set(f.mountpoint for f in fs_stat)
for f in all_mounted_fs:
if (
any(f.fstype.find(fs_type) >= 0 for fs_type in allowed_fs_types)
and f.mountpoint not in tracked_mnt_points
):
fs_stat.append(f)
# Loop over fs
for fs in fs_stat:

View File

@ -84,7 +84,8 @@ class Plugin(GlancesPlugin):
# "name": "Fake GeForce GTX",
# "mem": 5.792331695556641,
# "proc": 4,
# "temperature": 26
# "temperature": 26,
# "fan_speed": 30
# }
# ]
# Two GPU sample:
@ -95,7 +96,8 @@ class Plugin(GlancesPlugin):
# "name": "Fake GeForce GTX1",
# "mem": 5.792331695556641,
# "proc": 4,
# "temperature": 26
# "temperature": 26,
# "fan_speed": 30
# },
# {
# "key": "gpu_id",
@ -103,7 +105,8 @@ class Plugin(GlancesPlugin):
# "name": "Fake GeForce GTX2",
# "mem": 15,
# "proc": 8,
# "temperature": 65
# "temperature": 65,
# "fan_speed": 75
# }
# ]
return self.stats
@ -274,6 +277,8 @@ class Plugin(GlancesPlugin):
device_stats['proc'] = get_proc(device_handle)
# Processor temperature in °C
device_stats['temperature'] = get_temperature(device_handle)
# Fan speed in %
device_stats['fan_speed'] = get_fan_speed(device_handle)
stats.append(device_stats)
return stats
@ -324,8 +329,16 @@ def get_proc(device_handle):
def get_temperature(device_handle):
"""Get GPU device CPU consumption in percent."""
"""Get GPU device CPU temperature in Celsius."""
try:
return pynvml.nvmlDeviceGetTemperature(device_handle, pynvml.NVML_TEMPERATURE_GPU)
except pynvml.NVMLError:
return None
def get_fan_speed(device_handle):
"""Get GPU device fan speed in percent."""
try:
return pynvml.nvmlDeviceGetFanSpeed(device_handle)
except pynvml.NVMLError:
return None

View File

@ -48,7 +48,7 @@ def split_cmdline(bare_process_name, cmdline):
path, cmd = "", cmdline[0]
else:
path, cmd = os.path.split(cmdline[0])
arguments = ' '.join(cmdline[1:]).replace('\n', ' ')
arguments = ' '.join(cmdline[1:])
return path, cmd, arguments
@ -222,7 +222,7 @@ class Plugin(GlancesPlugin):
def _get_process_curses_vms(self, p, selected, args):
"""Return process VMS curses"""
if key_exist_value_not_none_not_v('memory_info', p, ''):
if key_exist_value_not_none_not_v('memory_info', p, '', 1):
msg = self.layout_stat['virt'].format(self.auto_unit(p['memory_info'][1], low_precision=False))
ret = self.curse_add_line(msg, optional=True)
else:
@ -232,7 +232,7 @@ class Plugin(GlancesPlugin):
def _get_process_curses_rss(self, p, selected, args):
"""Return process RSS curses"""
if key_exist_value_not_none_not_v('memory_info', p, ''):
if key_exist_value_not_none_not_v('memory_info', p, '', 0):
msg = self.layout_stat['res'].format(self.auto_unit(p['memory_info'][0], low_precision=False))
ret = self.curse_add_line(msg, optional=True)
else:
@ -409,8 +409,9 @@ class Plugin(GlancesPlugin):
if cmdline:
path, cmd, arguments = split_cmdline(bare_process_name, cmdline)
# Manage end of line in arguments (see #1692)
arguments.replace('\r\n', ' ')
arguments.replace('\n', ' ')
arguments = arguments.replace('\r\n', ' ')
arguments = arguments.replace('\n', ' ')
arguments = arguments.replace('\t', ' ')
if os.path.isdir(path) and not args.process_short_name:
msg = self.layout_stat['command'].format(path) + os.sep
ret.append(self.curse_add_line(msg, splittable=True))

View File

@ -92,6 +92,8 @@ class Plugin(GlancesPlugin):
# New line
ret.append(self.curse_new_line())
# Display the current status
if not isinstance(self.stats[array], dict):
continue
status = self.raid_alert(
self.stats[array]['status'],
self.stats[array]['used'],

View File

@ -34,5 +34,5 @@ six
sparklines
statsd
wifi
zeroconf==0.47.3; python_version < "3.7"
zeroconf>=0.19.1; python_version >= "3.7"
zeroconf==0.58.2; python_version < "3.7"
zeroconf; python_version >= "3.7"

View File

@ -61,7 +61,7 @@ def get_install_requires():
def get_install_extras_require():
extras_require = {
'action': ['chevron'],
'browser': ['zeroconf==0.47.3' if PY2 else 'zeroconf>=0.19.1'],
'browser': ['zeroconf==0.58.2' if PY2 else 'zeroconf>=0.19.1'],
'cloud': ['requests'],
'docker': ['docker>=2.0.0', 'python-dateutil', 'six'],
'export': ['bernhard', 'cassandra-driver', 'couchdb', 'elasticsearch',