use environment variable to control file location probing

If OSLO_CONFIG_SHOW_CODE_LOCATIONS is set to any non-empty string it
will turn on the ability to see which file has the definition of an
Opt or where set_default() was invoked.

Change-Id: Ie705014dcf331e3c6b3367d2fefbfb9acc091799
Signed-off-by: Doug Hellmann <doug@doughellmann.com>
This commit is contained in:
Doug Hellmann 2018-03-28 17:26:26 -04:00
parent b6cfa29055
commit 7db6a2604d
3 changed files with 48 additions and 26 deletions

View File

@ -6,3 +6,20 @@ Helper Functions
.. autofunction:: find_config_files
.. autofunction:: set_defaults
Showing detailed locations for configuration settings
-----------------------------------------------------
``oslo.config`` can track the location in application and library code
where an option is defined, defaults are set, or values are
overridden. This feature is disabled by default because it is
expensive and incurs a significant performance penalty, but it can be
useful for developers tracing down issues with configuration option
definitions.
To turn on detailed location tracking, set the environment variable
``OSLO_CONFIG_SHOW_CODE_LOCATIONS`` to any non-empty value (for
example, ``"1"`` or ``"yes, please"``) before starting the
application, test suite, or script. Then use
:func:`ConfigOpts.get_location` to access the location data for the
option.

View File

@ -489,7 +489,7 @@ import copy
import errno
import functools
import glob
# import inspect
import inspect
import itertools
import logging
import os
@ -804,6 +804,10 @@ def _is_opt_registered(opts, opt):
return False
_show_caller_details = bool(os.environ.get(
'OSLO_CONFIG_SHOW_CODE_LOCATIONS'))
def _get_caller_detail(n=2):
"""Return a string describing where this is being called from.
@ -811,23 +815,22 @@ def _get_caller_detail(n=2):
:type n: int
:returns: str
"""
return None
# FIXME(dhellmann): We need to look at the performance issues with
# doing this for every Opt instance.
# s = inspect.stack()[:n + 1]
# try:
# frame = s[n]
# try:
# return frame[1]
# # WARNING(dhellmann): Using frame.lineno to include the
# # line number in the return value causes some sort of
# # memory or stack corruption that manifests in values not
# # being cleaned up in the cfgfilter tests.
# # return '%s:%s' % (frame[1], frame[2])
# finally:
# del frame
# finally:
# del s
if not _show_caller_details:
return None
s = inspect.stack()[:n + 1]
try:
frame = s[n]
try:
return frame[1]
# WARNING(dhellmann): Using frame.lineno to include the
# line number in the return value causes some sort of
# memory or stack corruption that manifests in values not
# being cleaned up in the cfgfilter tests.
# return '%s:%s' % (frame[1], frame[2])
finally:
del frame
finally:
del s
def set_defaults(opts, **kwargs):

View File

@ -51,6 +51,12 @@ class GetLocationTestCase(base.BaseTestCase):
def setUp(self):
super(GetLocationTestCase, self).setUp()
def _clear():
cfg._show_caller_details = False
self.addCleanup(_clear)
cfg._show_caller_details = True
self.conf = TestConfigOpts()
self.normal_opt = cfg.StrOpt(
'normal_opt',
@ -70,8 +76,7 @@ class GetLocationTestCase(base.BaseTestCase):
cfg.Locations.opt_default,
loc.location,
)
self.assertIsNone(loc.detail)
# self.assertIn('test_get_location.py', loc.detail)
self.assertIn('test_get_location.py', loc.detail)
def test_set_default_on_config_opt(self):
self.conf.set_default('normal_opt', self.id())
@ -81,8 +86,7 @@ class GetLocationTestCase(base.BaseTestCase):
cfg.Locations.set_default,
loc.location,
)
self.assertIsNone(loc.detail)
# self.assertIn('test_get_location.py', loc.detail)
self.assertIn('test_get_location.py', loc.detail)
def test_set_defaults_func(self):
cfg.set_defaults([self.normal_opt], normal_opt=self.id())
@ -92,8 +96,7 @@ class GetLocationTestCase(base.BaseTestCase):
cfg.Locations.set_default,
loc.location,
)
self.assertIsNone(loc.detail)
# self.assertIn('test_get_location.py', loc.detail)
self.assertIn('test_get_location.py', loc.detail)
def test_set_override(self):
self.conf.set_override('normal_opt', self.id())
@ -103,8 +106,7 @@ class GetLocationTestCase(base.BaseTestCase):
cfg.Locations.set_override,
loc.location,
)
self.assertIsNone(loc.detail)
# self.assertIn('test_get_location.py', loc.detail)
self.assertIn('test_get_location.py', loc.detail)
def test_user_cli(self):
filename = self._write_opt_to_tmp_file(