glances.standalone   A
last analyzed

Complexity

Total Complexity 33

Size/Duplication

Total Lines 207
Duplicated Lines 0 %

Importance

Changes 0
Metric Value
eloc 121
dl 0
loc 207
rs 9.76
c 0
b 0
f 0
wmc 33

8 Methods

Rating   Name   Duplication   Size   Complexity  
A GlancesStandalone.serve_forever() 0 7 3
A GlancesStandalone.serve_n() 0 5 3
A GlancesStandalone.display_modules_list() 0 4 1
A GlancesStandalone.serve_issue() 0 8 1
A GlancesStandalone.quiet() 0 3 1
A GlancesStandalone.__serve_once() 0 37 3
A GlancesStandalone.end() 0 17 4
F GlancesStandalone.__init__() 0 84 17
1
#
2
# This file is part of Glances.
3
#
4
# SPDX-FileCopyrightText: 2022 Nicolas Hennion <[email protected]>
5
#
6
# SPDX-License-Identifier: LGPL-3.0-only
7
#
8
9
"""Manage the Glances standalone session."""
10
11
import sys
12
import time
13
14
from glances.globals import WINDOWS
15
from glances.logger import logger
16
from glances.outdated import Outdated
17
from glances.outputs.glances_curses import GlancesCursesStandalone
18
from glances.outputs.glances_stdout import GlancesStdout
19
from glances.outputs.glances_stdout_api_doc import GlancesStdoutApiDoc
20
from glances.outputs.glances_stdout_api_restful_doc import GlancesStdoutApiRestfulDoc
21
from glances.outputs.glances_stdout_csv import GlancesStdoutCsv
22
from glances.outputs.glances_stdout_fetch import GlancesStdoutFetch
23
from glances.outputs.glances_stdout_issue import GlancesStdoutIssue
24
from glances.outputs.glances_stdout_json import GlancesStdoutJson
25
from glances.processes import glances_processes
26
from glances.stats import GlancesStats
27
from glances.timer import Counter
28
29
30
class GlancesStandalone:
31
    """This class creates and manages the Glances standalone session."""
32
33
    def __init__(self, config=None, args=None):
34
        self.config = config
35
        self.args = args
36
37
        # Quiet mode
38
        self._quiet = args.quiet
39
        self.refresh_time = args.time
40
41
        # Init stats
42
        start_duration = Counter()
43
        start_duration.reset()
44
        self.stats = GlancesStats(config=config, args=args)
45
        logger.debug(f"Plugins initialisation duration: {start_duration.get()} seconds")
46
47
        # Modules (plugins and exporters) are loaded at this point
48
        # Glances can display the list if asked...
49
        if args.modules_list:
50
            self.display_modules_list()
51
            sys.exit(0)
52
53
        # Set the args for the glances_processes instance
54
        glances_processes.set_args(args)
55
56
        # If process extended stats is disabled by user
57
        if not args.enable_process_extended:
58
            logger.debug("Extended stats for top process are disabled")
59
            glances_processes.disable_extended()
60
        else:
61
            logger.debug("Extended stats for top process are enabled")
62
            glances_processes.enable_extended()
63
64
        # Manage optional process filter
65
        if args.process_filter is not None:
66
            logger.info(f"Process filter is set to: {args.process_filter}")
67
            glances_processes.process_filter = args.process_filter
68
69
        if (args.export or args.stdout) and args.export_process_filter is not None:
70
            logger.info(f"Export process filter is set to: {args.export_process_filter}")
71
            glances_processes.export_process_filter = args.export_process_filter
72
73
        if (not WINDOWS) and args.no_kernel_threads:
74
            # Ignore kernel threads in process list
75
            glances_processes.disable_kernel_threads()
76
77
        # Initial system information update
78
        start_duration.reset()
79
        self.stats.update()
80
        logger.debug(f"First stats update duration: {start_duration.get()} seconds")
81
82
        if self.quiet:
83
            logger.info("Quiet mode is ON, nothing will be displayed")
84
            # In quiet mode, nothing is displayed
85
            glances_processes.max_processes = 0
86
        elif args.stdout_issue:
87
            logger.info("Issue mode is ON")
88
            self.screen = GlancesStdoutIssue(config=config, args=args)
89
        elif args.stdout_api_doc:
90
            logger.info("Restful Python documentation mode is ON")
91
            self.screen = GlancesStdoutApiDoc(config=config, args=args)
92
        elif args.stdout_api_restful_doc:
93
            logger.info("Restful API documentation mode is ON")
94
            self.screen = GlancesStdoutApiRestfulDoc(config=config, args=args)
95
        elif args.stdout:
96
            logger.info(f"Stdout mode is ON, following stats will be displayed: {args.stdout}")
97
            self.screen = GlancesStdout(config=config, args=args)
98
        elif args.stdout_json:
99
            logger.info(f"Stdout JSON mode is ON, following stats will be displayed: {args.stdout_json}")
100
            self.screen = GlancesStdoutJson(config=config, args=args)
101
        elif args.stdout_csv:
102
            logger.info(f"Stdout CSV mode is ON, following stats will be displayed: {args.stdout_csv}")
103
            self.screen = GlancesStdoutCsv(config=config, args=args)
104
        elif args.stdout_fetch:
105
            logger.info("Fetch mode is ON")
106
            self.screen = GlancesStdoutFetch(config=config, args=args)
107
        else:
108
            # Init screen in default mode (curses) aka TUI mode
109
            self.screen = GlancesCursesStandalone(config=config, args=args)
110
111
            # If an error occur during the screen init, continue if export option is set
112
            # It is done in the screen.init function
113
            self._quiet = args.quiet
114
115
        # Check the latest Glances version
116
        self.outdated = Outdated(config=config, args=args)
117
118
    @property
119
    def quiet(self):
120
        return self._quiet
121
122
    def display_modules_list(self):
123
        """Display modules list"""
124
        print("Plugins list: {}".format(', '.join(sorted(self.stats.getPluginsList(enable=False)))))
125
        print("Exporters list: {}".format(', '.join(sorted(self.stats.getExportsList(enable=False)))))
126
127
    def serve_issue(self):
128
        """Special mode for the --issue option
129
130
        Update is done in the screen.update function
131
        """
132
        ret = not self.screen.update(self.stats)
133
        self.end()
134
        return ret
135
136
    def __serve_once(self):
137
        """Main loop for the CLI.
138
139
        :return: True if we should continue (no exit key has been pressed)
140
        """
141
        # Update stats
142
        # Start a counter used to compute the time needed
143
        counter_update = Counter()
144
        self.stats.update()
145
        logger.debug(f'Stats updated duration: {counter_update.get()} seconds')
146
147
        # Patch for issue1326 to avoid < 0 refresh
148
        adapted_refresh = (
149
            (self.refresh_time - counter_update.get()) if (self.refresh_time - counter_update.get()) > 0 else 0
150
        )
151
152
        # Display stats
153
        # and wait refresh_time - counter
154
        if not self.quiet:
155
            # The update function return True if an exit key 'q' or 'ESC'
156
            # has been pressed.
157
            counter_display = Counter()
158
            ret = not self.screen.update(self.stats, duration=adapted_refresh)
159
            logger.debug(f'Stats display duration: {counter_display.get() - adapted_refresh} seconds')
160
        else:
161
            # Nothing is displayed
162
            # Break should be done via a signal (CTRL-C)
163
            time.sleep(adapted_refresh)
164
            ret = True
165
166
        # Export stats
167
        # Start a counter used to compute the time needed
168
        counter_export = Counter()
169
        self.stats.export(self.stats)
170
        logger.debug(f'Stats exported duration: {counter_export.get()} seconds')
171
172
        return ret
173
174
    def serve_n(self, n=1):
175
        """Serve n time."""
176
        for _ in range(n):
177
            if not self.__serve_once():
178
                break
179
        # self.end()
180
181
    def serve_forever(self):
182
        """Wrapper to the serve_forever function."""
183
        if self.args.stop_after:
184
            self.serve_n(n=self.args.stop_after)
185
        else:
186
            while self.__serve_once():
187
                pass
188
        # self.end()
189
190
    def end(self):
191
        """End of the standalone CLI."""
192
        if not self.quiet:
193
            self.screen.end()
194
195
        # Exit from export modules
196
        self.stats.end()
197
198
        # Check Glances version versus PyPI one
199
        if self.outdated.is_outdated() and 'unknown' not in self.outdated.installed_version():
200
            latest_version = self.outdated.latest_version()
201
            installed_version = self.outdated.installed_version()
202
            print(f"You are using Glances version {installed_version}, however version {latest_version} is available.")
203
            print("You should consider upgrading using: pip install --upgrade glances")
204
            print("Disable this warning temporarily using: glances --disable-check-update")
205
            print(
206
                "To disable it permanently, refer config reference at "
207
                "https://glances.readthedocs.io/en/latest/config.html#syntax"
208
            )
209