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
This commit is contained in:
parent
4b66daafd7
commit
fb0057c105
|
@ -19,6 +19,7 @@ from k8sclient.client.apis import apiv_api
|
||||||
from oslo_log import log as logging
|
from oslo_log import log as logging
|
||||||
|
|
||||||
from magnum.conductor.handlers.common.cert_manager import create_client_files
|
from magnum.conductor.handlers.common.cert_manager import create_client_files
|
||||||
|
from magnum.i18n import _LE
|
||||||
|
|
||||||
LOG = logging.getLogger(__name__)
|
LOG = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
@ -36,7 +37,7 @@ class K8sAPI(apiv_api.ApivApi):
|
||||||
tmp.write(content)
|
tmp.write(content)
|
||||||
tmp.flush()
|
tmp.flush()
|
||||||
except Exception as err:
|
except Exception as err:
|
||||||
LOG.error("Error while creating temp file: %s", err)
|
LOG.error(_LE("Error while creating temp file: %s"), err)
|
||||||
raise
|
raise
|
||||||
return tmp
|
return tmp
|
||||||
|
|
||||||
|
|
|
@ -15,6 +15,8 @@
|
||||||
|
|
||||||
import re
|
import re
|
||||||
|
|
||||||
|
import pep8
|
||||||
|
|
||||||
"""
|
"""
|
||||||
Guidelines for writing new hacking checks
|
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\((\[)?(\(|\[)")
|
dict_constructor_with_list_copy_re = re.compile(r".*\bdict\((\[)?(\(|\[)")
|
||||||
assert_xrange_re = re.compile(
|
assert_xrange_re = re.compile(
|
||||||
r"\s*xrange\s*\(")
|
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*(.)*")
|
custom_underscore_check = re.compile(r"(.)*_\s*=\s*(.)*")
|
||||||
underscore_import_check = re.compile(r"(.)*import _(.)*")
|
underscore_import_check = re.compile(r"(.)*import _(.)*")
|
||||||
translated_log = re.compile(
|
translated_log = re.compile(
|
||||||
|
@ -125,6 +135,23 @@ def assert_true_isinstance(logical_line):
|
||||||
yield (0, "M316: assertTrue(isinstance(a, b)) sentences not allowed")
|
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):
|
def assert_equal_in(logical_line):
|
||||||
"""Check for assertEqual(True|False, A in B), assertEqual(A in B, True|False)
|
"""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(dict_constructor_with_list_copy)
|
||||||
register(no_xrange)
|
register(no_xrange)
|
||||||
register(no_log_warn)
|
register(no_log_warn)
|
||||||
|
register(validate_log_translations)
|
||||||
register(check_explicit_underscore_import)
|
register(check_explicit_underscore_import)
|
||||||
|
|
|
@ -132,9 +132,10 @@ class MagnumPeriodicTasks(periodic_task.PeriodicTasks):
|
||||||
# Any other exception means we do not perform any
|
# Any other exception means we do not perform any
|
||||||
# action on this bay in the current sync run, so remove
|
# action on this bay in the current sync run, so remove
|
||||||
# it from all records.
|
# it from all records.
|
||||||
LOG.warning("Exception while attempting to retrieve "
|
LOG.warning(_LW("Exception while attempting to retrieve "
|
||||||
"Heat stack %s for bay %s. Traceback "
|
"Heat stack %(stack_id)s for bay %(bay_id)s. "
|
||||||
"follows.")
|
"Traceback follows."),
|
||||||
|
{'stack_id': bay.stack_id, 'bay_id': bay.id})
|
||||||
LOG.warning(e)
|
LOG.warning(e)
|
||||||
_sid_to_bay_mapping.pop(bay.stack_id)
|
_sid_to_bay_mapping.pop(bay.stack_id)
|
||||||
_bay_stack_ids.remove(bay.stack_id)
|
_bay_stack_ids.remove(bay.stack_id)
|
||||||
|
|
|
@ -13,6 +13,9 @@
|
||||||
from oslo_log import log as logging
|
from oslo_log import log as logging
|
||||||
from tempest.lib import exceptions
|
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.api.v1.models import bay_model
|
||||||
from magnum.tests.functional.common import client
|
from magnum.tests.functional.common import client
|
||||||
from magnum.tests.functional.common import utils
|
from magnum.tests.functional.common import utils
|
||||||
|
@ -120,9 +123,9 @@ class BayClient(client.MagnumClient):
|
||||||
lambda: self.does_bay_exist(bay_id), 10, 1800)
|
lambda: self.does_bay_exist(bay_id), 10, 1800)
|
||||||
except Exception:
|
except Exception:
|
||||||
# In error state. Clean up the bay id if desired
|
# 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:
|
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.delete_bay(bay_id)
|
||||||
self.wait_for_bay_to_delete(bay_id)
|
self.wait_for_bay_to_delete(bay_id)
|
||||||
raise
|
raise
|
||||||
|
@ -136,35 +139,35 @@ class BayClient(client.MagnumClient):
|
||||||
resp, model = self.get_bay(bay_id)
|
resp, model = self.get_bay(bay_id)
|
||||||
if model.status in ['CREATED', 'CREATE_COMPLETE',
|
if model.status in ['CREATED', 'CREATE_COMPLETE',
|
||||||
'ERROR', 'CREATE_FAILED']:
|
'ERROR', 'CREATE_FAILED']:
|
||||||
self.LOG.info('Bay %s succeeded.' % bay_id)
|
self.LOG.info(_LI('Bay %s succeeded.') % bay_id)
|
||||||
return True
|
return True
|
||||||
else:
|
else:
|
||||||
return False
|
return False
|
||||||
except exceptions.NotFound:
|
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
|
return False
|
||||||
|
|
||||||
def does_bay_exist(self, bay_id):
|
def does_bay_exist(self, bay_id):
|
||||||
try:
|
try:
|
||||||
resp, model = self.get_bay(bay_id)
|
resp, model = self.get_bay(bay_id)
|
||||||
if model.status in ['CREATED', 'CREATE_COMPLETE']:
|
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
|
return True
|
||||||
elif model.status in ['ERROR', 'CREATE_FAILED']:
|
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(
|
raise exceptions.ServerFault(
|
||||||
"Got into an error condition: %s for %s" %
|
"Got into an error condition: %s for %s" %
|
||||||
(model.status, bay_id))
|
(model.status, bay_id))
|
||||||
else:
|
else:
|
||||||
return False
|
return False
|
||||||
except exceptions.NotFound:
|
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
|
return False
|
||||||
|
|
||||||
def does_bay_not_exist(self, bay_id):
|
def does_bay_not_exist(self, bay_id):
|
||||||
try:
|
try:
|
||||||
self.get_bay(bay_id)
|
self.get_bay(bay_id)
|
||||||
except exceptions.NotFound:
|
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 True
|
||||||
return False
|
return False
|
||||||
|
|
|
@ -17,6 +17,8 @@ import subprocess
|
||||||
from tempest.lib import base
|
from tempest.lib import base
|
||||||
|
|
||||||
import magnum
|
import magnum
|
||||||
|
from magnum.i18n import _LE
|
||||||
|
from magnum.i18n import _LI
|
||||||
|
|
||||||
|
|
||||||
COPY_LOG_HELPER = "magnum/tests/contrib/copy_instance_logs.sh"
|
COPY_LOG_HELPER = "magnum/tests/contrib/copy_instance_logs.sh"
|
||||||
|
@ -44,10 +46,10 @@ class BaseMagnumTest(base.BaseTestCase):
|
||||||
"""
|
"""
|
||||||
def int_copy_logs(exec_info):
|
def int_copy_logs(exec_info):
|
||||||
try:
|
try:
|
||||||
cls.LOG.info("Copying logs...")
|
cls.LOG.info(_LI("Copying logs..."))
|
||||||
fn = exec_info[2].tb_frame.f_locals['fn']
|
fn = exec_info[2].tb_frame.f_locals['fn']
|
||||||
func_name = fn.im_self._get_test_method().__name__
|
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()
|
nodes_addresses = get_nodes_fn()
|
||||||
|
|
||||||
master_nodes = nodes_addresses[0]
|
master_nodes = nodes_addresses[0]
|
||||||
|
@ -61,8 +63,8 @@ class BaseMagnumTest(base.BaseTestCase):
|
||||||
if not nodes_address:
|
if not nodes_address:
|
||||||
return
|
return
|
||||||
|
|
||||||
cls.LOG.info("copy logs from : %s" %
|
msg = _LI("copy logs from : %s") % ','.join(nodes_address)
|
||||||
','.join(nodes_address))
|
cls.LOG.info(msg)
|
||||||
log_name = prefix + "-" + func_name
|
log_name = prefix + "-" + func_name
|
||||||
for node_address in nodes_address:
|
for node_address in nodes_address:
|
||||||
try:
|
try:
|
||||||
|
@ -77,10 +79,13 @@ class BaseMagnumTest(base.BaseTestCase):
|
||||||
])
|
])
|
||||||
except Exception:
|
except Exception:
|
||||||
cls.LOG.error(msg)
|
cls.LOG.error(msg)
|
||||||
cls.LOG.exception(
|
msg = (_LE("failed to copy from %{node_address}s "
|
||||||
"failed to copy from %s to %s%s-%s" %
|
"to %{base_path}s%{log_name}s-"
|
||||||
(node_address, "/opt/stack/logs/bay-nodes/",
|
"%{node_address}s") %
|
||||||
log_name, node_address))
|
{'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('master', master_nodes)
|
||||||
do_copy_logs('node', agent_nodes)
|
do_copy_logs('node', agent_nodes)
|
||||||
|
|
|
@ -31,6 +31,7 @@ from k8sclient.client import api_client
|
||||||
from k8sclient.client.apis import apiv_api
|
from k8sclient.client.apis import apiv_api
|
||||||
from keystoneclient.v2_0 import client as ksclient
|
from keystoneclient.v2_0 import client as ksclient
|
||||||
from magnum.common.utils import rmtree_without_raise
|
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 base
|
||||||
from magnum.tests.functional.common import utils
|
from magnum.tests.functional.common import utils
|
||||||
from magnumclient.common.apiclient import exceptions
|
from magnumclient.common.apiclient import exceptions
|
||||||
|
@ -275,11 +276,11 @@ extendedKeyUsage = clientAuth
|
||||||
def _get_nodes(self):
|
def _get_nodes(self):
|
||||||
nodes = self._get_nodes_from_bay()
|
nodes = self._get_nodes_from_bay()
|
||||||
if not [x for x in nodes if x]:
|
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()
|
nodes = self._get_nodes_from_stack()
|
||||||
if not [x for x in nodes if x]:
|
if not [x for x in nodes if x]:
|
||||||
self.LOG.info("the list of nodes from stack is empty")
|
self.LOG.info(_LI("the list of nodes from stack is empty"))
|
||||||
self.LOG.info("Nodes are: %s" % nodes)
|
self.LOG.info(_LI("Nodes are: %s") % nodes)
|
||||||
return nodes
|
return nodes
|
||||||
|
|
||||||
def _get_nodes_from_bay(self):
|
def _get_nodes_from_bay(self):
|
||||||
|
@ -378,10 +379,10 @@ class BaseK8sTest(BayTest):
|
||||||
def _is_api_ready(self):
|
def _is_api_ready(self):
|
||||||
try:
|
try:
|
||||||
self.k8s_api.list_namespaced_node()
|
self.k8s_api.list_namespaced_node()
|
||||||
self.LOG.info("API is ready.")
|
self.LOG.info(_LI("API is ready."))
|
||||||
return True
|
return True
|
||||||
except Exception:
|
except Exception:
|
||||||
self.LOG.info("API is not ready yet.")
|
self.LOG.info(_LI("API is not ready yet."))
|
||||||
return False
|
return False
|
||||||
|
|
||||||
def test_pod_apis(self):
|
def test_pod_apis(self):
|
||||||
|
|
|
@ -17,6 +17,7 @@ from oslo_config import cfg
|
||||||
from requests import exceptions as req_exceptions
|
from requests import exceptions as req_exceptions
|
||||||
|
|
||||||
from magnum.common import docker_utils
|
from magnum.common import docker_utils
|
||||||
|
from magnum.i18n import _LI
|
||||||
from magnum.tests.functional.python_client_base import BayTest
|
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.
|
# investigate the cause of this issue. See bug #1583337.
|
||||||
for i in range(150):
|
for i in range(150):
|
||||||
try:
|
try:
|
||||||
self.LOG.info("Calling function " + func.__name__)
|
self.LOG.info(_LI("Calling function ") + func.__name__)
|
||||||
return func(*args, **kwargs)
|
return func(*args, **kwargs)
|
||||||
except req_exceptions.ConnectionError:
|
except req_exceptions.ConnectionError:
|
||||||
self.LOG.info("Connection aborted on calling Swarm API. "
|
self.LOG.info(_LI("Connection aborted on calling Swarm API. "
|
||||||
"Will retry in 2 seconds.")
|
"Will retry in 2 seconds."))
|
||||||
except errors.APIError as e:
|
except errors.APIError as e:
|
||||||
if e.response.status_code != 500:
|
if e.response.status_code != 500:
|
||||||
raise
|
raise
|
||||||
self.LOG.info("Internal Server Error: " + str(e))
|
self.LOG.info(_LI("Internal Server Error: ") + str(e))
|
||||||
time.sleep(2)
|
time.sleep(2)
|
||||||
|
|
||||||
raise Exception("Cannot connect to Swarm API.")
|
raise Exception("Cannot connect to Swarm API.")
|
||||||
|
|
|
@ -215,6 +215,28 @@ class HackingTestCase(base.TestCase):
|
||||||
"""
|
"""
|
||||||
self._assert_has_no_errors(code, check)
|
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):
|
def test_use_timeunitls_utcow(self):
|
||||||
errors = [(1, 0, "M310")]
|
errors = [(1, 0, "M310")]
|
||||||
check = checks.use_timeutils_utcnow
|
check = checks.use_timeutils_utcnow
|
||||||
|
|
Loading…
Reference in New Issue