diff --git a/contrib/cirrus/logformatter b/contrib/cirrus/logformatter
index 14b278521b..82da327520 100755
--- a/contrib/cirrus/logformatter
+++ b/contrib/cirrus/logformatter
@@ -12,6 +12,7 @@ use utf8;
 # Grumble. CI system doesn't have 'open'
 binmode STDIN,  ':utf8';
 binmode STDOUT, ':utf8';
+binmode STDERR, ':utf8';
 
 use strict;
 use warnings;
@@ -95,7 +96,7 @@ a.timing           { text-decoration: none; }
 .bats-summary   { font-size: 150%; }
 
 /* error titles: display next to timestamp, not on separate line */
-h2 { display: inline; }
+h2,h3 { display: inline; }
 END_CSS
 
 # END   user-customizable section
@@ -234,7 +235,7 @@ END_HTML
     my $subtest_status;           # pass, fail, skip, flake - for each subtest
     my $in_failure;               # binary flag: are we in an error dump?
     my $in_timing;                # binary flag: are we in the timing section?
-    my $after_divider = 0;        # Count of lines after seeing '-----'
+    my $after_divider = 999;      # Count of lines after seeing '-----'
     my $current_output;           # for removing duplication
     my $looks_like_bats;          # binary flag: for detecting BATS results
     my $looks_like_python;        #   " "   "  : for colorizing python tests
@@ -561,8 +562,35 @@ END_HTML
             $current_output .= ' ' . $line;
         }
 
-        # One line after each divider, there's a status/timing line.
+        #######################################################################
+        # DANGER DANGER DANGER! This is hideous and probably fragile.
+        #
+        # The way ginkgo shows tests is:
+        #
+        #      -------------
+        #   1  [+NNNNs] * Status [x.y seconds]
+        #   2  Podman test module name
+        #   3  /var/tmp/..../something_test.go:linenumber
+        #   4    podman actual test name
+        #
+        # That is: one line after each divider, there's a status/timing line,
+        # then the Describe() string from a foo_test.go file with the next
+        # line being the file and line number; then the fourth line after
+        # divider is the actual subtest name, the It() string. USUALLY: ginkgo
+        # also spits out dash lines for other purposes. More on that below.
+        #
+        # When we link to a test result (in-page anchor) we use line 4,
+        # the subtest name. It's easy to link to that line (4), but it's
+        # way more useful to link to the status line (1): that way the
+        # user can see status, start time, run time, module name, all
+        # without having to scroll up.
+        #
+        # To do that, we need to read ahead in our input stream. For now I
+        # choose to use tell(), read, then seek() back. If that doesn't work
+        # I'll have to look into a rolling input buffer. Either way, yuk.
+        #######################################################################
         if ($after_divider == 1) {
+            # Line 1: status and timing results
             $line =~ s{(\[(\d+)\.\d+\s+seconds\])}{
                 if ($2 > 5) { "<b><span class='log-slow'>$1</span></b>" }
                 else        { "<b>$1</b>" }
@@ -574,20 +602,49 @@ END_HTML
                 $subtest_status = lc($2);
             }
 
+            # Read ahead. Here's where it gets ugly.
+            my $stream_pos = tell STDIN;
+            # As mentioned above, ginkgo can spit out lots of other things
+            # after a row of dashes. Check for those, and exclude them.
+            chomp(my $l2 = <STDIN>);
+            if ($l2 && $l2 !~ /(\[.*Suite\]|Summarizing|Runner executing|Ran \d+ of \d+ Specs)/) {
+                # Don't really care about line 3, only that it has slashes
+                chomp(my $l3 = <STDIN>);
+                if ($l3 && $l3 =~ m!/.*/!) {
+                    # Line 4 should be a test name, indented, possibly with [It]
+                    chomp(my $l4 = <STDIN>);
+                    if ($l4 =~ /^\[\+\d+s\]   *(\[It\]\s*)?([a-zA-Z-].*\S)/) {
+                        # Yes! From the subtest name, make a page anchor,
+                        # and link to our **CURRENT LINE**, the status one.
+                        my $id = make_id(escapeHTML($2), 'anchor');
+                        $line = "<a name='t--$id'><h2 class=\"log-$subtest_status\">$line</h2></a>";
+                    }
+                    else {
+                        # Line 4 does not look like a test name.
+                        # This warning will only likely be seen by Ed.
+                        warn "$ME: line $.: unexpected line three down from dashes:\n";
+                        warn "     $line\n     $l2\n     $l3\n     $l4\n";
+                    }
+                }
+            }
+            else {
+                # Line 2 is one of the other non-test-result things that
+                # ginkgo emits after a row of dashes. Set this so our
+                # test name highlighter (below) does not false-trigger.
+                $after_divider = 999;
+            }
+
+            # Reset back to where we were in the input stream, and continue.
+            seek STDIN, $stream_pos, 0;
+
             # FIXME: gray out entire block if it's skipped?
         }
 
-        # Four lines after each divider, there's a test name. Make it
-        # an anchor so we can link to it later.
-        if ($after_divider == 4) {
-            # Sigh. There is no actual marker. Assume that anything with
-            ## two leading spaces then alpha or hyphen (not slashes) is
-            ## a test name.
-            if ($line =~ /^  (\[It\]\s*)?([a-zA-Z-].*\S)/) {
-                my $id = make_id($2, 'anchor');
-
-                $line = "<a name='t--$id'><h2 class=\"log-$subtest_status\">$line</h2></a>";
-            }
+        # Two and four lines after each divider, there's a test module
+        # Description and a subtest name. Highlight both.
+        if ($after_divider == 2 || $after_divider == 4) {
+            my $level = 2 + ($after_divider == 4);
+            $line = "<h$level class=\"log-$subtest_status\">$line</h$level>";
         }
         ++$after_divider;
 
diff --git a/contrib/cirrus/logformatter.t b/contrib/cirrus/logformatter.t
index 3bc8344257..7ce0f9f7e3 100755
--- a/contrib/cirrus/logformatter.t
+++ b/contrib/cirrus/logformatter.t
@@ -128,7 +128,7 @@ ok 4 blah
 [+0006s] CGO_ENABLED=1 GOOS=linux GOARCH=amd64 go build  -ldflags '-X github.com/containers/podman/v4/libpod/define.gitCommit=074143b0fac7af72cd92048d27931a92fe745084 -X github.com/containers/podman/v4/libpod/define.buildInfo=1681728434 -X github.com/containers/podman/v4/libpod/config._installPrefix=/usr/local -X github.com/containers/podman/v4/libpod/config._etcDir=/usr/local/etc -X github.com/containers/podman/v4/pkg/systemd/quadlet._binDir=/usr/local/bin -X github.com/containers/common/pkg/config.additionalHelperBinariesDir= ' -o test/goecho/goecho ./test/goecho
 [+0006s] ./hack/install_catatonit.sh
 [+0270s] ------------------------------
-[+0271s] • [3.327 seconds]
+[+0271s] * [3.327 seconds]
 [+0271s] Podman restart
 [+0271s] /var/tmp/go/src/github.com/containers/podman/test/e2e/restart_test.go:14
 [+0271s]   podman restart non-stop container with short timeout
@@ -160,10 +160,10 @@ ok 4 blah
 </pre>
 <hr />
 <pre>
-<span class="timestamp">[+0271s] </span>• <b>[3.327 seconds]</b>
-<span class="timestamp">         </span>Podman restart
+<span class="timestamp">[+0271s] </span><a name='t--podman-restart-non-stop-container-with-short-timeout--1'><h2 class="log-passed">* <b>[3.327 seconds]</b></h2></a>
+<span class="timestamp">         </span><h2 class="log-passed">Podman restart</h2>
 <span class="timestamp">         </span>/var/tmp/go/src/github.com<a class="codelink" href='https://github.com/containers/podman/blob/074143b0fac7af72cd92048d27931a92fe745084/test/e2e/restart_test.go#L14'>/containers/podman/test/e2e/restart_test.go:14</a>
-<span class="timestamp">         </span><a name='t--podman-restart-non-stop-container-with-short-timeout--1'><h2 class="log-passed">  podman restart non-stop container with short timeout</h2></a>
+<span class="timestamp">         </span><h3 class="log-passed">  podman restart non-stop container with short timeout</h3>
 <span class="timestamp">         </span>  /var/tmp/go/src/github.com<a class="codelink" href='https://github.com/containers/podman/blob/074143b0fac7af72cd92048d27931a92fe745084/test/e2e/restart_test.go#L148'>/containers/podman/test/e2e/restart_test.go:148</a>
 [+0271s]
 <span class="timestamp">         </span>  Timeline &gt;&gt;