Home | History | Annotate | Download | only in site_utils
      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 
      8 import argparse
      9 import ctypes
     10 import logging
     11 import logging.handlers
     12 import multiprocessing
     13 import signal
     14 import sys
     15 import time
     16 
     17 import common
     18 from autotest_lib.client.common_lib.global_config import global_config as config
     19 from autotest_lib.site_utils import log_socket_server
     20 
     21 
     22 DEFAULT_PORT = 9080
     23 LOGGING_FORMAT = '%(asctime)s.%(msecs)03d %(levelname)-5.5s| %(message)s'
     24 MEGABYTE = 1024 * 1024
     25 
     26 
     27 class LogServerAlreadyRunningError(Exception):
     28     pass
     29 
     30 
     31 class 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 
     84 def 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 
     94 def 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 
    116 def 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 
    128 if __name__ == '__main__':
    129     sys.exit(main())
    130