diff --git a/HACKING.rst b/HACKING.rst index 60029e2785..f2c06363e2 100644 --- a/HACKING.rst +++ b/HACKING.rst @@ -16,3 +16,9 @@ glance Specific Commandments assertIsNone(A) - [G319] Validate that debug level logs are not translated - [G320] For python 3 compatibility, use six.text_type() instead of unicode() +- [G321] Validate that LOG messages, except debug ones, have translations +- [G322] Validate that LOG.info messages use _LI. +- [G323] Validate that LOG.exception messages use _LE. +- [G324] Validate that LOG.error messages use _LE. +- [G325] Validate that LOG.critical messages use _LC. +- [G326] Validate that LOG.warning messages use _LW. \ No newline at end of file diff --git a/glance/common/location_strategy/__init__.py b/glance/common/location_strategy/__init__.py index e2f3fcbfd9..d297950df6 100644 --- a/glance/common/location_strategy/__init__.py +++ b/glance/common/location_strategy/__init__.py @@ -22,6 +22,7 @@ from glance import i18n import glance.openstack.common.log as logging _ = i18n._ +_LE = i18n._LE location_strategy_opts = [ cfg.StrOpt('location_strategy', default='location_order', @@ -61,8 +62,9 @@ def _load_strategies(): mgr.driver.init() modules[strategy_name] = mgr.driver except Exception as e: - LOG.error(_("Failed to load location strategy module " - "%(module)s: %(e)s") % {'module': module_name, 'e': e}) + LOG.error(_LE("Failed to load location strategy module " + "%(module)s: %(e)s") % {'module': module_name, + 'e': e}) return modules diff --git a/glance/common/property_utils.py b/glance/common/property_utils.py index 1ed15a79e8..4633043083 100644 --- a/glance/common/property_utils.py +++ b/glance/common/property_utils.py @@ -32,6 +32,7 @@ from glance.openstack.common import policy CONFIG = ConfigParser.SafeConfigParser(dict_type=OrderedDict) LOG = logging.getLogger(__name__) _ = i18n._ +_LE = i18n._LE property_opts = [ cfg.StrOpt('property_protection_file', @@ -99,9 +100,9 @@ class PropertyRules(object): if self.prop_prot_rule_format == 'policies': if ',' in permissions: LOG.error( - _("Multiple policies '%s' not allowed" - "for a given operation. Policies can be " - "combined in the policy file"), + _LE("Multiple policies '%s' not allowed " + "for a given operation. Policies can be " + "combined in the policy file"), permissions) raise InvalidPropProtectConf() self.prop_exp_mapping[compiled_rule] = property_exp diff --git a/glance/common/swift_store_utils.py b/glance/common/swift_store_utils.py index a139d0d797..a6bc51f5de 100644 --- a/glance/common/swift_store_utils.py +++ b/glance/common/swift_store_utils.py @@ -25,6 +25,7 @@ from glance import i18n from glance.openstack.common import log as logging _ = i18n._ +_LE = i18n._LE swift_opts = [ cfg.StrOpt('default_swift_reference', @@ -97,6 +98,6 @@ class SwiftParams(object): reference['key'] = CONFIG.get(ref, 'key') account_params[ref] = reference except (ValueError, SyntaxError, ConfigParser.NoOptionError) as e: - LOG.exception(_("Invalid format of swift store config" - "cfg")) + LOG.exception(_LE("Invalid format of swift store config " + "cfg")) return account_params diff --git a/glance/common/wsgi.py b/glance/common/wsgi.py index 26ddd64f8f..e1df9d8b61 100644 --- a/glance/common/wsgi.py +++ b/glance/common/wsgi.py @@ -51,6 +51,8 @@ import glance.openstack.common.log as logging _ = i18n._ +_LE = i18n._LE +_LI = i18n._LI bind_opts = [ cfg.StrOpt('bind_host', default='0.0.0.0', @@ -265,7 +267,7 @@ class Server(object): self.pool.spawn_n(self._single_run, self.application, self.sock) return else: - LOG.info(_("Starting %d workers") % CONF.workers) + LOG.info(_LI("Starting %d workers") % CONF.workers) signal.signal(signal.SIGTERM, kill_children) signal.signal(signal.SIGINT, kill_children) signal.signal(signal.SIGHUP, hup) @@ -280,13 +282,14 @@ class Server(object): try: pid, status = os.wait() if os.WIFEXITED(status) or os.WIFSIGNALED(status): - LOG.info(_('Removing dead child %s') % pid) + LOG.info(_LI('Removing dead child %s') % pid) self.children.remove(pid) if os.WIFEXITED(status) and os.WEXITSTATUS(status) != 0: - LOG.error(_('Not respawning child %d, cannot ' - 'recover from termination') % pid) + LOG.error(_LE('Not respawning child %d, cannot ' + 'recover from termination') % pid) if not self.children: - LOG.info(_('All workers have terminated. Exiting')) + LOG.info(_LI('All workers have terminated. ' + 'Exiting')) self.running = False else: self.run_child() @@ -294,7 +297,7 @@ class Server(object): if err.errno not in (errno.EINTR, errno.ECHILD): raise except KeyboardInterrupt: - LOG.info(_('Caught keyboard interrupt. Exiting.')) + LOG.info(_LI('Caught keyboard interrupt. Exiting.')) break eventlet.greenio.shutdown_safe(self.sock) self.sock.close() @@ -320,12 +323,12 @@ class Server(object): # and is respawned unnecessarily as a result signal.signal(signal.SIGINT, signal.SIG_IGN) self.run_server() - LOG.info(_('Child %d exiting normally') % os.getpid()) + LOG.info(_LI('Child %d exiting normally') % os.getpid()) # self.pool.waitall() has been called by run_server, so # its safe to exit here sys.exit(0) else: - LOG.info(_('Started child %s') % pid) + LOG.info(_LI('Started child %s') % pid) self.children.append(pid) def run_server(self): @@ -349,7 +352,7 @@ class Server(object): def _single_run(self, application, sock): """Start a WSGI server in a new green thread.""" - LOG.info(_("Starting single process server")) + LOG.info(_LI("Starting single process server")) eventlet.wsgi.server(sock, application, custom_pool=self.pool, log=self._wsgi_logger, debug=False) diff --git a/glance/hacking/checks.py b/glance/hacking/checks.py index 507218b32a..a79f3f59ae 100644 --- a/glance/hacking/checks.py +++ b/glance/hacking/checks.py @@ -14,6 +14,8 @@ import re +import pep8 + """ Guidelines for writing new hacking checks @@ -41,6 +43,18 @@ asse_equal_end_with_none_re = re.compile( asse_equal_start_with_none_re = re.compile( r"(.)*assertEqual\(None, (\w|\.|\'|\"|\[|\])+\)") unicode_func_re = re.compile(r"(\s|\W|^)unicode\(") +log_translation = re.compile( + r"(.)*LOG\.(audit)\(\s*('|\")") +log_translation_info = re.compile( + r"(.)*LOG\.(info)\(\s*(_\(|'|\")") +log_translation_exception = re.compile( + r"(.)*LOG\.(exception)\(\s*(_\(|'|\")") +log_translation_error = re.compile( + r"(.)*LOG\.(error)\(\s*(_\(|'|\")") +log_translation_critical = re.compile( + r"(.)*LOG\.(critical)\(\s*(_\(|'|\")") +log_translation_warning = re.compile( + r"(.)*LOG\.(warning)\(\s*(_\(|'|\")") def assert_true_instance(logical_line): @@ -101,9 +115,34 @@ def no_direct_use_of_unicode_function(logical_line): yield(0, "G320: Use six.text_type() instead of unicode()") +def validate_log_translations(logical_line, physical_line, filename): + # Translations are not required in the test directory + if pep8.noqa(physical_line): + return + msg = "G322: LOG.info messages require translations `_LI()`!" + if log_translation_info.match(logical_line): + yield (0, msg) + msg = "G323: LOG.exception messages require translations `_LE()`!" + if log_translation_exception.match(logical_line): + yield (0, msg) + msg = "G324: LOG.error messages require translations `_LE()`!" + if log_translation_error.match(logical_line): + yield (0, msg) + msg = "G325: LOG.critical messages require translations `_LC()`!" + if log_translation_critical.match(logical_line): + yield (0, msg) + msg = "G326: LOG.warning messages require translations `_LW()`!" + if log_translation_warning.match(logical_line): + yield (0, msg) + msg = "G321: Log messages require translations!" + if log_translation.match(logical_line): + yield (0, msg) + + def factory(register): register(assert_true_instance) register(assert_equal_type) register(assert_equal_none) register(no_translate_debug_logs) register(no_direct_use_of_unicode_function) + register(validate_log_translations) diff --git a/tools/migrate_image_owners.py b/tools/migrate_image_owners.py index cfc8ff4b79..90661b7ad7 100644 --- a/tools/migrate_image_owners.py +++ b/tools/migrate_image_owners.py @@ -20,9 +20,14 @@ from oslo.config import cfg import glance.context import glance.db.sqlalchemy.api as db_api +from glance import i18n import glance.openstack.common.log as logging import glance.registry.context +_ = i18n._ +_LC = i18n._LC +_LI = i18n._LI + LOG = logging.getLogger(__name__) LOG.addHandler(logging.StreamHandler()) LOG.setLevel(logging.DEBUG) @@ -44,7 +49,7 @@ def build_image_owner_map(owner_map, db, context): owner_name = image['owner'] if not owner_name: - LOG.info('Image %s has no owner. Skipping.' % image_id) + LOG.info(_LI('Image %s has no owner. Skipping.') % image_id) continue try: @@ -65,7 +70,7 @@ def build_image_owner_map(owner_map, db, context): def update_image_owners(image_owner_map, db, context): for (image_id, image_owner) in image_owner_map.items(): db.image_update(context, image_id, {'owner': image_owner}) - LOG.info('Image %s successfully updated.' % image_id) + LOG.info(_LI('Image %s successfully updated.') % image_id) if __name__ == "__main__": @@ -96,7 +101,7 @@ if __name__ == "__main__": admin_password = config.keystone_admin_password if not (auth_uri and admin_tenant_name and admin_user and admin_password): - LOG.critical('Missing authentication arguments') + LOG.critical(_LC('Missing authentication arguments')) sys.exit(1) ks = keystoneclient.v2_0.client.Client(username=admin_user,