We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
Track when an exception occurs in a Celery task
Similar to how we do this in other libraries
`tracked_request.tag("error", "true")`


--- 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/scout_apm/celery.py`
Content:
```
1 # coding=utf-8
2 from __future__ import absolute_import, division, print_function, unicode_literals
3 
4 import datetime as dt
5 
6 from celery.signals import before_task_publish, task_postrun, task_prerun
7 
8 import scout_apm.core
9 from scout_apm.compat import datetime_to_timestamp
10 from scout_apm.core.config import scout_config
11 from scout_apm.core.tracked_request import TrackedRequest
12 
13 
14 def before_task_publish_callback(headers=None, properties=None, **kwargs):
15     if "scout_task_start" not in headers:
16         headers["scout_task_start"] = datetime_to_timestamp(dt.datetime.utcnow())
17 
18 
19 def task_prerun_callback(task=None, **kwargs):
20     tracked_request = TrackedRequest.instance()
21     tracked_request.is_real_request = True
22 
23     start = getattr(task.request, "scout_task_start", None)
24     if start is not None:
25         now = datetime_to_timestamp(dt.datetime.utcnow())
26         try:
27             queue_time = now - start
28         except TypeError:
29             pass
30         else:
31             tracked_request.tag("queue_time", queue_time)
32 
33     task_id = getattr(task.request, "id", None)
34     if task_id:
35         tracked_request.tag("task_id", task_id)
36     parent_task_id = getattr(task.request, "parent_id", None)
37     if parent_task_id:
38         tracked_request.tag("parent_task_id", parent_task_id)
39 
40     delivery_info = task.request.delivery_info
41     tracked_request.tag("is_eager", delivery_info.get("is_eager", False))
42     tracked_request.tag("exchange", delivery_info.get("exchange", "unknown"))
43     tracked_request.tag("priority", delivery_info.get("priority", "unknown"))
44     tracked_request.tag("routing_key", delivery_info.get("routing_key", "unknown"))
45     tracked_request.tag("queue", delivery_info.get("queue", "unknown"))
46 
47     tracked_request.start_span(operation=("Job/" + task.name))
48 
49 
50 def task_postrun_callback(task=None, **kwargs):
51     tracked_request = TrackedRequest.instance()
52     tracked_request.stop_span()
53 
54 
55 def install(app=None):
56     if app is not None:
57         copy_configuration(app)
58 
59     installed = scout_apm.core.install()
60     if not installed:
61         return
62 
63     before_task_publish.connect(before_task_publish_callback)
64     task_prerun.connect(task_prerun_callback)
65     task_postrun.connect(task_postrun_callback)
66 
67 
68 def copy_configuration(app):
69     prefix = "scout_"
70     prefix_len = len(prefix)
71 
72     to_set = {}
73     for key, value in app.conf.items():
74         key_lower = key.lower()
75         if key_lower.startswith(prefix) and len(key_lower) > prefix_len:
76             scout_key = key_lower[prefix_len:]
77             to_set[scout_key] = value
78 
79     scout_config.set(**to_set)
80 
81 
82 def uninstall():
83     before_task_publish.disconnect(before_task_publish_callback)
84     task_prerun.disconnect(task_prerun_callback)
85     task_postrun.disconnect(task_postrun_callback)
86
```
--- 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/scout_apm/celery.py b/src/scout_apm/celery.py
--- a/src/scout_apm/celery.py
+++ b/src/scout_apm/celery.py
@@ -3,7 +3,7 @@
 
 import datetime as dt
 
-from celery.signals import before_task_publish, task_postrun, task_prerun
+from celery.signals import before_task_publish, task_failure, task_postrun, task_prerun
 
 import scout_apm.core
 from scout_apm.compat import datetime_to_timestamp
@@ -52,6 +52,11 @@
     tracked_request.stop_span()
 
 
+def task_failure_callback(task_id=None, **kwargs):
+    tracked_request = TrackedRequest.instance()
+    tracked_request.tag("error", "true")
+
+
 def install(app=None):
     if app is not None:
         copy_configuration(app)
@@ -62,6 +67,7 @@
 
     before_task_publish.connect(before_task_publish_callback)
     task_prerun.connect(task_prerun_callback)
+    task_failure.connect(task_failure_callback)
     task_postrun.connect(task_postrun_callback)

{"golden_diff": "diff --git a/src/scout_apm/celery.py b/src/scout_apm/celery.py\n--- a/src/scout_apm/celery.py\n+++ b/src/scout_apm/celery.py\n@@ -3,7 +3,7 @@\n \n import datetime as dt\n \n-from celery.signals import before_task_publish, task_postrun, task_prerun\n+from celery.signals import before_task_publish, task_failure, task_postrun, task_prerun\n \n import scout_apm.core\n from scout_apm.compat import datetime_to_timestamp\n@@ -52,6 +52,11 @@\n     tracked_request.stop_span()\n \n \n+def task_failure_callback(task_id=None, **kwargs):\n+    tracked_request = TrackedRequest.instance()\n+    tracked_request.tag(\"error\", \"true\")\n+\n+\n def install(app=None):\n     if app is not None:\n         copy_configuration(app)\n@@ -62,6 +67,7 @@\n \n     before_task_publish.connect(before_task_publish_callback)\n     task_prerun.connect(task_prerun_callback)\n+    task_failure.connect(task_failure_callback)\n     task_postrun.connect(task_postrun_callback)\n", "issue": "Track when an exception occurs in a Celery task\nSimilar to how we do this in other libraries\r\n`tracked_request.tag(\"error\", \"true\")`\r\n\n", "before_files": [{"content": "# coding=utf-8\nfrom __future__ import absolute_import, division, print_function, unicode_literals\n\nimport datetime as dt\n\nfrom celery.signals import before_task_publish, task_postrun, task_prerun\n\nimport scout_apm.core\nfrom scout_apm.compat import datetime_to_timestamp\nfrom scout_apm.core.config import scout_config\nfrom scout_apm.core.tracked_request import TrackedRequest\n\n\ndef before_task_publish_callback(headers=None, properties=None, **kwargs):\n    if \"scout_task_start\" not in headers:\n        headers[\"scout_task_start\"] = datetime_to_timestamp(dt.datetime.utcnow())\n\n\ndef task_prerun_callback(task=None, **kwargs):\n    tracked_request = TrackedRequest.instance()\n    tracked_request.is_real_request = True\n\n    start = getattr(task.request, \"scout_task_start\", None)\n    if start is not None:\n        now = datetime_to_timestamp(dt.datetime.utcnow())\n        try:\n            queue_time = now - start\n        except TypeError:\n            pass\n        else:\n            tracked_request.tag(\"queue_time\", queue_time)\n\n    task_id = getattr(task.request, \"id\", None)\n    if task_id:\n        tracked_request.tag(\"task_id\", task_id)\n    parent_task_id = getattr(task.request, \"parent_id\", None)\n    if parent_task_id:\n        tracked_request.tag(\"parent_task_id\", parent_task_id)\n\n    delivery_info = task.request.delivery_info\n    tracked_request.tag(\"is_eager\", delivery_info.get(\"is_eager\", False))\n    tracked_request.tag(\"exchange\", delivery_info.get(\"exchange\", \"unknown\"))\n    tracked_request.tag(\"priority\", delivery_info.get(\"priority\", \"unknown\"))\n    tracked_request.tag(\"routing_key\", delivery_info.get(\"routing_key\", \"unknown\"))\n    tracked_request.tag(\"queue\", delivery_info.get(\"queue\", \"unknown\"))\n\n    tracked_request.start_span(operation=(\"Job/\" + task.name))\n\n\ndef task_postrun_callback(task=None, **kwargs):\n    tracked_request = TrackedRequest.instance()\n    tracked_request.stop_span()\n\n\ndef install(app=None):\n    if app is not None:\n        copy_configuration(app)\n\n    installed = scout_apm.core.install()\n    if not installed:\n        return\n\n    before_task_publish.connect(before_task_publish_callback)\n    task_prerun.connect(task_prerun_callback)\n    task_postrun.connect(task_postrun_callback)\n\n\ndef copy_configuration(app):\n    prefix = \"scout_\"\n    prefix_len = len(prefix)\n\n    to_set = {}\n    for key, value in app.conf.items():\n        key_lower = key.lower()\n        if key_lower.startswith(prefix) and len(key_lower) > prefix_len:\n            scout_key = key_lower[prefix_len:]\n            to_set[scout_key] = value\n\n    scout_config.set(**to_set)\n\n\ndef uninstall():\n    before_task_publish.disconnect(before_task_publish_callback)\n    task_prerun.disconnect(task_prerun_callback)\n    task_postrun.disconnect(task_postrun_callback)\n", "path": "src/scout_apm/celery.py"}], "after_files": [{"content": "# coding=utf-8\nfrom __future__ import absolute_import, division, print_function, unicode_literals\n\nimport datetime as dt\n\nfrom celery.signals import before_task_publish, task_failure, task_postrun, task_prerun\n\nimport scout_apm.core\nfrom scout_apm.compat import datetime_to_timestamp\nfrom scout_apm.core.config import scout_config\nfrom scout_apm.core.tracked_request import TrackedRequest\n\n\ndef before_task_publish_callback(headers=None, properties=None, **kwargs):\n    if \"scout_task_start\" not in headers:\n        headers[\"scout_task_start\"] = datetime_to_timestamp(dt.datetime.utcnow())\n\n\ndef task_prerun_callback(task=None, **kwargs):\n    tracked_request = TrackedRequest.instance()\n    tracked_request.is_real_request = True\n\n    start = getattr(task.request, \"scout_task_start\", None)\n    if start is not None:\n        now = datetime_to_timestamp(dt.datetime.utcnow())\n        try:\n            queue_time = now - start\n        except TypeError:\n            pass\n        else:\n            tracked_request.tag(\"queue_time\", queue_time)\n\n    task_id = getattr(task.request, \"id\", None)\n    if task_id:\n        tracked_request.tag(\"task_id\", task_id)\n    parent_task_id = getattr(task.request, \"parent_id\", None)\n    if parent_task_id:\n        tracked_request.tag(\"parent_task_id\", parent_task_id)\n\n    delivery_info = task.request.delivery_info\n    tracked_request.tag(\"is_eager\", delivery_info.get(\"is_eager\", False))\n    tracked_request.tag(\"exchange\", delivery_info.get(\"exchange\", \"unknown\"))\n    tracked_request.tag(\"priority\", delivery_info.get(\"priority\", \"unknown\"))\n    tracked_request.tag(\"routing_key\", delivery_info.get(\"routing_key\", \"unknown\"))\n    tracked_request.tag(\"queue\", delivery_info.get(\"queue\", \"unknown\"))\n\n    tracked_request.start_span(operation=(\"Job/\" + task.name))\n\n\ndef task_postrun_callback(task=None, **kwargs):\n    tracked_request = TrackedRequest.instance()\n    tracked_request.stop_span()\n\n\ndef task_failure_callback(task_id=None, **kwargs):\n    tracked_request = TrackedRequest.instance()\n    tracked_request.tag(\"error\", \"true\")\n\n\ndef install(app=None):\n    if app is not None:\n        copy_configuration(app)\n\n    installed = scout_apm.core.install()\n    if not installed:\n        return\n\n    before_task_publish.connect(before_task_publish_callback)\n    task_prerun.connect(task_prerun_callback)\n    task_failure.connect(task_failure_callback)\n    task_postrun.connect(task_postrun_callback)\n\n\ndef copy_configuration(app):\n    prefix = \"scout_\"\n    prefix_len = len(prefix)\n\n    to_set = {}\n    for key, value in app.conf.items():\n        key_lower = key.lower()\n        if key_lower.startswith(prefix) and len(key_lower) > prefix_len:\n            scout_key = key_lower[prefix_len:]\n            to_set[scout_key] = value\n\n    scout_config.set(**to_set)\n\n\ndef uninstall():\n    before_task_publish.disconnect(before_task_publish_callback)\n    task_prerun.disconnect(task_prerun_callback)\n    task_postrun.disconnect(task_postrun_callback)\n", "path": "src/scout_apm/celery.py"}]}