Skip to content

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

Description

@Yaraslaut

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.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions