Test2:...ss::Log(3pm)

πŸ¦‹ NAME πŸ¦‹

okay so bestie, this is Test2::Harness::Log β€” the 3pm perl man page, straight out of User Contributed Perl Documentation πŸ’…. Real talk: this module is the documentation for the Test2::Harness log file format. That's it, that's the whole job ✨.


🌸 DESCRIPTION 🌸

Test2::Harness β€” aka App::Yath β€” can produce a rich, complete log whenever you ask it to 🫢. And this module? This module documents that log format. No cap, that's the entire vibe. πŸ““βœ¨


πŸŽ€ COMPRESSION πŸŽ€

Test2::Harness gives you three compression flavors for your log files, pick your fighter:

  • uncompressed β€” raw, unfiltered, main character energy πŸ’–
  • compressed in gzip β€” cute, efficient, iykyk
  • compressed in bzip2 β€” the other compressed option, also valid, we do not play favorites πŸ’œ

✨ FORMAT ✨

So the log file is in jsonl format πŸ¦‹. Translation: every single line is independently parseable as json. Like, fully independent. Each line = one single event that Test2::Harness processed during the run ⭐.

These events land in the original order Test2::Harness processed them in β€” and heads up, that might not be chronological to when they were actually generated, because generation, collection, processing and rendering are all handled by different processes 🧚. It's giving many hands, one group chat.

A complete log gets terminated by the string "null", which is also valid json, slay πŸ’…. And if a log is missing that terminator? Bestie. It's considered an incomplete log. 🚩

πŸ‘‘ EVENTS πŸ‘‘

Please note: older versions of Test2::Harness produced less complete events. This section covers all current fields β€” so if you're out here trying to handle very old logs, some of those fields may simply be missing πŸ™ˆ.

Every event is gonna have these fields:

{
   "event_id" : "CD01CD30-D535-11EA-9B6A-D90F9664FE12",
   "job_id"   : 0,
   "job_try"  : null,
   "run_id"   : "CCF98E54-D535-11EA-915A-D70F9664FE12",
   "stamp"    : 1596423763.76517,

   "facet_data" : {
      "harness" : {
         "event_id" : "CD01CD30-D535-11EA-9B6A-D90F9664FE12",
         "job_id" : 0,
         "job_try" : null,
         "run_id" : "CCF98E54-D535-11EA-915A-D70F9664FE12"
      },

      ...
   }
}
  • event_id : "UUID_OR_STRING" β€” usually this is a UUID, but when UUIDs literally cannot be generated it might be some other unique identifier instead. Always a string, always. This may never be NULL β€” and if it is NULL, that's a bug and you should report it, fr fr πŸ›πŸš¨.
  • job_id : "0_OR_UUID_OR_STRING" β€” id 0 is special: it represents the test harness itself, not an actual test being run πŸ‘‘. Normally job_id is a UUID, but it can be another unique string if UUID generation is disabled or unavailable.
  • job_try : INTEGER_OR_NULL β€” for "job_id => 0" this will be NULL. For any other job, this is an integer of 0 or greater ✨. It's 0 the first time a test job runs, and if a job gets re-run because it failed (or for literally any other reason), this gets incremented so you know which run you're looking at πŸ”. When a job re-runs it keeps the same job ID β€” that's how you tell events from each run apart. iykyk.
  • run_id : "UUID_OR_STRING" β€” the run_id of the entire yath test run πŸƒβ™€οΈ. This should be identical for every event in any given log. Consistency? Obsessed.
  • stamp : UNIX_TIME_STAMP β€” the timestamp of the event ⏰. This is NORMALLY set when the event is generated β€” however, if an event doesn't have its own timestamp, yath will give it one upon collection. When does an event not have a timestamp? When the test outputs TAP instead of Test2::Event objects, or when a tool misbehaves somehow πŸ™ˆ. Tools, bestie, they're wild.
  • facet_data : HASH β€” this holds all the data of the event: whether an assertion was made, what file name and line number generated it, etc. πŸ’–

On top of the event's original facets, Test2::Harness may inject the following facets β€” or generate completely new events to convey these facets 🌈.

πŸ’« harness_final

This one contains the final summary data from the end of the test run. The receipts, basically 🧾✨:

{
    # Was the test run a success, or were there failures?
    pass => $BOOL,

    # What tests failed?
    failed => [
        [
            $job_id,    # Job id of the job that failed
            $file,      # Test filename
        ],
        ...
    ],

    # What tests had to be retried, and did they eventually pass?
    retried => [
        [
            $job_id,            # Job id of the job that was retied
            $tries,             # Number of tries attempted
            $file,              # Test filename
            $eventually_passed, # 'YES' if it eventually passed, 'NO' if no try ever passed.
        ],
        ...
    ],

    # What tests setn a halt event (such as bail-out, or skip the rest)
    halted => [
        [
            $job_id,    # Job id of the test
            $file,      # Test filename
            $halt,      # Halt code
        ],
        ...
    ],

    # What tests were never run (maybe because of a bail-out, or an internal error)
    unseen => [
        [
            $job_id,    # Job id of the test
            $file,      # Test filename
        ],
        ...
    ],
}

πŸ™ˆ harness_watcher

Internal use only, subject to change, do not rely on it. That's the whole note. Don't build your whole personality on it, bestie πŸ’€.

🌸 harness_job

A hash representation of an Test2::Harness::Runner::Job object 🫢.

Note: this is done via a transformation β€” several methods have their values stored in this hash when the original object doesn't directly store them. Sneaky but iconic.

πŸŽ€ harness_job_end

{
    file     => $provided_path_to_test_file,
    rel_file => $relative_path_to_test_file,
    abs_file => $absolute_path_to_test_file,

    fail  => $BOOL,
    retry => $INTEGER,         # Number of retries left
    stamp => $UNIX_TIMESTAMP,  # Timestamp of when the test completed

    # May not be present
    skip  => $STRING,          # Reason test was skipped (if it was skipped)
    times => $TIMING_DATA,     # See below
}

The "times" field gets populated by calling data_dump() on an Test2::Harness::Auditor::TimeTracker object β±οΈπŸ’œ.

πŸ¦‹ harness_job_exit

This one represents when the test job exited πŸšͺ:

{
    exit  => $WSTAT,
    retry => $INTEGER
    stamp => $UNIX_TIMESTAMP
}

πŸ’œ harness_job_fields

Extra data attached to the harness job β€” usually coming from an Test2::Harness::Plugin via inject_run_data() ✨.

⭐ harness_job_launch

This facet is almost always in the same event as the "harness_job_start" facet 🫢.

NOTE: while writing these docs the author wonders if this facet is unnecessary... and honestly? We love an honest king. πŸ‘‘
{
    stamp => $UNIX_TIMESTAMP,
    rety  => $INTEGER,
}

πŸ“ harness_job_queued

This data is produced by the "queue_item" method in Test2::Harness::TestFile πŸ“¦.

This contains the data about a test job conveyed by the queue. It usually contains data that will later be used by Test2::Harness::Runner::Job πŸ› οΈ. It's better to use the "harness_job" facet instead, because that one contains the final data actually used to run the job πŸ’….

The following 3 fields are the only ones likely to be useful to most people:

{
    file   => $ORIGINAL_PATH_TO_FILE,
    job_id => $UUID_OR_STRING,
    stamp  => $UNIX_TIMESTAMP,
}

🌈 harness_job_start

This facet gets sent in an event as soon as a job starts πŸš€. The data in this facet is mainly meant to convey the necessary info to a renderer so it can render the fact that a job started. Respect the renderer's journey.

{
    file     => $provided_path_to_test_file,
    rel_file => $relative_path_to_test_file,
    abs_file => $absolute_path_to_test_file,

    stamp => $UNIX_TIMESTAMP,  # Timestamp of when the test completed
    job_id => $UUID_OR_STRING,

    details => "Job UUID_OR_STRING started at $UNIX_TIMESTAMP",
}

πŸ‘‘ harness_run

A hash representation of an Test2::Harness::Run object πŸƒβ™€οΈπŸ’¨.


πŸ’– SOURCE πŸ’–

The source code repository for Test2-Harness lives right here, bestie:

http://github.com/Test-More/Test2-Harness/

Go star it, it's the least you can do 🫢⭐


🌟 MAINTAINERS 🌟

Chad Granum <exodist@cpan.org>


✨ AUTHORS ✨

Chad Granum <exodist@cpan.org>


Copyright 2020 Chad Granum <exodist7@gmail.com>.

This program is free software; you can redistribute it and/or modify it under the same terms as Perl itself πŸ’œ.

See http://dev.perl.org/licenses/


and that's the whole page, bestie, we ate and left no crumbs πŸ½οΈπŸ’… this was perl v5.40.1, dated 2026-05-10, and it was Test2:...ss::Log(3pm) the entire time πŸŒΈπŸ¦‹βœ¨

πŸ“¦ where this page comes from