diff --git a/meta/classes-global/sstate.bbclass b/meta/classes-global/sstate.bbclass
index fe14022bc09f..a157ad5cb461 100644
--- a/meta/classes-global/sstate.bbclass
+++ b/meta/classes-global/sstate.bbclass
@@ -235,23 +235,50 @@ def sstate_log_expand_paths(d, message):
 python sstate_save_task_log () {
     import json
 
-    # Save the messages logged by this task, so they can be replayed when the
-    # task is restored from sstate. The records are written by bitbake right
-    # after the task body, before the postfuncs.
+    # Also bundle the messages of the non-sstate tasks of this recipe we depend
+    # on, as they are skipped when this task is restored from sstate. bitbake
+    # picks which setscene task replays them (BB_SETSCENE_REPLAY_TASKS).
+    taskdepdata = d.getVar('BB_TASKDEPDATA', False) or {}
+    sstatetasks = d.getVar('SSTATETASKS').split()
     mytask = d.getVar('BB_RUNTASK')
-    recordsfn = os.path.join(d.getVar('T'), 'logrecords.%s.json' % mytask)
-    if not os.path.exists(recordsfn):
-        return
-    with open(recordsfn) as f:
-        records = json.load(f)
-
-    tasks = {mytask: [{'levelno': levelno,
-                       'message': sstate_log_strip_paths(d, message)}
-                      for levelno, message in records]}
-
-    logfn = os.path.join(d.getVar('SSTATE_BUILDDIR'), "sstate-log.json")
-    with open(logfn, 'w') as f:
-        json.dump({'tasks': tasks}, f)
+    # The running task is always an entry in taskdepdata, under its own tid.
+    # Reconstruct that tid from BB_FILENAME and BB_RUNTASK.
+    filename = d.getVar('BB_FILENAME', False)
+    start = filename + ":" + mytask if filename else None
+    if start not in taskdepdata:
+        bb.fatal("sstate: cannot identify task %s in taskdepdata" % start)
+
+    loggedtasks = {mytask}
+    seen = {start}
+    todo = [start]
+    while todo:
+        for dep in taskdepdata[todo.pop()].deps:
+            t = taskdepdata[dep]
+            if dep in seen or t.fn != taskdepdata[start].fn or t.taskname in sstatetasks:
+                continue
+            seen.add(dep)
+            todo.append(dep)
+            loggedtasks.add(t.taskname)
+
+    # Every task writes its records to ${T} right after its body, before its
+    # postfuncs, so our own file and the dependency files all exist by now.
+    tasklogs = {}
+    for taskname in loggedtasks:
+        recordsfn = os.path.join(d.getVar('T'), 'logrecords.%s.json' % taskname)
+        if os.path.exists(recordsfn):
+            with open(recordsfn) as f:
+                tasklogs[taskname] = json.load(f)
+
+    tasks = {}
+    for task, records in tasklogs.items():
+        tasks[task] = [{'levelno': levelno,
+                        'message': sstate_log_strip_paths(d, message)}
+                       for levelno, message in records]
+
+    if tasks:
+        logfn = os.path.join(d.getVar('SSTATE_BUILDDIR'), "sstate-log.json")
+        with open(logfn, 'w') as f:
+            json.dump({'tasks': tasks}, f)
 }
 
 def sstate_add(ss, source, dest, d):
@@ -462,7 +489,11 @@ def sstate_installpkgdir(ss, d, replay=False):
         if os.path.exists(logfp):
             with open(logfp, 'r') as logfile:
                 logdata = json.load(logfile)
-            records = logdata.get('tasks', {}).get(d.getVar('BB_RUNTASK').removesuffix('_setscene'), [])
+            replaytasks = (d.getVar('BB_SETSCENE_REPLAY_TASKS') or '').split()
+            replaytasks.append(d.getVar('BB_RUNTASK').removesuffix('_setscene'))
+            records = []
+            for task in replaytasks:
+                records += logdata.get('tasks', {}).get(task, [])
             for logentry in records:
                 levelno = logentry.get('levelno', 0)
                 if levelno < bb.msg.BBLogFormatter.WARNONCE or "message" not in logentry:
@@ -481,6 +512,8 @@ def sstate_installpkgdir(ss, d, replay=False):
 
     return True
 
+sstate_installpkgdir[vardepsexclude] += "BB_SETSCENE_REPLAY_TASKS"
+
 python sstate_hardcode_path_unpack () {
     # Fixup hardcoded paths
     #
