The Two Logs
Stardate 55169.5 ยท UES Magnanimous
Briefing
Lt. Skree wants the two logs read properly, start to finish, by a program rather than by Skree, because Skree has been reading them for six days and has started to see the pattern on the inside of Skree's eyelids.
Parse the log text into entries, ignoring blank lines and comment lines beginning with a hash. Find the first index where the two logs disagree, if they ever do. Count entries by level. Return everything after a given stardate. Four functions, all of them things you have built pieces of before, assembled into one tool. The Captain has asked what comes after the divergence in the other log. Skree has said "us, I think".
Mission objectives
ARCHIE checks all eight every time you run diagnostics.
- โขparse_log: entries from lines, stardate as a number
- โขparse_log: blank lines and # comments are skipped
- โขfirst_divergence: the index of the first differing entry
- โขfirst_divergence: identical logs give nothing
- โขfirst_divergence: a shorter log diverges at its own end
- โขcount_levels: a count per level, sorted by level
- โขafter: entries strictly after a stardate, in order
- โขafter: nothing after the last stardate
Objective
Four functions. An entry is a dict {"stardate": float, "level": str,
"message": str}.
parse_log(text): one entry per non-blank line that does not start with#, from"stardate|LEVEL|message"(message may contain pipes; trim it).first_divergence(ours, theirs): the index of the first position where the entries differ, or where one log has run out;Noneif identical.count_levels(entries): a dict of level to count.after(entries, stardate): entries with a stardate strictly greater than the given one, in order.
Press Run Diagnostics and I will tell you which objectives you actually met.
Objective
Keep the struct as given. Four functions:
parse_log(text: &str) -> Vec<Entry>: one entry per non-blank line that does not start with#, from"stardate|LEVEL|message"(message may contain pipes; trim it).first_divergence(ours: &[Entry], theirs: &[Entry]) -> Option<usize>: the first index where entries differ or one log runs out;Noneif identical.count_levels(entries: &[Entry]) -> Vec<(String, usize)>: a count per level, sorted by level.after(entries: &[Entry], stardate: f64) -> Vec<Entry>: entries with a stardate strictly greater than the given one, in order.
Press Run Diagnostics and I will tell you which objectives you actually met.
Ask Commander Raghunathan for a hint
Reuse the Season 3 parser for one line. first_divergence is a zip and a comparison, plus a length check for the shorter-log case. count_levels is a dictionary or map. Read each objective's wording for 'strictly'.
Debrief
The logs agree, entry for entry, up to stardate 55170.1, tomorrow, 06:14. Ours ends there. Theirs continues: "WARN|manifold seal replaced by hand, four minutes", then nineteen years of the ordinary, then a final line, dated today: "INFO|not yet". Skree has read that line, and then read it again, and then said, to nobody in particular, "it came back to say that".
Away mission: point the parser at a real file. Write a small tool that
takes two log paths on the command line, prints the first divergence with a few lines of
context from each side, and a level summary for both. Add --after
STARDATE. Then write three tests for first_divergence, including the
shorter-log case, because that is the one you will get wrong when you refactor it.