file-handling · intermediate · ~30 min

Final Project: log-aggregator — count by level

Per-line classification and aggregate counting in one pass.

Challenge

Tally log lines by severity level — the kernel of every observability dashboard.

Task

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.

Input

  • 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.

Output

Nothing returned; *info, *warn, *err are set to the number of lines starting with each tag.

Example

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)

Edge cases

  • Empty input: all counts 0.
  • Lines whose tag is not a prefix are skipped.
  • The last line counts even without a trailing newline.

Rules

  • One pass; no allocations. Match the tag as a line prefix, not anywhere in the line.

Why this matters

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.

Input format

log: NUL-terminated text, lines split by '\n'; info/warn/err: output pointers.

Output format

Sets *info/*warn/*err to the count of lines prefixed INFO /WARN /ERROR .

Constraints

One pass, no allocations; match the level tag only as a line prefix.

Starter code

void log_count_levels(const char *log, int *info, int *warn, int *err) { /* TODO */ }

Common mistakes

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.

Edge cases to handle

Empty input. Unknown prefix lines. Multiple consecutive newlines.

Complexity

O(n) time.

Background lessons

Solve this exercise in the browser editor — compile and run against the test harness, no setup required.