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