修复 log 和 versionutils 之间的导入循环

https://blueprints.launchpad.net/oslo-incubator/+spec/fix-import-cycle-log-and-versionutils

打破导入循环,以便我们可以发布 oslo.log。

问题描述

versionutils 和日志记录代码之间存在循环依赖,它们计划被发布为独立的库。我们需要打破这个循环,以便 oslo.log 能够在此周期内毕业。

提议的变更

oslo-incubator

ContextAdapter.deprecated() 方法移动到 versionutils 中的一个函数,与其他的弃用相关代码一起。这意味着将 fatal_deprecations 配置选项移动过去,并更新所有调用者。

建议的函数签名是

# versionutils.py

def report_deprecated_feature(logger, msg, *args, **kwds):
    """Call this function when a deprecated feature is used.

     If the system is configured for fatal deprecations then the message
     is logged at the 'critical' level and :class:`DeprecatedConfig` will
     be raised.

     Otherwise, the message will be logged (once) at the 'warn' level.

     :param logger: The Python logger to use to generate the message.
     :type logger: logging.Logger
     :param msg: The message to emit.
     :type msg: unicode
     :raises: :class:`DeprecatedConfig` if the system is configured for
              fatal deprecations.

     """

为了保持当前的日志记录行为,report_deprecated_feature() 将接受一个 logger 作为参数,并使用它来发出消息(而不是拥有一个名称为 versionutils 模块的单个 logger)。

fatal_deprecations 从默认选项组移动到 deprecation 组,并带有适当的弃用设置,以便在找到旧名称时能够识别它。

更新 versionutils.deprecated() 以调用 report_deprecated_feature() 而不是 LOG.deprecated()

oslo.log

完全从 oslo.log 中删除所有与弃用相关的代码。它将保留在 versionutils 中,要么在 incubator 中,要么在一个新的库中,这将在另一个蓝图讨论。

备选方案

  1. 更改 versionutils 中 deprecated() 装饰器的实现,使其不再调用 LOG.deprecated()。这可能意味着复制 LOG.deprecated() 中的逻辑。

  2. 将 LOG.deprecated() 的大部分主体移动到 versionutils,但保留该方法。这限制了我们必须在调用者中进行的更改数量,但这意味着 oslo.log 依赖于 oslo.versionutils。我们可以通过让 versionutils 中的函数使用 python 的标准 logger 而不是 oslo.log 来消除循环依赖。这似乎符合 oslo.log 上面的 API 更改。

这两种替代方案都可以修复循环,但要求我们保留 LOG.deprecated() 和我们的特殊 ContextAdapter。我们正在尝试在另一个与 oslo.log 毕业相关的蓝图中删除该类。

Impact on Existing APIs

LOG.deprecated() 的调用者需要更新为使用 versionutils.report_deprecated_feature() 代替。

安全影响

性能影响

Configuration Impact

fatal_deprecations 从默认选项组移动到 versionutils 组。

开发人员影响

报告弃用代码和功能的 API 将移动到一个新的位置,因此我们需要公开此更改。应用程序可以在与 incubator 中的日志记录和 versionutils 代码同步更改时进行更新。

大多数调用者无论如何都使用 deprecated() 装饰器。

更新调用的搜索

oslo-incubator/tests/unit/test_deprecated.py
38:    def test_deprecated(self):
39:        LOG.deprecated('test')
54:        LOG.deprecated('only once!')
55:        LOG.deprecated('only once!')
56:        LOG.deprecated('only once!')
65:        LOG.deprecated(msg1)
66:        LOG.deprecated(msg2)
67:        LOG.deprecated(msg1)
68:        LOG.deprecated(msg1)
69:        LOG.deprecated(msg2)
70:        LOG.deprecated(msg2)
83:        LOG.deprecated('only once! %s', 'arg1')
84:        LOG.deprecated('only once! %s', 'arg1')
85:        LOG.deprecated('only once! %s', 'arg2')
86:        LOG.deprecated('only once! %s', 'arg2')
108:        LOG.deprecated(msg_fmt_1, msg_fmt_1_arg_1)
109:        LOG.deprecated(msg_fmt_1, msg_fmt_1_arg_2)  # logged: args different
110:        LOG.deprecated(msg_fmt_1, msg_fmt_1_arg_1)  # no log: same msg+args
112:        LOG.deprecated(msg_fmt_2, msg_fmt_2_arg_1)
113:        LOG.deprecated(msg_fmt_2, *msg_fmt_2_arg_2)  # logged: args different
114:        LOG.deprecated(msg_fmt_2, *msg_fmt_2_arg_3)  # logged: args different
115:        LOG.deprecated(msg_fmt_2, *msg_fmt_2_arg_3)  # no log: same msg+args
116:        LOG.deprecated(msg_fmt_2, *msg_fmt_2_arg_2)  # no log: same msg+args

cinder/cinder/api/contrib/services.py
91:            LOG.deprecated(_("Query by service parameter is deprecated. "

cinder/cinder/quota.py
106:                LOG.deprecated(_("Default quota for resource: %(res)s is set "

cinder/cinder/scheduler/manager.py
66:            LOG.deprecated(_('ChanceScheduler and SimpleScheduler have been '

neutron/neutron/plugins/vmware/nsx_cluster.py
49:            LOG.deprecated(_("Attribute '%s' has been deprecated or moved "

neutron/neutron/agent/common/config.py
104:        LOG.deprecated(_('DEFAULT.root_helper is deprecated! Please move '

glance/glance/store/__init__.py
200:                LOG.deprecated(_("%s not found in `known_store`. "

搜索用法

$ ack --ignore-dir=.tox --ignore-dir=build --ignore-dir=.venv \
--ignore-dir=.update-venv --ignore-dir=openstack 'deprecated\('

python-keystoneclient/keystoneclient/tests/test_discovery.py
673:    def test_allow_deprecated(self):

python-keystoneclient/keystoneclient/tests/test_http.py
136:    def test_client_deprecated(self):

keystone/keystone/catalog/backends/templated.py
128:@versionutils.deprecated(

keystone/keystone/contrib/stats/core.py
130:    @versionutils.deprecated(

keystone/keystone/contrib/access/core.py
35:    @versionutils.deprecated(

keystone/keystone/middleware/s3_token.py
50:    @versionutils.deprecated(

keystone/keystone/middleware/core.py
148:    @versionutils.deprecated(

keystone/keystone/auth/plugins/external.py
102:    @versionutils.deprecated(
113:    @versionutils.deprecated(
130:    @versionutils.deprecated(
151:    @versionutils.deprecated(

keystone/keystone/token/core.py
263:    @versionutils.deprecated(versionutils.deprecated.ICEHOUSE, remove_in=+1)

keystone/keystone/common/controller.py
33:def v2_deprecated(f):
42:        v2_deprecated = versionutils.deprecated(

keystone/keystone/common/kvs/legacy.py
49:    @versionutils.deprecated(versionutils.deprecated.ICEHOUSE,

keystone/vendor/python-keystoneclient-master/keystoneclient/tests/test_http.py
136:    def test_client_deprecated(self):

oslo-incubator/tests/unit/test_versionutils.py
24:    def assert_deprecated(self, mock_log, **expected_details):
35:        @versionutils.deprecated(as_of=versionutils.deprecated.ICEHOUSE)
48:            @versionutils.deprecated(as_of=versionutils.deprecated.ICEHOUSE)
59:        @versionutils.deprecated(as_of=versionutils.deprecated.ICEHOUSE,
66:        self.assert_deprecated(mock_log,
75:        @versionutils.deprecated(as_of=versionutils.deprecated.GRIZZLY,
82:        self.assert_deprecated(mock_log,
91:        @versionutils.deprecated(as_of=versionutils.deprecated.GRIZZLY)
97:        self.assert_deprecated(mock_log,
105:        @versionutils.deprecated(as_of=versionutils.deprecated.GRIZZLY,
113:        self.assert_deprecated(mock_log,
122:        @versionutils.deprecated(as_of=versionutils.deprecated.GRIZZLY,
129:        self.assert_deprecated(mock_log,
137:        @versionutils.deprecated(as_of=versionutils.deprecated.GRIZZLY,
144:        self.assert_deprecated(mock_log,

oslo-incubator/tests/unit/test_log.py
600:    def test_logfile_deprecated(self):
610:    def test_logdir_deprecated(self):

oslo-incubator/tests/unit/test_deprecated.py
38:    def test_deprecated(self):
39:        LOG.deprecated('test')
54:        LOG.deprecated('only once!')
55:        LOG.deprecated('only once!')
56:        LOG.deprecated('only once!')
65:        LOG.deprecated(msg1)
66:        LOG.deprecated(msg2)
67:        LOG.deprecated(msg1)
68:        LOG.deprecated(msg1)
69:        LOG.deprecated(msg2)
70:        LOG.deprecated(msg2)
83:        LOG.deprecated('only once! %s', 'arg1')
84:        LOG.deprecated('only once! %s', 'arg1')
85:        LOG.deprecated('only once! %s', 'arg2')
86:        LOG.deprecated('only once! %s', 'arg2')
108:        LOG.deprecated(msg_fmt_1, msg_fmt_1_arg_1)
109:        LOG.deprecated(msg_fmt_1, msg_fmt_1_arg_2)  # logged: args different
110:        LOG.deprecated(msg_fmt_1, msg_fmt_1_arg_1)  # no log: same msg+args
112:        LOG.deprecated(msg_fmt_2, msg_fmt_2_arg_1)
113:        LOG.deprecated(msg_fmt_2, *msg_fmt_2_arg_2)  # logged: args different
114:        LOG.deprecated(msg_fmt_2, *msg_fmt_2_arg_3)  # logged: args different
115:        LOG.deprecated(msg_fmt_2, *msg_fmt_2_arg_3)  # no log: same msg+args
116:        LOG.deprecated(msg_fmt_2, *msg_fmt_2_arg_2)  # no log: same msg+args

cinder/cinder/api/contrib/services.py
91:            LOG.deprecated(_("Query by service parameter is deprecated. "

cinder/cinder/quota.py
106:                LOG.deprecated(_("Default quota for resource: %(res)s is set "

cinder/cinder/scheduler/manager.py
66:            LOG.deprecated(_('ChanceScheduler and SimpleScheduler have been '

oslo.config/tests/test_cfg.py
654:    def test_conf_file_str_value_override_use_deprecated(self):
1086:    def test_conf_file_dict_values_override_deprecated(self):
1106:    def test_conf_file_dict_deprecated(self):
1232:    def test_conf_file_multistr_values_append_deprecated(self):
1271:    def test_conf_file_multistr_deprecated(self):

neutron/neutron/plugins/vmware/nsx_cluster.py
49:            LOG.deprecated(_("Attribute '%s' has been deprecated or moved "

neutron/neutron/agent/common/config.py
104:        LOG.deprecated(_('DEFAULT.root_helper is deprecated! Please move '

heat/heat/tests/test_neutron_loadbalancer.py
429:    def test_create_deprecated(self):

heat/heat/tests/test_neutron_vpnservice.py
201:    def test_create_deprecated(self):

heat/heat/tests/test_parser.py
759:    def test_stack_resolve_runtime_data_deprecated(self):

heat/heat/tests/test_engine_service.py
1950:    def test_list_resource_types_deprecated(self):

heat/heat/tests/test_neutron.py
914:    def test_subnet_deprecated(self):
1387:    def test_router_interface_deprecated(self):
1801:    def test_floating_ip_deprecated(self):

heat/heat/tests/test_neutron_network_gateway.py
233:    def test_network_gateway_create_deprecated(self):

os-refresh-config/os_refresh_config/tests/test_os_refresh_config.py
27:    def test_default_base_dir_deprecated(self):

glance/glance/store/__init__.py
200:                LOG.deprecated(_("%s not found in `known_store`. "

os-apply-config/os_apply_config/tests/test_apply_config.py
293:    def test_default_templates_dir_deprecated(self):
298:    def test_default_templates_dir_old_deprecated(self):

实现

负责人

主要负责人

Doug Hellmann (doug-hellmann)

其他贡献者

里程碑

完成目标里程碑:Juno-1

工作项

  1. ContextAdapter.deprecated() 移动到 log_deprecated_feature() 并更新实现。

  2. 移动 fatal_deprecations 选项定义的地点以及注册它的组。

  3. 更新 Cinder。

  4. 更新 Neutron。

  5. 更新 Glance。

孵化

N/A

采用

N/A

N/A

预计 API 稳定

这个新的 API 应该足够稳定,以便 oslo.versionutils 能够毕业。这项工作将由一个单独的规范/蓝图跟踪。

文档影响

配置选项正在移动到一个新的组,因此文档中生成的示例配置文件和配置表需要更新。

依赖项

参考资料

注意

本作品采用知识共享署名 3.0 非移植许可协议授权。 http://creativecommons.org/licenses/by/3.0/legalcode