Summary
morph::log exists and both the socket server and RemoteServer have access to it, but the
server side is almost entirely silent. Several outcomes that a client cannot distinguish from
each other produce no server-side record at all.
The gaps
1. Undecodable envelope. RemoteServer::dispatchMessage catches the decode failure and
replies with an err:
try {
env = ::morph::wire::decode(msg);
} catch (const std::exception& exc) {
reply(::morph::wire::encode(::morph::wire::makeErr(exc.what())));
return; // nothing logged
}
A client that swallows the error — or that is malformed precisely because it is confused —
leaves no trace of a request that never dispatched.
2. No per-request record. There is no single line saying a request was accepted and what
it was. dispatchMessage is the one place every kind funnels through, so it is the natural
spot. Without it, a client stuck mid-handshake is indistinguishable from one that never sent
anything.
3. Connection refused by maxConnections. The socket server closes the socket and returns:
if (_cfg.maxConnections != 0 && _clients.size() >= _cfg.maxConnections) {
socket->close();
socket->deleteLater();
return; // nothing logged
}
To the client this looks exactly like the server being down. The operator has no way to learn
the cap was hit, which is the one piece of information that would explain the symptom.
4. Connect / disconnect. Neither is recorded, so there is no way to reconstruct how many
clients were live, or why one went away (close code and reason are both available at that
point and are the useful part).
Why it matters
These are the questions asked when a deployment misbehaves — did the request arrive? was it
rejected? how many clients are connected? why did that one drop? — and none of them can
currently be answered from the server side. Each is a one-line morph::log call at a point
the code already reaches.
Suggested direction
Log at the four points above, using the existing morph::log levels:
logError — undecodable envelope: include the peer/connection id, the exception text, the
byte count, and a truncated prefix of the payload
logDebug — one line per accepted request: kind, call id, type/model/action ids, body size
logWarn — connection refused, naming the configured cap
logInfo — connect and disconnect, with the live count, plus close code and reason on
disconnect
Points worth deciding:
- Payload in logs. Echoing a rejected body is the most useful field for diagnosing a
malformed client and the most likely to contain application data. Truncating helps but does
not make it safe by itself; a length-only mode, or a hook to redact before logging, may be
the better default.
- Principal in the per-request line. Useful for attribution, and personal data in many
deployments. Possibly opt-in.
- Volume. One debug line per request is fine at
debug, but the level choice should be
deliberate so a busy server doesn't emit it by default.
Happy to open a PR — though given the payload/principal questions above, it's probably worth
agreeing on what should be logged by default before I write it.
Summary
morph::logexists and both the socket server andRemoteServerhave access to it, but theserver side is almost entirely silent. Several outcomes that a client cannot distinguish from
each other produce no server-side record at all.
The gaps
1. Undecodable envelope.
RemoteServer::dispatchMessagecatches the decode failure andreplies with an
err:A client that swallows the error — or that is malformed precisely because it is confused —
leaves no trace of a request that never dispatched.
2. No per-request record. There is no single line saying a request was accepted and what
it was.
dispatchMessageis the one place every kind funnels through, so it is the naturalspot. Without it, a client stuck mid-handshake is indistinguishable from one that never sent
anything.
3. Connection refused by
maxConnections. The socket server closes the socket and returns:To the client this looks exactly like the server being down. The operator has no way to learn
the cap was hit, which is the one piece of information that would explain the symptom.
4. Connect / disconnect. Neither is recorded, so there is no way to reconstruct how many
clients were live, or why one went away (close code and reason are both available at that
point and are the useful part).
Why it matters
These are the questions asked when a deployment misbehaves — did the request arrive? was it
rejected? how many clients are connected? why did that one drop? — and none of them can
currently be answered from the server side. Each is a one-line
morph::logcall at a pointthe code already reaches.
Suggested direction
Log at the four points above, using the existing
morph::loglevels:logError— undecodable envelope: include the peer/connection id, the exception text, thebyte count, and a truncated prefix of the payload
logDebug— one line per accepted request: kind, call id, type/model/action ids, body sizelogWarn— connection refused, naming the configured caplogInfo— connect and disconnect, with the live count, plus close code and reason ondisconnect
Points worth deciding:
malformed client and the most likely to contain application data. Truncating helps but does
not make it safe by itself; a length-only mode, or a hook to redact before logging, may be
the better default.
deployments. Possibly opt-in.
debug, but the level choice should bedeliberate so a busy server doesn't emit it by default.
Happy to open a PR — though given the payload/principal questions above, it's probably worth
agreeing on what should be logged by default before I write it.