Skip to content

Route every log line through one topic-tagged logger - #24

Merged
Rollocraft merged 1 commit into
devfrom
logging-consolidation
Aug 31, 2026
Merged

Route every log line through one topic-tagged logger#24
Rollocraft merged 1 commit into
devfrom
logging-consolidation

Conversation

@Rollocraft

@Rollocraft Rollocraft commented Aug 30, 2026

Copy link
Copy Markdown
Owner

Stacked on #22#21#20. Merge those first; this targets sync-integration so the diff shows only the logging work.

The problem

SyncLog was added for exactly this purpose and had zero callers. Meanwhile:

  • 243 Mod.log.* calls and 97 Mod.Verbose calls went to the game log
  • 174 separate FlightRecorder.Note calls went to the flight log
  • ~65 places wrote the same fact twice, once as prose and once as key=value

So neither file was complete on its own, and the two had to be read side by side to reconstruct what happened.

One log, two files

Everything now goes through SyncLog, and both files are written from that single path. The tier is chosen by what the line is, not by who wrote it:

Tier Game log Flight log
Detail — troubleshooting chatter topic on topic on
Trace — compact breadcrumb topic on always (buffered)
Event — a milestone always always
Warn / Error — something went wrong always always, flushed

Severity, not the settings, decides whether a switch is consulted. Connects, disconnects, world transfers, resyncs, dropped commands, quarantined batches and every fault are written with every switch off — nobody turns a switch on before the crash they did not know was coming. Verbose adds detail underneath those lines.

Why two files still

The game log is the readable one. The flight log is the same content made durable, and it earns the second file with four things the game log cannot do:

  • it is flushed per fault, so a hard exit keeps its tail (the game's logger buffers and loses exactly the interesting part)
  • it is not truncated on restart, so a player who crashes and relaunches has not destroyed the evidence
  • it also captures Unity's and other mods' exceptions
  • it is machine-readable (run id, sequence, elapsed, thread, key=value)

Nothing reaches the game log without also reaching the flight log, so "send us CS2MP-flight.log" is now a complete answer. help/errors-and-warnings.md says so.

Detail and trace lines are buffered rather than flushed, and the next fault commits them — turning a topic on no longer puts a disk write in every frame.

Per-feature switches, not one dev flag

LogTopic names eighteen: session, transport, world transfer, resync, pipeline, nets, buildings, land, city, routes, the four zone economies, players, UI, startup, performance. Each gets its own switch on a new Logging options tab, grouped the way a player narrows a problem down, plus a Log Everything master for "I do not know which one".

The enum lives in Core/Diagnostics so the portable networking and session code names the same topics without referencing a game assembly. IModLogger mirrors the same shape; ColossalModLogger is the one seam. All nine locale files updated, key parity verified (294 keys).

Prefixes belong to the logger

Call sites no longer write them. [MP] , [MP][OCC-DEV] , [security] , [upnp] , [relay] and [compatibility] are gone; the logger attaches one [topic] tag, so every line is greppable and no two subsystems can drift into spelling the same tag differently.

Other cleanups

  • Thirty "X ready." lines replaced by one startup line carrying the mod, protocol and game versions
  • The 30-second performance report demoted out of every player's log (it was Record, which the mechanical pass would have turned into an always-on line)
  • Expensive diagnostic probes now follow their own feature switch instead of the master one
  • Resync reports log their full Summary() rather than just the reason
  • No code outside Setting.cs reads a logging setting directly any more

Verification

No .NET SDK or CS2 game assemblies are available in this environment, so this has not been compiled — please build before merging.

What was checked instead:

  • all 609 logging calls validated for topic validity and overload arity
  • brace/paren/bracket balance across all 141 changed .cs files
  • an automated reformatter kept the repo's ~100-column style; a byte-comparison proved every string literal in all 308 files is unchanged
  • locale key parity across all nine languages

That last check caught two real bugs introduced by the automated passes — a dropped using block in CompanyStatsSyncSystem.cs and an off-by-one that ate opening quotes — both fixed. It is careful, but it is not a compiler.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: f7400d1833

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +209 to +211
_log.Event(LogTopic.Session, "Join requested: transport=" + config.Transport +
" target=" +
(config.Transport == TransportMode.SteamRelay ? config.JoinCode : config.HostAddress + ":" + config.Port) +

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Redact join targets before emitting the event

When a player joins through either transport, this ungated Event includes the direct host address or Steam join code, and SyncLog.Emit mirrors it into CS2MP-flight.log. That file is explicitly intended for public support posts, and the nearby status logger deliberately replaces the same target with target=redacted; LogPaths.Redact only handles filesystem paths. Sharing a flight log can therefore disclose a host's network address or a still-valid relay code, so retain the target only in the private game log or redact it before this event is mirrored.

Useful? React with 👍 / 👎.

if (phase != ClientWorldPhase.LoadingMap) _sawLoading = false;
_log.Info("[MP] World phase: " + phase);
Diagnostics.FlightRecorder.Note("phase " + phase);
_log.Detail(LogTopic.Session, "World phase: " + phase);

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Preserve world-phase transitions as flight-log traces

With the default logging switches off, Detail returns without writing anywhere, whereas this transition previously had an unconditional FlightRecorder.Note("phase " + phase). If joining hangs or the process crashes during map handover, the support flight log now omits the last client phase—the exact breadcrumb needed to distinguish waiting, loading, and resume-barrier failures. Emit this as a Trace so it remains in the flight log while staying gated in the readable game log.

Useful? React with 👍 / 👎.

@Rollocraft
Rollocraft force-pushed the logging-consolidation branch from f7400d1 to e16e037 Compare August 31, 2026 14:28
@Rollocraft
Rollocraft force-pushed the logging-consolidation branch from e16e037 to 5d3008f Compare August 31, 2026 14:28
Base automatically changed from sync-integration to dev August 31, 2026 14:29
The mod had two logging front doors writing two files that disagreed. 243
Mod.log calls and 97 Mod.Verbose calls went to the game log; 174 separate
FlightRecorder.Note calls went to the flight log; SyncLog, added for exactly
this purpose, had no callers at all. Roughly 65 places wrote the same fact
twice, once as prose and once as key=value, so neither file was complete and
the pair had to be read together.

Everything now goes through SyncLog, and both files are written from that one
path. Four tiers, chosen by what the line is rather than by who wrote it:

  Detail  troubleshooting chatter - both logs, only while its topic is on
  Trace   a compact breadcrumb    - flight log always, game log when on
  Event   a milestone             - both logs, always
  Warn    something went wrong    - both logs, always, flushed
  Error   the mod could not cope  - both logs, always, flushed, with the stack

Severity, not the settings, decides whether a switch is consulted. Connects,
disconnects, world transfers, resyncs, dropped commands, quarantined batches
and every fault are written with every switch off, because nobody turns a
switch on before the crash they did not know was coming.

Gating is per feature, not one "verbose" flag. LogTopic names eighteen of
them - session, transport, world transfer, resync, pipeline, nets, buildings,
land, city, routes, the four zone economies, players, UI, startup and
performance - each with its own switch on a new Logging options tab, plus a
Log Everything master for "I do not know which one". The enum lives in
Core/Diagnostics so the portable networking and session code names the same
topics; IModLogger mirrors the same shape and ColossalModLogger is the seam.

Call sites no longer write prefixes. The "[MP] ", "[MP][OCC-DEV] ",
"[security] ", "[upnp] ", "[relay] " and "[compatibility] " spellings are
gone; the logger attaches one [topic] tag so every line is greppable and no
two subsystems can drift.

Why two files still, and what the difference is: the game log is the readable
one. The flight log is the same content made durable - it is flushed per
fault so a hard exit keeps its tail, it is not truncated when the game
restarts, it also captures Unity and other mods' exceptions, and it is
machine-readable. Nothing reaches the game log without also reaching it, so
"send us CS2MP-flight.log" is now a complete answer. Detail and trace lines
are buffered rather than flushed, and the next fault commits them, so turning
a topic on no longer puts a disk write in every frame.

Also: thirty "X ready." lines replaced by one startup line carrying the mod,
protocol and game versions; the 30-second performance report demoted out of
every player's log; expensive diagnostic probes now follow their own feature
switch instead of the master one; resync reports log their full summary
rather than just the reason.
@Rollocraft
Rollocraft force-pushed the logging-consolidation branch from 5d3008f to c620f29 Compare August 31, 2026 14:29
@Rollocraft
Rollocraft merged commit 8e1e929 into dev Aug 31, 2026
@Rollocraft
Rollocraft deleted the logging-consolidation branch August 31, 2026 14:30
Rollocraft added a commit that referenced this pull request Sep 2, 2026
Route every log line through one topic-tagged logger
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant