def test_read_config(self): with tempfile.TemporaryDirectory() as tmpdirname: tmpfilename = tmpdirname + '/f.yaml' create_file(tmpfilename, SAMPLE_JSON.split('\n')) result = read_config.read_config(tmpfilename) self.assertEqual(result['gyr1']['port'], '/tmp/tty_gyr1') self.assertEqual(len(result), 4) # Let it figure out that it's JSON result = read_config.read_config(tmpfilename) self.assertEqual(result['gyr1']['port'], '/tmp/tty_gyr1') self.assertEqual(len(result), 4)
def __init__(self, config_file, config_name=None, log_level=None): """Create a Listener from a Python config file. If the file name format is file_name:config, then assume the file_name is that of a cruise definition, and look for the config itself under the 'configs:' key of the file's YAML. """ # If they've got a ':' in the config file name, then we're # expecting them to also give us a config name to look for. if config_file.find(':') > 0: (config_file, config_name) = config_file.split(':', maxsplit=1) config = read_config.read_config(config_file) if config_name: config_dict = config.get('configs', None) if not config_dict: raise ValueError('Configuration name "%s" specified, but no ' '"configs" section found in file "%s"' % (config_name, config_file)) config = config_dict.get(config_name, None) if not config: raise ValueError('Configuration name "%s" not found in file "%s"' % (config_name, config_file)) logging.info('Loaded config file: %s', pprint.pformat(config)) super().__init__(config=config)
def _read_definitions(self, filespec_paths): definitions = {} for filespec in filespec_paths.split(','): logging.debug('reading definitions from %s', filespec) for filename in glob.glob(filespec): new_defs = read_config.read_config(filename) for key in new_defs: if key in definitions: logging.warning('Duplicate definition for key "%s" found in %s', key, filename) definitions[key] = new_defs[key] return definitions
def _read_definitions(self, filespec_paths): """Read the files on the filespec_paths and return dictionary of accumulated definitions. """ definitions = {} for filespec in filespec_paths.split(','): filenames = glob.glob(filespec) if not filenames: logging.warning('No files match definition file spec "%s"', filespec) for filename in filenames: file_definitions = read_config.read_config(filename) for new_def_name, new_def in file_definitions.items(): if new_def_name in definitions: logging.warning('Duplicate definition for "%s" found in %s', new_def_name, filename) definitions[new_def_name] = new_def return definitions
def config_from_filename(filename): """Load a logger configuration from a filename. If there's a ':' in the config file name, then we expect what is before the colon to be a cruise definition, and what is after to be the name of a configuration inside that definition. """ config_name = None if filename.find(':') > 0: (filename, config_name) = filename.split(':', maxsplit=1) config = read_config(filename) if config_name: config_dict = config.get('configs', None) if not config_dict: raise ValueError('Configuration name "%s" specified, but no ' '"configs" section found in file "%s"' % (config_name, filename)) config = config_dict.get(config_name, None) if not config: raise ValueError('Configuration name "%s" not found in file "%s"' % (config_name, filename)) logging.info('Loaded config file: %s', pprint.pformat(config)) return config
dest='mode', required=True, help='Cruise mode to select') args = parser.parse_args() # Set up logging first of all LOG_LEVELS = {0: logging.WARNING, 1: logging.INFO, 2: logging.DEBUG} log_level = LOG_LEVELS[min(args.verbosity, max(LOG_LEVELS))] logging.basicConfig(format=DEFAULT_LOGGING_FORMAT, level=log_level) # What level do we want our component loggers to write? logger_log_level = LOG_LEVELS[min(args.logger_verbosity, max(LOG_LEVELS))] config = read_config(args.config) mode_config_names = config.get('modes').get(args.mode) all_configs = config.get('configs') mode_configs = { logger: all_configs.get(mode_config_names[logger]) for logger in mode_config_names } sup = LoggerSupervisor(configs=mode_configs, stderr_file_pattern=args.stderr_file_pattern, stderr_data_server=args.stderr_data_server, max_tries=args.max_tries, min_uptime=args.min_uptime, interval=args.interval, logger_log_level=logger_log_level) sup.run()
dest='verbosity', default=0, action='count', help='Increase output verbosity') args = parser.parse_args() LOGGING_FORMAT = '%(asctime)-15s %(message)s' logging.basicConfig(format=LOGGING_FORMAT) LOG_LEVELS = {0: logging.WARNING, 1: logging.INFO, 2: logging.DEBUG} args.verbosity = min(args.verbosity, max(LOG_LEVELS)) logging.getLogger().setLevel(LOG_LEVELS[args.verbosity]) # Okay - get to work here if args.config: configs = read_config(args.config) logging.info('Read configs: %s', configs) thread_list = [] writer_list = [] for instrument, config in configs.items(): port = config['port'] filebase = config['filebase'] writer = SimNetwork(port=port, filebase=filebase, instrument=instrument) writer_thread = threading.Thread(target=writer.run, kwargs={'loop': args.loop}, daemon=True) writer_thread.start() thread_list.append(writer_thread) writer_list.append('%s %d, %s' % (instrument, port, filebase))
def _new_read_definitions(self, filespec_paths, definitions=None): """Read the files on the filespec_paths and return dictionary of accumulated definitions. filespec_paths - a list of possibly-globbed filespecs to be read definitions - optional dict of pre-existing definitions that will be added to. Typically this will be omitted on a base call, but may be added to when recursing. Passing it in allows flagging when items are defined more than once. """ # If nothing was passed in, start with base case. definitions = definitions or {'devices': {}, 'device_types': {}} for filespec in filespec_paths.split(','): filenames = glob.glob(filespec) if not filenames: logging.warning('No files match definition file spec "%s"', filespec) for filename in filenames: file_definitions = read_config.read_config(filename) for key, val in file_definitions.items(): # If we have a dict of device definitions, copy them into the # 'devices' key of our definitions. if key == 'devices': if not isinstance(val, dict): logging.error( '"devices" values in file %s must be dict. ' 'Found type "%s"', filename, type(val)) return None for device_name, device_def in val.items(): if device_name in definitions['devices']: logging.warning( 'Duplicate definition for "%s" found in %s', device_name, filename) definitions['devices'][device_name] = device_def # If we have a dict of device_type definitions, copy them into the # 'device_types' key of our definitions. elif key == 'device_types': if not isinstance(val, dict): logging.error( '"device_typess" values in file %s must be dict. ' 'Found type "%s"', filename, type(val)) return None for device_type_name, device_type_def in val.items(): if device_type_name in definitions['device_types']: logging.warning( 'Duplicate definition for "%s" found in %s', device_type_name, filename) definitions['device_types'][ device_type_name] = device_type_def # If we're including other files, recurse inelegantly elif key == 'includes': if not type(val) in [str, list]: logging.error( '"includes" values in file %s must be either ' 'a list or a simple string. Found type "%s"', filename, type(val)) return None if isinstance(val, str): val = [val] for filespec in val: new_defs = self._new_read_definitions( filespec, definitions) definitions['devices'].update( new_defs.get('devices', {})) definitions['device_types'].update( new_defs.get('device_types', {})) # If it's not an includes/devices/device_types def, assume # it's a (deprecated) top-level device or device_type # definition. Try adding it to the right place. else: category = val.get('category', None) if category not in ['device', 'device_type']: logging.warning( 'Top-level definition "%s" in file %s is not ' 'category "device" or "device_type". ' 'Category is "%s" - ignoring', category) continue if category == 'device': if key in definitions['devices']: logging.warning( 'Duplicate definition for "%s" found in %s', key, filename) definitions['devices'][key] = val else: if key in definitions['device_types']: logging.warning( 'Duplicate definition for "%s" found in %s', key, filename) definitions['device_types'][key] = val # Finally, return the accumulated definitions return definitions
def process_command(self, command): """Parse and execute the command string we've received.""" try: if not command: logging.info('Empty command received') # elif command == 'cruises': # cruises = self.api.get_cruises() # if cruises: # print('Loaded cruises: ' + ', '.join(cruises)) # else: # print('No cruises loaded') # load_cruise <cruise config file name> elif command == 'load_configuration': raise ValueError( 'format: load_configuration <config file name>') elif command.find('load_configuration ') == 0: (load_cmd, filename) = command.split(maxsplit=1) logging.info('Loading config from %s', filename) try: config = read_config(filename) self.api.load_configuration(config) except FileNotFoundError as e: logging.error('Unable to find file "%s"', filename) # set_cruise <JSON encoding of a cruise> elif command == 'set_configuration': raise ValueError( 'format: set_configuration <JSON encoding of config>') elif command.find('set_configuration ') == 0: (cruise_cmd, config_json) = command.split(maxsplit=1) logging.info('Setting config to %s', config_json) self.api.load_configuration(json.loads(config_json)) # delete_cruise <cruise_id> # elif command == 'delete_configuration': # raise ValueError('format: delete_configuration') elif command.find('delete_configuration') == 0: (config_cmd) = command.split(maxsplit=1) logging.info('Deleting config') self.api.delete_configuration() # modes <cruise_id> # elif command == 'modes': # raise ValueError('format: modes') elif command.find('get_modes') == 0: (mode_cmd) = command.split(maxsplit=1) modes = self.api.get_modes() if len(modes) > 0: print('Available Modes: %s' % (', '.join(modes))) else: print('Available Modes: n/a') ############################ # mode <cruise_id> # elif command == 'mode': # raise ValueError('format: mode') elif command.find('get_active_mode') == 0: (mode_cmd) = command.split(maxsplit=1) mode = self.api.get_active_mode() print('Current mode: %s' % (mode)) # set_active_mode <mode> elif command == 'set_active_mode': raise ValueError('format: set_active_mode <mode>') elif command.find('set_active_mode ') == 0: (mode_cmd, mode_name) = command.split(maxsplit=1) logging.info('Setting mode to %s', mode_name) self.api.set_active_mode(mode_name) ############################ # loggers <cruise_id> # elif command == 'loggers': # raise ValueError('format: loggers') elif command.find('get_loggers') == 0: (loggers_cmd) = command.split(maxsplit=1) loggers = self.api.get_loggers() if len(loggers) > 0: print('Loggers: %s' % (', '.join(loggers))) else: print('Loggers: n/a') ############################ # logger_configs <cruise_id> <logger> elif command == 'get_logger_configs': raise ValueError('format: get_logger_configs <logger name>') elif command.find('get_logger_configs ') == 0: (logger_cmd, logger_name) = command.split(maxsplit=1) logger_configs = self.api.get_logger_config_names(logger_name) print('Configs for %s: %s' % (logger_name, ', '.join(logger_configs))) ############################ # set_logger_config_name <cruise_id> <logger name> <name of logger config> elif command == 'set_active_logger_config': raise ValueError( 'format: set_active_logger_config <logger name> <name of logger config>' ) elif command.find('set_active_logger_config ') == 0: (logger_cmd, logger_name, config_name) = command.split(maxsplit=2) logging.info('Setting logger %s to config %s', logger_name, config_name) # Is this a valid config for this logger? if not config_name in self.api.get_logger_config_names( logger_name): raise ValueError( 'Config "%s" is not valid for logger "%s"' % (config_name, logger_name)) self.api.set_active_logger_config(logger_name, config_name) ############################ # configs <cruise_id> # elif command == 'configs': # raise ValueError('format: configs') elif command.find('get_active_logger_configs') == 0: (config_cmd) = command.split(maxsplit=1) config_names = { logger_id: self.api.get_logger_config_name(logger_id) for logger_id in self.api.get_loggers() } if len(config_names) > 0: for logger_id, config_name in config_names.items(): print('%s: %s' % (logger_id, config_name)) else: print("No configs found!") ############################ # status # elif command == 'status': # raise ValueError('format: status') elif command.find('get_status') == 0: (status_cmd) = command.split(maxsplit=1) status_dict = self.api.get_status() print('%s' % pprint.pformat(status_dict)) ############################ # status_since elif command == 'get_status_since': raise ValueError('format: get_status_since <timestamp>') elif command.find('get_status_since ') == 0: (status_cmd, since_timestamp) = command.split(maxsplit=1) status_dict = self.api.get_status(float(since_timestamp)) print('%s' % pprint.pformat(status_dict)) ############################ # server_log elif command == 'get_server_log': server_log = self.api.get_message_log(source=SOURCE_NAME) print('%s' % pprint.pformat(server_log)) ############################ # server_log timestamp elif command.find('get_server_log') == 0: (log_cmd, since_timestamp) = command.split(maxsplit=1) server_log = self.api.get_message_log( source=SOURCE_NAME, user=None, log_level=self.api.DEBUG, since_timestamp=float(since_timestamp)) print('%s' % pprint.pformat(server_log)) ############################ # Quit gracefully elif command == 'quit': logging.info('Got quit command') self.quit() ############################ elif command == 'help': self.show_commands() ############################ else: print('Got unknown command: "{}"'.format(command)) print('Type "help" for help') except ValueError as e: logging.error('%s', e) finally: self.api.message_log(source=SOURCE_NAME, user='******' % (USER, HOSTNAME), log_level=self.api.INFO, message='command: ' + command)
def index(request): """Home page - render logger states and cruise information. """ global api if api is None: api = DjangoServerAPI() ############################ # If we've gotten a POST request # cruise_id = '' errors = [] if request.method == 'POST': logging.debug('POST: %s', request.POST) # First things first: log the request log_request(request, 'index') # Are they deleting a cruise?(!) if 'delete_cruise' in request.POST: logging.info('deleting cruise') api.delete_cruise() # Did we get a mode selection? elif 'select_mode' in request.POST: new_mode_name = request.POST['select_mode'] logging.info('switching to mode "%s"', new_mode_name) try: api.set_active_mode(new_mode_name) except ValueError as e: logging.warning('Error trying to set mode to "%s": %s', new_mode_name, str(e)) elif 'reload_button' in request.POST: logging.info('reloading current configuration file') try: cruise = api.get_configuration() filename = cruise['config_filename'] # Load the file to memory and parse to a dict. Add the name # of the file we've just loaded to the dict. config = read_config(filename) if 'cruise' in config: config['cruise']['config_filename'] = filename api.load_configuration(config) except ValueError as e: logging.warning('Error reloading current configuration: %s', str(e)) # If they canceled the upload elif 'cancel' in request.POST: logging.warning('User canceled upload') # Else unknown post else: logging.warning('Unknown POST request: %s', request.POST) # Assemble information to draw page template_vars = { 'websocket_server': WEBSOCKET_DATA_SERVER, 'errors': { 'django': errors }, } try: configuration = api.get_configuration() template_vars['cruise_id'] = configuration.get('id', 'Cruise') template_vars['filename'] = configuration.get('config_filename', '-none-') template_vars['loggers'] = api.get_loggers() template_vars['modes'] = api.get_modes() template_vars['active_mode'] = api.get_active_mode() template_vars['errors'] = errors except (ValueError, AttributeError): logging.info('No configuration loaded') return render(request, 'django_gui/index.html', template_vars)
action='count', help='Increase output verbosity of component loggers') args = parser.parse_args() # Set up logging first of all LOG_LEVELS = {0: logging.WARNING, 1: logging.INFO, 2: logging.DEBUG} log_level = LOG_LEVELS[min(args.verbosity, max(LOG_LEVELS))] if args.stderr_file: stderr_writers = [TextFileWriter(args.stderr_file)] logging.getLogger().addHandler(StdErrLoggingHandler(stderr_writers)) # What level do we want our component loggers to write? logger_log_level = LOG_LEVELS[min(args.logger_verbosity, max(LOG_LEVELS))] configs = read_config(args.config) if args.config else None # If they've specified a mode, see if what we've read in is in fact # a cruise definition with modes we can choose from. if args.mode: modes = configs.get('modes', None) if not modes: logging.fatal('--mode specified, but "%s" has no modes' % args.config) sys.exit(1) logger_configs = configs.get('configs', None) if not logger_configs: logging.fatal('File "%s" has no logger configs?' % args.config) sys.exit(1) # What are the names of the logger configs for the requested mode?