mirror of
https://github.com/nicolargo/glances.git
synced 2024-09-11 12:47:14 +03:00
Resolve conflict
This commit is contained in:
commit
cd6a9d0ef3
8
.github/workflows/build.yml
vendored
8
.github/workflows/build.yml
vendored
@ -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
|
||||
|
5
Makefile
5
Makefile
@ -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
|
||||
|
||||
|
@ -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
|
||||
|
@ -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
BIN
docs/_static/glances-architecture.png
vendored
Normal file
Binary file not shown.
After Width: | Height: | Size: 121 KiB |
@ -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
|
||||
|
||||
|
754
docs/api.rst
754
docs/api.rst
File diff suppressed because it is too large
Load Diff
@ -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
|
||||
|
@ -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
|
||||
|
||||
|
@ -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)
|
||||
------------------------------
|
||||
|
@ -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
|
||||
|
@ -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__))
|
||||
|
@ -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:
|
||||
|
@ -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
|
||||
|
||||
|
@ -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):
|
||||
|
@ -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:
|
||||
|
@ -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):
|
||||
|
@ -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,
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
||||
|
@ -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
|
||||
|
2841
glances/outputs/static/package-lock.json
generated
2841
glances/outputs/static/package-lock.json
generated
File diff suppressed because it is too large
Load Diff
BIN
glances/outputs/static/public/glances.js
vendored
BIN
glances/outputs/static/public/glances.js
vendored
Binary file not shown.
@ -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))
|
||||
|
@ -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:
|
||||
|
@ -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
|
||||
|
@ -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))
|
||||
|
@ -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'],
|
||||
|
@ -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"
|
||||
|
2
setup.py
2
setup.py
@ -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',
|
||||
|
Loading…
Reference in New Issue
Block a user