CodeRigor

FREE LESSON

Capstone: deterministic JSON log summary

Combine strict JSON decoding, explicit errors, maps, structs and sorted serialization in a tested offline library and CLI.

The capstone turns local JSON Lines into a deterministic service report. It is an offline library with a thin optional CLI, so the graded work needs no server, credentials or network requests. The challenge is the boundary between raw text, validated records and published output. Every earlier lesson contributes: typed fields, loops, explicit outcomes, map aggregation, ordered slices and errors that preserve their cause.

Start by writing the pipeline on paper. A line can be blank, invalid, or one valid event. A valid event contributes exactly one count for one service and level. Serialization happens only after the entire input has passed. That ordering implements the promised all-or-nothing result without transactions or global state.

Validate everything before publishing
start / 4
Any framing, JSON or schema failure returns an error instead of a partial report.
Validate everything before publishing
Any framing, JSON or schema failure returns an error instead of a partial report.

A decoder needs a policy around it

encoding/json supplies parsing, not your whole schema. Use exported struct fields with JSON tags. Reject unknown fields through the Decoder setting, then check the event's permitted strings and service alphabet. A successful first Decode can leave another JSON value behind, so require the next Decode to return io.EOF. The exercise explicitly follows the standard decoder's behavior for duplicate object keys: repeated valid strings use the final string, while decode errors still fail. Field-name matching is case-insensitive, as documented by encoding/json; required null fields fail. A real external protocol may require exact field names or reject duplicate keys instead.

Line framing is another policy. Blank physical lines are ignored, but they still count toward later error positions. CRLF and a final unterminated line are valid. Scanner has a bounded token buffer; check Err after the loop so an oversized line cannot silently truncate the report. The build also caps total input bytes. Those limits are part of the stated contract, not a claim that arbitrary logs can be buffered safely in memory.

Go
package main
import ("encoding/json"; "fmt"; "sort")
func main() {
    counts := map[string]int{"web": 2, "api": 1}
    names := make([]string, 0, len(counts))
    for name := range counts { names = append(names, name) }
    sort.Strings(names)
    out, _ := json.Marshal(names)
    fmt.Println(string(out))
}

The sorted names print as ["api","web"]. The ignored Marshal error is safe only in this narrow demonstration: a []string contains no unsupported JSON values. The build's implementation must still handle its returned error.

Two services, ordered output
start / 2
Counts accumulate by service; lexical ordering is chosen only at publication.
Two services, ordered output
Counts accumulate by service; lexical ordering is chosen only at publication.

Publish deterministic rows

Map entries containing structs are values. Read a row, update the matching counter, then assign it back. Extract and sort service names before creating the output slice. A nonnil empty slice serializes as [], while a nil slice serializes as null; the output contract chooses []. Field tags and declaration order give the required compact representation with all zero counts present.

Return an empty string with an ErrInvalidLog-compatible error whenever any record fails. A useful message includes its physical line number, while the caller can use errors.Is for control flow. Keep rendering and process exit decisions in the CLI wrapper.

Complete the counter fill, fix ordering and strict-decoding bugs, then run the build against mixed services, repeated levels, blank lines and malformed input. The standalone lab uses the same reference behind a real Go module and command. HTTP, remote APIs, persistence and concurrency remain separate next topics.

Watch & read

Free lectures, talks and readings that cover this skill from another angle. All resources →

Revisit the small-program and standard-library examples. Apply the ideas to local JSON processing here; this capstone does not execute the lecture’s network examples.