Skip to content

core+qt: log the four silent server-side outcomes - #40

Open
Yaraslaut wants to merge 1 commit into
masterfrom
feature/30-server-side-observability
Open

core+qt: log the four silent server-side outcomes#40
Yaraslaut wants to merge 1 commit into
masterfrom
feature/30-server-side-observability

Conversation

@Yaraslaut

Copy link
Copy Markdown
Member

Summary

  • morph::log exists and both RemoteServer and QtWebSocketServer have access to it, but the server side was almost entirely silent — several client-indistinguishable outcomes left no server-side record at all.
  • The issue explicitly raised two logging-policy questions before asking for a PR (payload truncation vs. redaction on the decode-failure path; whether to include the session principal on the per-request line), since both are real payload/PII trade-offs. Confirmed with the repo owner before implementing: truncated payload prefix (matching the issue's own lean), principal omitted by default from the per-request line.
  • Logs at the four points identified, each a one-line call at a spot the code already reaches:
    • RemoteServer::dispatchMessage, undecodable envelope (logError): connection id, exception text, byte count, truncated (256-byte) payload prefix.
    • RemoteServer::dispatchMessage, one line per successfully-decoded request (logDebug): connection id, kind, callId, typeId/modelId/modelType/actionType, body size — principal and body omitted by design (see above).
    • QtWebSocketServer::onNewConnection, connection refused by maxConnections (logWarn): live count and the configured cap.
    • QtWebSocketServer::onNewConnection/onDisconnected, connect/disconnect (logInfo): connection id and live count on both; close code + reason (captured before teardown) on disconnect.

Test plan

  • tests/qt/test_qt_websocket_adversarial.cpp: new end-to-end test sending a genuinely undecodable frame over a real socket — confirms the err reply, the truncated-preview error log line, and that the server keeps serving honest clients afterward.
  • tests/qt/test_qt_websocket.cpp: two new tests — maxConnections refusal logs a warning naming the cap; connect/disconnect both log at info with the live count.
  • Full Qt suite: 53 test cases / 351 assertions — the 50/334 pre-change baseline plus the 3 new cases.
  • Full main suite: ./build/tests/morph_tests — all 811 test cases / 8284 assertions pass; the new per-request debug line is visibly firing throughout the existing RemoteServer-based tests with sensible data, confirming it works correctly across the whole suite, not just the new tests.

Closes #30

🤖 Generated with Claude Code

morph::log exists and both RemoteServer and QtWebSocketServer have access
to it, but the server side was almost entirely silent. Several outcomes a
client cannot distinguish from each other -- did the request arrive? was it
rejected? how many clients are connected? why did that one drop? -- had no
server-side record at all, closing off exactly the questions asked when a
deployment misbehaves.

Log at the four points the issue identified, each a one-line call at a spot
the code already reaches:

- RemoteServer::dispatchMessage, undecodable envelope (logError): connection
  id, exception text, byte count, and a truncated (256-byte) prefix of the
  raw payload -- the most useful field for diagnosing why a client sent
  something malformed, and the most likely to carry application data, hence
  capped rather than logged in full.
- RemoteServer::dispatchMessage, one line per successfully-decoded request
  (logDebug): connection id, kind, callId, typeId/modelId/modelType/
  actionType, body size. Omits the session principal (personal data in many
  deployments; still recoverable after the fact by correlating callId with
  the journal where auth is configured) and the request body (already
  covered, truncated, on the decode-failure path; logging every successful
  body would be far higher volume and duplicate the action log).
- QtWebSocketServer::onNewConnection, connection refused by maxConnections
  (logWarn): live count and the configured cap -- to the client this looks
  exactly like the server being down, and the cap being hit is the one
  piece of information that would explain the symptom.
- QtWebSocketServer::onNewConnection/onDisconnected, connect and disconnect
  (logInfo): connection id and live count on both; close code and reason
  (captured from the socket before it is torn down) on disconnect.

The issue raised two logging-policy questions before writing any code --
whether to log a truncated payload on the decode-failure path, and whether
to include the session principal on the per-request line -- both flagged as
worth agreeing on first given the payload/PII trade-offs. Confirmed with the
repo owner before implementing: truncated payload prefix (matching the
issue's own lean), principal omitted by default from the per-request line.

Verified end-to-end against a real Qt WebSocket server: the undecodable-
envelope log fires with a truncated preview and the server keeps serving
honest clients afterward; the maxConnections warning fires and names the
cap; connect/disconnect both log with the live count.

Closes #30

Signed-off-by: Yaraslau Tamashevich <yaraslau.tamashevich@gmail.com>
@codecov

codecov Bot commented Aug 3, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.

📢 Thoughts on this report? Let us know!

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.

Server side is silent: rejected envelopes, refused connections and disconnects go unlogged

1 participant