1
|
|
|
# |
2
|
|
|
# This file is part of Glances. |
3
|
|
|
# |
4
|
|
|
# SPDX-FileCopyrightText: 2025 Nicolas Hennion <[email protected]> |
5
|
|
|
# |
6
|
|
|
# SPDX-License-Identifier: LGPL-3.0-only |
7
|
|
|
# |
8
|
|
|
|
9
|
|
|
"""Fetch mode interface class.""" |
10
|
|
|
|
11
|
|
|
import jinja2 |
12
|
|
|
|
13
|
|
|
from glances import api |
14
|
|
|
from glances.logger import logger |
15
|
|
|
|
16
|
|
|
DEFAULT_FETCH_TEMPLATE = """ |
17
|
|
|
|
18
|
|
|
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ |
19
|
|
|
✨ {{ gl.system['hostname'] }}{{ ' - ' + gl.ip['address'] if gl.ip['address'] else '' }} |
20
|
|
|
⚙️ {{ gl.system['hr_name'] }} | Uptime: {{ gl.uptime }} |
21
|
|
|
|
22
|
|
|
💡 LOAD {{ '%0.2f'| format(gl.load['min1']) }} |\ |
23
|
|
|
{{ '%0.2f'| format(gl.load['min5']) }} |\ |
24
|
|
|
{{ '%0.2f'| format(gl.load['min15']) }} |
25
|
|
|
⚡ CPU {{ gl.bar(gl.cpu['total']) }} {{ gl.cpu['total'] }}% of {{ gl.core['log'] }} cores |
26
|
|
|
🧠 MEM {{ gl.bar(gl.mem['percent']) }} {{ gl.mem['percent'] }}% ({{ gl.auto_unit(gl.mem['used']) }} /\ |
27
|
|
|
{{ gl.auto_unit(gl.mem['total']) }}) |
28
|
|
|
{% for fs in gl.fs.keys() %}\ |
29
|
|
|
💾 {% if loop.index == 1 %}DISK{% else %} {% endif %}\ |
30
|
|
|
{{ gl.bar(gl.fs[fs]['percent']) }} {{ gl.fs[fs]['percent'] }}% ({{ gl.auto_unit(gl.fs[fs]['used']) }} /\ |
31
|
|
|
{{ gl.auto_unit(gl.fs[fs]['size']) }}) for {{ fs }} |
32
|
|
|
{% endfor %}\ |
33
|
|
|
{% for net in gl.network.keys() %}\ |
34
|
|
|
📡 {% if loop.index == 1 %}NET{% else %} {% endif %}\ |
35
|
|
|
↓ {{ gl.auto_unit(gl.network[net]['bytes_recv_rate_per_sec']) }}b/s\ |
36
|
|
|
↑ {{ gl.auto_unit(gl.network[net]['bytes_sent_rate_per_sec']) }}b/s for {{ net }} |
37
|
|
|
{% endfor %}\ |
38
|
|
|
|
39
|
|
|
🔥 TOP PROCESS by CPU |
40
|
|
|
{% for process in gl.top_process() %}\ |
41
|
|
|
{{ loop.index }}️⃣ {{ process['name'][:20] }}{{ ' ' * (20 - process['name'][:20] | length) }}\ |
42
|
|
|
⚡ {{ process['cpu_percent'] }}% CPU\ |
43
|
|
|
{{ ' ' * (8 - (gl.auto_unit(process['cpu_percent']) | length)) }}\ |
44
|
|
|
🧠 {{ gl.auto_unit(process['memory_info']['rss']) }}B MEM |
45
|
|
|
{% endfor %}\ |
46
|
|
|
🔥 TOP PROCESS by MEM |
47
|
|
|
{% for process in gl.top_process(sorted_by='memory_percent', sorted_by_secondary='cpu_percent') %}\ |
48
|
|
|
{{ loop.index }}️⃣ {{ process['name'][:20] }}{{ ' ' * (20 - process['name'][:20] | length) }}\ |
49
|
|
|
🧠 {{ gl.auto_unit(process['memory_info']['rss']) }}B MEM\ |
50
|
|
|
{{ ' ' * (7 - (gl.auto_unit(process['memory_info']['rss']) | length)) }}\ |
51
|
|
|
⚡ {{ process['cpu_percent'] }}% CPU |
52
|
|
|
{% endfor %}\ |
53
|
|
|
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ |
54
|
|
|
|
55
|
|
|
""" |
56
|
|
|
|
57
|
|
|
|
58
|
|
|
class GlancesStdoutFetch: |
59
|
|
|
"""This class manages the Stdout JSON display.""" |
60
|
|
|
|
61
|
|
|
def __init__(self, config=None, args=None): |
62
|
|
|
# Init |
63
|
|
|
self.config = config |
64
|
|
|
self.args = args |
65
|
|
|
self.gl = api.GlancesAPI(self.config, self.args) |
66
|
|
|
|
67
|
|
|
def end(self): |
68
|
|
|
pass |
69
|
|
|
|
70
|
|
|
def update(self, stats, duration=3, cs_status=None, return_to_browser=False): |
71
|
|
|
"""Display fetch from the template file to stdout.""" |
72
|
|
|
if self.args.fetch_template == "": |
73
|
|
|
fetch_template = DEFAULT_FETCH_TEMPLATE |
74
|
|
|
else: |
75
|
|
|
logger.info("Using fetch template file: " + self.args.fetch_template) |
76
|
|
|
# Load the template from the file given in the self.args.fetch_template argument |
77
|
|
|
with open(self.args.fetch_template) as f: |
78
|
|
|
fetch_template = f.read() |
79
|
|
|
|
80
|
|
|
# Create a Jinja2 environment |
81
|
|
|
jinja_env = jinja2.Environment(loader=jinja2.BaseLoader()) |
82
|
|
|
template = jinja_env.from_string(fetch_template) |
83
|
|
|
output = template.render(gl=self.gl) |
84
|
|
|
print(output) |
85
|
|
|
|
86
|
|
|
# Return True to exit directly (no refresh) |
87
|
|
|
return True |
88
|
|
|
|