xref: /aosp_15_r20/external/autotest/site_utils/rpc_logserver.py (revision 9c5db1993ded3edbeafc8092d69fe5de2ee02df7)
1#!/usr/bin/python3
2#
3# Copyright (c) 2015 The Chromium OS Authors. All rights reserved.
4# Use of this source code is governed by a BSD-style license that can be
5# found in the LICENSE file.
6
7
8from __future__ import absolute_import
9from __future__ import division
10from __future__ import print_function
11
12import argparse
13import ctypes
14import logging
15import logging.handlers
16import multiprocessing
17import signal
18import sys
19import time
20
21import common
22from autotest_lib.client.common_lib.global_config import global_config as config
23from autotest_lib.site_utils import log_socket_server
24
25
26DEFAULT_PORT = 9080
27LOGGING_FORMAT = '%(asctime)s.%(msecs)03d %(levelname)-5.5s| %(message)s'
28MEGABYTE = 1024 * 1024
29
30
31class LogServerAlreadyRunningError(Exception):
32    pass
33
34
35class LogServer(object):
36    """A wrapper class to start and stop a TCP server for logging."""
37
38    process = None
39
40    @staticmethod
41    def start(port, log_handler):
42        """Start Log Record Socket Receiver in a new process.
43
44        @param port: Port to listen on.
45        @param log_handler: Logging handler.
46
47        @raise Exception: if TCP server is already running.
48        """
49        if LogServer.process:
50            raise LogServerAlreadyRunningError('LogServer is already running.')
51        server_started = multiprocessing.Value(ctypes.c_bool, False)
52        LogServer.process = multiprocessing.Process(
53                target=LogServer._run,
54                args=(server_started, port, log_handler))
55        LogServer.process.start()
56        while not server_started.value:
57            time.sleep(0.1)
58        print('LogServer is started at port %d.' % port)
59
60
61    @staticmethod
62    def _run(server_started, port, log_handler):
63        """Run LogRecordSocketReceiver to receive log.
64
65        @param server_started: True if socket log server is started.
66        @param port: Port used by socket log server.
67        @param log_handler: Logging handler.
68        """
69        # Clear all existing log handlers.
70        logging.getLogger().handlers = []
71        logging.getLogger().addHandler(log_handler)
72
73        tcp_server = log_socket_server.LogRecordSocketReceiver(
74                port=port)
75        print('Starting LogServer...')
76        server_started.value = True
77        tcp_server.serve_until_stopped()
78
79
80    @staticmethod
81    def stop():
82        """Stop LogServer."""
83        if LogServer.process:
84            LogServer.process.terminate()
85            LogServer.process = None
86
87
88def signal_handler(signal, frame):
89    """Handler for signal SIGINT.
90
91    @param signal: SIGINT
92    @param frame: the current stack frame
93    """
94    LogServer.stop()
95    sys.exit(0)
96
97
98def get_logging_handler():
99    """Return a logging handler.
100
101    Configure a RPC logging handler based on global_config and return
102    the handler.
103    """
104    max_log_size = config.get_config_value('SERVER', 'rpc_max_log_size_mb',
105                                           type=int)
106    number_of_old_logs = config.get_config_value('SERVER', 'rpc_num_old_logs',
107                                                 type=int)
108    log_path = config.get_config_value('SERVER', 'rpc_log_path')
109
110    formatter = logging.Formatter(
111            fmt=LOGGING_FORMAT, datefmt='%m/%d %H:%M:%S')
112    handler = logging.handlers.RotatingFileHandler(
113            log_path,
114            maxBytes=max_log_size*MEGABYTE,
115            backupCount=number_of_old_logs)
116    handler.setFormatter(formatter)
117    return handler
118
119
120def main():
121    parser = argparse.ArgumentParser(
122            formatter_class=argparse.ArgumentDefaultsHelpFormatter)
123    parser.add_argument('-p', type=int, dest='port',
124                        help=('Listening port number'), default=DEFAULT_PORT)
125    options = parser.parse_args()
126
127    signal.signal(signal.SIGINT, signal_handler)
128
129    LogServer.start(options.port, get_logging_handler())
130
131
132if __name__ == '__main__':
133    sys.exit(main())
134