We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
minor config-related nit with anonymous telemetry
```
10:17:08.49 [ERROR] Please set `repo_id = "<uuid>"` in the [anonymous-telemetry] section of pants.toml, where `<uuid>` is some fixed random identifier, such as one generated by uuidgen. No telemetry will be sent for this run. See https://www.pantsbuild.org/v2.7/docs/anonymous-telemetry for details.
```

Pants should just generate a UUID and display it in the message as the suggestion.

--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `src/python/pants/goal/anonymous_telemetry.py`
Content:
```
1 # Copyright 2021 Pants project contributors (see CONTRIBUTORS.md).
2 # Licensed under the Apache License, Version 2.0 (see LICENSE).
3 
4 from __future__ import annotations
5 
6 import json
7 import logging
8 import re
9 import uuid
10 from typing import cast
11 
12 from humbug.consent import HumbugConsent
13 from humbug.report import HumbugReporter, Modes, Report
14 
15 from pants.engine.internals.scheduler import Workunit
16 from pants.engine.rules import collect_rules, rule
17 from pants.engine.streaming_workunit_handler import (
18     StreamingWorkunitContext,
19     WorkunitsCallback,
20     WorkunitsCallbackFactory,
21     WorkunitsCallbackFactoryRequest,
22 )
23 from pants.engine.unions import UnionRule
24 from pants.option.option_types import BoolOption, StrOption
25 from pants.option.subsystem import Subsystem
26 from pants.util.docutil import doc_url
27 from pants.util.strutil import softwrap
28 
29 logger = logging.getLogger(__name__)
30 
31 
32 _bugout_access_token = "974b1acc-e052-4e5f-a45e-bae928e47bb0"
33 _telemetry_docs_referral = f"See {doc_url('anonymous-telemetry')} for details"
34 
35 
36 class AnonymousTelemetry(Subsystem):
37     options_scope = "anonymous-telemetry"
38     help = "Options related to sending anonymous stats to the Pants project, to aid development."
39 
40     enabled = BoolOption(
41         "--enabled",
42         default=False,
43         help=softwrap(
44             f"""
45             Whether to send anonymous telemetry to the Pants project.
46 
47             Telemetry is sent asynchronously, with silent failure, and does not impact build times
48             or outcomes.
49 
50             {_telemetry_docs_referral}.
51             """
52         ),
53         advanced=True,
54     )
55     repo_id = StrOption(
56         "--repo-id",
57         default=None,
58         help=softwrap(
59             f"""
60             An anonymized ID representing this repo.
61 
62             For private repos, you likely want the ID to not be derived from, or algorithmically
63             convertible to, anything identifying the repo.
64 
65             For public repos the ID may be visible in that repo's config file, so anonymity of the
66             repo is not guaranteed (although user anonymity is always guaranteed).
67 
68             {_telemetry_docs_referral}.
69             """
70         ),
71         advanced=True,
72     )
73 
74 
75 class AnonymousTelemetryCallback(WorkunitsCallback):
76     def __init__(self, unhashed_repo_id: str) -> None:
77         super().__init__()
78         self._unhashed_repo_id = unhashed_repo_id
79 
80     # Broken out into a staticmethod for testing.
81     @staticmethod
82     def validate_repo_id(unhashed_repo_id: str) -> bool:
83         return re.match(r"^[a-zA-Z0-9-_]{30,60}$", unhashed_repo_id) is not None
84 
85     @property
86     def can_finish_async(self) -> bool:
87         # Because we don't log anything, it's safe to finish in the background.
88         return True
89 
90     def __call__(
91         self,
92         *,
93         started_workunits: tuple[Workunit, ...],
94         completed_workunits: tuple[Workunit, ...],
95         finished: bool,
96         context: StreamingWorkunitContext,
97     ) -> None:
98         if not finished:
99             return
100 
101         # Assemble and send the telemetry.
102         # Note that this method is called with finished=True only after the
103         # StreamingWorkunitHandler context ends, i.e., after end_run() has been called,
104         # so the RunTracker will have had a chance to finalize its state.
105         telemetry_data = context.run_tracker.get_anonymous_telemetry_data(self._unhashed_repo_id)
106         # TODO: Add information about any errors that occurred.
107 
108         reporter = HumbugReporter(
109             name="pantsbuild/pants",
110             # We've already established consent at this point.
111             consent=HumbugConsent(True),
112             session_id=str(telemetry_data.get("run_id", uuid.uuid4())),
113             bugout_token=_bugout_access_token,
114             timeout_seconds=5,
115             # We don't want to spawn a thread in the engine, and we're
116             # already running in a background thread in pantsd.
117             mode=Modes.SYNCHRONOUS,
118         )
119 
120         # This is copied from humbug code, to ensure that future changes to humbug
121         # don't add tags that inadvertently violate our anonymity promise.
122         system_tags = [
123             f"source:{reporter.name}",
124             f"os:{reporter.system_information.os}",
125             f"arch:{reporter.system_information.machine}",
126             f"python:{reporter.system_information.python_version_major}",
127             "python:{}.{}".format(
128                 reporter.system_information.python_version_major,
129                 reporter.system_information.python_version_minor,
130             ),
131             f"python:{reporter.system_information.python_version}",
132             f"session:{reporter.session_id}",
133         ]
134         tags = (
135             system_tags
136             + [
137                 f"pants_version:{telemetry_data.get('pants_version')}",
138                 # This is hashed, unlike the contents of the unhashed_repo_id var.
139                 f"repo:{telemetry_data.get('repo_id', 'UNKNOWN')}",
140                 f"user:{telemetry_data.get('user_id', 'UNKNOWN')}",
141                 f"machine:{telemetry_data.get('machine_id', 'UNKNOWN')}",
142                 f"duration:{telemetry_data.get('duration', '0')}",
143                 f"outcome:{telemetry_data.get('outcome', 'UNKNOWN')}",
144             ]
145             + [f"goal:{goal}" for goal in telemetry_data.get("standard_goals", [])]
146         )
147 
148         report = Report(
149             title=f"pants run {reporter.session_id}",
150             tags=tags,
151             content=json.dumps(telemetry_data, sort_keys=True),
152         )
153         reporter.publish(report)
154 
155 
156 class AnonymousTelemetryCallbackFactoryRequest:
157     """A unique request type that is installed to trigger construction of the WorkunitsCallback."""
158 
159 
160 @rule
161 def construct_callback(
162     _: AnonymousTelemetryCallbackFactoryRequest, anonymous_telemetry: AnonymousTelemetry
163 ) -> WorkunitsCallbackFactory:
164     enabled = anonymous_telemetry.enabled
165     unhashed_repo_id = anonymous_telemetry.repo_id
166 
167     if anonymous_telemetry.options.is_default("enabled"):
168         logger.warning(
169             "Please either set `enabled = true` in the [anonymous-telemetry] section of "
170             "pants.toml to enable sending anonymous stats to the Pants project to aid "
171             "development, or set `enabled = false` to disable it. No telemetry sent "
172             "for this run. An explicit setting will get rid of this message. "
173             f"{_telemetry_docs_referral}."
174         )
175     if enabled:
176         if unhashed_repo_id is None:
177             logger.error(
178                 'Please set `repo_id = "<uuid>"` in the [anonymous-telemetry] section '
179                 "of pants.toml, where `<uuid>` is some fixed random identifier, such as "
180                 "one generated by uuidgen. No telemetry will be sent for this run. "
181                 f"{_telemetry_docs_referral}."
182             )
183             enabled = False
184         elif not AnonymousTelemetryCallback.validate_repo_id(unhashed_repo_id):
185             logger.error(
186                 "The repo_id option in the [anonymous-telemetry] scope must be between 30 and "
187                 "60 characters long, and consist of only alphanumeric characters, dashes "
188                 "and underscores."
189             )
190             enabled = False
191 
192     return WorkunitsCallbackFactory(
193         lambda: AnonymousTelemetryCallback(cast(str, unhashed_repo_id)) if enabled else None
194     )
195 
196 
197 def rules():
198     return [
199         UnionRule(WorkunitsCallbackFactoryRequest, AnonymousTelemetryCallbackFactoryRequest),
200         *collect_rules(),
201     ]
202
```
--- END FILES ---

Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.

Here is an example:

```diff
diff --git a/examples/server_async.py b/examples/server_async.py
--- a/examples/server_async.py
+++ b/examples/server_async.py
@@ -313,4 +313,4 @@
 
 
 if __name__ == "__main__":
-    asyncio.run(run_async_server("."), debug=True)
+    asyncio.run(run_async_server(), debug=True)
diff --git a/examples/server_sync.py b/examples/server_sync.py
--- a/examples/server_sync.py
+++ b/examples/server_sync.py
@@ -313,5 +313,5 @@
 
 
 if __name__ == "__main__":
-    server = run_sync_server(".")
+    server = run_sync_server()
     server.shutdown()

```

diff --git a/src/python/pants/goal/anonymous_telemetry.py b/src/python/pants/goal/anonymous_telemetry.py
--- a/src/python/pants/goal/anonymous_telemetry.py
+++ b/src/python/pants/goal/anonymous_telemetry.py
@@ -166,26 +166,45 @@
 
     if anonymous_telemetry.options.is_default("enabled"):
         logger.warning(
-            "Please either set `enabled = true` in the [anonymous-telemetry] section of "
-            "pants.toml to enable sending anonymous stats to the Pants project to aid "
-            "development, or set `enabled = false` to disable it. No telemetry sent "
-            "for this run. An explicit setting will get rid of this message. "
-            f"{_telemetry_docs_referral}."
+            softwrap(
+                f"""
+                Please either set `enabled = true` in the [anonymous-telemetry] section of
+                pants.toml to enable sending anonymous stats to the Pants project to aid
+                development, or set `enabled = false` to disable it. No telemetry sent
+                for this run. An explicit setting will get rid of this message.
+                {_telemetry_docs_referral}.
+                """
+            )
         )
     if enabled:
         if unhashed_repo_id is None:
             logger.error(
-                'Please set `repo_id = "<uuid>"` in the [anonymous-telemetry] section '
-                "of pants.toml, where `<uuid>` is some fixed random identifier, such as "
-                "one generated by uuidgen. No telemetry will be sent for this run. "
-                f"{_telemetry_docs_referral}."
+                softwrap(
+                    f"""
+                    Please set `repo_id = "<uuid>"` in the [anonymous-telemetry] section
+                    of pants.toml, where `<uuid>` is some fixed random identifier, such as
+                    one generated by uuidgen.
+
+                    Example (using a randomly generated UUID):
+
+                        [anonymous-telemetry]
+                        repo_id = "{uuid.uuid4()}"
+
+                    No telemetry will be sent for this run.
+                    {_telemetry_docs_referral}.
+                    """
+                )
             )
             enabled = False
         elif not AnonymousTelemetryCallback.validate_repo_id(unhashed_repo_id):
             logger.error(
-                "The repo_id option in the [anonymous-telemetry] scope must be between 30 and "
-                "60 characters long, and consist of only alphanumeric characters, dashes "
-                "and underscores."
+                softwrap(
+                    """
+                    The repo_id option in the [anonymous-telemetry] scope must be between 30 and
+                    60 characters long, and consist of only alphanumeric characters, dashes
+                    and underscores.
+                    """
+                )
             )
             enabled = False

{"golden_diff": "diff --git a/src/python/pants/goal/anonymous_telemetry.py b/src/python/pants/goal/anonymous_telemetry.py\n--- a/src/python/pants/goal/anonymous_telemetry.py\n+++ b/src/python/pants/goal/anonymous_telemetry.py\n@@ -166,26 +166,45 @@\n \n     if anonymous_telemetry.options.is_default(\"enabled\"):\n         logger.warning(\n-            \"Please either set `enabled = true` in the [anonymous-telemetry] section of \"\n-            \"pants.toml to enable sending anonymous stats to the Pants project to aid \"\n-            \"development, or set `enabled = false` to disable it. No telemetry sent \"\n-            \"for this run. An explicit setting will get rid of this message. \"\n-            f\"{_telemetry_docs_referral}.\"\n+            softwrap(\n+                f\"\"\"\n+                Please either set `enabled = true` in the [anonymous-telemetry] section of\n+                pants.toml to enable sending anonymous stats to the Pants project to aid\n+                development, or set `enabled = false` to disable it. No telemetry sent\n+                for this run. An explicit setting will get rid of this message.\n+                {_telemetry_docs_referral}.\n+                \"\"\"\n+            )\n         )\n     if enabled:\n         if unhashed_repo_id is None:\n             logger.error(\n-                'Please set `repo_id = \"<uuid>\"` in the [anonymous-telemetry] section '\n-                \"of pants.toml, where `<uuid>` is some fixed random identifier, such as \"\n-                \"one generated by uuidgen. No telemetry will be sent for this run. \"\n-                f\"{_telemetry_docs_referral}.\"\n+                softwrap(\n+                    f\"\"\"\n+                    Please set `repo_id = \"<uuid>\"` in the [anonymous-telemetry] section\n+                    of pants.toml, where `<uuid>` is some fixed random identifier, such as\n+                    one generated by uuidgen.\n+\n+                    Example (using a randomly generated UUID):\n+\n+                        [anonymous-telemetry]\n+                        repo_id = \"{uuid.uuid4()}\"\n+\n+                    No telemetry will be sent for this run.\n+                    {_telemetry_docs_referral}.\n+                    \"\"\"\n+                )\n             )\n             enabled = False\n         elif not AnonymousTelemetryCallback.validate_repo_id(unhashed_repo_id):\n             logger.error(\n-                \"The repo_id option in the [anonymous-telemetry] scope must be between 30 and \"\n-                \"60 characters long, and consist of only alphanumeric characters, dashes \"\n-                \"and underscores.\"\n+                softwrap(\n+                    \"\"\"\n+                    The repo_id option in the [anonymous-telemetry] scope must be between 30 and\n+                    60 characters long, and consist of only alphanumeric characters, dashes\n+                    and underscores.\n+                    \"\"\"\n+                )\n             )\n             enabled = False\n", "issue": "minor config-related nit with anonymous telemetry\n```\r\n10:17:08.49 [ERROR] Please set `repo_id = \"<uuid>\"` in the [anonymous-telemetry] section of pants.toml, where `<uuid>` is some fixed random identifier, such as one generated by uuidgen. No telemetry will be sent for this run. See https://www.pantsbuild.org/v2.7/docs/anonymous-telemetry for details.\r\n```\r\n\r\nPants should just generate a UUID and display it in the message as the suggestion.\n", "before_files": [{"content": "# Copyright 2021 Pants project contributors (see CONTRIBUTORS.md).\n# Licensed under the Apache License, Version 2.0 (see LICENSE).\n\nfrom __future__ import annotations\n\nimport json\nimport logging\nimport re\nimport uuid\nfrom typing import cast\n\nfrom humbug.consent import HumbugConsent\nfrom humbug.report import HumbugReporter, Modes, Report\n\nfrom pants.engine.internals.scheduler import Workunit\nfrom pants.engine.rules import collect_rules, rule\nfrom pants.engine.streaming_workunit_handler import (\n    StreamingWorkunitContext,\n    WorkunitsCallback,\n    WorkunitsCallbackFactory,\n    WorkunitsCallbackFactoryRequest,\n)\nfrom pants.engine.unions import UnionRule\nfrom pants.option.option_types import BoolOption, StrOption\nfrom pants.option.subsystem import Subsystem\nfrom pants.util.docutil import doc_url\nfrom pants.util.strutil import softwrap\n\nlogger = logging.getLogger(__name__)\n\n\n_bugout_access_token = \"974b1acc-e052-4e5f-a45e-bae928e47bb0\"\n_telemetry_docs_referral = f\"See {doc_url('anonymous-telemetry')} for details\"\n\n\nclass AnonymousTelemetry(Subsystem):\n    options_scope = \"anonymous-telemetry\"\n    help = \"Options related to sending anonymous stats to the Pants project, to aid development.\"\n\n    enabled = BoolOption(\n        \"--enabled\",\n        default=False,\n        help=softwrap(\n            f\"\"\"\n            Whether to send anonymous telemetry to the Pants project.\n\n            Telemetry is sent asynchronously, with silent failure, and does not impact build times\n            or outcomes.\n\n            {_telemetry_docs_referral}.\n            \"\"\"\n        ),\n        advanced=True,\n    )\n    repo_id = StrOption(\n        \"--repo-id\",\n        default=None,\n        help=softwrap(\n            f\"\"\"\n            An anonymized ID representing this repo.\n\n            For private repos, you likely want the ID to not be derived from, or algorithmically\n            convertible to, anything identifying the repo.\n\n            For public repos the ID may be visible in that repo's config file, so anonymity of the\n            repo is not guaranteed (although user anonymity is always guaranteed).\n\n            {_telemetry_docs_referral}.\n            \"\"\"\n        ),\n        advanced=True,\n    )\n\n\nclass AnonymousTelemetryCallback(WorkunitsCallback):\n    def __init__(self, unhashed_repo_id: str) -> None:\n        super().__init__()\n        self._unhashed_repo_id = unhashed_repo_id\n\n    # Broken out into a staticmethod for testing.\n    @staticmethod\n    def validate_repo_id(unhashed_repo_id: str) -> bool:\n        return re.match(r\"^[a-zA-Z0-9-_]{30,60}$\", unhashed_repo_id) is not None\n\n    @property\n    def can_finish_async(self) -> bool:\n        # Because we don't log anything, it's safe to finish in the background.\n        return True\n\n    def __call__(\n        self,\n        *,\n        started_workunits: tuple[Workunit, ...],\n        completed_workunits: tuple[Workunit, ...],\n        finished: bool,\n        context: StreamingWorkunitContext,\n    ) -> None:\n        if not finished:\n            return\n\n        # Assemble and send the telemetry.\n        # Note that this method is called with finished=True only after the\n        # StreamingWorkunitHandler context ends, i.e., after end_run() has been called,\n        # so the RunTracker will have had a chance to finalize its state.\n        telemetry_data = context.run_tracker.get_anonymous_telemetry_data(self._unhashed_repo_id)\n        # TODO: Add information about any errors that occurred.\n\n        reporter = HumbugReporter(\n            name=\"pantsbuild/pants\",\n            # We've already established consent at this point.\n            consent=HumbugConsent(True),\n            session_id=str(telemetry_data.get(\"run_id\", uuid.uuid4())),\n            bugout_token=_bugout_access_token,\n            timeout_seconds=5,\n            # We don't want to spawn a thread in the engine, and we're\n            # already running in a background thread in pantsd.\n            mode=Modes.SYNCHRONOUS,\n        )\n\n        # This is copied from humbug code, to ensure that future changes to humbug\n        # don't add tags that inadvertently violate our anonymity promise.\n        system_tags = [\n            f\"source:{reporter.name}\",\n            f\"os:{reporter.system_information.os}\",\n            f\"arch:{reporter.system_information.machine}\",\n            f\"python:{reporter.system_information.python_version_major}\",\n            \"python:{}.{}\".format(\n                reporter.system_information.python_version_major,\n                reporter.system_information.python_version_minor,\n            ),\n            f\"python:{reporter.system_information.python_version}\",\n            f\"session:{reporter.session_id}\",\n        ]\n        tags = (\n            system_tags\n            + [\n                f\"pants_version:{telemetry_data.get('pants_version')}\",\n                # This is hashed, unlike the contents of the unhashed_repo_id var.\n                f\"repo:{telemetry_data.get('repo_id', 'UNKNOWN')}\",\n                f\"user:{telemetry_data.get('user_id', 'UNKNOWN')}\",\n                f\"machine:{telemetry_data.get('machine_id', 'UNKNOWN')}\",\n                f\"duration:{telemetry_data.get('duration', '0')}\",\n                f\"outcome:{telemetry_data.get('outcome', 'UNKNOWN')}\",\n            ]\n            + [f\"goal:{goal}\" for goal in telemetry_data.get(\"standard_goals\", [])]\n        )\n\n        report = Report(\n            title=f\"pants run {reporter.session_id}\",\n            tags=tags,\n            content=json.dumps(telemetry_data, sort_keys=True),\n        )\n        reporter.publish(report)\n\n\nclass AnonymousTelemetryCallbackFactoryRequest:\n    \"\"\"A unique request type that is installed to trigger construction of the WorkunitsCallback.\"\"\"\n\n\n@rule\ndef construct_callback(\n    _: AnonymousTelemetryCallbackFactoryRequest, anonymous_telemetry: AnonymousTelemetry\n) -> WorkunitsCallbackFactory:\n    enabled = anonymous_telemetry.enabled\n    unhashed_repo_id = anonymous_telemetry.repo_id\n\n    if anonymous_telemetry.options.is_default(\"enabled\"):\n        logger.warning(\n            \"Please either set `enabled = true` in the [anonymous-telemetry] section of \"\n            \"pants.toml to enable sending anonymous stats to the Pants project to aid \"\n            \"development, or set `enabled = false` to disable it. No telemetry sent \"\n            \"for this run. An explicit setting will get rid of this message. \"\n            f\"{_telemetry_docs_referral}.\"\n        )\n    if enabled:\n        if unhashed_repo_id is None:\n            logger.error(\n                'Please set `repo_id = \"<uuid>\"` in the [anonymous-telemetry] section '\n                \"of pants.toml, where `<uuid>` is some fixed random identifier, such as \"\n                \"one generated by uuidgen. No telemetry will be sent for this run. \"\n                f\"{_telemetry_docs_referral}.\"\n            )\n            enabled = False\n        elif not AnonymousTelemetryCallback.validate_repo_id(unhashed_repo_id):\n            logger.error(\n                \"The repo_id option in the [anonymous-telemetry] scope must be between 30 and \"\n                \"60 characters long, and consist of only alphanumeric characters, dashes \"\n                \"and underscores.\"\n            )\n            enabled = False\n\n    return WorkunitsCallbackFactory(\n        lambda: AnonymousTelemetryCallback(cast(str, unhashed_repo_id)) if enabled else None\n    )\n\n\ndef rules():\n    return [\n        UnionRule(WorkunitsCallbackFactoryRequest, AnonymousTelemetryCallbackFactoryRequest),\n        *collect_rules(),\n    ]\n", "path": "src/python/pants/goal/anonymous_telemetry.py"}], "after_files": [{"content": "# Copyright 2021 Pants project contributors (see CONTRIBUTORS.md).\n# Licensed under the Apache License, Version 2.0 (see LICENSE).\n\nfrom __future__ import annotations\n\nimport json\nimport logging\nimport re\nimport uuid\nfrom typing import cast\n\nfrom humbug.consent import HumbugConsent\nfrom humbug.report import HumbugReporter, Modes, Report\n\nfrom pants.engine.internals.scheduler import Workunit\nfrom pants.engine.rules import collect_rules, rule\nfrom pants.engine.streaming_workunit_handler import (\n    StreamingWorkunitContext,\n    WorkunitsCallback,\n    WorkunitsCallbackFactory,\n    WorkunitsCallbackFactoryRequest,\n)\nfrom pants.engine.unions import UnionRule\nfrom pants.option.option_types import BoolOption, StrOption\nfrom pants.option.subsystem import Subsystem\nfrom pants.util.docutil import doc_url\nfrom pants.util.strutil import softwrap\n\nlogger = logging.getLogger(__name__)\n\n\n_bugout_access_token = \"974b1acc-e052-4e5f-a45e-bae928e47bb0\"\n_telemetry_docs_referral = f\"See {doc_url('anonymous-telemetry')} for details\"\n\n\nclass AnonymousTelemetry(Subsystem):\n    options_scope = \"anonymous-telemetry\"\n    help = \"Options related to sending anonymous stats to the Pants project, to aid development.\"\n\n    enabled = BoolOption(\n        \"--enabled\",\n        default=False,\n        help=softwrap(\n            f\"\"\"\n            Whether to send anonymous telemetry to the Pants project.\n\n            Telemetry is sent asynchronously, with silent failure, and does not impact build times\n            or outcomes.\n\n            {_telemetry_docs_referral}.\n            \"\"\"\n        ),\n        advanced=True,\n    )\n    repo_id = StrOption(\n        \"--repo-id\",\n        default=None,\n        help=softwrap(\n            f\"\"\"\n            An anonymized ID representing this repo.\n\n            For private repos, you likely want the ID to not be derived from, or algorithmically\n            convertible to, anything identifying the repo.\n\n            For public repos the ID may be visible in that repo's config file, so anonymity of the\n            repo is not guaranteed (although user anonymity is always guaranteed).\n\n            {_telemetry_docs_referral}.\n            \"\"\"\n        ),\n        advanced=True,\n    )\n\n\nclass AnonymousTelemetryCallback(WorkunitsCallback):\n    def __init__(self, unhashed_repo_id: str) -> None:\n        super().__init__()\n        self._unhashed_repo_id = unhashed_repo_id\n\n    # Broken out into a staticmethod for testing.\n    @staticmethod\n    def validate_repo_id(unhashed_repo_id: str) -> bool:\n        return re.match(r\"^[a-zA-Z0-9-_]{30,60}$\", unhashed_repo_id) is not None\n\n    @property\n    def can_finish_async(self) -> bool:\n        # Because we don't log anything, it's safe to finish in the background.\n        return True\n\n    def __call__(\n        self,\n        *,\n        started_workunits: tuple[Workunit, ...],\n        completed_workunits: tuple[Workunit, ...],\n        finished: bool,\n        context: StreamingWorkunitContext,\n    ) -> None:\n        if not finished:\n            return\n\n        # Assemble and send the telemetry.\n        # Note that this method is called with finished=True only after the\n        # StreamingWorkunitHandler context ends, i.e., after end_run() has been called,\n        # so the RunTracker will have had a chance to finalize its state.\n        telemetry_data = context.run_tracker.get_anonymous_telemetry_data(self._unhashed_repo_id)\n        # TODO: Add information about any errors that occurred.\n\n        reporter = HumbugReporter(\n            name=\"pantsbuild/pants\",\n            # We've already established consent at this point.\n            consent=HumbugConsent(True),\n            session_id=str(telemetry_data.get(\"run_id\", uuid.uuid4())),\n            bugout_token=_bugout_access_token,\n            timeout_seconds=5,\n            # We don't want to spawn a thread in the engine, and we're\n            # already running in a background thread in pantsd.\n            mode=Modes.SYNCHRONOUS,\n        )\n\n        # This is copied from humbug code, to ensure that future changes to humbug\n        # don't add tags that inadvertently violate our anonymity promise.\n        system_tags = [\n            f\"source:{reporter.name}\",\n            f\"os:{reporter.system_information.os}\",\n            f\"arch:{reporter.system_information.machine}\",\n            f\"python:{reporter.system_information.python_version_major}\",\n            \"python:{}.{}\".format(\n                reporter.system_information.python_version_major,\n                reporter.system_information.python_version_minor,\n            ),\n            f\"python:{reporter.system_information.python_version}\",\n            f\"session:{reporter.session_id}\",\n        ]\n        tags = (\n            system_tags\n            + [\n                f\"pants_version:{telemetry_data.get('pants_version')}\",\n                # This is hashed, unlike the contents of the unhashed_repo_id var.\n                f\"repo:{telemetry_data.get('repo_id', 'UNKNOWN')}\",\n                f\"user:{telemetry_data.get('user_id', 'UNKNOWN')}\",\n                f\"machine:{telemetry_data.get('machine_id', 'UNKNOWN')}\",\n                f\"duration:{telemetry_data.get('duration', '0')}\",\n                f\"outcome:{telemetry_data.get('outcome', 'UNKNOWN')}\",\n            ]\n            + [f\"goal:{goal}\" for goal in telemetry_data.get(\"standard_goals\", [])]\n        )\n\n        report = Report(\n            title=f\"pants run {reporter.session_id}\",\n            tags=tags,\n            content=json.dumps(telemetry_data, sort_keys=True),\n        )\n        reporter.publish(report)\n\n\nclass AnonymousTelemetryCallbackFactoryRequest:\n    \"\"\"A unique request type that is installed to trigger construction of the WorkunitsCallback.\"\"\"\n\n\n@rule\ndef construct_callback(\n    _: AnonymousTelemetryCallbackFactoryRequest, anonymous_telemetry: AnonymousTelemetry\n) -> WorkunitsCallbackFactory:\n    enabled = anonymous_telemetry.enabled\n    unhashed_repo_id = anonymous_telemetry.repo_id\n\n    if anonymous_telemetry.options.is_default(\"enabled\"):\n        logger.warning(\n            softwrap(\n                f\"\"\"\n                Please either set `enabled = true` in the [anonymous-telemetry] section of\n                pants.toml to enable sending anonymous stats to the Pants project to aid\n                development, or set `enabled = false` to disable it. No telemetry sent\n                for this run. An explicit setting will get rid of this message.\n                {_telemetry_docs_referral}.\n                \"\"\"\n            )\n        )\n    if enabled:\n        if unhashed_repo_id is None:\n            logger.error(\n                softwrap(\n                    f\"\"\"\n                    Please set `repo_id = \"<uuid>\"` in the [anonymous-telemetry] section\n                    of pants.toml, where `<uuid>` is some fixed random identifier, such as\n                    one generated by uuidgen.\n\n                    Example (using a randomly generated UUID):\n\n                        [anonymous-telemetry]\n                        repo_id = \"{uuid.uuid4()}\"\n\n                    No telemetry will be sent for this run.\n                    {_telemetry_docs_referral}.\n                    \"\"\"\n                )\n            )\n            enabled = False\n        elif not AnonymousTelemetryCallback.validate_repo_id(unhashed_repo_id):\n            logger.error(\n                softwrap(\n                    \"\"\"\n                    The repo_id option in the [anonymous-telemetry] scope must be between 30 and\n                    60 characters long, and consist of only alphanumeric characters, dashes\n                    and underscores.\n                    \"\"\"\n                )\n            )\n            enabled = False\n\n    return WorkunitsCallbackFactory(\n        lambda: AnonymousTelemetryCallback(cast(str, unhashed_repo_id)) if enabled else None\n    )\n\n\ndef rules():\n    return [\n        UnionRule(WorkunitsCallbackFactoryRequest, AnonymousTelemetryCallbackFactoryRequest),\n        *collect_rules(),\n    ]\n", "path": "src/python/pants/goal/anonymous_telemetry.py"}]}