summaryrefslogtreecommitdiffstats
path: root/glances/__init__.py
blob: 514ebdc137f7c5e59694327fbeec47f420e8484d (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
# -*- coding: utf-8 -*-
#
# This file is part of Glances.
#
# SPDX-FileCopyrightText: 2023 Nicolas Hennion <nicolas@nicolargo.com>
#
# SPDX-License-Identifier: LGPL-3.0-only
#
#

"""Init the Glances software."""

# Import system libs
import locale
import platform
import signal
import sys

# Global name
# Version should start and end with a numerical char
# See https://packaging.python.org/specifications/core-metadata/#version
__version__ = '3.4.0.4'
__author__ = 'Nicolas Hennion <nicolas@nicolargo.com>'
__license__ = 'LGPLv3'

# Import psutil
try:
    from psutil import __version__ as psutil_version
except ImportError:
    print('psutil library not found. Glances cannot start.')
    sys.exit(1)

# Import Glances libs
# Note: others Glances libs will be imported optionally
from glances.compat import PY3
from glances.logger import logger
from glances.main import GlancesMain
from glances.timer import Counter

# Check locale
try:
    locale.setlocale(locale.LC_ALL, '')
except locale.Error:
    print("Warning: Unable to set locale. Expect encoding problems.")

# Check Python version
if sys.version_info < (2, 7) or (3, 0) <= sys.version_info < (3, 4):
    print('Glances requires at least Python 2.7 or 3.4 to run.')
    sys.exit(1)

# Check psutil version
psutil_min_version = (5, 3, 0)
psutil_version_info = tuple([int(num) for num in psutil_version.split('.')])
if psutil_version_info < psutil_min_version:
    print('psutil 5.3.0 or higher is needed. Glances cannot start.')
    sys.exit(1)

# Trac malloc is only available on Python 3.4 or higher
if PY3:
    import tracemalloc


def __signal_handler(signal, frame):
    logger.debug("Signal {} catched".format(signal))
    end()


def end():
    """Stop Glances."""
    try:
        mode.end()
    except (NameError, KeyError):
        # NameError: name 'mode' is not defined in case of interrupt shortly...
        # ...after starting the server mode (issue #1175)
        pass

    logger.info("Glances stopped gracefully")

    # The end...
    sys.exit(0)


def start(config, args):
    """Start Glances."""

    # Load mode
    global mode

    if args.trace_malloc or args.memory_leak:
        tracemalloc.start()

    start_duration = Counter()

    if core.is_standalone():
        from glances.standalone import GlancesStandalone as GlancesMode
    elif core.is_client():
        if core.is_client_browser():
            from glances.client_browser import GlancesClientBrowser as GlancesMode
        else:
            from glances.client import GlancesClient as GlancesMode
    elif core.is_server():
        from glances.server import GlancesServer as GlancesMode
    elif core.is_webserver():
        from glances.webserver import GlancesWebServer as GlancesMode

    # Init the mode
    logger.info("Start {} mode".format(GlancesMode.__name__))
    mode = GlancesMode(config=config, args=args)

    # Start the main loop
    logger.debug("Glances started in {} seconds".format(start_duration.get()))
    if args.stop_after:
        logger.info('Glances will be stopped in ~{} seconds'.format(args.stop_after * args.time * args.memory_leak * 2))

    if args.memory_leak:
        print(
            'Memory leak detection, please wait ~{} seconds...'.format(
                args.stop_after * args.time * args.memory_leak * 2
            )
        )
        # First run without dump to fill the memory
        mode.serve_n(args.stop_after)
        # Then start the memory-leak loop
        snapshot_begin = tracemalloc.take_snapshot()

    if args.stdout_issue or args.stdout_apidoc:
        # Serve once for issue/test mode
        mode.serve_issue()
    else:
        # Serve forever
        mode.serve_forever()

    if args.memory_leak:
        snapshot_end = tracemalloc.take_snapshot()
        snapshot_diff = snapshot_end.compare_to(snapshot_begin, 'filename')
        memory_leak = sum([s.size_diff for s in snapshot_diff])
        print("Memory consumption: {0:.1f}KB (see log for details)".format(memory_leak / 1000))
        logger.info("Memory consumption (top 5):")
        for stat in snapshot_diff[:5]:
            logger.info(stat)
    elif args.trace_malloc:
        # See more options here: https://docs.python.org/3/library/tracemalloc.html
        snapshot = tracemalloc.take_snapshot()
        top_stats = snapshot.statistics("filename")
        print("[ Trace malloc - Top 10 ]")
        for stat in top_stats[:10]:
            print(stat)

    # Shutdown
    mode.end()


def main():
    """Main entry point for Glances.

    Select the mode (standalone, client or server)
    Run it...
    """
    # SIGHUP not available on Windows (see issue #2408)
    if sys.platform.startswith('win'):
        signal_list = (signal.SIGTERM, signal.SIGINT)
    else:
        signal_list = (signal.SIGTERM, signal.SIGINT, signal.SIGHUP)
    # Catch the kill signal
    for sig in signal_list:
        signal.signal(sig, __signal_handler)

    # Log Glances and psutil version
    logger.info('Start Glances {}'.format(__version__))
    logger.info(
        '{} {} ({}) and psutil {} detected'.format(
            platform.python_implementation(), platform.python_version(), sys.executable, psutil_version
        )
    )

    # Share global var
    global core

    # Create the Glances main instance
    # Glances options from the command line are read first (in __init__)
    # then the options from the config file (in parse_args)
    core = GlancesMain()

    # Glances can be ran in standalone, client or server mode
    start(config=core.get_config(), args=core.get_args())