Browse Source

Add i18n translation for Log messages

Added i18n translation to all log messages. Also added
hacking check for this to ensure in future all log
messages are translated.

Change-Id: I77fbb18ffe47b12232125cc1fa7aae97ea9b1214
Closes-Bug: #1603759
changes/11/355311/1
yatin karel 5 years ago
parent
commit
fb0057c105
  1. 3
      magnum/conductor/k8s_api.py
  2. 28
      magnum/hacking/checks.py
  3. 7
      magnum/service/periodic.py
  4. 19
      magnum/tests/functional/api/v1/clients/bay_client.py
  5. 21
      magnum/tests/functional/common/base.py
  6. 11
      magnum/tests/functional/python_client_base.py
  7. 9
      magnum/tests/functional/swarm/test_swarm_python_client.py
  8. 22
      magnum/tests/unit/test_hacking.py

3
magnum/conductor/k8s_api.py

@ -19,6 +19,7 @@ from k8sclient.client.apis import apiv_api
from oslo_log import log as logging
from magnum.conductor.handlers.common.cert_manager import create_client_files
from magnum.i18n import _LE
LOG = logging.getLogger(__name__)
@ -36,7 +37,7 @@ class K8sAPI(apiv_api.ApivApi):
tmp.write(content)
tmp.flush()
except Exception as err:
LOG.error("Error while creating temp file: %s", err)
LOG.error(_LE("Error while creating temp file: %s"), err)
raise
return tmp

28
magnum/hacking/checks.py

@ -15,6 +15,8 @@
import re
import pep8
"""
Guidelines for writing new hacking checks
@ -56,6 +58,14 @@ assert_true_isinstance_re = re.compile(
dict_constructor_with_list_copy_re = re.compile(r".*\bdict\((\[)?(\(|\[)")
assert_xrange_re = re.compile(
r"\s*xrange\s*\(")
log_translation = re.compile(
r"(.)*LOG\.(audit|error|critical)\(\s*('|\")")
log_translation_info = re.compile(
r"(.)*LOG\.(info)\(\s*(_\(|'|\")")
log_translation_exception = re.compile(
r"(.)*LOG\.(exception)\(\s*(_\(|'|\")")
log_translation_LW = re.compile(
r"(.)*LOG\.(warning|warn)\(\s*(_\(|'|\")")
custom_underscore_check = re.compile(r"(.)*_\s*=\s*(.)*")
underscore_import_check = re.compile(r"(.)*import _(.)*")
translated_log = re.compile(
@ -125,6 +135,23 @@ def assert_true_isinstance(logical_line):
yield (0, "M316: assertTrue(isinstance(a, b)) sentences not allowed")
def validate_log_translations(logical_line, physical_line, filename=None):
if pep8.noqa(physical_line):
return
msg = "M328: LOG.info messages require translations `_LI()`!"
if log_translation_info.match(logical_line):
yield (0, msg)
msg = "M329: LOG.exception messages require translations `_LE()`!"
if log_translation_exception.match(logical_line):
yield (0, msg)
msg = "M330: LOG.warning, LOG.warn messages require translations `_LW()`!"
if log_translation_LW.match(logical_line):
yield (0, msg)
msg = "M321: Log messages require translations!"
if log_translation.match(logical_line):
yield (0, msg)
def assert_equal_in(logical_line):
"""Check for assertEqual(True|False, A in B), assertEqual(A in B, True|False)
@ -215,4 +242,5 @@ def factory(register):
register(dict_constructor_with_list_copy)
register(no_xrange)
register(no_log_warn)
register(validate_log_translations)
register(check_explicit_underscore_import)

7
magnum/service/periodic.py

@ -132,9 +132,10 @@ class MagnumPeriodicTasks(periodic_task.PeriodicTasks):
# Any other exception means we do not perform any
# action on this bay in the current sync run, so remove
# it from all records.
LOG.warning("Exception while attempting to retrieve "
"Heat stack %s for bay %s. Traceback "
"follows.")
LOG.warning(_LW("Exception while attempting to retrieve "
"Heat stack %(stack_id)s for bay %(bay_id)s. "
"Traceback follows."),
{'stack_id': bay.stack_id, 'bay_id': bay.id})
LOG.warning(e)
_sid_to_bay_mapping.pop(bay.stack_id)
_bay_stack_ids.remove(bay.stack_id)

19
magnum/tests/functional/api/v1/clients/bay_client.py

@ -13,6 +13,9 @@
from oslo_log import log as logging
from tempest.lib import exceptions
from magnum.i18n import _LE
from magnum.i18n import _LI
from magnum.i18n import _LW
from magnum.tests.functional.api.v1.models import bay_model
from magnum.tests.functional.common import client
from magnum.tests.functional.common import utils
@ -120,9 +123,9 @@ class BayClient(client.MagnumClient):
lambda: self.does_bay_exist(bay_id), 10, 1800)
except Exception:
# In error state. Clean up the bay id if desired
self.LOG.error('Bay %s entered an exception state.' % bay_id)
self.LOG.error(_LE('Bay %s entered an exception state.') % bay_id)
if delete_on_error:
self.LOG.error('We will attempt to delete bays now.')
self.LOG.error(_LE('We will attempt to delete bays now.'))
self.delete_bay(bay_id)
self.wait_for_bay_to_delete(bay_id)
raise
@ -136,35 +139,35 @@ class BayClient(client.MagnumClient):
resp, model = self.get_bay(bay_id)
if model.status in ['CREATED', 'CREATE_COMPLETE',
'ERROR', 'CREATE_FAILED']:
self.LOG.info('Bay %s succeeded.' % bay_id)
self.LOG.info(_LI('Bay %s succeeded.') % bay_id)
return True
else:
return False
except exceptions.NotFound:
self.LOG.warning('Bay %s is not found.' % bay_id)
self.LOG.warning(_LW('Bay %s is not found.') % bay_id)
return False
def does_bay_exist(self, bay_id):
try:
resp, model = self.get_bay(bay_id)
if model.status in ['CREATED', 'CREATE_COMPLETE']:
self.LOG.info('Bay %s is created.' % bay_id)
self.LOG.info(_LI('Bay %s is created.') % bay_id)
return True
elif model.status in ['ERROR', 'CREATE_FAILED']:
self.LOG.error('Bay %s is in fail state.' % bay_id)
self.LOG.error(_LE('Bay %s is in fail state.') % bay_id)
raise exceptions.ServerFault(
"Got into an error condition: %s for %s" %
(model.status, bay_id))
else:
return False
except exceptions.NotFound:
self.LOG.warning('Bay %s is not found.' % bay_id)
self.LOG.warning(_LW('Bay %s is not found.') % bay_id)
return False
def does_bay_not_exist(self, bay_id):
try:
self.get_bay(bay_id)
except exceptions.NotFound:
self.LOG.warning('Bay %s is not found.' % bay_id)
self.LOG.warning(_LW('Bay %s is not found.') % bay_id)
return True
return False

21
magnum/tests/functional/common/base.py

@ -17,6 +17,8 @@ import subprocess
from tempest.lib import base
import magnum
from magnum.i18n import _LE
from magnum.i18n import _LI
COPY_LOG_HELPER = "magnum/tests/contrib/copy_instance_logs.sh"
@ -44,10 +46,10 @@ class BaseMagnumTest(base.BaseTestCase):
"""
def int_copy_logs(exec_info):
try:
cls.LOG.info("Copying logs...")
cls.LOG.info(_LI("Copying logs..."))
fn = exec_info[2].tb_frame.f_locals['fn']
func_name = fn.im_self._get_test_method().__name__
msg = "Failed to copy logs for bay"
msg = (_LE("Failed to copy logs for bay"))
nodes_addresses = get_nodes_fn()
master_nodes = nodes_addresses[0]
@ -61,8 +63,8 @@ class BaseMagnumTest(base.BaseTestCase):
if not nodes_address:
return
cls.LOG.info("copy logs from : %s" %
','.join(nodes_address))
msg = _LI("copy logs from : %s") % ','.join(nodes_address)
cls.LOG.info(msg)
log_name = prefix + "-" + func_name
for node_address in nodes_address:
try:
@ -77,10 +79,13 @@ class BaseMagnumTest(base.BaseTestCase):
])
except Exception:
cls.LOG.error(msg)
cls.LOG.exception(
"failed to copy from %s to %s%s-%s" %
(node_address, "/opt/stack/logs/bay-nodes/",
log_name, node_address))
msg = (_LE("failed to copy from %{node_address}s "
"to %{base_path}s%{log_name}s-"
"%{node_address}s") %
{'node_address': node_address,
'base_path': "/opt/stack/logs/bay-nodes/",
'log_name': log_name})
cls.LOG.exception(msg)
do_copy_logs('master', master_nodes)
do_copy_logs('node', agent_nodes)

11
magnum/tests/functional/python_client_base.py

@ -31,6 +31,7 @@ from k8sclient.client import api_client
from k8sclient.client.apis import apiv_api
from keystoneclient.v2_0 import client as ksclient
from magnum.common.utils import rmtree_without_raise
from magnum.i18n import _LI
from magnum.tests.functional.common import base
from magnum.tests.functional.common import utils
from magnumclient.common.apiclient import exceptions
@ -275,11 +276,11 @@ extendedKeyUsage = clientAuth
def _get_nodes(self):
nodes = self._get_nodes_from_bay()
if not [x for x in nodes if x]:
self.LOG.info("the list of nodes from bay is empty")
self.LOG.info(_LI("the list of nodes from bay is empty"))
nodes = self._get_nodes_from_stack()
if not [x for x in nodes if x]:
self.LOG.info("the list of nodes from stack is empty")
self.LOG.info("Nodes are: %s" % nodes)
self.LOG.info(_LI("the list of nodes from stack is empty"))
self.LOG.info(_LI("Nodes are: %s") % nodes)
return nodes
def _get_nodes_from_bay(self):
@ -378,10 +379,10 @@ class BaseK8sTest(BayTest):
def _is_api_ready(self):
try:
self.k8s_api.list_namespaced_node()
self.LOG.info("API is ready.")
self.LOG.info(_LI("API is ready."))
return True
except Exception:
self.LOG.info("API is not ready yet.")
self.LOG.info(_LI("API is not ready yet."))
return False
def test_pod_apis(self):

9
magnum/tests/functional/swarm/test_swarm_python_client.py

@ -17,6 +17,7 @@ from oslo_config import cfg
from requests import exceptions as req_exceptions
from magnum.common import docker_utils
from magnum.i18n import _LI
from magnum.tests.functional.python_client_base import BayTest
@ -97,15 +98,15 @@ class TestSwarmAPIs(BayTest):
# investigate the cause of this issue. See bug #1583337.
for i in range(150):
try:
self.LOG.info("Calling function " + func.__name__)
self.LOG.info(_LI("Calling function ") + func.__name__)
return func(*args, **kwargs)
except req_exceptions.ConnectionError:
self.LOG.info("Connection aborted on calling Swarm API. "
"Will retry in 2 seconds.")
self.LOG.info(_LI("Connection aborted on calling Swarm API. "
"Will retry in 2 seconds."))
except errors.APIError as e:
if e.response.status_code != 500:
raise
self.LOG.info("Internal Server Error: " + str(e))
self.LOG.info(_LI("Internal Server Error: ") + str(e))
time.sleep(2)
raise Exception("Cannot connect to Swarm API.")

22
magnum/tests/unit/test_hacking.py

@ -215,6 +215,28 @@ class HackingTestCase(base.TestCase):
"""
self._assert_has_no_errors(code, check)
def test_log_translations(self):
logs = ['audit', 'error', 'info', 'warning', 'critical', 'warn',
'exception']
levels = ['_LI', '_LW', '_LE', '_LC']
debug = "LOG.debug('OK')"
self.assertEqual(
0, len(list(checks.validate_log_translations(debug, debug))))
for log in logs:
bad = 'LOG.%s("Bad")' % log
self.assertEqual(
1, len(list(checks.validate_log_translations(bad, bad))))
ok = "LOG.%s('OK') # noqa" % log
self.assertEqual(
0, len(list(checks.validate_log_translations(ok, ok))))
ok = "LOG.%s(variable)" % log
self.assertEqual(
0, len(list(checks.validate_log_translations(ok, ok))))
for level in levels:
ok = "LOG.%s(%s('OK'))" % (log, level)
self.assertEqual(
0, len(list(checks.validate_log_translations(ok, ok))))
def test_use_timeunitls_utcow(self):
errors = [(1, 0, "M310")]
check = checks.use_timeutils_utcnow

Loading…
Cancel
Save