We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
Capture details of Celery Chains and Chords
Celery has some more advanced features to join multiple jobs into one. The agent needs testing and investigation into how they can be best instrumented.

--- 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.tracked_request import TrackedRequest
11 
12 
13 def before_publish_callback(headers=None, properties=None, **kwargs):
14     if "scout_task_start" not in headers:
15         headers["scout_task_start"] = datetime_to_timestamp(dt.datetime.utcnow())
16 
17 
18 def prerun_callback(task=None, **kwargs):
19     tracked_request = TrackedRequest.instance()
20     tracked_request.mark_real_request()
21 
22     start = getattr(task.request, "scout_task_start", None)
23     if start is not None:
24         now = datetime_to_timestamp(dt.datetime.utcnow())
25         try:
26             queue_time = now - start
27         except TypeError:
28             pass
29         else:
30             tracked_request.tag("queue_time", queue_time)
31 
32     delivery_info = task.request.delivery_info
33     tracked_request.tag("is_eager", delivery_info.get("is_eager", False))
34     tracked_request.tag("exchange", delivery_info.get("exchange", "unknown"))
35     tracked_request.tag("routing_key", delivery_info.get("routing_key", "unknown"))
36     tracked_request.tag("queue", delivery_info.get("queue", "unknown"))
37 
38     tracked_request.start_span(operation=("Job/" + task.name))
39 
40 
41 def postrun_callback(task=None, **kwargs):
42     tracked_request = TrackedRequest.instance()
43     tracked_request.stop_span()
44 
45 
46 def install():
47     installed = scout_apm.core.install()
48     if not installed:
49         return
50 
51     before_task_publish.connect(before_publish_callback)
52     task_prerun.connect(prerun_callback)
53     task_postrun.connect(postrun_callback)
54 
55 
56 def uninstall():
57     before_task_publish.disconnect(before_publish_callback)
58     task_prerun.disconnect(prerun_callback)
59     task_postrun.disconnect(postrun_callback)
60
```
--- 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
@@ -29,6 +29,13 @@
         else:
             tracked_request.tag("queue_time", queue_time)
 
+    task_id = getattr(task.request, "id", None)
+    if task_id:
+        tracked_request.tag("task_id", task_id)
+    parent_task_id = getattr(task.request, "parent_id", None)
+    if parent_task_id:
+        tracked_request.tag("parent_task_id", parent_task_id)
+
     delivery_info = task.request.delivery_info
     tracked_request.tag("is_eager", delivery_info.get("is_eager", False))
     tracked_request.tag("exchange", delivery_info.get("exchange", "unknown"))

{"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@@ -29,6 +29,13 @@\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", "issue": "Capture details of Celery Chains and Chords\nCelery has some more advanced features to join multiple jobs into one. The agent needs testing and investigation into how they can be best instrumented.\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.tracked_request import TrackedRequest\n\n\ndef before_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 prerun_callback(task=None, **kwargs):\n    tracked_request = TrackedRequest.instance()\n    tracked_request.mark_real_request()\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    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(\"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 postrun_callback(task=None, **kwargs):\n    tracked_request = TrackedRequest.instance()\n    tracked_request.stop_span()\n\n\ndef install():\n    installed = scout_apm.core.install()\n    if not installed:\n        return\n\n    before_task_publish.connect(before_publish_callback)\n    task_prerun.connect(prerun_callback)\n    task_postrun.connect(postrun_callback)\n\n\ndef uninstall():\n    before_task_publish.disconnect(before_publish_callback)\n    task_prerun.disconnect(prerun_callback)\n    task_postrun.disconnect(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_postrun, task_prerun\n\nimport scout_apm.core\nfrom scout_apm.compat import datetime_to_timestamp\nfrom scout_apm.core.tracked_request import TrackedRequest\n\n\ndef before_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 prerun_callback(task=None, **kwargs):\n    tracked_request = TrackedRequest.instance()\n    tracked_request.mark_real_request()\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(\"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 postrun_callback(task=None, **kwargs):\n    tracked_request = TrackedRequest.instance()\n    tracked_request.stop_span()\n\n\ndef install():\n    installed = scout_apm.core.install()\n    if not installed:\n        return\n\n    before_task_publish.connect(before_publish_callback)\n    task_prerun.connect(prerun_callback)\n    task_postrun.connect(postrun_callback)\n\n\ndef uninstall():\n    before_task_publish.disconnect(before_publish_callback)\n    task_prerun.disconnect(prerun_callback)\n    task_postrun.disconnect(postrun_callback)\n", "path": "src/scout_apm/celery.py"}]}