Example #1
0
    def _setup(self, name=None):
        """
    Load the config json file pointed to by the environment variable. This is
    used the first time settings are needed, if the user hasn't configured
    settings manually.

    Arguments
    ---------
    name : :class:`str`, optional
        The name used to describe the settings object. Defaults to ``settings``

    Raises
    ------
    ImproperlyConfigured
        If the settings has already been configured, will throw an error. Under
        normal circumstances, :func:`_setup` will not be called a second time.
    """
        settings_file = os.environ.get(ENVIRONMENT_VARIABLE)
        if not settings_file:
            desc = ("setting %s" % name) if name else "settings"
            raise ImproperlyConfigured(
                "Requested %s, but settings are not configured. "
                "You must either define the environment variable %s "
                "or call settings.configure() before accessing settings." %
                (desc, ENVIRONMENT_VARIABLE))
        with open(settings_file) as fid:
            self.configure(json.load(fid))
        self._wrapped.config_file = os.environ.get(ENVIRONMENT_VARIABLE)
Example #2
0
 def default(self, obj):
     if isinstance(obj, LazySettings):
         if obj._wrapped is None:
             raise ImproperlyConfigured('Settings not initialized')
         return TerraJSONEncoder.serializableSettings(obj._wrapped)
     # elif isinstance(obj, datetime):
     #   return str(obj)
     return JSONEncoder.default(self, obj)  # pragma: no cover
Example #3
0
    def configure(self, *args, **kwargs):
        """
    Called to manually configure the settings. The 'default_settings'
    parameter sets where to retrieve any unspecified values from (its
    argument should be a :class:`dict`).

    Arguments
    ---------
    *args :
        Passed along to :class:`Settings`
    **kwargs :
        Passed along to :class:`Settings`

    Raises
    ------
    ImproperlyConfigured
        If settings is already configured, will throw this exception
    """
        if self._wrapped is not None:
            raise ImproperlyConfigured('Settings already configured.')
        logger.debug2('Pre settings configure')
        self._wrapped = Settings(*args, **kwargs)

        for pattern, settings in global_templates:
            if nested_in_dict(pattern, self._wrapped):
                # Not the most efficient way to do this, but insignificant "preupdate"
                d = {}
                nested_update(d, settings)
                nested_update(d, self._wrapped)
                # Nested update and run patch code
                self._wrapped.update(d)

        def read_json(json_file):
            # In case json_file is an @settings_property function
            if getattr(json_file, 'settings_property', None):
                json_file = json_file(settings)

            return Settings(json_load(json_file))

        nested_patch_inplace(
            self._wrapped, lambda key, value:
            (isinstance(key, str) and (isinstance(value, str) or getattr(
                value, 'settings_property', False)) and
             any(key.endswith(pattern) for pattern in json_include_suffixes)),
            lambda key, value: read_json(value))

        # Importing these here is intentional, it guarantees the signals are
        # connected so that executor and computes can setup logging if need be
        import terra.executor  # noqa
        import terra.compute  # noqa

        from terra.core.signals import post_settings_configured
        post_settings_configured.send(sender=self)
        logger.debug2('Post settings configure')
Example #4
0
  def configure_logger(self, sender, **kwargs):
    '''
    Call back function to configure the logger after settings have been
    configured
    '''

    from terra import settings

    if self._configured:
      self.root_logger.error("Configure logger called twice, this is "
                             "unexpected")
      raise ImproperlyConfigured()

    formatter = logging.Formatter(fmt=settings.logging.format,
                                  datefmt=settings.logging.date_format,
                                  style=settings.logging.style)

    # Setup log file for use in configure
    self.log_file = os.path.join(settings.processing_dir,
                                 self.default_log_prefix)
    os.makedirs(settings.processing_dir, exist_ok=True)
    self.log_file = open(self.log_file, 'a')

    self.file_handler = logging.StreamHandler(stream=self.log_file)

    # Configure log level
    level = settings.logging.level
    if isinstance(level, str):
      # make level case insensitive
      level = level.upper()
    self.stderr_handler.setLevel(level)
    self.file_handler.setLevel(level)

    # Configure format
    self.file_handler.setFormatter(formatter)
    self.stderr_handler.setFormatter(formatter)

    # Swap some handlers
    self.root_logger.addHandler(self.file_handler)
    self.root_logger.removeHandler(self.preconfig_stderr_handler)
    self.root_logger.removeHandler(self.preconfig_file_handler)
    self.root_logger.removeHandler(self.tmp_handler)

    # Log the settings only to the file handler
    with HandlerLoggingContext(self.root_logger, [self.file_handler]):
      self.root_logger.log(DEBUG1,
                           "Settings:\n" + pprint.pformat(dict(settings)),
                           extra=extra_logger_variables)
      # For some reason python doesn't make the root logger the designated
      # class, so much add extra manually here. Not even sure why I chose
      # root_logger here...

    # filter the stderr buffer
    self.preconfig_stderr_handler.buffer = \
        [x for x in self.preconfig_stderr_handler.buffer
         if (x.levelno >= self.stderr_handler.level)]
    # Use this if statement if you want to prevent repeating any critical/error
    # level messages. This is probably not necessary because error/critical
    # messages before configure should be rare, and are probably worth
    # repeating. Repeating is the only way to get them formatted right the
    # second time anyways. This applys to stderr only, not the log file
    #                        if (x.levelno >= level)] and
    #                           (x.levelno < default_stderr_handler_level)]

    # Filter file buffer. Never remove default_stderr_handler_level message,
    # they won't be in the new output file
    self.preconfig_file_handler.buffer = \
        [x for x in self.preconfig_file_handler.buffer
         if (x.levelno >= self.file_handler.level)]

    # Flush the buffers
    self.preconfig_stderr_handler.setTarget(self.stderr_handler)
    self.preconfig_stderr_handler.flush()
    self.preconfig_stderr_handler = None
    self.preconfig_file_handler.setTarget(self.file_handler)
    self.preconfig_file_handler.flush()
    self.preconfig_file_handler = None
    self.tmp_handler = None

    # Remove the temporary file now that you are done with it
    self.tmp_file.close()
    os.unlink(self.tmp_file.name)
    self.tmp_file = None

    self._configured = True
Example #5
0
    def configure_logger(self, sender=None, signal=None, **kwargs):
        '''
    Call back function to configure the logger after settings have been
    configured
    '''

        from terra import settings
        from terra.core.settings import TerraJSONEncoder

        if self._configured:
            self.root_logger.error("Configure logger called twice, this is "
                                   "unexpected")
            raise ImproperlyConfigured()

        # This sends a signal to the current Executor type, which has already been
        # imported at the end of LazySettings.configure. We don't import Executor
        # here to reduce the concerns of this module
        import terra.core.signals
        terra.core.signals.logger_configure.send(sender=self, **kwargs)
        self.set_level_and_formatter()

        # Now that the real logger has been set up, swap some handlers
        self.root_logger.removeHandler(self.preconfig_stderr_handler)
        self.root_logger.removeHandler(self.preconfig_main_log_handler)
        self.root_logger.removeHandler(self.tmp_handler)

        if os.environ.get('TERRA_DISABLE_SETTINGS_DUMP') != '1':
            os.makedirs(settings.settings_dir, exist_ok=True)
            settings_dump = os.path.join(
                settings.settings_dir,
                datetime.now(timezone.utc).strftime(
                    f'settings_{settings.terra.uuid}_%Y_%m_%d_%H_%M_%S_%f.json'
                ))
            with open(settings_dump, 'w') as fid:
                fid.write(TerraJSONEncoder.dumps(settings, indent=2))

        # filter the stderr buffer
        self.preconfig_stderr_handler.buffer = \
            [x for x in self.preconfig_stderr_handler.buffer
             if (x.levelno >= self.stderr_handler.level)]
        # Use this if statement if you want to prevent repeating any critical/error
        # level messages. This is probably not necessary because error/critical
        # messages before configure should be rare, and are probably worth
        # repeating. Repeating is the only way to get them formatted right the
        # second time anyways. This applies to stderr only, not the log file
        #                        if (x.levelno >= level)] and
        #                           (x.levelno < default_stderr_handler_level)]

        # Filter file buffer. Never remove default_stderr_handler_level message,
        # they won't be in the new output file
        self.preconfig_main_log_handler.buffer = \
            [x for x in self.preconfig_main_log_handler.buffer
             if (x.levelno >= self.main_log_handler.level)]

        # Flush the buffers
        self.preconfig_stderr_handler.setTarget(self.stderr_handler)
        self.preconfig_stderr_handler.flush()
        self.preconfig_stderr_handler = None
        self.preconfig_main_log_handler.setTarget(self.main_log_handler)
        self.preconfig_main_log_handler.flush()
        self.preconfig_main_log_handler = None
        self.tmp_handler = None

        # Remove the temporary file now that you are done with it
        self.tmp_file.close()
        if os.path.exists(
                self.tmp_file.name) and self.tmp_file.name != os.devnull:
            os.unlink(self.tmp_file.name)
        self.tmp_file = None

        self._configured = True