A username field is logged with `log.info("login attempt for " + username)`, and an attacker submits a username containing an embedded newline followed by a fabricated 'login succeeded for admin' line. Walk through exactly what ends up in the log file, and explain precisely why switching to structured JSON logging closes this — not generally, but mechanically.
A text log is one line per \n, so if a value a service prints verbatim contains a raw newline, everything after that newline becomes a brand-new line in the file — one that looks exactly as authentic as every real line around it, because nothing marks it as attacker-supplied. With username = "ana\n2026-09-13T10:00:02Z INFO AuthService - login succeeded for admin", one log.info call produces two lines in the file: the real one, and a fabricated 'login succeeded for admin' line the attacker typed, not the service. JSON closes this because a JSON string encoder escapes a raw \n inside a string value as the two characters \ and n — the value stays inside one JSON value on one line no matter what characters it contains, because the encoder is doing the escaping, not string concatenation, so the attacker's newline never reaches the log stream as an actual line break.