Skip to content

Reading Unified Logs

A unified log can contain multiple runtime instances after a mission change or an appended restart. Each Instantiated lifecycle record announces a fresh runtime. Its CopperList IDs and clock can start over independently of the previous instance.

Use the application's logreader binary to list the instances and select one:

logreader logs/robot.copper list-instances
logreader logs/robot.copper --instance 1 fsck --dump-runtime-lifecycle
logreader logs/robot.copper --instance 1 extract-copperlists
logreader logs/robot.copper --instance 1 extract-text-log target/debug/cu29_log_index
logreader logs/robot.copper --instance 1 log-stats --output instance-1.json
logreader logs/robot.copper --instance 1 export-mcap --output instance-1.mcap

Indices are zero-based and follow Instantiated record order. They are distinct from the recorded instance_id, which can repeat across process restarts. list-instances reads lifecycle metadata without decoding application payloads. It shows the mission, application, runtime instance ID, start time, and whether ShutdownCompleted was recorded.

Single-instance logs select their instance automatically. Logs from standalone writers with no Instantiated record are treated as one implicit instance. Multi-instance logs require --instance for extraction, fsck, statistics, and MCAP export. The selection includes the runtime's initial stream reservations and all of its CL, keyframe, lifecycle, and structured-log sections. A multi-instance log whose startup section ordering cannot be recognized is listed but rejected for selection.

The selected instance supplies the recorded configuration used by logging codecs. Statistics also default to that configuration and its recorded mission; --config and --mission provide explicit overrides. Without a recorded configuration, statistics use copperconfig.ron. Use a logreader and string index built for the application version that produced the selected instance.

fsck checks CopperList IDs within the selected instance, reports decoding errors, and returns an error for repeated or decreasing IDs and an unclean final log close. An ID reset at the next Instantiated belongs to that next instance.

Experimental native payload descriptions

This API is proposed in PR #1443. The following commands and examples apply to its gbin/self-describing-logs-api feature branch while the PR is under review.

With cu29/self-describing-logs enabled, the usual Encode and Reflect derives provide a description of a payload's native encoded bytes. Build it once with ValueDecodeDescription::from_type::<Payload>(), serialize the description using native bincode, and transport it with payload bytes to offline tooling.

description.decode(bytes, producer_config, ValueDecodeLimits::default()) returns a Value tree and the exact number of consumed bytes. It retains scalar widths, field names, original type identities, and coherent quantity storage units. For a handwritten encoder, implement ValueDecode::DECODE by delegating to the representation it writes; an opaque wrapper encoding four floats can reuse <[f32; 4] as ValueDecode>::DECODE.

The feature enables std and reflection. Description construction and tree allocation run offline; native message encoding keeps its existing byte layout and encoding pass. The first PR supplies the API and byte-agreement tests; packaging, catalogue embedding, and unified-log reader integration follow in later PRs. Run just self-describing-logs-check in the Copper workspace to verify the prototype.