)]}'
{"/COMMIT_MSG":[{"author":{"_account_id":7847,"name":"Alistair Coles","email":"alistairncoles@gmail.com","username":"acoles"},"change_message_id":"341c96dd782ae69484792d485bb482b73dacd5aa","unresolved":true,"context_lines":[{"line_number":4,"context_line":"Commit:     Clay Gerrard \u003cclay.gerrard@gmail.com\u003e"},{"line_number":5,"context_line":"CommitDate: 2026-08-03 18:58:51 -0500"},{"line_number":6,"context_line":""},{"line_number":7,"context_line":"test: avoid capture-handler order assumptions"},{"line_number":8,"context_line":""},{"line_number":9,"context_line":"pytest attaches capture handlers to existing non-propagating loggers."},{"line_number":10,"context_line":"Those handlers may format records before Swift\u0027s handlers."}],"source_content_type":"text/x-gerrit-commit-message","patch_set":2,"id":"90067052_e0be8487","line":7,"updated":"2026-08-04 10:18:36.000000000","message":"I\u0027m curious how this manifested and if it was the same as I eventually managed to reproduce (see inline)?\n\nIIUC this patch is making two correcting two different test errors:\n\n1. do not assume the number of handlers that have been installed on a logger\n\n2. other handlers may cause exception logging format to be altered (although I\u0027m yet sure exactly why)","commit_id":"08cce5693940c2907ef1ec06bf1b76496e1e4e37"},{"author":{"_account_id":7847,"name":"Alistair Coles","email":"alistairncoles@gmail.com","username":"acoles"},"change_message_id":"d67689cdd7d857977f4391496c4b3aab47d8f9f1","unresolved":false,"context_lines":[{"line_number":4,"context_line":"Commit:     Clay Gerrard \u003cclay.gerrard@gmail.com\u003e"},{"line_number":5,"context_line":"CommitDate: 2026-08-03 18:58:51 -0500"},{"line_number":6,"context_line":""},{"line_number":7,"context_line":"test: avoid capture-handler order assumptions"},{"line_number":8,"context_line":""},{"line_number":9,"context_line":"pytest attaches capture handlers to existing non-propagating loggers."},{"line_number":10,"context_line":"Those handlers may format records before Swift\u0027s handlers."}],"source_content_type":"text/x-gerrit-commit-message","patch_set":2,"id":"5b4fd6b3_cfd24a95","line":7,"in_reply_to":"90067052_e0be8487","updated":"2026-08-07 13:17:05.000000000","message":"Done","commit_id":"08cce5693940c2907ef1ec06bf1b76496e1e4e37"},{"author":{"_account_id":7847,"name":"Alistair Coles","email":"alistairncoles@gmail.com","username":"acoles"},"change_message_id":"341c96dd782ae69484792d485bb482b73dacd5aa","unresolved":true,"context_lines":[{"line_number":7,"context_line":"test: avoid capture-handler order assumptions"},{"line_number":8,"context_line":""},{"line_number":9,"context_line":"pytest attaches capture handlers to existing non-propagating loggers."},{"line_number":10,"context_line":"Those handlers may format records before Swift\u0027s handlers."},{"line_number":11,"context_line":""},{"line_number":12,"context_line":"Add a reusable isolated logger, then use it only for the prefixed"},{"line_number":13,"context_line":"exception and console-handler tests. Identify SysLog handlers explicitly"}],"source_content_type":"text/x-gerrit-commit-message","patch_set":2,"id":"d67560eb_0dcbfe5d","line":10,"range":{"start_line":10,"start_character":0,"end_line":10,"end_character":58},"updated":"2026-08-04 10:18:36.000000000","message":"I\u0027d love more explanation here, because my understanding is that formatters are attached to handlers, so one handler\u0027s formatting should not impact another handler. However, I wonder if there is some default carriage return/newline formatting built-in to logging i.e. this is not coupling of explicit formatters, but something more implicit.","commit_id":"08cce5693940c2907ef1ec06bf1b76496e1e4e37"},{"author":{"_account_id":7847,"name":"Alistair Coles","email":"alistairncoles@gmail.com","username":"acoles"},"change_message_id":"d67689cdd7d857977f4391496c4b3aab47d8f9f1","unresolved":false,"context_lines":[{"line_number":7,"context_line":"test: avoid capture-handler order assumptions"},{"line_number":8,"context_line":""},{"line_number":9,"context_line":"pytest attaches capture handlers to existing non-propagating loggers."},{"line_number":10,"context_line":"Those handlers may format records before Swift\u0027s handlers."},{"line_number":11,"context_line":""},{"line_number":12,"context_line":"Add a reusable isolated logger, then use it only for the prefixed"},{"line_number":13,"context_line":"exception and console-handler tests. Identify SysLog handlers explicitly"}],"source_content_type":"text/x-gerrit-commit-message","patch_set":2,"id":"d123fec1_e4905b53","line":10,"range":{"start_line":10,"start_character":0,"end_line":10,"end_character":58},"in_reply_to":"d67560eb_0dcbfe5d","updated":"2026-08-07 13:17:05.000000000","message":"Done","commit_id":"08cce5693940c2907ef1ec06bf1b76496e1e4e37"},{"author":{"_account_id":7847,"name":"Alistair Coles","email":"alistairncoles@gmail.com","username":"acoles"},"change_message_id":"341c96dd782ae69484792d485bb482b73dacd5aa","unresolved":true,"context_lines":[{"line_number":9,"context_line":"pytest attaches capture handlers to existing non-propagating loggers."},{"line_number":10,"context_line":"Those handlers may format records before Swift\u0027s handlers."},{"line_number":11,"context_line":""},{"line_number":12,"context_line":"Add a reusable isolated logger, then use it only for the prefixed"},{"line_number":13,"context_line":"exception and console-handler tests. Identify SysLog handlers explicitly"},{"line_number":14,"context_line":"where tests inspect their settings."},{"line_number":15,"context_line":""}],"source_content_type":"text/x-gerrit-commit-message","patch_set":2,"id":"649a83f8_fe803778","line":12,"range":{"start_line":12,"start_character":44,"end_line":12,"end_character":48},"updated":"2026-08-04 10:18:36.000000000","message":"is this \"only\" because it should not be used elsewhere, or \"only\" in order to minimise the diff?","commit_id":"08cce5693940c2907ef1ec06bf1b76496e1e4e37"},{"author":{"_account_id":7847,"name":"Alistair Coles","email":"alistairncoles@gmail.com","username":"acoles"},"change_message_id":"d67689cdd7d857977f4391496c4b3aab47d8f9f1","unresolved":false,"context_lines":[{"line_number":9,"context_line":"pytest attaches capture handlers to existing non-propagating loggers."},{"line_number":10,"context_line":"Those handlers may format records before Swift\u0027s handlers."},{"line_number":11,"context_line":""},{"line_number":12,"context_line":"Add a reusable isolated logger, then use it only for the prefixed"},{"line_number":13,"context_line":"exception and console-handler tests. Identify SysLog handlers explicitly"},{"line_number":14,"context_line":"where tests inspect their settings."},{"line_number":15,"context_line":""}],"source_content_type":"text/x-gerrit-commit-message","patch_set":2,"id":"3913ef83_2cf3dfc0","line":12,"range":{"start_line":12,"start_character":44,"end_line":12,"end_character":48},"in_reply_to":"649a83f8_fe803778","updated":"2026-08-07 13:17:05.000000000","message":"Done","commit_id":"08cce5693940c2907ef1ec06bf1b76496e1e4e37"},{"author":{"_account_id":7847,"name":"Alistair Coles","email":"alistairncoles@gmail.com","username":"acoles"},"change_message_id":"d67689cdd7d857977f4391496c4b3aab47d8f9f1","unresolved":true,"context_lines":[{"line_number":20,"context_line":"Reset module logger state before each test and register the matching"},{"line_number":21,"context_line":"cleanup. Tests that attach and inspect handlers receive a factory with"},{"line_number":22,"context_line":"a unique log route, preventing capture handlers left on shared Swift"},{"line_number":23,"context_line":"loggers from affecting the test under inspection."},{"line_number":24,"context_line":""},{"line_number":25,"context_line":"Assisted-By: Codex:gpt-5.6"},{"line_number":26,"context_line":"Change-Id: Ic98849876ea3aff57cc296662b775d35a17b1299"}],"source_content_type":"text/x-gerrit-commit-message","patch_set":3,"id":"1d4f746b_42a9c8a8","line":23,"updated":"2026-08-07 13:17:05.000000000","message":"nice commit message,  future me will be grateful","commit_id":"5a3f08c2546e54f93a57eaedbbef3cd014b62942"}],"/PATCHSET_LEVEL":[{"author":{"_account_id":7847,"name":"Alistair Coles","email":"alistairncoles@gmail.com","username":"acoles"},"change_message_id":"341c96dd782ae69484792d485bb482b73dacd5aa","unresolved":false,"context_lines":[],"source_content_type":"","patch_set":2,"id":"9cf30d67_c85ef06f","updated":"2026-08-04 10:18:36.000000000","message":"+1 because AFAICT this fixes potential test coupling, assuming my reproducers align with whatever was seen in CI somewhere. kudos for tracking that down.\n\nNot +2 because I\u0027d prefer to maintain a simpler/more explicit fix. Suggestion here \n999704: sq? simpler log_route isolation | https://review.opendev.org/c/openstack/swift/+/999704","commit_id":"08cce5693940c2907ef1ec06bf1b76496e1e4e37"},{"author":{"_account_id":7847,"name":"Alistair Coles","email":"alistairncoles@gmail.com","username":"acoles"},"change_message_id":"4285c6a4a5fc572874e554a19a0ae48ba996e633","unresolved":false,"context_lines":[],"source_content_type":"","patch_set":2,"id":"55b5dc50_fcc46767","updated":"2026-08-04 15:25:12.000000000","message":"oops I didn\u0027t notice the follow up...so maybe we do need the helper functions, but could they live in test_logs.py","commit_id":"08cce5693940c2907ef1ec06bf1b76496e1e4e37"}],"test/debug_logger.py":[{"author":{"_account_id":7847,"name":"Alistair Coles","email":"alistairncoles@gmail.com","username":"acoles"},"change_message_id":"341c96dd782ae69484792d485bb482b73dacd5aa","unresolved":true,"context_lines":[{"line_number":302,"context_line":""},{"line_number":303,"context_line":"def get_isolated_swift_logger(*args, **kwargs):"},{"line_number":304,"context_line":"    \"\"\"Get a Swift logger with a log route unique to this test call.\"\"\""},{"line_number":305,"context_line":"    return get_isolated_get_swift_logger()(*args, **kwargs)"},{"line_number":306,"context_line":""},{"line_number":307,"context_line":""},{"line_number":308,"context_line":"def debug_statsd_client(conf):"}],"source_content_type":"text/x-python","patch_set":2,"id":"5db97b64_59578576","line":305,"updated":"2026-08-04 10:18:36.000000000","message":"IMHO don\u0027t belong in this module because they are setting up real logger test instances rather than fake/debug logging, and they are only used in test_logs.py, so should be in test_logs.py until if/when they are more widely needed.\n\nBut, I also think these functions are a little convoluted an unnecessary - see my sq? patch for a simpler fix.\n\n999704: sq? simpler log_route isolation | https://review.opendev.org/c/openstack/swift/+/999704","commit_id":"08cce5693940c2907ef1ec06bf1b76496e1e4e37"}],"test/unit/common/middleware/test_proxy_logging.py":[{"author":{"_account_id":7847,"name":"Alistair Coles","email":"alistairncoles@gmail.com","username":"acoles"},"change_message_id":"341c96dd782ae69484792d485bb482b73dacd5aa","unresolved":true,"context_lines":[{"line_number":163,"context_line":"        syslog_handlers \u003d [handler for handler in logger.handlers"},{"line_number":164,"context_line":"                           if isinstance(handler, SysLogHandler)]"},{"line_number":165,"context_line":"        self.assertEqual(1, len(syslog_handlers))"},{"line_number":166,"context_line":"        return syslog_handlers[0]"},{"line_number":167,"context_line":""},{"line_number":168,"context_line":"    def assertLabeledUpdateStats(self, exp_metrics_values_labels, statsd\u003dNone):"},{"line_number":169,"context_line":"        statsd \u003d statsd or self.statsd"}],"source_content_type":"text/x-python","patch_set":2,"id":"ff9075df_bb72bde4","line":166,"updated":"2026-08-04 10:18:36.000000000","message":"The test coupling obviously isn\u0027t showing up in zuul CI so I reproduced what I assume is the handler-coupling issue by adding a test that deliberately sets a different handler on the ``proxy-access`` logger:\n\n```\ndiff --git a/test/unit/common/middleware/test_proxy_logging.py b/test/unit/common/middleware/test_proxy_logging.py\nindex c9553d5ed..1c9eb5be6 100644\n--- a/test/unit/common/middleware/test_proxy_logging.py\n+++ b/test/unit/common/middleware/test_proxy_logging.py\n@@ -512,6 +512,25 @@ class TestProxyLogging(BaseTestProxyLogging):\n     def get_v4_amz_date_header(self):\n         return datetime.now(timezone.utc).strftime(\u0027%Y%m%dT%H%M%SZ\u0027)\n \n+    def test_add_handler_coupling(self):\n+        conf \u003d {\n+            \u0027log_headers\u0027: \u0027no\u0027,\n+            \u0027log_statsd_valid_http_methods\u0027: \u0027GET\u0027,\n+            \u0027log_facility\u0027: \u0027LOG_LOCAL7\u0027,\n+            \u0027log_name\u0027: \u0027bob\u0027,\n+            \u0027log_level\u0027: \u0027DEBUG\u0027,\n+            \u0027log_udp_host\u0027: \u0027example.com\u0027,\n+            \u0027log_udp_port\u0027: \u00273456\u0027,\n+            \u0027log_statsd_host\u0027: \u0027example.com\u0027,\n+            \u0027log_statsd_port\u0027: \u00271234\u0027,\n+            \u0027log_statsd_default_sample_rate\u0027: 10,\n+            \u0027log_statsd_sample_rate_factor\u0027: .04,\n+            \u0027log_statsd_metric_prefix\u0027: \u0027foo\u0027,\n+        }\n+        log_adapter \u003d get_swift_logger(conf, name\u003d\u0027proxy-access\u0027)\n+        log_adapter.logger.addHandler(logging.NullHandler())\n+        self.assertEqual(1, len(log_adapter.logger.handlers), log_adapter.logger.handlers)\n+\n     def test_init_logger_and_legacy_statsd_options_log_prefix(self):\n         conf \u003d {\n             \u0027log_headers\u0027: \u0027no\u0027,\n@@ -535,6 +554,7 @@ class TestProxyLogging(BaseTestProxyLogging):\n         self.assertEqual([\u0027GET\u0027], app.valid_methods)\n \n         log_adapter \u003d app.access_logger\n+        self.assertEqual(1, len(log_adapter.logger.handlers), log_adapter.logger.handlers)\n         self.assertEqual(\u0027proxy-access\u0027, log_adapter.name)\n         self.assertEqual(\u0027bob\u0027, app.access_logger.server)\n         self.assertEqual(logging.DEBUG, log_adapter.logger.level)\n\n\n```\n\nthen at least one of these tests will fail, regardless of the order:\n\n```\n% pytest test/unit/common/middleware/test_proxy_logging.py::TestProxyLogging::test_add_handler_coupling test/unit/common/middleware/test_proxy_logging.py::TestProxyLogging::test_init_logger_and_legacy_statsd_options_log_prefix\n\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d test session starts \u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\nplatform darwin -- Python 3.8.15, pytest-8.3.5, pluggy-1.5.0 -- /Users/acoles/.pyenv/versions/3.8.15/envs/swift-3.8.15/bin/python3.8\ncachedir: .pytest_cache\nrootdir: /Users/acoles/0dev/openstack/swift\nconfigfile: tox.ini\nplugins: cov-2.12.1, repeat-0.9.3, reverse-1.7.0, subtests-0.13.1, flake8-1.1.0\ncollected 2 items\n\ntest/unit/common/middleware/test_proxy_logging.py::TestProxyLogging::test_add_handler_coupling FAILED                                  [ 50%]\ntest/unit/common/middleware/test_proxy_logging.py::TestProxyLogging::test_init_logger_and_legacy_statsd_options_log_prefix FAILED      [100%]\n\n\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d FAILURES \u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\n_________________________________________________ TestProxyLogging.test_add_handler_coupling _________________________________________________\n\nself \u003d \u003ctest.unit.common.middleware.test_proxy_logging.TestProxyLogging testMethod\u003dtest_add_handler_coupling\u003e\n\n    def test_add_handler_coupling(self):\n        conf \u003d {\n            \u0027log_headers\u0027: \u0027no\u0027,\n            \u0027log_statsd_valid_http_methods\u0027: \u0027GET\u0027,\n            \u0027log_facility\u0027: \u0027LOG_LOCAL7\u0027,\n            \u0027log_name\u0027: \u0027bob\u0027,\n            \u0027log_level\u0027: \u0027DEBUG\u0027,\n            \u0027log_udp_host\u0027: \u0027example.com\u0027,\n            \u0027log_udp_port\u0027: \u00273456\u0027,\n            \u0027log_statsd_host\u0027: \u0027example.com\u0027,\n            \u0027log_statsd_port\u0027: \u00271234\u0027,\n            \u0027log_statsd_default_sample_rate\u0027: 10,\n            \u0027log_statsd_sample_rate_factor\u0027: .04,\n            \u0027log_statsd_metric_prefix\u0027: \u0027foo\u0027,\n        }\n        log_adapter \u003d get_swift_logger(conf, name\u003d\u0027proxy-access\u0027)\n        log_adapter.logger.addHandler(logging.NullHandler())\n\u003e       self.assertEqual(1, len(log_adapter.logger.handlers), log_adapter.logger.handlers)\nE       AssertionError: 1 !\u003d 2 : [\u003cThreadSafeSysLogHandler (NOTSET)\u003e, \u003cNullHandler (NOTSET)\u003e]\n\ntest/unit/common/middleware/test_proxy_logging.py:532: AssertionError\n___________________________________ TestProxyLogging.test_init_logger_and_legacy_statsd_options_log_prefix ___________________________________\n\nself \u003d \u003ctest.unit.common.middleware.test_proxy_logging.TestProxyLogging testMethod\u003dtest_init_logger_and_legacy_statsd_options_log_prefix\u003e\n\n    def test_init_logger_and_legacy_statsd_options_log_prefix(self):\n        conf \u003d {\n            \u0027log_headers\u0027: \u0027no\u0027,\n            \u0027log_statsd_valid_http_methods\u0027: \u0027GET\u0027,\n            \u0027log_facility\u0027: \u0027LOG_LOCAL7\u0027,\n            \u0027log_name\u0027: \u0027bob\u0027,\n            \u0027log_level\u0027: \u0027DEBUG\u0027,\n            \u0027log_udp_host\u0027: \u0027example.com\u0027,\n            \u0027log_udp_port\u0027: \u00273456\u0027,\n            \u0027log_statsd_host\u0027: \u0027example.com\u0027,\n            \u0027log_statsd_port\u0027: \u00271234\u0027,\n            \u0027log_statsd_default_sample_rate\u0027: 10,\n            \u0027log_statsd_sample_rate_factor\u0027: .04,\n            \u0027log_statsd_metric_prefix\u0027: \u0027foo\u0027,\n        }\n        with mock.patch(\u0027swift.common.statsd_client.StatsdClient\u0027,\n                        FakeStatsdClient):\n            app \u003d proxy_logging.ProxyLoggingMiddleware(FakeApp(), conf)\n\n        self.assertFalse(app.log_hdrs)\n        self.assertEqual([\u0027GET\u0027], app.valid_methods)\n\n        log_adapter \u003d app.access_logger\n\u003e       self.assertEqual(1, len(log_adapter.logger.handlers), log_adapter.logger.handlers)\nE       AssertionError: 1 !\u003d 2 : [\u003cNullHandler (NOTSET)\u003e, \u003cThreadSafeSysLogHandler (NOTSET)\u003e]\n\ntest/unit/common/middleware/test_proxy_logging.py:557: AssertionError\n\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d warnings summary \u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\ntest/unit/common/middleware/test_proxy_logging.py::TestProxyLogging::test_init_logger_and_legacy_statsd_options_log_prefix\n  /Users/acoles/.pyenv/versions/3.8.15/envs/swift-3.8.15/lib/python3.8/site-packages/eventlet/support/greendns.py:379: DeprecationWarning: please use dns.resolver.Resolver.resolve() instead\n    a \u003d fun(*args, **kwargs)\n\n-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html\n\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d short test summary info \u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\nFAILED test/unit/common/middleware/test_proxy_logging.py::TestProxyLogging::test_add_handler_coupling - AssertionError: 1 !\u003d 2 : [\u003cThreadSafeSysLogHandler (NOTSET)\u003e, \u003cNullHandler (NOTSET)\u003e]\nFAILED test/unit/common/middleware/test_proxy_logging.py::TestProxyLogging::test_init_logger_and_legacy_statsd_options_log_prefix - AssertionError: 1 !\u003d 2 : [\u003cNullHandler (NOTSET)\u003e, \u003cThreadSafeSysLogHandler (NOTSET)\u003e]\n\n```\n\nnote how the handler order is swapped between tests, because get_swift_logger removes the syslog handler and then re-adds it !!","commit_id":"08cce5693940c2907ef1ec06bf1b76496e1e4e37"}],"test/unit/common/utils/test_logs.py":[{"author":{"_account_id":7847,"name":"Alistair Coles","email":"alistairncoles@gmail.com","username":"acoles"},"change_message_id":"341c96dd782ae69484792d485bb482b73dacd5aa","unresolved":true,"context_lines":[{"line_number":453,"context_line":"                         \u0027WARNING: MY_SERVER test\\n\u0027)"},{"line_number":454,"context_line":""},{"line_number":455,"context_line":"    @reset_logger_state"},{"line_number":456,"context_line":"    def test_clean_logger_exception(self):"},{"line_number":457,"context_line":"        # setup stream logging"},{"line_number":458,"context_line":"        sio \u003d StringIO()"},{"line_number":459,"context_line":"        logger \u003d get_swift_logger(None)"}],"source_content_type":"text/x-python","patch_set":2,"id":"612a6201_8b3fdcbe","line":456,"updated":"2026-08-04 10:18:36.000000000","message":"hmmm, so why doesn\u0027t this one suffer coupling?\n\n```\n% pytest ./test/unit/common/utils/test_logs.py::TestUtilsLogs::test_log_route_coupling ./test/unit/common/utils/test_logs.py::TestUtilsLogs::test_clean_logger_exception\n\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d test session starts \u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\nplatform darwin -- Python 3.8.15, pytest-8.3.5, pluggy-1.5.0 -- /Users/acoles/.pyenv/versions/3.8.15/envs/swift-3.8.15/bin/python3.8\ncachedir: .pytest_cache\nrootdir: /Users/acoles/0dev/openstack/swift\nconfigfile: tox.ini\nplugins: cov-2.12.1, repeat-0.9.3, reverse-1.7.0, subtests-0.13.1, flake8-1.1.0\ncollected 2 items\n\ntest/unit/common/utils/test_logs.py::TestUtilsLogs::test_log_route_coupling PASSED                                                     [ 50%]\ntest/unit/common/utils/test_logs.py::TestUtilsLogs::test_clean_logger_exception PASSED                                                 [100%]\n\n\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d 2 passed in 2.96s \u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\n```","commit_id":"08cce5693940c2907ef1ec06bf1b76496e1e4e37"},{"author":{"_account_id":7847,"name":"Alistair Coles","email":"alistairncoles@gmail.com","username":"acoles"},"change_message_id":"d67689cdd7d857977f4391496c4b3aab47d8f9f1","unresolved":false,"context_lines":[{"line_number":453,"context_line":"                         \u0027WARNING: MY_SERVER test\\n\u0027)"},{"line_number":454,"context_line":""},{"line_number":455,"context_line":"    @reset_logger_state"},{"line_number":456,"context_line":"    def test_clean_logger_exception(self):"},{"line_number":457,"context_line":"        # setup stream logging"},{"line_number":458,"context_line":"        sio \u003d StringIO()"},{"line_number":459,"context_line":"        logger \u003d get_swift_logger(None)"}],"source_content_type":"text/x-python","patch_set":2,"id":"9929acc8_ffca0c3b","line":456,"in_reply_to":"612a6201_8b3fdcbe","updated":"2026-08-07 13:17:05.000000000","message":"Acknowledged","commit_id":"08cce5693940c2907ef1ec06bf1b76496e1e4e37"},{"author":{"_account_id":7847,"name":"Alistair Coles","email":"alistairncoles@gmail.com","username":"acoles"},"change_message_id":"341c96dd782ae69484792d485bb482b73dacd5aa","unresolved":true,"context_lines":[{"line_number":746,"context_line":"    def test_get_prefixed_swift_logger_exception_method(self):"},{"line_number":747,"context_line":"        # setup stream logging"},{"line_number":748,"context_line":"        sio \u003d StringIO()"},{"line_number":749,"context_line":"        base_logger \u003d get_isolated_swift_logger(None)"},{"line_number":750,"context_line":"        handler \u003d logging.StreamHandler(sio)"},{"line_number":751,"context_line":"        base_logger.logger.addHandler(handler)"},{"line_number":752,"context_line":"        logger \u003d get_prefixed_swift_logger(base_logger, \u0027some prefix: \u0027)"}],"source_content_type":"text/x-python","patch_set":2,"id":"beca6acf_6e812273","line":749,"updated":"2026-08-04 10:18:36.000000000","message":"Using the diff pasted in later comment, this will fail presumably because the first StreamHandler installed by the coupling test is formatting carriage returns before ???\n\n```\n(swift-3.8.15) (acoles) ~/0dev/openstack/swift{master} % pytest ./test/unit/common/utils/test_logs.py::TestUtilsLogs::test_log_route_coupling ./test/unit/common/utils/test_logs.py::TestUtilsLogs::test_get_prefixed_swift_logger_exception_method -sx\n\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d test session starts \u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\nplatform darwin -- Python 3.8.15, pytest-8.3.5, pluggy-1.5.0 -- /Users/acoles/.pyenv/versions/3.8.15/envs/swift-3.8.15/bin/python3.8\ncachedir: .pytest_cache\nrootdir: /Users/acoles/0dev/openstack/swift\nconfigfile: tox.ini\nplugins: cov-2.12.1, repeat-0.9.3, reverse-1.7.0, subtests-0.13.1, flake8-1.1.0\ncollecting ... Unable to read test config /etc/swift/test.conf - file not found\ncollected 2 items\n\ntest/unit/common/utils/test_logs.py::TestUtilsLogs::test_log_route_coupling PASSED\ntest/unit/common/utils/test_logs.py::TestUtilsLogs::test_get_prefixed_swift_logger_exception_method some prefix: blah: [Errno 5] my 5 error message\nsome prefix: blah: [Errno 28] my 28 error message\nsome prefix: blah: BadStatusLine(\u0027my error message\u0027)\nsome prefix: blah: ConnectionTimeout (99s)\nsome prefix: blah:\nTraceback (most recent call last):\n  File \"/Users/acoles/0dev/openstack/swift/test/unit/common/utils/test_logs.py\", line 762, in log_exception\n    raise exc\nOSError\nFAILED\n\n\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d FAILURES \u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\n_______________________________________ TestUtilsLogs.test_get_prefixed_swift_logger_exception_method ________________________________________\n\nself \u003d \u003ctest.unit.common.utils.test_logs.TestUtilsLogs testMethod\u003dtest_get_prefixed_swift_logger_exception_method\u003e\n\n    @reset_logger_state\n    def test_get_prefixed_swift_logger_exception_method(self):\n        # setup stream logging\n        sio \u003d StringIO()\n        base_logger \u003d get_swift_logger(None)\n        handler \u003d logging.StreamHandler(sio)\n        base_logger.logger.addHandler(handler)\n        logger \u003d get_prefixed_swift_logger(base_logger, \u0027some prefix: \u0027)\n\n        def strip_value(sio):\n            sio.seek(0)\n            v \u003d sio.getvalue()\n            sio.truncate(0)\n            return v\n\n        def log_exception(exc):\n            try:\n                raise exc\n            except (Exception, Timeout):\n                logger.exception(\u0027blah\u0027)\n            msg_lines \u003d strip_value(sio).strip().split(\u0027\\n\u0027)\n            return msg_lines\n\n        try:\n            # test OSError\n            for en in (errno.EIO, errno.ENOSPC):\n                exc \u003d OSError(en, \u0027my %s error message\u0027 % en)\n                log_msg_lines \u003d log_exception(exc)\n                self.assertEqual(1, len(log_msg_lines))\n                self.assertEqual(\u0027some prefix: blah: %s\u0027 % exc,\n                                 log_msg_lines[0])\n\n            # BadStatusLine\n            exc \u003d http.client.BadStatusLine(\u0027my error message\u0027)\n            log_msg_lines \u003d log_exception(exc)\n            self.assertEqual(1, len(log_msg_lines))\n            self.assertEqual(\"some prefix: blah: %r\" % exc, log_msg_lines[0])\n\n            # Timeout\n            with ConnectionTimeout(99) as exc:\n                log_msg_lines \u003d log_exception(exc)\n            self.assertEqual(1, len(log_msg_lines))\n            self.assertNotIn(\u0027Traceback\u0027, log_msg_lines[0])\n            self.assertEqual(\"some prefix: blah: ConnectionTimeout (99s)\",\n                             log_msg_lines[0])\n\n            # unfiltered\n            for exc in (OSError(), ValueError()):\n                log_msg_lines \u003d log_exception(exc)\n\u003e               self.assertEqual(2, len(log_msg_lines), log_msg_lines)\nE               AssertionError: 2 !\u003d 5 : [\u0027some prefix: blah: \u0027, \u0027Traceback (most recent call last):\u0027, \u0027  File \"/Users/acoles/0dev/openstack/swift/test/unit/common/utils/test_logs.py\", line 762, in log_exception\u0027, \u0027    raise exc\u0027, \u0027OSError\u0027]\n\ntest/unit/common/utils/test_logs.py:794: AssertionError\n\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d short test summary info \u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\nFAILED test/unit/common/utils/test_logs.py::TestUtilsLogs::test_get_prefixed_swift_logger_exception_method - AssertionError: 2 !\u003d 5 : [\u0027some prefix: blah: \u0027, \u0027Traceback (most recent call last):\u0027, \u0027  File \"/Users/acoles/0dev/openstack/swift/test/u...\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d 1 failed, 1 passed in 0.80s \u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\n```","commit_id":"08cce5693940c2907ef1ec06bf1b76496e1e4e37"},{"author":{"_account_id":7847,"name":"Alistair Coles","email":"alistairncoles@gmail.com","username":"acoles"},"change_message_id":"d67689cdd7d857977f4391496c4b3aab47d8f9f1","unresolved":false,"context_lines":[{"line_number":746,"context_line":"    def test_get_prefixed_swift_logger_exception_method(self):"},{"line_number":747,"context_line":"        # setup stream logging"},{"line_number":748,"context_line":"        sio \u003d StringIO()"},{"line_number":749,"context_line":"        base_logger \u003d get_isolated_swift_logger(None)"},{"line_number":750,"context_line":"        handler \u003d logging.StreamHandler(sio)"},{"line_number":751,"context_line":"        base_logger.logger.addHandler(handler)"},{"line_number":752,"context_line":"        logger \u003d get_prefixed_swift_logger(base_logger, \u0027some prefix: \u0027)"}],"source_content_type":"text/x-python","patch_set":2,"id":"114f1418_914c1fbd","line":749,"in_reply_to":"beca6acf_6e812273","updated":"2026-08-07 13:17:05.000000000","message":"Acknowledged","commit_id":"08cce5693940c2907ef1ec06bf1b76496e1e4e37"},{"author":{"_account_id":7847,"name":"Alistair Coles","email":"alistairncoles@gmail.com","username":"acoles"},"change_message_id":"341c96dd782ae69484792d485bb482b73dacd5aa","unresolved":true,"context_lines":[{"line_number":960,"context_line":"                                        utils.logs.LoggerFileObject))"},{"line_number":961,"context_line":""},{"line_number":962,"context_line":"    @reset_logger_state"},{"line_number":963,"context_line":"    def test_get_swift_logger_console(self):"},{"line_number":964,"context_line":"        get_logger \u003d get_isolated_get_swift_logger()"},{"line_number":965,"context_line":"        logger \u003d get_logger(None)"},{"line_number":966,"context_line":"        console_handlers \u003d [h for h in logger.logger.handlers if"}],"source_content_type":"text/x-python","patch_set":2,"id":"bbab5e80_c2a9605b","line":963,"updated":"2026-08-04 10:18:36.000000000","message":"I can reproduce a coupling issue here using:\n\n```\ndiff --git a/test/unit/common/utils/test_logs.py b/test/unit/common/utils/test_logs.py\nindex 7a536f91c..d32589bd1 100644\n--- a/test/unit/common/utils/test_logs.py\n+++ b/test/unit/common/utils/test_logs.py\n@@ -957,6 +957,10 @@ class TestUtilsLogs(unittest.TestCase):\n             self.assertFalse(isinstance(mock_sys.stderr,\n                                         utils.logs.LoggerFileObject))\n \n+    def test_log_route_coupling(self):\n+        logger \u003d get_swift_logger(None)\n+        logger.logger.addHandler(logging.StreamHandler())\n+\n     @reset_logger_state\n     def test_get_swift_logger_console(self):\n         logger \u003d get_swift_logger(None)\n\n```\n\nand then:\n\n```\n% pytest ./test/unit/common/utils/test_logs.py::TestUtilsLogs::test_log_route_coupling ./test/unit/common/utils/test_logs.py::TestUtilsLogs::test_get_swift_logger_console\n\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d test session starts \u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\nplatform darwin -- Python 3.8.15, pytest-8.3.5, pluggy-1.5.0 -- /Users/acoles/.pyenv/versions/3.8.15/envs/swift-3.8.15/bin/python3.8\ncachedir: .pytest_cache\nrootdir: /Users/acoles/0dev/openstack/swift\nconfigfile: tox.ini\nplugins: cov-2.12.1, repeat-0.9.3, reverse-1.7.0, subtests-0.13.1, flake8-1.1.0\ncollected 2 items\n\ntest/unit/common/utils/test_logs.py::TestUtilsLogs::test_log_route_coupling PASSED                                                     [ 50%]\ntest/unit/common/utils/test_logs.py::TestUtilsLogs::test_get_swift_logger_console FAILED                                               [100%]\n\n\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d FAILURES \u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\n________________________________________________ TestUtilsLogs.test_get_swift_logger_console _________________________________________________\n\nself \u003d \u003ctest.unit.common.utils.test_logs.TestUtilsLogs testMethod\u003dtest_get_swift_logger_console\u003e\n\n    @reset_logger_state\n    def test_get_swift_logger_console(self):\n        logger \u003d get_swift_logger(None)\n        console_handlers \u003d [h for h in logger.logger.handlers if\n                            isinstance(h, logging.StreamHandler)]\n\u003e       self.assertFalse(console_handlers)\nE       AssertionError: [\u003cStreamHandler \u003c_io.FileIO name\u003d8 mode\u003d\u0027rb+\u0027 closefd\u003dTrue\u003e (NOTSET)\u003e] is not false\n\ntest/unit/common/utils/test_logs.py:969: AssertionError\n\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d short test summary info \u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\nFAILED test/unit/common/utils/test_logs.py::TestUtilsLogs::test_get_swift_logger_console - AssertionError: [\u003cStreamHandler \u003c_io.FileIO name\u003d8 mode\u003d\u0027rb+\u0027 closefd\u003dTrue\u003e (NOTSET)\u003e] is not false\n\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d 1 failed, 1 passed in 0.94s \u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\n```","commit_id":"08cce5693940c2907ef1ec06bf1b76496e1e4e37"},{"author":{"_account_id":7847,"name":"Alistair Coles","email":"alistairncoles@gmail.com","username":"acoles"},"change_message_id":"d67689cdd7d857977f4391496c4b3aab47d8f9f1","unresolved":false,"context_lines":[{"line_number":960,"context_line":"                                        utils.logs.LoggerFileObject))"},{"line_number":961,"context_line":""},{"line_number":962,"context_line":"    @reset_logger_state"},{"line_number":963,"context_line":"    def test_get_swift_logger_console(self):"},{"line_number":964,"context_line":"        get_logger \u003d get_isolated_get_swift_logger()"},{"line_number":965,"context_line":"        logger \u003d get_logger(None)"},{"line_number":966,"context_line":"        console_handlers \u003d [h for h in logger.logger.handlers if"}],"source_content_type":"text/x-python","patch_set":2,"id":"b719d332_664e5717","line":963,"in_reply_to":"bbab5e80_c2a9605b","updated":"2026-08-07 13:17:05.000000000","message":"Acknowledged","commit_id":"08cce5693940c2907ef1ec06bf1b76496e1e4e37"},{"author":{"_account_id":7847,"name":"Alistair Coles","email":"alistairncoles@gmail.com","username":"acoles"},"change_message_id":"341c96dd782ae69484792d485bb482b73dacd5aa","unresolved":true,"context_lines":[{"line_number":961,"context_line":""},{"line_number":962,"context_line":"    @reset_logger_state"},{"line_number":963,"context_line":"    def test_get_swift_logger_console(self):"},{"line_number":964,"context_line":"        get_logger \u003d get_isolated_get_swift_logger()"},{"line_number":965,"context_line":"        logger \u003d get_logger(None)"},{"line_number":966,"context_line":"        console_handlers \u003d [h for h in logger.logger.handlers if"},{"line_number":967,"context_line":"                            isinstance(h, logging.StreamHandler)]"}],"source_content_type":"text/x-python","patch_set":2,"id":"49611498_77fe01f0","line":964,"range":{"start_line":964,"start_character":8,"end_line":964,"end_character":18},"updated":"2026-08-04 10:18:36.000000000","message":"I\u0027d prefer a different name here that doesn\u0027t collide with the familiar ``utils.get_logger`` function, and ideally the name should very explicitly indicate the fixed up factory function e.g. ``isolated_get_swift_logger \u003d get_isolated_get_swift_logger()``\n\nbut I also think the functions are overkill, see sq follow-up patch\n999704: sq? simpler log_route isolation | https://review.opendev.org/c/openstack/swift/+/999704","commit_id":"08cce5693940c2907ef1ec06bf1b76496e1e4e37"},{"author":{"_account_id":7847,"name":"Alistair Coles","email":"alistairncoles@gmail.com","username":"acoles"},"change_message_id":"d67689cdd7d857977f4391496c4b3aab47d8f9f1","unresolved":false,"context_lines":[{"line_number":961,"context_line":""},{"line_number":962,"context_line":"    @reset_logger_state"},{"line_number":963,"context_line":"    def test_get_swift_logger_console(self):"},{"line_number":964,"context_line":"        get_logger \u003d get_isolated_get_swift_logger()"},{"line_number":965,"context_line":"        logger \u003d get_logger(None)"},{"line_number":966,"context_line":"        console_handlers \u003d [h for h in logger.logger.handlers if"},{"line_number":967,"context_line":"                            isinstance(h, logging.StreamHandler)]"}],"source_content_type":"text/x-python","patch_set":2,"id":"68dc28f6_182f7b1a","line":964,"range":{"start_line":964,"start_character":8,"end_line":964,"end_character":18},"in_reply_to":"49611498_77fe01f0","updated":"2026-08-07 13:17:05.000000000","message":"Done","commit_id":"08cce5693940c2907ef1ec06bf1b76496e1e4e37"},{"author":{"_account_id":7847,"name":"Alistair Coles","email":"alistairncoles@gmail.com","username":"acoles"},"change_message_id":"341c96dd782ae69484792d485bb482b73dacd5aa","unresolved":true,"context_lines":[{"line_number":973,"context_line":"        # make sure you can\u0027t have two console handlers"},{"line_number":974,"context_line":"        self.assertEqual(len(console_handlers), 1)"},{"line_number":975,"context_line":"        old_handler \u003d console_handlers[0]"},{"line_number":976,"context_line":"        logger \u003d get_logger(None, log_to_console\u003dTrue)"},{"line_number":977,"context_line":"        console_handlers \u003d [h for h in logger.logger.handlers if"},{"line_number":978,"context_line":"                            isinstance(h, logging.StreamHandler)]"},{"line_number":979,"context_line":"        self.assertEqual(len(console_handlers), 1)"}],"source_content_type":"text/x-python","patch_set":2,"id":"435117d6_36998178","line":976,"updated":"2026-08-04 10:18:36.000000000","message":"...I fear that future me could stare at this for a long time before realising this is NOT ``utils.get_logger``","commit_id":"08cce5693940c2907ef1ec06bf1b76496e1e4e37"},{"author":{"_account_id":7847,"name":"Alistair Coles","email":"alistairncoles@gmail.com","username":"acoles"},"change_message_id":"d67689cdd7d857977f4391496c4b3aab47d8f9f1","unresolved":false,"context_lines":[{"line_number":973,"context_line":"        # make sure you can\u0027t have two console handlers"},{"line_number":974,"context_line":"        self.assertEqual(len(console_handlers), 1)"},{"line_number":975,"context_line":"        old_handler \u003d console_handlers[0]"},{"line_number":976,"context_line":"        logger \u003d get_logger(None, log_to_console\u003dTrue)"},{"line_number":977,"context_line":"        console_handlers \u003d [h for h in logger.logger.handlers if"},{"line_number":978,"context_line":"                            isinstance(h, logging.StreamHandler)]"},{"line_number":979,"context_line":"        self.assertEqual(len(console_handlers), 1)"}],"source_content_type":"text/x-python","patch_set":2,"id":"8ccc1275_7c7317ef","line":976,"in_reply_to":"435117d6_36998178","updated":"2026-08-07 13:17:05.000000000","message":"Done","commit_id":"08cce5693940c2907ef1ec06bf1b76496e1e4e37"},{"author":{"_account_id":7847,"name":"Alistair Coles","email":"alistairncoles@gmail.com","username":"acoles"},"change_message_id":"d67689cdd7d857977f4391496c4b3aab47d8f9f1","unresolved":true,"context_lines":[{"line_number":968,"context_line":"                                        utils.logs.LoggerFileObject))"},{"line_number":969,"context_line":""},{"line_number":970,"context_line":"    @with_isolated_logger"},{"line_number":971,"context_line":"    def test_get_swift_logger_console(self, get_isolated_logger):"},{"line_number":972,"context_line":"        logger \u003d get_isolated_logger(None)"},{"line_number":973,"context_line":"        console_handlers \u003d [h for h in logger.logger.handlers if"},{"line_number":974,"context_line":"                            isinstance(h, logging.StreamHandler)]"}],"source_content_type":"text/x-python","patch_set":3,"id":"a6abfde5_d98792e7","line":971,"updated":"2026-08-07 13:17:05.000000000","message":"FWIW I reassured myself that this test is dealing with  single ``Logger`` instance:\n\n```\ndiff --git a/test/unit/common/utils/test_logs.py b/test/unit/common/utils/test_logs.py\nindex c4860644a..3f94b95f3 100644\n--- a/test/unit/common/utils/test_logs.py\n+++ b/test/unit/common/utils/test_logs.py\n@@ -970,10 +970,12 @@ class TestUtilsLogs(BaseTestCase):\n     @with_isolated_logger\n     def test_get_swift_logger_console(self, get_isolated_logger):\n         logger \u003d get_isolated_logger(None)\n+        core_logger \u003d logger.logger\n         console_handlers \u003d [h for h in logger.logger.handlers if\n                             isinstance(h, logging.StreamHandler)]\n         self.assertFalse(console_handlers)\n         logger \u003d get_isolated_logger(None, log_to_console\u003dTrue)\n+        self.assertIs(core_logger, logger.logger)\n         console_handlers \u003d [h for h in logger.logger.handlers if\n                             isinstance(h, logging.StreamHandler)]\n         self.assertTrue(console_handlers)\n@@ -981,6 +983,7 @@ class TestUtilsLogs(BaseTestCase):\n         self.assertEqual(len(console_handlers), 1)\n         old_handler \u003d console_handlers[0]\n         logger \u003d get_isolated_logger(None, log_to_console\u003dTrue)\n+        self.assertIs(core_logger, logger.logger)\n         console_handlers \u003d [h for h in logger.logger.handlers if\n                             isinstance(h, logging.StreamHandler)]\n         self.assertEqual(len(console_handlers), 1)\n\n```","commit_id":"5a3f08c2546e54f93a57eaedbbef3cd014b62942"}]}
