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