Test Failed
Push — develop ( b7cdf6...584fbb )
by Nicolas
01:28 queued 40s
created

glances.setup_server_mode()   A

Complexity

Conditions 3

Size

Total Lines 7
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 3
eloc 4
nop 2
dl 0
loc 7
rs 10
c 0
b 0
f 0
1
#
2
# This file is part of Glances.
3
#
4
# SPDX-FileCopyrightText: 2024 Nicolas Hennion <[email protected]>
5
#
6
# SPDX-License-Identifier: LGPL-3.0-only
7
#
8
#
9
10
"""Init the Glances software."""
11
12
# Import system libs
13
import locale
14
import platform
15
import signal
16
import sys
17
import tracemalloc
18
19
# Global name
20
# Version should start and end with a numerical char
21
# See https://packaging.python.org/specifications/core-metadata/#version
22
__version__ = "4.3.2_dev01"
23
__apiversion__ = '4'
24
__author__ = 'Nicolas Hennion <[email protected]>'
25
__license__ = 'LGPLv3'
26
27
# Import psutil
28
try:
29
    from psutil import __version__ as psutil_version
30
except ImportError:
31
    print('psutil library not found. Glances cannot start.')
32
    sys.exit(1)
33
34
# Import Glances libs
35
# Note: others Glances libs will be imported optionally
36
from glances.logger import logger
37
from glances.main import GlancesMain
38
from glances.timer import Counter
39
40
# Check locale
41
try:
42
    locale.setlocale(locale.LC_ALL, '')
43
except locale.Error:
44
    print("Warning: Unable to set locale. Expect encoding problems.")
45
46
# Check psutil version
47
psutil_min_version = (5, 3, 0)
48
psutil_version_info = tuple([int(num) for num in psutil_version.split('.')])
49
if psutil_version_info < psutil_min_version:
50
    print('psutil 5.3.0 or higher is needed. Glances cannot start.')
51
    sys.exit(1)
52
53
54
# Trac malloc is only available on Python 3.4 or higher
55
56
57
def __signal_handler(signal, frame):
58
    logger.debug(f"Signal {signal} caught")
59
    end()
60
61
62
def end():
63
    """Stop Glances."""
64
    try:
65
        mode.end()
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable mode does not seem to be defined.
Loading history...
66
    except (NameError, KeyError):
67
        # NameError: name 'mode' is not defined in case of interrupt shortly...
68
        # ...after starting the server mode (issue #1175)
69
        pass
70
71
    logger.info("Glances stopped gracefully")
72
73
    # The end...
74
    sys.exit(0)
75
76
77
def start_main_loop(args, start_duration):
78
    logger.debug(f"Glances started in {start_duration.get()} seconds")
79
    if args.stop_after:
80
        logger.info(f'Glances will be stopped in ~{args.stop_after * args.time} seconds')
81
82
83
def check_memleak(args, mode):
84
    if args.memory_leak:
85
        wait = args.stop_after * args.time * args.memory_leak * 2
86
        print(f'Memory leak detection, please wait ~{wait} seconds...')
87
        # First run without dump to fill the memory
88
        mode.serve_n(args.stop_after)
89
        # Then start the memory-leak loop
90
        snapshot_begin = tracemalloc.take_snapshot()
91
    else:
92
        snapshot_begin = None
93
94
    return snapshot_begin
95
96
97
def setup_server_mode(args, mode):
98
    if args.stdout_issue or args.stdout_apidoc:
99
        # Serve once for issue/test mode
100
        mode.serve_issue()
101
    else:
102
        # Serve forever
103
        mode.serve_forever()
104
105
106
def maybe_trace_memleak(args, snapshot_begin):
107
    if args.memory_leak:
108
        snapshot_end = tracemalloc.take_snapshot()
109
        snapshot_diff = snapshot_end.compare_to(snapshot_begin, 'filename')
110
        memory_leak = sum([s.size_diff for s in snapshot_diff])
111
        print(f"Memory consumption: {memory_leak / 1000:.1f}KB (see log for details)")
112
        logger.info("Memory consumption (top 5):")
113
        for stat in snapshot_diff[:5]:
114
            logger.info(stat)
115
    elif args.trace_malloc:
116
        # See more options here: https://docs.python.org/3/library/tracemalloc.html
117
        snapshot = tracemalloc.take_snapshot()
118
        top_stats = snapshot.statistics("filename")
119
        print("[ Trace malloc - Top 10 ]")
120
        for stat in top_stats[:10]:
121
            print(stat)
122
123
124
def start(config, args):
125
    """Start Glances."""
126
127
    # Load mode
128
    global mode
129
130
    if args.trace_malloc or args.memory_leak:
131
        tracemalloc.start()
132
133
    start_duration = Counter()
134
135
    if core.is_standalone():
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable core does not seem to be defined.
Loading history...
136
        from glances.standalone import GlancesStandalone as GlancesMode
137
    elif core.is_client():
138
        if core.is_client_browser():
139
            from glances.client_browser import GlancesClientBrowser as GlancesMode
140
        else:
141
            from glances.client import GlancesClient as GlancesMode
142
    elif core.is_server():
143
        from glances.server import GlancesServer as GlancesMode
144
    elif core.is_webserver():
145
        from glances.webserver import GlancesWebServer as GlancesMode
146
147
    # Init the mode
148
    logger.info(f"Start {GlancesMode.__name__} mode")
149
    mode = GlancesMode(config=config, args=args)
0 ignored issues
show
introduced by
The variable GlancesMode does not seem to be defined for all execution paths.
Loading history...
150
151
    start_main_loop(args, start_duration)
152
    snapshot_begin = check_memleak(args, mode)
153
    setup_server_mode(args, mode)
154
    maybe_trace_memleak(args, snapshot_begin)
155
156
    # Shutdown
157
    mode.end()
158
159
160
def main():
161
    """Main entry point for Glances.
162
163
    Select the mode (standalone, client or server)
164
    Run it...
165
    """
166
    # SIGHUP not available on Windows (see issue #2408)
167
    if sys.platform.startswith('win'):
168
        signal_list = (signal.SIGTERM, signal.SIGINT)
169
    else:
170
        signal_list = (signal.SIGTERM, signal.SIGINT, signal.SIGHUP)
171
    # Catch the kill signal
172
    for sig in signal_list:
173
        signal.signal(sig, __signal_handler)
174
175
    # Log Glances and psutil version
176
    logger.info(f'Start Glances {__version__}')
177
    python_impl = platform.python_implementation()
178
    python_ver = platform.python_version()
179
    logger.info(f'{python_impl} {python_ver} ({sys.executable}) and psutil {psutil_version} detected')
180
181
    # Share global var
182
    global core
183
184
    # Create the Glances main instance
185
    # Glances options from the command line are read first (in __init__)
186
    # then the options from the config file (in parse_args)
187
    core = GlancesMain()
188
189
    # Glances can be ran in standalone, client or server mode
190
    start(config=core.get_config(), args=core.get_args())
191