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