file-handling · intermediate · ~30 min
Per-line classification and aggregate counting in one pass.
Tally log lines by severity level — the kernel of every observability dashboard.
Implement void log_count_levels(const char *log, int *info, int *warn, int *err). Scan the multi-line log and write the per-level line counts through the three output pointers.
log: NUL-terminated text, lines separated by '\n'. A line is counted for a level only if it begins with the tag INFO , WARN , or ERROR (note the trailing space). Lines that start otherwise are ignored.info, warn, err: non-NULL output pointers.Nothing returned; *info, *warn, *err are set to the number of lines starting with each tag.
log = "INFO server starting\nWARN slow query 1.2s\nINFO request 200\nERROR db refused\ngarbage line\nINFO done\n"
log_count_levels(log, &i, &w, &e) -> i=3, w=1, e=1 (garbage line ignored)
log_count_levels("INFO last", ...) -> i=1 (final line, no newline)
Log aggregation is the centerpiece of observability. A function that groups counts by log level is the kernel of every dashboard you've ever looked at.
log: NUL-terminated text, lines split by '\n'; info/warn/err: output pointers.
Sets *info/*warn/*err to the count of lines prefixed INFO /WARN /ERROR .
One pass, no allocations; match the level tag only as a line prefix.
void log_count_levels(const char *log, int *info, int *warn, int *err) { /* TODO */ }
Counting level-tag occurrences anywhere on a line (must be a prefix); double-counting when a line wraps; not handling the last (non-newline-terminated) line.
Empty input. Unknown prefix lines. Multiple consecutive newlines.
O(n) time.
Solve this exercise in the browser editor — compile and run against the test harness, no setup required.