Assigned filtering IDs to logger messages

Any ID has common scheme 'log-level.module.description', so it contains
three period-separated groups with possible dashes inside each group.

List of all IDs can be obtained by the following command (in an Unix
environment):

```
$ grep -R "'id': '" pelican | sed -e "s/.*'id': '\([^']\+\)'.*/\1/" | sort -u
```

Fixes #1594.
This commit is contained in:
Alexander Turenko 2016-08-31 10:44:31 +03:00
commit b3a5d87a9e
11 changed files with 196 additions and 97 deletions

View file

@ -107,7 +107,7 @@ Setting name (followed by default value, if any)
and the message to be ignored.
For example: ``[(logging.WARN, 'TAG_SAVE_AS is set to False')]``
``LOG_FILTER_IDS = []`` A list of containing IDs of messages to be ignored.
For example: ``['warn.img.alt.empty']``
For example: ``['warn.readers.empty-alt-attribute']``
``READERS = {}`` A dictionary of file extensions / Reader classes for Pelican to
process or ignore. For example, to avoid processing .html files,
set: ``READERS = {'html': None}``. To add a custom reader for the
@ -780,7 +780,7 @@ It's hard to ignore a group of messages containing dynamic substrings (e.g.
paths to files). Such messages can be ignored using the ``LOG_FILTER_IDS``
setting.
For example: ``['warn.img.alt.empty']``
For example: ``['warn.readers.empty-alt-attribute']``
.. _reading_only_modified_content:

View file

@ -55,7 +55,8 @@ class Pelican(object):
def init_path(self):
if not any(p in sys.path for p in ['', os.curdir]):
logger.debug("Adding current directory to system path")
logger.debug("Adding current directory to system path",
extra={'id': 'debug.init.adding-cwd-to-system-path'})
sys.path.insert(0, '')
def init_plugins(self):
@ -67,7 +68,8 @@ class Pelican(object):
for plugin in self.settings['PLUGINS']:
# if it's a string, then import it
if isinstance(plugin, six.string_types):
logger.debug("Loading plugin `%s`", plugin)
logger.debug("Loading plugin `%s`", plugin,
extra={'id': 'debug.init.loading-plugin'})
try:
plugin = __import__(plugin, globals(), locals(),
str('module'))
@ -76,10 +78,12 @@ class Pelican(object):
"Cannot load plugin `%s`\n%s", plugin, e)
continue
logger.debug("Registering plugin `%s`", plugin.__name__)
logger.debug("Registering plugin `%s`", plugin.__name__,
extra={'id': 'debug.init.registering-plugin'})
plugin.register()
self.plugins.append(plugin)
logger.debug('Restoring system path')
logger.debug('Restoring system path',
extra={'id': 'debug.init.restoring-system-path'})
sys.path = _sys_path
def _handle_deprecation(self):
@ -87,7 +91,8 @@ class Pelican(object):
if self.settings.get('CLEAN_URLS', False):
logger.warning('Found deprecated `CLEAN_URLS` in settings.'
' Modifying the following settings for the'
' same behaviour.')
' same behaviour.',
extra={'id': 'warn.init.clean-urls-deprected'})
self.settings['ARTICLE_URL'] = '{slug}/'
self.settings['ARTICLE_LANG_URL'] = '{slug}-{lang}/'
@ -96,17 +101,21 @@ class Pelican(object):
for setting in ('ARTICLE_URL', 'ARTICLE_LANG_URL', 'PAGE_URL',
'PAGE_LANG_URL'):
logger.warning("%s = '%s'", setting, self.settings[setting])
logger.warning("%s = '%s'", setting, self.settings[setting],
extra={'id': 'warn.init.clean-urls-deprected'})
if self.settings.get('AUTORELOAD_IGNORE_CACHE'):
logger.warning('Found deprecated `AUTORELOAD_IGNORE_CACHE` in '
'settings. Use --ignore-cache instead.')
'settings. Use --ignore-cache instead.',
extra={'id': 'warn.init.autoreload-ignore-cache'})
self.settings.pop('AUTORELOAD_IGNORE_CACHE')
if self.settings.get('ARTICLE_PERMALINK_STRUCTURE', False):
logger.warning('Found deprecated `ARTICLE_PERMALINK_STRUCTURE` in'
' settings. Modifying the following settings for'
' the same behaviour.')
logger.warning(
'Found deprecated `ARTICLE_PERMALINK_STRUCTURE` in'
' settings. Modifying the following settings for'
' the same behaviour.',
extra={'id': 'warn.init.article-permalink-structure'})
structure = self.settings['ARTICLE_PERMALINK_STRUCTURE']
@ -126,7 +135,9 @@ class Pelican(object):
'PAGE_SAVE_AS', 'PAGE_LANG_SAVE_AS'):
self.settings[setting] = os.path.join(structure,
self.settings[setting])
logger.warning("%s = '%s'", setting, self.settings[setting])
logger.warning(
"%s = '%s'", setting, self.settings[setting],
extra={'id': 'warn.init.article-permalink-structure'})
for new, old in [('FEED', 'FEED_ATOM'), ('TAG_FEED', 'TAG_FEED_ATOM'),
('CATEGORY_FEED', 'CATEGORY_FEED_ATOM'),
@ -137,7 +148,8 @@ class Pelican(object):
'to %(old)s in your settings and theme for the same '
'behavior. Temporarily setting %(old)s for backwards '
'compatibility.',
{'new': new, 'old': old}
{'new': new, 'old': old},
extra={'id': 'warn.init.feed-setting-deprecated'}
)
self.settings[old] = self.settings[new]
@ -229,7 +241,8 @@ class Pelican(object):
for v in value:
if isinstance(v, type):
logger.debug('Found generator: %s', v)
logger.debug('Found generator: %s', v,
extra={'id': 'debug.init.found-generator'})
generators.append(v)
# StaticGenerator must run last, so it can identify files that
@ -247,11 +260,13 @@ class Pelican(object):
else:
writer = writers[0]
if writers_found == 1:
logger.debug('Found writer: %s', writer)
logger.debug('Found writer: %s', writer,
extra={'id': 'debug.init.found-writer'})
else:
logger.warning(
'%s writers found, using only first one: %s',
writers_found, writer)
writers_found, writer,
extra={'id': 'debug.init.many-writers-found'})
return writer(self.output_path, settings=self.settings)
@ -385,8 +400,10 @@ def main():
args = parse_arguments()
init(args.verbosity, args.fatal)
logger.debug('Pelican version: %s', __version__)
logger.debug('Python version: %s', sys.version.split()[0])
logger.debug('Pelican version: %s', __version__,
extra={'id': 'debug.init.pelican-version'})
logger.debug('Python version: %s', sys.version.split()[0],
extra={'id': 'debug.init.python-version'})
try:
pelican, settings = get_instance(args)
@ -455,33 +472,42 @@ def main():
', '.join(k for k, v in modified.items() if v)))
if modified['content'] is None:
logger.warning('No valid files found in content.')
logger.warning(
'No valid files found in content.',
extra={'id': 'warn.init.no-valid-content'})
if modified['theme'] is None:
logger.warning('Empty theme folder. Using `basic` '
'theme.')
logger.warning(
'Empty theme folder. Using `basic` theme.',
extra={'id': 'warn.init.empty-theme-folder'})
pelican.run()
except KeyboardInterrupt:
logger.warning("Keyboard interrupt, quitting.")
logger.warning(
"Keyboard interrupt, quitting.",
extra={'id': 'warn.init.keyboard-interrupt'})
break
except Exception as e:
if (args.verbosity == logging.DEBUG):
raise
logger.warning(
'Caught exception "%s". Reloading.', e)
'Caught exception "%s". Reloading.', e,
extra={'id': 'warn.init.caught-exception'})
finally:
time.sleep(.5) # sleep to avoid cpu load
else:
if next(watchers['content']) is None:
logger.warning('No valid files found in content.')
logger.warning(
'No valid files found in content.',
extra={'id': 'warn.init.no-valid-content-files'})
if next(watchers['theme']) is None:
logger.warning('Empty theme folder. Using `basic` theme.')
logger.warning('Empty theme folder. Using `basic` theme.',
extra={'id': 'warn.init.empty-theme-folder'})
pelican.run()

View file

@ -38,14 +38,16 @@ class FileDataCacher(object):
except (IOError, OSError) as err:
logger.debug('Cannot load cache %s (this is normal on first '
'run). Proceeding with empty cache.\n%s',
self._cache_path, err)
self._cache_path, err,
extra={'id': 'debug.cache.load'})
self._cache = {}
except pickle.PickleError as err:
logger.warning('Cannot unpickle cache %s, cache may be using '
'an incompatible protocol (see pelican '
'caching docs). '
'Proceeding with empty cache.\n%s',
self._cache_path, err)
self._cache_path, err,
extra={'id': 'warn.cache.unpickle'})
self._cache = {}
else:
self._cache = {}
@ -71,7 +73,8 @@ class FileDataCacher(object):
pickle.dump(self._cache, fhandle)
except (IOError, OSError, pickle.PicklingError) as err:
logger.warning('Could not save cache %s\n ... %s',
self._cache_path, err)
self._cache_path, err,
extra={'id': 'warn.cache.save'})
class FileStampDataCacher(FileDataCacher):
@ -100,7 +103,8 @@ class FileStampDataCacher(FileDataCacher):
self._filestamp_func = filestamp_func
except AttributeError as err:
logger.warning('Could not get hashing function\n\t%s', err)
logger.warning('Could not get hashing function\n\t%s', err,
extra={'id': 'warn.cache.hash'})
self._filestamp_func = None
def cache_data(self, filename, data):
@ -122,7 +126,8 @@ class FileStampDataCacher(FileDataCacher):
return self._filestamp_func(filename)
except (IOError, OSError, TypeError) as err:
logger.warning('Cannot get modification stamp for %s\n\t%s',
filename, err)
filename, err,
extra={'id': 'warn.cache.get-timestamp'})
return ''
def get_cached_data(self, filename, default=None):

View file

@ -241,7 +241,8 @@ class Content(object):
logger.warning(
"%s used {attach} link syntax on a "
"non-static file. Use {filename} instead.",
self.get_relative_source_path())
self.get_relative_source_path(), extra={
'id': 'warn.contents.non-static-attach'})
origin = '/'.join((siteurl, linked_content.url))
origin = origin.replace('\\', '/') # for Windows paths.
else:
@ -249,7 +250,8 @@ class Content(object):
"Unable to find `%s`, skipping url replacement.",
value.geturl(), extra={
'limit_msg': ("Other resources were not found "
"and their urls not replaced")})
"and their urls not replaced"),
'id': 'warn.contents.unable-to-find-url'})
elif what == 'category':
origin = '/'.join((siteurl, Category(path, self.settings).url))
elif what == 'tag':
@ -262,7 +264,8 @@ class Content(object):
logger.warning(
"Replacement Indicator '%s' not recognized, "
"skipping replacement",
what)
what, extra={
'id': 'warn.contents.unknown-replacement-indicator'})
# keep all other parts, such as query, fragment, etc.
parts = list(value)
@ -313,7 +316,8 @@ class Content(object):
"""deprecated function to access summary"""
logger.warning('_get_summary() has been deprecated since 3.6.4. '
'Use the summary decorator instead')
'Use the summary decorator instead',
extra={'id': 'warn.contents.get-summary-deprecated'})
return self.summary
@summary.setter
@ -447,7 +451,8 @@ class Static(Page):
"{filename} link behavior instead.",
content.get_relative_source_path(),
self.get_relative_source_path(), reason,
extra={'limit_msg': "More {attach} warnings silenced."})
extra={'limit_msg': "More {attach} warnings silenced.",
'id': 'warn.contents.link-relocation-failed'})
# We never override an override, because we don't want to interfere
# with user-defined overrides that might be in EXTRA_PATH_METADATA.

View file

@ -71,7 +71,8 @@ class Generator(object):
extensions=self.settings['JINJA_EXTENSIONS'],
)
logger.debug('Template list: %s', self.env.list_templates())
logger.debug('Template list: %s', self.env.list_templates(),
extra={'id': 'debug.generators.template-list'})
# provide utils.strftime as a jinja filter
self.env.filters.update({'strftime': DateFormatter()})
@ -728,7 +729,8 @@ class StaticGenerator(Generator):
save_as = os.path.join(self.output_path, sc.save_as)
mkdir_p(os.path.dirname(save_as))
shutil.copy2(source_path, save_as)
logger.info('Copying %s to %s', sc.source_path, sc.save_as)
logger.info('Copying %s to %s', sc.source_path, sc.save_as,
extra={'id': 'info.generators.copying'})
class SourceFileGenerator(Generator):
@ -743,7 +745,8 @@ class SourceFileGenerator(Generator):
copy(obj.source_path, dest)
def generate_output(self, writer=None):
logger.info('Generating source files...')
logger.info('Generating source files...',
extra={'id': 'info.generators.generating-source-files'})
for obj in chain(self.context['articles'], self.context['pages']):
self._create_source(obj)
for obj_trans in obj.translations:

View file

@ -269,7 +269,8 @@ class MarkdownReader(BaseReader):
logger.warning(
'Duplicate definition of `%s` '
'for %s. Using first one.',
name, self._source_path)
name, self._source_path,
extra={'id': 'warn.readers.duplicate-metadata-def'})
output[name] = self.process_metadata(name, value[0])
elif len(value) > 1:
# handle list metadata as list of string
@ -389,9 +390,11 @@ class HTMLReader(BaseReader):
if name is None:
attr_list = ['{}="{}"'.format(k, v) for k, v in attrs]
attr_serialized = ', '.join(attr_list)
logger.warning("Meta tag in file %s does not have a 'name' "
"attribute, skipping. Attributes: %s",
self._filename, attr_serialized)
logger.warning(
"Meta tag in file %s does not have a 'name' "
"attribute, skipping. Attributes: %s",
self._filename, attr_serialized,
extra={'id': 'warn.readers.unknown-meta-tag-attribute'})
return
name = name.lower()
contents = self._attr_value(attrs, 'content', '')
@ -404,7 +407,8 @@ class HTMLReader(BaseReader):
self._filename,
extra={'limit_msg': "Other files have meta tag "
"attribute 'contents' that should "
"be changed to 'content'"})
"be changed to 'content'",
'id': 'warn.readers.contents-meta-tag-used'})
if name == 'keywords':
name = 'tags'
@ -444,8 +448,10 @@ class Readers(FileStampDataCacher):
for cls in [BaseReader] + BaseReader.__subclasses__():
if not cls.enabled:
logger.debug('Missing dependencies for %s',
', '.join(cls.file_extensions))
logger.debug(
'Missing dependencies for %s',
', '.join(cls.file_extensions),
extra={'id': 'debug.readers.missing-dependencies'})
continue
for ext in cls.file_extensions:
@ -484,7 +490,8 @@ class Readers(FileStampDataCacher):
source_path = posixize_path(os.path.relpath(path, base_path))
logger.debug(
'Read file %s -> %s',
source_path, content_class.__name__)
source_path, content_class.__name__,
extra={'id': 'debug.readers.read-file'})
if not fmt:
_, ext = os.path.splitext(os.path.basename(path))
@ -497,7 +504,8 @@ class Readers(FileStampDataCacher):
if preread_signal:
logger.debug(
'Signal %s.send(%s)',
preread_signal.name, preread_sender)
preread_signal.name, preread_sender,
extra={'id': 'debug.readers.signal-send'})
preread_signal.send(preread_sender)
reader = self.readers[fmt]
@ -556,7 +564,8 @@ class Readers(FileStampDataCacher):
logger.debug(
'Signal %s.send(%s, <metadata>)',
context_signal.name,
context_sender)
context_sender,
extra={'id': 'debug.readers.signal-send-metadata'})
context_signal.send(context_sender, metadata=metadata)
return content_class(content=content, metadata=metadata,
@ -593,7 +602,7 @@ def find_empty_alt(content, path):
'Empty alt attribute for image %s in %s',
os.path.basename(match[1] + match[5]), path,
extra={'limit_msg': 'Other images have empty alt attributes',
'id': 'warn.img.alt.empty'})
'id': 'warn.readers.empty-alt-attribute'})
def default_metadata(settings=None, process=None):

View file

@ -156,13 +156,17 @@ def read_settings(path=None, override=None):
local_settings[p] = absp
if 'PLUGIN_PATH' in local_settings:
logger.warning('PLUGIN_PATH setting has been replaced by '
'PLUGIN_PATHS, moving it to the new setting name.')
logger.warning(
'PLUGIN_PATH setting has been replaced by '
'PLUGIN_PATHS, moving it to the new setting name.',
extra={'id': 'warn.settings.plugin-path-deprecated'})
local_settings['PLUGIN_PATHS'] = local_settings['PLUGIN_PATH']
del local_settings['PLUGIN_PATH']
if isinstance(local_settings['PLUGIN_PATHS'], six.string_types):
logger.warning("Defining PLUGIN_PATHS setting as string "
"has been deprecated (should be a list)")
logger.warning(
"Defining PLUGIN_PATHS setting as string "
"has been deprecated (should be a list)",
extra={'id': 'warn.settings.plugin-paths-is-a-string'})
local_settings['PLUGIN_PATHS'] = [local_settings['PLUGIN_PATHS']]
elif local_settings['PLUGIN_PATHS'] is not None:
def getabs(path, pluginpath):
@ -267,7 +271,8 @@ def configure_settings(settings):
logger.warn(
'Detected misconfigured %s (%s), '
'falling back to the default (%s)',
key, value, DEFAULT_CONFIG[key])
key, value, DEFAULT_CONFIG[key],
extra={'id': 'warn.settings.misconfigured-setting'})
# try to set the different locales, fallback on the default.
locales = settings.get('LOCALE', DEFAULT_CONFIG['LOCALE'])
@ -279,14 +284,17 @@ def configure_settings(settings):
except locale.Error:
pass
else:
logger.warning("LOCALE option doesn't contain a correct value")
logger.warning("LOCALE option doesn't contain a correct value",
extra={'id': 'warn.settings.incorrect-locale'})
if ('SITEURL' in settings):
# If SITEURL has a trailing slash, remove it and provide a warning
siteurl = settings['SITEURL']
if (siteurl.endswith('/')):
settings['SITEURL'] = siteurl[:-1]
logger.warning("Removed extraneous trailing slash from SITEURL.")
logger.warning(
"Removed extraneous trailing slash from SITEURL.",
extra={'id': 'warn.settings.siteurl-trailing-slash'})
# If SITEURL is defined but FEED_DOMAIN isn't,
# set FEED_DOMAIN to SITEURL
if 'FEED_DOMAIN' not in settings:
@ -298,7 +306,8 @@ def configure_settings(settings):
settings.get('WITH_FUTURE_DATES', False):
logger.warning(
"WITH_FUTURE_DATES conflicts with CONTENT_CACHING_LAYER "
"set to 'generator', use 'reader' layer instead")
"set to 'generator', use 'reader' layer instead",
extra={'id': 'warn.settings.conflicting-cache-setting'})
# Warn if feeds are generated with both SITEURL & FEED_DOMAIN undefined
feed_keys = [
@ -313,14 +322,16 @@ def configure_settings(settings):
if any(settings.get(k) for k in feed_keys):
if not settings.get('SITEURL'):
logger.warning('Feeds generated without SITEURL set properly may'
' not be valid')
' not be valid',
extra={'id': 'warn.settings.not-set-siteurl'})
if 'TIMEZONE' not in settings:
logger.warning(
'No timezone information specified in the settings. Assuming'
' your timezone is UTC for feed generation. Check '
'http://docs.getpelican.com/en/latest/settings.html#timezone '
'for more information')
'for more information',
extra={'id': 'warn.settings.no-timezone'})
# fix up pagination rules
from pelican.paginator import PaginationRule
@ -342,7 +353,8 @@ def configure_settings(settings):
if old_key in settings:
logger.warning(
'Deprecated setting %s, moving it to %s list',
old_key, new_key)
old_key, new_key,
extra={'id': 'warn.settings.dir-paths-setting-deprecated'})
settings[new_key] = [settings[old_key]] # also make a list
del settings[old_key]
@ -367,15 +379,18 @@ def configure_settings(settings):
if isinstance(settings[PATH_KEY], six.string_types):
logger.warning("Detected misconfiguration with %s setting "
"(must be a list), falling back to the default",
PATH_KEY)
PATH_KEY,
extra={'id': 'warn.settings.setting-must-be-list'})
settings[PATH_KEY] = DEFAULT_CONFIG[PATH_KEY]
# Save people from declaring MD_EXTENSIONS as a list rather than a dict
if not isinstance(settings.get('MD_EXTENSIONS', {}), dict):
logger.warning('The format of the MD_EXTENSIONS setting has '
'changed. It should now be a dict mapping '
'fully-qualified extension names to their '
'configurations. Falling back to the default.')
logger.warning(
'The format of the MD_EXTENSIONS setting has '
'changed. It should now be a dict mapping '
'fully-qualified extension names to their '
'configurations. Falling back to the default.',
extra={'id': 'warn.settings.bad-format-of-md-extensions'})
settings['MD_EXTENSIONS'] = DEFAULT_CONFIG['MD_EXTENSIONS']
# Add {PAGE,ARTICLE}_PATHS to {ARTICLE,PAGE}_EXCLUDES
@ -401,6 +416,7 @@ def configure_settings(settings):
old, new)
if doc:
message += ', see {} for details'.format(doc)
logger.warning(message)
logger.warning(message, extra={
'id': 'warn.settings.setting-was-removed'})
return settings

View file

@ -152,7 +152,9 @@ def wp2fields(xml, wp_custpost=False):
title = unescape(item.title.contents[0])
except IndexError:
title = 'No title [%s]' % item.find('post_name').string
logger.warning('Post "%s" is lacking a proper title', title)
logger.warning(
'Post "%s" is lacking a proper title', title,
extra={'id': 'warn.pelican-import.post-no-proper-title'})
filename = item.find('post_name').string
post_id = item.find('post_id').string
@ -671,7 +673,9 @@ def download_attachments(output_path, urls):
locations.append(os.path.join(localpath, filename))
except (URLError, IOError) as e:
# Python 2.7 throws an IOError rather Than URLError
logger.warning("No file could be downloaded from %s\n%s", url, e)
logger.warning(
"No file could be downloaded from %s\n%s", url, e,
extra={'id': 'warn.pelican-import.no-attachments-downloaded'})
return locations

View file

@ -97,7 +97,8 @@ class URLWrapper(object):
setting = "%s_%s" % (self.__class__.__name__.upper(), key)
value = self.settings[setting]
if not isinstance(value, six.string_types):
logger.warning('%s is set to %s', setting, value)
logger.warning('%s is set to %s', setting, value, extra={
'id': 'warn.urlwrappers.setting-is-not-a-string'})
return value
else:
if get_page_name:

View file

@ -206,9 +206,11 @@ def deprecated_attribute(old, new, since=None, remove=None, doc=None):
message.append(
' and will be removed by version {}'.format(version))
message.append('. Use {} instead.'.format(new))
logger.warning(''.join(message))
logger.warning(''.join(message), extra={
'id': 'warn.utils.attribute-deprecated'})
logger.debug(''.join(six.text_type(x) for x
in traceback.format_stack()))
in traceback.format_stack()),
extra={'id': 'debug.utils.attribute-deprecated'})
def fget(self):
_warn()
@ -318,7 +320,8 @@ def copy(source, destination, ignores=None):
def walk_error(err):
logger.warning("While copying %s: %s: %s",
source_, err.filename, err.strerror)
source_, err.filename, err.strerror,
extra={'id': 'warn.utils.copy-walk-error'})
source_ = os.path.abspath(os.path.expanduser(source))
destination_ = os.path.abspath(os.path.expanduser(destination))
@ -328,24 +331,29 @@ def copy(source, destination, ignores=None):
if any(fnmatch.fnmatch(os.path.basename(source), ignore)
for ignore in ignores):
logger.info('Not copying %s due to ignores', source_)
logger.info('Not copying %s due to ignores', source_,
extra={'id': 'info.utils.not-copying-ignore'})
return
if os.path.isfile(source_):
dst_dir = os.path.dirname(destination_)
if not os.path.exists(dst_dir):
logger.info('Creating directory %s', dst_dir)
logger.info('Creating directory %s', dst_dir,
extra={'id': 'info.utils.creating-directory'})
os.makedirs(dst_dir)
logger.info('Copying %s to %s', source_, destination_)
logger.info('Copying %s to %s', source_, destination_,
extra={'id': 'info.utils.copying'})
shutil.copy2(source_, destination_)
elif os.path.isdir(source_):
if not os.path.exists(destination_):
logger.info('Creating directory %s', destination_)
logger.info('Creating directory %s', destination_,
extra={'id': 'info.utils.creating-directory'})
os.makedirs(destination_)
if not os.path.isdir(destination_):
logger.warning('Cannot copy %s (a directory) to %s (a file)',
source_, destination_)
source_, destination_,
extra={'id': 'warn.utils.cannot-copy-dir-to-file'})
return
for src_dir, subdirs, others in os.walk(source_):
@ -358,7 +366,8 @@ def copy(source, destination, ignores=None):
for i in ignores))
if not os.path.isdir(dst_dir):
logger.info('Creating directory %s', dst_dir)
logger.info('Creating directory %s', dst_dir,
extra={'id': 'warn.utils.creating-directory'})
# Parent directories are known to exist, so 'mkdir' suffices.
os.mkdir(dst_dir)
@ -366,19 +375,22 @@ def copy(source, destination, ignores=None):
src_path = os.path.join(src_dir, o)
dst_path = os.path.join(dst_dir, o)
if os.path.isfile(src_path):
logger.info('Copying %s to %s', src_path, dst_path)
logger.info('Copying %s to %s', src_path, dst_path,
extra={'id': 'info.utils.copying'})
shutil.copy2(src_path, dst_path)
else:
logger.warning('Skipped copy %s (not a file or '
'directory) to %s',
src_path, dst_path)
src_path, dst_path,
extra={'id': 'warn.utils.skipped-copy'})
def clean_output_dir(path, retention):
"""Remove all files from output directory except those in retention list"""
if not os.path.exists(path):
logger.debug("Directory already removed: %s", path)
logger.debug("Directory already removed: %s", path,
extra={'id': 'warn.utils.directory-already-removed'})
return
if not os.path.isdir(path):
@ -393,18 +405,21 @@ def clean_output_dir(path, retention):
file = os.path.join(path, filename)
if any(filename == retain for retain in retention):
logger.debug("Skipping deletion; %s is on retention list: %s",
filename, file)
filename, file,
extra={'id': 'debug.utils.skipping-deletion'})
elif os.path.isdir(file):
try:
shutil.rmtree(file)
logger.debug("Deleted directory %s", file)
logger.debug("Deleted directory %s", file,
extra={'id': 'debug.utils.deleted-directory'})
except Exception as e:
logger.error("Unable to delete directory %s; %s",
file, e)
elif os.path.isfile(file) or os.path.islink(file):
try:
os.remove(file)
logger.debug("Deleted file/link %s", file)
logger.debug("Deleted file/link %s", file,
extra={'id': 'debug.utils.deleted-file'})
except Exception as e:
logger.error("Unable to delete file %s; %s", file, e)
else:
@ -629,10 +644,14 @@ def process_translations(content_list, order_by=None):
lang_items = list(lang_items)
len_ = len(lang_items)
if len_ > 1:
logger.warning('There are %s variants of "%s" with lang %s',
len_, slug, lang)
logger.warning(
'There are %s variants of "%s" with lang %s',
len_, slug, lang,
extra={'id': 'warn.utils.many-translation-variants'})
for x in lang_items:
logger.warning('\t%s', x.source_path)
logger.warning(
'\t%s', x.source_path,
extra={'id': 'warn.utils.many-translation-variants'})
# find items with default language
default_lang_items = list(filter(
@ -647,7 +666,8 @@ def process_translations(content_list, order_by=None):
logger.warning(
'Empty slug for %s. You can fix this by '
'adding a title or a slug to your content',
default_lang_items[0].source_path)
default_lang_items[0].source_path,
extra={'id': 'warn.utils.empty-slug'})
index.extend(default_lang_items)
translations.extend([x for x in items if x not in default_lang_items])
for a in items:
@ -677,11 +697,13 @@ def process_translations(content_list, order_by=None):
except AttributeError:
logger.warning(
'There is no "%s" attribute in the item '
'metadata. Defaulting to slug order.', order_by)
'metadata. Defaulting to slug order.', order_by,
extra={'id': 'warn.utils.translations-index-sorting'})
else:
logger.warning(
'Invalid *_ORDER_BY setting (%s).'
'Valid options are strings and functions.', order_by)
'Valid options are strings and functions.', order_by,
extra={'id': 'warn.utils.order-by-is-invalid'})
return index, translations
@ -704,7 +726,9 @@ def folder_watcher(path, extensions, ignores=[]):
try:
yield os.stat(os.path.join(root, f)).st_mtime
except OSError as e:
logger.warning('Caught Exception: %s', e)
logger.warning(
'Caught Exception: %s', e,
extra={'id': 'warn.utils.caugh-exception'})
LAST_MTIME = 0
while True:
@ -727,7 +751,9 @@ def file_watcher(path):
try:
mtime = os.stat(path).st_mtime
except OSError as e:
logger.warning('Caught Exception: %s', e)
logger.warning(
'Caught Exception: %s', e,
extra={'id': 'warn.utils.caugh-exception'})
continue
if mtime > LAST_MTIME:

View file

@ -74,11 +74,13 @@ class Writer(object):
raise RuntimeError('File %s is set to be overridden twice'
% filename)
else:
logger.info('Skipping %s', filename)
logger.info('Skipping %s', filename,
extra={'id': 'info.writers.skip'})
filename = os.devnull
elif filename in self._written_files:
if override:
logger.info('Overwriting %s', filename)
logger.info('Overwriting %s', filename,
extra={'id': 'info.writers.overwrite'})
else:
raise RuntimeError('File %s is to be overwritten' % filename)
if override:
@ -129,7 +131,8 @@ class Writer(object):
encoding = 'utf-8' if six.PY3 else None
with self._open_w(complete_path, encoding, override_output) as fp:
feed.write(fp, 'utf-8')
logger.info('Writing %s', complete_path)
logger.info('Writing %s', complete_path,
extra={'id': 'info.writers.write-feed'})
signals.feed_written.send(
complete_path, context=context, feed=feed)
@ -174,7 +177,8 @@ class Writer(object):
with self._open_w(path, 'utf-8', override=override) as f:
f.write(output)
logger.info('Writing %s', path)
logger.info('Writing %s', path,
extra={'id': 'into.writers.render-template-to-file'})
# Send a signal to say we're writing a file with some specific
# local context.