Skip to content

Commit 979d040

Browse files
committed
Merge branch 'issue410' into develop
2 parents 1aa8d22 + 8e8773d commit 979d040

14 files changed

+704
-351
lines changed

docs/api.rst

+405-242
Large diffs are not rendered by default.

docs/man/glances.1

+1-1
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ level margin: \\n[rst2man-indent\\n[rst2man-indent-level]]
2828
.\" new: \\n[rst2man-indent\\n[rst2man-indent-level]]
2929
.in \\n[rst2man-indent\\n[rst2man-indent-level]]u
3030
..
31-
.TH "GLANCES" "1" "Jan 04, 2025" "4.3.0.8" "Glances"
31+
.TH "GLANCES" "1" "Jan 26, 2025" "4.3.1_dev09" "Glances"
3232
.SH NAME
3333
glances \- An eye on your system
3434
.SH SYNOPSIS

glances/globals.py

+11-2
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@
2929
from datetime import datetime
3030
from operator import itemgetter, methodcaller
3131
from statistics import mean
32-
from typing import Any, Union
32+
from typing import Any, Optional, Union
3333
from urllib.error import HTTPError, URLError
3434
from urllib.parse import urlparse
3535
from urllib.request import Request, urlopen
@@ -393,13 +393,22 @@ def dictlist(data, item):
393393
return None
394394

395395

396-
def json_dumps_dictlist(data, item):
396+
def dictlist_json_dumps(data, item):
397397
dl = dictlist(data, item)
398398
if dl is None:
399399
return None
400400
return json_dumps(dl)
401401

402402

403+
def dictlist_first_key_value(data: list[dict], key, value) -> Optional[dict]:
404+
"""In a list of dict, return first item where key=value or none if not found."""
405+
try:
406+
ret = next(item for item in data if key in item and item[key] == value)
407+
except StopIteration:
408+
ret = None
409+
return ret
410+
411+
403412
def string_value_to_float(s):
404413
"""Convert a string with a value and an unit to a float.
405414
Example:

glances/outputs/glances_restful_api.py

+68
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
from glances.globals import json_dumps
2222
from glances.logger import logger
2323
from glances.password import GlancesPassword
24+
from glances.processes import glances_processes
2425
from glances.servers_list import GlancesServersList
2526
from glances.servers_list_dynamic import GlancesAutoDiscoverClient
2627
from glances.stats import GlancesStats
@@ -221,6 +222,12 @@ def _router(self) -> APIRouter:
221222
# POST
222223
router.add_api_route(f'{base_path}/events/clear/warning', self._events_clear_warning, methods=['POST'])
223224
router.add_api_route(f'{base_path}/events/clear/all', self._events_clear_all, methods=['POST'])
225+
router.add_api_route(
226+
f'{base_path}/processes/extended/disable', self._api_disable_extended_processes, methods=['POST']
227+
)
228+
router.add_api_route(
229+
f'{base_path}/processes/extended/{{pid}}', self._api_set_extended_processes, methods=['POST']
230+
)
224231

225232
# GET
226233
route_mapping = {
@@ -235,6 +242,8 @@ def _router(self) -> APIRouter:
235242
f'{base_path}/all/views': self._api_all_views,
236243
f'{base_path}/pluginslist': self._api_plugins,
237244
f'{base_path}/serverslist': self._api_servers_list,
245+
f'{base_path}/processes/extended': self._api_get_extended_processes,
246+
f'{base_path}/processes/{{pid}}': self._api_get_processes,
238247
f'{plugin_path}': self._api,
239248
f'{plugin_path}/history': self._api_history,
240249
f'{plugin_path}/history/{{nb}}': self._api_history,
@@ -900,3 +909,62 @@ def _api_args_item(self, item: str):
900909
raise HTTPException(status.HTTP_404_NOT_FOUND, f"Cannot get args item ({str(e)})")
901910

902911
return GlancesJSONResponse(args_json)
912+
913+
def _api_set_extended_processes(self, pid: str):
914+
"""Glances API RESTful implementation.
915+
916+
Set the extended process stats for the given PID
917+
HTTP/200 if OK
918+
HTTP/400 if PID is not found
919+
HTTP/404 if others error
920+
"""
921+
process_stats = glances_processes.get_stats(int(pid))
922+
923+
if not process_stats:
924+
raise HTTPException(status.HTTP_404_NOT_FOUND, f"Unknown PID process {pid}")
925+
926+
glances_processes.extended_process = process_stats
927+
928+
return GlancesJSONResponse(True)
929+
930+
def _api_disable_extended_processes(self):
931+
"""Glances API RESTful implementation.
932+
933+
Disable extended process stats
934+
HTTP/200 if OK
935+
HTTP/400 if PID is not found
936+
HTTP/404 if others error
937+
"""
938+
glances_processes.extended_process = None
939+
940+
return GlancesJSONResponse(True)
941+
942+
def _api_get_extended_processes(self):
943+
"""Glances API RESTful implementation.
944+
945+
Get the extended process stats (if set before)
946+
HTTP/200 if OK
947+
HTTP/400 if PID is not found
948+
HTTP/404 if others error
949+
"""
950+
process_stats = glances_processes.get_extended_stats()
951+
952+
if not process_stats:
953+
process_stats = {}
954+
955+
return GlancesJSONResponse(process_stats)
956+
957+
def _api_get_processes(self, pid: str):
958+
"""Glances API RESTful implementation.
959+
960+
Get the process stats for the given PID
961+
HTTP/200 if OK
962+
HTTP/400 if PID is not found
963+
HTTP/404 if others error
964+
"""
965+
process_stats = glances_processes.get_stats(int(pid))
966+
967+
if not process_stats:
968+
raise HTTPException(status.HTTP_404_NOT_FOUND, f"Unknown PID process {pid}")
969+
970+
return GlancesJSONResponse(process_stats)

glances/outputs/glances_stdout_apidoc.py

+27-1
Original file line numberDiff line numberDiff line change
@@ -225,7 +225,30 @@ def print_all():
225225
print('Get all Glances stats::')
226226
print('')
227227
print(f' # curl {API_URL}/all')
228-
print(' Return a very big dictionary (avoid using this request, performances will be poor)...')
228+
print(' Return a very big dictionary with all stats')
229+
print('')
230+
print('Note: Update is done automatically every time /all or /<plugin> is called.')
231+
print('')
232+
233+
234+
def print_processes():
235+
sub_title = 'GET stats of a specific process'
236+
print(sub_title)
237+
print('-' * len(sub_title))
238+
print('')
239+
print('Get stats for process with PID == 777::')
240+
print('')
241+
print(f' # curl {API_URL}/processes/777')
242+
print(' Return stats for process (dict)')
243+
print('')
244+
print('Enable extended stats for process with PID == 777 (only one process at a time can be enabled)::')
245+
print('')
246+
print(f' # curl -X POST {API_URL}/processes/extended/777')
247+
print(f' # curl {API_URL}/all')
248+
print(f' # curl {API_URL}/processes/777')
249+
print(' Return stats for process (dict)')
250+
print('')
251+
print('Note: Update *is not* done automatically when you call /processes/<pid>.')
229252
print('')
230253

231254

@@ -370,6 +393,9 @@ def update(self, stats, duration=1):
370393
# Get all stats
371394
print_all()
372395

396+
# Get process stats
397+
print_processes()
398+
373399
# Get top stats (only for plugins with a list of items)
374400
# Example for processlist plugin: get top 2 processes
375401
print_top(stats)

glances/outputs/static/css/style.scss

+33-18
Original file line numberDiff line numberDiff line change
@@ -168,28 +168,28 @@ body {
168168
margin-bottom: 1em;
169169
}
170170

171-
.clear-button {
172-
background-color: $glances-link-hover-color !important;
173-
color: white;
174-
border: none;
175-
text-align: center;
176-
text-decoration: none;
177-
display: inline-block;
178-
transition-duration: 0.4s;
171+
.button {
172+
color: #99CCFF; /* Bleu clair high-tech */
173+
background: rgba(0, 0, 0, 0.4); /* Fond légèrement transparent */
174+
border: 1px solid #99CCFF; /* Bordure discrète */
175+
padding: 5px 10px;
176+
border-radius: 5px;
177+
letter-spacing: 1px;
178+
cursor: pointer;
179+
transition: all 0.2s ease-in-out;
180+
position: relative;
181+
overflow: hidden;
179182
}
180183

181-
.clear-button:hover {
182-
background-color: white;
183-
color: black;
184+
.button:hover {
185+
background: rgba(153, 204, 255, 0.15); /* Légère coloration au survol */
186+
border-color: #B0D0FF;
187+
color: #B0D0FF;
184188
}
185189

186-
#system {
187-
span {
188-
padding-left: 10px;
189-
}
190-
span:nth-child(1) {
191-
padding-left: 0px;
192-
}
190+
.button:active {
191+
transform: scale(0.95); /* Légère réduction pour effet de pression */
192+
box-shadow: 0 0 8px rgba(153, 204, 255, 0.5); /* Flash léger */
193193
}
194194

195195
.frequency {
@@ -392,12 +392,26 @@ body {
392392
}
393393
}
394394

395+
#processlist div.extendedstats {
396+
margin-bottom: 1em;
397+
margin-top: 1em;
398+
}
399+
400+
#processlist div.extendedstats div span:not(:last-child) {
401+
margin-right: 1em;
402+
}
403+
395404
#processlist {
396405
overflow-y: auto;
397406
height: 600px;
398407
.table {
399408
margin-bottom: 1em;
400409
}
410+
411+
.table-hover tbody tr:hover td {
412+
background: $glances-link-hover-color;
413+
}
414+
401415
// Default column size
402416
* > td:nth-child(-n+12) {
403417
width: 5em;
@@ -427,6 +441,7 @@ body {
427441
}
428442
}
429443

444+
430445
#alerts {
431446
span {
432447
padding-left: 10px;

glances/outputs/static/js/components/plugin-alert.vue

+1-1
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
<span class="title" v-if="hasAlerts">
44
Warning or critical alerts (last {{ countAlerts }} entries)
55
<span>
6-
<button class="clear-button" v-on:click="clear()">Clear alerts</button>
6+
<button class="button" v-on:click="clear()">Clear alerts</button>
77
</span>
88
</span>
99
<span class="title" v-else>No warning or critical alert detected</span>

0 commit comments

Comments
 (0)