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