)]}'
{"/COMMIT_MSG":[{"author":{"_account_id":38767,"name":"Wael Halbawi","display_name":"Wael Halbawi","email":"whalbawi@nvidia.com","username":"whalbawi"},"change_message_id":"ad3f89585e29271466d0cb47deeeb68215272dc2","unresolved":true,"context_lines":[{"line_number":4,"context_line":"Commit:     shreeyad \u003cshreeyad@nvidia.com\u003e"},{"line_number":5,"context_line":"CommitDate: 2026-05-15 13:29:10 -0500"},{"line_number":6,"context_line":""},{"line_number":7,"context_line":"add prom metrics to dispersion report"},{"line_number":8,"context_line":""},{"line_number":9,"context_line":"Change-Id: I18206720b1fcffe63e6c0e968ec7de5cfd7786ed"},{"line_number":10,"context_line":"Signed-off-by: Shreeya Deshpande \u003cshreeyad@nvidia.com\u003e"}],"source_content_type":"text/x-gerrit-commit-message","patch_set":13,"id":"0d077f37_111915d6","line":7,"updated":"2026-05-18 22:01:50.000000000","message":"I think it\u0027s useful to describe the scope of the change, what metrics are being emitted and why.","commit_id":"d43b4af67d87eb1f98707fed6b3ff433f00a6d5f"},{"author":{"_account_id":7233,"name":"Matthew Oliver","email":"matt@oliver.net.au","username":"mattoliverau"},"change_message_id":"ec08556bc082dbf4c7572c5e0ff1d388a0f936c7","unresolved":true,"context_lines":[{"line_number":4,"context_line":"Commit:     shreeyad \u003cshreeyad@nvidia.com\u003e"},{"line_number":5,"context_line":"CommitDate: 2026-05-15 13:29:10 -0500"},{"line_number":6,"context_line":""},{"line_number":7,"context_line":"add prom metrics to dispersion report"},{"line_number":8,"context_line":""},{"line_number":9,"context_line":"Change-Id: I18206720b1fcffe63e6c0e968ec7de5cfd7786ed"},{"line_number":10,"context_line":"Signed-off-by: Shreeya Deshpande \u003cshreeyad@nvidia.com\u003e"}],"source_content_type":"text/x-gerrit-commit-message","patch_set":13,"id":"a2b1c900_626278f6","line":7,"in_reply_to":"0d077f37_111915d6","updated":"2026-05-21 02:05:10.000000000","message":"Yeah, what Wael said. Here is the link to what openstack/opendev commit messages should look like:\nhttps://wiki.openstack.org/wiki/GitCommitMessages#Summary_of_Git_commit_message_structure","commit_id":"d43b4af67d87eb1f98707fed6b3ff433f00a6d5f"},{"author":{"_account_id":35790,"name":"Shreeya Deshpande","email":"shreeyad@nvidia.com","username":"shreeyad"},"change_message_id":"c3e08cd5bf3119b0547abbde356f6fdedb898b44","unresolved":false,"context_lines":[{"line_number":4,"context_line":"Commit:     shreeyad \u003cshreeyad@nvidia.com\u003e"},{"line_number":5,"context_line":"CommitDate: 2026-05-15 13:29:10 -0500"},{"line_number":6,"context_line":""},{"line_number":7,"context_line":"add prom metrics to dispersion report"},{"line_number":8,"context_line":""},{"line_number":9,"context_line":"Change-Id: I18206720b1fcffe63e6c0e968ec7de5cfd7786ed"},{"line_number":10,"context_line":"Signed-off-by: Shreeya Deshpande \u003cshreeyad@nvidia.com\u003e"}],"source_content_type":"text/x-gerrit-commit-message","patch_set":13,"id":"28db8a81_fad54552","line":7,"in_reply_to":"a2b1c900_626278f6","updated":"2026-05-21 21:49:26.000000000","message":"Done","commit_id":"d43b4af67d87eb1f98707fed6b3ff433f00a6d5f"}],"/PATCHSET_LEVEL":[{"author":{"_account_id":38767,"name":"Wael Halbawi","display_name":"Wael Halbawi","email":"whalbawi@nvidia.com","username":"whalbawi"},"change_message_id":"ad3f89585e29271466d0cb47deeeb68215272dc2","unresolved":false,"context_lines":[],"source_content_type":"","patch_set":13,"id":"8b0bf3e2_ab50161d","updated":"2026-05-18 22:01:50.000000000","message":"Most of my comments are about clarification of scope. I think the integration work with `PrometheusClient` LGTM modulo a few minor comments. Happy to take another look once these comments are addressed.","commit_id":"d43b4af67d87eb1f98707fed6b3ff433f00a6d5f"},{"author":{"_account_id":1179,"name":"Clay Gerrard","email":"clay.gerrard@gmail.com","username":"clay-gerrard"},"change_message_id":"d7553688a4dd66be2c1630cf986c5d31061ecb06","unresolved":false,"context_lines":[],"source_content_type":"","patch_set":20,"id":"c2bf8a76_b1c410fb","updated":"2026-05-27 06:36:17.000000000","message":"I think we have to get the dispersion report tests better situated before we can add these new behaviors; a lot of the \"how should this behave\" questions would be easier to explore if we had some test infra to help us out.","commit_id":"a92db4071a3dcf4e4e7da3e0d0dc8be5b0c1e360"},{"author":{"_account_id":35790,"name":"Shreeya Deshpande","email":"shreeyad@nvidia.com","username":"shreeyad"},"change_message_id":"3f356b444847a4aee691879f10c79da5ead9e7ac","unresolved":false,"context_lines":[],"source_content_type":"","patch_set":26,"id":"a471cc43_5e16567d","updated":"2026-07-15 16:30:51.000000000","message":"recheck","commit_id":"30c1b36c9958838490851bacdfac4eda68514755"},{"author":{"_account_id":1179,"name":"Clay Gerrard","email":"clay.gerrard@gmail.com","username":"clay-gerrard"},"change_message_id":"f4b675b73574e7fd3378c73a59286d2770e3aed0","unresolved":false,"context_lines":[],"source_content_type":"","patch_set":31,"id":"bb52942a_1017d67a","updated":"2026-08-12 19:47:14.000000000","message":"probably back out the direct client changes\n\n^ blocker?\n\nmaybe move the prom client changes to the prom client change\n\n^ probably helps people ramp up on the interface w/ having it immediately change on them.  I think it will be hard to make sense of the `write_all_stats` sometimes not actually writing any stats in isolation tho - so we might have to think of a different affordance there...","commit_id":"18867fed23f40bf2117321bc895bf8b0a31abd5f"},{"author":{"_account_id":6968,"name":"Christian Schwede","email":"cschwede@nvidia.com","username":"cschwede"},"change_message_id":"94e9721088820c5a45e8bebabe75c50196537916","unresolved":false,"context_lines":[],"source_content_type":"","patch_set":35,"id":"9eeb11be_63aace1f","updated":"2026-08-17 09:56:56.000000000","message":"There is a blocker here - running `swift-dispersion-report` drops metrics written to `metrics_filename` if using multiple policies.\n\nFor example, on a default SAIO:\n\n```\n$ head /etc/swift/dispersion.conf \n[dispersion]\nmetrics_filename \u003d /tmp/dispersion.prom\n\n$ swift-dispersion-populate # default policy\n$ swift-dispersion-populate -P ec # also populate EC policy\n$ swift-dispersion-report\n# /tmp/dispersion.prom now contains entries with the default policy\n$ swift-dispersion-report -P ec\n# /tmp/dispersion.prom now contains entries with the EC policy, any default policy entries are now lost\n```\n\nOne easy option to solve this would be to document that there should be different configuraton files with different `metrics_filename` settings when using multiple policies. For example:\n```\n$ swift-dispersion-report -P default /etc/swift/dispersion_default.conf\n$ swift-dispersion-report -P ec /etc/swift/dispersion_ec.conf \n```","commit_id":"666504708c2d178654aa955830f581a8ec374452"},{"author":{"_account_id":15343,"name":"Tim Burke","email":"tburke@nvidia.com","username":"tburke"},"change_message_id":"9c6154e2387e517c97e955e4be18f467f1539068","unresolved":false,"context_lines":[],"source_content_type":"","patch_set":38,"id":"12991df9_41952208","updated":"2026-08-20 16:36:42.000000000","message":"The `if not missing_copies` filter for objects and not containers seems wrong.\n\nI don\u0027t want to scope-creep too bad, but I wonder if there should be a pre-req to do... something... with the container report and how it handles storage policies.","commit_id":"26f57d0f85308e1e6ef67aeaab127d713180929c"}],"swift/cli/dispersion_report.py":[{"author":{"_account_id":1179,"name":"Clay Gerrard","email":"clay.gerrard@gmail.com","username":"clay-gerrard"},"change_message_id":"c36d34ba7ab384f3d592ac4775ecb5a642410a49","unresolved":true,"context_lines":[{"line_number":38,"context_line":"json_output \u003d False"},{"line_number":39,"context_line":"debug \u003d False"},{"line_number":40,"context_line":"insecure \u003d False"},{"line_number":41,"context_line":"prom_client \u003d None"},{"line_number":42,"context_line":""},{"line_number":43,"context_line":""},{"line_number":44,"context_line":"def get_error_log(prefix):"}],"source_content_type":"text/x-python","patch_set":13,"id":"880a2e99_ba3c2b25","line":41,"updated":"2026-05-18 19:09:31.000000000","message":"i would try to avoid addig new globals if possible","commit_id":"d43b4af67d87eb1f98707fed6b3ff433f00a6d5f"},{"author":{"_account_id":35790,"name":"Shreeya Deshpande","email":"shreeyad@nvidia.com","username":"shreeyad"},"change_message_id":"c3e08cd5bf3119b0547abbde356f6fdedb898b44","unresolved":false,"context_lines":[{"line_number":38,"context_line":"json_output \u003d False"},{"line_number":39,"context_line":"debug \u003d False"},{"line_number":40,"context_line":"insecure \u003d False"},{"line_number":41,"context_line":"prom_client \u003d None"},{"line_number":42,"context_line":""},{"line_number":43,"context_line":""},{"line_number":44,"context_line":"def get_error_log(prefix):"}],"source_content_type":"text/x-python","patch_set":13,"id":"ca89fa6e_22b82f48","line":41,"in_reply_to":"880a2e99_ba3c2b25","updated":"2026-05-21 21:49:26.000000000","message":"Done","commit_id":"d43b4af67d87eb1f98707fed6b3ff433f00a6d5f"},{"author":{"_account_id":38767,"name":"Wael Halbawi","display_name":"Wael Halbawi","email":"whalbawi@nvidia.com","username":"whalbawi"},"change_message_id":"ad3f89585e29271466d0cb47deeeb68215272dc2","unresolved":true,"context_lines":[{"line_number":146,"context_line":"                           copies_found, labels)"},{"line_number":147,"context_line":"        prom_client.record(\u0027swift_dispersion_container_copies_expected\u0027,"},{"line_number":148,"context_line":"                           copies_expected, labels)"},{"line_number":149,"context_line":"        prom_client.record(\u0027swift_dispersion_container_pct_found\u0027,"},{"line_number":150,"context_line":"                           value, labels)"},{"line_number":151,"context_line":"        prom_client.record(\u0027swift_dispersion_container_retries\u0027,"},{"line_number":152,"context_line":"                           retries_done[0], labels)"}],"source_content_type":"text/x-python","patch_set":13,"id":"35199f47_a20c43a1","line":149,"updated":"2026-05-18 22:01:50.000000000","message":"Seems like a redundant stream. Can be derived from the first two metrics.","commit_id":"d43b4af67d87eb1f98707fed6b3ff433f00a6d5f"},{"author":{"_account_id":35790,"name":"Shreeya Deshpande","email":"shreeyad@nvidia.com","username":"shreeyad"},"change_message_id":"c3e08cd5bf3119b0547abbde356f6fdedb898b44","unresolved":false,"context_lines":[{"line_number":146,"context_line":"                           copies_found, labels)"},{"line_number":147,"context_line":"        prom_client.record(\u0027swift_dispersion_container_copies_expected\u0027,"},{"line_number":148,"context_line":"                           copies_expected, labels)"},{"line_number":149,"context_line":"        prom_client.record(\u0027swift_dispersion_container_pct_found\u0027,"},{"line_number":150,"context_line":"                           value, labels)"},{"line_number":151,"context_line":"        prom_client.record(\u0027swift_dispersion_container_retries\u0027,"},{"line_number":152,"context_line":"                           retries_done[0], labels)"}],"source_content_type":"text/x-python","patch_set":13,"id":"e48484f4_1d718c82","line":149,"in_reply_to":"35199f47_a20c43a1","updated":"2026-05-21 21:49:26.000000000","message":"Acknowledged","commit_id":"d43b4af67d87eb1f98707fed6b3ff433f00a6d5f"},{"author":{"_account_id":38767,"name":"Wael Halbawi","display_name":"Wael Halbawi","email":"whalbawi@nvidia.com","username":"whalbawi"},"change_message_id":"ad3f89585e29271466d0cb47deeeb68215272dc2","unresolved":true,"context_lines":[{"line_number":275,"context_line":"                           copies_found, labels)"},{"line_number":276,"context_line":"        prom_client.record(\u0027swift_dispersion_object_copies_expected\u0027,"},{"line_number":277,"context_line":"                           copies_expected, labels)"},{"line_number":278,"context_line":"        prom_client.record(\u0027swift_dispersion_object_pct_found\u0027,"},{"line_number":279,"context_line":"                           value, labels)"},{"line_number":280,"context_line":"        prom_client.record(\u0027swift_dispersion_object_retries\u0027,"},{"line_number":281,"context_line":"                           retries_done[0], labels)"}],"source_content_type":"text/x-python","patch_set":13,"id":"22811627_8417e04c","line":278,"updated":"2026-05-18 22:01:50.000000000","message":"Seems like a redundant stream. Can be derived from the first two metrics.","commit_id":"d43b4af67d87eb1f98707fed6b3ff433f00a6d5f"},{"author":{"_account_id":35790,"name":"Shreeya Deshpande","email":"shreeyad@nvidia.com","username":"shreeyad"},"change_message_id":"c3e08cd5bf3119b0547abbde356f6fdedb898b44","unresolved":false,"context_lines":[{"line_number":275,"context_line":"                           copies_found, labels)"},{"line_number":276,"context_line":"        prom_client.record(\u0027swift_dispersion_object_copies_expected\u0027,"},{"line_number":277,"context_line":"                           copies_expected, labels)"},{"line_number":278,"context_line":"        prom_client.record(\u0027swift_dispersion_object_pct_found\u0027,"},{"line_number":279,"context_line":"                           value, labels)"},{"line_number":280,"context_line":"        prom_client.record(\u0027swift_dispersion_object_retries\u0027,"},{"line_number":281,"context_line":"                           retries_done[0], labels)"}],"source_content_type":"text/x-python","patch_set":13,"id":"0456e341_ac2c3ec2","line":278,"in_reply_to":"22811627_8417e04c","updated":"2026-05-21 21:49:26.000000000","message":"Acknowledged","commit_id":"d43b4af67d87eb1f98707fed6b3ff433f00a6d5f"},{"author":{"_account_id":1179,"name":"Clay Gerrard","email":"clay.gerrard@gmail.com","username":"clay-gerrard"},"change_message_id":"c36d34ba7ab384f3d592ac4775ecb5a642410a49","unresolved":true,"context_lines":[{"line_number":401,"context_line":"        from swiftclient import get_auth"},{"line_number":402,"context_line":"    except ImportError:"},{"line_number":403,"context_line":"        from swift.common.internal_client import get_auth"},{"line_number":404,"context_line":"    global json_output, prom_client"},{"line_number":405,"context_line":"    json_output \u003d config_true_value(conf.get(\u0027dump_json\u0027, \u0027no\u0027))"},{"line_number":406,"context_line":"    if policy_name is None:"},{"line_number":407,"context_line":"        policy \u003d POLICIES.default"}],"source_content_type":"text/x-python","patch_set":13,"id":"b3f7f203_6f1c7e5e","line":404,"updated":"2026-05-18 19:09:31.000000000","message":"i *think* all the plumbing for `prom_client` is already done - you can just define `prom_client \u003d None` here?","commit_id":"d43b4af67d87eb1f98707fed6b3ff433f00a6d5f"},{"author":{"_account_id":35790,"name":"Shreeya Deshpande","email":"shreeyad@nvidia.com","username":"shreeyad"},"change_message_id":"c3e08cd5bf3119b0547abbde356f6fdedb898b44","unresolved":false,"context_lines":[{"line_number":401,"context_line":"        from swiftclient import get_auth"},{"line_number":402,"context_line":"    except ImportError:"},{"line_number":403,"context_line":"        from swift.common.internal_client import get_auth"},{"line_number":404,"context_line":"    global json_output, prom_client"},{"line_number":405,"context_line":"    json_output \u003d config_true_value(conf.get(\u0027dump_json\u0027, \u0027no\u0027))"},{"line_number":406,"context_line":"    if policy_name is None:"},{"line_number":407,"context_line":"        policy \u003d POLICIES.default"}],"source_content_type":"text/x-python","patch_set":13,"id":"779906f5_fade9076","line":404,"in_reply_to":"b3f7f203_6f1c7e5e","updated":"2026-05-21 21:49:26.000000000","message":"Done","commit_id":"d43b4af67d87eb1f98707fed6b3ff433f00a6d5f"},{"author":{"_account_id":1179,"name":"Clay Gerrard","email":"clay.gerrard@gmail.com","username":"clay-gerrard"},"change_message_id":"c36d34ba7ab384f3d592ac4775ecb5a642410a49","unresolved":true,"context_lines":[{"line_number":411,"context_line":"            exit(\u0027Unable to find policy: %s\u0027 % policy_name)"},{"line_number":412,"context_line":""},{"line_number":413,"context_line":"    if conf.get(\u0027metrics_filename\u0027):"},{"line_number":414,"context_line":"        prom_client \u003d get_prometheus_client(conf)"},{"line_number":415,"context_line":""},{"line_number":416,"context_line":"    if not json_output:"},{"line_number":417,"context_line":"        print(\u0027Using storage policy: %s \u0027 % policy.name)"}],"source_content_type":"text/x-python","patch_set":13,"id":"7843de36_bf5dfae4","line":414,"updated":"2026-05-18 19:09:31.000000000","message":"maybe a cool think we could do here is:\n\n```\nconf[\u0027filename\u0027] \u003d conf.get(\u0027metrics_filename\u0027, \u0027/dev/null\u0027)\n```\n\n... then we could *unconditionally* create/use a `prom_client` and then the \"dump to disk\" just has no side-effect.","commit_id":"d43b4af67d87eb1f98707fed6b3ff433f00a6d5f"},{"author":{"_account_id":1179,"name":"Clay Gerrard","email":"clay.gerrard@gmail.com","username":"clay-gerrard"},"change_message_id":"d7553688a4dd66be2c1630cf986c5d31061ecb06","unresolved":true,"context_lines":[{"line_number":411,"context_line":"            exit(\u0027Unable to find policy: %s\u0027 % policy_name)"},{"line_number":412,"context_line":""},{"line_number":413,"context_line":"    if conf.get(\u0027metrics_filename\u0027):"},{"line_number":414,"context_line":"        prom_client \u003d get_prometheus_client(conf)"},{"line_number":415,"context_line":""},{"line_number":416,"context_line":"    if not json_output:"},{"line_number":417,"context_line":"        print(\u0027Using storage policy: %s \u0027 % policy.name)"}],"source_content_type":"text/x-python","patch_set":13,"id":"d337868b_ce76bb9e","line":414,"in_reply_to":"3115d2f6_abc10171","updated":"2026-05-27 06:36:17.000000000","message":"\u003e write_all_stats already returns early when self.filename is None\n\nI think it raises a RuntimeError\n\n\u003e we would still construct the client and accumulate records in self._stats\n\nok, good - that\u0027s what I want\n\n\u003e write_all_stats becomes the only conditional\n\nthat would be better; create the client regardless, update the stats as we go - maybe `write_all_stats` (if configured to do so)\n\n\u003e Making this change: ... just adds extra work!\n\nI\u0027m not sure I understand this correctly, the \"work\" I want to minimize is me reading diffs with a bunch of `if prom_client` - I want the prom client to be created unconditionally, I want the stats to be accumulated unconditionally - this makes the instrumentation the minimum amount of tedious to read - and also maintain; because I can just add `prom_client.record(...)` instead of `if prom_client: prom_client.record(...)`.\n\n\u003e os.rename ... /dev/null would probably fail\n\nthat is *so true* - kudos for calling out a bad idea when you see it!\n\n\u003e might need to modify write_all_stats for that\n\nI\u0027d hesitate on that; we clearly have a use-case for \"instrument code with prom_client w/o having to constantly check `if prom_client`\" - but that doesn\u0027t mean we have a use-case for \"`prom_client.write_all_stats()` must silently noop if you accidentally typed `metircs_filename \u003d /opt/important.prom` in your config file\"\n\n... the answer might be something like:\n\n```\nself.logger.debug(\u0027Prometheus metrics filename: ...\u0027)\n```\n\nhttps://github.com/NVIDIA/swift/blob/master/swift/common/statsd_client.py#L546C13-L546C51\n\nso that if you\u0027re not getting metrics you can throw a `-v` on there and get a clue from debug logging:  \"wait why is filename \u003d None!?  I configured metircs_fi.... OOOOOHHHHHH\"\n\nif we find everywhere we want to call `metrics.write_all_metrics()` we end up just always having to write `if metrics.filename: metrics.write_all_metrics()` then maybe we should rethink the `RuntimeError` - especially if there\u0027s a better/obvious way to debug \"why does write_all_metrics not do anything and not error\" - maybe an info log line about all the awesome metrics you *would* be getting dumped if you\u0027d had configured a `metrics_filename` ???","commit_id":"d43b4af67d87eb1f98707fed6b3ff433f00a6d5f"},{"author":{"_account_id":35790,"name":"Shreeya Deshpande","email":"shreeyad@nvidia.com","username":"shreeyad"},"change_message_id":"c3e08cd5bf3119b0547abbde356f6fdedb898b44","unresolved":true,"context_lines":[{"line_number":411,"context_line":"            exit(\u0027Unable to find policy: %s\u0027 % policy_name)"},{"line_number":412,"context_line":""},{"line_number":413,"context_line":"    if conf.get(\u0027metrics_filename\u0027):"},{"line_number":414,"context_line":"        prom_client \u003d get_prometheus_client(conf)"},{"line_number":415,"context_line":""},{"line_number":416,"context_line":"    if not json_output:"},{"line_number":417,"context_line":"        print(\u0027Using storage policy: %s \u0027 % policy.name)"}],"source_content_type":"text/x-python","patch_set":13,"id":"3115d2f6_abc10171","line":414,"in_reply_to":"7843de36_bf5dfae4","updated":"2026-05-21 21:49:26.000000000","message":"write_all_stats already returns early when self.filename is None or self._stats is empty. When metrics_filename is unset, we would still construct the client and accumulate records in self._stats. write_all_stats becomes the only conditional! \nMaking this change: not checking if filename exisits and let write_all_stats figure it out just adds extra work!\n\nwrite_all_stats writes via tempfile + os.rename into os.path.dirname(filename), so /dev/null would probably fail. we might need to modify write_all_stats for that?","commit_id":"d43b4af67d87eb1f98707fed6b3ff433f00a6d5f"},{"author":{"_account_id":35790,"name":"Shreeya Deshpande","email":"shreeyad@nvidia.com","username":"shreeyad"},"change_message_id":"790e7a1fbf57e68001d1fde9adcc38c112398f37","unresolved":false,"context_lines":[{"line_number":411,"context_line":"            exit(\u0027Unable to find policy: %s\u0027 % policy_name)"},{"line_number":412,"context_line":""},{"line_number":413,"context_line":"    if conf.get(\u0027metrics_filename\u0027):"},{"line_number":414,"context_line":"        prom_client \u003d get_prometheus_client(conf)"},{"line_number":415,"context_line":""},{"line_number":416,"context_line":"    if not json_output:"},{"line_number":417,"context_line":"        print(\u0027Using storage policy: %s \u0027 % policy.name)"}],"source_content_type":"text/x-python","patch_set":13,"id":"8cf645ad_44ec4b4c","line":414,"in_reply_to":"d337868b_ce76bb9e","updated":"2026-08-19 00:50:18.000000000","message":"Done","commit_id":"d43b4af67d87eb1f98707fed6b3ff433f00a6d5f"},{"author":{"_account_id":38767,"name":"Wael Halbawi","display_name":"Wael Halbawi","email":"whalbawi@nvidia.com","username":"whalbawi"},"change_message_id":"ad3f89585e29271466d0cb47deeeb68215272dc2","unresolved":true,"context_lines":[{"line_number":466,"context_line":"            conf.get(\u0027partitions\u0027), policy, prom_client)"},{"line_number":467,"context_line":""},{"line_number":468,"context_line":"    if prom_client:"},{"line_number":469,"context_line":"        prom_client.write_all_stats()"},{"line_number":470,"context_line":""},{"line_number":471,"context_line":"    return output"},{"line_number":472,"context_line":""}],"source_content_type":"text/x-python","patch_set":13,"id":"0059f89f_6d97235c","line":469,"updated":"2026-05-18 22:01:50.000000000","message":"We should handle errors here so that this method can still return its output and the tool can finish execution.","commit_id":"d43b4af67d87eb1f98707fed6b3ff433f00a6d5f"},{"author":{"_account_id":35790,"name":"Shreeya Deshpande","email":"shreeyad@nvidia.com","username":"shreeyad"},"change_message_id":"c3e08cd5bf3119b0547abbde356f6fdedb898b44","unresolved":false,"context_lines":[{"line_number":466,"context_line":"            conf.get(\u0027partitions\u0027), policy, prom_client)"},{"line_number":467,"context_line":""},{"line_number":468,"context_line":"    if prom_client:"},{"line_number":469,"context_line":"        prom_client.write_all_stats()"},{"line_number":470,"context_line":""},{"line_number":471,"context_line":"    return output"},{"line_number":472,"context_line":""}],"source_content_type":"text/x-python","patch_set":13,"id":"4978917a_d60da7da","line":469,"in_reply_to":"0059f89f_6d97235c","updated":"2026-05-21 21:49:26.000000000","message":"Acknowledged","commit_id":"d43b4af67d87eb1f98707fed6b3ff433f00a6d5f"},{"author":{"_account_id":1179,"name":"Clay Gerrard","email":"clay.gerrard@gmail.com","username":"clay-gerrard"},"change_message_id":"d7553688a4dd66be2c1630cf986c5d31061ecb06","unresolved":true,"context_lines":[{"line_number":48,"context_line":"            identifier \u003d \u0027%s:%s/%s\u0027 % (msg_or_exc.http_host,"},{"line_number":49,"context_line":"                                       msg_or_exc.http_port,"},{"line_number":50,"context_line":"                                       msg_or_exc.http_device)"},{"line_number":51,"context_line":"            if msg_or_exc.http_status \u003d\u003d 507:"},{"line_number":52,"context_line":"                if identifier not in unmounted:"},{"line_number":53,"context_line":"                    unmounted.append(identifier)"},{"line_number":54,"context_line":"                    print(\u0027ERROR: %s is unmounted -- This will \u0027"}],"source_content_type":"text/x-python","patch_set":20,"id":"588b41fd_6426d0ec","line":51,"updated":"2026-05-27 06:36:17.000000000","message":"it\u0027d be nice if we could some instrumentation counters on the observed errors by status label","commit_id":"a92db4071a3dcf4e4e7da3e0d0dc8be5b0c1e360"},{"author":{"_account_id":35790,"name":"Shreeya Deshpande","email":"shreeyad@nvidia.com","username":"shreeyad"},"change_message_id":"1423f06064b21424504a40a5d725f69e824378fd","unresolved":false,"context_lines":[{"line_number":48,"context_line":"            identifier \u003d \u0027%s:%s/%s\u0027 % (msg_or_exc.http_host,"},{"line_number":49,"context_line":"                                       msg_or_exc.http_port,"},{"line_number":50,"context_line":"                                       msg_or_exc.http_device)"},{"line_number":51,"context_line":"            if msg_or_exc.http_status \u003d\u003d 507:"},{"line_number":52,"context_line":"                if identifier not in unmounted:"},{"line_number":53,"context_line":"                    unmounted.append(identifier)"},{"line_number":54,"context_line":"                    print(\u0027ERROR: %s is unmounted -- This will \u0027"}],"source_content_type":"text/x-python","patch_set":20,"id":"2fc575bd_d276b7a1","line":51,"in_reply_to":"588b41fd_6426d0ec","updated":"2026-07-15 02:05:55.000000000","message":"Done","commit_id":"a92db4071a3dcf4e4e7da3e0d0dc8be5b0c1e360"},{"author":{"_account_id":1179,"name":"Clay Gerrard","email":"clay.gerrard@gmail.com","username":"clay-gerrard"},"change_message_id":"d7553688a4dd66be2c1630cf986c5d31061ecb06","unresolved":true,"context_lines":[{"line_number":67,"context_line":"    return error_log"},{"line_number":68,"context_line":""},{"line_number":69,"context_line":""},{"line_number":70,"context_line":"def container_dispersion_report(coropool, connpool, account, container_ring,"},{"line_number":71,"context_line":"                                retries, output_missing_partitions, policy,"},{"line_number":72,"context_line":"                                prom_client\u003dNone):"},{"line_number":73,"context_line":"    with connpool.item() as conn:"}],"source_content_type":"text/x-python","patch_set":20,"id":"e8fe2140_23f8a3de","line":70,"updated":"2026-05-27 06:36:17.000000000","message":"wow there\u0027s not an `account_dispersion_report`","commit_id":"a92db4071a3dcf4e4e7da3e0d0dc8be5b0c1e360"},{"author":{"_account_id":35790,"name":"Shreeya Deshpande","email":"shreeyad@nvidia.com","username":"shreeyad"},"change_message_id":"1423f06064b21424504a40a5d725f69e824378fd","unresolved":false,"context_lines":[{"line_number":67,"context_line":"    return error_log"},{"line_number":68,"context_line":""},{"line_number":69,"context_line":""},{"line_number":70,"context_line":"def container_dispersion_report(coropool, connpool, account, container_ring,"},{"line_number":71,"context_line":"                                retries, output_missing_partitions, policy,"},{"line_number":72,"context_line":"                                prom_client\u003dNone):"},{"line_number":73,"context_line":"    with connpool.item() as conn:"}],"source_content_type":"text/x-python","patch_set":20,"id":"d2da7830_d221af9d","line":70,"in_reply_to":"e8fe2140_23f8a3de","updated":"2026-07-15 02:05:55.000000000","message":"Done","commit_id":"a92db4071a3dcf4e4e7da3e0d0dc8be5b0c1e360"},{"author":{"_account_id":1179,"name":"Clay Gerrard","email":"clay.gerrard@gmail.com","username":"clay-gerrard"},"change_message_id":"d7553688a4dd66be2c1630cf986c5d31061ecb06","unresolved":true,"context_lines":[{"line_number":69,"context_line":""},{"line_number":70,"context_line":"def container_dispersion_report(coropool, connpool, account, container_ring,"},{"line_number":71,"context_line":"                                retries, output_missing_partitions, policy,"},{"line_number":72,"context_line":"                                prom_client\u003dNone):"},{"line_number":73,"context_line":"    with connpool.item() as conn:"},{"line_number":74,"context_line":"        containers \u003d [c[\u0027name\u0027] for c in conn.get_account("},{"line_number":75,"context_line":"            prefix\u003d\u0027dispersion_%d\u0027 % policy.idx, full_listing\u003dTrue)[1]]"}],"source_content_type":"text/x-python","patch_set":20,"id":"50e30c02_67b62a82","line":72,"updated":"2026-05-27 06:36:17.000000000","message":"I don\u0027t think prom_client should be kwarg - it\u0027s always passed in and the implementation is simpler if it\u0027s a required arg","commit_id":"a92db4071a3dcf4e4e7da3e0d0dc8be5b0c1e360"},{"author":{"_account_id":35790,"name":"Shreeya Deshpande","email":"shreeyad@nvidia.com","username":"shreeyad"},"change_message_id":"1423f06064b21424504a40a5d725f69e824378fd","unresolved":false,"context_lines":[{"line_number":69,"context_line":""},{"line_number":70,"context_line":"def container_dispersion_report(coropool, connpool, account, container_ring,"},{"line_number":71,"context_line":"                                retries, output_missing_partitions, policy,"},{"line_number":72,"context_line":"                                prom_client\u003dNone):"},{"line_number":73,"context_line":"    with connpool.item() as conn:"},{"line_number":74,"context_line":"        containers \u003d [c[\u0027name\u0027] for c in conn.get_account("},{"line_number":75,"context_line":"            prefix\u003d\u0027dispersion_%d\u0027 % policy.idx, full_listing\u003dTrue)[1]]"}],"source_content_type":"text/x-python","patch_set":20,"id":"3bf6e110_bae4fa05","line":72,"in_reply_to":"50e30c02_67b62a82","updated":"2026-07-15 02:05:55.000000000","message":"Acknowledged","commit_id":"a92db4071a3dcf4e4e7da3e0d0dc8be5b0c1e360"},{"author":{"_account_id":1179,"name":"Clay Gerrard","email":"clay.gerrard@gmail.com","username":"clay-gerrard"},"change_message_id":"d7553688a4dd66be2c1630cf986c5d31061ecb06","unresolved":true,"context_lines":[{"line_number":94,"context_line":"            try:"},{"line_number":95,"context_line":"                attempts, _junk \u003d direct_client.retry("},{"line_number":96,"context_line":"                    direct_client.direct_head_container, node, part, account,"},{"line_number":97,"context_line":"                    container, error_log\u003derror_log, retries\u003dretries)"},{"line_number":98,"context_line":"                retries_done[0] +\u003d attempts - 1"},{"line_number":99,"context_line":"                found_count +\u003d 1"},{"line_number":100,"context_line":"            except ClientException as err:"}],"source_content_type":"text/x-python","patch_set":20,"id":"f69020da_06b30a75","line":97,"updated":"2026-05-27 06:36:17.000000000","message":"this `error_log` kwarg is *wild*\n\nhttps://github.com/NVIDIA/swift/blob/master/swift/common/direct_client.py#L633","commit_id":"a92db4071a3dcf4e4e7da3e0d0dc8be5b0c1e360"},{"author":{"_account_id":35790,"name":"Shreeya Deshpande","email":"shreeyad@nvidia.com","username":"shreeyad"},"change_message_id":"1423f06064b21424504a40a5d725f69e824378fd","unresolved":false,"context_lines":[{"line_number":94,"context_line":"            try:"},{"line_number":95,"context_line":"                attempts, _junk \u003d direct_client.retry("},{"line_number":96,"context_line":"                    direct_client.direct_head_container, node, part, account,"},{"line_number":97,"context_line":"                    container, error_log\u003derror_log, retries\u003dretries)"},{"line_number":98,"context_line":"                retries_done[0] +\u003d attempts - 1"},{"line_number":99,"context_line":"                found_count +\u003d 1"},{"line_number":100,"context_line":"            except ClientException as err:"}],"source_content_type":"text/x-python","patch_set":20,"id":"c44ab47d_f7a2ae96","line":97,"in_reply_to":"f69020da_06b30a75","updated":"2026-07-15 02:05:55.000000000","message":"error_log not a kwarg anymore","commit_id":"a92db4071a3dcf4e4e7da3e0d0dc8be5b0c1e360"},{"author":{"_account_id":1179,"name":"Clay Gerrard","email":"clay.gerrard@gmail.com","username":"clay-gerrard"},"change_message_id":"d7553688a4dd66be2c1630cf986c5d31061ecb06","unresolved":true,"context_lines":[{"line_number":154,"context_line":"        prom_client.record(\u0027swift_dispersion_container_distinct_partitions\u0027,"},{"line_number":155,"context_line":"                           distinct_partitions, labels)"},{"line_number":156,"context_line":""},{"line_number":157,"context_line":"    if not json_output:"},{"line_number":158,"context_line":"        print(\u0027\\r\\x1B[KQueried %d containers for dispersion reporting, \u0027"},{"line_number":159,"context_line":"              \u0027%d%s, %d retries\u0027 % (containers_listed, round(elapsed),"},{"line_number":160,"context_line":"                                    elapsed_unit, retries_done[0]))"}],"source_content_type":"text/x-python","patch_set":20,"id":"1ce45a55_c9e1d345","line":157,"updated":"2026-05-27 06:36:17.000000000","message":"something bothers me about making `metrics_filename` completely orthogonal to human/json output vs `stdout`\n\nit seems like there should be a \"pick one\" semantic","commit_id":"a92db4071a3dcf4e4e7da3e0d0dc8be5b0c1e360"},{"author":{"_account_id":35790,"name":"Shreeya Deshpande","email":"shreeyad@nvidia.com","username":"shreeyad"},"change_message_id":"1423f06064b21424504a40a5d725f69e824378fd","unresolved":true,"context_lines":[{"line_number":154,"context_line":"        prom_client.record(\u0027swift_dispersion_container_distinct_partitions\u0027,"},{"line_number":155,"context_line":"                           distinct_partitions, labels)"},{"line_number":156,"context_line":""},{"line_number":157,"context_line":"    if not json_output:"},{"line_number":158,"context_line":"        print(\u0027\\r\\x1B[KQueried %d containers for dispersion reporting, \u0027"},{"line_number":159,"context_line":"              \u0027%d%s, %d retries\u0027 % (containers_listed, round(elapsed),"},{"line_number":160,"context_line":"                                    elapsed_unit, retries_done[0]))"}],"source_content_type":"text/x-python","patch_set":20,"id":"e5c02982_d5e1d24e","line":157,"in_reply_to":"1ce45a55_c9e1d345","updated":"2026-07-15 02:05:55.000000000","message":"Yes, do we want to not dp json dump? It may break other things when someone wants json dump. \nWe can supress json dump when metrics_filename is set. (Always set every time? maybe we don\u0027t need a stdout dump?)","commit_id":"a92db4071a3dcf4e4e7da3e0d0dc8be5b0c1e360"},{"author":{"_account_id":35790,"name":"Shreeya Deshpande","email":"shreeyad@nvidia.com","username":"shreeyad"},"change_message_id":"87fcda1404be12041baad4f1a0f5b45868d053eb","unresolved":false,"context_lines":[{"line_number":154,"context_line":"        prom_client.record(\u0027swift_dispersion_container_distinct_partitions\u0027,"},{"line_number":155,"context_line":"                           distinct_partitions, labels)"},{"line_number":156,"context_line":""},{"line_number":157,"context_line":"    if not json_output:"},{"line_number":158,"context_line":"        print(\u0027\\r\\x1B[KQueried %d containers for dispersion reporting, \u0027"},{"line_number":159,"context_line":"              \u0027%d%s, %d retries\u0027 % (containers_listed, round(elapsed),"},{"line_number":160,"context_line":"                                    elapsed_unit, retries_done[0]))"}],"source_content_type":"text/x-python","patch_set":20,"id":"8ca01572_49dde4fe","line":157,"in_reply_to":"e5c02982_d5e1d24e","updated":"2026-08-19 00:33:23.000000000","message":"Done","commit_id":"a92db4071a3dcf4e4e7da3e0d0dc8be5b0c1e360"},{"author":{"_account_id":1179,"name":"Clay Gerrard","email":"clay.gerrard@gmail.com","username":"clay-gerrard"},"change_message_id":"d7553688a4dd66be2c1630cf986c5d31061ecb06","unresolved":true,"context_lines":[{"line_number":177,"context_line":"                   \u0027copies_found\u0027: copies_found,"},{"line_number":178,"context_line":"                   \u0027copies_expected\u0027: copies_expected}"},{"line_number":179,"context_line":"        for missing_copies, num_parts in container_copies_missing.items():"},{"line_number":180,"context_line":"            results[\u0027missing_%d\u0027 % (missing_copies)] \u003d num_parts"},{"line_number":181,"context_line":"        return results"},{"line_number":182,"context_line":""},{"line_number":183,"context_line":""}],"source_content_type":"text/x-python","patch_set":20,"id":"8c694cfe_59c848c8","line":180,"updated":"2026-05-27 06:36:17.000000000","message":"I think this is an import/key metric that I don\u0027t see represented in the prom output.\n\nit\u0027s the perfect candidate for a label:\n\n```\nmissing{num_copies\u003dN} num_parts\n```","commit_id":"a92db4071a3dcf4e4e7da3e0d0dc8be5b0c1e360"},{"author":{"_account_id":35790,"name":"Shreeya Deshpande","email":"shreeyad@nvidia.com","username":"shreeyad"},"change_message_id":"1423f06064b21424504a40a5d725f69e824378fd","unresolved":false,"context_lines":[{"line_number":177,"context_line":"                   \u0027copies_found\u0027: copies_found,"},{"line_number":178,"context_line":"                   \u0027copies_expected\u0027: copies_expected}"},{"line_number":179,"context_line":"        for missing_copies, num_parts in container_copies_missing.items():"},{"line_number":180,"context_line":"            results[\u0027missing_%d\u0027 % (missing_copies)] \u003d num_parts"},{"line_number":181,"context_line":"        return results"},{"line_number":182,"context_line":""},{"line_number":183,"context_line":""}],"source_content_type":"text/x-python","patch_set":20,"id":"8eb4f87b_c33a7d10","line":180,"in_reply_to":"8c694cfe_59c848c8","updated":"2026-07-15 02:05:55.000000000","message":"Done! Added swift_dispersion_{container,object}_partitions_missing{policy, missing_copies}\ne.g. swift_dispersion_container_partitions_missing","commit_id":"a92db4071a3dcf4e4e7da3e0d0dc8be5b0c1e360"},{"author":{"_account_id":1179,"name":"Clay Gerrard","email":"clay.gerrard@gmail.com","username":"clay-gerrard"},"change_message_id":"d7553688a4dd66be2c1630cf986c5d31061ecb06","unresolved":true,"context_lines":[{"line_number":203,"context_line":"              \u0027been run?\u0027, file\u003dstderr)"},{"line_number":204,"context_line":"        stderr.flush()"},{"line_number":205,"context_line":"        return"},{"line_number":206,"context_line":"    retries_done \u003d [0]"},{"line_number":207,"context_line":"    objects_queried \u003d [0]"},{"line_number":208,"context_line":"    object_copies_found \u003d [0]"},{"line_number":209,"context_line":"    object_copies_expected \u003d [0]"}],"source_content_type":"text/x-python","patch_set":20,"id":"3e5a2985_f95431fc","line":206,"updated":"2026-05-27 06:36:17.000000000","message":"FWIW i\u0027m *pretty* sure this is just an ancient python spelling of `nonlocal` so that `retries_done +\u003d 1` in the closure doesn\u0027t define a new var in that scope.","commit_id":"a92db4071a3dcf4e4e7da3e0d0dc8be5b0c1e360"},{"author":{"_account_id":35790,"name":"Shreeya Deshpande","email":"shreeyad@nvidia.com","username":"shreeyad"},"change_message_id":"1423f06064b21424504a40a5d725f69e824378fd","unresolved":false,"context_lines":[{"line_number":203,"context_line":"              \u0027been run?\u0027, file\u003dstderr)"},{"line_number":204,"context_line":"        stderr.flush()"},{"line_number":205,"context_line":"        return"},{"line_number":206,"context_line":"    retries_done \u003d [0]"},{"line_number":207,"context_line":"    objects_queried \u003d [0]"},{"line_number":208,"context_line":"    object_copies_found \u003d [0]"},{"line_number":209,"context_line":"    object_copies_expected \u003d [0]"}],"source_content_type":"text/x-python","patch_set":20,"id":"fc886451_6f9ee63e","line":206,"in_reply_to":"3e5a2985_f95431fc","updated":"2026-07-15 02:05:55.000000000","message":"Acknowledged","commit_id":"a92db4071a3dcf4e4e7da3e0d0dc8be5b0c1e360"},{"author":{"_account_id":1179,"name":"Clay Gerrard","email":"clay.gerrard@gmail.com","username":"clay-gerrard"},"change_message_id":"d7553688a4dd66be2c1630cf986c5d31061ecb06","unresolved":true,"context_lines":[{"line_number":349,"context_line":""},{"line_number":350,"context_line":"[conf_file] defaults to %s\u0027\u0027\u0027.strip() % conffile)"},{"line_number":351,"context_line":"    parser.add_option(\u0027-j\u0027, \u0027--dump-json\u0027, action\u003d\u0027store_true\u0027, default\u003dFalse,"},{"line_number":352,"context_line":"                      help\u003d\u0027dump dispersion report in json format\u0027)"},{"line_number":353,"context_line":"    parser.add_option(\u0027-d\u0027, \u0027--debug\u0027, action\u003d\u0027store_true\u0027, default\u003dFalse,"},{"line_number":354,"context_line":"                      help\u003d\u0027print 404s to standard error\u0027)"},{"line_number":355,"context_line":"    parser.add_option(\u0027-p\u0027, \u0027--partitions\u0027, action\u003d\u0027store_true\u0027, default\u003dFalse,"}],"source_content_type":"text/x-python","patch_set":20,"id":"308e1d58_a6f512bf","line":352,"updated":"2026-05-27 06:36:17.000000000","message":"OMG ^\u0026*(ing OptionParser\n\nI think what I want to see is ArgumentParser\u0027s \"Mutual exclusion\"\n\nhttps://docs.python.org/3/library/argparse.html#mutual-exclusion\n\ni.e. \n\n```\ns-d-r --dump-json\ns-d-r --dump-prom\n```\n\nI\u0027m indifferent/unsure about:\n\n```\ns-d-r --dump-prom metrics.prom\n```\n\nvs.\n\n```\ns-d-r --dump-prom \u003e metrics.prom\n```\n\nin our cron file\n\n... but if we want to support `metrics_filename` from the config then we have to decide what to output to the console, and either of the two existing options seems like a waste if all we care about is what get\u0027s rendered into the metrics filename\n\n... I guess `2\u003e report.err` would still be useful","commit_id":"a92db4071a3dcf4e4e7da3e0d0dc8be5b0c1e360"},{"author":{"_account_id":1179,"name":"Clay Gerrard","email":"clay.gerrard@gmail.com","username":"clay-gerrard"},"change_message_id":"f4b675b73574e7fd3378c73a59286d2770e3aed0","unresolved":false,"context_lines":[{"line_number":349,"context_line":""},{"line_number":350,"context_line":"[conf_file] defaults to %s\u0027\u0027\u0027.strip() % conffile)"},{"line_number":351,"context_line":"    parser.add_option(\u0027-j\u0027, \u0027--dump-json\u0027, action\u003d\u0027store_true\u0027, default\u003dFalse,"},{"line_number":352,"context_line":"                      help\u003d\u0027dump dispersion report in json format\u0027)"},{"line_number":353,"context_line":"    parser.add_option(\u0027-d\u0027, \u0027--debug\u0027, action\u003d\u0027store_true\u0027, default\u003dFalse,"},{"line_number":354,"context_line":"                      help\u003d\u0027print 404s to standard error\u0027)"},{"line_number":355,"context_line":"    parser.add_option(\u0027-p\u0027, \u0027--partitions\u0027, action\u003d\u0027store_true\u0027, default\u003dFalse,"}],"source_content_type":"text/x-python","patch_set":20,"id":"fb8805fe_69e25da2","line":352,"in_reply_to":"308e1d58_a6f512bf","updated":"2026-08-12 19:47:14.000000000","message":"ok, so where we landed was NO way to configure prom output from the command line - if you want to opt into metrics_filename you HAVE to do it via `/etc/swift/dispersion.conf`","commit_id":"a92db4071a3dcf4e4e7da3e0d0dc8be5b0c1e360"},{"author":{"_account_id":1179,"name":"Clay Gerrard","email":"clay.gerrard@gmail.com","username":"clay-gerrard"},"change_message_id":"d7553688a4dd66be2c1630cf986c5d31061ecb06","unresolved":true,"context_lines":[{"line_number":467,"context_line":"        prom_client.write_all_stats()"},{"line_number":468,"context_line":"    except Exception as err:"},{"line_number":469,"context_line":"        print(\u0027ERROR: failed to write prometheus metrics: %s\u0027 % err,"},{"line_number":470,"context_line":"              file\u003dstderr)"},{"line_number":471,"context_line":"        stderr.flush()"},{"line_number":472,"context_line":""},{"line_number":473,"context_line":"    return output"}],"source_content_type":"text/x-python","patch_set":20,"id":"7323e677_229a1c33","line":470,"updated":"2026-05-27 06:36:17.000000000","message":"this is ohkay, but seems sort of noisy if the config didn\u0027t define `metrics_filename` and the cli didn\u0027t ask for `--dump-prom`\n\nOTOH, if they *did* configure `metrics_filename` or ask for `--dump-prom` it\u0027s really ugly to print an `ERROR` and then exit 0\n\nI don\u0027t think this is the right way to achive what ever we\u0027re going for.","commit_id":"a92db4071a3dcf4e4e7da3e0d0dc8be5b0c1e360"},{"author":{"_account_id":1179,"name":"Clay Gerrard","email":"clay.gerrard@gmail.com","username":"clay-gerrard"},"change_message_id":"f4b675b73574e7fd3378c73a59286d2770e3aed0","unresolved":true,"context_lines":[{"line_number":467,"context_line":"        prom_client.write_all_stats()"},{"line_number":468,"context_line":"    except Exception as err:"},{"line_number":469,"context_line":"        print(\u0027ERROR: failed to write prometheus metrics: %s\u0027 % err,"},{"line_number":470,"context_line":"              file\u003dstderr)"},{"line_number":471,"context_line":"        stderr.flush()"},{"line_number":472,"context_line":""},{"line_number":473,"context_line":"    return output"}],"source_content_type":"text/x-python","patch_set":20,"id":"8404f2a0_ea84ce2d","line":470,"in_reply_to":"7323e677_229a1c33","updated":"2026-08-12 19:47:14.000000000","message":"`--drop-prom` isn\u0027t a thing.\n\nIf the user doesn\u0027t configure metrics_filename - I don\u0027t guess it\u0027s actually an \"error\" - output of json to stdout is probably still a \"supported config\"\n\nI\u0027m not sure what do here tho - maybe `if prom_client.filename: ...`\n\nwe shouldn\u0027t print an error if the user did not request prom metrics filename","commit_id":"a92db4071a3dcf4e4e7da3e0d0dc8be5b0c1e360"},{"author":{"_account_id":35790,"name":"Shreeya Deshpande","email":"shreeyad@nvidia.com","username":"shreeyad"},"change_message_id":"87fcda1404be12041baad4f1a0f5b45868d053eb","unresolved":false,"context_lines":[{"line_number":467,"context_line":"        prom_client.write_all_stats()"},{"line_number":468,"context_line":"    except Exception as err:"},{"line_number":469,"context_line":"        print(\u0027ERROR: failed to write prometheus metrics: %s\u0027 % err,"},{"line_number":470,"context_line":"              file\u003dstderr)"},{"line_number":471,"context_line":"        stderr.flush()"},{"line_number":472,"context_line":""},{"line_number":473,"context_line":"    return output"}],"source_content_type":"text/x-python","patch_set":20,"id":"736f729a_bf6544a4","line":470,"in_reply_to":"8404f2a0_ea84ce2d","updated":"2026-08-19 00:33:23.000000000","message":"Done","commit_id":"a92db4071a3dcf4e4e7da3e0d0dc8be5b0c1e360"},{"author":{"_account_id":1179,"name":"Clay Gerrard","email":"clay.gerrard@gmail.com","username":"clay-gerrard"},"change_message_id":"d7553688a4dd66be2c1630cf986c5d31061ecb06","unresolved":true,"context_lines":[{"line_number":468,"context_line":"    except Exception as err:"},{"line_number":469,"context_line":"        print(\u0027ERROR: failed to write prometheus metrics: %s\u0027 % err,"},{"line_number":470,"context_line":"              file\u003dstderr)"},{"line_number":471,"context_line":"        stderr.flush()"},{"line_number":472,"context_line":""},{"line_number":473,"context_line":"    return output"},{"line_number":474,"context_line":""}],"source_content_type":"text/x-python","patch_set":20,"id":"898b31bf_d7f5b42a","line":471,"updated":"2026-05-27 06:36:17.000000000","message":"I\u0027m not sure I\u0027m convinced that `print` would\u0027t do this to the stream/file already most of the time, but if it\u0027s the last thing we do before we exit it can\u0027t matter.","commit_id":"a92db4071a3dcf4e4e7da3e0d0dc8be5b0c1e360"},{"author":{"_account_id":35790,"name":"Shreeya Deshpande","email":"shreeyad@nvidia.com","username":"shreeyad"},"change_message_id":"1423f06064b21424504a40a5d725f69e824378fd","unresolved":false,"context_lines":[{"line_number":468,"context_line":"    except Exception as err:"},{"line_number":469,"context_line":"        print(\u0027ERROR: failed to write prometheus metrics: %s\u0027 % err,"},{"line_number":470,"context_line":"              file\u003dstderr)"},{"line_number":471,"context_line":"        stderr.flush()"},{"line_number":472,"context_line":""},{"line_number":473,"context_line":"    return output"},{"line_number":474,"context_line":""}],"source_content_type":"text/x-python","patch_set":20,"id":"6755a3d4_a8aa7c63","line":471,"in_reply_to":"898b31bf_d7f5b42a","updated":"2026-07-15 02:05:55.000000000","message":"Acknowledged","commit_id":"a92db4071a3dcf4e4e7da3e0d0dc8be5b0c1e360"},{"author":{"_account_id":1179,"name":"Clay Gerrard","email":"clay.gerrard@gmail.com","username":"clay-gerrard"},"change_message_id":"f4b675b73574e7fd3378c73a59286d2770e3aed0","unresolved":true,"context_lines":[{"line_number":40,"context_line":"insecure \u003d False"},{"line_number":41,"context_line":""},{"line_number":42,"context_line":""},{"line_number":43,"context_line":"def get_error_log(prefix, prom_client, policy_name):"},{"line_number":44,"context_line":""},{"line_number":45,"context_line":"    def error_log(msg_or_exc):"},{"line_number":46,"context_line":"        global debug, unmounted, notfound"}],"source_content_type":"text/x-python","patch_set":31,"id":"295983e4_d08ee864","line":43,"updated":"2026-08-12 19:47:14.000000000","message":"I wonder if the signature should be\n\n`get_error_log(prefix, client, labels)` to support additional label axis extensions\n\nFWIW in practice \"prefix\" here is `node_to_string(node)`","commit_id":"18867fed23f40bf2117321bc895bf8b0a31abd5f"},{"author":{"_account_id":35790,"name":"Shreeya Deshpande","email":"shreeyad@nvidia.com","username":"shreeyad"},"change_message_id":"87fcda1404be12041baad4f1a0f5b45868d053eb","unresolved":false,"context_lines":[{"line_number":40,"context_line":"insecure \u003d False"},{"line_number":41,"context_line":""},{"line_number":42,"context_line":""},{"line_number":43,"context_line":"def get_error_log(prefix, prom_client, policy_name):"},{"line_number":44,"context_line":""},{"line_number":45,"context_line":"    def error_log(msg_or_exc):"},{"line_number":46,"context_line":"        global debug, unmounted, notfound"}],"source_content_type":"text/x-python","patch_set":31,"id":"2920c871_e8dfc94f","line":43,"in_reply_to":"295983e4_d08ee864","updated":"2026-08-19 00:33:23.000000000","message":"Done","commit_id":"18867fed23f40bf2117321bc895bf8b0a31abd5f"},{"author":{"_account_id":1179,"name":"Clay Gerrard","email":"clay.gerrard@gmail.com","username":"clay-gerrard"},"change_message_id":"f4b675b73574e7fd3378c73a59286d2770e3aed0","unresolved":true,"context_lines":[{"line_number":46,"context_line":"        global debug, unmounted, notfound"},{"line_number":47,"context_line":"        if hasattr(msg_or_exc, \u0027http_status\u0027):"},{"line_number":48,"context_line":"            prom_client.add("},{"line_number":49,"context_line":"                \u0027swift_dispersion_errors\u0027, 1,"},{"line_number":50,"context_line":"                {\u0027status\u0027: str(msg_or_exc.http_status),"},{"line_number":51,"context_line":"                 \u0027policy\u0027: policy_name})"},{"line_number":52,"context_line":"            identifier \u003d \u0027%s:%s/%s\u0027 % (msg_or_exc.http_host,"}],"source_content_type":"text/x-python","patch_set":31,"id":"c161bcf9_6225a9a3","line":49,"updated":"2026-08-12 19:47:14.000000000","message":"more readable as `increment(name)` instead of `add(name, 1)` ??","commit_id":"18867fed23f40bf2117321bc895bf8b0a31abd5f"},{"author":{"_account_id":35790,"name":"Shreeya Deshpande","email":"shreeyad@nvidia.com","username":"shreeyad"},"change_message_id":"87fcda1404be12041baad4f1a0f5b45868d053eb","unresolved":false,"context_lines":[{"line_number":46,"context_line":"        global debug, unmounted, notfound"},{"line_number":47,"context_line":"        if hasattr(msg_or_exc, \u0027http_status\u0027):"},{"line_number":48,"context_line":"            prom_client.add("},{"line_number":49,"context_line":"                \u0027swift_dispersion_errors\u0027, 1,"},{"line_number":50,"context_line":"                {\u0027status\u0027: str(msg_or_exc.http_status),"},{"line_number":51,"context_line":"                 \u0027policy\u0027: policy_name})"},{"line_number":52,"context_line":"            identifier \u003d \u0027%s:%s/%s\u0027 % (msg_or_exc.http_host,"}],"source_content_type":"text/x-python","patch_set":31,"id":"462950c6_e9f37db6","line":49,"in_reply_to":"c161bcf9_6225a9a3","updated":"2026-08-19 00:33:23.000000000","message":"Done","commit_id":"18867fed23f40bf2117321bc895bf8b0a31abd5f"},{"author":{"_account_id":1179,"name":"Clay Gerrard","email":"clay.gerrard@gmail.com","username":"clay-gerrard"},"change_message_id":"f4b675b73574e7fd3378c73a59286d2770e3aed0","unresolved":true,"context_lines":[{"line_number":47,"context_line":"        if hasattr(msg_or_exc, \u0027http_status\u0027):"},{"line_number":48,"context_line":"            prom_client.add("},{"line_number":49,"context_line":"                \u0027swift_dispersion_errors\u0027, 1,"},{"line_number":50,"context_line":"                {\u0027status\u0027: str(msg_or_exc.http_status),"},{"line_number":51,"context_line":"                 \u0027policy\u0027: policy_name})"},{"line_number":52,"context_line":"            identifier \u003d \u0027%s:%s/%s\u0027 % (msg_or_exc.http_host,"},{"line_number":53,"context_line":"                                       msg_or_exc.http_port,"}],"source_content_type":"text/x-python","patch_set":31,"id":"e1e94396_2c51c0bc","line":50,"updated":"2026-08-12 19:47:14.000000000","message":"good call including http_status here!","commit_id":"18867fed23f40bf2117321bc895bf8b0a31abd5f"},{"author":{"_account_id":35790,"name":"Shreeya Deshpande","email":"shreeyad@nvidia.com","username":"shreeyad"},"change_message_id":"87fcda1404be12041baad4f1a0f5b45868d053eb","unresolved":false,"context_lines":[{"line_number":47,"context_line":"        if hasattr(msg_or_exc, \u0027http_status\u0027):"},{"line_number":48,"context_line":"            prom_client.add("},{"line_number":49,"context_line":"                \u0027swift_dispersion_errors\u0027, 1,"},{"line_number":50,"context_line":"                {\u0027status\u0027: str(msg_or_exc.http_status),"},{"line_number":51,"context_line":"                 \u0027policy\u0027: policy_name})"},{"line_number":52,"context_line":"            identifier \u003d \u0027%s:%s/%s\u0027 % (msg_or_exc.http_host,"},{"line_number":53,"context_line":"                                       msg_or_exc.http_port,"}],"source_content_type":"text/x-python","patch_set":31,"id":"577be3a6_57c169bb","line":50,"in_reply_to":"e1e94396_2c51c0bc","updated":"2026-08-19 00:33:23.000000000","message":"Done","commit_id":"18867fed23f40bf2117321bc895bf8b0a31abd5f"},{"author":{"_account_id":1179,"name":"Clay Gerrard","email":"clay.gerrard@gmail.com","username":"clay-gerrard"},"change_message_id":"f4b675b73574e7fd3378c73a59286d2770e3aed0","unresolved":true,"context_lines":[{"line_number":62,"context_line":"                    stderr.flush()"},{"line_number":63,"context_line":"            if debug and identifier not in notfound:"},{"line_number":64,"context_line":"                notfound.append(identifier)"},{"line_number":65,"context_line":"                print(\u0027ERROR: %s returned a 404\u0027 % (identifier), file\u003dstderr)"},{"line_number":66,"context_line":"                stderr.flush()"},{"line_number":67,"context_line":"        if not hasattr(msg_or_exc, \u0027http_status\u0027) or \\"},{"line_number":68,"context_line":"                msg_or_exc.http_status not in (404, 507):"}],"source_content_type":"text/x-python","patch_set":31,"id":"91d91270_b380a100","line":65,"updated":"2026-08-12 19:47:14.000000000","message":"not really clear how/why this condition means the http_status \u003d\u003d 404 ???","commit_id":"18867fed23f40bf2117321bc895bf8b0a31abd5f"},{"author":{"_account_id":1179,"name":"Clay Gerrard","email":"clay.gerrard@gmail.com","username":"clay-gerrard"},"change_message_id":"f4b675b73574e7fd3378c73a59286d2770e3aed0","unresolved":true,"context_lines":[{"line_number":66,"context_line":"                stderr.flush()"},{"line_number":67,"context_line":"        if not hasattr(msg_or_exc, \u0027http_status\u0027) or \\"},{"line_number":68,"context_line":"                msg_or_exc.http_status not in (404, 507):"},{"line_number":69,"context_line":"            print(\u0027ERROR: %s: %s\u0027 % (prefix, msg_or_exc), file\u003dstderr)"},{"line_number":70,"context_line":"            stderr.flush()"},{"line_number":71,"context_line":"    return error_log"},{"line_number":72,"context_line":""}],"source_content_type":"text/x-python","patch_set":31,"id":"23847758_60e7dea9","line":69,"updated":"2026-08-12 19:47:14.000000000","message":"I worry that we don\u0027t get any metric for these kinds of errors - i\u0027m not sure whey they would come up in practice?  timeout?","commit_id":"18867fed23f40bf2117321bc895bf8b0a31abd5f"},{"author":{"_account_id":1179,"name":"Clay Gerrard","email":"clay.gerrard@gmail.com","username":"clay-gerrard"},"change_message_id":"f4b675b73574e7fd3378c73a59286d2770e3aed0","unresolved":true,"context_lines":[{"line_number":76,"context_line":"                                prom_client):"},{"line_number":77,"context_line":"    with connpool.item() as conn:"},{"line_number":78,"context_line":"        containers \u003d [c[\u0027name\u0027] for c in conn.get_account("},{"line_number":79,"context_line":"            prefix\u003d\u0027dispersion_%d\u0027 % policy.idx, full_listing\u003dTrue)[1]]"},{"line_number":80,"context_line":"    containers_listed \u003d len(containers)"},{"line_number":81,"context_line":"    if not containers_listed:"},{"line_number":82,"context_line":"        print(\u0027No containers to query. Has \u0027"}],"source_content_type":"text/x-python","patch_set":31,"id":"6db62c24_c4ccae67","line":79,"updated":"2026-08-12 19:47:14.000000000","message":"this is weird - it looks like we\u0027re creating a set of container dbs for each object storage policy - i don\u0027t get how this could have possibly been backwards compatible with a pre-storage-policy-swift container dispersion report populate","commit_id":"18867fed23f40bf2117321bc895bf8b0a31abd5f"},{"author":{"_account_id":15343,"name":"Tim Burke","email":"tburke@nvidia.com","username":"tburke"},"change_message_id":"9c6154e2387e517c97e955e4be18f467f1539068","unresolved":true,"context_lines":[{"line_number":76,"context_line":"                                prom_client):"},{"line_number":77,"context_line":"    with connpool.item() as conn:"},{"line_number":78,"context_line":"        containers \u003d [c[\u0027name\u0027] for c in conn.get_account("},{"line_number":79,"context_line":"            prefix\u003d\u0027dispersion_%d\u0027 % policy.idx, full_listing\u003dTrue)[1]]"},{"line_number":80,"context_line":"    containers_listed \u003d len(containers)"},{"line_number":81,"context_line":"    if not containers_listed:"},{"line_number":82,"context_line":"        print(\u0027No containers to query. Has \u0027"}],"source_content_type":"text/x-python","patch_set":31,"id":"b15ac4cf_676cb593","line":79,"in_reply_to":"6db62c24_c4ccae67","updated":"2026-08-20 16:36:42.000000000","message":"I don\u0027t think it was: https://review.opendev.org/c/openstack/swift/+/185459\n\nPretty sure you had to run a fresh `swift-dispersion-populate` following upgrade. :-/\n\nIn all fairness, though, you have to re-run `swift-dispersion-populate` now and then anyway -- like following a part power increase.","commit_id":"18867fed23f40bf2117321bc895bf8b0a31abd5f"},{"author":{"_account_id":1179,"name":"Clay Gerrard","email":"clay.gerrard@gmail.com","username":"clay-gerrard"},"change_message_id":"f4b675b73574e7fd3378c73a59286d2770e3aed0","unresolved":true,"context_lines":[{"line_number":279,"context_line":"    value \u003d 100.0 * copies_found / copies_expected"},{"line_number":280,"context_line":"    elapsed, elapsed_unit \u003d get_time_units(time() - begun)"},{"line_number":281,"context_line":""},{"line_number":282,"context_line":"    if prom_client:"},{"line_number":283,"context_line":"        labels \u003d {\u0027policy\u0027: policy.name}"},{"line_number":284,"context_line":"        prom_client.record(\u0027swift_dispersion_object_copies_found\u0027,"},{"line_number":285,"context_line":"                           copies_found, labels)"}],"source_content_type":"text/x-python","patch_set":31,"id":"b0daf472_e948bce4","line":282,"updated":"2026-08-12 19:47:14.000000000","message":"i think this is never false and that we can make this \"unconditional\" - which I think would be great for two reasons:\n\n1) less indentation is easier to fit on my terminal\n2) less cyclomatic complexity is easier to fit in my brain","commit_id":"18867fed23f40bf2117321bc895bf8b0a31abd5f"},{"author":{"_account_id":35790,"name":"Shreeya Deshpande","email":"shreeyad@nvidia.com","username":"shreeyad"},"change_message_id":"87fcda1404be12041baad4f1a0f5b45868d053eb","unresolved":false,"context_lines":[{"line_number":279,"context_line":"    value \u003d 100.0 * copies_found / copies_expected"},{"line_number":280,"context_line":"    elapsed, elapsed_unit \u003d get_time_units(time() - begun)"},{"line_number":281,"context_line":""},{"line_number":282,"context_line":"    if prom_client:"},{"line_number":283,"context_line":"        labels \u003d {\u0027policy\u0027: policy.name}"},{"line_number":284,"context_line":"        prom_client.record(\u0027swift_dispersion_object_copies_found\u0027,"},{"line_number":285,"context_line":"                           copies_found, labels)"}],"source_content_type":"text/x-python","patch_set":31,"id":"e4f64208_ccb5b435","line":282,"in_reply_to":"b0daf472_e948bce4","updated":"2026-08-19 00:33:23.000000000","message":"Acknowledged","commit_id":"18867fed23f40bf2117321bc895bf8b0a31abd5f"},{"author":{"_account_id":1179,"name":"Clay Gerrard","email":"clay.gerrard@gmail.com","username":"clay-gerrard"},"change_message_id":"f4b675b73574e7fd3378c73a59286d2770e3aed0","unresolved":true,"context_lines":[{"line_number":280,"context_line":"    elapsed, elapsed_unit \u003d get_time_units(time() - begun)"},{"line_number":281,"context_line":""},{"line_number":282,"context_line":"    if prom_client:"},{"line_number":283,"context_line":"        labels \u003d {\u0027policy\u0027: policy.name}"},{"line_number":284,"context_line":"        prom_client.record(\u0027swift_dispersion_object_copies_found\u0027,"},{"line_number":285,"context_line":"                           copies_found, labels)"},{"line_number":286,"context_line":"        prom_client.record(\u0027swift_dispersion_object_copies_expected\u0027,"}],"source_content_type":"text/x-python","patch_set":31,"id":"051aad7b_676a10d4","line":283,"updated":"2026-08-12 19:47:14.000000000","message":"let\u0027s keep this consistent with other policy labels in statsd:\n\nhttps://github.com/NVIDIA/swift/blob/master/swift/common/middleware/proxy_logging.py#L640C13-L640C27\n\ni.e. use `int(policy)` as the value","commit_id":"18867fed23f40bf2117321bc895bf8b0a31abd5f"},{"author":{"_account_id":35790,"name":"Shreeya Deshpande","email":"shreeyad@nvidia.com","username":"shreeyad"},"change_message_id":"87fcda1404be12041baad4f1a0f5b45868d053eb","unresolved":false,"context_lines":[{"line_number":280,"context_line":"    elapsed, elapsed_unit \u003d get_time_units(time() - begun)"},{"line_number":281,"context_line":""},{"line_number":282,"context_line":"    if prom_client:"},{"line_number":283,"context_line":"        labels \u003d {\u0027policy\u0027: policy.name}"},{"line_number":284,"context_line":"        prom_client.record(\u0027swift_dispersion_object_copies_found\u0027,"},{"line_number":285,"context_line":"                           copies_found, labels)"},{"line_number":286,"context_line":"        prom_client.record(\u0027swift_dispersion_object_copies_expected\u0027,"}],"source_content_type":"text/x-python","patch_set":31,"id":"622b00d7_4118d642","line":283,"in_reply_to":"051aad7b_676a10d4","updated":"2026-08-19 00:33:23.000000000","message":"Done","commit_id":"18867fed23f40bf2117321bc895bf8b0a31abd5f"},{"author":{"_account_id":15343,"name":"Tim Burke","email":"tburke@nvidia.com","username":"tburke"},"change_message_id":"9c6154e2387e517c97e955e4be18f467f1539068","unresolved":true,"context_lines":[{"line_number":40,"context_line":"insecure \u003d False"},{"line_number":41,"context_line":""},{"line_number":42,"context_line":""},{"line_number":43,"context_line":"def get_error_log(prefix, client, labels):"},{"line_number":44,"context_line":"    # Accept either a labels dict (preferred) or a legacy single value"},{"line_number":45,"context_line":"    # (e.g. policy name/index). Coerce to a dict so callers that still"},{"line_number":46,"context_line":"    # pass a non-dict value remain compatible with the new API."}],"source_content_type":"text/x-python","patch_set":38,"id":"b497b85b_d02ef3fe","line":43,"range":{"start_line":43,"start_character":26,"end_line":43,"end_character":32},"updated":"2026-08-20 16:36:42.000000000","message":"Better as `prom_client`, like you\u0027ve got elsewhere.","commit_id":"26f57d0f85308e1e6ef67aeaab127d713180929c"},{"author":{"_account_id":35790,"name":"Shreeya Deshpande","email":"shreeyad@nvidia.com","username":"shreeyad"},"change_message_id":"d9d6f299480079f24880cdc8eea4e25a2b370bdb","unresolved":false,"context_lines":[{"line_number":40,"context_line":"insecure \u003d False"},{"line_number":41,"context_line":""},{"line_number":42,"context_line":""},{"line_number":43,"context_line":"def get_error_log(prefix, client, labels):"},{"line_number":44,"context_line":"    # Accept either a labels dict (preferred) or a legacy single value"},{"line_number":45,"context_line":"    # (e.g. policy name/index). Coerce to a dict so callers that still"},{"line_number":46,"context_line":"    # pass a non-dict value remain compatible with the new API."}],"source_content_type":"text/x-python","patch_set":38,"id":"ff53587f_a1a41a08","line":43,"range":{"start_line":43,"start_character":26,"end_line":43,"end_character":32},"in_reply_to":"b497b85b_d02ef3fe","updated":"2026-08-25 20:25:32.000000000","message":"Acknowledged","commit_id":"26f57d0f85308e1e6ef67aeaab127d713180929c"},{"author":{"_account_id":15343,"name":"Tim Burke","email":"tburke@nvidia.com","username":"tburke"},"change_message_id":"9c6154e2387e517c97e955e4be18f467f1539068","unresolved":true,"context_lines":[{"line_number":156,"context_line":"    elapsed, elapsed_unit \u003d get_time_units(time() - begun)"},{"line_number":157,"context_line":"    container_copies_missing.pop(0, None)"},{"line_number":158,"context_line":""},{"line_number":159,"context_line":"    labels \u003d {\u0027policy\u0027: int(policy)}"},{"line_number":160,"context_line":"    prom_client.record(\u0027swift_dispersion_container_copies_found\u0027,"},{"line_number":161,"context_line":"                       copies_found, labels)"},{"line_number":162,"context_line":"    prom_client.record(\u0027swift_dispersion_container_copies_expected\u0027,"}],"source_content_type":"text/x-python","patch_set":38,"id":"32052580_ce48029e","line":159,"updated":"2026-08-20 16:36:42.000000000","message":"I\u0027m starting to see what this means, but I\u0027m still not sure I *like* it. Do we really want ops to need to create dispersion-report DBs for every container-ring part for every policy? I\u0027m not clear how that\u0027s better than just creating DBs with random policies (or always policy 0, or always default policy) for every container-ring part.\n\nLike, the interesting thing here is how well DB replicas are tracking their primary assigned locations, right? And for that, policy shouldn\u0027t really have any influence.\n\nI could almost say \"well, let\u0027s figure it out in a follow-up that takes a closer look at `container_dispersion_report` and `policy`\" but then we\u0027re putting it in our metrics pipeline... and I\u0027m not sure how disruptive it\u0027ll be for ops if we fix that later as opposed to getting it right *first*.","commit_id":"26f57d0f85308e1e6ef67aeaab127d713180929c"},{"author":{"_account_id":15343,"name":"Tim Burke","email":"tburke@nvidia.com","username":"tburke"},"change_message_id":"9c6154e2387e517c97e955e4be18f467f1539068","unresolved":true,"context_lines":[{"line_number":304,"context_line":"    prom_client.record(\u0027swift_dispersion_object_distinct_partitions\u0027,"},{"line_number":305,"context_line":"                       distinct_partitions, labels)"},{"line_number":306,"context_line":"    for missing_copies, num_parts in object_copies_missing.items():"},{"line_number":307,"context_line":"        if not missing_copies:"},{"line_number":308,"context_line":"            continue"},{"line_number":309,"context_line":"        prom_client.record("},{"line_number":310,"context_line":"            \u0027swift_dispersion_object_partitions_missing\u0027,"}],"source_content_type":"text/x-python","patch_set":38,"id":"01ca2173_7ef93b0f","line":307,"range":{"start_line":307,"start_character":11,"end_line":307,"end_character":29},"updated":"2026-08-20 16:36:42.000000000","message":"Interesting that the prom metrics skip these, but the JSON output doesn\u0027t. Is there a reason?\n\nOh, and for the container report, we *don\u0027t* have this filter... yeah, this feels off.","commit_id":"26f57d0f85308e1e6ef67aeaab127d713180929c"},{"author":{"_account_id":35790,"name":"Shreeya Deshpande","email":"shreeyad@nvidia.com","username":"shreeyad"},"change_message_id":"d9d6f299480079f24880cdc8eea4e25a2b370bdb","unresolved":false,"context_lines":[{"line_number":304,"context_line":"    prom_client.record(\u0027swift_dispersion_object_distinct_partitions\u0027,"},{"line_number":305,"context_line":"                       distinct_partitions, labels)"},{"line_number":306,"context_line":"    for missing_copies, num_parts in object_copies_missing.items():"},{"line_number":307,"context_line":"        if not missing_copies:"},{"line_number":308,"context_line":"            continue"},{"line_number":309,"context_line":"        prom_client.record("},{"line_number":310,"context_line":"            \u0027swift_dispersion_object_partitions_missing\u0027,"}],"source_content_type":"text/x-python","patch_set":38,"id":"c0c46dc5_6b485623","line":307,"range":{"start_line":307,"start_character":11,"end_line":307,"end_character":29},"in_reply_to":"01ca2173_7ef93b0f","updated":"2026-08-25 20:25:32.000000000","message":"agree, container_copies_missing gets pop(0, None) before the output stage, which effectively drops the “0 missing copies” bucket.\nobject_copies_missing does not do that, instead, it skips the zero bucket only in the Prometheus metrics loop. made it consistent!","commit_id":"26f57d0f85308e1e6ef67aeaab127d713180929c"},{"author":{"_account_id":15343,"name":"Tim Burke","email":"tburke@nvidia.com","username":"tburke"},"change_message_id":"9c6154e2387e517c97e955e4be18f467f1539068","unresolved":true,"context_lines":[{"line_number":331,"context_line":"        return None"},{"line_number":332,"context_line":"    else:"},{"line_number":333,"context_line":"        results \u003d {\u0027retries\u0027: retries_done[0],"},{"line_number":334,"context_line":"                   \u0027overlapping\u0027: objects_listed - distinct_partitions,"},{"line_number":335,"context_line":"                   \u0027pct_found\u0027: value,"},{"line_number":336,"context_line":"                   \u0027copies_found\u0027: copies_found,"},{"line_number":337,"context_line":"                   \u0027copies_expected\u0027: copies_expected}"}],"source_content_type":"text/x-python","patch_set":38,"id":"59731689_68900a98","line":334,"updated":"2026-08-20 16:36:42.000000000","message":"OK, so prom metrics can compute this as `swift_dispersion_object_partitions_queried - swift_dispersion_object_distinct_partitions`, right?\n\nAre `objects_listed` and `objects_queried[0]` *always* the same following that `coropool.waitall()`? Seems like they should be, anyway...","commit_id":"26f57d0f85308e1e6ef67aeaab127d713180929c"},{"author":{"_account_id":35790,"name":"Shreeya Deshpande","email":"shreeyad@nvidia.com","username":"shreeyad"},"change_message_id":"d9d6f299480079f24880cdc8eea4e25a2b370bdb","unresolved":false,"context_lines":[{"line_number":331,"context_line":"        return None"},{"line_number":332,"context_line":"    else:"},{"line_number":333,"context_line":"        results \u003d {\u0027retries\u0027: retries_done[0],"},{"line_number":334,"context_line":"                   \u0027overlapping\u0027: objects_listed - distinct_partitions,"},{"line_number":335,"context_line":"                   \u0027pct_found\u0027: value,"},{"line_number":336,"context_line":"                   \u0027copies_found\u0027: copies_found,"},{"line_number":337,"context_line":"                   \u0027copies_expected\u0027: copies_expected}"}],"source_content_type":"text/x-python","patch_set":38,"id":"044dd282_3cb1eb2e","line":334,"in_reply_to":"59731689_68900a98","updated":"2026-08-25 20:25:32.000000000","message":"yes, prom metrics can compute that!\nyes!","commit_id":"26f57d0f85308e1e6ef67aeaab127d713180929c"}],"swift/common/direct_client.py":[{"author":{"_account_id":1179,"name":"Clay Gerrard","email":"clay.gerrard@gmail.com","username":"clay-gerrard"},"change_message_id":"f4b675b73574e7fd3378c73a59286d2770e3aed0","unresolved":true,"context_lines":[{"line_number":639,"context_line":"    :raises ClientException: all retries failed"},{"line_number":640,"context_line":"    \"\"\""},{"line_number":641,"context_line":"    retries \u003d kwargs.pop(\u0027retries\u0027, 5)"},{"line_number":642,"context_line":"    error_log \u003d kwargs.pop(\u0027error_log\u0027)"},{"line_number":643,"context_line":"    attempts \u003d 0"},{"line_number":644,"context_line":"    backoff \u003d 1"},{"line_number":645,"context_line":"    while attempts \u003c\u003d retries:"}],"source_content_type":"text/x-python","patch_set":31,"id":"e74c9746_f2c0cfc5","line":642,"updated":"2026-08-12 19:47:14.000000000","message":"this makes the error_log kwarg required - that\u0027s not really what kwargs are for\n\nif have a use-case for making this kwarg *non-optional* (???) we could spell it more natively like this:\n\n```\n\u003e\u003e\u003e def myfunc(arg1, *, kwarg1\u003dNone, kwarg2):\n...     print(arg1, kwarg1, kwarg2)\n```","commit_id":"18867fed23f40bf2117321bc895bf8b0a31abd5f"},{"author":{"_account_id":6968,"name":"Christian Schwede","email":"cschwede@nvidia.com","username":"cschwede"},"change_message_id":"94e9721088820c5a45e8bebabe75c50196537916","unresolved":true,"context_lines":[{"line_number":639,"context_line":"    :raises ClientException: all retries failed"},{"line_number":640,"context_line":"    \"\"\""},{"line_number":641,"context_line":"    retries \u003d kwargs.pop(\u0027retries\u0027, 5)"},{"line_number":642,"context_line":"    error_log \u003d kwargs.pop(\u0027error_log\u0027)"},{"line_number":643,"context_line":"    attempts \u003d 0"},{"line_number":644,"context_line":"    backoff \u003d 1"},{"line_number":645,"context_line":"    while attempts \u003c\u003d retries:"}],"source_content_type":"text/x-python","patch_set":31,"id":"f73e5af7_ae1ba514","line":642,"in_reply_to":"e74c9746_f2c0cfc5","updated":"2026-08-17 09:56:56.000000000","message":"Agree, and the docstring a few lines above still mentions that `error_log` is dropped IF sent.","commit_id":"18867fed23f40bf2117321bc895bf8b0a31abd5f"},{"author":{"_account_id":35790,"name":"Shreeya Deshpande","email":"shreeyad@nvidia.com","username":"shreeyad"},"change_message_id":"87fcda1404be12041baad4f1a0f5b45868d053eb","unresolved":false,"context_lines":[{"line_number":639,"context_line":"    :raises ClientException: all retries failed"},{"line_number":640,"context_line":"    \"\"\""},{"line_number":641,"context_line":"    retries \u003d kwargs.pop(\u0027retries\u0027, 5)"},{"line_number":642,"context_line":"    error_log \u003d kwargs.pop(\u0027error_log\u0027)"},{"line_number":643,"context_line":"    attempts \u003d 0"},{"line_number":644,"context_line":"    backoff \u003d 1"},{"line_number":645,"context_line":"    while attempts \u003c\u003d retries:"}],"source_content_type":"text/x-python","patch_set":31,"id":"0ce2006f_da051f8a","line":642,"in_reply_to":"f73e5af7_ae1ba514","updated":"2026-08-19 00:33:23.000000000","message":"Done","commit_id":"18867fed23f40bf2117321bc895bf8b0a31abd5f"},{"author":{"_account_id":1179,"name":"Clay Gerrard","email":"clay.gerrard@gmail.com","username":"clay-gerrard"},"change_message_id":"f4b675b73574e7fd3378c73a59286d2770e3aed0","unresolved":true,"context_lines":[{"line_number":647,"context_line":"        try:"},{"line_number":648,"context_line":"            return attempts, func(*args, **kwargs)"},{"line_number":649,"context_line":"        except (socket.error, HTTPException, Timeout) as err:"},{"line_number":650,"context_line":"            if error_log:"},{"line_number":651,"context_line":"                error_log(err)"},{"line_number":652,"context_line":"            if attempts \u003e retries:"},{"line_number":653,"context_line":"                raise"}],"source_content_type":"text/x-python","patch_set":31,"id":"58b15bb5_57570c83","line":650,"updated":"2026-08-12 19:47:14.000000000","message":"this sort of seems re-dundant now?\n\nOR!!! let\u0027s just allow callers to not provide error_log and not make ANY changes to direct_client or test_direct_client!","commit_id":"18867fed23f40bf2117321bc895bf8b0a31abd5f"},{"author":{"_account_id":35790,"name":"Shreeya Deshpande","email":"shreeyad@nvidia.com","username":"shreeyad"},"change_message_id":"87fcda1404be12041baad4f1a0f5b45868d053eb","unresolved":false,"context_lines":[{"line_number":647,"context_line":"        try:"},{"line_number":648,"context_line":"            return attempts, func(*args, **kwargs)"},{"line_number":649,"context_line":"        except (socket.error, HTTPException, Timeout) as err:"},{"line_number":650,"context_line":"            if error_log:"},{"line_number":651,"context_line":"                error_log(err)"},{"line_number":652,"context_line":"            if attempts \u003e retries:"},{"line_number":653,"context_line":"                raise"}],"source_content_type":"text/x-python","patch_set":31,"id":"441eece3_f995e4cb","line":650,"in_reply_to":"58b15bb5_57570c83","updated":"2026-08-19 00:33:23.000000000","message":"Acknowledged","commit_id":"18867fed23f40bf2117321bc895bf8b0a31abd5f"}],"swift/common/prom_metrics.py":[{"author":{"_account_id":1179,"name":"Clay Gerrard","email":"clay.gerrard@gmail.com","username":"clay-gerrard"},"change_message_id":"f4b675b73574e7fd3378c73a59286d2770e3aed0","unresolved":true,"context_lines":[{"line_number":297,"context_line":"    def write_all_stats(self, filename\u003dNone):"},{"line_number":298,"context_line":"        filename \u003d filename or self.filename"},{"line_number":299,"context_line":"        if not filename:"},{"line_number":300,"context_line":"            return self.get_all_stats_data()"},{"line_number":301,"context_line":"        stats_data \u003d self.get_all_stats()"},{"line_number":302,"context_line":"        tf \u003d None"},{"line_number":303,"context_line":"        try:"}],"source_content_type":"text/x-python","patch_set":31,"id":"803ca2da_a7bffcab","line":300,"updated":"2026-08-12 19:47:14.000000000","message":"this is a significant behavior change - it should be in the commit message","commit_id":"18867fed23f40bf2117321bc895bf8b0a31abd5f"},{"author":{"_account_id":35790,"name":"Shreeya Deshpande","email":"shreeyad@nvidia.com","username":"shreeyad"},"change_message_id":"87fcda1404be12041baad4f1a0f5b45868d053eb","unresolved":false,"context_lines":[{"line_number":297,"context_line":"    def write_all_stats(self, filename\u003dNone):"},{"line_number":298,"context_line":"        filename \u003d filename or self.filename"},{"line_number":299,"context_line":"        if not filename:"},{"line_number":300,"context_line":"            return self.get_all_stats_data()"},{"line_number":301,"context_line":"        stats_data \u003d self.get_all_stats()"},{"line_number":302,"context_line":"        tf \u003d None"},{"line_number":303,"context_line":"        try:"}],"source_content_type":"text/x-python","patch_set":31,"id":"e17c9815_382bd821","line":300,"in_reply_to":"803ca2da_a7bffcab","updated":"2026-08-19 00:33:23.000000000","message":"Done","commit_id":"18867fed23f40bf2117321bc895bf8b0a31abd5f"}],"test/unit/cli/test_dispersion_report.py":[{"author":{"_account_id":38767,"name":"Wael Halbawi","display_name":"Wael Halbawi","email":"whalbawi@nvidia.com","username":"whalbawi"},"change_message_id":"ad3f89585e29271466d0cb47deeeb68215272dc2","unresolved":true,"context_lines":[{"line_number":64,"context_line":"    return ring"},{"line_number":65,"context_line":""},{"line_number":66,"context_line":""},{"line_number":67,"context_line":"class TestMissingString(unittest.TestCase):"},{"line_number":68,"context_line":""},{"line_number":69,"context_line":"    def test_all_copies_missing(self):"},{"line_number":70,"context_line":"        result \u003d dispersion_report.missing_string(1, 3, 3)"}],"source_content_type":"text/x-python","patch_set":13,"id":"c18e9949_890ce24f","line":67,"range":{"start_line":67,"start_character":0,"end_line":67,"end_character":43},"updated":"2026-05-18 22:01:50.000000000","message":"I don\u0027t see an associated diff in the implementation file. Is this a rogue change or did you intend to expand test coverage for `missing_string`?","commit_id":"d43b4af67d87eb1f98707fed6b3ff433f00a6d5f"},{"author":{"_account_id":35790,"name":"Shreeya Deshpande","email":"shreeyad@nvidia.com","username":"shreeyad"},"change_message_id":"c3e08cd5bf3119b0547abbde356f6fdedb898b44","unresolved":false,"context_lines":[{"line_number":64,"context_line":"    return ring"},{"line_number":65,"context_line":""},{"line_number":66,"context_line":""},{"line_number":67,"context_line":"class TestMissingString(unittest.TestCase):"},{"line_number":68,"context_line":""},{"line_number":69,"context_line":"    def test_all_copies_missing(self):"},{"line_number":70,"context_line":"        result \u003d dispersion_report.missing_string(1, 3, 3)"}],"source_content_type":"text/x-python","patch_set":13,"id":"e9400b2b_93c4e564","line":67,"range":{"start_line":67,"start_character":0,"end_line":67,"end_character":43},"in_reply_to":"c18e9949_890ce24f","updated":"2026-05-21 21:49:26.000000000","message":"just adding test coverage, not exactly related with the changes!","commit_id":"d43b4af67d87eb1f98707fed6b3ff433f00a6d5f"},{"author":{"_account_id":38767,"name":"Wael Halbawi","display_name":"Wael Halbawi","email":"whalbawi@nvidia.com","username":"whalbawi"},"change_message_id":"ad3f89585e29271466d0cb47deeeb68215272dc2","unresolved":true,"context_lines":[{"line_number":109,"context_line":"        p.idx \u003d idx"},{"line_number":110,"context_line":"        return p"},{"line_number":111,"context_line":""},{"line_number":112,"context_line":"    def test_no_containers_returns_none(self):"},{"line_number":113,"context_line":"        result \u003d dispersion_report.container_dispersion_report("},{"line_number":114,"context_line":"            make_coropool(), make_connpool(containers\u003d[]),"},{"line_number":115,"context_line":"            \u0027AUTH_test\u0027, make_ring(), 3, False, self._policy())"}],"source_content_type":"text/x-python","patch_set":13,"id":"39192f6b_dd44e3ae","line":112,"updated":"2026-05-18 22:01:50.000000000","message":"None of the following three tests assert new behavior. Is it intentional that you\u0027re expanding test coverage?","commit_id":"d43b4af67d87eb1f98707fed6b3ff433f00a6d5f"},{"author":{"_account_id":35790,"name":"Shreeya Deshpande","email":"shreeyad@nvidia.com","username":"shreeyad"},"change_message_id":"c3e08cd5bf3119b0547abbde356f6fdedb898b44","unresolved":false,"context_lines":[{"line_number":109,"context_line":"        p.idx \u003d idx"},{"line_number":110,"context_line":"        return p"},{"line_number":111,"context_line":""},{"line_number":112,"context_line":"    def test_no_containers_returns_none(self):"},{"line_number":113,"context_line":"        result \u003d dispersion_report.container_dispersion_report("},{"line_number":114,"context_line":"            make_coropool(), make_connpool(containers\u003d[]),"},{"line_number":115,"context_line":"            \u0027AUTH_test\u0027, make_ring(), 3, False, self._policy())"}],"source_content_type":"text/x-python","patch_set":13,"id":"31196041_1a373311","line":112,"in_reply_to":"39192f6b_dd44e3ae","updated":"2026-05-21 21:49:26.000000000","message":"yes, test coverage for dispersion_report is null! Writing tests here and there as I find feasible!","commit_id":"d43b4af67d87eb1f98707fed6b3ff433f00a6d5f"},{"author":{"_account_id":38767,"name":"Wael Halbawi","display_name":"Wael Halbawi","email":"whalbawi@nvidia.com","username":"whalbawi"},"change_message_id":"ad3f89585e29271466d0cb47deeeb68215272dc2","unresolved":true,"context_lines":[{"line_number":154,"context_line":"        prom_client.write_all_stats()"},{"line_number":155,"context_line":"        metrics \u003d read_metrics(metrics_file)"},{"line_number":156,"context_line":"        labels \u003d {\u0027policy\u0027: \u0027default\u0027}"},{"line_number":157,"context_line":"        for name in (\u0027swift_dispersion_container_copies_found\u0027,"},{"line_number":158,"context_line":"                     \u0027swift_dispersion_container_copies_expected\u0027,"},{"line_number":159,"context_line":"                     \u0027swift_dispersion_container_pct_found\u0027,"},{"line_number":160,"context_line":"                     \u0027swift_dispersion_container_retries\u0027,"}],"source_content_type":"text/x-python","patch_set":13,"id":"bf97499e_9187189e","line":157,"updated":"2026-05-18 22:01:50.000000000","message":"How about an assertion on the metric values, too?","commit_id":"d43b4af67d87eb1f98707fed6b3ff433f00a6d5f"},{"author":{"_account_id":35790,"name":"Shreeya Deshpande","email":"shreeyad@nvidia.com","username":"shreeyad"},"change_message_id":"c3e08cd5bf3119b0547abbde356f6fdedb898b44","unresolved":false,"context_lines":[{"line_number":154,"context_line":"        prom_client.write_all_stats()"},{"line_number":155,"context_line":"        metrics \u003d read_metrics(metrics_file)"},{"line_number":156,"context_line":"        labels \u003d {\u0027policy\u0027: \u0027default\u0027}"},{"line_number":157,"context_line":"        for name in (\u0027swift_dispersion_container_copies_found\u0027,"},{"line_number":158,"context_line":"                     \u0027swift_dispersion_container_copies_expected\u0027,"},{"line_number":159,"context_line":"                     \u0027swift_dispersion_container_pct_found\u0027,"},{"line_number":160,"context_line":"                     \u0027swift_dispersion_container_retries\u0027,"}],"source_content_type":"text/x-python","patch_set":13,"id":"29e754fc_c677459d","line":157,"in_reply_to":"bf97499e_9187189e","updated":"2026-05-21 21:49:26.000000000","message":"Done","commit_id":"d43b4af67d87eb1f98707fed6b3ff433f00a6d5f"},{"author":{"_account_id":38767,"name":"Wael Halbawi","display_name":"Wael Halbawi","email":"whalbawi@nvidia.com","username":"whalbawi"},"change_message_id":"ad3f89585e29271466d0cb47deeeb68215272dc2","unresolved":true,"context_lines":[{"line_number":179,"context_line":"        p.__int__ \u003d mock.Mock(return_value\u003didx)"},{"line_number":180,"context_line":"        return p"},{"line_number":181,"context_line":""},{"line_number":182,"context_line":"    def test_no_objects_returns_none(self):"},{"line_number":183,"context_line":"        result \u003d dispersion_report.object_dispersion_report("},{"line_number":184,"context_line":"            make_coropool(), make_connpool(objects\u003d[]),"},{"line_number":185,"context_line":"            \u0027AUTH_test\u0027, make_ring(), 3, False, self._policy())"}],"source_content_type":"text/x-python","patch_set":13,"id":"45201c09_f63d745d","line":182,"updated":"2026-05-18 22:01:50.000000000","message":"Are the three following tests just for expanding coverage? It would be useful to describe the scope of this patch in the commit message.","commit_id":"d43b4af67d87eb1f98707fed6b3ff433f00a6d5f"},{"author":{"_account_id":35790,"name":"Shreeya Deshpande","email":"shreeyad@nvidia.com","username":"shreeyad"},"change_message_id":"c3e08cd5bf3119b0547abbde356f6fdedb898b44","unresolved":false,"context_lines":[{"line_number":179,"context_line":"        p.__int__ \u003d mock.Mock(return_value\u003didx)"},{"line_number":180,"context_line":"        return p"},{"line_number":181,"context_line":""},{"line_number":182,"context_line":"    def test_no_objects_returns_none(self):"},{"line_number":183,"context_line":"        result \u003d dispersion_report.object_dispersion_report("},{"line_number":184,"context_line":"            make_coropool(), make_connpool(objects\u003d[]),"},{"line_number":185,"context_line":"            \u0027AUTH_test\u0027, make_ring(), 3, False, self._policy())"}],"source_content_type":"text/x-python","patch_set":13,"id":"4be35e5e_3ab809f5","line":182,"in_reply_to":"45201c09_f63d745d","updated":"2026-05-21 21:49:26.000000000","message":"Acknowledged","commit_id":"d43b4af67d87eb1f98707fed6b3ff433f00a6d5f"},{"author":{"_account_id":38767,"name":"Wael Halbawi","display_name":"Wael Halbawi","email":"whalbawi@nvidia.com","username":"whalbawi"},"change_message_id":"ad3f89585e29271466d0cb47deeeb68215272dc2","unresolved":true,"context_lines":[{"line_number":231,"context_line":"            self.assertIn(metric_key(name, **labels), metrics)"},{"line_number":232,"context_line":""},{"line_number":233,"context_line":""},{"line_number":234,"context_line":"# maybe not needed?"},{"line_number":235,"context_line":"class TestPrometheusClient(unittest.TestCase):"},{"line_number":236,"context_line":""},{"line_number":237,"context_line":"    @with_tempdir"}],"source_content_type":"text/x-python","patch_set":13,"id":"c8e4d5e6_168869cd","line":234,"updated":"2026-05-18 22:01:50.000000000","message":"Because they test the client itself? Seems reasonable to move them somewhere else. None of these tests depend on `dispersion_report.py`.","commit_id":"d43b4af67d87eb1f98707fed6b3ff433f00a6d5f"},{"author":{"_account_id":35790,"name":"Shreeya Deshpande","email":"shreeyad@nvidia.com","username":"shreeyad"},"change_message_id":"c3e08cd5bf3119b0547abbde356f6fdedb898b44","unresolved":false,"context_lines":[{"line_number":231,"context_line":"            self.assertIn(metric_key(name, **labels), metrics)"},{"line_number":232,"context_line":""},{"line_number":233,"context_line":""},{"line_number":234,"context_line":"# maybe not needed?"},{"line_number":235,"context_line":"class TestPrometheusClient(unittest.TestCase):"},{"line_number":236,"context_line":""},{"line_number":237,"context_line":"    @with_tempdir"}],"source_content_type":"text/x-python","patch_set":13,"id":"cff86713_bc4b4b6a","line":234,"in_reply_to":"1b907828_eee81337","updated":"2026-05-21 21:49:26.000000000","message":"I feel that the prom client is well tested in test_prom_metrics.py already!","commit_id":"d43b4af67d87eb1f98707fed6b3ff433f00a6d5f"},{"author":{"_account_id":7233,"name":"Matthew Oliver","email":"matt@oliver.net.au","username":"mattoliverau"},"change_message_id":"ec08556bc082dbf4c7572c5e0ff1d388a0f936c7","unresolved":true,"context_lines":[{"line_number":231,"context_line":"            self.assertIn(metric_key(name, **labels), metrics)"},{"line_number":232,"context_line":""},{"line_number":233,"context_line":""},{"line_number":234,"context_line":"# maybe not needed?"},{"line_number":235,"context_line":"class TestPrometheusClient(unittest.TestCase):"},{"line_number":236,"context_line":""},{"line_number":237,"context_line":"    @with_tempdir"}],"source_content_type":"text/x-python","patch_set":13,"id":"1b907828_eee81337","line":234,"in_reply_to":"c8e4d5e6_168869cd","updated":"2026-05-21 02:05:10.000000000","message":"If it\u0027s generic enough, maybe it could be placed in test_prom_metrics maybe? but if there is specific tests for dispersion related metrics then it could stay, seems `test_records_metrics_to_prom_client` does a pretty good job of getting dispersion metrics, serialising them to the prom file and pulling them back out. So maybe these could be moved.","commit_id":"d43b4af67d87eb1f98707fed6b3ff433f00a6d5f"},{"author":{"_account_id":7233,"name":"Matthew Oliver","email":"matt@oliver.net.au","username":"mattoliverau"},"change_message_id":"ec08556bc082dbf4c7572c5e0ff1d388a0f936c7","unresolved":true,"context_lines":[{"line_number":236,"context_line":""},{"line_number":237,"context_line":"    @with_tempdir"},{"line_number":238,"context_line":"    def test_initializes_from_conf(self, tempdir):"},{"line_number":239,"context_line":"        metrics_file \u003d os.path.join(tempdir, \u0027metrics.txt\u0027)"},{"line_number":240,"context_line":"        client \u003d get_prometheus_client({\u0027metrics_filename\u0027: metrics_file})"},{"line_number":241,"context_line":"        self.assertIsNotNone(client)"},{"line_number":242,"context_line":"        self.assertEqual(client.filename, metrics_file)"}],"source_content_type":"text/x-python","patch_set":16,"id":"f7d79526_49247a82","line":239,"range":{"start_line":239,"start_character":46,"end_line":239,"end_character":57},"updated":"2026-05-21 02:05:10.000000000","message":"Are we expecting these to be .txt files in real life, or should be make them .prom or something?\n\nI know it probably doesn\u0027t matter. But feel .txt seems wrong here.","commit_id":"04622259f9d7182666e8f0c6b675cda3ffcf36f9"},{"author":{"_account_id":1179,"name":"Clay Gerrard","email":"clay.gerrard@gmail.com","username":"clay-gerrard"},"change_message_id":"d7553688a4dd66be2c1630cf986c5d31061ecb06","unresolved":true,"context_lines":[{"line_number":236,"context_line":""},{"line_number":237,"context_line":"    @with_tempdir"},{"line_number":238,"context_line":"    def test_initializes_from_conf(self, tempdir):"},{"line_number":239,"context_line":"        metrics_file \u003d os.path.join(tempdir, \u0027metrics.txt\u0027)"},{"line_number":240,"context_line":"        client \u003d get_prometheus_client({\u0027metrics_filename\u0027: metrics_file})"},{"line_number":241,"context_line":"        self.assertIsNotNone(client)"},{"line_number":242,"context_line":"        self.assertEqual(client.filename, metrics_file)"}],"source_content_type":"text/x-python","patch_set":16,"id":"74b4e884_ce40f9ae","line":239,"range":{"start_line":239,"start_character":46,"end_line":239,"end_character":57},"in_reply_to":"2e1bba15_ed7907b0","updated":"2026-05-27 06:36:17.000000000","message":"look in `/opt/ss/support/metrics`","commit_id":"04622259f9d7182666e8f0c6b675cda3ffcf36f9"},{"author":{"_account_id":35790,"name":"Shreeya Deshpande","email":"shreeyad@nvidia.com","username":"shreeyad"},"change_message_id":"1423f06064b21424504a40a5d725f69e824378fd","unresolved":false,"context_lines":[{"line_number":236,"context_line":""},{"line_number":237,"context_line":"    @with_tempdir"},{"line_number":238,"context_line":"    def test_initializes_from_conf(self, tempdir):"},{"line_number":239,"context_line":"        metrics_file \u003d os.path.join(tempdir, \u0027metrics.txt\u0027)"},{"line_number":240,"context_line":"        client \u003d get_prometheus_client({\u0027metrics_filename\u0027: metrics_file})"},{"line_number":241,"context_line":"        self.assertIsNotNone(client)"},{"line_number":242,"context_line":"        self.assertEqual(client.filename, metrics_file)"}],"source_content_type":"text/x-python","patch_set":16,"id":"a7e0a3dd_e07d41a6","line":239,"range":{"start_line":239,"start_character":46,"end_line":239,"end_character":57},"in_reply_to":"74b4e884_ce40f9ae","updated":"2026-07-15 02:05:55.000000000","message":"Done","commit_id":"04622259f9d7182666e8f0c6b675cda3ffcf36f9"},{"author":{"_account_id":35790,"name":"Shreeya Deshpande","email":"shreeyad@nvidia.com","username":"shreeyad"},"change_message_id":"c3e08cd5bf3119b0547abbde356f6fdedb898b44","unresolved":true,"context_lines":[{"line_number":236,"context_line":""},{"line_number":237,"context_line":"    @with_tempdir"},{"line_number":238,"context_line":"    def test_initializes_from_conf(self, tempdir):"},{"line_number":239,"context_line":"        metrics_file \u003d os.path.join(tempdir, \u0027metrics.txt\u0027)"},{"line_number":240,"context_line":"        client \u003d get_prometheus_client({\u0027metrics_filename\u0027: metrics_file})"},{"line_number":241,"context_line":"        self.assertIsNotNone(client)"},{"line_number":242,"context_line":"        self.assertEqual(client.filename, metrics_file)"}],"source_content_type":"text/x-python","patch_set":16,"id":"2e1bba15_ed7907b0","line":239,"range":{"start_line":239,"start_character":46,"end_line":239,"end_character":57},"in_reply_to":"f7d79526_49247a82","updated":"2026-05-21 21:49:26.000000000","message":"Yep! .prom would look better! I dont know if they are goinf to be .txt in real life. @clay.gerrard@gmail.com any idea?","commit_id":"04622259f9d7182666e8f0c6b675cda3ffcf36f9"},{"author":{"_account_id":22348,"name":"Zuul","username":"zuul","tags":["SERVICE_USER"]},"tag":"autogenerated:zuul:check","change_message_id":"2abd6edb985b8318f8e2e9a085dd35c68ed68c1c","unresolved":false,"context_lines":[{"line_number":10,"context_line":"# License for the specific language governing permissions and limitations"},{"line_number":11,"context_line":"# under the License."},{"line_number":12,"context_line":""},{"line_number":13,"context_line":"\u003c\u003c\u003c\u003c\u003c\u003c\u003c PATCH SET (03c57a11098cde4945060f74ba582791c28c3a03 add prom metrics to dispersion report)"},{"line_number":14,"context_line":"import os"},{"line_number":15,"context_line":"\u003d\u003d\u003d\u003d\u003d\u003d\u003d"},{"line_number":16,"context_line":"from io import StringIO"}],"source_content_type":"text/x-python","patch_set":24,"id":"e1bccae1_79a94445","line":13,"updated":"2026-07-13 14:45:05.000000000","message":"pep8: E999 SyntaxError: leading zeros in decimal integer literals are not permitted; use an 0o prefix for octal integers","commit_id":"4df6e0d883fc0ef371be86f20a0ce00b0c86f3dd"},{"author":{"_account_id":22348,"name":"Zuul","username":"zuul","tags":["SERVICE_USER"]},"tag":"autogenerated:zuul:check","change_message_id":"ed4e8103a55e3ab6e3cb254edb678dfb1958cf34","unresolved":false,"context_lines":[{"line_number":112,"context_line":"        self.assertEqual(prom_client._stats, {})"},{"line_number":113,"context_line":""},{"line_number":114,"context_line":""},{"line_number":115,"context_line":"    def test_unmounted_device_is_reported_once_across_loggers(self):"},{"line_number":116,"context_line":"        \"\"\"Test unmounted devices are reported once per report run.\"\"\""},{"line_number":117,"context_line":"        prom_client \u003d get_prometheus_client({})"},{"line_number":118,"context_line":"        container_error_log \u003d dispersion_report.get_error_log("}],"source_content_type":"text/x-python","patch_set":25,"id":"97dea99d_731ea16e","line":115,"updated":"2026-07-14 21:06:48.000000000","message":"pep8: E303 too many blank lines (2)","commit_id":"5baedea203ef2c7548f71c0efe8eca4272d332bf"},{"author":{"_account_id":22348,"name":"Zuul","username":"zuul","tags":["SERVICE_USER"]},"tag":"autogenerated:zuul:check","change_message_id":"ed4e8103a55e3ab6e3cb254edb678dfb1958cf34","unresolved":false,"context_lines":[{"line_number":172,"context_line":""},{"line_number":173,"context_line":"class TestMissingString(unittest.TestCase):"},{"line_number":174,"context_line":""},{"line_number":175,"context_line":"    "},{"line_number":176,"context_line":"    def test_single_partition_single_copy_missing(self):"},{"line_number":177,"context_line":"        result \u003d dispersion_report.missing_string(1, 1, 3)"},{"line_number":178,"context_line":"        self.assertEqual(result, \u0027There was 1 partition missing 1 copy.\u0027)"}],"source_content_type":"text/x-python","patch_set":25,"id":"da42d9af_9d93bb6c","line":175,"updated":"2026-07-14 21:06:48.000000000","message":"pep8: W293 blank line contains whitespace","commit_id":"5baedea203ef2c7548f71c0efe8eca4272d332bf"},{"author":{"_account_id":22348,"name":"Zuul","username":"zuul","tags":["SERVICE_USER"]},"tag":"autogenerated:zuul:check","change_message_id":"ed4e8103a55e3ab6e3cb254edb678dfb1958cf34","unresolved":false,"context_lines":[{"line_number":173,"context_line":"class TestMissingString(unittest.TestCase):"},{"line_number":174,"context_line":""},{"line_number":175,"context_line":"    "},{"line_number":176,"context_line":"    def test_single_partition_single_copy_missing(self):"},{"line_number":177,"context_line":"        result \u003d dispersion_report.missing_string(1, 1, 3)"},{"line_number":178,"context_line":"        self.assertEqual(result, \u0027There was 1 partition missing 1 copy.\u0027)"},{"line_number":179,"context_line":""}],"source_content_type":"text/x-python","patch_set":25,"id":"f5ee1383_c8d27ea7","line":176,"updated":"2026-07-14 21:06:48.000000000","message":"pep8: E303 too many blank lines (2)","commit_id":"5baedea203ef2c7548f71c0efe8eca4272d332bf"},{"author":{"_account_id":22348,"name":"Zuul","username":"zuul","tags":["SERVICE_USER"]},"tag":"autogenerated:zuul:check","change_message_id":"ed4e8103a55e3ab6e3cb254edb678dfb1958cf34","unresolved":false,"context_lines":[{"line_number":307,"context_line":"            with self.assertRaises(SystemExit):"},{"line_number":308,"context_line":"                dispersion_report.generate_report(conf,"},{"line_number":309,"context_line":"                                                  policy_name\u003d\u0027nonexistent\u0027)"},{"line_number":310,"context_line":"    "},{"line_number":311,"context_line":""},{"line_number":312,"context_line":"class TestContainerDispersionReport(unittest.TestCase):"},{"line_number":313,"context_line":""}],"source_content_type":"text/x-python","patch_set":25,"id":"c1036f11_19fc32dd","line":310,"updated":"2026-07-14 21:06:48.000000000","message":"pep8: W293 blank line contains whitespace","commit_id":"5baedea203ef2c7548f71c0efe8eca4272d332bf"},{"author":{"_account_id":22348,"name":"Zuul","username":"zuul","tags":["SERVICE_USER"]},"tag":"autogenerated:zuul:check","change_message_id":"ed4e8103a55e3ab6e3cb254edb678dfb1958cf34","unresolved":false,"context_lines":[{"line_number":514,"context_line":"            metric_key(\u0027swift_dispersion_container_copies_expected\u0027,"},{"line_number":515,"context_line":"                       policy\u003d\u0027default\u0027): 50.0,"},{"line_number":516,"context_line":"            metric_key(\u0027swift_dispersion_object_copies_found\u0027,"},{"line_number":517,"context_line":"                        policy\u003d\u0027default\u0027): 45.0,"},{"line_number":518,"context_line":"            metric_key(\u0027swift_dispersion_object_copies_expected\u0027,"},{"line_number":519,"context_line":"                       policy\u003d\u0027default\u0027): 50.0,"},{"line_number":520,"context_line":"        })"}],"source_content_type":"text/x-python","patch_set":25,"id":"c01fc229_b63b6821","line":517,"updated":"2026-07-14 21:06:48.000000000","message":"pep8: E127 continuation line over-indented for visual indent","commit_id":"5baedea203ef2c7548f71c0efe8eca4272d332bf"},{"author":{"_account_id":22348,"name":"Zuul","username":"zuul","tags":["SERVICE_USER"]},"tag":"autogenerated:zuul:check","change_message_id":"8352f51693c9f6ddd56502ad9d6e8af35f253835","unresolved":false,"context_lines":[{"line_number":112,"context_line":"        self.assertEqual(prom_client._stats, {})"},{"line_number":113,"context_line":""},{"line_number":114,"context_line":""},{"line_number":115,"context_line":"    def test_unmounted_device_is_reported_once_across_loggers(self):"},{"line_number":116,"context_line":"        \"\"\"Test unmounted devices are reported once per report run.\"\"\""},{"line_number":117,"context_line":"        prom_client \u003d get_prometheus_client({})"},{"line_number":118,"context_line":"        container_error_log \u003d dispersion_report.get_error_log("}],"source_content_type":"text/x-python","patch_set":26,"id":"40fd34ea_246312b5","line":115,"updated":"2026-07-15 16:49:34.000000000","message":"pep8: E303 too many blank lines (2)","commit_id":"30c1b36c9958838490851bacdfac4eda68514755"},{"author":{"_account_id":22348,"name":"Zuul","username":"zuul","tags":["SERVICE_USER"]},"tag":"autogenerated:zuul:check","change_message_id":"8352f51693c9f6ddd56502ad9d6e8af35f253835","unresolved":false,"context_lines":[{"line_number":172,"context_line":""},{"line_number":173,"context_line":"class TestMissingString(unittest.TestCase):"},{"line_number":174,"context_line":""},{"line_number":175,"context_line":"    "},{"line_number":176,"context_line":"    def test_single_partition_single_copy_missing(self):"},{"line_number":177,"context_line":"        result \u003d dispersion_report.missing_string(1, 1, 3)"},{"line_number":178,"context_line":"        self.assertEqual(result, \u0027There was 1 partition missing 1 copy.\u0027)"}],"source_content_type":"text/x-python","patch_set":26,"id":"abdf3b7f_3308e05c","line":175,"updated":"2026-07-15 16:49:34.000000000","message":"pep8: W293 blank line contains whitespace","commit_id":"30c1b36c9958838490851bacdfac4eda68514755"},{"author":{"_account_id":22348,"name":"Zuul","username":"zuul","tags":["SERVICE_USER"]},"tag":"autogenerated:zuul:check","change_message_id":"8352f51693c9f6ddd56502ad9d6e8af35f253835","unresolved":false,"context_lines":[{"line_number":173,"context_line":"class TestMissingString(unittest.TestCase):"},{"line_number":174,"context_line":""},{"line_number":175,"context_line":"    "},{"line_number":176,"context_line":"    def test_single_partition_single_copy_missing(self):"},{"line_number":177,"context_line":"        result \u003d dispersion_report.missing_string(1, 1, 3)"},{"line_number":178,"context_line":"        self.assertEqual(result, \u0027There was 1 partition missing 1 copy.\u0027)"},{"line_number":179,"context_line":""}],"source_content_type":"text/x-python","patch_set":26,"id":"d91c8b64_67971483","line":176,"updated":"2026-07-15 16:49:34.000000000","message":"pep8: E303 too many blank lines (2)","commit_id":"30c1b36c9958838490851bacdfac4eda68514755"},{"author":{"_account_id":22348,"name":"Zuul","username":"zuul","tags":["SERVICE_USER"]},"tag":"autogenerated:zuul:check","change_message_id":"8352f51693c9f6ddd56502ad9d6e8af35f253835","unresolved":false,"context_lines":[{"line_number":307,"context_line":"            with self.assertRaises(SystemExit):"},{"line_number":308,"context_line":"                dispersion_report.generate_report(conf,"},{"line_number":309,"context_line":"                                                  policy_name\u003d\u0027nonexistent\u0027)"},{"line_number":310,"context_line":"    "},{"line_number":311,"context_line":""},{"line_number":312,"context_line":"class TestContainerDispersionReport(unittest.TestCase):"},{"line_number":313,"context_line":""}],"source_content_type":"text/x-python","patch_set":26,"id":"8da383b6_99570897","line":310,"updated":"2026-07-15 16:49:34.000000000","message":"pep8: W293 blank line contains whitespace","commit_id":"30c1b36c9958838490851bacdfac4eda68514755"},{"author":{"_account_id":22348,"name":"Zuul","username":"zuul","tags":["SERVICE_USER"]},"tag":"autogenerated:zuul:check","change_message_id":"8352f51693c9f6ddd56502ad9d6e8af35f253835","unresolved":false,"context_lines":[{"line_number":514,"context_line":"            metric_key(\u0027swift_dispersion_container_copies_expected\u0027,"},{"line_number":515,"context_line":"                       policy\u003d\u0027default\u0027): 50.0,"},{"line_number":516,"context_line":"            metric_key(\u0027swift_dispersion_object_copies_found\u0027,"},{"line_number":517,"context_line":"                        policy\u003d\u0027default\u0027): 45.0,"},{"line_number":518,"context_line":"            metric_key(\u0027swift_dispersion_object_copies_expected\u0027,"},{"line_number":519,"context_line":"                       policy\u003d\u0027default\u0027): 50.0,"},{"line_number":520,"context_line":"        })"}],"source_content_type":"text/x-python","patch_set":26,"id":"7ea4770d_7cf8632c","line":517,"updated":"2026-07-15 16:49:34.000000000","message":"pep8: E127 continuation line over-indented for visual indent","commit_id":"30c1b36c9958838490851bacdfac4eda68514755"},{"author":{"_account_id":22348,"name":"Zuul","username":"zuul","tags":["SERVICE_USER"]},"tag":"autogenerated:zuul:check","change_message_id":"194bba9ded73e7a780f93edd56692ad764f9cd8e","unresolved":false,"context_lines":[{"line_number":112,"context_line":"        self.assertEqual(prom_client._stats, {})"},{"line_number":113,"context_line":""},{"line_number":114,"context_line":""},{"line_number":115,"context_line":"    def test_unmounted_device_is_reported_once_across_loggers(self):"},{"line_number":116,"context_line":"        \"\"\"Test unmounted devices are reported once per report run.\"\"\""},{"line_number":117,"context_line":"        prom_client \u003d get_prometheus_client({})"},{"line_number":118,"context_line":"        container_error_log \u003d dispersion_report.get_error_log("}],"source_content_type":"text/x-python","patch_set":27,"id":"18fa1b49_b1afce74","line":115,"updated":"2026-08-03 17:23:58.000000000","message":"pep8: E303 too many blank lines (2)","commit_id":"15f5958dc16a611fd3f233d3aa537c5efc746612"},{"author":{"_account_id":22348,"name":"Zuul","username":"zuul","tags":["SERVICE_USER"]},"tag":"autogenerated:zuul:check","change_message_id":"194bba9ded73e7a780f93edd56692ad764f9cd8e","unresolved":false,"context_lines":[{"line_number":172,"context_line":""},{"line_number":173,"context_line":"class TestMissingString(unittest.TestCase):"},{"line_number":174,"context_line":""},{"line_number":175,"context_line":"    "},{"line_number":176,"context_line":"    def test_single_partition_single_copy_missing(self):"},{"line_number":177,"context_line":"        result \u003d dispersion_report.missing_string(1, 1, 3)"},{"line_number":178,"context_line":"        self.assertEqual(result, \u0027There was 1 partition missing 1 copy.\u0027)"}],"source_content_type":"text/x-python","patch_set":27,"id":"8abbb5da_db6c41a6","line":175,"updated":"2026-08-03 17:23:58.000000000","message":"pep8: W293 blank line contains whitespace","commit_id":"15f5958dc16a611fd3f233d3aa537c5efc746612"},{"author":{"_account_id":22348,"name":"Zuul","username":"zuul","tags":["SERVICE_USER"]},"tag":"autogenerated:zuul:check","change_message_id":"194bba9ded73e7a780f93edd56692ad764f9cd8e","unresolved":false,"context_lines":[{"line_number":173,"context_line":"class TestMissingString(unittest.TestCase):"},{"line_number":174,"context_line":""},{"line_number":175,"context_line":"    "},{"line_number":176,"context_line":"    def test_single_partition_single_copy_missing(self):"},{"line_number":177,"context_line":"        result \u003d dispersion_report.missing_string(1, 1, 3)"},{"line_number":178,"context_line":"        self.assertEqual(result, \u0027There was 1 partition missing 1 copy.\u0027)"},{"line_number":179,"context_line":""}],"source_content_type":"text/x-python","patch_set":27,"id":"3b956234_86dd6a13","line":176,"updated":"2026-08-03 17:23:58.000000000","message":"pep8: E303 too many blank lines (2)","commit_id":"15f5958dc16a611fd3f233d3aa537c5efc746612"},{"author":{"_account_id":22348,"name":"Zuul","username":"zuul","tags":["SERVICE_USER"]},"tag":"autogenerated:zuul:check","change_message_id":"194bba9ded73e7a780f93edd56692ad764f9cd8e","unresolved":false,"context_lines":[{"line_number":307,"context_line":"            with self.assertRaises(SystemExit):"},{"line_number":308,"context_line":"                dispersion_report.generate_report(conf,"},{"line_number":309,"context_line":"                                                  policy_name\u003d\u0027nonexistent\u0027)"},{"line_number":310,"context_line":"    "},{"line_number":311,"context_line":""},{"line_number":312,"context_line":"class TestContainerDispersionReport(unittest.TestCase):"},{"line_number":313,"context_line":""}],"source_content_type":"text/x-python","patch_set":27,"id":"080494ad_997425fe","line":310,"updated":"2026-08-03 17:23:58.000000000","message":"pep8: W293 blank line contains whitespace","commit_id":"15f5958dc16a611fd3f233d3aa537c5efc746612"},{"author":{"_account_id":22348,"name":"Zuul","username":"zuul","tags":["SERVICE_USER"]},"tag":"autogenerated:zuul:check","change_message_id":"194bba9ded73e7a780f93edd56692ad764f9cd8e","unresolved":false,"context_lines":[{"line_number":514,"context_line":"            metric_key(\u0027swift_dispersion_container_copies_expected\u0027,"},{"line_number":515,"context_line":"                       policy\u003d\u0027default\u0027): 50.0,"},{"line_number":516,"context_line":"            metric_key(\u0027swift_dispersion_object_copies_found\u0027,"},{"line_number":517,"context_line":"                        policy\u003d\u0027default\u0027): 45.0,"},{"line_number":518,"context_line":"            metric_key(\u0027swift_dispersion_object_copies_expected\u0027,"},{"line_number":519,"context_line":"                       policy\u003d\u0027default\u0027): 50.0,"},{"line_number":520,"context_line":"        })"}],"source_content_type":"text/x-python","patch_set":27,"id":"92ba5a78_29c52bb4","line":517,"updated":"2026-08-03 17:23:58.000000000","message":"pep8: E127 continuation line over-indented for visual indent","commit_id":"15f5958dc16a611fd3f233d3aa537c5efc746612"},{"author":{"_account_id":22348,"name":"Zuul","username":"zuul","tags":["SERVICE_USER"]},"tag":"autogenerated:zuul:check","change_message_id":"c1209d470b0e1e467638c236f05ea31dddd93e85","unresolved":false,"context_lines":[{"line_number":112,"context_line":"        self.assertEqual(prom_client._stats, {})"},{"line_number":113,"context_line":""},{"line_number":114,"context_line":""},{"line_number":115,"context_line":"    def test_unmounted_device_is_reported_once_across_loggers(self):"},{"line_number":116,"context_line":"        \"\"\"Test unmounted devices are reported once per report run.\"\"\""},{"line_number":117,"context_line":"        prom_client \u003d get_prometheus_client({})"},{"line_number":118,"context_line":"        container_error_log \u003d dispersion_report.get_error_log("}],"source_content_type":"text/x-python","patch_set":28,"id":"c17fefea_da7fef18","line":115,"updated":"2026-08-07 15:46:01.000000000","message":"pep8: E303 too many blank lines (2)","commit_id":"5b40b39d09698d7b0002608f5b321cf342e8be5f"},{"author":{"_account_id":22348,"name":"Zuul","username":"zuul","tags":["SERVICE_USER"]},"tag":"autogenerated:zuul:check","change_message_id":"c1209d470b0e1e467638c236f05ea31dddd93e85","unresolved":false,"context_lines":[{"line_number":172,"context_line":""},{"line_number":173,"context_line":"class TestMissingString(unittest.TestCase):"},{"line_number":174,"context_line":""},{"line_number":175,"context_line":"    "},{"line_number":176,"context_line":"    def test_single_partition_single_copy_missing(self):"},{"line_number":177,"context_line":"        result \u003d dispersion_report.missing_string(1, 1, 3)"},{"line_number":178,"context_line":"        self.assertEqual(result, \u0027There was 1 partition missing 1 copy.\u0027)"}],"source_content_type":"text/x-python","patch_set":28,"id":"fff91ac4_ebefe42a","line":175,"updated":"2026-08-07 15:46:01.000000000","message":"pep8: W293 blank line contains whitespace","commit_id":"5b40b39d09698d7b0002608f5b321cf342e8be5f"},{"author":{"_account_id":22348,"name":"Zuul","username":"zuul","tags":["SERVICE_USER"]},"tag":"autogenerated:zuul:check","change_message_id":"c1209d470b0e1e467638c236f05ea31dddd93e85","unresolved":false,"context_lines":[{"line_number":173,"context_line":"class TestMissingString(unittest.TestCase):"},{"line_number":174,"context_line":""},{"line_number":175,"context_line":"    "},{"line_number":176,"context_line":"    def test_single_partition_single_copy_missing(self):"},{"line_number":177,"context_line":"        result \u003d dispersion_report.missing_string(1, 1, 3)"},{"line_number":178,"context_line":"        self.assertEqual(result, \u0027There was 1 partition missing 1 copy.\u0027)"},{"line_number":179,"context_line":""}],"source_content_type":"text/x-python","patch_set":28,"id":"c496ea6d_34c1b642","line":176,"updated":"2026-08-07 15:46:01.000000000","message":"pep8: E303 too many blank lines (2)","commit_id":"5b40b39d09698d7b0002608f5b321cf342e8be5f"},{"author":{"_account_id":22348,"name":"Zuul","username":"zuul","tags":["SERVICE_USER"]},"tag":"autogenerated:zuul:check","change_message_id":"c1209d470b0e1e467638c236f05ea31dddd93e85","unresolved":false,"context_lines":[{"line_number":307,"context_line":"            with self.assertRaises(SystemExit):"},{"line_number":308,"context_line":"                dispersion_report.generate_report(conf,"},{"line_number":309,"context_line":"                                                  policy_name\u003d\u0027nonexistent\u0027)"},{"line_number":310,"context_line":"    "},{"line_number":311,"context_line":""},{"line_number":312,"context_line":"class TestContainerDispersionReport(unittest.TestCase):"},{"line_number":313,"context_line":""}],"source_content_type":"text/x-python","patch_set":28,"id":"a1e93d46_8d91d01b","line":310,"updated":"2026-08-07 15:46:01.000000000","message":"pep8: W293 blank line contains whitespace","commit_id":"5b40b39d09698d7b0002608f5b321cf342e8be5f"},{"author":{"_account_id":22348,"name":"Zuul","username":"zuul","tags":["SERVICE_USER"]},"tag":"autogenerated:zuul:check","change_message_id":"c1209d470b0e1e467638c236f05ea31dddd93e85","unresolved":false,"context_lines":[{"line_number":514,"context_line":"            metric_key(\u0027swift_dispersion_container_copies_expected\u0027,"},{"line_number":515,"context_line":"                       policy\u003d\u0027default\u0027): 50.0,"},{"line_number":516,"context_line":"            metric_key(\u0027swift_dispersion_object_copies_found\u0027,"},{"line_number":517,"context_line":"                        policy\u003d\u0027default\u0027): 45.0,"},{"line_number":518,"context_line":"            metric_key(\u0027swift_dispersion_object_copies_expected\u0027,"},{"line_number":519,"context_line":"                       policy\u003d\u0027default\u0027): 50.0,"},{"line_number":520,"context_line":"        })"}],"source_content_type":"text/x-python","patch_set":28,"id":"b931e343_718ceb6d","line":517,"updated":"2026-08-07 15:46:01.000000000","message":"pep8: E127 continuation line over-indented for visual indent","commit_id":"5b40b39d09698d7b0002608f5b321cf342e8be5f"},{"author":{"_account_id":1179,"name":"Clay Gerrard","email":"clay.gerrard@gmail.com","username":"clay-gerrard"},"change_message_id":"f4b675b73574e7fd3378c73a59286d2770e3aed0","unresolved":true,"context_lines":[{"line_number":23,"context_line":"    metric_key"},{"line_number":24,"context_line":""},{"line_number":25,"context_line":""},{"line_number":26,"context_line":"def read_metrics(filename):"},{"line_number":27,"context_line":"    metrics \u003d {}"},{"line_number":28,"context_line":"    with open(filename) as f:"},{"line_number":29,"context_line":"        for line in f:"}],"source_content_type":"text/x-python","patch_set":31,"id":"2e7f037c_a00166b4","line":26,"updated":"2026-08-12 19:47:14.000000000","message":"is this duplicated with test_prometheus_client\u0027s read_metrics?\n\nlet\u0027s move this method into prom_metrics module as a first class citizen","commit_id":"18867fed23f40bf2117321bc895bf8b0a31abd5f"},{"author":{"_account_id":35790,"name":"Shreeya Deshpande","email":"shreeyad@nvidia.com","username":"shreeyad"},"change_message_id":"87fcda1404be12041baad4f1a0f5b45868d053eb","unresolved":false,"context_lines":[{"line_number":23,"context_line":"    metric_key"},{"line_number":24,"context_line":""},{"line_number":25,"context_line":""},{"line_number":26,"context_line":"def read_metrics(filename):"},{"line_number":27,"context_line":"    metrics \u003d {}"},{"line_number":28,"context_line":"    with open(filename) as f:"},{"line_number":29,"context_line":"        for line in f:"}],"source_content_type":"text/x-python","patch_set":31,"id":"0c2730b2_17414ce4","line":26,"in_reply_to":"2e7f037c_a00166b4","updated":"2026-08-19 00:33:23.000000000","message":"Done","commit_id":"18867fed23f40bf2117321bc895bf8b0a31abd5f"},{"author":{"_account_id":1179,"name":"Clay Gerrard","email":"clay.gerrard@gmail.com","username":"clay-gerrard"},"change_message_id":"f4b675b73574e7fd3378c73a59286d2770e3aed0","unresolved":true,"context_lines":[{"line_number":286,"context_line":"        self.assertTrue(self.mock_container_dispersion_report.called)"},{"line_number":287,"context_line":"        self.assertTrue(self.mock_object_dispersion_report.called)"},{"line_number":288,"context_line":""},{"line_number":289,"context_line":"    def test_generate_report_without_metrics_filename_does_not_fail(self):"},{"line_number":290,"context_line":"        conf \u003d self._base_conf()"},{"line_number":291,"context_line":"        with self.mock_report_functions():"},{"line_number":292,"context_line":"            result \u003d dispersion_report.generate_report(conf)"}],"source_content_type":"text/x-python","patch_set":31,"id":"9227ae7d_eb37a87b","line":289,"updated":"2026-08-12 19:47:14.000000000","message":"... OR print an error","commit_id":"18867fed23f40bf2117321bc895bf8b0a31abd5f"},{"author":{"_account_id":35790,"name":"Shreeya Deshpande","email":"shreeyad@nvidia.com","username":"shreeyad"},"change_message_id":"87fcda1404be12041baad4f1a0f5b45868d053eb","unresolved":false,"context_lines":[{"line_number":286,"context_line":"        self.assertTrue(self.mock_container_dispersion_report.called)"},{"line_number":287,"context_line":"        self.assertTrue(self.mock_object_dispersion_report.called)"},{"line_number":288,"context_line":""},{"line_number":289,"context_line":"    def test_generate_report_without_metrics_filename_does_not_fail(self):"},{"line_number":290,"context_line":"        conf \u003d self._base_conf()"},{"line_number":291,"context_line":"        with self.mock_report_functions():"},{"line_number":292,"context_line":"            result \u003d dispersion_report.generate_report(conf)"}],"source_content_type":"text/x-python","patch_set":31,"id":"6ca47be6_948ecc9e","line":289,"in_reply_to":"9227ae7d_eb37a87b","updated":"2026-08-19 00:33:23.000000000","message":"we still want to get structured metrics from generate_report","commit_id":"18867fed23f40bf2117321bc895bf8b0a31abd5f"},{"author":{"_account_id":1179,"name":"Clay Gerrard","email":"clay.gerrard@gmail.com","username":"clay-gerrard"},"change_message_id":"f4b675b73574e7fd3378c73a59286d2770e3aed0","unresolved":true,"context_lines":[{"line_number":380,"context_line":"            \u0027AUTH_test\u0027, make_ring(nodes\u003dnodes), 3, False, self._policy(),"},{"line_number":381,"context_line":"            prom_client)"},{"line_number":382,"context_line":"        prom_client.write_all_stats()"},{"line_number":383,"context_line":"        metrics \u003d read_metrics(metrics_file)"},{"line_number":384,"context_line":"        self.assertEqual(metrics, {"},{"line_number":385,"context_line":"            metric_key(\u0027swift_dispersion_container_copies_found\u0027,"},{"line_number":386,"context_line":"                       {\u0027policy\u0027: \u0027default\u0027}): 3.0,"}],"source_content_type":"text/x-python","patch_set":31,"id":"10a6f3fd_12b84606","line":383,"updated":"2026-08-12 19:47:14.000000000","message":"i guess you could also just not configure a metrics_file and then `write_all_stats` *returns* the metrics dict directly","commit_id":"18867fed23f40bf2117321bc895bf8b0a31abd5f"},{"author":{"_account_id":35790,"name":"Shreeya Deshpande","email":"shreeyad@nvidia.com","username":"shreeyad"},"change_message_id":"87fcda1404be12041baad4f1a0f5b45868d053eb","unresolved":false,"context_lines":[{"line_number":380,"context_line":"            \u0027AUTH_test\u0027, make_ring(nodes\u003dnodes), 3, False, self._policy(),"},{"line_number":381,"context_line":"            prom_client)"},{"line_number":382,"context_line":"        prom_client.write_all_stats()"},{"line_number":383,"context_line":"        metrics \u003d read_metrics(metrics_file)"},{"line_number":384,"context_line":"        self.assertEqual(metrics, {"},{"line_number":385,"context_line":"            metric_key(\u0027swift_dispersion_container_copies_found\u0027,"},{"line_number":386,"context_line":"                       {\u0027policy\u0027: \u0027default\u0027}): 3.0,"}],"source_content_type":"text/x-python","patch_set":31,"id":"24dc2655_20fc9f4e","line":383,"in_reply_to":"10a6f3fd_12b84606","updated":"2026-08-19 00:33:23.000000000","message":"Done","commit_id":"18867fed23f40bf2117321bc895bf8b0a31abd5f"},{"author":{"_account_id":1179,"name":"Clay Gerrard","email":"clay.gerrard@gmail.com","username":"clay-gerrard"},"change_message_id":"f4b675b73574e7fd3378c73a59286d2770e3aed0","unresolved":true,"context_lines":[{"line_number":449,"context_line":""},{"line_number":450,"context_line":"    @with_tempdir"},{"line_number":451,"context_line":"    @mock.patch(\u0027swift.common.direct_client.retry\u0027)"},{"line_number":452,"context_line":"    def test_records_metrics_to_prom_client(self, tempdir, mock_retry):"},{"line_number":453,"context_line":"        mock_retry.return_value \u003d (1, None)"},{"line_number":454,"context_line":"        metrics_file \u003d os.path.join(tempdir, \u0027metrics.prom\u0027)"},{"line_number":455,"context_line":"        prom_client \u003d get_prometheus_client({\u0027metrics_filename\u0027: metrics_file})"}],"source_content_type":"text/x-python","patch_set":31,"id":"61d0dd76_838bc695","line":452,"updated":"2026-08-12 19:47:14.000000000","message":"should this test name include \"object\" in it somewhere?","commit_id":"18867fed23f40bf2117321bc895bf8b0a31abd5f"},{"author":{"_account_id":35790,"name":"Shreeya Deshpande","email":"shreeyad@nvidia.com","username":"shreeyad"},"change_message_id":"87fcda1404be12041baad4f1a0f5b45868d053eb","unresolved":false,"context_lines":[{"line_number":449,"context_line":""},{"line_number":450,"context_line":"    @with_tempdir"},{"line_number":451,"context_line":"    @mock.patch(\u0027swift.common.direct_client.retry\u0027)"},{"line_number":452,"context_line":"    def test_records_metrics_to_prom_client(self, tempdir, mock_retry):"},{"line_number":453,"context_line":"        mock_retry.return_value \u003d (1, None)"},{"line_number":454,"context_line":"        metrics_file \u003d os.path.join(tempdir, \u0027metrics.prom\u0027)"},{"line_number":455,"context_line":"        prom_client \u003d get_prometheus_client({\u0027metrics_filename\u0027: metrics_file})"}],"source_content_type":"text/x-python","patch_set":31,"id":"900e82a2_219320f2","line":452,"in_reply_to":"61d0dd76_838bc695","updated":"2026-08-19 00:33:23.000000000","message":"Done","commit_id":"18867fed23f40bf2117321bc895bf8b0a31abd5f"},{"author":{"_account_id":1179,"name":"Clay Gerrard","email":"clay.gerrard@gmail.com","username":"clay-gerrard"},"change_message_id":"f4b675b73574e7fd3378c73a59286d2770e3aed0","unresolved":true,"context_lines":[{"line_number":474,"context_line":"        })"},{"line_number":475,"context_line":""},{"line_number":476,"context_line":""},{"line_number":477,"context_line":"class TestPrometheusClient(unittest.TestCase):"},{"line_number":478,"context_line":""},{"line_number":479,"context_line":"    @with_tempdir"},{"line_number":480,"context_line":"    def test_initializes_from_conf(self, tempdir):"}],"source_content_type":"text/x-python","patch_set":31,"id":"3c0bcc13_7de751bf","line":477,"updated":"2026-08-12 19:47:14.000000000","message":"these probably don\u0027t belong in the test_dispersion_report module","commit_id":"18867fed23f40bf2117321bc895bf8b0a31abd5f"},{"author":{"_account_id":35790,"name":"Shreeya Deshpande","email":"shreeyad@nvidia.com","username":"shreeyad"},"change_message_id":"87fcda1404be12041baad4f1a0f5b45868d053eb","unresolved":false,"context_lines":[{"line_number":474,"context_line":"        })"},{"line_number":475,"context_line":""},{"line_number":476,"context_line":""},{"line_number":477,"context_line":"class TestPrometheusClient(unittest.TestCase):"},{"line_number":478,"context_line":""},{"line_number":479,"context_line":"    @with_tempdir"},{"line_number":480,"context_line":"    def test_initializes_from_conf(self, tempdir):"}],"source_content_type":"text/x-python","patch_set":31,"id":"d23be286_bb9ee9f2","line":477,"in_reply_to":"3c0bcc13_7de751bf","updated":"2026-08-19 00:33:23.000000000","message":"Acknowledged","commit_id":"18867fed23f40bf2117321bc895bf8b0a31abd5f"}],"test/unit/common/test_direct_client.py":[{"author":{"_account_id":1179,"name":"Clay Gerrard","email":"clay.gerrard@gmail.com","username":"clay-gerrard"},"change_message_id":"f4b675b73574e7fd3378c73a59286d2770e3aed0","unresolved":true,"context_lines":[{"line_number":1054,"context_line":"            attempts, resp \u003d direct_client.retry("},{"line_number":1055,"context_line":"                direct_client.direct_head_object, self.node, self.part,"},{"line_number":1056,"context_line":"                self.account, self.container, self.obj,"},{"line_number":1057,"context_line":"                error_log\u003dlambda err: None)"},{"line_number":1058,"context_line":"            self.assertEqual(conn.method, \u0027HEAD\u0027)"},{"line_number":1059,"context_line":"            self.assertEqual(conn.path, self.obj_path)"},{"line_number":1060,"context_line":"        self.assertEqual(conn.req_headers[\u0027user-agent\u0027], self.user_agent)"}],"source_content_type":"text/x-python","patch_set":31,"id":"b6a674a4_a1bcfa6a","line":1057,"updated":"2026-08-12 19:47:14.000000000","message":"ok, so the one and only place with test this method - we\u0027re testing it w/o the error_log kwarg to make sure that works","commit_id":"18867fed23f40bf2117321bc895bf8b0a31abd5f"},{"author":{"_account_id":35790,"name":"Shreeya Deshpande","email":"shreeyad@nvidia.com","username":"shreeyad"},"change_message_id":"87fcda1404be12041baad4f1a0f5b45868d053eb","unresolved":false,"context_lines":[{"line_number":1054,"context_line":"            attempts, resp \u003d direct_client.retry("},{"line_number":1055,"context_line":"                direct_client.direct_head_object, self.node, self.part,"},{"line_number":1056,"context_line":"                self.account, self.container, self.obj,"},{"line_number":1057,"context_line":"                error_log\u003dlambda err: None)"},{"line_number":1058,"context_line":"            self.assertEqual(conn.method, \u0027HEAD\u0027)"},{"line_number":1059,"context_line":"            self.assertEqual(conn.path, self.obj_path)"},{"line_number":1060,"context_line":"        self.assertEqual(conn.req_headers[\u0027user-agent\u0027], self.user_agent)"}],"source_content_type":"text/x-python","patch_set":31,"id":"5c05628a_80ae76d0","line":1057,"in_reply_to":"b6a674a4_a1bcfa6a","updated":"2026-08-19 00:33:23.000000000","message":"Done","commit_id":"18867fed23f40bf2117321bc895bf8b0a31abd5f"},{"author":{"_account_id":1179,"name":"Clay Gerrard","email":"clay.gerrard@gmail.com","username":"clay-gerrard"},"change_message_id":"f4b675b73574e7fd3378c73a59286d2770e3aed0","unresolved":true,"context_lines":[{"line_number":1070,"context_line":"                direct_client.retry(direct_client.direct_delete_object,"},{"line_number":1071,"context_line":"                                    self.node, self.part,"},{"line_number":1072,"context_line":"                                    self.account, self.container, self.obj,"},{"line_number":1073,"context_line":"                                    retries\u003d2, error_log\u003dlogger.error)"},{"line_number":1074,"context_line":"        self.assertEqual(\u0027DELETE\u0027, conn.method)"},{"line_number":1075,"context_line":"        self.assertEqual(err_ctx.exception.http_status, 500)"},{"line_number":1076,"context_line":"        self.assertIn(\u0027DELETE\u0027, err_ctx.exception.args[0])"}],"source_content_type":"text/x-python","patch_set":31,"id":"d63d18fa_431e8c16","line":1073,"updated":"2026-08-12 19:47:14.000000000","message":"e.g. here we test *with* the \"optional\" error_log kwarg","commit_id":"18867fed23f40bf2117321bc895bf8b0a31abd5f"},{"author":{"_account_id":35790,"name":"Shreeya Deshpande","email":"shreeyad@nvidia.com","username":"shreeyad"},"change_message_id":"87fcda1404be12041baad4f1a0f5b45868d053eb","unresolved":false,"context_lines":[{"line_number":1070,"context_line":"                direct_client.retry(direct_client.direct_delete_object,"},{"line_number":1071,"context_line":"                                    self.node, self.part,"},{"line_number":1072,"context_line":"                                    self.account, self.container, self.obj,"},{"line_number":1073,"context_line":"                                    retries\u003d2, error_log\u003dlogger.error)"},{"line_number":1074,"context_line":"        self.assertEqual(\u0027DELETE\u0027, conn.method)"},{"line_number":1075,"context_line":"        self.assertEqual(err_ctx.exception.http_status, 500)"},{"line_number":1076,"context_line":"        self.assertIn(\u0027DELETE\u0027, err_ctx.exception.args[0])"}],"source_content_type":"text/x-python","patch_set":31,"id":"97a6fdc5_87da9d86","line":1073,"in_reply_to":"d63d18fa_431e8c16","updated":"2026-08-19 00:33:23.000000000","message":"Done","commit_id":"18867fed23f40bf2117321bc895bf8b0a31abd5f"}]}
